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
//**************************************************************************************************************************