Skip to content

Knocking a player out and carrying them

A fight does not have to end in a death. A mode can knock a player out - they drop where they stand, their screen goes dark, their health stays as it is - and someone can pick them up, carry them over a shoulder to somewhere else and put them down. It is the game’s own grab, carry and put-down: the carrier’s body takes the other over the shoulder, walks with them and lays them down, and every player who has both bodies sees exactly that. The same works for the dead - a character that lies dead, a dead player’s corpse - and for NPC actors, which a mode can have carry or be carried.

This page is the whole job: knocking a player out, carrying them, and letting players grab bodies themselves. The names are in the Carrying group of the server API.

SetPlayerKnockedOut(pid, true, seconds) takes a player down. With seconds they wake by themselves after that long; without, they stay down until the mode wakes them (SetPlayerKnockedOut(pid, false)), they die, leave or respawn. It answers true, or false and the reason (“They are riding.”) - a rider has to be put off the horse first (ThrowPlayerFromHorse).

While they are down players cannot fight, ride, take a cart seat, make an emote, start a dice match or open anything; their health is whatever it was - bleeding goes on, so a long knock-out of a wounded player can still end in a death. The mode is told twice: OnPlayerKnockedOut and OnPlayerWake ("woke" when the timer ran out, "mode", "died", "left", "respawned").

A common use is a mode’s own rule for a blow that would kill:

-- a blow that would kill knocks the player out for a minute instead
function OnPlayerDamage(pid, attacker, damage)
if damage >= GetPlayerHealth(pid) and not IsPlayerKnockedOut(pid) then
if SetPlayerKnockedOut(pid, true, 60) then
return GetPlayerHealth(pid) - 1 -- they keep one point of health
end
end
end

An NPC actor can be knocked out too (SetActorKnockedOut): it drops, its walk and its fight stop, and it can be carried the same way.

CarryPlayer(carrier, target) has one player take another. The carrier’s game plays the grab - about three seconds - and then the carry; the target does not have to be knocked out (they show knocked out for the carry and wake after it), but a player the mode knocked out stays down after the put. Both must be standing in the world close together (the order reaches six metres) and not busy - riding, in a cart, flying, in a dice match, in a fall or a pull-down, already carrying or carried. The carrier must also be alive and not knocked out, in a fight, at a shop or in a dialogue (the player they take may be in a fight, at a shop or in a dialogue). The answer is true, or false and a reason you can show:

local ok, why = CarryPlayer(guard, prisoner)
if not ok then SendClientMessage(guard, COLOR_RED, why) end -- "Hans is too far away (8.2 m; 6 m at most)."

StopCarry(pid) puts them down - pid can be the carrier or the carried, and which of them may order it is yours to decide: a /putdown command should check IsPlayerCarrying(pid) first, or the carried player puts himself down - with the game’s own put-down, or at a place of your choosing, or at once:

StopCarry(guard) -- the put-down plays, the body lies where the game puts it
StopCarry(guard, cellX, cellY, cellZ, 180) -- ... at the cell, facing south
StopCarry(guard, cellX, cellY, cellZ, 180, true) -- ... at once, no animation

A put ordered while the grab still goes on waits for it to finish, then plays. While they carry, the carrier walks at the carry’s pace (2.4 metres a second unless you pass another, at most 4) and cannot sprint, jump, fight, ride or act. The carried player’s position is the carrier’s - the server does not judge it - and they cannot act either. When the carry ends, OnPlayerCarryEnd says why: "put down", "mode", "hit" (the game broke it off - a blow on the carrier), a death, a disconnect, "moved" (you teleported one of them) and the rest. Anything you do to one of the two on your own - SetPlayerPos, a respawn, MountPlayer, a cart seat, another virtual world - ends the carry, so end it first when you mean to keep it. A carried player is not a free player for your commands either: a /unstuck or a /createcart that moves him would end his carry for him, so a mode that means it says no to a knocked-out or carried player first (BasicRP does).

