HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Need some help - Faked Aura

04-03-2006, 01:56 PM#1
Chuckle_Brother
I am making an activateable aura type ability for my map, but I am running into some really stupid issues. My logic SEEMS to make sense, but the aura is failing to remove the effect ability from units who are no longer eligable.

Any help is appreciated.

Edit: And before anyone mentions it, yes I could use Vexorian's excellent aura template, but I want to do this myself, since I won't learn jack if I just use a precreated template.

Collapse JASS:
constant function Trig_Favor_of_Elune_BonusSpellId takes nothing returns integer
    return 'A006'
endfunction

constant function Trig_Favor_of_Elune_SpellId takes nothing returns integer
    return 'A007'
endfunction

function Trig_Favor_of_Elune_Filter takes nothing returns boolean
    return GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0
endfunction

function Trig_Favor_of_Elune_ActiveCons takes nothing returns boolean
    return GetIssuedOrderId()==852177
endfunction

function Trig_Favor_of_Elune_PeriodicActs takes nothing returns nothing
    local timer t=GetExpiredTimer()
    local string s=GetAttachmentTable(t)
    local unit cast=GetTableUnit(s, "caster")
    local group current=CreateGroup()
    local group previous=GetTableGroup(s, "previous")
    local integer lvl=GetUnitAbilityLevel(cast, Trig_Favor_of_Elune_SpellId())
    local unit temp
    local boolexpr cons=Condition(function Trig_Favor_of_Elune_Filter)
    local group aux=CreateGroup()
    local group aux2=CreateGroup()

    if GetUnitAbilityLevel(cast, 'B000') > 0 then
        call GroupEnumUnitsInRange(current, GetUnitX(cast), GetUnitY(cast), 500, cons)
        call GroupAddGroup(previous, aux)
        loop
            set temp=FirstOfGroup(current)
            exitwhen temp==null    
            if IsUnitAlly(temp, GetOwningPlayer(cast)) then
                call UnitAddAbility(temp, Trig_Favor_of_Elune_BonusSpellId())    
                call SetUnitAbilityLevel(temp, Trig_Favor_of_Elune_BonusSpellId(),lvl)
                call GroupAddUnit(aux2, temp)                
            endif
            call GroupRemoveUnit(current, temp)
            set temp=null
        endloop
        loop
            set temp=FirstOfGroup(aux)
            exitwhen temp==null
            if IsUnitInGroup(temp, aux2) then
                call SetUnitAbilityLevel(temp, Trig_Favor_of_Elune_BonusSpellId(),lvl)
                call GroupAddUnit(previous, temp)
            else
                call GroupRemoveUnit(previous, temp)
                call UnitRemoveAbility(temp, Trig_Favor_of_Elune_BonusSpellId())
            endif
            call GroupRemoveUnit(aux, temp)
            set temp=null
        endloop
        call SetTableObject(s, "previous", previous)
    else
        loop
            set temp=FirstOfGroup(previous)
            exitwhen temp==null
            call UnitRemoveAbility(temp, Trig_Favor_of_Elune_BonusSpellId())
            call GroupRemoveUnit(previous, temp)
            set temp=null
        endloop
        call DestroyGroup(previous)
        call ClearTimer(t)
    endif
    call DestroyGroup(aux)
    call DestroyGroup(aux2)
    call DestroyGroup(current)
    set aux=null
    set aux2=null
    set previous=null
    set current=null
    set cast=null
    set t=null
endfunction

function Trig_Favor_of_Elune_ActiveActs takes nothing returns nothing
    local unit cast=GetTriggerUnit()
    local timer t=CreateTimer()
    local string s=GetAttachmentTable(t)
    local group previous=CreateGroup()
    
    call SetTableObject(s, "caster", cast)
    call SetTableObject(s, "previous", previous)
    call TriggerSleepAction(1)
    call TimerStart(t, 2, true, function Trig_Favor_of_Elune_PeriodicActs)
    set cast=null
    set t=null
    set previous=null
endfunction

