Skip to content

Menus

Screens a client script opens over the game: a buy menu, a vote, a dialog asking a question. A menu frees the mouse and takes keys; one opens at a time, and a dialog opens over it and gives back its answer. A menu may open on a purpose action’s key, as a buy menu on buy, which the player chose for every server.

Here too is the loading screen a mod may draw in place of the stock one while players load a match. The stock one lists the purpose actions your mod handles, with their labels and the player’s keys; your own gets them as props.binds.

On a client loading_screen(component)

Draws the loading screen in place of the stock one while the match loads, once a mod, at a script's top.

The component is given {map, title, image, gametype, stage, progress, bytes_done, bytes_total, bytes_per_second, binds} and draws again as they or what it read change. title and image are the map’s, image nil for none. While connecting, map and gametype are empty and title is the server’s address. stage is "connecting", "waiting" (while the mod’s connecting holds the join), "downloading", "map", "files" or "declarations"; progress is the share of the match’s files loaded, 0 to 1, or while downloading of the bytes, bytes_done of bytes_total coming at bytes_per_second, all 0 at the other stages. binds are the purpose actions the server handles, each {action, label, keys}: the action, as "tactical", the label it has here, and the keys the player put it on, the first as Controls shows it first, empty for none.

It takes no pointer and goes once the match plays. The stock screen shows while none is declared, and from when its render fails until the match plays. Another script’s call fails, naming both.

NameTypeWhat it is
component(props: LoadingProps) -> Node?Needed.
Fails
  • a value of the wrong type
loading_screen(function(props)
return Box {
`{props.title} ({props.stage})`,
Box { style = { width = `{props.progress * 100}%`, height = 8, background = "#ffcc33" } },
style = { left = 0, right = 0, bottom = 80, padding = 40, background = "rgba(0, 0, 0, 0.6)" },
}
end)

To list the keys of what the server’s mod does on them

Section titled “To list the keys of what the server’s mod does on them”
loading_screen(function(props)
return Box {
Each(props.binds, function(bind)
return Box { `{bind.keys[1] or "unbound"}: {bind.label}`, key = bind.action }
end),
style = { left = 80, top = 80, fontSize = 28 },
}
end)
On a client menu(name, options?, render) → Menu

Declares a menu, which open(menu, props) shows over the HUD, freeing the pointer; gives its handle.

It is declared at a script’s top. Its name is up to 16 lowercase letters, digits and _, one script’s: another script declaring it fails, naming both. render is given the props open gave, copied, with close(value), which closes it. One menu is open at a time, open replacing it. A player opens one with its action’s key, a key they bind to open <name>, or /open <name>, with no props.

While a menu shows, the player’s binds do nothing and the keys held are let go. A tap of Esc runs its keys.Escape, false for a forced choice, or else opens its back, or else closes it. Holding Esc a second always opens the engine’s menu over the game, a ring filling from a quarter second: no script sees the hold.

action takes a purpose action, as "buy", which no mod binds to a key: the player has, once for every server. Two menus on one action fail at load. A menu on an action the server handles opens as its handler hears the key go down.

NameTypeWhat it is
namestringNeeded.
optionstable?A table of the options below. It, and each option, may be left out.
pointerbooleandefault trueFrees the pointer, its tree taking hover and clicks, and takes every key; false keeps the player playing but for its keys, which cannot then be Esc: the keys the player moves, jumps and chats with stay theirs.
keys({[string]: ((props: MenuProps) -> ()) | false})?What its keys do, as { Q = fn, ["1"] = fn, Enter = fn, Escape = false }: a key a player binds or Escape, each given the props, false doing nothing; Mouse1 and Mouse2 only with pointer = false, as they click.
onOpen((props: MenuProps) -> ())?Runs as it opens, given the props.
onClose((props: MenuProps) -> ())?Runs as it closes, given the props.
backstring?The menu a tap of Esc opens in its place, by name, rather than closing it.
togglebooleandefault falseA key bound to open it, or to its action, closes it.
action("tactical" | "lethal" | "utility" | "ultimate" | "buy" | "drop" | "quick_menu" | "ping" | "map")?The purpose action whose keys open it, as "buy"; the server's handler of it runs too.
holdbooleandefault falseCloses as the key that opened it is let go.
helpstring?Its line on Settings → Controls, up to 64 bytes.
render(props: MenuProps) -> Node?Needed.
Returns
Menu
Fails
  • a value of the wrong type
  • an option it does not have
