[vJASS] Enumeration In Structs

Level 29
Joined
Mar 10, 2009
Messages
5,016
Please explain how and when to destroy structs...

EDIT: Full Code posted for improvement, please suggest...

What does the spell do?...
When casted to a point an enemy unit cant get out from the AoE or vortices...any enemy caught will be trapped as well...
also it damages any ground non-structure enemy units that touches the vortices...

JASS:
//Spell Name: Confinement
//Made by: Mckill2009

//Requires: TimerUtils by Vexorian

scope Confinement initializer init

globals
    private constant integer SPELLID    = 'A000'
    private constant integer DUMMYID    = 'h001'
    private constant integer FENCE1ID   = 'h002'
    private constant integer FENCE2ID   = 'h003'
    private constant integer AURAID     = 'h000' 
    private constant real FENCESPEED    = 0.03125
    private constant attacktype ATT     = ATTACK_TYPE_PIERCE
    private constant damagetype DAM     = DAMAGE_TYPE_DEATH
    private constant real AoERange      = 400
    private constant real AoEDamage     = 80
endglobals

globals
    private unit caster
    private unit dummy
    private real damage
endglobals

private function CON_DURATION takes integer i returns real
    return 5 + i * 5.
endfunction

private function CON_DAMAGE takes integer i returns real
    return 3 + i * 5.
endfunction

private struct Con
    unit u
    unit aura
    unit dum
    unit fence1
    unit fence2
    real x
    real y
    real hurt
    real angle1
    real angle2
    real duration
    integer level
    
    static method onDamage takes nothing returns boolean
        local unit u = GetFilterUnit()
        if IsUnitType(u, UNIT_TYPE_FLYING)==false and IsUnitEnemy(caster, GetOwningPlayer(u)) and GetWidgetLife(u) > 0.405 then
            call UnitDamageTarget(caster, u, damage , false, false, ATT, DAM, null)  
        endif
        set u = null
        return false          
    endmethod
    
    static method onRange takes nothing returns boolean
        local unit u = GetFilterUnit()
        local real x1 = GetUnitX(u) - GetUnitX(dummy)
        local real y1 = GetUnitY(u) - GetUnitY(dummy)    
        local real dist = SquareRoot(x1*x1 + y1*y1)
        local real angle = Atan2(GetUnitY(dummy) - GetUnitY(u), GetUnitX(dummy) - GetUnitX(u))       
        if IsUnitType(u, UNIT_TYPE_FLYING)==false and IsUnitEnemy(caster, GetOwningPlayer(u)) and GetWidgetLife(u) > 0.405 and dist > AoERange-50 then 
            call SetUnitX(u, GetUnitX(u) + 30 * Cos(angle))
            call SetUnitY(u, GetUnitY(u) + 30 * Sin(angle))
        endif
        set u = null
        return false          
    endmethod
    
    static method onAction takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local thistype con = GetTimerData(t)
        if con.duration > 0 then
            set con.angle1 = con.angle1 + 5
            set con.angle2 = con.angle2 - 5
            set con.duration = con.duration - FENCESPEED
            call SetUnitX(con.fence1, GetUnitX(con.dum) + AoERange * Cos(con.angle1 * bj_DEGTORAD))
            call SetUnitY(con.fence1, GetUnitY(con.dum) + AoERange * Sin(con.angle1 * bj_DEGTORAD))
            call SetUnitX(con.fence2, GetUnitX(con.dum) + AoERange * Cos(con.angle2 * bj_DEGTORAD))
            call SetUnitY(con.fence2, GetUnitY(con.dum) + AoERange * Sin(con.angle2 * bj_DEGTORAD))
            set caster = con.u
            set damage = con.hurt
            set dummy = con.dum
            call GroupEnumUnitsInRange(bj_lastCreatedGroup, GetUnitX(con.fence1), GetUnitY(con.fence1), AoEDamage, Filter(function thistype.onDamage)) 
            call GroupEnumUnitsInRange(bj_lastCreatedGroup, GetUnitX(con.dum), GetUnitY(con.dum), AoERange, Filter(function thistype.onRange))
        else
            call ReleaseTimer(t)
            call UnitApplyTimedLife(con.aura, 'BTLF', 0.01)
            call UnitApplyTimedLife(con.dum, 'BTLF', 0.01)
            call UnitApplyTimedLife(con.fence1, 'BTLF', 0.01)
            call UnitApplyTimedLife(con.fence2, 'BTLF', 0.01)
        endif
        set t = null
    endmethod
    
    static method onCreate takes nothing returns thistype
        local thistype con = thistype.create()
        local timer t = NewTimer()
        set con.u = GetTriggerUnit()
        set con.x = GetSpellTargetX()
        set con.y = GetSpellTargetY()
        set con.level = GetUnitAbilityLevel(con.u, SPELLID)
        set con.aura = CreateUnit(GetOwningPlayer(con.u), AURAID, con.x, con.y, 0)
        set con.dum = CreateUnit(GetOwningPlayer(con.u), DUMMYID, con.x, con.y, 0)
        set con.fence1 = CreateUnit(GetOwningPlayer(con.u), FENCE1ID, con.x, con.y, 0)
        set con.fence2 = CreateUnit(GetOwningPlayer(con.u), FENCE2ID, con.x, con.y, 0)
        set con.duration = CON_DURATION(con.level)
        set con.hurt = CON_DAMAGE(con.level)
        set con.angle1 = 0
        set con.angle2 = 0
        call SetTimerData(t, con)
        call TimerStart(t, FENCESPEED, true, function thistype.onAction)
        set t = null
        return con
    endmethod
    
