Skip to content

Movement

How players move, and how the mod changes it: their speed, jump and gravity, a push, a jump to a point, holding them in place, and a limit on where they can look.

A player’s game predicts their own movement, so it feels instant. The server’s orders reach it marked with the moment they take effect, so the player sees each one a ping after the mod gave it, with no jump. An order that arrives too late for that is carried out at once and the player’s game corrected. Speeds are in metres a second and angles in radians; see units and axes.

A jump pad or a teleport that waits a ping feels late. So a client script gives the same orders on me in a handler of a trigger that fires on clients, and the player sees them at once; the server’s handler of the same trigger gives them too, and the two agreeing show nothing. Put the code both handlers run in a .shared.luau file both sides require.

p:control hands a player’s keys and view to a model, a shape, a camera or a part, as a vehicle’s driver, in place of their body.

What a player, p, or an entity, e, reads beside the mod’s state. A field of the other side’s fails.

NameTypeSideWhat it is
p.positionvector?On both sidesWhere they stand, at their feet.
p.yawnumber?On the serverWhich way they face, in radians: 0 faces +Z, more turns left.
p.pitchnumber?On the serverHow far up they look, in radians.
p.ground(Entity | Player)?On the serverWhat they stand on; nil in the air or on the map.
p.moveMove?On the serverTheir movement keys, each -1 to 1, as of their latest command.
On the server p:set_velocity(velocity)
On a client p:set_velocity(velocity)

Sets a player's velocity, in metres a second, as a jump pad throws them.

On the server

The velocity is up to 100 m/s long. A dead player is not pushed. On an NPC it fails.

NameTypeWhat it is
velocityvectorNeeded.
Fails
  • a value of the wrong type

On a client

Sets the player’s own velocity, in metres a second, in a handler of a trigger that fires on clients, so a jump pad throws them at once.

The player’s game carries it out from the next command on, and the server’s handler of the same trigger gives the same order, which the game then confirms: the two agreeing show nothing, and differing a correction, once. It is checked as the server’s is. Anywhere else, or on another player, it fails.

NameTypeWhat it is
velocityvectorNeeded.
Fails
  • a value of the wrong type
p:set_velocity(vector.create(0, 8, 0))

To throw the player up off a jump pad at once

Section titled “To throw the player up off a jump pad at once”
triggers.jump_pad:on("entered", function()
me:set_velocity(vector.create(0, 8, 0))
end)
On the server p:add_velocity(velocity)
On a client p:add_velocity(velocity)

Adds to a player's velocity, in metres a second, as a blast pushes them.

On the server

The push is up to 100 m/s long, and takes them no faster than 100 m/s or than they already went. A dead player is not pushed. On an NPC it fails.

NameTypeWhat it is
velocityvectorNeeded.
Fails
  • a value of the wrong type

On a client

Adds to the player’s own velocity, in metres a second, in a handler of a trigger that fires on clients, as me:set_velocity sets it.

NameTypeWhat it is
velocityvectorNeeded.
Fails
  • a value of the wrong type
local blast = vector.create(0, 0, 0)
local away = vector.normalize(p.position - blast + vector.create(0, 1, 0))
p:add_velocity(away * 6)

To push the player along a conveyor at once

Section titled “To push the player along a conveyor at once”
triggers.conveyor:on("entered", function()
me:add_velocity(vector.create(4, 0, 0))
end)
On the server p:tune(scales)
On a client p:tune(scales)

Scales how a player moves: their running speed, jump height and gravity, their view's bob and their weapon's sway.

On the server

Each scale is 1 as the engine has it, and those left out are kept; the scales outlast death. weapons scales the stats of every weapon the player holds, after the weapon’s own tune, each by 0 to 10: interval’s scales a burst’s too, and each result stays within what a weapon’s file may give. A weapon taken away is back to its own stats, and the next player to hold it scales it by their own. Each scaled weapon counts as one of the 4096 a mod names: past them, a weapon stays unscaled, which the server says as the mod’s error. On an NPC it fails.

NameTypeWhat it is
scalestableA table of the options below. Each may be left out.
speednumber?0 to 10Their running speed.
jumpnumber?0 to 10How high they jump.
gravitynumber?0 to 10Their gravity: at 0 a jump stays on the ground and a landing is no fall.
bobnumber?0 to 10How much their eyes bob with each stride.
swaynumber?0 to 10How much their weapon moves before their eyes: its bob, its lag behind the view's turns and its breathing.
weapons({["damage" | "interval" | "range" | "penetrate" | "spread" | "spread_moving" | "spread_air" | "reload" | "drop" | "raise" | "sprint_out" | "move_speed" | "fire_delay" | "aim_time" | "aim_spread" | "melee_damage" | "melee_range" | "melee_time" | "melee_delay"]: number})?Every weapon they hold, after its own tune: each stat named, by its scale, as a perk such as Double Tap does.
Fails
  • a value of the wrong type
  • an option it does not have
  • a value outside its range

