/* TimerV 1.0, by Violet CLM http://www.jazz2online.com/snippets/157/timerv/ */ /* Usage: To schedule a function to be called at some point in the future, call the TimerV constructor with the desired delay and function as arguments, e.g.: void myAlert() { jjAlert("A second has passed."); } void onLevelLoad() { TimerV(70, myAlert); //calls myAlert after one second (70 ticks) } Anonymous functions (or delegates) may be used instead: void onLevelLoad() { TimerV(70, function(){ jjAlert("A second has passed."); }); //same effect as above } For a recurring event, have the called function construct another timer for itself: void morphEveryone() { for (int i = 0; i < jjLocalPlayerCount; ++i) jjLocalPlayers[i].morph(true); TimerV(5 * 70, morphEveryone); } void onLevelLoad() { morphEveryone(); //morphs all local players every five seconds } To pass one or more arguments to the delayed function, use a function that takes a single dictionary@ as its sole argument, and pass that dictionary@ to the TimerV constructor: void onFunction0(uint8 triggerID) { if (!jjTriggers[triggerID]) { jjTriggers[triggerID] = true; TimerV( //turns on, then off, whichever trigger was specified by the offset parameter of the Text event 2 * 70, function(arguments) { jjTriggers[uint8(arguments["ID"])] = false; }, dictionary = {{"ID",triggerID}} ); } } Another use of a dictionary argument is to limit the number of times the function is called: void playSound(dictionary@ arguments) { jjSamplePriority(SOUND::COMMON_COIN); int count = int(arguments["count"]) - 1; if (count > 0) { arguments["count"] = count; TimerV(40, playSound, arguments); } } void onLevelLoad() { playSound(dictionary = {{"count",5}}); //plays the COMMON_COIN sample exactly five times } As mentioned, the TimerV lines are actually constructors, not regular functions. If you have any reason to keep a TimerV object around after its construction, e.g. if there's a possibility you might need to cancel it, it provides the following API: const bool Active true iff this timer is still running const int Elapsed How many ticks have passed since the construction, or -1 if Active is false const int Total The original time parameter passed to the constructor, as a reminder, or -1 if Active is false const int Remaining (Total - Elapsed), or -1 if Active is false bool Paused While true, this timer will not advance, though Active will remain true bool Stop() Stops the timer early (WITHOUT executing the function) and returns true, or returns false if Active was false */ funcdef void TimerVDictionaryFunction(dictionary@); class TimerV : jjBEHAVIORINTERFACE { TimerV(int time, jjVOIDFUNC@ callback) { @_callback = @callback; _start(time); } TimerV(int time, TimerVDictionaryFunction@ callback, dictionary@ arguments) { @_callbackWithArguments = @callback; @_arguments = @arguments; _start(time); } bool get_Active() const { return cast(_object.behavior) is this; } int get_Elapsed() const { if (Active) return _object.age; return -1; } int get_Total() const { if (Active) return _object.counter; return -1; } int get_Remaining() const { if (Active) return _object.counter - _object.age; return -1; } bool Stop() { if (Active && _object.age < _object.counter) { _object.delete(); return true; } return false; } bool Paused = false; private jjVOIDFUNC@ _callback = null; private TimerVDictionaryFunction@ _callbackWithArguments; private dictionary@ _arguments; private jjOBJ@ _object; private int _startTime; private void _start(int time) { if (time > 0) { @_object = jjObjects[jjAddObject(OBJECT::BEES, -1000, -1000, 0, CREATOR::OBJECT, BEHAVIOR::BEES)]; _object.behavior = this; _object.counter = time; _object.age = 0; _object.playerHandling = HANDLING::PARTICLE; _object.deactivates = false; _startTime = jjGameTicks; } else { @_object = jjObjects[0]; //avoid null pointer access _pickCallback(); } } private void onBehave(jjOBJ@ obj) { if (!Paused && jjGameTicks > _startTime && obj is _object && ++_object.age >= _object.counter) { _pickCallback(); _object.delete(); } } private void _pickCallback() { if (_callback !is null) _callback(); else _callbackWithArguments(_arguments); } }