Inventory and items
The server holds each player's inventory, through kcds.players.Inventory.
Naming items
Use an item's class GUID or its name in the game's item table, such as apple, bread or arrow_crude.
Inventory.classes() lists them.
Items.model(item) gives the mesh a class has on the ground, or '' if the game's tables give none. Most of these
also work as props, which shows a sword on its own, held still:
const { Items } = kcds.players; kcds.world.Prop.spawn(Items.model('longSwordDuel'), position, undefined, undefined, 'none');
Changing an inventory
Each change is all or nothing, and answers { ok, code, revision, items }. A refused change has ok: false and a
code, such as invalidItem, invalidAmount, insufficientItems, inventoryCapacity, unknownItem or
staleRevision.
const answer = kcds.players.Inventory.add(player, { item: 'apple', amount: 3 }); if (!answer.ok) { console.log(`refused: ${answer.code}`); } // Shorter forms: player.giveItem('bread', 2); player.takeItem('apple', 1);
| Call | Effect |
|---|---|
Inventory.add(player, { item, amount, metadata? }) | adds units to the row with the same properties, or a new row |
Inventory.remove(player, { units: [{ id, amount }] }) | takes units out of rows |
Inventory.editRow(player, { id, metadata }) | replaces a row's quality, condition and custom fields |
Inventory.editCustom(player, { id, name?, description?, data? }) | sets a row's own name, description or data; null resets one |
Inventory.set(player, { items, quickslots? }) | replaces everything and dresses the body; see Equipment |
Inventory.transfer(from, to, { units }) | moves exact units between two players |
metadata accepts quality, health or condition, poison, poisonCharges, onEquipBuffs, transient, and
custom: { name, description, data }, where data is a plain object, not text.
notify: false in a request leaves out the "You received" notice.
Reading
Inventory.get(player) returns { revision, items, quickslots, ready }. Each row is { id, item, name, amount, quality, health, condition, equipped, metadata }. If you pass the revision you read with a change, the change is
refused if the inventory has changed in the meantime.
Items that vanish on leaving
A row with transient: true leaves the inventory when its player disconnects, before playerDisconnect fires. So a
script saving the inventory at that point never saves it. It always gets its own row, and reads back with
metadata.transient. If you save at another time, you can leave such rows out yourself.
const { Inventory } = kcds.players; // A sack over the prisoner's head, gone if they leave the server. Inventory.add(prisoner, { item: 'BagOverHead_m01', amount: 1, metadata: { transient: true }, }); kcds.core.Events.on('playerDisconnect', (player) => { // The sack is not in what gets saved here. console.info(JSON.stringify(Inventory.get(player)?.items)); });
Events
playerInventoryReady: their game now shows the server's stockplayerInventoryChanged: with the reason for the changeplayerItemUsed: food, potions, or ammunition spent
Your own item types
Items.register creates a type that borrows the look of a miscellaneous item, crafting material or document. It works
with all inventory, stash and ground item calls.
const { Items } = kcds.players; const sealedLetter = Items.register('myres:sealed_letter', { name: 'Sealed letter', description: 'A letter with the seal of the burgrave.', visual: 'crime_letterOfRecognition', weight: 0.1, usable: true, useLabel: 'Break the seal', }); player.giveItem(sealedLetter); kcds.core.Events.on('playerCustomItemUse', (player, row, revision) => { kcds.core.Chat.sendToPlayer(player, 'The seal breaks.'); });
Changing the game's items
Items.override(item, { weight, price, max, ...stats }) changes an item for all players, where max is the most units
a player can hold. Items.clearOverride(item) restores the game's values. To apply the same when the server starts, use
resources/item-config.json:
{
"arrow_crude": { "max": 40, "price": 20 },
"bread": { "weight": 0.2 }
}Inventory.overrideStats(item, stats) rewrites a class's combat numbers for everyone. A new set replaces the previous
one entirely. Inventory.itemStats(item) reads them, or returns null for a class that is unchanged.
const { Inventory } = kcds.players; Inventory.overrideStats('longSwordDuel', { attack: 210, strReq: 12 }); Inventory.overrideStats('SkullCap02_m02_C2', { defenseStab: 150, noise: 0.1 }); Inventory.overrideStats('longSwordDuel', null); // back to the game's numbers
Other calls: Inventory.setWearRates({ default, armor, ... }) makes items wear faster or slower,
Inventory.renameItem(item, name) renames an item for everyone, and Inventory.itemPrice prices one unit as the game
does.
Items on the ground
kcds.world.GroundItem is a stack in the world that all players see and can pick up. Items players drop and arrows
that land become ground items too.
const { GroundItem } = kcds.world; GroundItem.spawn('apple', player.position, {}, 5); GroundItem.spawn('bread', player.position, {}, 1, undefined, { name: 'harvest_table' }); const breadStack = GroundItem.all().find((stack) => stack.name === 'harvest_table'); kcds.core.Events.on('groundItemPickup', (stack, player) => { console.info(`${player.nickname} took it`); });
Landing
A stack starts where it was spawned or dropped, and the game's physics lets it fall and roll. When the first player's
game with a view of it sees it stop, it stays at that spot for everyone: resting turns true, position is where it
lies, and groundItemResting fires. To wait for landing, listen for that event rather than polling the position:
const { GroundItem } = kcds.world; const droppedApple = GroundItem.spawn('apple', { x: 1650, y: 2151, z: 40 }); kcds.core.Events.on('groundItemResting', (landed) => { if (landed === droppedApple) { console.info(`the apple landed at ${landed.position.z.toFixed(2)}`); } });
A landed arrow or bolt is at rest from the start. If it sticks in a target, wall or tree, it stays there for all players, where the shooter's game saw it, and any player can pull it out once.
For one player only
A stack can be shown to a single player, whose game alone lays it and who alone can take it, such as an item a shop
previews for a customer. showOnlyTo(null) shows it to everyone again. If that player leaves, nobody sees the stack
until it is shown to someone else.
const preview = kcds.world.GroundItem.spawn('longSwordDuel', counter, {}, 1, undefined, { visibleTo: player, });
To refuse a pick-up of the level's own items, use worldItemPickup; see Time, weather and the world.
In the player's game
On the client, kcds.players.Inventory.whenUsed(item, handler) takes over an item's actions on the inventory screen.
The handler receives the use, and the server decides what it does.
Reference: Inventory, Items, GroundItem.