Skip to content

Globals ​

Top-level functions and small namespaces (storage) callable from any script. These don't need a prefix beyond the namespace name.

Player Access ​

FunctionReturnsDescription
local_player()playerThe local player object
get_players()tableAll enemy players. Teammates are always available via get_teammates()
get_all_players()tableAll valid players except the local player
get_teammates()tableTeammate players only
lua
local me = local_player()
for _, p in ipairs(get_players()) do
    if p:is_enemy() and p:is_alive() then
        -- ...
    end
end

World Entities ​

FunctionReturnsDescription
get_world_entities([type])WorldEntity[]All tracked world entities. Optional type string filters by coarse type name (e.g. "sinner", "tower") or exact engine class name (e.g. "citadel_breakableprop")

Each WorldEntity has: type, class_name, x, y, z, health, max_health, team.

lua
-- Print all sinners (neutral soul-denying enemies)
for _, e in ipairs(get_world_entities("sinner")) do
    print(string.format("sinner at %.0f,%.0f hp=%d/%d", e.x, e.y, e.health, e.max_health))
end

-- Check for breakable props regardless of sub-type
for _, e in ipairs(get_world_entities("citadel_breakableprop")) do
    print(e.class_name, e.subclass)
end

Time ​

FunctionReturnsDescription
clock()numberHigh-resolution time in seconds. Use for deltatime and debouncing
game_time()numberMatch clock time in seconds (pause-aware HUD timer)
get_match_time()numberAlias for game_time()
sim_time()numberRaw server SimTime; the clock for ability phase timestamps

clock() is wall-clock monotonic seconds since the engine started. game_time() (and its alias get_match_time()) advances with the match clock and freezes when the game is paused.

sim_time() is distinct from both: it is the absolute server timestamp the game uses internally for ability phase fields like cast_delay_start, cooldown_end, and modifier expires_at. Always compare those fields against sim_time(), not game_time() or clock().

lua
-- Check how long a cast delay has been running
local ab = local_player():get_ability(slot.ability1)
if ab and ab.is_in_cast_delay then
    local elapsed = sim_time() - ab.cast_delay_start
    print("Cast delay running for " .. elapsed .. "s")
end

Output ​

FunctionReturnsDescription
print(...)-Output to app console and Windows console. Auto-prefixed with [Lua:script_name]
toast(text, [duration], [style])-Centered HUD toast. Optional per-call styling. See below
notify(text, [duration], [color])-Persistent notification. Default duration 3.0, color white
play_sound(filename)-Play a WAV file from assets\sounds\. Pass the filename only, no path separators
lua
toast("ready")
notify("warning", 5.0)
play_sound("alert.wav")   -- plays assets\sounds\alert.wav

toast(text, [duration], [style]) ​

A centered HUD toast notification.

  • duration, seconds to display. Pass 0 to use the global default from menu settings.
  • style, optional table with per-call overrides. Any key omitted falls back to the global defaults configured in the menu:
KeyTypeNotes
bg{r, g, b, a}Background fill
text{r, g, b, a}Text color
outline{r, g, b, a}Outline / drop-shadow color
scalenumberSize multiplier (1.0 = default)

Toasts deduplicate by text only. If the same string is currently showing or already queued, the call is dropped on the floor, even if you passed a different style table. This means it's safe to fire toast("X") inside on_tick without flooding the screen; a tick-rate spam of the same message renders the original once.

lua
toast("Hit", 2, {bg = draw.color(255,0,0)})  -- shows
toast("Hit", 2, {bg = draw.color(0,255,0)})  -- DEDUPED (same text)
toast("Hit!", 2)                               -- shows (different text)

Different toasts with different text aren't deduplicated against each other, only repeats of the same string are suppressed, so a stream of "Hit X", "Hit Y", "Hit Z" all appear. The queue holds at most 5 pending toasts at a time.

