• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Hero Simple States Machine

This bundle is marked as pending. It has not been reviewed by a staff member yet.
  • Like
Reactions: Vinz
Hero Simple State Machine Ver 0.0.2.
By
allknowledge aka iam20842


//**************************************************************************************************************************
// HeroSimpleStateMachine - Version 0.0.2 - By allknowledge aka iam20842
//**************************************************************************************************************************

//**************************************************************************************************************************
// Add custom temporarily state to an Hero.
//**************************************************************************************************************************

//**************************************************************************************************************************
// How the magic happend?
// 1. Save the state hash in statesTable using CreateState (Find the function explaination in: HSSM Globals Trigger)
// 1. Create an global variable for the state using integer STATE_YOURCUSTOMSTATE = yourvalue in HSSM Globals Trigger
// 2. Define a way to see the default value of the heroesTable for an Hero (Find a example in: HSSM SaveHeroTable Trigger)
// 3. Create your custom spell
// 3. Add your custom spell id like a global variable like this SPELL_STATE_YOURCUSTOMSTATE in HSSM Globals Trigger
// 3.1 Use UnitAddState for add an state
// 3.2 Use UnitRemoveState for remove an state
// 3.3 Use UnitHasState if you want add an state only if hero already have another state, like sleep to awake
// 3.4 Use UnitHasStateLeft if you want get the remaining time of an state
// 3.5 Use UnitHasStateMsg for get a debug message of the state
// 4. Combine your spells with the power of Hero Simple States Machine to add damage,
// times, or any bonus, checking if a unit have your custom state . see HSSM Example
//**************************************************************************************************************************

//**************************************************************************************************************************
// Conclusion:
//**************************************************************************************************************************
// 1. Cast a state_spell over the unit to set custom state
// 2. If the unit already have the spell and you set stack mode OFF, this will happend
// 2.1 If new duration of the state is biggest that the current, the new will set
// 2.2 If new duration is less that the current state, nothing will apply
// 3. If the unit already have the spell and you set stack mode ON, this will happend
// 3.1 If new duration of the state is biggest that the current, the new will set
// 2.2 If new duration is less that the current state, both duration will sum and create new timer for the result duration

// The stack mode is "pseudostack" because even you set stack mode ON only the state with less duration that the current
// will sum, no biggers.
//**************************************************************************************************************************

What are the adventages?


1. Is MUI
2. Easy manage of state durations or transitions
3. Simple functions to manage setting, getting, or removing temporarily states.
4. Leaks free or so I think ;)
5. PseudoStack System


