Efficiency question for my buff system

Tom_Kazansky

--- wraith it ! ---
Reaction score
157
I made a buff system, here is its code, it's shortened (removed some functions):

JASS:

scope CustomBuff

globals
    constant integer BUFF_STANDARD = 0
    constant integer BUFF_STACKING = 1
    
    constant integer BUFF_DURATION_NEW = 0    //take new duration
    constant integer BUFF_DURATION_HIGH = 1 //compare old/new duration, take the higher
    constant integer BUFF_DURATION_ADD = 2    //add the old and new duration
endglobals

function interface TBuff_Event takes tBuff tb returns nothing
function interface TBuff_EventX takes tBuff tb, tBuff tbo returns nothing
function interface TBuff_EventR takes tBuff tb, unit remover returns nothing

struct tBuffAttribute
    boolean pos
    boolean neg
    boolean psy
    boolean mag
    boolean aura
    boolean univ
    integer lvl
    boolean silence
    boolean slow
    boolean abnormal
    boolean stealable
    
    integer category         = BUFF_STANDARD
    integer durType            = BUFF_DURATION_NEW
    boolean removeOnDead     = true
    
    static method create takes integer id returns thistype
        local thistype this = thistype.allocate()
        set this.pos = HaveSavedBoolean(tj_ABILITYHASH, id, RegisterBuffData_IP)
        set this.neg = HaveSavedBoolean(tj_ABILITYHASH, id, RegisterBuffData_IN)
        set this.psy = HaveSavedBoolean( tj_ABILITYHASH, id, RegisterBuffData_IPh)
        set this.mag = HaveSavedBoolean( tj_ABILITYHASH, id, RegisterBuffData_IM )
        set this.aura = HaveSavedBoolean(tj_ABILITYHASH, id, RegisterBuffData_IA)
        set this.univ = HaveSavedBoolean(tj_ABILITYHASH, id, RegisterBuffData_IU)
        set this.lvl = LoadInteger(tj_ABILITYHASH, id, RegisterBuffData_BPL)
        set this.silence = HaveSavedBoolean(tj_ABILITYHASH, id, Register_SilenceState)
        set this.slow = HaveSavedBoolean(tj_ABILITYHASH, id, Register_SlowState)
        set this.abnormal = HaveSavedBoolean(tj_ABILITYHASH, id, Register_AbnormalState)
        set this.stealable = HaveSavedBoolean(tj_ABILITYHASH, id, RegisterBuffData_IS)
        set this.durType = LoadInteger(tj_ABILITYHASH, id, RegisterBuffData_DT)
        return this
    endmethod
    
    method check takes integer lvl, integer pos, integer neg, integer psy, integer mag, integer aura, integer univ, integer abn, integer silence, integer slow returns boolean
        if ( pos==0 or (pos>0 and (pos==1)==this.pos) ) and /*
        */ ( neg==0 or (neg>0 and (neg==1)==this.neg) ) and /*
        */ ( psy==0 or (psy>0 and (psy==1)==this.psy) ) and /*
        */ ( mag==0 or (mag>0 and (mag==1)==this.mag) ) and /*
        */ ( aura==0 or (aura>0 and (aura==1)==this.aura) ) and /*
        */ ( univ==0 or (univ>0 and (univ==1)==this.univ) ) and /*
        */ ( abn==0 or (abn>0 and (abn==1)==this.abnormal) ) and /*
        */ ( silence==0 or (silence>0 and (silence==1)==this.silence) ) and /*
        */ ( slow==0 or (slow>0 and (slow==1)==this.slow )) and /*
        */ this.lvl<=lvl then
            return true
        endif
        return false
    endmethod
    
    method copy takes nothing returns thistype
        local thistype d = thistype.allocate()
        set d.pos = .pos
        set d.neg = .neg
        set d.psy = .psy
        set d.mag = .mag
        set d.aura = .aura
        set d.univ = .univ
        set d.lvl = .lvl
        set d.silence = .silence
        set d.slow = .slow
        set d.abnormal = .abnormal
        set d.stealable = .stealable
        set d.category = .category
        set d.durType = .durType
        set d.removeOnDead = .removeOnDead
        return d
    endmethod
endstruct