lua
toast("Target locked", 2, {
    bg = {r = 40, g = 15, b = 50, a = 220},
    text = {r = 200, g = 140, b = 255},
    scale = 1.2
})

Demo script - each button triggers a different style preset:

lua
-- Toast Style Demo
-- Click buttons to see different toast styles
name        = "Toast Style Demo"
description = "Showcases custom toast styling"

ui.new_tab("toast_demo", "Toast Demo")

ui.button("toast_demo", "styles", "Default Toast", function()
    toast("Default style, uses your global settings", 3)
end)

ui.button("toast_demo", "styles", "Success (Green)", function()
    toast("Parry successful!", 3, {
        bg   = {r=20, g=60, b=20, a=220},
        text = {r=100, g=255, b=100},
        outline = {r=80, g=200, b=80, a=120},
    })
end)

ui.button("toast_demo", "styles", "Danger (Red)", function()
    toast("LOW HP, retreat!", 4, {
        bg   = {r=80, g=10, b=10, a=230},
        text = {r=255, g=80, b=80},
        outline = {r=255, g=60, b=60, a=150},
        scale = 1.3,
    })
end)

ui.button("toast_demo", "styles", "Info (Blue)", function()
    toast("Cooldown ready", 2, {
        bg   = {r=15, g=25, b=60, a=220},
        text = {r=120, g=180, b=255},
        outline = {r=80, g=140, b=220, a=100},
    })
end)

ui.button("toast_demo", "styles", "Big Gold", function()
    toast("ULTRA KILL!", 5, {
        bg   = {r=40, g=30, b=5, a=240},
        text = {r=255, g=215, b=0},
        outline = {r=255, g=180, b=0, a=160},
        scale = 1.8,
    })
end)

Input shortcuts ​

FunctionReturnsDescription
slot_to_key(slot)integerVK code bound to the given ability/item slot. See Game Keybinds
item_slot_to_key(config_slot)integerVK code for a 0-based item config slot (0-3). Equivalent to slot_to_key(config_slot + 4)
left_click()-Simulate a left mouse click
right_click()-Simulate a right mouse click

For finer-grained input control (key down, key up, mouse movement), see the Input namespace.

Game state ​

is_position_visible(pos) ​

Performs a BVH raycast from the camera to a world-space position. Returns true if the path is unobstructed (the point is visible from the camera).

lua
local pos = some_player:get_position()
if is_position_visible(pos) then
    -- position has line-of-sight from camera
end

This is a point-in-world check, not a player-visibility check. For per-player visibility use player:is_visible() instead.

is_in_menu() ​

Returns true when the game cursor is visible, meaning the player is in a menu, shop, scoreboard, or settings screen.

lua
if is_in_menu() then return end

All input actions (key presses, mouse movement) from Lua scripts are automatically blocked while in menu. You don't need to check is_in_menu() for safety, it's handled internally. Use this to skip expensive logic like targeting when the player isn't actively playing.

is_game_focused() ​

Returns true when the game window is in the foreground (active and focused).

lua
if not is_game_focused() then return end

Use this to skip logic when the player has alt-tabbed or is in another window. Unlike is_in_menu(), this detects when the game itself isn't the active window.

Spectators ​

The game namespace exposes who is currently spectating the match.

