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.
Fields
Section titled “Fields”What a player, p, or an entity, e, reads beside the mod’s state. A field of the other side’s fails.
| Name | Type | Side | What it is |
|---|---|---|---|
p.position | vector? | On both sides | Where they stand, at their feet. |
p.yaw | number? | On the server | Which way they face, in radians: 0 faces +Z, more turns left. |
p.pitch | number? | On the server | How far up they look, in radians. |
p.ground | (Entity | Player)? | On the server | What they stand on; nil in the air or on the map. |
p.move | Move? | On the server | Their movement keys, each -1 to 1, as of their latest command. |
set_velocity
Section titled “set_velocity”p:set_velocity(velocity)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.
| Name | Type | What it is |
|---|---|---|
velocity | vector | Needed. |
- 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.
| Name | Type | What it is |
|---|---|---|
velocity | vector | Needed. |
- Fails
- a value of the wrong type
To throw a player up into the air
Section titled “To throw a player up into the air”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)add_velocity
Section titled “add_velocity”p:add_velocity(velocity)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.
| Name | Type | What it is |
|---|---|---|
velocity | vector | Needed. |
- 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.
| Name | Type | What it is |
|---|---|---|
velocity | vector | Needed. |
- Fails
- a value of the wrong type
To knock a player back from a blast
Section titled “To knock a player back from a blast”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)p:tune(scales)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.
| Name | Type | What it is |
|---|---|---|
scales | table | A table of the options below. Each may be left out. |
speed | number?0 to 10 | Their running speed. |
jump | number?0 to 10 | How high they jump. |
gravity | number?0 to 10 | Their gravity: at 0 a jump stays on the ground and a landing is no fall. |
bob | number?0 to 10 | How much their eyes bob with each stride. |
sway | number?0 to 10 | How 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.
| Name | Type | What it is |
|---|---|---|
scales | table | A table of the options below. Each may be left out. |
speed | number?0 to 10 | Their running speed. |
jump | number?0 to 10 | How high they jump. |
gravity | number?0 to 10 | Their gravity: at 0 a jump stays on the ground and a landing is no fall. |
bob | number?0 to 10 | How much their eyes bob with each stride. |
sway | number?0 to 10 | How 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
To slow a player wading through mud
Section titled “To slow a player wading through mud”p:tune({ speed = 0.5, jump = 0.5 })To give a player Double Tap
Section titled “To give a player Double Tap”p:tune({ weapons = { interval = 0.75, damage = 2 } })To float in low gravity for ten seconds
Section titled “To float in low gravity for ten seconds”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)limit_view
Section titled “limit_view”p:limit_view(limits?)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.
| Name | Type | What it is |
|---|---|---|
limits | table? | 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. |
yaw | AngleRange? | 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. |
pitch | AngleRange? | How far the view turns down and up from around, as yaw, positive looking up. Not with cone. |
cone | number?0 to 3.1415927410125732 | The most the view strays from around's direction, in radians, in place of yaw and pitch. Not with pitch or yaw. |
speed | number?0 or more | The 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
yawandconebothpitchandconeboth
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.
| Name | Type | What it is |
|---|---|---|
limits | table? | 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. |
yaw | AngleRange? | 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. |
pitch | AngleRange? | How far the view turns down and up from around, as yaw, positive looking up. Not with cone. |
cone | number?0 to 3.1415927410125732 | The most the view strays from around's direction, in radians, in place of yaw and pitch. Not with pitch or yaw. |
speed | number?0 or more | The 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
yawandconebothpitchandconeboth
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)set_position
Section titled “set_position”x:set_position(point)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.
| Name | Type | What it is |
|---|---|---|
point | vector | Needed. |
- 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.
| Name | Type | What it is |
|---|---|---|
point | vector | Needed. |
- 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.positionwait(5)p:set_position(start)To put a crate on a ledge
Section titled “To put a crate on a ledge”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)set_angles
Section titled “set_angles”x:set_angles(angles)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.
| Name | Type | What it is |
|---|---|---|
angles | Angles | Needed. |
- 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.
| Name | Type | What it is |
|---|---|---|
angles | Angles | Needed. |
- 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 })To tip a crate onto its side
Section titled “To tip a crate onto its side”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)control
Section titled “control”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.
| Name | Type | What it is |
|---|---|---|
target | Entity? | May be left out. |
options | table? | A table of the options below. It, and each option, may be left out. |
movement | string? | 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)To give a player back their body
Section titled “To give a player back their body”p:control(nil)p:set_camera(nil)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.
| Name | Type | What it is |
|---|---|---|
held | boolean | Needed. |
- 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) endendwait(5)for _, p in players do if not p.npc then p:hold(false) endend