Items
Items, inventories, containers and the interaction key (Game design document §5.5, §7.2, §7.4): the blocks the phone, the locks and keys of cars, the garages and stealth build on. Weapons and their ammunition are items too: what a character holds is the weapon in its selected slot, its ammunition in a pouch beside the strip (below). Everything here is simulation (packages/sim), so the server and every client's prediction world share it, and the determinism gate replays it.
Items are data
An item is a definition (ItemDef in packages/sim/src/items.ts): an id, a name, tags, how many stack in one slot, what may be done with it (use, drop, give into a container), for an item that is used, the hit points it heals, what a shop asks for it (its price; a game's rules.prices overrides it, $10 when neither says) and, for a weapon, the weapon it is (weapon, a name of the simulation's weapon table). The room's items are a table: the common ones, then every mission's own (items of a mission in the game document, see the Missions guide); a stack names an item by its index in that table, and the welcome sends the table to every client.
| Id | Name | Tags | Stack | Actions | Price | Used |
|---|---|---|---|---|---|---|
key | Key | key | 1 | drop, give | ||
keycard | Keycard | keycard | 1 | drop, give | ||
package | Package | package, delivery | 4 | drop, give | $20 | |
crate | Crate | crate, delivery | 1 | drop, give | ||
first_aid | First-aid kit | medical | 3 | use, drop, give | $50 | heals 50 (not when full) |
cash | Cash | cash | 1000 | drop, give | a player who takes it gets Cash, not a slot (see Cash) | |
dart | Tranquilizer dart | ammo, ammo:dart | 30 | drop, give | $3 | the tranquilizer fires one per shot (Stealth) |
ticket | Parking ticket | ticket | 5 | drop, give | $5 | lifts a barrier locked by ticket for its driver (Doors) |
snack | Snack | food | 5 | use, drop, give | $3 | heals 10 (not when full) |
jerry_can | Jerry can | fuel | 1 | drop, give | $25 | a thing to carry and deliver; gas stations sell them |
phone | Phone | phone | 1 | |||
pistol | Pistol | weapon, weapon:pistol | 1 | drop, give | $250 | the pistol: one pistol round a shot; the one gun that fires from a car |
shotgun | Shotgun | weapon, weapon:shotgun | 1 | drop, give | $600 | one shell a shot (all eight pellets) |
rifle | Rifle | weapon, weapon:rifle | 1 | drop, give | $1200 | one rifle round a shot |
rocket_launcher | Rocket launcher | weapon, weapon:rocket_launcher | 1 | drop, give | $3000 | one rocket a shot |
grenade | Grenade | weapon, weapon:grenade | 10 | drop, give | $60 | its own ammunition: each one thrown (or gone off in the hand) is used up |
tranquilizer | Tranquilizer | weapon, weapon:tranquilizer | 1 | drop, give | $500 | one dart a shot |
pistol_rounds | Pistol rounds | ammo, ammo:pistol | 120 | drop, give | $1 | the pistol's |
shells | Shells | ammo, ammo:shotgun | 50 | drop, give | $2 | the shotgun's |
rifle_rounds | Rifle rounds | ammo, ammo:rifle | 300 | drop, give | $1 | the rifle's |
rocket | Rocket | ammo, ammo:rocket | 10 | drop, give | $150 | the rocket launcher's |
Every character starts with a phone in its inventory's last slot when the room runs a game whose rules say so (the default); it is never dropped nor given. Its contacts, messages, apps and calls are not items but entries the missions keep: see the Phone guide.
Weapons are items
What a character holds is the weapon of the item in its selected slot (heldWeapon in packages/sim/src/weapons.ts): an empty slot, or an item that is no weapon (a first-aid kit, a key), is the fists. Seated, it is the pistol when that is the slot selected (from a car only the pistol fires, forward), the fists for anything else, and the HUD says why (rifle · can't fire from a car (2: pistol)); NPCs in cars select their pistol (carSlot). A character keeps its ammunition in a pouch of eight slots beyond the sixteen of the strip (AMMO_POUCH in packages/sim/src/items.ts): ammunition goes there first, whatever brings it in (a loadout, a pickup, a crate, a shop), spills into the strip only once the pouch is full, and nothing else ever goes there. Every gun spends its ammunition out of the inventory, pouch and all, one a shot: a pistol round, a shotgun shell (all eight pellets), a rifle round, a rocket, a tranquilizer dart; a grenade is its own ammunition, used up when it is thrown or goes off in the hand, so the last one leaves the hand empty. With none left a weapon does not fire, and the HUD says so (pistol · OUT OF AMMO; else pistol · 24 rounds, grenade · 3 left). Weapons and ammunition lie on the ground, sit in crates, lockers, trunks and pockets, are picked up, dropped and given like any item (the pouch's rounds are among the player's own in a container's panel, to put in a crate or a trunk), and the server checks every move: a searched guard gives up its gun (Stealth).
The number keys 1–9 select the first nine slots (X and a click on the strip reach all sixteen); the phone's panel takes them while it is out and a garage's panel takes 1 and 2 at the wheel. The input carries the selected slot, never a weapon: the server works out what is held, so no client chooses a gun it does not carry.
The strip, bottom centre, lays the sixteen slots in two rows of eight, no taller than the eight slots it had before: each tile reads its item's name in the small type and, under it, the count (×3), a weapon's tile its rounds left, the whole inventory's (48, 0 once it is out), so a weapon shows once and its ammunition never on a tile of its own; a name too long for the tile is cut with an ellipsis (Rocket l…). It stays clear of the legend on a 1280-pixel window, and the aim never follows the mouse over it, so a short strip leaves the ground south of the character to aim at.
Loadouts
What a player starts with is the game's rules.loadout (see the Missions guide): stacks of items by id, each in the slot of the strip it names (1 to 16) or the first free one; ammunition goes in the pouch, whatever slot it names. Without one every game and free roam give the arsenal (ARSENAL in packages/sim/src/loadouts.ts), the weapons free roam always had in the slots that keep the number keys meaning what they meant:
| Key / slot | Holds |
|---|---|
1 | nothing: the fists |
2 | the pistol |
3 | the shotgun |
4 | the rifle |
5 | the rocket launcher |
6 | ten grenades |
7 | the tranquilizer (its darts are found) |
| the pouch | 120 pistol rounds, 50 shells, 300 rifle rounds, 10 rockets |
| 16 | the phone, where the game gives one |
Sixteen slots: the arsenal's six weapons and the phone take seven, and nine are left for what is picked up (a key, a mission's parcels), the empty first slot among them: it fills first, so a weapon picked up there is on 1. A level reset gives every player their loadout anew; coming back after dying does not (what was spent is spent). NPCs carry their weapons in their pockets the same way (AI).
Dropping a mission's items on death
A character that dies (a player, a guard) drops the items a mission defined that it carried (the room's items after the common ones) where it fell, one pickup per stack in a ring around the body, for anyone to pick up; the common items stay with it. The game's rules.dropMissionItems (on by default) decides; the server's world alone does it (dropOnDeath in loadouts.ts, at the end of a step), so no client predicts a pickup of its own.
Tags
Missions check tags, not names: an item answers to each of its tags and to its id, so a door locked with key:door:office opens for whoever carries the mission's office key, and collect { tag: "package" } counts packages however they came. Each common item has a catalogue entry (item.<id>).
Cash: one wallet
A player has one Cash (Game design document §14), a number of dollars the room keeps per player for as long as it lasts (SimWorld.cash, packages/sim/src/cash.ts), and everything that pays or charges goes through it:
- a mission's reward pays into it, and a mission's
give/takeofcashadds to it and takes from it; - the
cashitems a player takes (off the ground, out of a crate, a locker, a trunk, a body's pockets) are counted into it, never into a slot of the strip; - a shop's counter sells for it, the garages take a respray or a stored car's fee out of it, and the police's fine for an arrest comes out of it.
The wallet (under the mission tracker, top right, missions or not; the in-game UI drawn in the scene) shows it, and a shop's panel shows it under the stock. Cash still lies around as an item (a mission hides banknotes in a locker, a guard carries them in its pockets): only a player's own hands turn it into Cash, so it cannot be put back into a crate. The decision was to have one number rather than a Cash item in the strip plus a mission wallet beside it: a player who picks up $100, wins a mission's $200 and pays a respray has $250 left, wherever each came from. A reset of the level forgets every Cash.
Shops
A shop is a counter (block:shop in a level, with its items; a mission's shop actor, a counter, vending or terminal, with what it sells, see the Missions guide; or a generated town's supermarket, gas station or shop row, whose counter anchors carry one, see the City guide), a terminal (TERMINAL_KINDS' counter, a 1.8 m × 0.7 m box as high as a hip) whose stock is a list of items at a price each: the game's rules.prices, else the item's own, else $10. E Shop in front of it opens its stock as the container panel does, with each line's price and the player's Cash; a click on a line buys one (the input's transfer), when the player has its price and it fits in the inventory, and the server says so (a buy event, the mission's item:<id>.bought).
Who holds items
- A character carries sixteen slots, its weapons and what it picks up, and a pouch of eight for their ammunition. The selected slot is part of the input: its weapon is the one held,
Fuses its item,Gdrops it. - Items on the ground are pickups: entities with a pose and a stack and no collider at all, so nothing (a wheel, a shot, the cover probe) ever touches them; the interaction key finds them by distance. A level, a mission (an
itemactor, aspawnItemaction, what agivecould not fit) or a drop lays them out. - A container: a crate (opened from any side) or a locker (opened from its front) holds eight slots and stands on a fixed box that blocks and gives cover like a wall. A level or a mission (
containeractor) puts one down. - A car's trunk holds six slots and opens from behind a car standing still that nobody drives; a two-wheeler has none. While its panel is open the character faces it, the middle of the rear bumper, whatever it aims at, as it faces any container, shop or terminal it has open (
openedFacing). - A lock (a tag) keeps a door or a container shut for anyone without an item answering to it; with one, the key unlocks it for good. Missions lock and unlock doors.
The interaction key
One key, E, decided in one place, interactionOf (packages/sim/src/interaction.ts): the server acts on it, the client shows it as the prompt beside the character. The candidates, with their reach from the edge of what they act on:
| Prompt | What | Reach |
|---|---|---|
| Get in · Get in as passenger · Carjack | a car (carjack.ts, as before) | its half length + 3 m from its centre |
| Unlock · Locked · hold to pick | a locked car: with its key, unlocks it and gets in; without, held three seconds, picks its lock (see Vehicles) | as a car |
| Take out class | the empty bay of a garage that stores, with a car stored | standing in the bay |
| Open trunk | behind a car standing still that nobody drives | 1.5 m of its rear bumper |
| Pick up name | items on the ground | 1.5 m |
| Open | a crate from any side, a locker from its front | 1.2 m of its box |
| Open door · Close door | a door, from either side; it swings away from whoever opens it | 1.5 m of its doorway |
| Locked | a locked door or container, without its key: nothing happens | as above |
| Enter code | a door a keypad locks: the phone's panel shows its keypad | 1.5 m of its doorway |
| Talk | a contact standing in the world: their dialogue | 1.5 m of their capsule |
| Use · Hack | a terminal: its app's screen in the phone's panel | 1.2 m of its post |
| Shop | a shop's counter: its stock and prices in the panel, a click buys one | 1.2 m of its counter |
| Close | the container the player has open (the panel's E) | always first |
| Search | an NPC asleep, knocked out or dead: its pockets in the panel | 1.5 m of its centre |
The closest wins, each candidate measured from the character to the nearest edge of what it acts on. Two within a quarter of a metre of each other go by a fixed order: closing what is open, then items, a person to talk to, a body to search or wake, a terminal, a container, a trunk, a stored car, a keypad, a door, and the car last (carjack, unlock, get in, ride along, pick), so the particular thing beats the car parked beside it, and the trunk beats getting in when standing right behind an empty car. Behind a car with a driver the key still rides along, as it always did.
A container the player opens shows as a panel above the inventory strip: what it holds and what the player holds, a click on one of its items taking the stack (as much as fits), a click on one of the player's putting it in (an item that may be given). The panel's buttons never take the keyboard's focus, so the game's keys keep working while it is open; it closes on E, or when the player walks away, sits in a car, goes down or takes cover. X selects the next slot of the strip; a click selects one.
Doors
A door is a block of the level pipeline (block:door, see the Levels guide): a panel standing on its node's origin, the middle of its doorway's floor, scaled to its width, height and thickness, turned with yaw only, its script's lock the tag that unlocks it. The export lists it under the level's doors (not a placement: the simulation builds it). The world makes one entity per door, shut; open, it is swung a quarter turn about its hinge (its −x end) away from the character, and its collider with it. A mission's door actor binds the level's door nearest a place, and its rules lock and unlock it; the snapshots carry each door's state to every client.
A door has a kind (its script's kind): a door (as above), a gate (slides aside along its width) or a barrier (an arm that lifts). A gate or a barrier opens by itself for a car within 6 m of its doorway whose driver carries what unlocks it (a gate locked by keycard for a keycard, a barrier locked by ticket for a parking ticket, one with no lock for anybody), away from the car, unless a keypad locks it; it shuts again once nothing has come within 3 m of its doorway for a second and a half. On foot it opens with the interaction key like a door. The gates' and barriers' system runs on the server before each step (gateSystem in packages/sim/src/doors.ts) and tells the missions (a gate event, the door: events).
A container is a block too (block:container, never scaled): its script's kind (crate, locker, or pickup for items lying on the ground), items (ids with an optional count: first_aid*2 cash*50) and lock; the export lists it under the level's containers, and the server lays them out with the world and again on a level reset (which also shuts the doors and locks them as the level has them). An item a level names that the room does not know is left out, logged.
On the wire
- The input carries the selected slot (the weapon held is worked out from it: the input has no weapon of its own), the
dropandusepresses and atransfer(one byte:n > 0takes the open container's slotn − 1,n < 0puts the player's slot−n − 1in). Like the other one-shots, a repeated input never carries them and a dropped one hands them on. They are never predicted: the snapshots and the inventory say what came of them. - Snapshots carry the doors (always), the items on the ground and the containers (within the area of interest); the client's mirror keeps twins of them, so the predicted character bumps into a crate as the server's does and the local interaction rule finds the same candidates.
- A reliable
inventorymessage tells each player what they hold and the container they have open, whenever it changes; the mirror puts it on the player's twin, so the prompt knows the keys the player carries and the HUD the weapon held and its ammunition. The welcome's table of items says which are weapons (weapon). - The item events (picked up, dropped, given, a container opened, a door opened or shut) stay on the server: the mission host turns them into the missions'
item:,container:anddoor:events.
Determinism
Inventories (every stack held, by entity and slot), every player's Cash, pickups, containers, shops' stock and doors (a gate's or a barrier's state and its clearance count with them) are part of hashSimState, and packages/sim/src/determinism.integration.test.ts replays a player picking items up, dropping them, opening a crate and moving a stack out of it and back, a player buying at a counter for Cash, a driver with a keycard through a gate, then random item presses and players with the arsenal firing at random (spending their ammunition), in two worlds that must agree on every tick.
Mini levels and tests
test-inventory: a first-aid kit on the ground and a crate of cash (taken, it is Cash) a few steps from the spawn, the player's car for its trunk, and its game's Parcel Run (three parcels to collect and deliver, a waybill of its own) and loadout (a pistol, 24 rounds, three grenades). E2E-130 to E2E-134, E2E-390 to E2E-394 (the slots and the weapon held, ammunition, a weapon dropped and picked up, the waybill dropped on death, the game's loadout).test-city-life: Cash by the spawn, a shop's counter selling first-aid kits and parking tickets, a garage west of the spawn, a gate locked by a keycard and a car park's barrier locked by a ticket. E2E-303, E2E-304, E2E-306 (see the City guide).test-interaction: a room whose front door is locked by the office key lying nearby, an unlocked side door, a locker, and its game's Office Hours. E2E-135 to E2E-137.- Unit tests:
packages/sim/src/items.test.ts,interaction.test.tsandloadouts.test.ts(weapons as items, ammunition, loadouts, the drop on death),packages/missions/src/runtime-items.test.tsandvalidate-items.test.ts,apps/server/src/items.test.ts,packages/world/src/pieces-interactables.test.ts.
What comes next on these blocks
The locks and keys of cars, the garages and the parked cars are built (an owner and a lock per vehicle, keys as items tagged key:vehicle:<id>, as the RentaCar app hands over: see the Vehicles guide), and so are weapons and ammunition as items and a mission's items dropped on death. Next: a mission's own weapons (an item of a mission with a weapon), and inventories that outlast the room (accounts). The phone is built: an item whose contacts, messages, apps and calls are entries the missions keep (see the Phone guide). NPCs' pockets and keycards are Stealth's: a character's own inventory is its pockets, searched once it is down (E Search, the panel's Pockets); an NPC at the key wakes a sleeper instead.