HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Why does it leak?

06-08-2006, 02:08 PM#1
StockBreak
Hi all, I made an ability similar to Fan of Knives, but is seems to leak after some uses, why? Here is the code:
Collapse JASS:
function Trig_Ventaglio_di_Pugnali_Conditions takes nothing returns boolean
    if ( not ( GetSpellAbilityId() == 'A00C' ) ) then
        return false
    endif
    return true
endfunction

function Trig_Ventaglio_di_Pugnali_Group_Conditions takes nothing returns boolean
    if ( not ( IsUnitAlly( GetFilterUnit(  ), GetOwningPlayer( GetTriggerUnit(  ) ) ) == false ) ) then
        return false
    endif
    if ( not ( IsUnitDeadBJ( GetFilterUnit(  ) ) == false ) ) then
        return false
    endif
    return true
endfunction

function Trig_Ventaglio_di_Pugnali_Group_Actions takes nothing returns nothing
    local unit assassin = GetTriggerUnit(  )
    local location assassinLoc = GetUnitLoc( assassin )
    local unit dummyArcher = CreateUnitAtLoc( GetOwningPlayer( assassin ), 'e002', assassinLoc, bj_UNIT_FACING )
    local unit target = GetEnumUnit(  )

    call UnitApplyTimedLife( dummyArcher, 'BTLF', 2.00 )
    call IssueTargetOrderBJ( dummyArcher, "attackonce", target )

    set assassin = null
    call RemoveLocation( assassinLoc )
    set dummyArcher = null
    set target = null
endfunction

function Trig_Ventaglio_di_Pugnali_Actions takes nothing returns nothing
    local unit assassin = GetTriggerUnit(  )
    local location assassinLoc = GetUnitLoc( assassin )
    local group pugnalate = GetUnitsInRangeOfLocMatching( 20000, assassinLoc, Condition( function Trig_Ventaglio_di_Pugnali_Group_Conditions ) )

    call DisplayTextToForce( GetPlayersAll(  ), I2S( CountUnitsInGroup( pugnalate ) ) )
    call ForGroup( pugnalate, function Trig_Ventaglio_di_Pugnali_Group_Actions )

    set assassin = null
    call RemoveLocation( assassinLoc )
    call DestroyGroup( pugnalate )
endfunction

//===========================================================================
function InitTrig_Ventaglio_di_Pugnali takes nothing returns nothing
    set gg_trg_Ventaglio_di_Pugnali = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Ventaglio_di_Pugnali, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Ventaglio_di_Pugnali, Condition( function Trig_Ventaglio_di_Pugnali_Conditions ) )
    call TriggerAddAction( gg_trg_Ventaglio_di_Pugnali, function Trig_Ventaglio_di_Pugnali_Actions )
endfunction


Another thing i noticed: it seems that not all the times an archer is created FOR EACH unit in group (I mean that sometimes some units are not hit even if they're in group, why?). Thank you.
06-08-2006, 02:14 PM#2
aquilla
You forgot to null assassinLoc in 2 functions, and pugnalate in one of those. Also, Condition( function Trig_Ventaglio_di_Pugnali_Group_Conditions ) creates a new boolexpr which will leak as it's not destroyed

There is a much neater way in JASS of doing things like these by using a loop and GetFirstOfGroup()

Other things that could be improved are the use of BJ functions and locations (use GetUnitX and GetUnitY instead)

Edit: Oh, Blade's right. And since I'm extremely bored, hope it's not too much, I wrote this;
Collapse JASS:
function Trig_Ventaglio_di_Pugnali_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A00C'
endfunction

function Trig_Ventaglio_di_Pugnali_Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local player p = GetOwningPlayer(u)
    local real x = GetUnitX(u) // instead of GetUnitLoc
    local real y = GetUnitY(u)
    local group g = CreateGroup()
    local unit f // the unit we filter
    local unit d // dummy archer
    call GroupEnumUnitsInRange(g, x, y, 20000, null) // add all units to group
    loop
        set f = FirstOfGroup(g) //pick a unit
        exitwhen f == null // end the loop when there are no more units in the group
        if not IsUnitAlly(f, p) and GetWidgetLife(f) > 0 then // check if the unit we picked is an enemy and is alive
            set d = CreateUnit(p, 'e002', x, y, 0)
            call UnitApplyTimedLife(d, 'BTLF', 2)
            call IssueTargetOrder(d, "attackonce", f)
        endif
        call GroupRemoveUnit(g, f) // remove the unit so it doesn't get picked again
    endloop
    call DestroyGroup(g) // clean up
    set u = null
    set p = null
    set g = null
    set f = null
    set d = null
endfunction

//===========================================================================
function InitTrig_Ventaglio_di_Pugnali takes nothing returns nothing
    local trigger t = CreateTrigger() // don't use a local trigger if you want to be able to destroy/disable/etc it
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function Trig_Ventaglio_di_Pugnali_Conditions))
    call TriggerAddAction(t, function Trig_Ventaglio_di_Pugnali_Actions)
    set t = null
endfunction

06-08-2006, 02:15 PM#3
Blade.dk
No, the BJ group enumeration functions destroys the boolexpr value passed to them.
06-08-2006, 03:29 PM#4
Vexorian
not-set to null leaks for locations and groups are apparentally the only leaks there
06-08-2006, 03:45 PM#5
StockBreak
Thank you all for help! I though that things such as Locations / Groups didn't need to be nullified (just destroyed). What about the other fact (sometimes not all the units in range are picked)?
06-08-2006, 03:59 PM#6
Vexorian
Give an abomination model to the dummy so you can verify if the cause is units not getting picked or dummy units not being able to attack