struct tBuff
    //_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
    static                 thistype            theList
    //------------------------------------------------------------------
                        unit                caster
                        unit                target
                        integer                id
                        integer                lvl
                        string                bonus
                        string                bonusEx
                        real                dur        // -1: not check
                        real                baseDur //
    //------------------------------------------------------------------
                        
                        real                progress    = 0.
                        real                tickTime    = BUFF_PERIOD
                        
                        integer                data        = 0    
                        boolean                firstTick    = true
                        
                        thistype            leadRef        = 0
                        Table                refData        = 0
                        integer                refIndex    = 0
                        integer                refPos        = 0
                        integer                refMax        = 0
                        integer                refCount    = 0
                        
                        tBuffAttribute        atr            = 0
    //------------------------------------------------------------------
                        TBuff_Event            onTick        = 0
                        TBuff_Event            onEnd        = 0
                        TBuff_EventR        onRemove    = 0
                        TBuff_EventX        onReApply    = 0
                        
                        TBuff_EventR        onKill        = 0
                        TBuff_EventR        onDead        = 0
                        
                        TBuff_Event            onDetach    = 0
                        TBuff_Event         doAttach    = 0    //mainly for data of buff
                        TBuff_EventX        doDuplicate    = 0    //mainly for data of buff
    //------------------------------------------------------------------
    implement LinkedList //Kenny's
    //---
    private method periodic takes nothing returns nothing
        //-----
        if GetUnitTypeId(.target)==0 then
            call .detachThis()//call .stopPeriodic()
            call .onEnd.evaluate(this)
            call .destroy()
            return
        endif
        //-----
        if .dur > 0. then
            set .dur = .dur - BUFF_PERIOD
        endif
        if .onTick != 0 then
            set .progress = .progress + BUFF_PERIOD
            if .progress == .tickTime or .progress > .tickTime then
                set .progress = .progress - .tickTime
                call .onTick.evaluate(this)
            endif
        endif
        if .firstTick then
            set .firstTick = false
            return
        endif
        if (.dur>-1 and .dur<=0.000001) or GetUnitAbilityLevel(.target,.id)==0 then
            call this.terminate()
        endif
    endmethod
    
    static method HandlePeriodic takes nothing returns nothing
        local thistype this = thistype.theList.head
        local thistype tmp
        loop
            exitwhen 0==this
            set tmp = this.next
            call this.periodic()
            set this = tmp
        endloop
    endmethod
    
    static method Apply takes GBD gd returns thistype
        local thistype this
        local thistype ret
        local tBuff_Apply ufunc
        local tBuff_Apply func
        local integer i
        local integer j

        set this = thistype.create()
        set this.caster = gd.source
        set this.target = gd.target
        set this.id     = gd.id
        set this.lvl    = gd.lvl
        set this.bonus  = gd.bonus
        set this.bonusEx = gd.bonusEx
        set this.dur     = gd.dur
        set this.baseDur= gd.baseDur
        
        set this.atr = gd.bAtr.copy()
        
        set this.refMax = gd.refMax
        set this.refIndex = gd.refIndex
        
        set this.tickTime = gd.tickTime
        set this.onTick = gd.onTick
        set this.onRemove = gd.onRemove
        set this.onEnd = gd.onEnd
        set this.onReApply = gd.onReApply
        set this.onDetach = gd.onDetach
        set this.doAttach = gd.doAttach
        set this.doDuplicate = gd.doDuplicate
        set this.onKill = gd.onKill
        set this.onDead = gd.onDead
        
        if gd.chkEventFunc then
            // event onBuff Apply
            set ufunc = tBuff_Apply.Data(GetUnitId(gd.source))
            set i = 0
            set j = ufunc.size
            loop
                exitwhen i==ufunc.size
                set func = ufunc<i>
                if func.cast then
                    call func.evt.evaluate(gd,func.spellId,func.spellLv)
                    if gd.target==null then
                        if not gd.permanent then
                            call gd.destroy()
                        endif
                        return 0
                    endif
                endif
                if j!=ufunc.size then
                    set i = i - 1
                    set j = ufunc.size
                endif
                set i = i + 1
            endloop
            
            set ufunc = tBuff_Apply.Data(GetUnitId(gd.target))
            set i = 0
            set j = ufunc.size
            loop
                exitwhen i==ufunc.size
                set func = ufunc<i>
                if not func.cast then
                    call func.evt.evaluate(gd,func.spellId,func.spellLv)
                    if gd.target==null then
                        if not gd.permanent then
                            call gd.destroy()
                        endif
                        return 0
                    endif
                endif
                if j!=ufunc.size then
                    set i = i - 1
                    set j = ufunc.size
                endif
                set i = i + 1
            endloop
        endif
        
        if gd.bAtr.category==BUFF_STACKING then
            if gd.refMax==0 then
                set ret = this.AddStackIndex()
            else
                set ret = this.AddStack()
            endif
        else
            set ret = this.Add()
        endif
        
        if not gd.permanent then
            call gd.destroy()
        endif
        return ret
    endmethod
    
