| 09-20-2008, 04:39 PM | #1 |
Hi guys, I started working on a lightning spell for my map. This spell will be better than any system IMO because for the first time (and only, afaik) it will allow the user to choose any model he wants for the lightning effect. However this is not a lightning system, it is merely a lightning spell. Anyway, such thing will never happen if I don't fix a bug. If you run my code, it does fine, however. However, when I was giving the final touch an evil thing happened. I found a loop doesn't work. And it isn't even a complicated loop, just a simple stupid loop... My problem is in this loop: JASS:private function Actions takes nothing returns nothing local SpellData data = SpellData.create(GetTriggerUnit()) local integer i set data.vic = GetSpellTargetUnit() //here we add the caster the the target to the picked group call GroupAddUnit(data.picked, data.caster) call GroupAddUnit(data.picked, data.vic) //Here we move the projectile call MoveMissile(data) //Pick new Target call NextTarget(data) //Here we move the projectile call MoveMissile(data) // WHY THE LOOP DOES NOT WORK ???? // loop // exitwhen (i == TargetsNumber(data.level)) // //Here we move the projectile // call MoveMissile(data) // // //Pick new Target // call NextTarget(data) // set i = i + 1 // endloop call data.destroy() endfunction I must use that loop, but I can't. However, if I use the instructions without the loop (as you can see I call same functions before loop) the code works just fine ... Can any one find me a stupid reason for why this stupid mistake is happening ? Full Code (it's really easy it just has lots of comments...): JASS://=========================================================================== //A JESP spell that allows the user to create lightning spells with any model //he desires. // //Requires TimerUtils // //@author Flame_Phoenix // //@credits //- Daelin, for his tutorials and codes // //@version 1.0 //=========================================================================== scope Lightning initializer Init private keyword tmpPlayer //=========================================================================== //=============================SETUP START=================================== //=========================================================================== globals private constant integer AID = 'A000'//'AUdc' //rw of teh ability private constant real SPEED = 900. //speed of the missile private constant integer MISSILE_ID = 'h000' //rw of the missile private constant real TIMER_CICLE = 0.03 //cicles of the timer endglobals private function Range takes integer level returns real //If there is more than one Target, a next target will be picked in a 500 //AOE from the first return 500. + (level * 0) endfunction private function Damage takes integer level returns real //Damage each Target will take return 100. * level endfunction private function TargetsNumber takes integer level returns integer //The number of targets return 5 + (level * 0) endfunction private function AceptedTargets takes nothing returns boolean return IsUnitEnemy(GetFilterUnit(), tmpPlayer) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false) and (GetWidgetLife(GetFilterUnit()) > 0.405) endfunction //=========================================================================== //=============================SETUP END===================================== //=========================================================================== globals private group g private boolexpr b private player tmpPlayer = null endglobals private struct SpellData unit caster unit vic //the current victim integer level group picked //saves all targeted units so far, so they don't get picked again timer t unit missile real wait static method create takes unit caster returns SpellData local SpellData data = SpellData.allocate() //setting variables set data.caster = caster set data.vic = null set data.level = GetUnitAbilityLevel(caster, AID) set data.picked = CreateGroup() set data.missile = CreateUnit(GetOwningPlayer(caster), MISSILE_ID, GetUnitX(caster), GetUnitY(caster), 0) set data.wait = 0. return data endmethod method onDestroy takes nothing returns nothing call DestroyGroup(.picked) call ShowUnit(.missile, false) call KillUnit(.missile) endmethod endstruct //=========================================================================== private function NextTarget takes integer structure returns nothing local SpellData data = structure local unit f set tmpPlayer = GetOwningPlayer(data.caster) call GroupEnumUnitsInRange(g, GetUnitX(data.vic), GetUnitY(data.vic), 500., b) set data.vic = GroupPickRandomUnit(g) call GroupAddUnit(data.picked, data.vic) loop set f = FirstOfGroup(g) exitwhen(f == null) call GroupRemoveUnit(g, f) endloop endfunction //=========================================================================== private function TargetEffect takes integer structure returns nothing local SpellData data = structure call UnitDamageTarget(data.caster, data.vic, Damage(data.level), true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null) endfunction //=========================================================================== private function Move takes nothing returns nothing local SpellData data = SpellData(GetTimerData(GetExpiredTimer())) local real x1 = GetUnitX(data.missile) local real x2 = GetUnitX(data.vic) local real y1 = GetUnitY(data.missile) local real y2 = GetUnitY(data.vic) local real dx = TIMER_CICLE * (x2 - x1) / data.wait local real dy = TIMER_CICLE * (y2 - y1) / data.wait call SetUnitPosition(data.missile, x1 + dx, y1 + dy) set data.wait = data.wait - TIMER_CICLE if data.wait < TIMER_CICLE then call SetUnitPosition(data.missile, x2, y2) call ReleaseTimer(data.t) call TargetEffect(data) endif endfunction //=========================================================================== private function MoveMissile takes integer structure returns nothing local SpellData data = structure local real a = GetUnitX(data.missile) - GetUnitX(data.vic) local real b = GetUnitY(data.missile) - GetUnitY(data.vic) local real d = SquareRoot(a*a + b*b) //the distance between "a" and "b" set data.t = NewTimer() set data.wait = d / SPEED //we attach the struct to the timer and we start it call SetTimerData(data.t, integer(data)) call TimerStart(data.t, TIMER_CICLE, true, function Move) //gotta fix this =S call PolledWait(data.wait) endfunction //=========================================================================== private function Conditions takes nothing returns boolean return GetSpellAbilityId() == AID endfunction //=========================================================================== private function Actions takes nothing returns nothing local SpellData data = SpellData.create(GetTriggerUnit()) local integer i set data.vic = GetSpellTargetUnit() //here we add the caster the the target to the picked group call GroupAddUnit(data.picked, data.caster) call GroupAddUnit(data.picked, data.vic) //Here we move the projectile call MoveMissile(data) //Pick new Target call NextTarget(data) //Here we move the projectile call MoveMissile(data) // WHY THE LOOP DOES NOT WORK ???? // loop // exitwhen (i == TargetsNumber(data.level)) // //Here we move the projectile // call MoveMissile(data) // // //Pick new Target // call NextTarget(data) // set i = i + 1 // endloop call data.destroy() endfunction //=========================================================================== private function Init takes nothing returns nothing local trigger LightningTrg = CreateTrigger( ) call TriggerRegisterAnyUnitEventBJ( LightningTrg, EVENT_PLAYER_UNIT_SPELL_EFFECT ) call TriggerAddCondition( LightningTrg, Condition( function Conditions ) ) call TriggerAddAction(LightningTrg, function Actions ) set LightningTrg = null //setting globals set b = Condition(function AceptedTargets) set g = CreateGroup() endfunction endscope Is there a chance the problem is on the "call PolledWait(data.wait)" line ? I don't understand, I saw this same thing in another code, and it worked just fine (in fact it is approved here in wc3c and it still works). HELP ! +credits and rep will be given Anyway, here is the map ... enjoy killing peasants ! |
| 09-20-2008, 04:47 PM | #2 |
You didn't give an initial value to i. |
| 09-20-2008, 07:35 PM | #3 |
LOL ... what a dummy mistake .. Anyway thx for help, +rep EDIT EDIT EDIT ARRGHHHH ! WHY IS THIS TORTURING ME ! WHYYY !!!! Guys, Now I have another problem, but this one is a lot more complicated =( When my code doesn't find a unit to kill, it just goes mad !!! It either kills the target instantly or even worse I get a damn annoying message saying: "Warning: ReleaseTimer: Double free!" And then my spell blows and it never ever works ever again ! EVER ! Please What am I doing wrong ? PS: here you guys have map again, for you joy (or not lol) JASS:globals private group g private boolexpr b private player tmpPlayer = null endglobals private struct SpellData unit caster unit vic //the current victim integer level group picked //saves all targeted units so far, so they don't get picked again timer t unit missile real wait integer i //counter for loop in function ACtions static method create takes unit caster returns SpellData local SpellData data = SpellData.allocate() //setting variables set data.caster = caster set data.vic = null set data.level = GetUnitAbilityLevel(caster, AID) set data.picked = CreateGroup() set data.missile = CreateUnit(GetOwningPlayer(caster), MISSILE_ID, GetUnitX(caster), GetUnitY(caster), 0) set data.wait = 0. set data.i = 0 return data endmethod method onDestroy takes nothing returns nothing call DestroyGroup(.picked) call ShowUnit(.missile, false) call KillUnit(.missile) endmethod endstruct //=========================================================================== private function NextTarget takes integer structure returns unit local SpellData data = structure local unit f local unit ret set tmpPlayer = GetOwningPlayer(data.caster) call GroupEnumUnitsInRange(g, GetUnitX(data.vic), GetUnitY(data.vic), Range(data.level), b) set ret = GroupPickRandomUnit(g) call GroupAddUnit(data.picked, ret) loop set f = FirstOfGroup(g) exitwhen(f == null) call GroupRemoveUnit(g, f) endloop if ret == null then call ReleaseTimer(data.t) endif return ret endfunction //=========================================================================== private function TargetEffect takes integer structure returns nothing local SpellData data = structure call UnitDamageTarget(data.caster, data.vic, Damage(data.level) - (Reduction(data.level) * 100 * data.i), true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null) endfunction //=========================================================================== private function Move takes nothing returns nothing local SpellData data = SpellData(GetTimerData(GetExpiredTimer())) local real x1 = GetUnitX(data.missile) local real x2 = GetUnitX(data.vic) local real y1 = GetUnitY(data.missile) local real y2 = GetUnitY(data.vic) local real dx = TIMER_CICLE * (x2 - x1) / data.wait local real dy = TIMER_CICLE * (y2 - y1) / data.wait call SetUnitPosition(data.missile, x1 + dx, y1 + dy) set data.wait = data.wait - TIMER_CICLE if data.wait < TIMER_CICLE then call SetUnitPosition(data.missile, x2, y2) call ReleaseTimer(data.t) call TargetEffect(data) endif endfunction //=========================================================================== private function MoveMissile takes integer structure returns nothing local SpellData data = structure local real a = GetUnitX(data.missile) - GetUnitX(data.vic) local real b = GetUnitY(data.missile) - GetUnitY(data.vic) local real d = SquareRoot(a*a + b*b) //the distance between "a" and "b" set data.t = NewTimer() set data.wait = d / SPEED //we attach the struct to the timer and we start it call SetTimerData(data.t, integer(data)) call TimerStart(data.t, TIMER_CICLE, true, function Move) //gotta fix this =S call PolledWait(data.wait) endfunction //=========================================================================== private function Conditions takes nothing returns boolean return GetSpellAbilityId() == AID endfunction //=========================================================================== private function Actions takes nothing returns nothing local SpellData data = SpellData.create(GetTriggerUnit()) set data.vic = GetSpellTargetUnit() //here we add the caster the the target to the picked group call GroupAddUnit(data.picked, data.caster) call GroupAddUnit(data.picked, data.vic) loop exitwhen (data.i == TargetsNumber(data.level)) or (data.vic == null) //Here we move the projectile call MoveMissile(data) //Pick new Target set data.vic = NextTarget(data) set data.i = data.i + 1 endloop call data.destroy() endfunction //=========================================================================== private function Init takes nothing returns nothing local trigger LightningTrg = CreateTrigger( ) call TriggerRegisterAnyUnitEventBJ( LightningTrg, EVENT_PLAYER_UNIT_SPELL_EFFECT ) call TriggerAddCondition( LightningTrg, Condition( function Conditions ) ) call TriggerAddAction(LightningTrg, function Actions ) set LightningTrg = null //setting globals set b = Condition(function AceptedTargets) set g = CreateGroup() endfunction endscope Again, +rep and credit, help ! |
| 09-20-2008, 08:17 PM | #4 |
Something like this?: JASS://=========================================================================== //A JESP spell that allows the user to create lightning spells with any model //he desires. // //Requires TimerUtils // //@author Flame_Phoenix // //@credits //- Daelin, for his tutorials and codes // //@version 1.0 //=========================================================================== scope Lightning initializer Init private keyword tmpPlayer //=========================================================================== //=============================SETUP START=================================== //=========================================================================== globals private constant integer AID = 'A000'//'AUdc' //rw of teh ability private constant real SPEED = 900. //speed of the missile private constant integer MISSILE_ID = 'h000' //rw of the missile private constant real TIMER_CICLE = 0.03 //cicles of the timer endglobals private function Range takes integer level returns real //If there is more than one Target, a next target will be picked in a 500 //AOE from the first return 100. + (level * 0) endfunction private function Damage takes integer level returns real //Damage each Target will take return 100. * level endfunction private function Reduction takes integer level returns real //Damage reduction per Target return 0.15 + (level * 0) endfunction private function TargetsNumber takes integer level returns integer //The number of targets return 5 + (level * 0) endfunction private function AceptedTargets takes nothing returns boolean return IsUnitEnemy(GetFilterUnit(), tmpPlayer) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false) and (GetWidgetLife(GetFilterUnit()) > 0.405) endfunction //=========================================================================== //=============================SETUP END===================================== //=========================================================================== globals private group g private boolexpr b private player tmpPlayer = null endglobals private struct SpellData unit caster unit vic //the current victim integer level group picked //saves all targeted units so far, so they don't get picked again timer t unit missile real wait integer i //counter for loop in function ACtions static method create takes unit caster returns SpellData local SpellData data = SpellData.allocate() //setting variables set data.caster = caster set data.vic = null set data.level = GetUnitAbilityLevel(caster, AID) set data.picked = CreateGroup() set data.missile = CreateUnit(GetOwningPlayer(caster), MISSILE_ID, GetUnitX(caster), GetUnitY(caster), 0) set data.wait = 0. set data.i = 0 return data endmethod method onDestroy takes nothing returns nothing call DestroyGroup(.picked) call ShowUnit(.missile, false) call KillUnit(.missile) endmethod endstruct //=========================================================================== private function NextTarget takes integer structure returns unit local SpellData data = structure local unit f local unit ret set tmpPlayer = GetOwningPlayer(data.caster) call GroupEnumUnitsInRange(g, GetUnitX(data.vic), GetUnitY(data.vic), Range(data.level), b) set ret = GroupPickRandomUnit(g) loop call GroupRemoveUnit( g, ret ) if not IsUnitInGroup( ret, data.picked ) or ret == null then exitwhen true endif set ret = GroupPickRandomUnit(g) endloop if ret != null then call GroupAddUnit(data.picked, ret) loop set f = FirstOfGroup(g) exitwhen(f == null) call GroupRemoveUnit(g, f) endloop endif return ret endfunction //=========================================================================== private function TargetEffect takes integer structure returns nothing local SpellData data = structure call UnitDamageTarget(data.caster, data.vic, Damage(data.level) - (Reduction(data.level) * 100 * data.i), true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null) endfunction //=========================================================================== private function Move takes nothing returns nothing local SpellData data = SpellData(GetTimerData(GetExpiredTimer())) local real x1 = GetUnitX(data.missile) local real x2 = GetUnitX(data.vic) local real y1 = GetUnitY(data.missile) local real y2 = GetUnitY(data.vic) local real dx = TIMER_CICLE * (x2 - x1) / data.wait local real dy = TIMER_CICLE * (y2 - y1) / data.wait call SetUnitPosition(data.missile, x1 + dx, y1 + dy) set data.wait = data.wait - TIMER_CICLE if data.wait < TIMER_CICLE then call SetUnitPosition(data.missile, x2, y2) call ReleaseTimer(data.t) call TargetEffect(data) endif endfunction //=========================================================================== private function MoveMissile takes integer structure returns nothing local SpellData data = structure local real a = GetUnitX(data.missile) - GetUnitX(data.vic) local real b = GetUnitY(data.missile) - GetUnitY(data.vic) local real d = SquareRoot(a*a + b*b) //the distance between "a" and "b" set data.t = NewTimer() set data.wait = d / SPEED //we attach the struct to the timer and we start it call SetTimerData(data.t, integer(data)) call TimerStart(data.t, TIMER_CICLE, true, function Move) //gotta fix this =S call PolledWait(data.wait) endfunction //=========================================================================== private function Conditions takes nothing returns boolean return GetSpellAbilityId() == AID endfunction //=========================================================================== private function Actions takes nothing returns nothing local SpellData data = SpellData.create(GetTriggerUnit()) set data.vic = GetSpellTargetUnit() //here we add the caster the the target to the picked group call GroupAddUnit(data.picked, data.caster) call GroupAddUnit(data.picked, data.vic) loop exitwhen (data.i == TargetsNumber(data.level)) or (data.vic == null) //Here we move the projectile call MoveMissile(data) //Pick new Target set data.vic = NextTarget(data) if data.vic == null then exitwhen true else set data.i = data.i + 1 endif endloop call data.destroy() endfunction //=========================================================================== private function Init takes nothing returns nothing local trigger LightningTrg = CreateTrigger( ) call TriggerRegisterAnyUnitEventBJ( LightningTrg, EVENT_PLAYER_UNIT_SPELL_EFFECT ) call TriggerAddCondition( LightningTrg, Condition( function Conditions ) ) call TriggerAddAction(LightningTrg, function Actions ) set LightningTrg = null //setting globals set b = Condition(function AceptedTargets) set g = CreateGroup() endfunction endscope |
| 09-20-2008, 08:57 PM | #5 |
Bobo_Kodo, thx for your code, I didn't see what you changed but I tested it. Thing is while your code works for one case (the case with 1 unit) and it doesn't work for the other cases (with many units) my code works for the last case, but not for the first. Our complement each other xD Thx for trying anyway =S |
| 09-21-2008, 01:58 AM | #6 |
ya it does work, the range is just really small... you had it set at 100 not 500 >< |
| 09-21-2008, 09:56 AM | #7 | |
Quote:
EDIT EDIT EDIT Guys I have a problem with a loop. I was meant to be a tricky solution, but it doesn't work =S Like I am remaking the spell, without Waits, the obviously screwed up the whole spell, so I am using a loop and a variable instead. The I have problems with is the loop with the BJDebuggMessaged... Some how the variable is ALWAYS false, even if when I set it to true! but how ! Much of the code is useless, I just posted the two entire functions so you guys could see the globals thing: JASS:private function MoveMissile takes nothing returns nothing local SpellData data = SpellData(GetTimerData(GetExpiredTimer())) local real x1 = GetUnitX(data.missile) local real x2 = GetUnitX(data.vic) local real y1 = GetUnitY(data.missile) local real y2 = GetUnitY(data.vic) local real dx = TIMER_CICLE * (x2 - x1) / data.wait local real dy = TIMER_CICLE * (y2 - y1) / data.wait call SetUnitPosition(data.missile, x1 + dx, y1 + dy) set data.wait = data.wait - TIMER_CICLE //this is when the missile gets to the unit if data.wait < TIMER_CICLE then call SetUnitPosition(data.missile, x2, y2) set data.inTarg = true call PauseTimer(data.t) // call TargetEffect(data) endif endfunction //=========================================================================== private function Actions takes nothing returns nothing local SpellData data = SpellData.create(GetTriggerUnit(), GetSpellTargetUnit()) local integer i =0 local real a local real b local real d loop exitwhen(i >= 2) set a = GetUnitX(data.missile) - GetUnitX(data.vic) set b = GetUnitY(data.missile) - GetUnitY(data.vic) set d = SquareRoot(a*a + b*b) //the distance between "a" and "b" set data.wait = d / SPEED call SetTimerData(data.t, integer(data)) call TimerStart(data.t, TIMER_CICLE, true, function MoveMissile) loop exitwhen(data.inTarg) if data.inTarg then call BJDebugMsg("true") else call BJDebugMsg("false") endif endloop set data.vic = data.caster endloop // call data.destroy() endfunction Can some one explain me why this doesn't work ? |
| 09-21-2008, 01:52 PM | #8 |
Actually mine does work, replay attached And on your new method, won't this cause on inifinite loop -> thread crash? JASS:
loop
exitwhen(data.inTarg)
if data.inTarg then
call BJDebugMsg("true")
else
call BJDebugMsg("false")
endif
endloop
|
