| 05-17-2008, 04:53 AM | #1 |
Well this is the first time I've really used dummy units as missiles actually. You may of realize that the struct storage is simliar to moyacks Spear passive. Straight to the point, the code below DoubleFrees a struct once. If I use the onDestroy method doublefree it many times.... Usually I can intercept these problems but I've no idea how to in this case. So any ideas why... Yeah you guys can go through the code at the same time if you want to and fix it up to your liking. JASS:scope ExplodingSpear initializer InitTrig globals private constant integer SpellID = 'A004' private constant integer BuffID = 'B004' private constant integer FlameSID = 'A007' private constant integer Missile = 'h002' private constant integer Dummy = 'h001' private constant attacktype AttackType = ATTACK_TYPE_NORMAL private constant damagetype DamageType = DAMAGE_TYPE_FIRE private constant real damagerate = 0.8 private timer ESTimer = CreateTimer() private timer DamTimer = CreateTimer() private integer DamTimerLimiter = 0 endglobals private function Damage takes unit caster returns real return 50.*GetUnitAbilityLevel(caster,SpellID)+(3.*GetHeroInt(caster,false)) endfunction private function RunTime takes integer level returns real return 1.8 endfunction private function AoE takes integer level returns real return 200. endfunction private struct DataDamage static integer counter = 0 unit target unit caster real damage real runtime real count static method create takes unit caster, unit target returns DataDamage local DataDamage a = DataDamage.allocate() local player p = GetOwningPlayer(caster) local unit d = CreateUnit(p,Dummy,GetUnitX(target),GetUnitY(target),0.) call UnitAddAbility(d,FlameSID) call IssueTargetOrder(d,"innerfire",target) call UnitApplyTimedLife(d,'BTLF',2.) set a.target = target set a.caster = caster set a.damage = Damage(caster)/8. set a.runtime = RunTime(GetUnitAbilityLevel(caster,SpellID)) if integer(a) > a.counter then set a.counter = integer(a) endif return a endmethod static method AddStructs takes nothing returns boolean local unit e = GetFilterUnit() if IsUnitInRangeXY(e,bj_enumDestructableRadius,TempReal,bj_randomSubGroupChance) and IsUnitEnemy(e,bj_groupEnumOwningPlayer) then call DataDamage.create(bj_ghoul[80],e) endif set e = null return false endmethod endstruct private struct ExplodingS static integer counter = 0 unit caster real targx real targy real angle unit missile real delay real distance boolean start static method create takes unit caster, location point returns ExplodingS local ExplodingS a = ExplodingS.allocate() set a.caster = caster set a.targx = GetLocationX(point) set a.targy = GetLocationY(point) set a.start = false set a.distance = SquareRoot((a.targx - GetUnitX(a.caster)) * (a.targx - GetUnitX(a.caster)) + (a.targy - GetUnitY(a.caster)) * (a.targy - GetUnitY(a.caster))) call RemoveLocation(point) if integer(a) > a.counter then set a.counter = integer(a) endif return a endmethod method onDestroy takes nothing returns nothing call SetUnitExploded(.missile,true) call UnitApplyTimedLife(.missile,'BTLF',0.1) set .caster = null set .missile = null set .targx = 0. set .targy = 0. set .angle = 0. set .delay = 0. set .distance = 0. if integer(this) == ExplodingS.counter then set ExplodingS.counter = ExplodingS.counter - 1 endif set this = 0 endmethod endstruct private function AfterEffect takes nothing returns nothing local integer i = 1 local real x local real y local DataDamage DD loop exitwhen i > DD.counter set DD = DataDamage(i) set DD.count = DD.count + 0.2 set DD.runtime = DD.runtime - 0.2 if DD.runtime > 0. and GetUnitAbilityLevel(DD.target,BuffID) > 0 then set x = GetRandomReal(GetUnitX(DD.target)-300.,GetUnitX(DD.target)+300.) set y = GetRandomReal(GetUnitY(DD.target)-300.,GetUnitY(DD.target)+300.) call IssuePointOrder(DD.target,"move",x,y) endif if DD.count > damagerate and GetUnitAbilityLevel(DD.target,BuffID) > 0 then set DD.count = 0. call UnitDamageTarget(DD.caster,DD.target,DD.damage,false,false,AttackType,DamageType,WEAPON_TYPE_WHOKNOWS) endif if GetUnitAbilityLevel(DD.target,BuffID) < 1 or GetWidgetLife(DD.target) < .406 then set DD.caster = null set DD.target = null set DD.damage = 0. set DD.runtime = 0. set DD.count = 0. if integer(DD) == DataDamage.counter then set DataDamage.counter = DataDamage.counter - 1 endif call DD.destroy() set DD = 0 endif set i = i + 1 endloop endfunction private function Loop takes nothing returns nothing local integer i = 1 local real x local real y local group g local ExplodingS ES loop exitwhen i > ES.counter set ES = ExplodingS(i) if not ES.start then set ES.delay = ES.delay + 0.015 if ES.delay > .2 then set ES.angle = GetUnitFacing(ES.caster) set bj_groupEnumOwningPlayer = GetOwningPlayer(ES.caster) set ES.missile = CreateUnit(bj_groupEnumOwningPlayer,Missile,GetUnitX(ES.caster),GetUnitY(ES.caster),ES.angle) set ES.angle = ES.angle * bj_DEGTORAD call UnitAddAbility(ES.missile,'Amrf') call UnitRemoveAbility(ES.missile,'Amrf') call SetUnitFlyHeight(ES.missile,113.,1000.) call SetUnitAnimationByIndex(ES.caster,5) set ES.start = true endif else if ES.distance > 0. then set x = GetUnitX(ES.missile) + Cos(ES.angle)*10. set y = GetUnitY(ES.missile) + Sin(ES.angle)*10. call SetUnitX(ES.missile,x) call SetUnitY(ES.missile,y) call SetUnitFlyHeight(ES.missile,GetUnitFlyHeight(ES.missile)-1.,1000.) set ES.distance = ES.distance - 10. else set g = CreateGroup() set bj_ghoul[80] = ES.caster set bj_enumDestructableRadius = ES.targx set TempReal = ES.targy set bj_randomSubGroupChance = AoE(GetUnitAbilityLevel(ES.caster,SpellID)) set bj_groupEnumOwningPlayer = GetOwningPlayer(ES.caster) call GroupEnumUnitsInRange(g,ES.targx,ES.targy,bj_randomSubGroupChance,Condition(function DataDamage.AddStructs)) call DestroyGroup(g) call ES.destroy() set g = null endif endif set i = i + 1 endloop endfunction private function Conditions takes nothing returns boolean return GetSpellAbilityId() == SpellID endfunction private function Actions takes nothing returns nothing local unit c = GetTriggerUnit() local location l = GetSpellTargetLoc() call ExplodingS.create(c,l) set c = null set l = null endfunction function InitTrig takes nothing returns nothing set gg_trg_Exploding_Spear = CreateTrigger( ) call TriggerRegisterAnyUnitEventBJ( gg_trg_Exploding_Spear, EVENT_PLAYER_UNIT_SPELL_EFFECT ) call TriggerAddCondition( gg_trg_Exploding_Spear, Condition( function Conditions ) ) call TriggerAddAction( gg_trg_Exploding_Spear, function Actions ) call TimerStart(ESTimer,0.015,true,function Loop) call TimerStart(DamTimer,0.2,true,function AfterEffect) endfunction endscope I also think that it can be optimized a bit better as well. But as long as it works properly and no war3err errors it will be nice. The base spell is blizzard and the dummy(s) is a missile with locust and a empty model for the dummy. the buff id is generated from the FlameSID spell (Inner Fire). If you want to test it properly. Only trusted people i know will get a copy of the map im working the spell on can get a copy if they are too lazy. -Av3n |
| 05-17-2008, 05:54 AM | #2 |
You never decrement ExplodingS.counter, so you're iterating through structs that shouldn't exist. Thus, the value of ES.distance is < 0.00 when the struct doesn't exist and, well, you get the picture. |
| 05-17-2008, 06:06 AM | #3 |
O_o... I do it in the onDestroy method thanks for pointing it out though. Well anyways, I need to clarify it a bit more to the DataDamage struct. -Av3n |
