Skip to content

Types

The types state, events, requests and commands are declared with, in the global t, on the server and in client scripts. Most are a type themselves, t.int to t.duration, listed first below; t’s functions make a type of others. A name t lacks, as t.innt, fails where it is read, so at load.

Limits are part of a type: t.int { min = 1, max = 999 }, t.number { min = 0 }, t.string { max = 32 } in bytes. A value outside them is refused, never clamped, a default too. Types nest 32 deep at most.

Here too are the helpers for the engine’s axes, angles and vector.distance, and the timings a change eases by, timing. A transition is {seconds, timing}, 0 seconds being at once; a style’s transition stays CSS’s text. See units and axes.

On both sides t.int: Limited

A whole number. Called with limits, t.int { min = 1, max = 999 }, it refuses one outside them, never clamping it.

On both sides t.number: Limited

A finite number. Called with limits, t.number { min = 0 }, it refuses one outside them, never clamping it.

On both sides t.string: Sized

Text. Called with its most bytes, t.string { max = 32 }, it refuses longer text; a command's argument is one word.

On both sides t.bool: Type

true or false.

On both sides t.vector: Type

A point or a direction: given as a vector or a table of x, y and z, read as a vector.

On both sides t.player: Type

A player or an NPC: sent as its id, read as the player. A command's argument is typed as part of a name or #id.

On both sides t.entity: Type

An entity: sent as its id, read as the entity.

On both sides t.model: Type

A model's file, by its name, checked as it is given.

On both sides t.sound: Type

A sound's file, by its name, checked as it is given.

On both sides t.effect: Type

An effect's file, by its name, checked as it is given.

On both sides t.image: Type

An image's file, by its name, checked as it is given.

On both sides t.weapon: Type

A weapon's file, by its name, checked as it is given.

On both sides t.animation: Type

An animation's file, by its name, checked as it is given.

On both sides t.material: Type

A material's file, by its name, checked as it is given.

On both sides t.text: Type

The rest of a command's line: its last argument's type alone.

On both sides t.duration: Type

A whole number of seconds typed with its unit, 30s, 5m, 12h or 7d, up to 3650 days: a command's argument's type alone.

On both sides angles.forward(a) → vector

Gives the way angles face, a vector of length 1: yaw 0 faces +Z, positive yaw turns left, and pitch looks up.

It takes angles, { yaw, pitch, roll } in radians, each 0 where it is left out, or anything with them: a marker, a player, a model or a part.

NameTypeWhat it is
aAngledNeeded.
Returns
vector
Fails
  • a value of the wrong type
model("rocket", { at = p.position + angles.forward(p) * 2 })
On both sides angles.right(a) → vector

Gives the way to the right of angles, a vector of length 1, as roll tips it.

NameTypeWhat it is
aAngledNeeded.
Returns
vector
Fails
  • a value of the wrong type

To put a model beside a player, on their right

Section titled “To put a model beside a player, on their right”
model("rocket", { at = p.position + angles.right(p) * 1.5 })
On both sides angles.up(a) → vector

Gives the way up from angles, a vector of length 1, as pitch and roll tip it.

NameTypeWhat it is
aAngledNeeded.
Returns
vector
Fails
  • a value of the wrong type
local at, leaning = vector.create(0, 0, 5), { pitch = 0.3 }
model("rocket", { at = at, angles = leaning })
model("rocket", { at = at + angles.up(leaning) * 2, angles = leaning })
On both sides angles.of(dir) → Angles

Gives the yaw and pitch that face a direction; one straight up or down faces yaw 0.

NameTypeWhat it is
dirvectorNeeded.
Returns
Angles
Fails
  • a value of the wrong type
local at = vector.create(0, 0, 5)
model("rocket", { at = at, angles = angles.of(p.position - at) })
On both sides angles.rotate(v, a) → vector

Gives an offset turned by angles: where it is from what has them, as vector.create(0, 0, 1) is 1 m in front.

NameTypeWhat it is
vvectorNeeded.
aAngledNeeded.
Returns
vector
Fails
  • a value of the wrong type

To put a model at the tip of a player’s gun

Section titled “To put a model at the tip of a player’s gun”
model("rocket", { at = p.position + vector.create(0, 1.5, 0) + angles.rotate(vector.create(-0.2, 0, 0.8), p) })
On both sides angles.delta(a, b) → Angles

Gives the shortest turn from one angles to another, each from -π to π: of the angles either has, the other's 0 where it has none.

NameTypeWhat it is
aAngledNeeded.
bAngledNeeded.
Returns
Angles
Fails
  • a value of the wrong type
local target = vector.create(5, 0, 5)
local turn = angles.delta(p, angles.of(target - p.position))
if math.abs(turn.yaw) < 0.1 then
say(`{p.name} aims at it`)
end
On both sides angles.lerp(a, b, t) → Angles

Gives the angles t of the way from one to another, the short way round, 0.5 halfway: of the angles either has, the other's 0 where it has none.

NameTypeWhat it is
aAngledNeeded.
bAngledNeeded.
tnumberNeeded.
Returns
Angles
Fails
  • a value of the wrong type

To aim a camera halfway from yaw 0 to where a player looks

Section titled “To aim a camera halfway from yaw 0 to where a player looks”
spawn_camera({ at = vector.create(0, 2, 0), angles = angles.lerp({ yaw = 0 }, p, 0.5) })
On both sides vector.distance(a, b) → number

Gives the distance between two points, in metres.

NameTypeWhat it is
avectorNeeded.
bvectorNeeded.
Returns
number
Fails
  • a value of the wrong type

