Example Scripts
Minimal Script
A simple script that uses ability 2 on the closest target:
lua
name = "Example"
id = hero_id.abrams
function is_enabled()
return config.get_bool("enabled") and input.is_key_held(VK.XBUTTON2)
end
function on_tick()
local target = targeting.find_closest_by_fov(5.0, 50.0)
if not target or not target:is_targetable() then return end
local lp = local_player()
if not lp then return end
if lp:is_ability_ready(slot.ability2) then
if snap_to_target(target, { bone = bone.spine_1 }) then
press_ability(slot.ability2)
end
end
end
settings = {
{ key = "enabled", type = "bool", default = false, label = "Enabled" },
}Combo Script
Combos use helpers like snap_to_target, sleep, wait_until_in_range, and press_ability together. on_tick() runs as a coroutine — when it returns, it will be restarted on the next tick.
lua
name = "Bebop"
id = hero_id.bebop
function is_enabled()
return config.get_bool("enabled")
and input.is_key_held(config.get_int("activation_key"))
end
function on_tick()
local target = targeting.find_closest_by_fov(config.get_float("max_fov"), 70.0)
if not target or not target:is_targetable() then return end
local lp = local_player()
if not lp then return end
-- hook (ability 3)
local hook = lp:get_ability(slot.ability3)
if not hook or not hook.learned then return end
if not lp:is_ability_ready(slot.ability3) then return end
snap_to_target(target, { bone = bone.spine_1, projectile_velocity = 3100 })
press_ability(slot.ability3)
if not wait_for_cooling_down(slot.ability3, 5000) then return end
if not wait_until_in_range(target, 4.0, 4000) then return end
-- bomb (ability 2)
local bomb = lp:get_ability(slot.ability2)
if config.get_bool("bomb") and bomb and bomb.learned and lp:is_ability_ready(slot.ability2) then
snap_to_target(target, { bone = bone.spine_1 })
sleep(100)
press_ability(slot.ability2)
sleep(100)
left_click()
-- echo shard
if config.get_bool("echoshard") and lp:has_item("upgrade_ability_power_shard") then
input.press_key(item_slot_to_key(config.get_int("echoshard_slot")))
sleep(100)
if lp:is_ability_ready(slot.ability2) then
snap_to_target(target, { bone = bone.spine_1 })
sleep(100)
press_ability(slot.ability2)
sleep(100)
left_click()
end
end
end
-- uppercut (ability 1)
local uppercut = lp:get_ability(slot.ability1)
if config.get_bool("uppercut") and uppercut and uppercut.learned and lp:is_ability_ready(slot.ability1) then
snap_to_target(target, { bone = bone.spine_1 })
sleep(100)
press_ability(slot.ability1)
end
end
settings = {
{ key = "enabled", type = "bool", default = false, label = "Enabled" },
{ key = "activation_key", type = "keybind", default = VK.XBUTTON2, label = "Activation Key" },
{ key = "max_fov", type = "float", default = 5.0, label = "Max FOV", min = 1.0, max = 15.0 },
{ key = "bomb", type = "bool", default = true, label = "Bomb" },
{ key = "uppercut", type = "bool", default = true, label = "Uppercut" },
{ key = "echoshard", type = "bool", default = false, label = "Echo Shard" },
{ key = "echoshard_slot", type = "item_slot", default = 0, label = "Echo Shard Slot", depends_on = "echoshard", depends_value = 1 },
}Key Patterns
Activation with Hold Key
lua
function is_enabled()
return config.get_bool("enabled")
and input.is_key_held(config.get_int("hotkey"))
endActivation Mode (Hold Key vs Always On)
lua
function is_enabled()
if not config.get_bool("enabled") then return false end
if config.get_bool("always_on") then return true end
local key = config.get_int("activation_key")
return key > 0 and input.is_key_held(key)
end
settings = {
{ key = "enabled", type = "bool", default = false, label = "Enabled" },
{ key = "always_on", type = "bool", default = false, label = "Always On" },
{ key = "activation_key", type = "keybind", default = VK.XBUTTON2, label = "Key", depends_on = "always_on", depends_value = 0 },
}Multi-Parent Dependencies
Pass a table to depends_on when a setting only makes sense if several parents are all satisfied. Visibility is transitive — turning off any ancestor hides every descendant — and children are auto-indented under their parent.
lua
settings = {
{ key = "dispel_magic", type = "bool", default = false, label = "Dispel Magic" },
{ key = "include_unstoppable", type = "bool", default = false, label = "Include unstoppable",
depends_on = "dispel_magic" },
{ key = "prioritise_unstoppable", type = "bool", default = false, label = "Prioritise Unstoppable",
depends_on = { "dispel_magic", "include_unstoppable" } },
{ key = "interaction_delay", type = "int", default = 250, label = "Interaction Delay (ms)",
min = 0, max = 2000, depends_on = "dispel_magic" },
}Prioritise Unstoppable shows only when both Dispel Magic and Include unstoppable are on. If Dispel Magic is turned off, Include unstoppable becomes hidden, and Prioritise Unstoppable is hidden along with it. depends_value accepts a parallel table (e.g. depends_value = { 1, 1 }) if you need to match a non-default value.
Low-Health Execute
Using find_closest_by_predicate and is_targetable:
lua
function on_tick()
local lp = local_player()
if not lp or not lp:is_ability_ready(slot.ability4) then return end
local target = find_closest_by_predicate(function(e)
return e:is_targetable() and e:get_health_percentage() < 20
end, 30.0)
if not target then return end
if snap_to_target(target, { bone = bone.spine_1 }) then
press_ability(slot.ability4)
end
endCooldown Gating with Debounce
Prevent spamming an action with debounce:
lua
function on_tick()
local target = targeting.find_closest_by_fov(5.0, 30.0)
if not target or not target:is_targetable() then return end
-- only fire every 2 seconds
if debounce("combo", 2000) then
press_ability(slot.ability1)
end
endCustom Mouse Movement
Raw vs smoothed mouse movement:
lua
function on_tick()
local target = targeting.find_closest_by_fov(5.0, 50.0)
if not target then return end
local delta = targeting.compute_aim_delta(target, bone.head)
if delta:empty() then return end
-- raw instant flick
input.move_mouse(delta)
-- smoothed movement (speed 0.5)
input.move_mouse(delta, 0.5)
-- smoothed with detach factor
input.move_mouse(delta, 0.5, 0.3)
endSmoothness Compensation
When aiming with smoothing, the crosshair lags behind a moving target. Pass your speed value as the 4th argument to compute_aim_delta — it applies smoothness compensation automatically, predicting where the target will be by the time the smooth cursor catches up.
lua
function on_tick()
local target = targeting.find_closest_by_fov(5.0, 50.0)
if not target or not target:is_targetable() then return end
local speed = config.get_float("smooth_speed")
-- speed param enables smoothness compensation inside compute_aim_delta
local delta = targeting.compute_aim_delta(target, bone.head, 0, speed)
if delta:empty() then return end
input.move_mouse(delta, speed)
endThe higher-level helpers (aim_at_target, lock_aim) handle this automatically.
Raw Mouse Movement Explained
input.move_mouse(delta) sends a raw mouse delta in pixel units — the game converts it to angle change using the mouse multiplier (0.044) and sensitivity. With no extra args it applies instantly in one frame. With a speed argument (0.01–1.0), it interpolates over multiple frames — lower values are smoother but slower to converge.
lua
function on_tick()
local target = targeting.find_closest_by_fov(5.0, 50.0)
if not target then return end
local delta = targeting.compute_aim_delta(target, bone.head)
if delta:empty() then return end
-- raw: full delta applied this frame
input.move_mouse(delta)
-- smoothed: only a fraction applied per frame, call every tick
-- input.move_mouse(delta, 0.3)
-- smoothed with detach: stops early when close enough
-- input.move_mouse(delta, 0.3, 0.5)
endAim at World Position
Use the vec3 overload of compute_aim_delta to aim at an arbitrary world point instead of a player bone:
lua
function on_tick()
-- aim at a fixed world coordinate
local pos = vec3(1200, -500, 300)
local delta = targeting.compute_aim_delta(pos)
if delta:empty() then return end
input.move_mouse(delta, 0.5)
endCamera and World-to-Screen
Access camera state and project world positions to screen coordinates:
lua
function on_tick()
local angles = camera.get_view_angles() -- vec2(pitch, yaw)
local forward = camera.get_forward() -- unit vec3
local fov = camera.get_fov()
local screen = camera.get_screen_size() -- vec2(width, height)
-- project a world position to screen
local target = targeting.find_closest_by_fov(10.0, 50.0)
if not target then return end
local head = target:get_bone_position(bone.head)
local screen_pos = camera.world_to_screen(head)
if screen_pos then
print("head on screen at: " .. tostring(screen_pos))
end
endAim Test Script
Diagnostic script that prints aim state each tick — useful for tuning sensitivity and smoothness:
lua
name = "Aim Test"
id = hero_id.any
function is_enabled()
return config.get_bool("enabled") and input.is_key_held(VK.XBUTTON2)
end
function on_tick()
local target = targeting.find_closest_by_fov(10.0, 50.0)
if not target or not target:is_targetable() then return end
local fov = targeting.get_fov(target, bone.head)
local delta = targeting.compute_aim_delta(target, bone.head)
local angles = camera.get_view_angles()
print(string.format("fov=%.2f delta=%s angles=%s", fov, tostring(delta), tostring(angles)))
if fov > 0.5 then
local speed = config.get_float("speed")
input.move_mouse(delta, speed)
end
end
settings = {
{ key = "enabled", type = "bool", default = false, label = "Enabled" },
{ key = "speed", type = "float", default = 0.5, label = "Smooth Speed", min = 0.01, max = 1.0 },
}