JASS:
library HeroSimpleStateMachine
    globals
        hashtable heroesTable  = InitHashtable()
        hashtable statesTable = InitHashtable()
        hashtable timersTable = InitHashtable()
        integer STATE_STUN = 0
        integer STATE_POISON = 1
        integer STATE_PARALYSIS = 2
        integer STATE_SLEEP = 3
        integer STATE_BROKEN = 4
        integer STATE_ROOTED = 5
        integer STATE_SLOWED = 6
        integer STATE_DRAINED = 7
        integer STATE_CAPTURE = 8
        integer STATE_FROZEN = 9
        integer STATE_HEALED = 10
        integer SPELL_STATE_STUN = 'A000'
        integer SPELL_STATE_STUNX30 = 'A008'
        integer SPELL_STATE_PARALYSIS = 'A001'
        integer SPELL_STATE_SLEEP = 'A002'
        integer SPELL_STATE_BROKEN = 'A003'
        integer SPELL_STATE_CLEAR = 'A006'
        integer SPELL_STATE_CHECK = 'A005'
        integer SPELL_STATE_STORMBOLT = 'A007'
        integer MAX_STATES
    endglobals

    function TimerHandler takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local integer tid = GetHandleId(t)
        local integer uid = LoadInteger(timersTable, GetHandleId(t), 1)
        local integer sid = LoadInteger(timersTable, GetHandleId(t), 2)
        local string sn = LoadStr(statesTable, sid, 1)

        call FlushChildHashtable(timersTable, tid)
        call SaveInteger(heroesTable, uid, sid, 0)
        call PauseTimer(t)
        call DestroyTimer(t)

        set t = null
    endfunction

    function CreateState takes integer i, string n, string d, boolean s returns nothing
        call SaveInteger(statesTable, i, 0, i)
        call SaveStr(statesTable,     i, 1, n)
        call SaveStr(statesTable,     i, 2, d)
        call SaveBoolean(statesTable, i, 3, s)
    endfunction

    function UnitHasState takes unit u, integer s returns boolean
        local integer uid = GetHandleId(u)
        local integer sid = LoadInteger(statesTable, s, 0)
        local integer us = LoadInteger(heroesTable, uid, sid)
        local boolean flag = false
    
        if (us == 1) then
            set flag = true
        else
            set flag = false
        endif

        set u = null

        return flag
    endfunction


    function UnitHasStateLeft takes unit u, integer s returns real
        local integer uid = GetHandleId(u)
        local integer sid = LoadInteger(statesTable, s, 0)
        local integer us = LoadInteger(heroesTable, uid, sid)
        local timer t = LoadTimerHandle(timersTable, uid, sid)
        local real tl = TimerGetRemaining(t)

        return tl
    endfunction

    function UnitHasStateMsg takes unit u, integer s returns nothing
        local integer uid = GetHandleId(u)
        local integer sid = LoadInteger(statesTable, s, 0)
        local string sn = LoadStr(statesTable, s, 1)
        local integer us = LoadInteger(heroesTable, uid, sid)
        local timer t = LoadTimerHandle(timersTable, uid, sid)
        local real tl = TimerGetRemaining(t)

        call ClearTextMessages()

        if (us == 1) then
            call BJDebugMsg("State: " + sn + " |cff00ff00ON|r" + " left: " + "|cffffff00" + R2S(tl) + "|r seconds" )
        else
            call BJDebugMsg("State: " + sn + " |cffff0000OFF|r")
        endif

        set u = null
    endfunction

    function UnitRemoveState takes unit u, integer s returns nothing
        local integer sid = LoadInteger(statesTable, s, 0)
        local string sn = LoadStr(statesTable, s, 1)
        local integer uid = GetHandleId(u)
        local timer t = LoadTimerHandle(timersTable, uid, sid)
        local integer tid = GetHandleId(t)

        call SaveInteger(heroesTable, uid, sid, 0)
        call FlushChildHashtable(timersTable, tid)
        call PauseTimer(t)
        call DestroyTimer(t)

        set t = null
        set u = null

    endfunction

    function UnitAddState takes unit u, integer s, real d returns nothing
        local integer uid = GetHandleId(u)
        local integer sid = LoadInteger(statesTable, s, 0)
        local string sn = LoadStr(statesTable, s, 1)
        local boolean sm = LoadBoolean(statesTable, s, 3)
        local timer t = CreateTimer()
        local integer tid = GetHandleId(t)
        local real ntl
        local timer nt

    if(UnitHasState(u, sid) == true) then
        if (d > UnitHasStateLeft(u, sid) ) then
            call UnitRemoveState(u, sid)

            call SaveInteger(heroesTable, uid, sid, 1)
            call SaveTimerHandle(timersTable, uid, sid, t)
            call SaveInteger(timersTable, tid, 1, uid)
            call SaveInteger(timersTable, tid, 2, sid)

            call TimerStart(t, d, false, function TimerHandler)
        else
            if (sm == true) then
                set ntl = d + UnitHasStateLeft(u, sid)

                call UnitRemoveState(u, sid)

                call SaveTimerHandle(timersTable, uid, sid, t)
                call SaveInteger(timersTable, tid, 1, uid)
                call SaveInteger(timersTable, tid, 2, sid)

                call TimerStart(t, d, false, function TimerHandler)
            else

                set u = null
                set t = null
                return
            endif
        endif
    else
        call SaveInteger(heroesTable, uid, sid, 1)
        call SaveTimerHandle(timersTable, uid, sid, t)
        call SaveInteger(timersTable, tid, 1, uid)
        call SaveInteger(timersTable, tid, 2, sid)
    
        call TimerStart(t, d, false, function TimerHandler)
    endif

    set u = null
    set t = null

    endfunction
endlibrary

JASS:
library HeroSimpleStateMachine

    //**************************************************************************************************************************
    //     HeroSimpleStateMachine - Version 0.0.2 - By allknowledge aka iam20842  
    //**************************************************************************************************************************

    //**************************************************************************************************************************
    //     Add custom temporarily state to an Hero.
    //**************************************************************************************************************************

    //**************************************************************************************************************************
    // How the magic happend?
    // 1. Save the state hash in statesTable using CreateState (Find the function explaination in: HSSM Globals Trigger)
    // 1. Create an global variable for the state using integer STATE_YOURCUSTOMSTATE = yourvalue in HSSM Globals Trigger
    // 2. Define a way to see the default value of the heroesTable for an Hero (Find a example in: HSSM SaveHeroTable Trigger)
    // 3. Create your custom spell
    // 3. Add your custom spell id like a global variable like this SPELL_STATE_YOURCUSTOMSTATE in HSSM Globals Trigger
    // 3.1 Use UnitAddState for add an state
    // 3.2 Use UnitRemoveState for remove an state
    // 3.3 Use UnitHasState if you want add an state only if hero already have another state, like sleep to awake
    // 3.4 Use UnitHasStateLeft if you want get the remaining time of an state
    // 3.5 Use UnitHasStateMsg for get a debug message of the state
    // 4. Combine your spells with the power of Hero Simple States Machine to add damage,
    //    times, or any bonus, checking if a unit have your custom state . see HSSM Example
    //**************************************************************************************************************************

    //**************************************************************************************************************************
    // Conclusion:
    //
    // 1. Cast a state_spell over the unit to set custom state
    // 2. If the unit already have the spell and you set stack mode OFF, this will happend
    // 2.1 If new duration of the state is biggest that the current, the new will set
    // 2.2 If new duration is less that the current state, nothing will apply
    // 3. If the unit already have the spell and you set stack mode ON, this will happend
    // 3.1 If new duration of the state is biggest that the current, the new will set
    // 2.2 If new duration is less that the current state, both duration will sum and create new timer for the result duration

    // The stack mode is "pseudostack" because even you set stack mode ON only the state with less duration that the current
    // will sum, no biggers.
    //**************************************************************************************************************************
 
    globals

        hashtable heroesTable  = InitHashtable()
        hashtable statesTable = InitHashtable()
        hashtable timersTable = InitHashtable()

        integer STATE_STUN = 0
        integer STATE_POISON = 1
        integer STATE_PARALYSIS = 2
        integer STATE_SLEEP = 3
        integer STATE_BROKEN = 4
        integer STATE_ROOTED = 5
        integer STATE_SLOWED = 6
        integer STATE_DRAINED = 7
        integer STATE_CAPTURE = 8
        integer STATE_FROZEN = 9
        integer STATE_HEALED = 10

        integer SPELL_STATE_STUN = 'A000'
        integer SPELL_STATE_STUNX30 = 'A008'

        integer SPELL_STATE_PARALYSIS = 'A001'
        integer SPELL_STATE_SLEEP = 'A002'
        integer SPELL_STATE_BROKEN = 'A003'

        integer SPELL_STATE_CLEAR = 'A006'
        integer SPELL_STATE_CHECK = 'A005'

        integer SPELL_STATE_STORMBOLT = 'A007'

        integer MAX_STATES

    endglobals
    
    //**************************************************************************************************************************
    // Explaining the HASHTABLES
    //**************************************************************************************************************************

    //**************************************************************************************************************************
    // statesTable: save every custom state
    //**************************************************************************************************************************
    //  Takes:
    //
    //   Parent: Integer -> state index
    //   Child:  0 -> Integer -> index
    //           1 -> String  -> name
    //           2 -> String  -> description
    //           3 -> Boolean -> Stack mode
    //   Value:  the correspondig
    //**************************************************************************************************************************

    //**************************************************************************************************************************
    // heroesTable: save the every state of the hero and their values, default: 0
    //**************************************************************************************************************************
    // Takes:
    //   Parent: Integer -> unit index
    //   Child:  Integer -> state index
    //**************************************************************************************************************************

    //**************************************************************************************************************************
    // timersTable: save the timer of the state (duration) for every unit+state
    //**************************************************************************************************************************
    // Takes:
    //
    //  Parent: Integer -> timer index
    //  Child:  1 -> Retrieve -> Integer -> unit index
    //          2 -> Retrieve -> Integer -> state index
    //
    //  Parent: Integer -> unit index
    //  Child:  Integer -> stateIndex -> Retrieve -> Timer -> currentTimer

    //**************************************************************************************************************************
    // Explaining the functions
    //**************************************************************************************************************************

    //**************************************************************************************************************************
    // TimerHandler: Create a timer that manage the duration of state, when it expire the state get zero
    //**************************************************************************************************************************

    function TimerHandler takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local integer tid = GetHandleId(t)
        local integer uid = LoadInteger(timersTable, GetHandleId(t), 1)
        local integer sid = LoadInteger(timersTable, GetHandleId(t), 2)
        local string sn = LoadStr(statesTable, sid, 1)

        // CLEAR tid child data.
        call FlushChildHashtable(timersTable, tid)

        call SaveInteger(heroesTable, uid, sid, 0)
        call PauseTimer(t)
        call DestroyTimer(t)
        set t = null
    
        // DEBUG msg
        call BJDebugMsg("State: " + sn + " |cffff0000Expired|r")
    endfunction

    //**************************************************************************************************************************
    // CreateState: Create a new state.
    //**************************************************************************************************************************
    //  Takes:
    //   integer i  -> index
    //   string  n  -> name
    //   string  d  -> description
    //**************************************************************************************************************************
    
    function CreateState takes integer i, string n, string d, boolean s returns nothing
        call SaveInteger(statesTable, i, 0, i)
        call SaveStr(statesTable,     i, 1, n)
        call SaveStr(statesTable,     i, 2, d)
        call SaveBoolean(statesTable, i, 3, s)
    endfunction

    //**************************************************************************************************************************
    // UnitHasState: Get true or false from check does hero have state?
    //**************************************************************************************************************************
    //  Takes:
    //   unit u  -> target unit
    //   integer sid -> state index
    //**************************************************************************************************************************

    function UnitHasState takes unit u, integer s returns boolean
        local integer uid = GetHandleId(u)
        local integer sid = LoadInteger(statesTable, s, 0)
        local integer us = LoadInteger(heroesTable, uid, sid)
        local boolean flag = false

        if (us == 1) then
           set flag = true
        else
           set flag = false
        endif

        set u = null

        return flag
    endfunction

    //**************************************************************************************************************************
    // UnitHasStateLeft: Get the remaining time of the State from hero.
    //**************************************************************************************************************************
    // Takes:
    //   unit u  -> target unit
    //   integer sid -> state index
    // Retrieves:
    //   real -> remaining time
    //**************************************************************************************************************************
      

    function UnitHasStateLeft takes unit u, integer s returns real
        local integer uid = GetHandleId(u)
        local integer sid = LoadInteger(statesTable, s, 0)
        local integer us = LoadInteger(heroesTable, uid, sid)

        local timer t = LoadTimerHandle(timersTable, uid, sid)
        local real tl = TimerGetRemaining(t)
    
        return tl

    endfunction

    //**************************************************************************************************************************
    // UnitHasStateMsg: Return a message with the current value of the hero state
    //**************************************************************************************************************************
    // Takes:
    //   unit u  -> target unit
    //   integer sid -> state index
    //  Retrieve:
    //   Custom message
    //**************************************************************************************************************************

    function UnitHasStateMsg takes unit u, integer s returns nothing
        local integer uid = GetHandleId(u)
        local integer sid = LoadInteger(statesTable, s, 0)
        local string sn = LoadStr(statesTable, s, 1)
        local integer us = LoadInteger(heroesTable, uid, sid)
        local timer t = LoadTimerHandle(timersTable, uid, sid)
        local real tl = TimerGetRemaining(t)
    
        call ClearTextMessages()

        if (us == 1) then
           call BJDebugMsg("State: " + sn + " |cff00ff00ON|r" + " left: " + "|cffffff00" + R2S(tl) + "|r seconds" )
        else
           call BJDebugMsg("State: " + sn + " |cffff0000OFF|r")
        endif
        set u = null
    endfunction

    //**************************************************************************************************************************
    // UnitRemoveState: Set OF an state of a Hero
    //**************************************************************************************************************************
    // Takes:
    //   unit u  -> target unit
    //   integer sid -> state index
    //**************************************************************************************************************************

    function UnitRemoveState takes unit u, integer s returns nothing

        local integer sid = LoadInteger(statesTable, s, 0)
        local string sn = LoadStr(statesTable, s, 1)
        local integer uid = GetHandleId(u)

        local timer t = LoadTimerHandle(timersTable, uid, sid)
        local integer tid = GetHandleId(t)

        call ClearTextMessages()

        // Debug Message
        call BJDebugMsg("State: " + sn + " |cffff0000OFF|r")

        // SET hero + state => 0
        call SaveInteger(heroesTable, uid, sid, 0)
  
        // CLEAR tid child data.
        call FlushChildHashtable(timersTable, tid)

        call PauseTimer(t)
        call DestroyTimer(t)

        set t = null
        set u = null

    endfunction

    //**************************************************************************************************************************
    // UnitAddState: Set ON an state of a Hero
    //**************************************************************************************************************************
    //  Takes:
    //   unit u  -> target unit
    //   integer sid -> state index
    //   real d  -> duration of the state
    //**************************************************************************************************************************

    function UnitAddState takes unit u, integer s, real d returns nothing
        local integer uid = GetHandleId(u)
        local integer sid = LoadInteger(statesTable, s, 0)
        local string sn = LoadStr(statesTable, s, 1)
        local boolean sm = LoadBoolean(statesTable, s, 3)

        local timer t = CreateTimer()
        local integer tid = GetHandleId(t)
        local real ntl
        local timer nt

        call ClearTextMessages()

        // Check if unit have a timer (state)

        // You can check the STACK value for the timer.

        // Stack -> 0 : will sum the remaining actual time (if exist) to the new duration of the state
        // Stack -> 1 : will set the current state remaining time to the biggest value. This mean that
        //              if unit have 8 sec left of state X and you apply 5 sec of state Y,
        //              the time left is gonna be 8 sec

        if(UnitHasState(u, sid) == true) then

           // Debug Message

            call BJDebugMsg("The unit HAVE the state, checking remaining times")

            // if the current time (ctl) is less than the new (d), the new timer will apply

            call BJDebugMsg("Remaining time: " + R2S(UnitHasStateLeft(u, sid)))

            if ( d > UnitHasStateLeft(u, sid) ) then

                call BJDebugMsg("The new timer(d) is bigger than old timer(ctl), effect will apply")
            
                call BJDebugMsg("call UnitRemoveState()")

                // Removing previous state

                call UnitRemoveState(u, sid)        

                call BJDebugMsg("--------------------")

                // SET hero + state => 1
                call SaveInteger(heroesTable, uid, sid, 1)
  
                // SAVE for hero + state => Timer
                call SaveTimerHandle(timersTable, uid, sid, t)

                // SAVE for timer + 1 => unit index
                call SaveInteger(timersTable, tid, 1, uid)

                // SAVE for timer + 2 => state index
                call SaveInteger(timersTable, tid, 2, sid)

                // START the timer
                call TimerStart(t, d, false, function TimerHandler)
            
                // Debug Message
                call BJDebugMsg("State: " + sn + " |cff00ff00ON|r" + " for: " + "|cffffff00" + R2S(d) + "|r seconds" )

            else

                call BJDebugMsg("The new timer is lowest than the actual")
                call BJDebugMsg("Checking stack mode")

                // Stack Mode.
                // If ON, will add the timer
                // If OFF, will do nothing

                if (sm == true) then

                   call BJDebugMsg("Stack ON: sum the times")

                   set ntl = d + UnitHasStateLeft(u, sid)
            
                   call BJDebugMsg("call UnitRemoveState()")

                   // Removing previous state
                   call UnitRemoveState(u, sid)
      
                   call BJDebugMsg("--------------------")
            
                   // SAVE for hero + state => Timer
                   call SaveTimerHandle(timersTable, uid, sid, t)

                   // SAVE for timer + 1 => unit index
                   call SaveInteger(timersTable, tid, 1, uid)

                   // SAVE for timer + 2 => state index
                   call SaveInteger(timersTable, tid, 2, sid)

                   // START the timer
                   call TimerStart(t, d, false, function TimerHandler)

                   // Debug Message
                   call BJDebugMsg("Update State: " + sn + " |cff00ff00ON|r" + " for: " + "|cffffff00" + R2S(ntl) + "|r seconds" )
               else
                   call BJDebugMsg("Stack OFF nothing more to do")
                   set u = null
                   set t = null
                   return
               endif
            endif
        else
            // Debug Message
            call BJDebugMsg("The unit DONT have the state, effects will apply")

            // SET hero + state => 1
            call SaveInteger(heroesTable, uid, sid, 1)
  
            // SAVE for hero + state => Timer
            call SaveTimerHandle(timersTable, uid, sid, t)

            // SAVE for timer + 1 => unit index
            call SaveInteger(timersTable, tid, 1, uid)

            // SAVE for timer + 2 => state index
            call SaveInteger(timersTable, tid, 2, sid)

            // START the timer
            call TimerStart(t, d, false, function TimerHandler)

            // Debug Message
            call BJDebugMsg("State: " + sn + " |cff00ff00ON|r" + " for: " + "|cffffff00" + R2S(d) + "|r seconds" )
        endif

        set u = null
        set t = null

    endfunction
