Spawn NPCs
Spawn server-owned NPCs, change them, pin one to a player for a scripted scene, and remove them.
An NPC is a body your resource puts in the world: a guard, a stallholder, an actor in a scene. The server owns its name, health, orders and clothes; a nearby player’s client runs the body.
const guard = Npc.create({ soul: "guard", position: player.position, name: "Guard Radim", nametag: true,});guard.lookAt(player);Spawn an NPC
Section titled “Spawn an NPC”Npc.create takes one options
object. Everything has a default; in practice you set soul and position.
| Option | What it does |
|---|---|
soul |
A role from Npc.roles() (guard, bandit, townswoman, …) or a soul GUID from the game’s tables. |
position, rotation |
Where it stands and which way it faces. |
name |
Shown over it and in conversation. Empty keeps its soul’s own name. |
outfit |
A clothing preset GUID from the game’s table. |
wearing |
A list of item class GUIDs to dress it in instead. |
appearance |
Face, hair, beard and skin, as for a player. |
health, maxHealth |
The health ledger. maxHealth defaults to 100. |
faction |
Faction row for relationship and crime decisions; 0 is none. |
locomotion |
native (the default) or kinematic; see how it walks. |
invulnerable, frozen |
Refuse damage; hold the pose whatever the orders say. |
interactable, nametag |
Raise npcInteract on the talk key; draw the name. Both on by default. |
lootable |
Whether the corpse keeps its inventory for whoever searches it. |
virtualWorld |
Which virtual world it lives in. |
A role is a real soul from the game’s tables, so guard already looks like a
guard. Animal names and GUIDs from Npc.animals() also select their native class;
see Animal populations. Other souls are given by GUID;
Souls lists the game’s human looks.
console.log(Npc.roles().join(", "));Npc.create returns before any client runs the body. A new NPC far from every
player starts dormant, which is fine.
Use ordinary readable text for name; KCDC supplies the game’s labels for
conversation and name displays. A resource does not need to register its own
localization key just to name an NPC.
Take over a level NPC
Section titled “Take over a level NPC”Npc.adopt(levelGuid, options) takes over a body the level already placed. A
level EntityGuid is the same on every machine, so every client finds the same
body. soul and class are ignored, and adopting the same guid twice returns
the NPC that already has it.
Check who runs the body
Section titled “Check who runs the body”The server cannot walk or animate a body, so one client simulates each NPC. The server elects the nearest client within about 120 m, keeps it until it is past 160 m or someone is clearly nearer, and reruns the election about twice a second. Each client runs a limited number; the overflow goes to the next nearest player.
With nobody in range the NPC is dormant: still on the server, run by
nobody. npc.simulator is the player running it, or null while dormant.
const runner = npc.simulator;console.log(runner ? `${npc.name} is run by ${runner.nickname}` : `${npc.name} is dormant`);A change of simulator changes nothing about the NPC: its orders, health and identity stay on the server and the new simulator picks them up.
Pin an NPC to a player
Section titled “Pin an NPC to a player”npc.pin(player) makes that player’s client run the NPC whatever the
distances. npc.pin(null) hands it back to the election. Pin actors in a
scripted scene, so the scene is timed on the machine it is played to.
const actor = Npc.create({ soul: "townsman", position: player.position, name: "Vendel" });actor.pin(player);// ... run the scene, then:actor.pin(null);A pinned NPC goes dormant, rather than migrating, when its player walks out of range, and is unpinned if that player disconnects. The NPC cutscene tutorial shows the full pattern.
Change an NPC
Section titled “Change an NPC”npc.name = "Guard Vaclav";npc.nametag = true;npc.interactable = false;npc.invulnerable = true;npc.frozen = true; // holds its pose whatever its orders saynpc.faction = 3;
const hair = Appearances.options("hair", "male")[0];if (hair) npc.setAppearance({ gender: "male", hair: hair.name }); // only what you pass changessetOutfit(presetGuid)andwear(itemClassGuids)redress it, like theoutfitandwearingoptions.setAppearanceis a write, not a request. The soul fixes the gender, so an appearance from the other gender’s catalog is refused.soulis read-only. For a different soul, remove the NPC and create another.npc.teleport(position, rotation?)moves it outright; a pose the simulator sent just before cannot put it back.
Find and remove NPCs
Section titled “Find and remove NPCs”Npc.all(); // every NPC; pass a virtual world to narrow itNpc.getById(npc.id); // null once it is gonenpc.remove(); // this one, everywhereNpc.removeAll(); // all of them; pass a virtual world to narrow itStore ids, not handles, and resolve them with getById. To clean up on a hot
reload, remove the NPCs you made in a resourceStop handler, and only those:
Npc.removeAll() takes every other resource’s NPCs too.
The default gamemode’s src/server/commands/npc.ts and npcdemo.ts exercise
every call on this page.
Related
Section titled “Related”- Move NPCs: walk, follow, patrol, and hear when they are done.
- NPC damage and death: health, hits and the talk key.
- Build an NPC shop: an NPC who trades.
- Script an NPC cutscene: pinned actors in a scene.