HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Coding Help...

05-17-2008, 04:53 AM#1
Av3n
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.

Collapse 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
Pyrogasm
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
Av3n
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