IsPlayerCarrying, IsPlayerCarried, GetPlayerCarrying and GetPlayerCarriedBy read it back - the last two answer a kind ("player", "corpse" or "actor") and an id.

CarryEntity(carrier, id) takes an NPC actor’s body - dead, or alive and shown knocked out for the carry - or a dead player’s corpse. A player’s corpse is a body in the world only when the server keeps it ([combat] corpse_seconds above 0 in server.toml): it is then carried like any other, and searched where it was put down. An NPC actor can carry too: ActorCarryEntity(actorId, id) and ActorCarryPlayer(actorId, pid) have a guard take a body or a player; walk the actor with MoveActor once its grab is done (a few seconds later; it answers false until then) and the body goes with it, then ActorPutDown. No callback tells an actor’s carry - poll GetEntityCarrier(id).

With SetCarrying(true, rules) the players do it themselves: the game’s own “grab” prompt shows on a body that lies down - a dead character’s, a knocked-out player’s or actor’s - and a player within reach takes it. It is off by default; the rules say what it takes:

function OnGameModeInit()
SetCarrying(true, {
range = 2.5, -- metres from the body when they reach for it
speed = 2, -- the carrier's pace, metres a second
corpses = true, -- the dead
players = true, -- knocked-out players
actors = false, -- knocked-out NPC actors
})
end

The server checks each ask - the reach, that nobody else has the body, that the player is free to - and the mode has the last word in OnPlayerCarry; return false to refuse:

-- only the guards (team 1) may carry other players; anyone may carry the dead
function OnPlayerCarry(pid, kind, id, victim)
if kind == "player" and GetPlayerTeam(pid) ~= 1 then
SendClientMessage(pid, COLOR_RED, "Only the guards may carry prisoners.")
return false
end
end

SetEntityCarryable(id, false) takes one body out of the prompt - a quest corpse that must stay where it lies - while your own orders still carry it. OnPlayerCarryStart and OnPlayerCarryEnd are the places to keep score, say a line or save the place the body was put.

freeroam.lua and basicrp.lua in the server folder have a CARRY table at the top (enabled = false, range, speed, and what the prompt takes), switch the grab on from it, and answer the commands an admin needs to try it alone: /ko [player] [seconds], /wake [player], /carrying on|off, /carry <player> and /putdown. BasicRP lets every player use /carry (on a knocked-out player within the rules’ range and a metre more, as the prompt does) and /putdown (what they carry themselves) while CARRY.enabled is true; an admin’s /carry and /putdown work in BasicRP whatever CARRY.enabled says, and /carry takes any player, knocked out or not. The two modes differ on /ko: BasicRP’s, given no time, keeps the player down for CARRY.ko_seconds (120 as shipped; 0 = until /wake), freeroam’s keeps them down until /wake. BasicRP answers a knocked-out or carried player’s commands with “Not while you are knocked out or carried.” - he may still talk. duel_arena.lua keeps it off.

  • A player’s game must be able to take part. A game from an older or unsupported build cannot carry or be carried; the server starts nothing with it, and the order answers false with the reason. (It is knocked out all the same: the server holds the player down, his game just does not show it.)
  • The prompt’s state keys are the server’s. The grab is switched on for the clients through the world state carry, and a body taken out of it through that entity’s state carry; do not set them yourself. A mode reload switches the grab off again - the new mode’s OnGameModeInit calls SetCarrying.
  • A body the game cannot grab stays where it lay. And where a carrier puts one down is where the game laid it as long as that is within a few metres of him, on his level and in the open; if not, the server lays it a step ahead of him.
  • Nothing is saved. A carry and a knock-out are over when the server stops; a mode that keeps a prisoner knocked out saves that itself.
  • Women carry and are carried like men. Nothing in the API treats them differently.
  • Reach. A player’s own grab reaches as far as range (3 metres by default) and the server allows a metre more for the positions being a few frames old; the mode’s orders reach six metres.