Solarus quests  1.6
Quest maker's reference
Timers

Timers allow you to call a function in the future with a specified delay.

Here is a first example of use:

-- Play sound "secret" in one second.
local function play_secret_sound()
  sol.audio.play_sound("secret")
end

sol.timer.start(1000, play_secret_sound)

Shorter version to do the same thing:

-- Equivalent code using an anonymous function.
sol.timer.start(1000, function()
  sol.audio.play_sound("secret")
end)

You can repeat a timer by returning true from your function:

-- Call a function every second.
sol.timer.start(1000, function()
  sol.audio.play_sound("danger")
  return true  -- To call the timer again (with the same delay).
end)

To make a timer that repeats itself 10 times, just return false after 10 calls:

-- Call a function ten times, with one second between each call.
local num_calls = 0
sol.timer.start(1000, function()
  sol.audio.play_sound("danger")
  num_calls = num_calls + 1
  return num_calls < 10
end)

It is possible to restrict the lifetime of a timer to a context, like the game, the map or an enemy:

-- Enemy that shoots a fireball every 5 seconds until it is killed.
sol.timer.start(your_enemy, 5000, function()
  sol.audio.play_sound("attack_fireball")
  map:create_enemy(...)  -- Code that creates the fireball.
  return true  -- Repeat the timer.
end)

Setting the context to an enemy ensures that when the enemy is killed, the timer is canceled. Otherwise, the callback function would still be called: in this example, you would hear the "attack_fireball" sound and the fireball would be created even if the enemy is killed in the meantime.

Functions of sol.timer

sol.timer.start([context], delay, callback)

Sets a function to be called after a delay.

If the delay is set to zero, the function is called immediately.

  • context (map, game, item, map entity, state, menu or sol.main; optional): Determines the lifetime of the timer. The context is where the timer belongs.
    If the context gets closed before the timer is finished, then the timer is automatically canceled. More precisely, the following rules are applied.
    • If you set the context to a map, the timer is canceled when the player goes to another map.
      Example: a button that opens a door for a limited time.
    • If you set the context to a game or an item, the timer is canceled when the game is closed. (Items have the same lifetime as the game they belong to.) This is only possible when the game is running. Example: hot water that becomes cold after a few minutes, and that the player should bring to an NPC on another map while it's still hot.
    • If you set the context to a map entity, the timer is canceled when the entity is removed from the map. In the case of an enemy, the timer is also canceled when the enemy is hurt, immobilized or restarts. Also note that while the entity is suspended, the timer is also suspended. An entity may be suspended when the game is suspended, or when the entity is disabled.
      Example: a boss who shoots fireballs every 10 seconds. Most enemy scripts usually create timers.
    • If you set the context to a state, the timer is canceled when the custom hero state finishes or when the hero is removed. Like entity timers, state timers get suspended when the hero is suspended. Example: charging an attack during 3 seconds in a custom state.
    • If you set the context to a menu, the timer is canceled when the menu is closed.
      Example: in the title screen, show some animations after a few seconds without action from the user.
    • If you set the context to the sol.main table, the timer is canceled when Lua is closed. Thus, it will be a global timer. This kind of timer is not often needed.
      Example: dumping some global information periodically while the program is running.
    • If you don't specify a context, then a default context is set for you: the current map during a game, and sol.main if no game is running.
  • delay (number): Delay before calling the function in milliseconds.
  • callback (function): The function to be called when the timer finishes. If this callback function returns true, then the timer automatically repeats itself with the same delay. In this case, if the delay is shorter than the time of a cycle of the main loop, the callback may be executed several times in the same cycle in order to catch up.
  • Return value (timer): The timer created. Most of the time, you don't need to store the returned timer. Indeed, there is no problem if it gets garbage-collected: the timer persists in the engine side until its completion or the end of its context. Usually, you will store the return value only if you need to stop the timer explicitly later or to call another method on it.
Remarks
When they are created, map timers, map entity timers and item timers are initially suspended if a dialog is active. After that, they get automatically suspended and unsuspended when the map is suspended or unsuspended. This default behavior is suited for most use cases, but if you want to change it, you can use timer:set_suspended() and timer:set_suspended_with_map().

sol.timer.stop_all(context)

Cancels all timers that are currently running in a context.

This function is equivalent to calling timer:stop() on each timer of the context. It may allow you to avoid to store explicitly all your timers.

Remarks
Canceling timers by hand may be tedious and error-prone. In lots of cases, you can simply pass a context parameter to sol.timer.start() in order to restrict the lifetime of your timer to some other object.

Methods of the type timer

timer:stop()

Cancels this timer.

If the timer was already finished or canceled, nothing happens.

Remarks
Canceling timers by hand may be tedious and error-prone. In lots of cases, you can simply pass a context parameter to sol.timer.start() in order to restrict the lifetime of your timer to some other object.

timer:is_with_sound()

Returns whether a clock sound is played repeatedly during this timer.

  • Return value (boolean): true if a clock sound is played with this timer.

timer:set_with_sound(with_sound)

Sets whether a clock sound is played repeatedly during this timer.

  • with_sound (boolean, optional): true to play a clock sound repeatedly (no value means true).

timer:is_suspended()

Returns whether this timer is currently suspended.

  • Return value (boolean): true if this timer is currently suspended.

timer:set_suspended([suspended])

Returns whether this timer is currently suspended.

  • suspended (boolean, optional): true to suspend the timer, false to unsuspend it (no value means true).

timer:is_suspended_with_map()

Returns whether this timer gets automatically suspended when the map is suspended.

  • Return value (boolean): true if this timer gets suspended when the map is suspended.

timer:set_suspended_with_map([suspended_with_map])

Sets whether this timer should automatically be suspended when the map gets suspended.

The map is suspended by the engine in a few cases, like when the game is paused, when there is a dialog or when the camera is being moved by a script. When this happens, all map entities stop moving and most sprites stop their animation. With this setting, you can choose whether your timer gets suspended automatically as well.

By default, map timers, entity timers, state timers and item timers are suspended with the map.

  • suspended_with_map (boolean, optional): true to suspend the timer when the map is suspended, false to continue (no value means true).
Remarks
When this setting is true, entity timers also get automatically suspended when the entity is disabled.

timer:get_remaining_time()

Returns the remaining time of this timer.

  • Return value (number): The time remaining in milliseconds. 0 means that the timer is finished (or will finish in the current cycle) or was canceled.

timer:set_remaining_time(remaining_time)

Changes the remaining time of this timer.

This function has no effect if the timer is already finished.

  • remaining_time (number): The time remaining in milliseconds. 0 makes the timer finish now and immediately executes its callback.
Remarks
When a timer is repeated (that is, if its callback returns true or a number), the timer gets rescheduled with its full delay again, no matter if you called this function in the meantime.