endlibrary
//**************************************************************************************************************************
// END
//**************************************************************************************************************************

JASS:
function CreateStates takes nothing returns nothing
    call CreateState(0, "stun", "you get stunned", true)
    call CreateState(1, "poison", "you get poisoned", false)
    call CreateState(2, "paralysis", "you get paralyzed", false)
    call CreateState(3, "sleep", "you get sleep", false)
    call CreateState(4, "broken", "you get broken", false)
    call CreateState(5, "rooted", "you get rooted", false)
    call CreateState(6, "slowed", "you get slowed", false)
    call CreateState(7, "drained", "you get drained", false)
    call CreateState(8, "capture", "you get capture", false)
    call CreateState(9, "frozen", "you get frozen", false)
    call CreateState(10, "healed", "you get healed", false)

    // Remember set the MAX_STATES
    set MAX_STATES = 11
endfunction

//===========================================================================
function InitTrig_HSSM_CreateStates takes nothing returns nothing
    local trigger tg = CreateTrigger(  )
    call TriggerRegisterTimerEventSingle( tg, 0.00 )
    call TriggerAddAction( tg, function CreateStates)
endfunction

JASS:
function HSSM_SaveHeroTable_Actions takes nothing returns nothing
    local unit su = GetSoldUnit()
    local integer uid = GetHandleId(su)
    local integer i = 0
    call ClearTextMessages()
    // Set the default states zero
    loop
        call SaveInteger(heroesTable, uid, i, 0)
        set i = i + 1
        exitwhen i == MAX_STATES
    endloop

    set su = null
 
    call BJDebugMsg("You hero is ready for get custom state!")
    call BJDebugMsg("Use Q and select what state you want apply")
    call BJDebugMsg("Use W to get the current state of the target unit")

    call BJDebugMsg("Use E to get all the states cleared for the target unit")
    call BJDebugMsg("Use R without and with STUN state to see the magic")