endstruct 

private function CON_CAST takes nothing returns boolean
    if GetSpellAbilityId()==SPELLID then
        call Con.onCreate()        
    endif 
    return false
endfunction

private function init takes nothing returns nothing
    local trigger t = CreateTrigger()          
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function CON_CAST))
    set t = null
endfunction

endscope
 
Last edited:
Level 11
Joined
Oct 13, 2005
Messages
233
You destroy structs when you're done using them with the .destroy method. I'm not sure why you're allocating a new instance of the struct in the onDamage method when a local unit variable would suffice.

For the purposes of when to destroy the struct, treat it like you would treat a handle. You would need to destroy that struct before the return statement unless you wanted to leak a struct instance. As I said, in this case you should avoid using a struct and instead use a local unit variable (and of course null that variable before the return statement).

As far as I can tell, the enumeration seems like it would work fine although I've never personally done it that way. If you want to avoid the use of globals, traverse the group in a loop instead of in the filter function.
 
Level 11
Joined
Oct 13, 2005
Messages
233
You never need to null a struct variable because struct variables are simply integers when run through JassHelper. .deallocate is only used if you override the .destroy method, much like the .allocate method is used when you override the .create method. Unless you override .destroy, you shouldn't need to use .deallocate
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
no, I did not say I will null a variable in struct, I was asking if its the same method as removing and nulling a location...but well if it's not then it cleared up a bit...sadly I got this strange message, something like "unable to allocate call_con" (forget if its the exact sentence) if I dont put .deallocate() before the return, the loop is running 0.03 seconds in 70 seconds just for testing btw...
 
Level 20
Joined
Jul 6, 2009
Messages
1,885
To clear things up:
allocate() assigns a unique id for the instance since each instance is an integer, representing the index of array for struct's members.
deallocate() doesn't do anything to the instance itself, it just frees up it's id so a new instance that gets allocated gets an id that's not used.
create() uses allocate() by default and that's all it does unless you override it (you can't use allocate() instead of create() since allocate() is a private method)
destroy() uses deallocate() by default, and same goes as for create() method.
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
before its like this and its giving me that bloody message, idk why it wont display anymore...

JASS:
    static method onDamage takes nothing returns boolean
        local thistype con = thistype.allocate()
        set con.u = GetFilterUnit()
        if IsUnitType(con.u, UNIT_TYPE_FLYING)==false and IsUnitEnemy(caster, GetOwningPlayer(con.u)) and GetWidgetLife(con.u) > 0.405 then
            call UnitDamageTarget(caster, con.u, damage , false, false, ATT, DAM, null)  
        endif
        return false          
    endmethod
 
Top