local Shop = menu("shop", { action = "buy", toggle = true, help = "Buy weapons" }, function(props)
return Box {
"Shop",
Box { "Close", onClick = function() props.close() end },
style = { left = "40%", top = "30%", padding = 24, background = "rgba(0, 0, 0, 0.8)" },
}
end)
On a client dialog(name, options?, render) → Menu

Declares a dialog, which open(dialog, props) shows over the menu, waiting for its answer; gives its handle.

It is declared at a script’s top, as a menu is. One dialog is open at a time, over the menu if one is. open of one waits, in a handler only, until it closes, and gives what props.close(value) passed, or nil if it closed otherwise: by Esc, which closes it unanswered unless its keys.Escape says, another dialog, or its menu closing.

NameTypeWhat it is
namestringNeeded.
optionstable?A table of the options below. It, and each option, may be left out.
pointerbooleandefault trueFrees the pointer, its tree taking hover and clicks, and takes every key; false keeps the player playing but for its keys, which cannot then be Esc: the keys the player moves, jumps and chats with stay theirs.
keys({[string]: ((props: MenuProps) -> ()) | false})?What its keys do, as { Q = fn, ["1"] = fn, Enter = fn, Escape = false }: a key a player binds or Escape, each given the props, false doing nothing; Mouse1 and Mouse2 only with pointer = false, as they click.
onOpen((props: MenuProps) -> ())?Runs as it opens, given the props.
onClose((props: MenuProps) -> ())?Runs as it closes, given the props.
render(props: MenuProps) -> Node?Needed.
Returns
Menu
Fails
  • a value of the wrong type
  • an option it does not have
local Confirm = dialog("confirm", { keys = { Enter = function(props) props.close(true) end } }, function(props)
return Box {
props.question,
Box { "Yes", onClick = function() props.close(true) end },
Box { "No", onClick = function() props.close(false) end },
}
end)
local Shop = menu("shop", nil, function()
return Box {
"Buy the MP40",
onClick = function()
if open(Confirm, { question = "Buy the MP40?" }) then request("buy") end
end,
}
end)
On a client open(menu, props?) → any

Opens a menu, in place of the one open, or a dialog over it, its render given a copy of props with close(value); a dialog's open gives its answer.

A dialog opens in a handler alone, on, onClick, a menu’s key or onOpen, as it waits until it closes: then it gives what props.close(value) passed, or nil if it closed otherwise.

NameTypeWhat it is
menuMenuNeeded.
props({[string]: any})?May be left out.
Returns
any
Fails
  • a value of the wrong type
local Shop = menu("shop", nil, function(props)
return Box { `Shop, opened by {props.by}`, onClick = function() props.close() end }
end)
on("said", function(e)
if e.text == "shop" then open(Shop, { by = "chat" }) end
end)
On a client close(menu)

Closes a menu, and a dialog over it, or a dialog, unanswered; one not open is left as it is.

NameTypeWhat it is
menuMenuNeeded.
Fails
  • a value of the wrong type
local Shop = menu("shop", nil, function() return Box { "Shop" } end)
on("killed", function(e)
if e.victim == me then close(Shop) end
end)
On a client is_open(menu) → boolean

Whether a menu or a dialog is open: a read a render draws again on.

NameTypeWhat it is
menuMenuNeeded.
Returns
boolean
Fails
  • a value of the wrong type
local Shop = menu("shop", nil, function() return Box { "Shop" } end)
mount(function()
return Box { "Round 1", style = { left = 40, top = 40, opacity = if is_open(Shop) then 0.3 else 1 } }
end)
On a client escape_menu(menu)

Names what a tap of Esc opens while nothing is open, in place of the engine's menu: a menu, or a function asked at each tap, whose nil opens the engine's.

A mod calls it once, at a script’s top; another script’s call fails, naming both. Holding Esc a second always opens the engine’s menu.

NameTypeWhat it is
menuMenu | () -> Menu?Needed.
Fails
  • a value of the wrong type
local Pause = menu("pause", nil, function(props)
return Box { "Paused", Box { "Resume", onClick = function() props.close() end } }
end)
escape_menu(Pause)