Skip to content
KCKingdoms Connected Scripting APIScripting guides and API
GuideMaintainer authored

NPC damage, death and interaction

Hurt, kill and revive NPCs, react to hits and deaths, and handle a player pressing the talk key at one.

The server keeps each NPC’s health. Players’ hits reach it after the server checks them, your script can change it, and events tell you when an NPC is hurt, dies, comes back or is spoken to.

Events.on("npcDeath", (npc, attacker) => {
const by = attacker instanceof Player ? attacker.nickname
: attacker instanceof Npc ? attacker.name : "nobody";
console.log(`${npc.name || npc.id} was killed by ${by}`);
});
npc.health; // current, clamped to maxHealth
npc.maxHealth; // what it starts with and is revived to; read-only
npc.alive; // false once health reaches zero
npc.invulnerable; // refuse damage before it reaches the ledger
npc.health = npc.maxHealth; // heal outright

Pass health and maxHealth to Npc.create to change the starting values.

npc.damage(25, player); // takes 25, credits player
npc.kill(player); // outright, even through invulnerable
npc.revive(); // back at full health
Call Does Refused when
damage(amount, attacker?) Takes health, raises npcDamage, and npcDeath if it was the last. The NPC is invulnerable or already dead.
kill(attacker?) Same path, ignoring invulnerable.
revive() Brings a dead NPC back at full health; clients make a fresh body.

The attacker is an optional player handle or id, used only to fill in the events. A dead NPC stays an entity: the corpse stays, the handle resolves, and players can search it if lootable is on. remove() or revive() it when you are done.

Player melee, arrows and NPC attacks can damage an NPC. For melee, the victim’s simulator resolves native contact and the server checks the accepted swing before changing health. npcDamage reports the amount actually taken. See NPC combat to give an NPC an attack order.

Event Arguments When
npcSpawn npc Right after an NPC is created or adopted, by any script.
npcDestroy npc While it is being removed. The handle still reads.
npcIntentDone npc, status Its order ended; see Move NPCs.
npcDamage npc, attacker, amount Health came off.
npcDeath npc, attacker The last of its health went.
npcRevive npc A dead NPC was brought back.
npcInteract npc, player A player pressed the talk key at it.
npcSimulatorChange npc, player The client running it changed; player is null when it went dormant.

Damage and death events use Player | Npc | null for attacker. The npcSimulatorChange player is still Player | null. Check the type before reading a player-only property such as nickname. Every event fires for every NPC on the server, including other resources’ NPCs: keep a set of your ids and return early for the rest.

Your game mode decides whether an NPC should counterattack, flee or keep its order. Here a guard’s partner runs when the guard is hit:

const partners = new Map<number, number>(); // npc id -> partner's id
Events.on("npcDamage", (npc, attacker, amount) => {
const partnerId = partners.get(npc.id);
if (partnerId === undefined || !attacker) return;
console.log(`${npc.name} took ${amount.toFixed(0)}, ${npc.health.toFixed(0)} left`);
Npc.getById(partnerId)?.flee(attacker.position, { speed: "run", radius: 30 });
});

npcInteract fires when a player presses the talk key (T by default, rebindable) within about three metres of an NPC while facing it. The server checks the distance, so a far-off claim never reaches your handler. Only NPCs with interactable on (the default) raise it.

Events.on("npcInteract", (npc, player) => {
npc.lookAt(player);
npc.say(`Well met, ${player.nickname}.`);
});

From here you usually open a dialogue or a shop; the NPC shop tutorial does both.

Events.on("npcSimulatorChange", (npc, runner) => {
console.log(`${npc.name || npc.id}: ${runner ? runner.nickname : "dormant"}`);
});

Most resources never need this. It helps with debugging, and with noticing that a pinned actor’s player walked away mid-scene. See Spawn NPCs.

Named and point-array patrols also raise patrolWaypoint(npc, info) and patrolFinished(npc, info). These include the route ID and waypoint state. See Named patrol routes for statuses and how they relate to npcIntentDone.

npcInventoryReady(npc) fires when the starting inventory is ready. npcInventoryChanged(npc, change) reports committed changes, including loot transfers. npcHarvested(npc, player) fires when a player finishes harvesting an animal. See Corpse loot for scripted stock and persistence.