//===========================================================================
function InitTrig_Favor_of_Elune takes nothing returns nothing
    set gg_trg_Favor_of_Elune = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Favor_of_Elune, EVENT_PLAYER_UNIT_ISSUED_ORDER )
    call TriggerAddCondition( gg_trg_Favor_of_Elune, Condition( function Trig_Favor_of_Elune_ActiveCons ) )
    call TriggerAddAction( gg_trg_Favor_of_Elune, function Trig_Favor_of_Elune_ActiveActs )
endfunction
04-03-2006, 02:55 PM#2
BertTheJasser
Hmm ... I think it's better to do it this way like:
Collapse JASS:
function Trig_Favor_of_Elune_PeriodicActs takes nothing returns nothing
    local timer t=GetExpiredTimer()
    local string s=GetAttachmentTable(t)
    local unit cast=GetTableUnit(s,"caster")
    local group current
    local group previous=GetTableGroup(s,"previous")
    local integer sp=Trig_Favor_of_Elune_SpellId()///Just to make it easier to read and to improve speed a very lil
    local integer lvl=GetUnitAbilityLevel(cast,s)
    local unit temp
    local boolexpr cons=Condition(function Trig_Favor_of_Elune_Filter)
    local group aux

    if(GetUnitAbilityLevel(cast, 'B000')>0)then ///What's that???? Tell me
        set aux=CreateGroup()
        set current=CreateGroup()
        set bj_groupEnumOwningPlayer=GetOwningPlayer(cast)///just for the conditions
        call GroupEnumUnitsInRange(current,GetUnitX(cast),GetUnitY(cast),500,cons)
        call GroupAddGroup(previous,aux)
        call GroupClear(previous)//this must be done, or you'll keep all your units 'as' they were in range
        loop
            set temp=FirstOfGroup(current)
            exitwhen temp==null
            if not IsUnitInGroup(temp,previous) then //wasn't in range before? -> add abilitie
                call UnitAddAbility(temp,sp)
            endif
            call SetUnitAbilityLevel(temp,sp,lvl)//just to update it every cycle
            call GroupAddUnit(previous,temp)//mark the unit for next round
            call GroupRemoveUnit(aux,temp) //because the unit is still in range, you don't need to check it in the second loop
            call GroupRemoveUnit(current,temp)//remove the unit to keep the looop going on
            set temp=null
        endloop
        //these are just the remaining units, which aren't anymore inrange
        loop
            set temp=FirstOfGroup(aux)
            exitwhen temp==null
            call UnitRemoveAbility(temp,sp)
            call GroupRemoveUnit(aux,temp)
            set temp=null
        endloop
        ///call SetTableObject(s,"previous",previous) you don't need to store this again, it's just timewaste
        call DestroyGroup(aux)
        set aux=null
        call DestroyGroup(current)
        set current=null
    else
        loop
            set temp=FirstOfGroup(previous)
            exitwhen temp==null
            call UnitRemoveAbility(temp,sp)
            call GroupRemoveUnit(previous,temp)
            set temp=null
        endloop
        call DestroyGroup(previous)
        call ClearTimer(t)
    endif
    set previous=null
    
    set cast=null
    set t=null
endfunction

but... you just forgott to clear the group >previous< so you'll keep all units which were once affected forever affected.
Thats it, I think so at least.
04-03-2006, 03:12 PM#3
Chuckle_Brother
Won't work, you are destroying 'previous'. Which is supposed to hold all the units who were given the aura effects in the previous execution of this function.

And that overall condition is a buff, because this is an immolation based ability that is activateable.
04-03-2006, 03:24 PM#4
BertTheJasser
I don't destroy the previous group, I just clear it.
04-03-2006, 03:28 PM#5
Chuckle_Brother
I meant in essence you destroy it, when it comes time for the next execution won't it be empty? So it won't know what units were in it before.

Edit: Working now, I just forgot to shunt the units who are currently being added into the previous group.
04-05-2006, 07:29 PM#6
BertTheJasser
No! I don't destroy it! I just clear it! And before I store all info in aux. So info is kept and next round can start. OK?
04-06-2006, 11:55 AM#7
Chuckle_Brother
Tried your way. And I am telling you dude, it doesn't work. It left shit on the guys, either way once I added another line to it it works fine.
04-06-2006, 05:05 PM#8
BertTheJasser
I didn't really expect it to work, cause I've done this really fast. So..

