• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[System] Trigger Stack

Level 7
Joined
Apr 30, 2011
Messages
359
JASS:
//========================================================================================
//
//      Trigger Stack
//      -*- overcold_ice -*-
//
//     -[*] Requirements:
//          - JNGP
//          - latest version of JassHelper
//
//     -[*] Optional Requirements:
//          - /*New*/ Table             hiveworkshop.com/forums/showthread.php?t=188084
//
//          For your advanced trigger 'variable'
//      This system provides easier and optimized 'advanced' trigger variable type.
//      Doesn't support any TriggerSleepAction/PolledWait.
//
//     -[*] API:
//
//          type triggerstack       extends integer
//          type triggerstackaction extends integer
//
//          function TSRegNullEvent takes nothing returns triggerstack
//              registers a new no-event trigger
//
//          function TSReg$EVENT$Event takes $REQUIRED_ARGUMENTS$ returns triggerstack
//              $EVENT$                 -> TriggerRegister$EVENT$ (from natives)
//                                          ex: TriggerRegisterDeathEvent
//                                           -> TSRegDeathEvent
//                                          ex: TriggerRegisterEnterRegion
//                                           -> TSRegEnterRegionEvent (add "Event" in this case)
//              $REQUIRED_ARGUMENTS$    -> its arguments other than trigger,
//                                         in that same order
//
//          function TSUnregEvent takes triggerstack ts returns nothing
//              unregisters a triggerstack (destroys it in other word)
//
//          function TSAddAction takes triggerstack ts, code c returns triggerstackaction
//              adds an action (actually, condition) to the triggerstack
//
//          function TSRemoveAction takes triggerstack ts, triggerstackaction tsa returns nothing
//              removes an action from the triggerstack
//
//          function TSEnable takes triggerstack ts, boolean enabled returns nothing
//              enable if enabled = true, or disable it (just like ordinary trigger's
//              enable/disable)
//
//          function TSIsEnabled takes triggerstack ts returns boolean
//              return true if the triggerstack is enabled, otherwise false
//
//          function TSExecute takes triggerstack ts returns nothing
//              execute a triggerstack, ignoring whether the triggerstack is enabled
//              or disabled
//
//     -[*] Required Example:
/*
            // . . .
            local triggerstack ts1 = TSRegNullEvent()
            local triggerstack ts2 = TSRegPlayerUnitEvent(Player(0), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
            local triggerstackaction a1 = TSAddAction(ts1, function.onEffect2)
            local triggerstackaction a2 = TSAddAction(ts2, function.onEffect1)
            
            if TSIsEnabled(ts1) then
                call TSEnable(ts1, false)
            endif
            // . . .
*/
//========================================================================================
library TriggerStack requires optional /*New*/Table
    
    type triggerstack       extends integer
    type triggerstackaction extends integer
    
    globals
        private integer tsc  = 0
        private integer tstc = 0
        private integer tsac = 0
        
        private key tsins
        private key tstrg
        private key tsevn
        private key tsact
        private key tsenb
        
        private key lln
        private key llp
        private key lll
        
        private key tscon
        private key tscow
        
        private constant string B = "B"
        private constant string H = "H"
        private constant string R = "R"
        private constant string S = "S"
    endglobals
    
    static if LIBRARY_Table then
        private module TableInit
            private static method onInit takes nothing returns nothing
                set .t = TableArray [51]
            endmethod
        endmodule
    endif
    
    private struct T extends array
        static if LIBRARY_Table then
            static TableArray t
            implement TableInit
        else
            static hashtable  t = InitHashtable()
        endif
    endstruct
    
    private function TriggerStackAction takes nothing returns boolean
        local integer  i = GetHandleId(GetTriggeringTrigger())
        local integer  l
        local trigger  t = CreateTrigger()
        
        static if LIBRARY_Table then
            set i = T.t [tsins] [i]
            set l = T.t [lll]   [i]
        else
            set i = LoadInteger(T.t, tsins, i)
            set l = LoadInteger(T.t,   lll, i)
        endif
        
        loop
            exitwhen l == 0
            
            static if LIBRARY_Table then
                if T.t [tsenb].boolean [l] then
                    call TriggerAddCondition(t, T.t [tsact].boolexpr [l])
                    call TriggerEvaluate(t)
                    call TriggerClearConditions(t)
                endif
            else
                if LoadBoolean(T.t, tsenb, l) then
                    call TriggerAddCondition(t, LoadBoolexprHandle(T.t, tsact, l))
                    call TriggerEvaluate(t)
                    call TriggerClearConditions(t)
                endif
            endif
            
            static if LIBRARY_Table then
                set i = T.t [llp] [l]
            else
                set i = LoadInteger(T.t, llp, l)
            endif
        endloop
        
        call DestroyTrigger(t)
        set t = null
        
        return false
    endfunction
    
    private function TriggerStackCreate takes nothing returns integer
        local integer  this
        
        static if LIBRARY_Table then
            set this = T.t [lll] [0]
        else
            set this = LoadInteger(T.t, lll, 0)
        endif
        
        if this == 0 then
            set tstc  = tstc + 1
            set this  = tstc
        else
            static if LIBRARY_Table then
                set T.t [lll] [0] = T.t [lll] [this]
                call T.t [lll].remove(this)
            else
                call SaveInteger(T.t, lll, 0, LoadInteger(T.t, lll, this))
                call RemoveSavedInteger(T.t, lll, this)
            endif
        endif
        
        static if LIBRARY_Table then
            set T.t [tstrg].trigger [this] = CreateTrigger()
            set T.t [tsins] [GetHandleId(T.t [tstrg].trigger [this])] = this
            call TriggerAddCondition(T.t [tstrg].trigger [this], Condition(function TriggerStackAction))
        else
            call SaveTriggerHandle(T.t, tstrg, this, CreateTrigger())
            call SaveInteger(T.t, tsins, GetHandleId(LoadTriggerHandle(T.t, tstrg, this)), this)
            call TriggerAddCondition(LoadTriggerHandle(T.t, tstrg, this), Condition(function TriggerStackAction))
        endif
        
        return this
    endfunction
    
    private function TriggerStackDestroy takes integer this returns nothing
        static if LIBRARY_Table then
            set T.t [lll] [this] = T.t [lll] [0]
            set T.t [lll]    [0] = this
            
            call TriggerClearConditions(T.t [tstrg].trigger [this])
            call DestroyTrigger(T.t [tstrg].trigger [this])
            call T.t [tsins].remove(GetHandleId(T.t [tstrg].trigger [this]))
            call T.t [tstrg].handle.remove(this)
        else
            call SaveInteger(T.t, lll, this, LoadInteger(T.t, lll, 0)
            call SaveInteger(T.t, lll,    0, this)
            
            call TriggerClearConditions(LoadTriggerHandle(T.t, tstrg, this)
            call DestroyTrigger(LoadTriggerHandle(T.t, tstrg, this))
            call RemoveSavedInteger(T.t, tsins, GetHandleId(LoadTriggerHandle(T.t, tstrg, this)))
            call RemoveSavedHandle(T.t, tstrg, this)
        endif
    endfunction
    
    private function TriggerStackAdd takes integer ts returns integer
        local integer this
        
        static if LIBRARY_Table then
            set this = T.t [lln] [0]
        else
            set this = LoadInteger(T.t, lln, 0)
        endif
        
        if this == 0 then
            set tsc  = tsc + 1
            set this = tsc
        else
            static if LIBRARY_Table then
                set T.t [lln] [0] = T.t [lln] [this]
            else
                call SaveInteger(T.t, lln, 0, LoadInteger(T.t, lln, this)
            endif
        endif
        
        static if LIBRARY_Table then
            if T.t [lll] [ts] == 0 then
                set T.t [lll] [ts]         = -ts
            endif
            
            set T.t [llp] [this]           = T.t [lll] [ts]
            set T.t [lln] [this]           = -ts
            set T.t [lln] [T.t [lll] [ts]] = this
            set T.t [lll] [ts]             = this
        else
            if LoadInteger(T.t, lll, ts) == 0 then
                call SaveInteger(T.t, lll, ts, -ts)
            endif
            
            call SaveInteger(T.t, llp, this, LoadInteger(T.t, lll, ts))
            call SaveInteger(T.t, lln, this, -ts)
            call SaveInteger(T.t, lln, LoadInteger(T.t, lll, ts), this)
            call SaveInteger(T.t, lll,   ts, this)
        endif
        
        return this
    endfunction
    
    private function TriggerStackRemove takes integer ts, integer this returns nothing
        static if LIBRARY_Table then
            if T.t [lln] [this] == -ts then
                if T.t [llp] [this] == -ts then
                    call TriggerStackDestroy(ts)
                else
                    set T.t [lll] [ts] = T.t [llp] [this]
                    set T.t [lln] [T.t [llp] [this]] = -ts
                endif
            else
                set T.t [lln] [T.t [llp] [this]] = T.t [lln] [this]
                set T.t [llp] [T.t [lln] [this]] = T.t [llp] [this]
            endif
            
            call T.t [llp].remove(this)
            set T.t [lln] [this] = T.t [lln] [0]
            set T.t [lln]    [0] = this
        else
            if LoadInteger(T.t, lln, this) == -ts then
                if LoadInteger(T.t, llp, this) == -ts then
                    call TriggerStackDestroy(ts)
                else
                    call SaveInteger(T.t, lll, ts, LoadInteger(T.t, llp, this))
                    call SaveInteger(T.t, lln, LoadInteger(T.t, llp, this), -ts)
                endif
            else
                call SaveInteger(T.t, lln, LoadInteger(T.t, llp, this), LoadInteger(T.t, lln, this))
                call SaveInteger(T.t, llp, LoadInteger(T.t, lln, this), LoadInteger(T.t, llp, this))
            endif
            
            call RemoveInteger(T.t, llp, this)
            call SaveInteger(T.t, lln, this, LoadInteger(T.t, lln, 0))
            call SaveInteger(T.t, lln,    0, this)
        endif
    endfunction
    
    private function PrivConv_B2S takes boolean b returns string
        if b then
            return "0"
        else
            return "1"
        endif
    endfunction
    
    globals
        private integer tsNull
    endglobals
    
    function TSRegNullEvent takes nothing returns triggerstack
        local integer ts
        
        if tsNull == 0 then
            set tsNull = TriggerStackCreate()
        endif
        
        set ts = TriggerStackAdd(tsNull)
        
        static if LIBRARY_Table then
            set T.t [tsevn] [ts] = tsNull
        else
            call SaveInteger(T.t, tsevn, i, tsNull)
        endif
        
        return ts
    endfunction
    
    function TSUnregEvent takes triggerstack ts returns nothing
        static if LIBRARY_Table then
            call TriggerStackRemove(T.t [tsevn] [ts], ts)
        else
            call TriggerStackRemove(LoadInteger(T.t, tsevn, ts), ts)
        endif
    endfunction
    
    //! textmacro TriggerStack___MakeRegAPI takes NAME, FUNCARG, CONVERSION, REGFUNC, REGARG
        globals
            private key ts$NAME$
        endglobals
        
        function TSReg$NAME$Event takes $FUNCARG$ returns triggerstack
            local integer i  = $CONVERSION$
            local integer ts
            
            static if LIBRARY_Table then
                if T.t [ts$NAME$] [i] == 0 then
                    set T.t [ts$NAME$] [i] = TriggerStackCreate()
                endif
                
                set ts = TriggerStackAdd(T.t [ts$NAME$] [i])
                set T.t [tsevn] [ts] = T.t [ts$NAME$] [i]
                call TriggerRegister$REGFUNC$(T.t [tstrg].trigger [ts], $REGARG$)
                
                return ts
            else
                if LoadInteger(T.t, ts$NAME$, i) == 0 then
                    call SaveInteger(T.t, ts$NAME$, i, TriggerStackCreate())
                endif
                
                set ts = TriggerStackAdd(LoadInteger(T.t, ts$NAME$, i))
                call SaveInteger(T.t, tsevn, i, LoadInteger(T.t, ts$NAME$, i))
                call TriggerRegister$REGFUNC$(LoadTriggerHandle(T.t, tstrg, ts), $REGARG$)
                
                return ts
            endif
        endfunction
    //! endtextmacro
    
    //! runtextmacro TriggerStack___MakeRegAPI("Death", "widget w", "GetHandleId(w)", "DeathEvent", "w")
    //! runtextmacro TriggerStack___MakeRegAPI("DialogButton", "button b", "GetHandleId(b)", "DialogButtonEvent", "b")
    //! runtextmacro TriggerStack___MakeRegAPI("Dialog", "dialog d", "GetHandleId(d)", "DialogEvent", "d")
    //! runtextmacro TriggerStack___MakeRegAPI("EnterRegion", "region r, boolexpr f", "StringHash(H + I2S(GetHandleId(r)) + H + I2S(GetHandleId(f)))", "EnterRegion", "r, f")
    //! runtextmacro TriggerStack___MakeRegAPI("FilterUnit", "unit u, unitevent e, boolexpr f", "StringHash(H + I2S(GetHandleId(u)) + H + I2S(GetHandleId(e)) + H + I2S(GetHandleId(f)))", "FilterUnitEvent", "u, e, f")
    //! runtextmacro TriggerStack___MakeRegAPI("Game", "gameevent e", "GetHandleId(e)", "GameEvent", "e")
    //! runtextmacro TriggerStack___MakeRegAPI("GameState", "gamestate gs, limitop lt, real lv", "StringHash(H + I2S(GetHandleId(gs)) + H + I2S(GetHandleId(lt)) + R + R2S(lv))", "GameStateEvent", "gs, lt, lv")
    //! runtextmacro TriggerStack___MakeRegAPI("LeaveRegion", "region r, boolexpr f", "StringHash(H + I2S(GetHandleId(r)) + H + I2S(GetHandleId(f)))", "LeaveRegion", "r, f")
    //! runtextmacro TriggerStack___MakeRegAPI("PlayerAllianceChange", "player p, alliancetype at", "StringHash(H + I2S(GetHandleId(p)) + H + I2S(GetHandleId(at)))", "PlayerAllianceChange", "p, at")
    //! runtextmacro TriggerStack___MakeRegAPI("PlayerChat", "player p, string s, boolean b", "StringHash(H + I2S(GetHandleId(p)) + S + I2S(StringHash(s)) + B + PrivConv_B2S(b))", "PlayerChatEvent", "p, s, b")
    //! runtextmacro TriggerStack___MakeRegAPI("Player", "player p, playerevent e", "StringHash(H + I2S(GetHandleId(p)) + H + I2S(GetHandleId(e)))", "PlayerEvent", "p, e")
    //! runtextmacro TriggerStack___MakeRegAPI("PlayerState", "player p, playerstate ps, limitop lt, real lv", "StringHash(H + I2S(GetHandleId(p)) + H + I2S(GetHandleId(ps)) + H + I2S(GetHandleId(lt)) + R + R2S(lv))", "PlayerStateEvent", "p, ps, lt, lv")
    //! runtextmacro TriggerStack___MakeRegAPI("PlayerUnit", "player p, playerunitevent e, boolexpr f", "StringHash(H + I2S(GetHandleId(p)) + H + I2S(GetHandleId(e)) + H + I2S(GetHandleId(f)))", "PlayerUnitEvent", "p, e, f")
    //! runtextmacro TriggerStack___MakeRegAPI("Timer", "real t, boolean p", "StringHash(R + R2S(t) + B + PrivConv_B2S(p))", "TimerEvent", "t, p")
    //! runtextmacro TriggerStack___MakeRegAPI("TimerExpire", "timer t", "GetHandleId(t)", "TimerExpireEvent", "t")
    //! runtextmacro TriggerStack___MakeRegAPI("TrackableHit", "trackable t", "GetHandleId(t)", "TrackableHitEvent", "t")
    //! runtextmacro TriggerStack___MakeRegAPI("TrackableTrack", "trackable t", "GetHandleId(t)", "TrackableTrackEvent", "t")
    //! runtextmacro TriggerStack___MakeRegAPI("Unit", "unit u, unitevent e", "StringHash(H + I2S(GetHandleId(u)) + H + I2S(GetHandleId(e)))", "UnitEvent", "u, e")
    //! runtextmacro TriggerStack___MakeRegAPI("UnitInRange", "unit u, real r, boolexpr f", "StringHash(H + I2S(GetHandleId(u)) + R + R2S(r) + H + I2S(GetHandleId(f)))", "UnitInRange", "u, r, f")
    //! runtextmacro TriggerStack___MakeRegAPI("UnitState", "unit u, unitstate us, limitop lt, real lv", "StringHash(H + I2S(GetHandleId(u)) + H + I2S(GetHandleId(us)) + H + I2S(GetHandleId(lt)) + R + R2S(lv))", "UnitStateEvent", "u, us, lt, lv")
    //! runtextmacro TriggerStack___MakeRegAPI("Variable", "string vn, limitop lt, real lv", "StringHash(S + I2S(StringHash(vn)) + H + I2S(GetHandleId(lt)) + R + R2S(lv))", "VariableEvent", "vn, lt, lv")
    
    function TSAddAction takes triggerstack ts, code c returns triggerstackaction
        set tsac = tsac + 1
        
        static if LIBRARY_Table then
            set T.t [tsact].boolexpr [ts] = And(T.t [tsact].boolexpr [ts], Condition(c))
            set T.t [tscon].boolexpr [tsac] = Condition(c)
            set T.t [tscow] [tsac] = ts
        else
            call SaveBoolexprHandle(T.t, tsact, ts, And(LoadBoolexprHandle(T.t, tsact, ts), Condition(c)))
            call SaveBoolexprHanlde(T.t, tscon, tsac, Condition(c))
            call SaveInteger(T.t, tscow, tsac, ts)
        endif
        
        return tsac
    endfunction
    
    function TSRemoveAction takes triggerstack ts, triggerstackaction tsa returns nothing
        local integer  l = tsac
        local boolexpr b
        
        loop
            exitwhen l == 0
            
            static if LIBRARY_Table then
                if T.t [tscow] [l] == ts and l != tsa then
                    set b = And(b, T.t [tscon].boolexpr [l])
                endif
            else
                if LoadInteger(T.t, tscow, l) == ts and l != tsa then
                    set b = And(b, LoadBoolexprHandle(T.t, tscon, l))
                endif
            endif
            
            set l = l - 1
        endloop
        
        static if LIBRARY_Table then
            set T.t [tscon].boolexpr [tsa] = T.t [tscon].boolexpr [tsac]
            set T.t [tscow] [tsa] = T.t [tscow] [tsac]
            call T.t [tscon].handle.remove(tsa)
            call T.t [tscow].remove(tsa)
        else
            call SaveBoolexprHandle(T.t, tscon, tsa, LoadBoolexprHandle(T.t, tscon, tsac))
            call SaveInteger(T.t, tscow, tsa, LoadInteger(T.t, tscow, tsac))
            call RemoveSavedHandle(T.t, tscon, tsa)
            call RemoveSavedInteger(T.t, tscow, tsa)
        endif
        
        set tsac = tsac - 1
    endfunction
    
    function TSEnable takes triggerstack ts, boolean b returns nothing
        static if LIBRARY_Table then
            set T.t [tsenb].boolean [ts] = b
        else
            call SaveBoolean(T.t, tsenb, ts, b)
        endif
    endfunction
    
    function TSIsEnabled takes triggerstack ts returns boolean
        static if LIBRARY_Table then
            return T.t [tsenb].boolean [ts]
        else
            return LoadBoolean(T.t, tsenb, ts)
        endif
    endfunction
    
    function TSExecute takes triggerstack ts returns nothing
        static if LIBRARY_Table then
            call TriggerEvaluate(T.t [tstrg].trigger [ts])
        else
            call TriggerEvaluate(LoadTriggerHandle(T.t, tstrg, ts))
        endif
    endfunction
endlibrary
 
Your thing doesn't even run... furthermore, these will break any map that has them in it
JASS:
    type triggerstack       extends integer
    type triggerstackaction extends integer

You can't do that ...

First, fix your bloody syntax errors, then fix your map criticals (the handle defs).


This also looks rather silly... like serious overkill.. it's easier to just work with trigs and triggerconditions directly... why abstract something into this complex mess when it's easier and faster to just work with the JASS natives??
 
Top