Ill explain how timers are used... how they are really used.
(In gui you dont even use timers.)
In JASS you have a simple action called TimerStart(). That action starts a given timer for a given duration and you can even tell if that timer should restart when it expired until it is destroyed.
JASS:
function foo takes nothing returns nothing
local timer t = CreateTimer()
call TimerStart(t, 5, false, null)
set t = null
endfunction
Cant be much simpler isnt it?
It starts timer t, for 5 seconds and does not restart when it expires.
That is how GUI uses timers...
Now there is a big difference between GUI and JASS timers.
In GUI, you cannot use that last value which is null in the example.
That value is a callback code.
The callback code is ran when the timer expires.
So in this example:
JASS:
function callback takes nothing returns nothing
local timer t = GetExpiredTimer()
set t = null
endfunction
function foo takes nothing returns nothing
local timer t = CreateTimer()
call TimerStart(t, 5, false, function callback)
set t = null
endfunction
The function callback is ran when that timer expires... EXACTLY 5 in-game seconds after the function foo ran.
You can get the expired timer by calling GetExpiredTimer().
(Always remember to null local variables except string, integer, real and boolean.)
Now... You want to remove and add a number of strength when function foo runs and you want to add it again when function callback runs.
Function foo is simple, but in callback, you have forgotten who that unit was.
(NEVER EVER EVER design your code to work for one unit only. Always base your desig MUI and if that is not possible due to dynamic arrays or MPI functions, then use MPI.)
What we can do is store the unit and the amount of strength added inside a hashtable.
However, hashtables are quite slow and I use a lot of data stored on a timer.
Therefor I have written a kind of Timer indexer which I use to do these kind of things.
(Today I learned how to use hooks and I will use those instead of the manually remove but that doesnt really matter.)
JASS:
library timerIndex
globals
hashtable udg_HandleIndex_Hashtable = InitHashtable()//Can be replaced by table.
//Timers
integer udg_NextTimerIndex = 0
boolean array udg_TimerIndex_Occupied
endglobals
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Timers
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function CreateTimerIndex takes timer t returns integer
loop
set udg_NextTimerIndex = udg_NextTimerIndex + 1
if udg_NextTimerIndex > 8191 then
set udg_NextTimerIndex = 1
endif
exitwhen not udg_TimerIndex_Occupied[udg_NextTimerIndex]
endloop
set udg_TimerIndex_Occupied[udg_NextTimerIndex] = true
call SaveInteger(udg_HandleIndex_Hashtable, GetHandleId(t), 0, udg_NextTimerIndex)
return udg_NextTimerIndex
endfunction
function ReleaseTimerIndex takes timer t returns nothing
local integer id = GetHandleId(t)
set udg_TimerIndex_Occupied[LoadInteger(udg_HandleIndex_Hashtable, id, 0)] = false
call RemoveSavedInteger(udg_HandleIndex_Hashtable, id, 0)
endfunction
function GetTimerIndex takes timer t returns integer
return LoadInteger(udg_HandleIndex_Hashtable, GetHandleId(t), 0)
endfunction
endlibrary
With that library, I can create a 1-8191 integer for each timer.
Assuming that there will not be more than 8191 timers that use that indexer at once.
It is your choice to use it or not.
It will improve the performance but will not do anything functionally.
Anyway, with that system and a little code, you can make something really awesome.
Just look at this piece of code:
udg_ stuff are global variables.
JASS:
function callback takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer id = GetTimerIndex(t)
call SetHeroStat(udg_TimedStat_Unit[id], udg_TimedStat_Type[id], GetHeroStatBJ(udg_TimedStat_Type[id], udg_TimedStat_Unit[id], false) - udg_TimedStat_Amount[id])
set udg_TimedStat_Unit[id] = null //handle pointer leak.
call ReleaseTimerIndex(t)
call DestroyTimer(t)
set t = null
endfunction
function AddTimedStat takes unit whichUnit, integer whichStat, integer value, real duration returns nothing
local timer t = CreateTimer()
local integer id = CreateTimerIndex(t)
call TimerStart(t, duration, false, function callback)
//bj_HEROSTAT_STR = Strength
//bj_HEROSTAT_AGI = Agility
//bj_HEROSTAT_INT = Intelligence
call SetHeroStat(whichUnit, whichStat, GetHeroStatBJ(whichStat, whichUnit, false) + value)
set udg_TimedStat_Unit[id] = whichUnit
set udg_TimedStat_Amount[id] = value
set udg_TimedStat_Type[id] = whichStat
set t = null
endfunction
I assume it works (not looking at negative attributes etc).
You can add a negative value and it will remove that value for the set amount of time.
Because I use my system, the code looks much cleaner as there are no hashtables involved in these actions themselves.
I hope that this was a little bit helpfull and that you can see how usefull timers are.