CreateMove
on_create_move(cmd) / on_create_move_post(cmd)
Section titled “on_create_move(cmd) / on_create_move_post(cmd)”- Thread: game thread, inside the game’s CreateMove. This can run several times per tick
with the same
cmd.sequence;cmd.new_tickis true on the first call of a tick. - Not called on official Valve servers, or when aqua had to disable command writes. Aiming and action requests require the same gate’s permission; priority cannot bypass it. Blocked calls discard pending aim without changing the camera or command.
cmdis a fresh table each call. Its methods only work during the callback that received it.
Order inside one CreateMove call: bhop -> air strafer -> on_create_move -> anti-aim
-> ragebot -> doubletap -> script actions/aim arbitration -> on_create_move_post -> checksum.
on_create_move submits movement, aim and action requests. Anti-aim rotates movement like your own
keys, and ragebot auto-stop can override it. on_create_move_post is read-only and sees the
final command. A script with aim priority above ragebot suspends ragebot and doubletap for
that call before they can generate attacks.
Command fields
Section titled “Command fields”| Field | Meaning |
|---|---|
sequence, new_tick |
Command number, and whether this is the tick’s first call |
alive, on_ground, velocity {x,y,z} |
Local player state |
view_yaw |
Your real camera yaw (not the anti-aim yaw) |
angles {pitch,yaw,roll} |
Base command angles, which may already contain anti-aim’s pose. In _post, the final base angles sent |
eye_position {x,y,z} |
Local geometric eye position for look_at; nil when unavailable |
ragebot_aim_priority, antiaim_aim_priority |
Built-in aim priorities: 100 and 50 |
weapon |
Copied active weapon details, or nil (see players and weapons) |
forward_move, left_move |
Movement wish, -1..1. left_move +1 = strafe left |
buttons |
Button bitmask |
aa_active |
Anti-aim wrote the pose this tick |
strafer_active |
The air strafer owns movement this tick (your request is ignored) |
subtick_moves, subtick_remaining, subtick_capacity |
Sub-tick moves in the command, and the 32-move budget left this tick (read-only) |
jump_priority |
Built-in Bunnyhop owns jump input because the user is holding jump; script jump requests are refused |
jump_pending |
A script jump request is queued and has not expired (snapshot before this callback) |
jump_staged |
The shared jump injector staged a press/release pair on this CreateMove call; not proof the engine accepted the jump |
_post only: aa_pose {pitch,yaw,roll} (nil when anti-aim is off), move_applied,
history_size, attack, aim_applied (a script aim was written), aim_owner
("script", "ragebot", "antiaim", "none" or "unavailable"), aim_priority
(selected script request’s priority, nil without a request), and aim_silent
(selected script request’s mode, even if it lost arbitration). These describe the shared
command, not just the script receiving the callback. actions_applied is a table with
boolean attack1, attack2, reload, walk and switch_weapon fields. Applied means
the request reached the command; it does not prove the game accepted the action.
Command methods
Section titled “Command methods”Methods work only in on_create_move; _post raises “read-only”.
| Method | Effect |
|---|---|
cmd:move_world(x, y) |
Walk toward world-space direction (x, y). Length is clamped to 1; shorter = slower wish. z is not used |
cmd:move(forward, left) |
Same, relative to your camera (not the anti-aim yaw). Clamped to length 1 |
cmd:stop() |
Request zero movement (overrides the player’s keys) |
cmd:clear_move() |
Drop this script’s request; the player’s keys apply again |
cmd:set_button(name, down) |
"duck", "walk" or "use". Not play-tested |
cmd:jump(down=true) |
Queue a jump intent; returns true if queued, false if dead or built-in jump priority applies. false cancels this script’s pending request |
cmd:aim(pitch, yaw, opts) |
Submit aim angles. Pitch clamps to -89..89, yaw wraps, roll is zero. Options: silent=false, priority=75. Returns whether the request was accepted, not whether it won final arbitration |
cmd:look_at(x, y, z, opts) |
Submit aim toward world coordinates from eye_position, with the same options. Returns false if dead, the eye is unavailable, or the target equals the eye |
cmd:clear_aim() |
Cancel this script’s pending aim request |
cmd:attack1(down=true, opts) |
Request primary attack press/hold or release |
cmd:attack2(down=true, opts) |
Request secondary attack press/hold or release |
cmd:reload(down=true, opts) |
Request reload input |
cmd:walk(down=true, opts) |
Request Shift/walking input |
cmd:switch_weapon(handle, opts) |
Request a held weapon by its full handle from aqua.get_weapon_inventory() |
cmd:clear_actions() |
Cancel this script’s pending action requests |
- A planar movement request lasts for the current tick only: call
move_worldevery tick you want to move. No call = no override. It is also dropped when you die, and when the script stops, errors or unloads. If two scripts ask in the same tick, the last one wins. - Movement methods do not change view angles. Movement is planar: pitch never changes the direction. Aqua’s anti-aim always sends roll 0; a non-zero roll from elsewhere would skew the server’s movement basis, and this API does not compensate for it.
- While the air strafer drives (
strafer_active), planar movement requests are ignored. Turn the strafer off for a walkbot that jumps. - Direction accuracy: servers usually run
sv_quantize_movement_input 1, which rounds the wish to 8 directions relative to the sent yaw.- Anti-aim on: aqua compensates through the sent yaw, so
move_worldis exact (measured in game: within 0.012 deg). With anti-aim’s movement dither on, the heading ripples about +/-2 deg around the target instead. A direction change shows up one tick late. - Anti-aim off: the sent yaw is your camera, so the direction snaps to the nearest of 8 around it (up to about 30 deg off; measured 29 deg for a request 61 deg off the camera). Steer the camera toward the target if you need exact paths without anti-aim.
- Anti-aim on: aqua compensates through the sent yaw, so
cmd:jump()requests a jump on the next CreateMove call, which may be a later call in this tick or the next tick. It works with Bunnyhop disabled. Refresh it each tick while you want to jump; it expires after more than one command advance. Last requesting script wins; cancellation affects only its owner’s request. Death, command-write blocking, stopping, errors and unload clear requests. Already staged edges cannot be cancelled.- Jump requests use the same timing and shared subtick budget as Bunnyhop, before the air
strafer claims slots. Built-in held-space Bunnyhop has priority (
jump_priority). The module reserves a press/release pair when a jump is plausible; raw budget writes are not exposed. Queued does not mean executed: grounding, movement type, water, engine timing, capacity and ordering can prevent staging. Keep requesting until airborne when attempting a single grounded jump.jump_stagedincludes built-in jumps as well as script jumps. - Raw sub-tick move emission is not exposed.
Action requests
Section titled “Action requests”- Each lasts one CreateMove call. Repeat a hold every callback;
falseexplicitly releases input. No request leaves normal input in charge. Requests cancel on stop/error/unload, death or blocked writes. Methods return whether queued, not final success. opts.priorityis an integer 0..200, default 75. Each action is arbitrated separately between scripts; highest wins, last equal request wins. Combat actions at 100 or below yield while ragebot is enabled. Above 100 they suspend ragebot and doubletap for this call. Walking uses script priority only and is applied before anti-aim movement correction.- Attack requests use the current camera direction in existing shot history when no
script aim takes over, preventing a button-only request from firing along anti-aim.
Pair attack with
aim/look_atto choose another direction. Keep the chosen policy across a firing sequence. These inputs do not add recoil/spread compensation. - Weapon handles are checked against the live held inventory before writing a switch. A dropped/recycled handle is rejected. Reload, scope, grenades and other secondary actions remain subject to native ammo, cooldown and weapon-state rules.
Aim priority and camera mode
Section titled “Aim priority and camera mode”opts.priority is an integer 0..200, default 75. Larger values have more
control. Aim has one winner across scripts; actions choose a winner separately for
attack1, attack2, reload, weapon switching and walking. Priorities apply to requests
from the current CreateMove call, including repeated calls with the same sequence.
| Script priority | Against an applied anti-aim pose (50) | Against ragebot-authored aim (100) | Combat actions while ragebot is enabled |
|---|---|---|---|
| 0..50 | Anti-aim wins | Ragebot wins | Script request yields |
| 51..100 | Script wins | Ragebot wins | Script request yields |
| 101..200 | Script wins | Script suspends ragebot and doubletap | Script takes combat control |
At equal priority, built-ins win against scripts. Between scripts, the last equal-priority request wins; script execution order breaks the tie, so distinct priorities are clearer when one script must dominate. Walking competes only between scripts and never suspends ragebot/doubletap by itself.
Aim yields to ragebot only when ragebot actually authors aim, including held-shot history. Combat actions at 100 or below yield whenever ragebot is enabled, even without a target. If neither built-in authors aim, a lower-priority script can aim. Priority above 100 suspends ragebot/doubletap for the call, even if no target exists. No priority bypasses the Valve-server or command-write gate.
An accepted request may later lose arbitration. Check aim_owner/aim_applied and
actions_applied in on_create_move_post; an applied request still does not prove
the native weapon accepted the action. Cancelling a winner does not resurrect
requests that already lost or were rejected. Choose one ownership policy through
the firing sequence rather than switching priorities around a shot.
- Aim requests last for this CreateMove call, including when the same command sequence
runs again. Call
aimorlook_atevery callback while you want control. No request means normal aiming. Stop, error, unload, death and blocked command writes discard requests. - A lower request is rejected while a higher one is pending. Clear your own request before lowering its priority within the same callback. Cancelling the winner does not restore previously rejected requests.
- Taking control above 100 suppresses ragebot’s firing, auto-stop, scope/cock actions and doubletap for the call. Player attack input is retained; use action requests to control script input. Ragebot aim ownership includes the command following a shot.
silent=truewrites the base command and existing history while leaving the camera alone.silent=falsealso turns the camera through the native input API. This API’s silent mode changes the network/body pose; it is not a history-only mode. If visible camera access is unavailable, or the camera-copy guard needed for silent mode is unavailable, aiming is refused and_post.aim_owneris"unavailable".- Both modes rotate base movement and directional buttons to keep the existing world-space
wish. Server movement quantization still applies; existing airborne subtick steering is
not retargeted.
look_atis geometric aiming, without recoil/spread compensation, visibility checks, lag compensation or firing-time eye prediction. - Angles/coordinates must be finite floats. Invalid options raise an error. These methods
work only during the owning script’s
on_create_move, never in_postoron_draw. Pitch clamps to -89..89, yaw wraps to -180..180 and roll is zero. For example,cmd:aim(9999, 9999)writes pitch 89, yaw -81, roll 0. NaN/infinity raise errors. Visible/silent camera modes, bounds and priorities were tested on a local server.
function on_create_move(cmd) if cmd.alive then -- Override anti-aim, let ragebot own its shots, turn the camera visibly. cmd:look_at(1200, -500, 64, {priority = 75, silent = false}) -- For full control with the camera unchanged, use priority = 101, silent = true. -- Use the same 101 priority on cmd:attack1(want_fire, {priority = 101}). endend
function on_create_move_post(cmd) if cmd.new_tick then print("aim owner:", cmd.aim_owner, "script applied:", cmd.aim_applied) endend-- Example only: replace this with your walkbot's decision to cross an obstacle.local want_jump = false
function on_create_move(cmd) if want_jump and cmd.alive and cmd.on_ground and not cmd.jump_priority then cmd:jump() else cmd:jump(false) endend-- Walk toward a world point, stopping inside 32 units.local target = { x = 1200, y = -500 }
function on_create_move(cmd) local me = aqua.get_local_player() if not (cmd.alive and me and me.origin) then return end local dx, dy = target.x - me.origin.x, target.y - me.origin.y if dx * dx + dy * dy < 32 * 32 then cmd:stop() else cmd:move_world(dx, dy) -- clamped to length 1 endend
function on_create_move_post(cmd) -- cmd.angles.yaw is the yaw actually sent; cmd.view_yaw is your camera. if cmd.new_tick and cmd.move_applied then print(("sent yaw %.1f, camera %.1f"):format(cmd.angles.yaw, cmd.view_yaw)) endend