| 07-20-2009, 06:07 PM | #1 |
Hello! I'm creating a simple damage over time system in vJass for practice reasons, but it worked out quite badly. What happens is that I know the data are stored in the struct array, but after that nothing else happens, no damage, no effects, no nothing. I have to say, everytime I work on something they never work for the first time, but this is becoming annoying as I can never find the malfunction reason. anyway here is the code: DOT code:library DamageOverTime initializer Init private keyword Data globals private constant real interval = 0.05 private timer tim private Data array dat private integer total = 0 endglobals private function Loop takes nothing returns nothing local Data d local integer i loop exitwhen i >= total set d = dat[i] call BJDebugMsg( "Current Interval: " + R2S( d.counter ) ) set d.counter = d.counter + interval if d.counter >= d.icheck then set d.counter = 0. call BJDebugMsg( "Current Damage: " + R2S( d.dmgcount ) ) if d.dmgcount < ( d.dmg * d.dur ) then set d.dmgcount = d.dmgcount + d.dmg call UnitDamageTarget( d.source, d.target, d.dmg, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, null ) call DestroyEffect( AddSpecialEffectTarget( d.insEffect, d.target, d.attach ) ) else call DestroyEffect( d.effectOT ) set d.source = null set d.target = null set d.counter = 0. set d.dmgcount = 0. call d.destroy( ) set total = total - 1 set dat[i] = dat[total] endif endif set i = i + 1 endloop if total == 0 then call PauseTimer( tim ) endif endfunction private struct Data unit source unit target real dmg real dur real icheck string insEffect effect effectOT string attach real counter real dmgcount static method Create takes unit source, unit target, real dmg, real dur, real icheck, string insEffect, effect effectOT, string attach returns nothing local Data d = Data.allocate( ) set d.source = source set d.target = target set d.dmg = dmg / dur / icheck set d.dur = dur set d.icheck = icheck set d.insEffect = insEffect set d.effectOT = effectOT if attach == "" then set d.attach = "chest" else set d.attach = attach endif set d.counter = 0. set d.dmgcount = 0. call BJDebugMsg( "data has been stored" ) if total == 0 then call TimerStart( tim, interval, true, function Loop ) endif set dat[total] = d set total = total + 1 endmethod endstruct function DotAttach takes unit source, unit target, real totaldmg, real duration, real intervalcheck, string insEffect, string effectOT, string attach returns nothing local effect e = AddSpecialEffectTarget( effectOT, target, attach ) call Data.Create( source, target, totaldmg, duration, intervalcheck, insEffect, e, attach ) endfunction private function Init takes nothing returns nothing set tim = CreateTimer( ) endfunction endlibrary I hope someone here can help me. Thanks in advance! |
| 07-20-2009, 06:13 PM | #2 |
error:
local integer i |
| 07-20-2009, 06:17 PM | #3 |
omg I can't believe it's because of that. Problem solved. Anyway I didn't knew about that, and I actually learned something. I'm really appreciated. Here's one cookie |
| 07-21-2009, 08:14 AM | #4 |
and because I don't want to create another topic, now my new spell doesn't work as it should. It creates missiles in front of the caster across 180 degrees of the target point of the ability which then will move forward at a certain speed damaging units as they touch the missiles. The thing is, something is messing up the speed values. The missiles should stop when the variable d.countdis is greater than the variable d.dis ( the max distance ) and so every interval time it increments the d.countdis with the speed value. This works okay, but when I do this: Moving part:set x = GetUnitX( d.moved ) + ( d.speed ) * Cos( d.angle * bj_DEGTORAD ) set y = GetUnitY( d.moved ) + ( d.speed ) * Sin( d.angle * bj_DEGTORAD ) call BJDebugMsg( R2S( d.speed ) ) here is the whole code: Fuuton:scope Fuuton initializer Init private keyword Moving globals private constant integer FPS = 30 private constant integer abilityid = 'A001' private constant integer missileid = 'h002' private constant real speed = 10. private constant real radius = 210. endglobals private constant function DmgPerSecond takes integer level returns real return level * 40. endfunction private constant function MaxDistance takes integer level returns real return level * 100. + 300. endfunction globals private timer movetim private timer knocktim private Moving array move private real interval private integer movetotal = 0 private integer knocktotal = 0 private boolexpr b private group g endglobals private function filter takes nothing returns boolean local unit u = GetFilterUnit( ) return IsUnitType( u, UNIT_TYPE_MAGIC_IMMUNE ) == false and IsUnitType( u, UNIT_TYPE_STRUCTURE ) == false and GetWidgetLife( u ) > 0.405 endfunction private function MoveLoop takes nothing returns nothing local Moving d local integer i = 0 local real x local real y local unit u local player p loop exitwhen i >= movetotal set d = move[i] if d.countdis <= d.dis then set p = GetOwningPlayer( d.moved ) set d.countdis = d.countdis + d.speed set x = GetUnitX( d.moved ) + ( d.speed ) * Cos( d.angle * bj_DEGTORAD ) set y = GetUnitY( d.moved ) + ( d.speed ) * Sin( d.angle * bj_DEGTORAD ) call BJDebugMsg( R2S( d.speed ) ) call SetUnitX( d.moved, x ) call SetUnitY( d.moved, y ) call GroupEnumUnitsInRange( g, GetUnitX( d.moved ), GetUnitY( d.moved ), d.radius, b ) loop set u = FirstOfGroup( g ) exitwhen u == null call GroupRemoveUnit( g, u ) if IsUnitEnemy( u, p ) then call UnitDamageTarget( d.moved, u, d.dmg * interval, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, null ) endif endloop else call Fade( d.moved, 1.20 ) set d.moved = null call d.destroy( ) set movetotal = movetotal - 1 set move[i] = move[movetotal] endif set i = i + 1 endloop set u = null endfunction private struct Moving unit moved real dis real angle real speed real radius real dmg real countdis static method Create takes unit moved, real dis, real angle, real speed, real radius, real dmg returns nothing local Moving d = Moving.allocate( ) set d.moved = moved set d.dis = dis set d.angle = angle set d.speed = speed set d.radius = radius set d.dmg = dmg set d.countdis = 0. if movetotal == 0 then call TimerStart( movetim, interval, true, function MoveLoop ) endif set move[movetotal] = d set movetotal = movetotal + 1 endmethod endstruct private function conditions takes nothing returns boolean return GetSpellAbilityId( ) == abilityid endfunction private function actions takes nothing returns nothing local integer i = 0 local unit c = GetTriggerUnit( ) local location p = GetSpellTargetLoc( ) local real x = GetUnitX( c ) local real y = GetUnitY( c ) local real a = ( bj_RADTODEG * Atan2( GetLocationY( p ) - y, GetLocationX( p ) - x ) ) - 90. local unit u local integer lvl = GetUnitAbilityLevel( c, abilityid ) loop exitwhen i == 8 set u = CreateUnit( GetOwningPlayer( c ), missileid, x, y, a ) call Moving.Create( u, MaxDistance( lvl ), a, speed, radius, DmgPerSecond( lvl ) ) set a = a + 22.5 set i = i + 1 endloop call RemoveLocation( p ) set c = null set u = null endfunction private function Init takes nothing returns nothing local trigger t = CreateTrigger( ) local integer i = 0 loop exitwhen i == bj_MAX_PLAYER_SLOTS call TriggerRegisterPlayerUnitEvent( t, Player( i ), EVENT_PLAYER_UNIT_SPELL_EFFECT, null ) set i = i + 1 endloop call TriggerAddCondition( t, Condition( function conditions ) ) call TriggerAddAction( t, function actions ) set movetim = CreateTimer( ) set knocktim = CreateTimer( ) set interval = 1.00 / FPS set b = Condition( function filter ) set g = CreateGroup( ) endfunction endscope Thanks in advance! |
| 07-21-2009, 09:21 AM | #5 |
Try restarting the Editor, I didn't see anything overwriting the speed and d.speed parameter. Still searching the code... |
| 07-21-2009, 09:29 AM | #6 |
restarted and still doesn't work I can post the map here if you want, don't know if it will serve as anything though |
| 07-21-2009, 09:38 AM | #7 |
It's ok if you can post the map, It'll be a lot easier for me to debug it. |
| 07-21-2009, 09:41 AM | #8 |
here it is then. It's the Fuuton Atsugai trigger. If you have the time could you see the other spell Raiton Gian? it is screwed up as well, angles are wrong when casting, takes a few seconds to unpause the unit when it should be instantly, and only works once, when I try to cast it again it doesn't work. |
| 07-21-2009, 09:51 AM | #9 |
ok, seems like you redeclared the variables "speed" and "radius" (once as constants once as locals in the create-method). if you rename the locals the create-method takes it should work. No idea why newgen does not find that mistake, looks like a bug to me. |
| 07-21-2009, 10:05 AM | #10 |
Fuuton Atsugai's problem came from the conflicting variable names in your struct and on your globals variable name conflict:globals integer speed endglobals struct integer speed endstruct By converting the global variable name to uppercase, I made the spell work. Here: quick fix:scope Fuuton initializer Init private keyword Moving globals private constant integer FPS = 30 private constant integer abilityid = 'A001' private constant integer missileid = 'h002' private constant real SPEED = 10. private constant real radius = 210. endglobals private constant function DmgPerSecond takes integer level returns real return level * 40. endfunction private constant function MaxDistance takes integer level returns real return level * 100. + 300. endfunction globals private timer movetim private timer knocktim private Moving array move private real interval private integer movetotal = 0 private integer knocktotal = 0 private boolexpr b private group g endglobals private function filter takes nothing returns boolean local unit u = GetFilterUnit( ) return IsUnitType( u, UNIT_TYPE_MAGIC_IMMUNE ) == false and IsUnitType( u, UNIT_TYPE_STRUCTURE ) == false and GetWidgetLife( u ) > 0.405 endfunction private function MoveLoop takes nothing returns nothing local Moving d local integer i = 0 local real x local real y local unit u local player p loop exitwhen i >= movetotal set d = move[i] if d.countdis <= d.dis then set p = GetOwningPlayer( d.moved ) set d.countdis = d.countdis + d.speed set x = GetUnitX( d.moved ) + d.speed * Cos( d.angle * bj_DEGTORAD ) set y = GetUnitY( d.moved ) + d.speed * Sin( d.angle * bj_DEGTORAD ) //call BJDebugMsg( R2S( d.speed ) ) call SetUnitX( d.moved, x ) call SetUnitY( d.moved, y ) call GroupEnumUnitsInRange( g, GetUnitX( d.moved ), GetUnitY( d.moved ), d.radius, b ) loop set u = FirstOfGroup( g ) exitwhen u == null call GroupRemoveUnit( g, u ) if IsUnitEnemy( u, p ) then call UnitDamageTarget( d.moved, u, d.dmg * interval, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, null ) endif endloop else call Fade( d.moved, 1. ) set d.moved = null call d.destroy( ) set movetotal = movetotal - 1 set move[i] = move[movetotal] endif set i = i + 1 endloop set u = null endfunction private struct Moving unit moved real dis real angle real speed real radius real dmg real countdis static method Create takes unit moved, real dis, real angle, real speed, real radius, real dmg returns nothing local Moving d = Moving.allocate( ) set d.moved = moved set d.dis = dis set d.angle = angle set d.speed = speed set d.radius = radius set d.dmg = dmg call BJDebugMsg( R2S( d.speed ) ) set d.countdis = 0. if movetotal == 0 then call TimerStart( movetim, .05, true, function MoveLoop ) endif set move[movetotal] = d set movetotal = movetotal + 1 endmethod endstruct private function conditions takes nothing returns boolean return GetSpellAbilityId( ) == abilityid endfunction private function actions takes nothing returns nothing local integer i = 0 local unit c = GetTriggerUnit( ) local location p = GetSpellTargetLoc( ) local real x = GetUnitX( c ) local real y = GetUnitY( c ) local real a = ( bj_RADTODEG * Atan2( GetLocationY( p ) - y, GetLocationX( p ) - x ) ) - 90. local unit u local integer lvl = GetUnitAbilityLevel( c, abilityid ) loop exitwhen i == 8 set u = CreateUnit( GetOwningPlayer( c ), missileid, x, y, a ) call Moving.Create( u, MaxDistance( lvl ), a, SPEED, radius, DmgPerSecond( lvl ) ) set a = a + 22.5 set i = i + 1 endloop call RemoveLocation( p ) set c = null set u = null endfunction private function Init takes nothing returns nothing local trigger t = CreateTrigger( ) local integer i = 0 loop exitwhen i == bj_MAX_PLAYER_SLOTS call TriggerRegisterPlayerUnitEvent( t, Player( i ), EVENT_PLAYER_UNIT_SPELL_EFFECT, null ) set i = i + 1 endloop call TriggerAddCondition( t, Condition( function conditions ) ) call TriggerAddAction( t, function actions ) set movetim = CreateTimer( ) set knocktim = CreateTimer( ) set interval = 1.00 / FPS set b = Condition( function filter ) set g = CreateGroup( ) endfunction endscope Don't use identical identifiers\variable names as it causes conflicts to the code. EDIT: Patpup is right, I forgot to mention the locals. |
| 07-21-2009, 10:13 AM | #11 | |
Quote:
I'm afraid you are slightly off there. You probably changed the speed-constants name to determine that - doing that solves the problem. But in fact constant- and member-names do not conflict because members are allways called as this.membername (i.e this.speed). The problem has something to do with "speed" in the create-method precompiling to "libraryname_speed". I have no idea why that should cause the value to be 210, which is the radius constant (that one has a conflict as well), though... Edit: you edited faster than me! high-five! ;) btw: chobibo is right - you should not have constants and struct-members with identical names. It DOES work but its bound to cause horrible, possibly hard to find typo-errors. i.e. if you forget a "." somewhere... |
| 07-21-2009, 10:36 AM | #12 |
nice! learned another thing, didn't knew they would conflict with each other. Thanks a lot!! I was kinda stupid setting constant globals and then store them in the struct. Now it works perfectly. Anyway, could any of you check the other trigger please? Raiton Gian? |
| 07-21-2009, 10:51 AM | #13 |
Ok, same problem as before, you are using a local variable not initialized. Its the "loop"-function: JASS:private function Loop takes nothing returns nothing local Data d local integer i = 0 local integer i2 = 1 local real array x local real array y local real array a local player p local group g = CreateGroup( ) local unit u loop exitwhen i >= Total set d = dat[i] if d.dis >= d.maxdis then // >> set p = GetOwningPlayer( d.source ) << Add this to make it work (in case thats what you inteded "p" to be) loop set u = FirstOfGroup( dummies ) exitwhen u == null call GroupRemoveUnit( dummies, u ) if GetOwningPlayer( u ) == p then call RemoveUnit( u ) endif endloop call BJDebugMsg( "Dummy removal works" ) //(...) endif else //(...) Without initializing "p" the loop dies as soon as d.dis reaches d.maxdis because it cant compare "GetOwningPlayer(u)" and "p". Once the last unit has been removed from "dummies", however, the function moves on and unpauses the "source"-unit. Thats what causes the delay. Hope that helps! Got to get back to my own map now ;)) Btw, some things about the movement of those lightning-effects in "RaitonGian": I can only guess what they are supposed to do, but you got one easy-to-miss typo in there anyways: JASS:set x[0] = GetUnitX( d.source ) set y[0] = GetUnitY( d.source ) set x[1] = x[0] + d.dis * Cos( d.a2 * bj_DEGTORAD ) set y[1] = y[0] + d.dis * Sin( d.a2 * bj_DEGTORAD ) set x[2] = x[0] + d.dis * Cos( d.a3 * bj_DEGTORAD ) set y[2] = x[0] + d.dis * Sin( d.a3 * bj_DEGTORAD ) Have a close look at that last line. Hint: He's a girl...(horrible pun) Furthermore, I guess the effects are supposed to move towards the direction the spell was cast. If thats the case then here is your problem: JASS:if d.interval >= intervalcheck then set d.a2 = GetRandomReal( 0., -45. ) set d.a3 = GetRandomReal( 0., 45. ) endif This means the angles "d.a2" and "d.a3" have no relation whatever to the angle the spell was cast at ("d.angle"). So it should be: JASS:if d.interval >= intervalcheck then set d.a2 = d.angle + GetRandomReal( 0., -45. ) set d.a3 = d.angle + GetRandomReal( 0., 45. ) endif That should fix it. Godspeed. |
| 07-21-2009, 11:22 AM | #14 |
yap it really helped me. Thanks! I hope some day I can return the favor since I can't +rep you anytime soon. Good luck for your map then. |
| 07-21-2009, 11:47 AM | #15 |
You don't have to! I'm really just using this as an excuse to take a break from my own stuff lol (which has more bugs than your regular rainforest it seems). And it kinda pushes your confidence to actually FIND and CORRECT some mistakes, haha. Anyway I'd like someone more gifted then me to have a look at the problem in that first spell. because I have absolutely no idea why that ".speed"-member got the "radius"-constants value (210) instead of the "speed"-constants (which noone would have noticed because it was 10 as well)... Good luck to you as well! |
