Players

kcds.players.Player represents one connected player, and the object stays the same for the session. Values such as health, position and buffs are what the player's game last reported. Changes you make go to their game and take effect a moment later.

const { Events } = kcds.core;
const { Player } = kcds.players;

Events.on('playerReady', (player) => {
  console.info(`${player.nickname} (${player.id}) is at ${player.position}`);
});

Events.on('playerCommand', (player, command, args) => {
  if (command === 'heal') {
    player.heal();
  }
  if (command === 'tp' && args[0]) {
    const [target] = Player.find(args[0]);
    if (target) {
      player.teleport(target.position);
    }
  }
});

Finding players

CallReturns
Player.all()everyone connected, including those still loading
Player.getById(id)one by network id, or null
Player.find(text)what a command argument names: an id, or matching nicknames
Player.inRadius(position, radius, options?)players with a body in the world, nearest first
Player.nearest(position, options?)the closest player with a body in the world

The options are dimension, except to leave one player out, and radius for nearest.

An id is unique while the server runs and is never reused. playerIndex is the connection slot, which is reused.

Position

  • position, which moves them when assigned, rotation, velocity and gaze
  • ready: their body is in the world
  • teleport(position, label?): moves them on their next frame
  • spawn(position, rotation): used inside playerSpawning to choose where they appear when joining

Drawing things on a body: in a client script, another player's position moves in steps as network updates arrive, 40 to 150 ms apart, while the game draws the body smoothly. For anything attached to the body, ask where the game is drawing it:

  • renderPosition: where this machine is drawing the body, or null before it is here
  • jointPosition(joint): where a joint is being drawn, or null if the body lacks it. Use 'Bip01 Head', 'Bip01 R Hand', or the game's names, 'Head' and 'RightHand'
// client: a rope between a guard's hand and a prisoner's neck
const { Player } = kcds.players;

const hand = new Player(data.guardId).jointPosition('Bip01 R Hand');
const neck = new Player(data.prisonerId).jointPosition('Bip01 Neck');
if (hand && neck) {
  console.log(`rope ${hand.distance(neck).toFixed(2)} m`);
}

Dimensions

Players and entities see each other only in the same dimension. Dimension 0 is the shared world everyone starts in. Use others for instances, interiors, minigames or an admin's own space.

player.setDimension(1000 + player.id); // a dimension of their own
player.showOnlyTo(admin); // one other player can still see them

Most spawn calls, such as Npc.create, Prop.spawn and Vfx.spawn, also take a dimension.

Health and condition

Read: health, maxHealth, healthPercent, stamina, exhaust, hunger, bleeding, drunkenness, poisoning, alive, knockedOut, ableToAct, injuries.

Change: setStat, addStat and fillStat with a PlayerStat name, setHealth, setHunger, and heal(), the game's own cure.

Knock-outs: a fatal blow knocks a player out and fires playerDied, and revive() gets them up. Only knockedOut, setHealth(0) and revive() control a knock-out. player.buffs does not list the unconsciousness and addBuff refuses it, so a saved buff list cannot hold a player down at their next login. setKnockoutVision(percent) sets how much they see while down, and lootable sets whether others can search them.

Looks and body

  • setAppearance({ gender, body, head, hair, beard }) takes names from Appearances.
  • setOutfit(preset) dresses them in one of the game's outfits.
  • setVisible(false) hides the body, and setDisguise(model) draws it as a prop.
  • clean() and soil() change dirt and blood, and grime reads them.
  • playAnimation(fragment, options) and stopAnimation() play and stop animations.

A woman is put on the female skeleton, on her own screen and everyone else's, so she moves, holds weapons and rests her hands as a woman. She keeps what she wore and held. The game's rule keeping women from alchemy tables, the grindstone, horses, carrying bodies and pickpocketing does not apply to players.

Removing players

  • kick(reason) ends their session with "You were kicked from the server: ...".
  • disconnect(text, { quit }) lets them go without the word "kicked". The main menu shows text as written, or with quit: true their game closes. playerDisconnect follows, where you can save them. On the client, kcds.core.Game.quit() closes the game in the same way.
  • ban(reason) bans them from this server by their identifiers except the address, on the list KCDS-Admin keeps. They leave with "You are banned from this server: <reason>." and are refused when they return.

For players who are not online, use Bans.add(identifiers, reason). Bans.remove(idOrIdentifier) unbans, and Bans.find and Bans.list read the list. A script's ban never ends by itself, so for a three-day ban, store the end date and call Bans.remove when it comes.

Restricting a player

MemberEffect
setCuffed(true)hands behind the back; they can only walk and look, and only the upper body takes the pose
noclipAllowed = falseno flying with NoClip; true by default and again on rejoining, so set it in playerJoin (Free camera)
frozen = trueheld in place; see below
putInPillory(name?), releaseFromPillory()the pillory
setPace(mode)forbids running or sprinting
stopFight(opponent)ends a fight
setInteraction(name, allowed)the game's interactions for this player; see Server rules

frozen works like Npc.frozen. Their game lets through only looking around and menus, and a modified game that moves the body anyway is put back within a second. A script's teleport moves the spot where they are held. It ends when they leave the server.

Carrying

carrying, heldBy and putDown() cover carrying. holdItem(item) and dropHeldItem() are for items in the arms. Any item the game can carry in the arms works, including the game's quest sacks, such as rasuvUcen_sackcarryable. When put down, it is laid as a GroundItem on all screens.

Attaching to another player

attachTo(other, options) keeps a body next to another player, like a rider on a horse. detach() ends it, and it also ends when either player leaves. attachedTo reads the other player.

OptionMeaning
offset{ x right, y forward, z up } in metres, seen from other
rotationdegrees to turn the body; it otherwise faces the way other faces
look'free' (default) looks around up to 120 degrees either side; 'follow' keeps the view on the body's direction
animation, otherAnimation{ fragment, ...playAnimation options }, looping by default, stopping when the attachment ends

otherAnimation is upper-body unless it says otherwise, so other can walk. A cuffed player keeps the cuffed pose, and animation does not play on them. The attached player's game lets through only the menus, plus looking around with 'free'.

The two keep their distance on all screens and do not collide. The attached body is carried, though, so its legs do not walk unless you play an animation, and it passes through walls and furniture. Teleport it to a free spot if it may be inside something when you detach it. For a prisoner walking on their own legs, use Follow with a distance.

Items, skills and buffs

  • giveItem, takeItem, getInventory() and dropAll(): see Inventory
  • addXp, setLevel, addPerk and others: see Progression
  • addBuff, removeBuff, hasBuff: see Custom buffs

Reference: Player.