Skip to content

Timers

Doing something later, or again and again. A module names each timer at its top with what it runs, then starts it once or on a loop, for the whole match or for one player.

A handler may also wait, and go on that many seconds later. Whatever it held may be gone by then: check exists.

now() is the mod’s clock. A client script reads the same clock, so a time the server keeps in state, such as when a round ends, counts down alike on every screen.

On the server now() → number
On a client now(step?) → number

The mod's time, in seconds, as of its last tick.

On the server

A client’s now() reckons the same clock, so a time the mod keeps in state reads there as it does here.

Returns
number

On a client

The server’s mod clock as this client reckons it, in seconds, 0 before the first snapshot; with step, rounded down to a whole number of step seconds.

It reads the same clock as the server’s now(), so a time the mod keeps in state reads here as there: now() - match.started. Read in a render, now() draws it again every frame, but now(step) once a step: now(1) for a countdown of seconds. step is above 0.

NameTypeWhat it is
stepnumber?May be left out.
Returns
number
Fails
  • a value of the wrong type

To keep when the match started, for the clients’ clocks

Section titled “To keep when the match started, for the clients’ clocks”
match_state("started", t.number, 0, { read_by = everyone })
on("start", function()
match.started = now()
end)
local ends = now() + 60
mount(function()
return Box { `{math.max(0, math.ceil(ends - now(1)))} s`, style = { right = 40, top = 40 } }
end)
On the server wait(seconds)

Pauses the handler, timer or command for seconds: it goes on with the next line at the first mod tick that much later.

What it held may be gone by then: check a player’s or an entity’s exists. A handler waits, never a module’s top, on_tick, on_event, a group or a function called outside a handler. A reload in place, or a new match, drops the handlers waiting. A handler’s error undoes what it did since it last waited, or since it started.

NameTypeWhat it is
secondsnumber0 to 3600Needed.
Fails
  • a value of the wrong type
  • a value outside its range
for left = 3, 1, -1 do
say(`Respawning in {left}`, { to = { p } })
wait(1)
end
if p.exists then
p:respawn()
end
On the server timer(name, fn)

Names the function the module's timer name runs, given the timer's player if it has one.

A module names its timers at its top, as it loads, and starts them with delay or loop. A timer is its module’s, by its name and its player, so two modules’ timers of one name never meet. It runs the function its name has as it fires, so after a reload in place an edit takes effect at its next run. A module’s names are those its last load gave, or those before if that load failed; a timer whose name has no function as it fires is dropped, and said. A timer goes with its player, and with its module.

NameTypeWhat it is
namestringNeeded.
fn(player: Player?) -> ()Needed.
Fails
  • a value of the wrong type
timer("time_up", function()
say("Time is up")
start_match()
end)
on("start", function()
delay("time_up", 300)
end)
On the server delay(name, seconds, player?)

Runs the module's timer name once, seconds from now, given player if one is given; given again before it runs, it starts over.

A timer given a player is separate from one of the same name with no player or another player, and goes as they leave. It runs as a handler does, a coroutine that may wait, on the mod tick within half a tick of its time, after that tick’s handlers. Timers outlast a reload in place, and go as the map changes. A name the module gave no timer fails.

NameTypeWhat it is
namestringNeeded.
secondsnumber0 to 3600Needed.
player(Player | number)?May be left out.
Fails
  • a value of the wrong type
  • a value outside its range

To bring a player back 5 seconds after they die

Section titled “To bring a player back 5 seconds after they die”
timer("respawn", function(p)
p:respawn()
end)
on("killed", function(e)
delay("respawn", 5, e.victim)
end)
On the server loop(name, seconds, player?)

Runs the module's timer name every seconds, given player if one is given, until cancel; given again, it takes the new time and keeps its beat.

seconds is above 0 and up to an hour. A beat that ran late counts on from then, and one that fails is done for that beat alone. Otherwise it is a timer as delay’s.

NameTypeWhat it is
namestringNeeded.
secondsnumberNeeded.
player(Player | number)?May be left out.
Fails
  • a value of the wrong type

To give every player 10 points every 5 seconds

Section titled “To give every player 10 points every 5 seconds”
player_state("points", t.int { min = 0 }, 0, { read_by = everyone })
timer("income", function()
for _, p in players do
p.points += 10
end
end)
on("start", function()
loop("income", 5)
end)
On the server cancel(name, player?)

Stops the module's timer name, of player if one is given; one not running is left as it is.

NameTypeWhat it is
namestringNeeded.
player(Player | number)?May be left out.
Fails
  • a value of the wrong type

To bleed a player who is hit until they bandage

Section titled “To bleed a player who is hit until they bandage”
timer("bleed", function(p)
p:hurt(2)
end)
on("hit", function(e)
loop("bleed", 1, e.victim)
end)
command("bandage", { help = "Stop your bleeding" }, function(e)
cancel("bleed", e.player)
end)
On both sides on("tick", fn)

The mod ticked: heard as often as the server's mod ticks.

NameTypeWhat it is
e.deltanumberThe seconds since the last.
On a client on("frame", fn)

A frame is drawn: heard once a frame, as often as the player's game draws.

NameTypeWhat it is
e.deltanumberThe seconds since the last frame.