- Joined
- Sep 9, 2007
- Messages
- 6,759
JASS:
// --------------------------------------------------------------------------------------------------------------------
//
// TimedStack
// =====
//
// Version: 1.3.0
// Author: Anachron
//
// Requirements:
// (New) Table [by Bribe] (v. 3.1) [url]http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/[/url]
// Stack [by Anachron] (v. 1.5)
// IndexStack [by Anachron] (v. 1.3)
// Optional:
// TimerUtils [by Vexorian] (v. 2.0) [url]http://www.wc3c.net/showthread.php?t=101322[/url]
//
// Description:
// TimedStack is a library to destroy redundant code based on timers.
// Any code can be executed either once or periodic for every instance.
// You can choose between a global timer or a local timer (so you can have different periods too).
// This is all bound to a textmacro so you can put them into modules and structs as you wish.
// Timer handling / recycling is all done by the system.
//
// History:
// 1.0.0: Initial Release
// 1.1.0: Fixed problem in onPeriodic method and renamed it, changed pause to stop, TimerUtils is optional now
// 1.2.0: Added checks in start + stop to skip when called twice, added clear, changed active to be method operator,
// replaced finished with iterate, added a lot of documentation/comments, added TimerUtils in optional
// 1.3.0: Periodic and delay are now constant in global timers, used active instead of checking table directly (still inline),
// Added limited intervals, added API for TextMacro, removed duplicated if
//
// API:
// ------------------------------------------------------------------------------------------------
// Basics
// ------------------------------------------------------------------------------------------------
// .active --> Boolean whether the instance has active timer or not (only readable)
// .iterate --> Boolean whether the instance should be removed from iteration or not
// .intervals --> Integer amount of times the instance should be iterated (-1 = endless)
// .start() --> Add the current instance to running stack
// .stop() --> Remove the current instance from running stack
// thistype.clear() --> Remove all instances from running stack
//
// ------------------------------------------------------------------------------------------------
// Advanced
// ------------------------------------------------------------------------------------------------
// [thistype].clock --> Timer instance for running
// [thistype].periodic --> Boolean whether timers are periodic or once
// [thistype].delay --> Delay / Period of timer
// thistype.myself --> Current iterated instance
//
// ------------------------------------------------------------------------------------------------
// Instance Getting
// ------------------------------------------------------------------------------------------------
// call .onPeriod()
// Method: (public/private) method onPeriod takes nothing returns nothing
// This way you already have the local instance in the method (this)
// call thistype.onPeriod()
// Method: (public/private) static method onPeriod takes nothing returns nothing
// If you do it like this, use thistype.myself
// call thistype.onPeriod(thistype.myself or this)
// Method: (public/private) static method onPeriod takes thistype this returns nothing
// Just like the first example, you already have this in the method
//
// ------------------------------------------------------------------------------------------------
// Textmacro API
// ------------------------------------------------------------------------------------------------
// 1. GLOBAL --> Boolean whether timer should be used globally for all instances or not
// 2. PERIODIC --> Boolean whether to run the timer in intervals or not
// 3. DELAY --> Real amount of time between each iteration
// 4. TIMES --> Integer how many iterations one instance can last (-1 for endless)
// 5. ACTION --> Some code to do, use a string to pass code ("call .onPeriod()")
//
// ------------------------------------------------------------------------------------------------
// Examples
// ------------------------------------------------------------------------------------------------
// Global timer, periodic, 0.03175, good for missile engines or smooth fading/effects
// //! runtextmacro TimedStack("true", "true", "0.03175", "-1", "call .onPeriod")
// Global timer, 1., once, good for non critical actions, just like repick
// //! runtextmacro TimedStack("true", "false", "1.", "-1", "call .onActivate")
// Local timer, once, good for delayed stuff just like effects
// //! runtextmacro TimedStack("false", "false", "1.", "-1", "call .cleanSpell")
// Local timer, periodic, custom time, good for anything that is spell level related
// //! runtextmacro TimedStack("false", "true", "1.0", "-1", "call .onFinish")
// --------------------------------------------------------------------------------------------------------------------------
library TimedStack requires Stack, IndexStack, optional TimerUtils
//! textmacro TimedStack takes GLOBAL, PERIODIC, DELAY, TIMES, ACTION
private static Stack running = 0
public static thistype myself = 0
public boolean iterate = true
public integer intervals = $TIMES$
static if $GLOBAL$ then
private static constant real delay = $DELAY$
private static constant boolean periodic = $PERIODIC$
private static timer clock = null
else
private static IndexStack timers = 0
private timer clock = null
private real delay = $DELAY$
private boolean periodic = $PERIODIC$
endif
public method operator active takes nothing returns boolean
return thistype.running.has(this)
endmethod
private static method TS_PERIODIC takes nothing returns nothing
local timer expired = GetExpiredTimer()
local thistype this = 0
local boolean once = false
static if $GLOBAL$ then
set once = not thistype.periodic
call thistype.running.reset()
loop
exitwhen not thistype.running.hasNext()
set this = thistype.running.getNext()
else
set once = not .periodic
set this = thistype.timers[GetHandleId(expired)]
endif
if .active then
set thistype.myself = this
if .intervals != 0 then
$ACTION$
endif
if .intervals > 0 then
set .intervals = .intervals -1
endif
if .intervals == 0 then
set .iterate = false
endif
endif
if ((not .iterate or once) and active) or this == 0 then
call .stop()
static if not $GLOBAL$ then
call thistype.timers.delete(GetHandleId(expired))
call PauseTimer(expired)
static if LIBRARY_TimerUtils then
call ReleaseTimer(.clock)
else
call DestroyTimer(.clock)
endif
endif
endif
static if $GLOBAL$ then
endloop
if thistype.running.count == 0 then
call PauseTimer(thistype.clock)
static if LIBRARY_TimerUtils then
call ReleaseTimer(thistype.clock)
else
call DestroyTimer(thistype.clock)
endif
endif
endif
set expired = null
endmethod
public method start takes nothing returns nothing
if .active then
return
endif
set .iterate = true
static if $GLOBAL$ then
if thistype.clock == null then
static if LIBRARY_TimerUtils then
set thistype.clock = NewTimer()
else
set thistype.clock = CreateTimer()
endif
endif
if thistype.running.count == 0 then
call TimerStart(thistype.clock, thistype.delay, thistype.periodic, function thistype.TS_PERIODIC)
endif
else
if .clock == null then
static if LIBRARY_TimerUtils then
set .clock = NewTimer()
else
set .clock = CreateTimer()
endif
endif
call TimerStart(.clock, .delay, .periodic, function thistype.TS_PERIODIC)
if thistype.timers == 0 then
set thistype.timers = IndexStack.create()
endif
set thistype.timers[GetHandleId(.clock)] = this
endif
if thistype.running == 0 then
set thistype.running = Stack.create()
endif
call thistype.running.add(this)
endmethod
public method stop takes nothing returns nothing
if not .active then
return
endif
call thistype.running.delete(this)
static if $GLOBAL$ then
if thistype.running.count == 0 then
call PauseTimer(thistype.clock)
endif
else
call PauseTimer(.clock)
endif
endmethod
public static method clear takes nothing returns nothing
local thistype this = 0
call thistype.running.reset()
loop
exitwhen not thistype.running.hasNext()
set this = thistype.running.getNext()
call .stop()
endloop
endmethod
//! endtextmacro
endlibrary
Last edited: