Script Structure
Required Globals
Every script must define these globals:
lua
name = "MyHero" -- display name (string)
id = hero_id.abrams -- which hero this script runs for
function is_enabled()
return true -- return true when the script should be active
end
function on_tick()
-- your logic here
endSettings Table
Define a settings table to expose configurable options in the UI:
lua
settings = {
{ key = "enabled", type = "bool", default = false, label = "Enabled" },
{ key = "fov", type = "float", default = 5.0, label = "Max FOV", min = 1.0, max = 15.0 },
{ key = "delay", type = "int", default = 100, label = "Delay ms", min = 0, max = 1000 },
{ key = "hotkey", type = "keybind", default = VK.XBUTTON2, label = "Hotkey" },
{ key = "mode", type = "combo", default = 0, label = "Mode", options = { "Hold Key", "Always On" } },
{ key = "slot", type = "item_slot", default = 0, label = "Item Slot" },
-- Layout helpers
{ key = "sep1", type = "separator" },
{ key = "info", type = "label", label = "Hold shift to activate", color = { 1, 0.85, 0.3, 1 } },
{ key = "sl1", type = "sameline" },
}TIP
settings defines the UI layout at load time. Use config (below) to read/write values at runtime. They are separate — settings is the definition, config is the API.
Entry Fields
| Field | Type | Description |
|---|---|---|
key | string | Config key (required) |
type | string | "bool", "int", "float", "keybind", "combo", "item_slot", "separator", "label", or "sameline" (defaults to "bool") |
default | any | Default value |
label | string | Display name in UI (defaults to key) |
min, max | number | Range for int/float sliders |
options | table | String list for "combo" type |
color | table | Text color for "label" type as { r, g, b, a } (0-1 floats, defaults to white) |
depends_on | string | string[] | Key of another config entry, or a list of keys for multi-parent. The entry is visible only when every named dependency matches its depends_value and is itself visible (transitive). |
depends_value | int | int[] | Value(s) the parent(s) must equal, parallel to depends_on. For booleans, 1 = true, 0 = false. Defaults to 1 for each parent. A scalar broadcasts to all parents. |
Entries with depends_on are visually indented under their parent automatically — one indent level per dependency-chain depth. No extra field is needed.
Config API
Read and write config values at runtime:
lua
config.get_bool("enabled") -- returns bool
config.get_int("delay") -- returns int
config.get_float("fov") -- returns float
config.set_bool("enabled", false) -- write back
config.set_int("delay", 200)
config.set_float("fov", 3.0)Config is persisted per-script as JSON in the scripts directory.
Layout Types
Three types exist purely for UI layout and don't store any config values:
| Type | Description |
|---|---|
"separator" | Horizontal line with spacing above and below |
"label" | Static text. Use label for the text and color for an RGBA color table |
"sameline" | Places the next widget on the same line as the previous one |
lua
settings = {
{ key = "enabled", type = "bool", label = "Enabled" },
{ key = "s1", type = "separator" },
{ key = "warn", type = "label", label = "Experimental feature!", color = { 1, 0.4, 0.4, 1 } },
{ key = "sl1", type = "sameline" },
{ key = "debug", type = "bool", label = "Debug" },
}TIP
Layout types still require a unique key but the key is not stored in config.
Console Color Codes
The script console supports Minecraft-style color codes using § followed by a hex digit (0-f) or r to reset. Multiple colors can be used in a single print() call.
lua
print("§aHealth OK §r| §cDamage: §e42")
print("§6Gold: §f1500 §r| §9Mana: §b350")| Code | Color | Code | Color |
|---|---|---|---|
§0 | Black | §8 | Dark Gray |
§1 | Dark Blue | §9 | Blue |
§2 | Dark Green | §a | Green |
§3 | Dark Aqua | §b | Aqua |
§4 | Dark Red | §c | Red |
§5 | Dark Purple | §d | Light Purple |
§6 | Gold | §e | Yellow |
§7 | Gray | §f | White |
§r | Reset |
Lines without color codes use the default auto-detection (red for errors, yellow for warnings, gray for engine messages).
Keybind Names
keybinds.get(name) returns the user's live in-game virtual-key for an action, looked up by its raw Deadlock action name. The named helpers (keybinds.reload_key(), keybinds.ability1_key(), …) are shortcuts for the most common ones.
lua
local parry = keybinds.get("HeldItem")
local dash = keybinds.get("Roll")
local ab1 = keybinds.get("Ability1")
local melee = keybinds.get("AbilityMelee")Pre-seeded defaults
These are loaded at startup before the game's keybind file is read, so they always resolve even if Steam userdata is unavailable:
| Name | In-game action | Default key |
|---|---|---|
Reload | Reload | R |
HeldItem | Parry / Heavy Melee | F |
Roll | Dash | Shift |
Mantle | Jump | Space |
Ability1 | Ability slot 1 | 1 |
Ability2 | Ability slot 2 | 2 |
Ability3 | Ability slot 3 | 3 |
Ability4 | Ability slot 4 | 4 |
Item1 | Item slot 1 | Z |
Item2 | Item slot 2 | X |
Item3 | Item slot 3 | C |
Item4 | Item slot 4 | V |
Other known action names
These are read from citadelkeys_personal.lst and are available once keybinds load from Steam. Names come straight from the game's keybind file.
| Name | In-game action |
|---|---|
Attack | Primary fire |
Attack2 | Secondary fire / Zoom |
AbilityMelee | Quick melee |
Crouch | Crouch |
Walk | Sprint / Walk toggle |
MoveForward | Move forward |
MoveBack | Move backward |
MoveLeft | Strafe left |
MoveRight | Strafe right |
Ping | Ping |
PingWheel | Ping wheel |
VoiceChat | Push to talk |
TextChat | All chat |
TeamChat | Team chat |
Scoreboard | Scoreboard |
ShowMap | Full map |
Shop | Open shop |
Interact | Use / Interact |
InspectHero | Inspect hero |
Recall | Recall to base |
TIP
This is not an exhaustive list. Any action present in your citadelkeys_personal.lst works — the file lives at Steam/userdata/<id>/1422450/remote/cfg/citadelkeys_personal.lst. Keybinds are refreshed from the game every 30 seconds while the cheat is running. keybinds.get returns 0 for an unbound or unknown name.
