Skip to content

Vehicles: owners, locks, keys and garages ​

Getting a vehicle (Game design document §5.5, §6.3, §12): every car has an owner and a lock, keys are items, a lock can be picked, a level parks cars in its bays, and garages respray and store them. It rests on the items (a key is an item, the interaction key opens what it may) and is written in the mission language. Everything here is simulation (packages/sim: locks.ts, garages.ts, spawners.ts), so the server decides it and the determinism gate replays it.

Owners ​

Every vehicle has an owner: nobody, a player (by client id), an NPC (by entity) or a mission (Vehicle.owner, Vehicle.ownerId).

How a car comesWhoseLocked
A player's car at their spawnthe player's (they take its wheel first)no
Ambient traffic, a chaser's car, a police carits NPC driver'sno
A level's vehicle spawner (a parking bay)nobody's or an NPC's, as the block saysunless the block says not
A mission's vehicle actorthe mission's, nobody's or an NPC's (owner)when the actor says (locked)
Taken out of a garagethe player'sno

Ownership changes hands three ways: taking the wheel of a car nobody owns makes it the driver's, and a player who takes the wheel of an NPC's car makes it theirs (stolen); a car a player carjacks or picks the lock of is theirs from then on, whoever's it was. Another player's car and a mission's stay whose they were when somebody else drives them; a mission's car somebody sits in when the mission ends is its driver's.

Locks and keys ​

A vehicle's lock is shut or open (Vehicle.locked); its key is any item answering to the car's key tag (SimWorld.locks, usually key:vehicle:<id>: exactly the shape the phone's RentaCar app hands over). Missions check tags, so a mission defines the key of one car as its own item ({ "id": "van_key", "name": "Van key", "tags": ["key:vehicle:van"] }) and gives it, lays it out or hides it like any item; a level's container may hold it too, and so may a guard's pockets (a mission's npc actor's pockets, a level NPC spawner's items), searched off the body once it is down (see Stealth).

The interaction key E at a car (vehicleInteraction in carjack.ts, weighed by interactionOf):