endfunction

//===========================================================================
function InitTrig_HSSM_SaveHeroTable takes nothing returns nothing
    local trigger tg = CreateTrigger()
    call TriggerRegisterUnitEvent( tg, gg_unit_ntav_0000, EVENT_UNIT_SELL )
    call TriggerAddAction( tg, function HSSM_SaveHeroTable_Actions )
endfunction

JASS:
function HSSM_Cast_Dummy_Spell_Actions takes nothing returns nothing
    local unit tu = GetSpellTargetUnit()
    local integer s = GetSpellAbilityId()
    local integer i = 0

    // STUN DEMO
    if (GetSpellAbilityId() == SPELL_STATE_STUN) then
        call UnitAddState(tu, 0, 10.0)
    endif

    // STUN X30 DEMO
    if (GetSpellAbilityId() == SPELL_STATE_STUNX30) then
        call UnitAddState(tu, 0, 30.0)
    endif

    // PARALYSIS DEMO
    if (GetSpellAbilityId() == SPELL_STATE_PARALYSIS) then
        call UnitAddState(tu, 2, 7.0)
    endif

    // SLEEP DEMO
    if (GetSpellAbilityId() == SPELL_STATE_SLEEP) then
        call UnitAddState(tu, 3, 20.0)
    endif

    // BROKEN DEMO
    if (GetSpellAbilityId() == SPELL_STATE_BROKEN) then
        call UnitAddState(tu, 5, 4.0)
    endif

    // CLEAR DEMO
    if (GetSpellAbilityId() == SPELL_STATE_CLEAR) then
        call ClearTextMessages()
        loop
            call UnitRemoveState(tu, i)
            set i = i + 1
            exitwhen i == MAX_STATES
        endloop
        call BJDebugMsg("All states Cleared")
    endif

    // CHECK DEMO
    if (GetSpellAbilityId() == SPELL_STATE_CHECK) then
        call BJDebugMsg("Current States")
        call ClearTextMessages()
        loop
            call UnitHasStateMsg(tu, i)
            set i = i + 1
            exitwhen i == MAX_STATES
        endloop
    endif

    set tu = null