endstruct

endscope
</i></i>

[/spoiler]
this method:
JASS:

//....
    static method Apply takes GBD gd returns thistype
        local thistype this
        local thistype ret
        local tBuff_Apply ufunc
        local tBuff_Apply func
        local integer i
        local integer j

        set this = thistype.create()
        set this.caster = gd.source
        set this.target = gd.target
        set this.id     = gd.id
        set this.lvl    = gd.lvl
        set this.bonus  = gd.bonus
        set this.bonusEx = gd.bonusEx
        set this.dur     = gd.dur
        set this.baseDur= gd.baseDur
        
        set this.atr = gd.bAtr.copy()
        
        set this.refMax = gd.refMax
        set this.refIndex = gd.refIndex
        
        set this.tickTime = gd.tickTime
        set this.onTick = gd.onTick
        set this.onRemove = gd.onRemove
        set this.onEnd = gd.onEnd
        set this.onReApply = gd.onReApply
        set this.onDetach = gd.onDetach
        set this.doAttach = gd.doAttach
        set this.doDuplicate = gd.doDuplicate
        set this.onKill = gd.onKill
        set this.onDead = gd.onDead
        
        if gd.chkEventFunc then
            // event onBuff Apply
            set ufunc = tBuff_Apply.Data(GetUnitId(gd.source))
            set i = 0
            set j = ufunc.size
            loop
                exitwhen i==ufunc.size
                set func = ufunc<i>
                if func.cast then
                    call func.evt.evaluate(gd,func.spellId,func.spellLv)
                    if gd.target==null then
                        if not gd.permanent then
                            call gd.destroy()
                        endif
                        return 0
                    endif
                endif
                if j!=ufunc.size then
                    set i = i - 1
                    set j = ufunc.size
                endif
                set i = i + 1
            endloop
            
            set ufunc = tBuff_Apply.Data(GetUnitId(gd.target))
            set i = 0
            set j = ufunc.size
            loop
                exitwhen i==ufunc.size
                set func = ufunc<i>
                if not func.cast then
                    call func.evt.evaluate(gd,func.spellId,func.spellLv)
                    if gd.target==null then
                        if not gd.permanent then
                            call gd.destroy()
                        endif
                        return 0
                    endif
                endif
                if j!=ufunc.size then
                    set i = i - 1
                    set j = ufunc.size
                endif
                set i = i + 1
            endloop
        endif
        
        if gd.bAtr.category==BUFF_STACKING then
            if gd.refMax==0 then
                set ret = this.AddStackIndex()
            else
                set ret = this.AddStack()
            endif
        else
            set ret = this.Add()
        endif
        
        if not gd.permanent then
            call gd.destroy()
        endif
        return ret
    endmethod
</i></i>


this method take one argument of type GBD (Generic Buff Data)

JASS:

struct GBD //General Buff Data
    static thistype glb = 0
    unit source
    unit target
    integer id
    integer lvl                = 1
    string bonus
    string bonusEx            //bonus for headRef (Master Stack)
    real dur                = -1
    real baseDur            = -1
    
    integer refIndex        = 0
    integer refMax            = 0
    
    tBuffAttribute bAtr
    
    real tickTime            = 0.
    TBuff_Event    onTick            = 0
    TBuff_Event onEnd            = 0
    TBuff_EventR onRemove        = 0
    TBuff_EventX onReApply        = 0
    TBuff_Event onDetach        = 0
    TBuff_Event doAttach        = 0
    TBuff_EventX doDuplicate    = 0
    
    TBuff_Event onKill            = 0
    TBuff_Event    onDead            = 0
    
    integer srcAbi          = 0
    integer srcAbilvl       = 1
    integer srcAbiElement   = SPELL_ELEMENT_NON
    integer srcAbiType      = SPELL_TYPE_NON
    integer affectType      = SPELL_AFFECT_STarget
    
    boolean chkEventFunc    = true    
    boolean permanent        = false
    
    method destroy takes nothing returns nothing
        call this.bAtr.destroy()
        call this.deallocate()
    endmethod
    
    method operator Dur= takes real r returns nothing
        set this.dur = r
        set this.baseDur = r
    endmethod
    
    static method create takes unit c, unit a, integer id, string bonus, real dur returns thistype
        local thistype this = thistype.allocate()
        set this.source = c
        set this.target = a
        set this.id = id
        set this.bonus = bonus
        if dur&gt;0 then
            set this.dur = dur
            set this.baseDur = dur
        endif
        set this.bAtr = tBuffAttribute.create(id)
        return this
    endmethod
    
    static method createS takes unit c, unit a, integer id, string bonus, real dur, integer sMax returns thistype
        local thistype this = thistype.allocate()
        set this.source = c
        set this.target = a
        set this.id = id
        set this.bonus = bonus
        if dur&gt;0 then
            set this.dur = dur
            set this.baseDur = dur
        endif
        set this.refMax = sMax
        set this.bAtr = tBuffAttribute.create(id)
        set this.bAtr.category = BUFF_STACKING
        return this
    endmethod
