Skip to content

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 | nil

buttons 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.

lua
-- 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
end

The 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:

lua
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
end

A 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:

lua
local m = cmd.mask()
if m and (m.clear & input.bit("attack")) ~= 0 then
    -- something is holding attack off right now
end

cmd.on_change(fn) ​

Calls fn(c) once for each new game command, about 64 times a second. c has:

FieldWhat it is
cmdThe new command number
prevThe one before
skippedCommands that went by between two calls. They are reported, not replayed
held, pressed, releasedButton 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 ​

  1. The internal is not running.
  2. needs_internal = true is missing from script_info.
  3. 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:

FieldWhat it is
cmds_seenCommands that went out while a clear, hold or press was live
cmds_clearedCommands where a cleared button was really there and was taken out
presses_appliedPresses written into a command
presses_droppedPresses that were too late to send
last_press_cmdThe command the last press went out on
press_wordsThe 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:

lua
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
end

If you were already holding the button, the press keeps it held, so pressed is set and released is not.