Elysium scripting Editor API index
Build

Editing the command

Every tick the game builds a command - buttons, view angles, movement. A script can read it and change it before it is sent.

CS2 is driven by commands. Sixty-four times a second the client builds one: which buttons are held, where the player is looking, how they want to move. That command is what the server acts on. A script that wants to press a button for you, turn the view without moving your screen, or change where you walk does it by editing the command.

Two events hand it over:

local hop = ui.group( "bunny hop" ):toggle( "enabled", false )

on( "move", function( cmd )
	if not hop:get( ) or not cmd:down( btn.jump ) then
		return
	end

	local me = ents.local_pawn( )

	if me and not me:on_ground( ) then
		cmd:release( btn.jump )       -- in the air: let go, so touching the ground is followed by a fresh press
	end
end )

The command object is only valid inside the handler that received it; using one you kept raises this command is only valid inside the move handler that received it. Both events run only while the local player is alive.

#Buttons

Buttons are a bit set: one number with a bit per button. The btn table names the bits, and the calls below take and return such numbers, so several buttons go together with + or bits.bor: btn.attack + btn.duck.

#cmd:buttons() → integer

The buttons held in this command.

#cmd:set_buttons( mask )

Replaces the whole set. The game is told which buttons changed.

#cmd:press( mask )

Holds the buttons in mask down in this command, as if the key was pressed.

#cmd:release( mask )

Lets the buttons in mask go in this command.

#cmd:down( mask ) → boolean

true when every button of mask is held. false for a mask of 0.

#cmd:any( mask ) → boolean

true when at least one button of mask is held.

if cmd:any( btn.move_left + btn.move_right ) then
	-- strafing
end

#The btn table

NameButtonNameButton
btn.attackprimary firebtn.attack2secondary fire
btn.jumpjumpbtn.duckcrouch
btn.forwardmove forwardbtn.backmove back
btn.move_leftstrafe leftbtn.move_rightstrafe right
btn.turn_leftturn leftbtn.turn_rightturn right
btn.useusebtn.reloadreload
btn.walkwalk (quiet steps)btn.scoreboardscoreboard
btn.zoomzoombtn.inspectinspect weapon

#View angles

#cmd:angles() → vec3

The view angles the command carries: x is the pitch (positive looks down), y the yaw, z the roll, in degrees. If the command carries none yet, the player's current view angles.

#cmd:set_angles( angles [, silent] )

Writes the angles the command is sent with. silent is true by default.

  • Silent (the default): the command - and so the server - sees the new angles, but the player's own view does not move. What you see on screen stays put.
  • With silent = false the player's view turns to the new angles as well.

Raises an error if a component is not a finite number.

-- look at a point, silently
local function look_at( cmd, point )
	local me     = ents.local_pawn( )
	local before = cmd:angles( )
	local after  = vec3.angle_to( me:eye( ), point ):wrapped( )

	cmd:set_angles( after )
	cmd:rotate_move( before.y, after.y )       -- keep walking where the player meant to
end

#Movement

The command's movement is two numbers - forward and left, each from -1 to 1 - plus an up value that only matters on ladders and in water.

#cmd:move() → forward, left, up

#cmd:set_move( forward, left [, up] )

Sets the movement. Values are clamped to -1..1. CS2 normally moves a player from the sub-tick steps attached to a command, which tell the exact moment each key changed; with steps present it ignores the plain numbers. set_move therefore drops the steps so that your values apply as given.

#cmd:rotate_move( from_yaw, to_yaw )

The movement in the command was meant for a view looking along from_yaw. This rewrites it so it produces the same direction in the world for a view looking along to_yaw. It is what to call after changing the angles of a command: without it, turning the view sideways would turn the walking direction with it.

#cmd:mouse() → dx, dy

The mouse movement the command carries.

#The rest

#cmd:number() → integer

The command's sequence number.

#cmd:tick() → integer

The client tick the command was built for.

#cmd:seed() → integer

The command's random seed.

#cmd:impulse() → integer

#cmd:set_impulse( n )

The command's impulse: 0 for none, 100 flashlight, 201 spray paint.

#cmd:select_weapon( weapon ) → boolean

Switches to a weapon the player owns. weapon is a weapon entity - from ent:weapons(). Answers true when the switch was put into the command and false when the weapon's slot cannot be worked out. Raises an error when weapon is not an entity.

-- hold use + duck to pull out the knife
on( "move", function( cmd )
	if not cmd:down( btn.use + btn.duck ) then
		return
	end

	for _, weapon in ipairs( ents.local_pawn( ):weapons( ) ) do
		if weapon:is_knife( ) then
			cmd:select_weapon( weapon )
		end
	end
end )

#Things to keep in mind

Elysium scripting guide · built 2026-10-03