To hurt the players within 10 m of a blast

Section titled “To hurt the players within 10 m of a blast”
local at = vector.create(0, 0, 0)
for _, p in players do
if vector.distance(p.position, at) < 10 then
p:hurt(20)
end
end
On both sides timing.cubic_bezier(x1, y1, x2, y2) → TimingFunction

Makes a timing of a cubic Bézier curve from (0, 0) to (1, 1), as CSS's cubic-bezier(): y1 and y2 past 0 or 1 overshoot.

A timing is how a change eases: one of the words "linear", "ease", "ease-in", "ease-out" and "ease-in-out", or what timing.cubic_bezier and timing.steps make. A move order takes one, and a client script’s transition, { seconds, timing }, linear without it. CSS’s strings, as "cubic-bezier(…)", are none.

NameTypeWhat it is
x1number0 to 1Needed.
y1number-1000 to 1000Needed.
x2number0 to 1Needed.
y2number-1000 to 1000Needed.
Returns
TimingFunction
Fails
  • a value of the wrong type
  • a value outside its range

To raise a platform, overshooting a little before it settles

Section titled “To raise a platform, overshooting a little before it settles”
local platform = model("rocket")
platform:move_by(vector.create(0, 3, 0), 2, { timing = timing.cubic_bezier(0.3, 1.4, 0.6, 1) })
On both sides timing.steps(count, jump?) → TimingFunction

Makes a timing of equal jumps, as CSS's steps(), jump saying where they fall: jump-end without it.

jump-start jumps at the start of each step and jump-end at its end; jump-none at neither end of the whole, so it takes 2 steps at least, and jump-both at both.

NameTypeWhat it is
countnumber1 to 65535Needed.
jumpJump?May be left out.
Returns
TimingFunction
Fails
  • a value of the wrong type
  • a value outside its range
view:set({ fov = 30 }, { seconds = 0.4, timing = timing.steps(4) })
On both sides t.one_of(values) → Type

Makes a type of one of a list of words, or of numbers, at least one and none twice.

A value not in the list is refused. A command’s argument of words takes one of them, which a player’s game completes as it is typed; a one_of of words keys a t.map.

NameTypeWhat it is
values{string} | {number}Needed.
Returns
Type
Fails
  • a value of the wrong type

To let admins choose how hard the zombies are

Section titled “To let admins choose how hard the zombies are”
server_state("difficulty", t.one_of { "easy", "normal", "hard" }, "normal", { read_by = everyone, set_by = admins })
On both sides t.choices(list) → Type

Makes a command's argument's type of a word of the list choices fills, by the list's name.

A player’s game completes the words as they are typed; a word not in the list is refused.

NameTypeWhat it is
liststringNeeded.
Returns
Type
Fails
  • a value of the wrong type
command("nextmap", { help = "Vote for the next map", args = { { "map", t.choices("maps") } } }, function(e)
say(`{e.player.name} votes for {e.map}`)
end)
on("start", function()
choices("maps", { "yard", "testbed" })
end)
On both sides t.optional(inner) → Type

Makes a type of a value of another, or nil.

An optional type stays as it is. A command’s optional argument may be left out, after those it needs, and reads nil.

NameTypeWhat it is
innerTypeNeeded.
Returns
Type
Fails
  • a value of the wrong type

To keep whom each player marked, if anyone

Section titled “To keep whom each player marked, if anyone”
player_state("marked", t.optional(t.player), nil, { read_by = owner })
command("boot", { args = { { "target", t.player }, { "reason", t.optional(t.text) } }, run_by = admins }, function(e)
e.target:kick(e.reason or "booted")
end)
On both sides t.secret(inner) → Type

Makes the type of a setting's secret, t.secret(t.string): text the mod passes to a call but never reads.

A secret is a server_state of set_by = config without read_by, or it fails at load; t.optional of one may be left unset, blank text making it nil. The mod holds a handle that shows as <secret name> wherever it is printed, joins into another with .., and gives its text only where a call connects: sql.pool takes one as its URL, and http.request as its URL or a header’s value. Whatever the server prints of the mod and of what a call answers has its text replaced so.

NameTypeWhat it is
innerTypeNeeded.
Returns
Type
Fails
  • a value of the wrong type

To keep the stats database’s address out of the mod

Section titled “To keep the stats database’s address out of the mod”
server_state("stats_db", t.secret(t.string), "sqlite::memory:", { set_by = config })
On both sides t.list(element) → Type

Makes a type of a list of values of another: a table of keys 1 to n and no other.

NameTypeWhat it is
elementTypeNeeded.
Returns
Type
Fails
  • a value of the wrong type
player_state("perks", t.list(t.string { max = 16 }), {}, { read_by = owner })
On both sides t.record(fields) → Type

Makes a type of a table of named fields, each of its own type: a field's name is up to 32 lowercase letters, digits and _.

Every field is given, but an optional one, and no other; an event’s or a request’s payload is one.

NameTypeWhat it is
fields{[string]: Type}Needed.
Returns
Type
Fails
  • a value of the wrong type
event("bought", t.record { player = t.player, weapon = t.weapon, price = t.int { min = 0 } }, { read_by = everyone })
On both sides t.map(key, value) → Type

Makes a type of a table of keys of one type to values of another.

A key is an int, a string, a bool, a player, an entity, a file or a one_of of words, up to 32 bytes as sent.

NameTypeWhat it is
keyTypeNeeded.
valueTypeNeeded.
Returns
Type
Fails
  • a value of the wrong type
player_state("kills_by_weapon", t.map(t.weapon, t.int { min = 0 }), {}, { read_by = owner })