FunctionReturnsDescription
game.get_spectators()tableArray of spectator name strings currently watching the match
game.get_spectator_count()integerNumber of spectators, without building the name table
lua
if game.get_spectator_count() > 0 then
    local specs = game.get_spectators()
    print(#specs .. " spectators: " .. table.concat(specs, ", "))
end

Tsuki Config ​

Read/write the cheat's own settings (ESP toggles, aimbot FOV, etc.).

FunctionReturnsDescription
tsuki.get_bool(key, default)booleanRead a boolean setting
tsuki.get_int(key, default)integerRead an integer setting
tsuki.get_float(key, default)numberRead a float setting
tsuki.set_bool(key, value)-Write a boolean setting
tsuki.set_int(key, value)-Write an integer setting
tsuki.set_float(key, value)-Write a float setting
tsuki.get_color(key, default)ColorRead a color {r,g,b,a} (0-255)
tsuki.set_color(key, value)-Write a color {r,g,b,a} (0-255)
lua
-- React to the user's configured aimbot FOV
local fov = tsuki.get_float("aimbot_fov", 3.0)
local target = targeting.find_closest_by_fov(fov, 30.0)

-- Temporarily override a setting and restore it
local prev = tsuki.get_bool("show_teammate_esp", false)
tsuki.set_bool("show_teammate_esp", false)
-- ... do something ...
tsuki.set_bool("show_teammate_esp", prev)

Colors are stored as [r,g,b,a] arrays (each 0-255); get_color/set_color use a matching {r,g,b,a} table:

lua
-- Tint the enemy box fill red while a condition holds, restore otherwise
local KEY  = "enemy_box_fill_vis_color"
local base = tsuki.get_color(KEY, {r=255, g=255, b=255, a=40})  -- cache the real color ONCE

if condition then
    tsuki.set_color(KEY, {r=255, g=0, b=0, a=90})
else
    tsuki.set_color(KEY, base)                                  -- restore
end

set_color writes the LIVE setting

set_color changes the user's actual saved value and it persists to their config. For a temporary or per-modifier tint, cache the original with get_color and restore it when the condition clears - otherwise the tint can be saved permanently if the game closes while it is active.

Setting keys match the IDs the cheat uses internally. For new script-defined settings, prefer the UI namespace - it creates a labeled widget and persists its value automatically.

Cross-Script Modules ​

Scripts can share code by using export and import. A library script calls export at the top level to register a table of functions under a name. Consumer scripts call import from on_tick to fetch it.

FunctionReturnsDescription
export(name, module_table)-Register a table under name so other scripts can import it. Call at top level
import(name)table | nilFetch a module exported by another loaded script. Returns nil if the library is not loaded

WARNING

require, dofile, and loadfile are blocked. export/import is the only supported mechanism for sharing code between scripts.

lua
-- mylib.lua - the library script
name = "mylib"
description = "Shared utilities"

export("mylib", {
    clamp = function(v, lo, hi) return math.max(lo, math.min(hi, v)) end,
    sign  = function(v) return v >= 0 and 1 or -1 end,
})
lua
-- consumer.lua
name = "consumer"
description = "Uses mylib"

local lib = nil

function on_tick()
    if not lib then lib = import("mylib") end
    if not lib then return end  -- library not loaded yet

    local clamped = lib.clamp(some_value, 0, 100)
end

Storage ​

Persistent key-value storage scoped per script. Values survive script reloads, game restarts, and PC restarts. Each script gets its own isolated storage at scripts\storage\<script_name>.json; keys from script A are invisible to script B.

FunctionReturnsDescription
storage.set(key, value)-Save a value under a key. Passing nil as the value deletes the key.
storage.get(key)any | nilLoad a saved value, or nil if not set
storage.keys()tableList of saved keys for this script

Values can be strings, numbers (integer or float), booleans, or nil. Tables are not supported - store fields individually or encode manually as a string if you need structured data. Writes are cached in memory and flushed to disk every ~5 seconds (periodic tick) and on script unload/shutdown. There is no immediate flush on each storage.set() call.

lua
-- Track cumulative kills across game sessions
function on_kill(player)
    if not player:is_enemy() then return end
    local total = (storage.get("total_kills") or 0) + 1
    storage.set("total_kills", total)
    print("Total kills: " .. total)
end

-- Store structured data as individual keys (no json global exists)
storage.set("loadout_slot1", "burst_fire")
storage.set("loadout_slot2", "trooper_bounty")
local slot1 = storage.get("loadout_slot1")

-- Delete a key
storage.set("old_data", nil)

Helpers ​

Coroutine-friendly helpers available in every script covering common patterns: sleeping, debouncing, key management, and aim control. All timing helpers (sleep, wait_*) yield the coroutine and are only usable inside coroutine callbacks (e.g. on_tick).

Timing ​

FunctionReturnsDescription
sleep(ms)-Yield for approximately ms milliseconds
debounce(key, cooldown_ms)booleanReturn true at most once per cooldown_ms window for a given key
lua
function on_tick()
    if not debounce("my_feature", 500) then return end
    -- runs at most twice per second
end

Key and Ability Shortcuts ​

FunctionReturnsDescription
press_ability(slot)-Press (down + up) the key bound to the given ability slot
hold_key(key, duration?)-Hold a VK key for duration ms then release. Default 500 ms
hold_ability(slot, duration?)-Hold the key bound to an ability slot. Default 500 ms
lua
press_ability(slot.ability1)     -- tap ability 1
hold_key(VK.SPACE, 200)          -- hold Space for 200 ms
hold_ability(slot.ability3, 300) -- hold ability 3 for 300 ms

Aim Helpers ​

FunctionReturnsDescription
snap_to_target(target, opts?)booleanFlick aim to target using input.snap_to. Returns false if target is invalid or dead
aim_at_target(target, opts?)booleanSmooth aim at target until within threshold FOV or timeout. Returns true on success
lock_aim(target, opts?)-Start continuously aiming at target every tick (processed after on_tick)
unlock_aim()-Cancel any active aim lock
fire_and_hold(target, slot, opts?)-Press ability then continuously aim at target for hold_time ms

opts table for aim helpers:

KeyTypeDefaultNotes
bonestring | integerspine_1 (index 4) for snap_to_target/aim_at_target; bone.chest for fire_and_holdBone to aim at
projectile_velocitynumber0Projectile speed for lead compensation
hold_timenumber200fire_and_hold only - ms to keep aiming after pressing
speednumber0.5aim_at_target only - smoothing speed
thresholdnumber0.5aim_at_target only - success FOV in degrees
timeoutnumber2000aim_at_target only - max ms before returning false
lua
-- Flick and fire
if snap_to_target(target, { bone = bone.head }) then
    press_ability(slot.ability1)
end

-- Smooth aim with timeout
if aim_at_target(target, { speed = 0.3, threshold = 1.5, timeout = 500 }) then
    left_click()
end

-- Fire then hold aim on the target
fire_and_hold(target, slot.ability2, { hold_time = 300, bone = bone.chest })

-- Continuous tracking per tick
lock_aim(target, { bone = bone.chest })
-- later, when done:
unlock_aim()

Wait Helpers ​

All wait_* helpers yield the coroutine until a condition is met, then return true. They return false if the timeout elapses first (default 3000 ms).

FunctionReturnsDescription
wait_for_cast_delay(slot, timeout?)booleanYield until the ability's cast delay finishes
wait_for_cooling_down(slot, timeout?)booleanYield until the ability has STARTED cooling down (is_cooling_down becomes true). Returns true at that point, not when the cooldown finishes
wait_until_in_range(target, distance, timeout?)booleanYield until target is within distance metres
lua
function on_tick()
    press_ability(slot.ability1)
    if not wait_for_cast_delay(slot.ability1, 1000) then return end  -- wait up to 1s
    -- cast delay finished, ability is active
    if not wait_for_cooling_down(slot.ability1, 5000) then return end -- wait for CD
    -- ready again
end

Targeting Helper ​

FunctionReturnsDescription
find_closest_by_predicate(predicate, max_dist)player | nilFind the closest enemy within max_dist metres that satisfies predicate(player) == true
lua
-- Find the closest enemy that has a specific item
local target = find_closest_by_predicate(function(p)
    return p:has_item("phantom_strike") and p:is_alive()
end, 30.0)

Not affiliated with Valve Corporation.