On a client

Scales how the player’s own body moves, in a handler of a trigger that fires on clients, as me:set_velocity pushes it; a player’s game scales no weapons.

NameTypeWhat it is
scalestableA table of the options below. Each may be left out.
speednumber?0 to 10Their running speed.
jumpnumber?0 to 10How high they jump.
gravitynumber?0 to 10Their gravity: at 0 a jump stays on the ground and a landing is no fall.
bobnumber?0 to 10How much their eyes bob with each stride.
swaynumber?0 to 10How much their weapon moves before their eyes: its bob, its lag behind the view's turns and its breathing.
Fails
  • a value of the wrong type
  • an option it does not have
  • a value outside its range
p:tune({ speed = 0.5, jump = 0.5 })
p:tune({ weapons = { interval = 0.75, damage = 2 } })
p:tune({ gravity = 0.2 })
wait(10)
p:tune({ gravity = 1 })

To slow the player at once as they step into mud

Section titled “To slow the player at once as they step into mud”
triggers.mud:on("entered", function()
me:tune({ speed = 0.5 })
end)
On the server p:limit_view(limits?)
On a client p:limit_view(limits?)

Keeps a player's view within ranges, or turning no faster than a speed, until p:limit_view(nil) lifts it.

On the server

yaw, pitch and cone are measured from around, which they need. At an edge the view stops, and it moves off it at once, never winding past it; the ranges win over the speed there. A limit about an entity removed keeps its speed alone. A new limit replaces the last, and the limit outlasts death. On an NPC it fails.

NameTypeWhat it is
limitstable?A table of the options below. It, and each option, may be left out.
around(Angles | Entity)?What yaw, pitch and cone are measured from: angles, a roll ignored, or a model, a shape or a part as it turns.
yawAngleRange?How far the view turns left and right of around: radians either way, or {min, max} within half a turn, positive turning left. Not with cone.
pitchAngleRange?How far the view turns down and up from around, as yaw, positive looking up. Not with cone.
conenumber?0 to 3.1415927410125732The most the view strays from around's direction, in radians, in place of yaw and pitch. Not with pitch or yaw.
speednumber?0 or moreThe fastest the view turns, in radians a second; 0 freezes it.
Fails
  • a value of the wrong type
  • an option it does not have
  • a value outside its range
  • yaw and cone both
  • pitch and cone both

On a client

Limits the player’s own view, in a handler of a trigger that fires on clients, as me:set_velocity pushes them; around is angles or an entity, which the server checks.

NameTypeWhat it is
limitstable?A table of the options below. It, and each option, may be left out.
around(Angles | Entity)?What yaw, pitch and cone are measured from: angles, a roll ignored, or a model, a shape or a part as it turns.
yawAngleRange?How far the view turns left and right of around: radians either way, or {min, max} within half a turn, positive turning left. Not with cone.
pitchAngleRange?How far the view turns down and up from around, as yaw, positive looking up. Not with cone.
conenumber?0 to 3.1415927410125732The most the view strays from around's direction, in radians, in place of yaw and pitch. Not with pitch or yaw.
speednumber?0 or moreThe fastest the view turns, in radians a second; 0 freezes it.
Fails
  • a value of the wrong type
  • an option it does not have
  • a value outside its range
  • yaw and cone both
  • pitch and cone both

To keep a player in a turret looking ahead

Section titled “To keep a player in a turret looking ahead”
local turret = model("rocket")
p:limit_view({ around = turret, yaw = math.pi / 4, pitch = { min = -0.2, max = 0.5 } })

To freeze a player’s view for a cutscene

Section titled “To freeze a player’s view for a cutscene”
p:limit_view({ speed = 0 })
wait(3)
p:limit_view(nil)

To hold the player’s view ahead as they sit in a turret

Section titled “To hold the player’s view ahead as they sit in a turret”
triggers.turret_seat:on("entered", function()
me:limit_view({ around = { yaw = 0 }, yaw = 0.8, pitch = 0.4 })
end)
On the server x:set_position(point)
On a client p:set_position(point)

Moves a player, an NPC, a model, a shape, a camera or a part to a point at once.

On the server

A player goes on as fast, in the same stance and looking the same way, off any ladder or ledge, as CoD’s setOrigin; a dead one is not moved. An NPC lands on the navmesh’s point nearest it, and finds its way on from there. The point is within 100 km of the map’s origin. move_to moves a model or a part over some seconds. On a looping sound or effect it fails; on what is gone it does nothing.

NameTypeWhat it is
pointvectorNeeded.
Fails
  • a value of the wrong type

On a client

Moves the player’s own body to a point at once, in a handler of a trigger that fires on clients, so a teleport shows at once, as me:set_velocity pushes them.

NameTypeWhat it is
pointvectorNeeded.
Fails
  • a value of the wrong type

To send a player back to where they started

Section titled “To send a player back to where they started”
local start = p.position
wait(5)
p:set_position(start)
local crate = model("rocket")
crate:set_position(vector.create(3, 2, -4))