The carThe promptWhat E does
open, or the player's ownGet in · Get in as passengeras always
locked, its key carriedUnlockunlocks it for good and gets in, on the seat it would have taken (the wheel when free): one press, decided so the key feels like a key
locked, no key, its wheel freeLocked · hold to picka press does nothing; held for three seconds (PICK), it picks the lock: the character stands still at the door, the prompt says Picking… 40% (the server's word), and the car is unlocked and the player's
locked, no key, a driver at its wheelLockednothing (riding along needs it open)
a driver to pull out (stopped, at the driver's door)Carjacka carjack is by force: no lock stops it

Where several things are within reach, the closest wins and a tie goes by PRIORITY in interaction.ts, the order stealth set: close, pickup, talk, search, wake, use, hack, open, trunk, take out (a stored car, in a garage's empty bay), keypad, open door, close door, locked, carjack, unlock, enter, passenger, pick last, so a held key never picks a lock while something else is offered. A garage's respray and store are not interactions: at the wheel, 1 and 2 on its panel (the input's service).

A locked car's trunk stays shut to whoever it does not open to. The input carries the key held (interact, besides the one-shot action); picking is never predicted (the snapshot carries how far a character has picked, 0 to 1). A pick raises a pick event at the car; the police count it as a crime of 8 Heat when somebody (a pedestrian, an officer) is within 30 m: one pick alone stays under a star. Chasers never walk to a locked car to take it.

On foot, a tag over the car the player looks at (the nearest within 9 m near their aim, or within 3 m) says Locked, Locked · your key or Yours.

Vehicle spawners (parking bays) ​

A level parks cars with the block:vehicle-spawner block (see the Levels guide): a bay on its node's origin, facing its +z, never scaled. Its script's parameters: class (a class name, or several separated by commas: a mix it goes through in turn), owner (nobody or npc), locked (1 or 0), key (the tag its key answers to; key:vehicle:<node name> when empty), respawn (seconds; 0 never). The export lists it under the level's spawners.

The server runs the spawners (startSpawners with the world and after a level reset, spawnerSystem every tick before the step; the clients' prediction worlds never spawn anything): a car stands in every bay; once it is gone (driven more than 8 m off, wrecked, removed), the next is put there respawn seconds later, as soon as the bay is clear (no car in it, nobody standing where the car would). A mission's vehicle actor is its own spawner: a class or a mix (each run of the mission takes the next), an owner, locked or not, a key tag; it does not respawn (it goes with the mission).

Garages ​

A level's garage is the block:garage block: a bay on its node's origin (the middle of its floor), scaled to its width, height and depth, its door at its +z end; its script's respray and store are the prices in dollars, −1 for a service it does not offer. The building around it is placed apart (walls of block:building, or a kit's piece): the garage is a behaviour on a door, not a mesh. A game's rules.garages ({ "respray": 200 }) sets every garage's price over the level's; the welcome carries it to the clients.

At the wheel of a car standing still (under 1 m/s) in a garage's bay, whole, the garage's panel (bottom centre) offers what it does with its price; 1 or a click resprays, 2 or a click stores, each paid out of the player's Cash (the one wallet that missions pay into, the cash picked up counts into and the shops sell for: see Items; a price the player cannot pay says so):

  • Respray: the car takes the next of eight paints (Vehicle.paint, drawn over its livery), is repaired and gets new tyres. The police clear the player's Wanted level, the Heat with it, unless an officer sees them or saw them within the last five seconds (they saw the car go in): resprayClears in @foi/ai's wanted.ts, from the respray event.
  • Store: everyone gets out (the driver where the car stood) and the car is kept for the player in the room (SimWorld.stored: its class, paint and key), gone from the world. Any car but another player's can be stored; a mission's stored vehicle is gone for its mission (vehicle:<id>.stored).
  • Take out: on foot in the empty bay of any garage that stores, with a car stored, the prompt says Take out compact (the last one stored): the car is put in the bay facing out of its door, the player's and open, the player at its wheel.

The stored cars travel to their player in the inventory text frame (class and paint); a level reset forgets them.

Missions ​

  • A vehicle actor gains owner, locked and key, and its class may be a list (a mix); a garage actor binds the level's garage nearest a place (within 6 m).
  • Actions: lockVehicle, unlockVehicle (what an app's Unlock button does), giveKey (the game's item that answers to the vehicle's key tag; the validator wants one defined).
  • Events: vehicle:<id>.unlocked|picked|stored|resprayed, garage:<id>.entered (the player drives or walks into its bay).
  • Objectives: unlock takes a vehicle (done once it is unlocked: its key, a pick, an unlockVehicle); deliver takes a garage as its destination (the vehicle in its bay, the player at its wheel; items handed over there).

See the Missions guide for the whole language; "Repo Season" on test-locks-garages uses all of it.

On the wire and on the server ​

  • The input: interact (the key held, a flag) and service (1 a respray, 2 storing; a byte, one-shot): 16 bytes since the weapon left it (the selected slot says what is held). Neither is predicted.
  • A snapshot's entity: locked (a flag), ownerKind and ownerId, paint (bytes 80 to 83 of 84, after stealth's status and alert), pursuit (a flag: the police's interceptor tune at three stars, see the AI guide); a character's picking share in its boost byte. The cars' key tags travel in their own keys text frame when they change (to every player: the prompt needs them to tell Unlock from Locked). PROTOCOL_VERSION 9.
  • The mirror puts owners, locks, paints and key tags on the cars' twins and the player's stored cars in the local world, so the prompt says what the server will.
  • apps/server: the game server parks the level's cars and runs the spawners; the mission host spawns, locks and unlocks the missions' vehicles, binds their garages and tells the missions what was done to their vehicles (unlocked, picked, resprayed, stored) and who stands in their garages.

Determinism ​

Owners, locks, paints, the picking (ticks and car), every player's stored cars and the spawners' clocks are part of hashSimState; packages/sim/src/determinism.integration.test.ts replays a lock picked, a respray, a car stored and taken out again, and a spawner putting its cars in its bay, in two worlds that must agree on every tick.

Mini level and tests ​

  • test-locks-garages (built from apps/level-editor/assets/kits/test-locks-garages.recipe.json): a street with three locked cars of the level's spawners (bay-1's key lying on the street by it, bay-2's in a crate behind it, bay-3 a compact then a van with a range dummy watching), a garage with a driveway (a respray for $50, storage free), $200 by the spot the player gets out at (into their Cash); its server runs with police. Its game, Repo Season: a locked van, its key given, delivered to the body shop. E2E-160 to E2E-168 (tests/e2e/specs/levels/test-locks-garages/); E2E-169 is the RentaCar's locked car on test-phone.
  • test-city-life: gates and barriers (kinds of the door block that open for a driver carrying what unlocks them, see Items), and a garage whose respray is paid out of the same Cash a shop sells for. E2E-303, E2E-304, E2E-306.
  • Unit tests: packages/sim/src/locks.test.ts, garages.test.ts; packages/world/src/pieces-vehicles.test.ts; packages/ai/src/wanted.test.ts, police.test.ts; packages/missions/src/runtime-locks.test.ts, validate-locks.test.ts; packages/net-client/src/mirror-locks.test.ts; apps/server/src/locks.test.ts; apps/client/src/renderer/locks-view.test.ts.

What comes next ​

Keys carried in NPCs' pockets (with stealth), hot-wiring and alarms, a player locking their own car, a respray's cost by class, and garages modelled as kit pieces with a roller door. (Money is one Cash now: the garages charge the wallet the missions pay into.)