Lua · Useful information

Common knowledge

The kinds of values the API uses, and the habits that keep scripts from breaking.

Types at a glance

TypeLooks likeNotes
color`color(255, 80, 80, 255)`One integer. Channels 0 to 255. See below.
vector`{ x = 120.5, y = -40, z = 64 }`World position or direction in game units. Make one with `vec.new(x, y, z)`.
player`{ slot = 3, name = "…", health = 100, … }`A plain table, a copy for this frame. See [game](/docs/lua/game#player-table).
steamid`"76561198000000000"`Text, not a number: 64-bit ids do not fit a Lua float exactly.
vk`0x75`A Windows key code. Table below.
handle`1`Images and fonts are small integers you got from a load call.

Colours

A colour is packed as a << 24 | b << 16 | g << 8 | r. You never need to do that by hand: use color(), color.alpha, color.lerp, color.hsv and color.unpack. Program settings (through config) store colours differently: as a table {r, g, b, a} of numbers from 0 to 1.

colors.lua
local c = color(255, 128, 0)
local r, g, b, a = color.unpack(c)
local as_setting = { r / 255, g / 255, b / 255, a / 255 }

Units and angles

  • World positions are game units. Players are about 72 units tall standing; 1 metre is about 39.37 units.
  • z is up. pos of a player is their feet.
  • Angles are degrees. Yaw goes from -180 to 180; pitch from -89 (looking up) to 89 (looking down).
  • Speeds are units per second. Running with a knife is 250.
  • Screen positions are pixels from the top-left corner. Use draw.screen(), never a fixed resolution.
  • Time is seconds as a decimal number.

nil is normal

Many values can be missing. Check before you use them, or your script stops with attempt to index a nil value.

Valuenil when
game.local_player()You are dead, spectating, or not in a match.
entity.* extra fieldsThe game build does not expose that field. Check p.bones, p.velocity and so on.
bomb.state().posThe bomb position is not known.
draw.load_image(…)The file is missing or not a PNG/JPG.
ui.get(id)No control has that id (often a typo).
config.get(path)The setting does not exist.
players.intel(id)The stats are still loading. Ask again later.
safe.lua
local me = entity.local_player()
if not me or not me.bones then return end
local head = me.bones.head

Variables and scope

  • Use local for everything. Globals are slower and easy to mistype.
  • Locals at the top of the file keep their value between frames, for as long as the script runs.
  • A reload (Save, file change, turning it off and on) starts the file over: every variable is reset. To keep something, use ui.* settings, db or files.
  • Callbacks (on_frame, on_kill…) must be globals, so the program can find them. Write them as function on_frame(), not local function on_frame().
  • Each script has its own world: two scripts cannot read each other's variables.

Key codes

Use these with input.key_down, input.key_pressed and as ui.keybind defaults.

Mouse

CodeKey
0x01Left
0x02Right
0x04Middle
0x05Mouse 4
0x06Mouse 5

Control

CodeKey
0x08Backspace
0x09Tab
0x0DEnter
0x10Shift
0x11Ctrl
0x12Alt
0x14Caps Lock
0x1BEsc
0x20Space

Navigation

CodeKey
0x21Page Up
0x22Page Down
0x23End
0x24Home
0x25Left
0x26Up
0x27Right
0x28Down
0x2DInsert
0x2EDelete

Letters and digits

CodeKey
0x30 - 0x390 to 9
0x41 - 0x5AA to Z (same as the capital letter's code: string.byte("W"))
0x60 - 0x69Numpad 0 to 9

Function

CodeKey
0x70F1
0x71F2
0x72F3
0x73F4
0x74F5
0x75F6
0x76F7
0x77F8
0x78F9
0x79F10
0x7AF11
0x7BF12

Sides

CodeKey
0xA0Left Shift
0xA1Right Shift
0xA2Left Ctrl
0xA3Right Ctrl
0xA4Left Alt
0xA5Right Alt