Let's do a complete rework...>>>PLEASE WAIT>>>

I hope this works now (in my way): I hope you'll test this too (I did not).
Collapse JASS:
function Elune_SpellId takes nothing returns integer
    return 'your id'
endfunction

function Elune_BuffId takes nothing returns integer
    return 'your id'
endfunction

function Elune_Radius takes real level returns real
    return 500+0*level
endfunction

function Elune_Filter takes nothing returns boolean
    return((GetWidgetLife(GetFilterUnit())>0.405)and IsUnitAlly(GetFilterUnit(),bj_groupEnumOwningPlayer))
    //here you can change if it affects allies or enemies or whatever you want
endfunction

function Elune_Actions takes nothing returns nothing
    local timer t=CreateTimer()
    local unit c=GetTriggerUnit()
    local unit u
    local group inrange=CreateGroup()
    local group aux=CreateGroup()
    local group previous=CreateGroup()
    local integer sp=Trig_Favor_of_Elune_SpellId()
    local integer lvl=GetUnitAbilityLevel(c,s)
    local real next=0
    local boolexpr cons=Condition(function Trig_Favor_of_Elune_Filter)

    call TimerStart(t,3600,false,null)//I guess, the effect won't last longer than 2h ;D
    loop
        exitwhen((GetUnitAbilityLevel(c,Elune_BuffId())==0)or(GetWidgetLife(c)<=0.405))
        if(TimerGetElapsed(t)>=next)then
            set next=next+1//the cycle when the action comes again
            set bj_groupEnumOwningPlayer=GetOwningPlayer(c)
            call GroupEnumUnitsInRange(inrange,GetUnitX(c),GetUnitY(c),Elune_Radius(lvl),cons)
            if(FirstOfGroup(previous)!=null)then
                set bj_wantDestroyGroup=false
                call GroupAddGroup(previous,aux)
                call GroupClear(previous)
            endif
            loop
                set u=FirstOfGroup(inrange)
                exitwhen u==null
                call GroupRemoveUnit(inrange,u)
                if IsUnitInGroup(u,aux) then
                    call GroupRemoveUnit(aux,u)
                else
                    call UnitAddAbility(u,sp)
                endif
                call SetUnitAbilityLevel(u,sp,lvl)
                call GroupAddUnit(previous,u)
            endloop
            //these are just the remaining units, which aren't anymore inrange
            loop
                set u=FirstOfGroup(aux)
                exitwhen u==null
                call GroupRemoveUnit(aux,u)
                call UnitRemoveAbility(u,sp)
            endloop
            call GroupClear(aux)
            call GroupClear(inrange)
        endif
        call TriggerSleepAction(0)
    endloop
    loop
        set u=FirstOfGroup(previous)
        exitwhen u==null
        call UnitRemoveAbility(u,sp)
        call GroupRemoveUnit(previous,u)
    endloop
    call DestroyTimer(t)
    set t=null
    call DestroyBoolExpr(cons)
    set cons=null
    call DestroyGroup(previous)
    set previous=null
    call DestroyGroup(aux)
    set aux=null
    call DestroyGroup(inrange)
    set inrange=null
    set c=null
endfunction

function Elune_Conditions takes nothing returns boolean
    return(Elune_SpellId()==GetSpellAbilityId())
endif

function InitTrig_Elune takes nothing returns nothing
local trigger t=CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t,Condition(function Elune_Conditions))
    call TriggerAddAction(t,function Elune_Actions)
set t=null
endfunction
04-06-2006, 07:54 PM#9
PipeDream
Collapse JASS:
    loop
        set u=FirstOfGroup(previous)
        exitwhen u==null
        call UnitRemoveAbility(u,sp)
        call GroupRemoveUnit(previous,u)
        set u=null
    endloop

You can remove the set u = null line. As long as you change u before it runs out of scope, it will not hold any memory hostage. People use "null" because it is a particularly convenient value to change to. Also, the set u = null at the end of the function is unnecessary since you exitwhen null.
04-08-2006, 07:56 AM#10
BertTheJasser
I know.
I used ChuckleBrother's code as starting resouce and was just too lazy to change. Fixed