Commands
Needs the internal running and needs_internal = true in script_info. Without it cmd.clear, cmd.hold, cmd.press, cmd.cast and cmd.use_item return false.
cmd.clear(buttons [, ms]) -> bool take these buttons out of every command
cmd.hold(buttons [, ms]) -> bool hold these buttons
cmd.release(buttons) -> integer end your clear or hold early
cmd.press(buttons) -> bool one press
cmd.cast(slot) -> bool cast ability 1-4
cmd.use_item(slot) -> bool use item 1-4
cmd.mask() -> table | nil
cmd.reset() drop everything this script asked for
cmd.on_change(fn) fn(c) once per new command
cmd.diag() -> table | nilbuttons is a button name like "attack", or a list of them like { "attack", "attack2" }. The names are the same ones input.* uses: attack, attack2, jump, duck, reload, dash, ability1-ability4, item1-item4, melee, parry, and the rest on the Input page. An unknown name raises an error, and so does "use", which sets no button in the command.
What it is for
input.* can press keys but cannot take one away. cmd.* changes the command the game sends after your real keys are in it, so a script can block attack while you hold the mouse button.
-- cleanse the moment a debuff lands, even while you are holding fire
local function should_cleanse(m)
return false -- your rule: check m.name against the debuffs you care about
end
function on_modifier_added(p, m)
if p:is_local() and should_cleanse(m) then
cmd.clear("attack", 150) -- no shooting for 150 ms
cmd.use_item(2) -- your cleanse item in slot 2
end
endThe modifier names to check come from your own logs. Debugging modifiers shows how to list them.
Every change is timed
A clear or a hold lasts ms milliseconds. Leave ms out and it lasts 100 ms. The longest is 5 seconds.
To keep one going, call it again. Calling it again makes it last longer, never shorter. For "while something is true", call it every tick while it is true:
function on_tick()
local me = local_player()
local ult = me and me:get_ability(slot.ability4)
if ult and ult.is_channeling then cmd.clear("attack") end -- asked again every tick, so it never runs out
endA clear can never get stuck. If your script stops asking, you get the button back when the time runs out, 100 ms by default. If it is turned off or errors, you get it back straight away.
cmd.release(buttons) ends your clear and hold of those buttons straight away. It returns how many of your clears and holds it changed, 0 when none matched. cmd.reset() ends everything your script asked for.
Pressing and casting
cmd.press(buttons) presses once. cmd.cast(slot) casts ability 1 to 4 and cmd.use_item(slot) uses item 1 to 4. slot is a number from 1 to 4, not a slot.* constant. slot.ability1 is 0, so cmd.cast(slot.ability1) raises an error, and slot.item1 is 4, so cmd.use_item(slot.item1) uses item 4. Any other number raises an error.
These go through the game command, not your keyboard, so they work with any keybinds and while a text box has focus.
Timing
A change reaches the game a few milliseconds after you ask. It takes a little longer if the overlay's Refresh Rate is set low. It is not tied to one exact command. Use cmd.* for "stop shooting while I cast", not for "change exactly command 1234".
If two scripts disagree
A clear beats a hold and a press. If one script clears attack and another holds it, attack is cleared.
cmd.mask() shows what is in force: { clear, hold, intents, mine = { clear, hold } }. clear and hold are button bit masks for every script together. mine has the same masks for your script only. intents is how many clears and holds are live. Use input.bit(name) to test a bit:
local m = cmd.mask()
if m and (m.clear & input.bit("attack")) ~= 0 then
-- something is holding attack off right now
endcmd.on_change(fn)
Calls fn(c) once for each new game command, about 64 times a second. c has:
| Field | What it is |
|---|---|
cmd | The new command number |
prev | The one before |
skipped | Commands that went by between two calls. They are reported, not replayed |
held, pressed, released | Button bit masks, the same as input.buttons() |
A script has one on_change function. Calling cmd.on_change again replaces it, and cmd.on_change(nil) stops it. Without needs_internal = true the call does nothing.
Returns false when
- The internal is not running.
needs_internal = trueis missing fromscript_info.- 64 clears and holds are already live across every script.
A press is also dropped if it cannot reach the game within half a second, for example during a loading screen. It is never delivered late.
When a script is turned off
Everything a script asked for is removed when it is turned off or errors: its clears, holds, on_change, and anything else it owns. See on_disable.
Checking it worked
cmd.diag() shows what was applied, not what was asked for. The main fields:
| Field | What it is |
|---|---|
cmds_seen | Commands that went out while a clear, hold or press was live |
cmds_cleared | Commands where a cleared button was really there and was taken out |
presses_applied | Presses written into a command |
presses_dropped | Presses that were too late to send |
last_press_cmd | The command the last press went out on |
press_words | The last press as it went out: { held, pressed, released }, as button bit masks |
Clearing a button nobody is pressing leaves cmds_cleared at 0.
To check that a press went out as a full tap:
local d, b = cmd.diag(), input.bit("ability1")
if d and (d.press_words[2] & b) ~= 0 and (d.press_words[3] & b) ~= 0 then
-- pressed and released on the same command
endIf you were already holding the button, the press keeps it held, so pressed is set and released is not.