The kinds of values the API uses, and the habits that keep scripts from breaking.
Types at a glance
Type
Looks like
Notes
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.
Value
nil when
game.local_player()
You are dead, spectating, or not in a match.
entity.* extra fields
The game build does not expose that field. Check p.bones, p.velocity and so on.
bomb.state().pos
The 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()
ifnot me ornot me.bones thenreturnendlocal 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
Code
Key
0x01
Left
0x02
Right
0x04
Middle
0x05
Mouse 4
0x06
Mouse 5
Control
Code
Key
0x08
Backspace
0x09
Tab
0x0D
Enter
0x10
Shift
0x11
Ctrl
0x12
Alt
0x14
Caps Lock
0x1B
Esc
0x20
Space
Navigation
Code
Key
0x21
Page Up
0x22
Page Down
0x23
End
0x24
Home
0x25
Left
0x26
Up
0x27
Right
0x28
Down
0x2D
Insert
0x2E
Delete
Letters and digits
Code
Key
0x30 - 0x39
0 to 9
0x41 - 0x5A
A to Z (same as the capital letter's code: string.byte("W"))