To teleport the player at once as they step onto a pad

Section titled “To teleport the player at once as they step onto a pad”
triggers.teleport:on("entered", function()
me:set_position(vector.create(0, 1, 20))
end)
On the server x:set_angles(angles)
On a client p:set_angles(angles)

Turns a player's view, an NPC, a model, a shape, a camera or a part at once, each angle left out kept.

On the server

A player turns by yaw and pitch, and an NPC by its yaw alone: a roll on either, or a pitch on an NPC, fails. A dead player is not turned. rotate_to turns a model or a part over some seconds. On a looping sound or effect it fails; on what is gone it does nothing.

NameTypeWhat it is
anglesAnglesNeeded.
Fails
  • a value of the wrong type

On a client

Turns the player’s own view, by yaw and pitch, in a handler of a trigger that fires on clients, as me:set_velocity pushes them; a roll fails.

NameTypeWhat it is
anglesAnglesNeeded.
Fails
  • a value of the wrong type

To turn a player to face the way they came

Section titled “To turn a player to face the way they came”
p:set_angles({ yaw = p.yaw + math.pi })
local crate = model("rocket")
crate:set_angles({ roll = math.pi / 2 })

To turn the player round as they come out of a teleport

Section titled “To turn the player round as they come out of a teleport”
triggers.teleport:on("entered", function()
me:set_angles({ yaw = math.pi })
end)
On the server p:control(target?, { movement? }?)

Hands a player's input to a model, a shape, a camera or a part in place of their body, until p:control(nil) gives it back.

Their movement keys, their view and their buttons then drive the entity. Without movement they drive nothing: the mod moves the entity with its orders and reads p.move and p.held as it likes. movement names a file of the mod’s that moves a model or a camera at each of the player’s commands: <name>.server.luau, run on the server alone, so the player sees it move a ping late, or <name>.shared.luau, run on their game too, so they see it move at once, as their body. A module’s own <name>.server.luau is no movement, so name a movement apart from it.

A movement file returns { hull = { radius, height }, state = t.record { … }, step = function(car, input, dt, world) … end }. step changes car in place: its position, velocity, angles, on_ground, and state, a record of up to 16 numbers, whole numbers, booleans, short strings, vectors and choices, starting at each field’s zero. input is { move = { forward, right }, angles = { yaw, pitch }, held }, and dt a tick. world:move(car, by) sweeps the hull, an upright capsule, by up to 3.9 m, sliding along what it meets, and gives { position, on_ground }; world:ground(point) gives the floor under a point, and world:trace(from, to) the first thing on a line, { position, normal }. A step is pure: it reads Luau’s libraries, vector, angles and t alone, gives no orders, and math.random and now() fail in it. The state goes whole to the player in every snapshot, so keep it to a few numbers. The steps of a tick share 2 ms, past which the commands left are dropped.

The hull’s radius and height are each 5 cm or more, up to 3 m and 4 m. It meets what stops players and never a body; a hull starting inside something is moved out by an inch. A step leaves the entity riding nothing, and an order of the mod’s moving it is where the next step starts. A string in the state is 32 bytes at most. A step that fails leaves the entity as it was, and the error is said once. Loaded again in place with a state of another type, a movement starts its state afresh.

Meanwhile the body stands where it was, and can be hurt and killed there; its view turns with the input and its weapon still fires, unless the mod disables it. Control outlasts death and a respawn. It ends as the entity is removed, as the player leaves, or at a new match. On an NPC or a player it fails, and with a movement on a shape or a part, which every player’s game is told of; on what is gone it does nothing. A movement file that fails to load fails control.

NameTypeWhat it is
targetEntity?May be left out.
optionstable?A table of the options below. It, and each option, may be left out.
movementstring?The movement file of the mod's that steps it, by its path without .server.luau or .shared.luau.
Fails
  • a value of the wrong type
  • an option it does not have

To fly a player’s gunship along its path while they aim from it

Section titled “To fly a player’s gunship along its path while they aim from it”
local plane = spawn_camera({ at = vector.create(0, 40, -30) })
plane:move_along({ vector.create(30, 40, 0), vector.create(0, 40, 30), vector.create(-30, 40, 0) }, 20, { loop = true })
p:set_camera(plane)
p:control(plane)
p:control(nil)
p:set_camera(nil)
On the server p:hold(held)

Holds a player where they are, in the air too, until p:hold(false) lets them go.

A held player still looks around, fires and changes stance, as CoD2’s linkTo holds them, and what they stand on still carries them. The hold outlasts death. On an NPC it fails.

NameTypeWhat it is
heldbooleanNeeded.
Fails
  • a value of the wrong type

To freeze everyone for a round’s countdown

Section titled “To freeze everyone for a round’s countdown”
for _, p in players do
if not p.npc then
p:hold(true)
end
end
wait(5)
for _, p in players do
if not p.npc then
p:hold(false)
end
end