endstruct


GBD is used to pass data to "event functions" (function interface), see the chkEventFunc block.
problem I ran into: code in these "event functions" could change the data in the GBD so sometime it's NOT good.

example:
- a unit stomps the ground, Stun is applied to nearby enemies
- one of affected units (let call it "A") has "stun duration reduction"; after applied for "A", duration is changed.
- if it's the last unit: no problem. if it's not the last unit: duration is changed, so... :(

that's example for "duration", there also case for "bonus" (unit/hero stats)

solutions I think of:

- re-set the duration/bonus before applying to new unit (currently using this)

- make a copy of GBD
JASS:

//....
    static method Apply takes GBD gd returns thistype
        local thistype this
        local thistype ret
        local tBuff_Apply ufunc
        local tBuff_Apply func
        local integer i
        local integer j

        set gd = gd.Copy()

        set this = thistype.create()
        set this.caster = gd.source
        set this.target = gd.target
        set this.id     = gd.id
        set this.lvl    = gd.lvl
        set this.bonus  = gd.bonus
        set this.bonusEx = gd.bonusEx
        set this.dur     = gd.dur
        set this.baseDur= gd.baseDur
        
        //.........

        call gd.destroy() // this &quot;gd&quot; is the copy

        return ret
    endmethod


GBD struct has many members, calling a function to copy those would take a little bit of performance, right? it's fine or just ONE call but what if there are 10 or 20 or more? what's your opinions?

thanks for reading!
 

Dirac

22710180
Reaction score
147
How do I say this without sounding rude...
"Delete the whole code"
... argh failed

Seriously you have so much overhead it makes my eyes hurt, you're using a hashtable for unit handles instead of a indexing system for unit id's???
Why are you using kenny's linked list?
Can a buff be both positive and negative? or be none at the same time? because you created a boolean for both possibilities, instead use only one named "isBuffPositive"
Can a buff have several types at the same time? magical + universal + physical? you created a boolean for each type, why not just create an integer variable name "buffType" and have a set of globals that determine which integer is which type
constant integer BUFF_TYPE_MAGICAL = 1
constant integer BUFF_TYPE_UNIVERSAL = 2
Why isn't this using TimerUtils?
Why SO MANY function interfaces? Did you know that they heavily increase map size and greatly reduce code performance?

This system could be done using LinkedListModule + Table + TimerUtils and it would have the following features:
-Double free protection
-unit has buff lookup with O(1) complexity
-No function interfaces whatsoever
-Wouldn't need a periodic timer, just 1 timer per buff.
-Dynamic capacities (you would be able to create buffs that doesn't affect the unit until applied)

If you really worry about performance then follow my suggestion.
 

Tom_Kazansky

--- wraith it ! ---
Reaction score
157
> How do I say this without sounding rude... "Delete the whole code"

it's not rude if it's necessary.

> Seriously you have so much overhead it makes my eyes hurt, you're using a hashtable for unit handles instead of a indexing system for unit id's???

I did use indexing system (AutoIndex) I use hashtable for buffs.

> Why are you using kenny's linked list?

isn't it good enough?

>Can a buff be both positive and negative? or be none at the same time? because you created a boolean for both possibilities, instead use only one named "isBuffPositive"
>Can a buff have several types at the same time? magical + universal + physical? you created a boolean for each type, why not just create an integer variable name "buffType" and have a >set of globals that determine which integer is which type


well... I didn't think of this :(

>Why isn't this using TimerUtils?

I'm worry about using up the timers. I'm using "Red-flavor"

> Why SO MANY function interfaces? Did you know that they heavily increase map size and greatly reduce code performance?

I didn't know about "heavily" and "greatly" :banghead:

about why I use function interfaces:
JASS:

struct DOT
    real dmg
    integer dmgType
    string color = &quot;&quot;
    string sfx = &quot;&quot;
    string sfxa = &quot;&quot;
    TBuff_Event onEnd
    
    static method DoEnd takes tBuff tb returns nothing
        local thistype this = tb.data
        call this.onEnd.evaluate(tb)
        call this.destroy()
    endmethod
    
    static method DoInterval takes tBuff tb returns nothing
        local thistype this = tb.data
        local GD gd = GD.create()
        
        set gd.source = tb.caster
        set gd.target = tb.target
        set gd.damage = .dmg
        set gd.atkType = tj_ATTACK_TYPE_DOT
        set gd.dmgType = .dmgType
        set gd.resType = GetResistForDamage(.dmgType)
        set gd.isrng = true
        set gd.dmgMod = DAMAGE_MODIFIER_NON
        call UnitDamageUnit( gd )
        
        if .color != &quot;&quot; then
            call NewTextTag( .color+I2S(R2I(.dmg))+&quot;|r&quot;,10, GetUnitX(tb.target), GetUnitY(tb.target),GetUnitFlyHeight(tb.target), 150, 90,2,1, true)
        endif
    endmethod
    
    static method DoDup takes tBuff tb, tBuff tbo returns nothing
        local thistype this = thistype.create()
        local thistype th = tbo.data
        set this.dmg = th.dmg
        set this.dmgType = th.dmgType
        set this.color = th.color
        set this.sfx = th.sfx
        set this.sfxa = th.sfxa
        set this.onEnd = th.onEnd
        set tb.data = this
    endmethod
    
    static method Do takes GBD gbd, real dmg, integer dmgtp, real interval, string color, string sfx, string sfxa returns nothing
        local thistype this
        local tBuff tb
        local TBuff_Event end = gbd.onEnd
        set gbd.onEnd = thistype.DoEnd
        set gbd.srcAbiType = SPELL_TYPE_DOT
        set gbd.tickTime = interval
        set gbd.onTick = thistype.DoInterval
        set gbd.doDuplicate = thistype.DoDup
        set tb = tBuff.Apply(gbd)
        if tb==0 then
            return
        endif
        
        set this = tb.data
        if this==0 then
            set this = thistype.create()
            set tb.data = this
        endif
        set this.dmg = dmg
        set this.dmgType = dmgtp
        set this.color = color
        set this.sfx = sfx
        set this.sfxa = sfxa
        set this.onEnd = end
        set gbd.onEnd = end
    endmethod
    
endstruct


e.g:
  • unit A causes DOT "X" to unit B
  • now a spell casts on B that spreads the "X" DOT to nearby units.
  • copy buff X is no problem right? but what about the DOT data?
  • so I use the event doDuplicate to copy the DOT data

This system could be done using LinkedListModule + Table + TimerUtils and it would have the following features:
-Double free protection
-unit has buff lookup with O(1) complexity
-No function interfaces whatsoever
-Wouldn't need a periodic timer, just 1 timer per buff.
-Dynamic capacities (you would be able to create buffs that doesn't affect the unit until applied)

If you really worry about performance then follow my suggestion.

ok but the bold line is gonna give me a headache
 

luorax

Invasion in Duskwood
Reaction score
67
Well, I used to be a BuffStruct user, but I figured out that creating a struct for each buff is really unnecessary. This simple snippet I made handles buffs correctly, and I can still attach data to them if I want to:

JASS:
library BuffSystem uses FireCode,TimerUtils

    struct Buff extends array
        implement Alloc
        readonly unit owner
        private thistype next
        private thistype prev
        
        integer buffAbility
        integer buffId
        integer buffData
        real buffDuration
        boolexpr buffRemove
        boolexpr buffApply
        
        static integer data
        static unit unit
        
        static method getBuff takes unit u,integer buffid returns thistype
            local thistype this=thistype(0)
            loop
                set this=this.next
                exitwhen this==0
                if this.buffId==buffid and this.owner==u then
                    return this
                endif
            endloop
            return 0
        endmethod
        private static method fireEvent takes boolexpr b,unit u,integer d returns nothing
            local unit oldUnit=thistype.unit
            local integer oldData=thistype.data
            set thistype.unit=u
            set thistype.data=d
            call FireCondition(b)
            set thistype.unit=oldUnit
            set thistype.data=oldData
            set b=null
            set u=null
        endmethod
        static method addBuff takes unit u,integer abil,integer buffid,real dur,boolexpr add,boolexpr rem, integer dat returns thistype
            local thistype this=thistype.getBuff(u,buffid)
            if this==0 then
                set this=thistype.allocate()
                set thistype(0).next.prev=this
                set this.next=thistype(0).next
                set thistype(0).next=this
                set this.prev=thistype(0)
                set this.owner=u
            else
                if this.buffRemove!=null then
                    call thistype.fireEvent(this.buffRemove,this.owner,this.buffData)
                endif
            endif
            set this.buffAbility=abil
            set this.buffId=buffid
            set this.buffData=dat
            set this.buffDuration=dur
            set this.buffRemove=rem
            set this.buffApply=add
            call UnitAddAbility(this.owner,this.buffAbility)
            call UnitMakeAbilityPermanent(this.owner,true,this.buffAbility)
            if this.buffApply!=null then
                call thistype.fireEvent(this.buffApply,this.owner,this.buffData)
            endif
            return this
        endmethod
        method remove takes nothing returns nothing
            set this.prev.next=this.next
            set this.next.prev=this.prev
            call UnitMakeAbilityPermanent(this.owner,false,this.buffAbility)
            call UnitRemoveAbility(this.owner,this.buffAbility)
            call UnitRemoveAbility(this.owner,this.buffId)
            if this.buffRemove!=null then
                call thistype.fireEvent(this.buffRemove,this.owner,this.buffData)
            endif
            call this.deallocate()
        endmethod
        static method removeBuff takes unit u,integer buffid returns boolean
            local thistype this=thistype.getBuff(u,buffid)
            if this&gt;0 then
                call this.remove()
                return true
            endif
            return false
        endmethod
        static method setDuration takes unit u,integer buffid,real dur returns boolean
            local thistype this=thistype.getBuff(u,buffid)
            if this&gt;0 then
                set this.buffDuration=dur
                return true
            endif
            return false
        endmethod
        static method isActive takes unit u,integer buffid returns boolean
            return GetUnitAbilityLevel(u,buffid)==1
        endmethod
        static method removeAll takes unit u returns nothing
            local thistype this=thistype(0).next
            loop
                exitwhen this==0
                set this=this.next
                if this.prev.owner==u then
                    call this.prev.remove()
                endif
            endloop
        endmethod
        static method iterate takes nothing returns nothing
            local thistype this=thistype(0)
            loop
                set this=this.next
                exitwhen this==0
                set this.buffDuration=this.buffDuration-.05
                if this.buffDuration&lt;=0. or not UnitAlive(this.owner) then
                    call this.remove()
                endif
            endloop
        endmethod
        private static method onInit takes nothing returns nothing
            call TimerStart(NewTimer(),.05,true,function thistype.iterate)
        endmethod
    endstruct
    //-----------------------------------------------------------
    // Function Wrappers
    function UnitAddBuff takes unit u,integer abil,integer id,real dur,boolexpr add,boolexpr rem,integer data returns BuffStruct
        return Buff.addBuff(u,abil,id,dur,add,rem,data)
    endfunction
    function UnitRemoveBuff takes unit u,integer buffid returns boolean
        return Buff.removeBuff(u,buffid)
    endfunction
    function UnitSetBuffTime takes unit u,integer buffid,real dur returns boolean
        return Buff.setDuration(u,buffid,dur)
    endfunction
    function UnitRemoveAllBuffs takes unit u returns nothing
        call Buff.removeAll(u)
    endfunction
    function GetBuffUnit takes nothing returns unit
        return Buff.unit
    endfunction
    function GetBuffData takes nothing returns integer
        return Buff.data
    endfunction
endlibrary
 

Tom_Kazansky

--- wraith it ! ---
Reaction score
157
ok, I will check that.

about function interface, can I use triggers instead? or they're triggers?
 

Dirac

22710180
Reaction score
147
they're triggers.
Use a module instead.

>Need a Linked List
>Use Alloc instead of LinkedListModule
>Genius
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top