endfunction

function InitTrig_HSSM_Cast_Dummy_Spell takes nothing returns nothing
    local trigger tg = CreateTrigger()
    local integer i = 0

    call TriggerAddAction(tg, function HSSM_Cast_Dummy_Spell_Actions)

    loop
        call TriggerRegisterPlayerUnitEvent(tg, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
        set i = i + 1
    exitwhen i == bj_MAX_PLAYERS
    endloop

endfunction

JASS:
function HSSM_Example_Actions takes nothing returns nothing
    local unit tu = GetSpellTargetUnit()
    local unit c = GetSpellAbilityUnit()
    local integer s = GetSpellAbilityId()
    local real b = 250.0

    // StormBolt Demo
    if (GetSpellAbilityId() == SPELL_STATE_STORMBOLT) then
        if (UnitHasState(tu , STATE_STUN)) then
             // Pure Damage
            if(GetUnitState(tu, UNIT_STATE_LIFE) <= b) then
                call UnitDamageTarget( c, tu, 1000000000.00, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_ROCK_HEAVY_BASH)
            else
                call UnitDamageTarget( c, tu, b, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_ROCK_HEAVY_BASH)         
            endif
     
            call UnitRemoveState(tu, STATE_STUN)
            call BJDebugMsg("+250 pure damage bonus!")
     
        else
            call BJDebugMsg("Unit dont have STUN, bonus will not apply")
        endif
    endif

    set tu = null
    set c = null
endfunction

function InitTrig_HSSM_Example takes nothing returns nothing
    local trigger tg = CreateTrigger()
    local integer i = 0

    call TriggerAddAction(tg, function HSSM_Example_Actions)

    loop
        call TriggerRegisterPlayerUnitEvent(tg, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
        set i = i + 1
    exitwhen i == bj_MAX_PLAYERS
    endloop

endfunction
Contents

Hero Simple States Machine 0.0.1 (Map)

Hero Simple States Machine 0.0.2 (Map)

Level 5
Joined
Jun 30, 2019
Messages
33
Some programming feedback:
  • Normalize your function names to WC3 standards; e.g. rename GetStateHave() to UnitHasState()
  • This is a library, so encapsulate all of your code in an appropriately named library and make your globals and functions private where appropriate
  • Rename your library; a "unit state" already describes hit points and mana
  • Avoid using magic numbers. If the Stunned state is described by the integer 1, create a constant named STATE_STUNNED with a value of 1 and use that instead
 

V

V

Level 7
Joined
Jan 13, 2019
Messages
284
Some programming feedback:
  • Normalize your function names to WC3 standards; e.g. rename GetStateHave() to UnitHasState()
  • This is a library, so encapsulate all of your code in an appropriately named library and make your globals and functions private where appropriate
  • Rename your library; a "unit state" already describes hit points and mana
  • Avoid using magic numbers. If the Stunned state is described by the integer 1, create a constant named STATE_STUNNED with a value of 1 and use that instead

1. Done
2. still not
3. still not
4. Done
 
Back to reviewing systems like these, and I'd say it was a pleasure to look at the system, at least from the readability of it. From the looks of it, the system seems to be based off of stacking duration, rather than stacking sources. This is just at a glance though.

  • The library can benefit from proper scoping of functions and variables, since some of the functions available are too generic for comfort.

  • Since the system is already taking advantage of vJASS, it would be appropriate to privatize the hashtables initialized by the system.
    JASS:
    globals
        private constant hashtable heroesTable  = InitHashtable()
        private constant hashtable statesTable = InitHashtable()
        private constant hashtable timersTable = InitHashtable()
        ...
    endglobals

  • In a similar vein, the numerous states already defined within the system should be made into constants, since these variables are expected to never change throughout the game.
    JASS:
    globals
        ....
        constant integer STATE_STUN = 0
        constant integer STATE_POISON = 1
        constant integer STATE_PARALYSIS = 2
        constant integer STATE_SLEEP = 3
        constant integer STATE_BROKEN = 4
        // Do the same for the ones below, {STATE_#}
    endglobals

  • Internally, CreateState should operate as a private constructor function, based on the syntax it already takes. You can expose a new function with the same name as CreateState without it taking an integer as a first parameter, since the integer supplied would be generated dynamically and supplied to the old CreateState function. Of course, the new CreateState function must be prefixed with a public scope to drastically reduce the possibility of name collisions.

  • UnitHasStateLeft does not roll off the tongue as well as it could've. I suggest renaming it to something like UnitStateGetRemaining or UnitCStateGetRemaining.

  • Debug messages should not be present on the release version of the system. You can enable debug messages by enclosing them within a static if and a constant debug boolean variable.
    JASS:
    globals
        ....
        private constant boolean IN_DEBUG_MODE = true
    endglobals
    
    ....
    static if IN_DEBUG_MODE then
        call BJDebugMsg("Lorem Ipsum")
    endif

  • When submitting vJASS systems that require certain things to be done on initialization, it is recommended to place the things to be initialized within a module initializer, as this guarantees that the initialization function will run first among the numerous initialization methods within the library.
    JASS:
    // Admittedly, this syntax is kinda ugly.
    private module M
        private static method onInit takes nothing returns nothing
        endmethod
    endmodule
    private struct S
        implement M
    endstruct
 
  • Love
Reactions: V
Top