# game.monsters.Swarm
The baby spiders, as rules. No entities and no input — the event's arithmetic, on its own.
**The first one teaches.** Every later swarm is a scramble; the first runs the world at a
fifth speed, gives twice the time and hurts a quarter as much, because a player who has
never been told which key to press must not die learning it.
```lua
local state = Swarm.new(now, tutorial)
Swarm.press(state) -- one press of E; true when it counted
Swarm.tick(state, dt) -- real seconds -> "ongoing" | "cleared" | "failed"
Swarm.damagePerSecond(state)
Swarm.prompt(state), Swarm.counter(state), Swarm.spidersLeft(state)
```
The clock runs on **real** seconds, so a slow-motion swarm is never given more wall-clock
time than a normal one — the slowdown exists to give the player time to read, not to give
the swarm time to bite.
Numbers come from `GameRules.SPIDERS`: five presses, six seconds, the prompts, the
cooldown, the damage.
# game.Bus
The one table the game's parts talk over. **Every slice announces what happened
and listens for what it cares about; no slice requires another**, and this is
the table in the middle they share.
```lua
local Bus = require("game.Bus")
Bus.emit(Bus.E.noise, { id = "sprint", position = p, source = "player" })
local handle = Bus.on(Bus.E.playerCaught, function(payload)
print(payload.monster) -- "resident"
end)
Bus.off(Bus.E.playerCaught, handle)
```
`Bus.E` is the event-name list, spelled once so no slice can invent a string
nobody else listens for. It is the same set as `GameRules.EVENTS`, which also
documents the payload each event carries; the scene entrypoint checks the two
agree on every load and warns if they have drifted.
`on`, `once`, `off`, `emit`, `count`, `clear`, plus `error()` and `clearError()`
for the last handler failure.
## Two rules, because getting them wrong desynchronises a co-op run
1. **The bus is local.** It is a module, and a module is one instance *per
peer*. An emit reaches the parts of the game running on this machine and
nowhere else. Anything another player must agree about — a door, a key, the
objective list, the monster — is written to the **shared store**
(`runtime_data.world`, under the keys in `GameRules.DATA`) and read back by
every peer. Emit the local *response* to a thing; store the *fact* of it.
A part that emits `doorOpened` and never writes the store has a door that
opens for one player and stays shut for everyone else.
2. **An emit is synchronous.** Handlers run before `emit` returns, in
subscription order, on the frame the thing happened. The payload table is
handed out, not copied — read it, do not keep it, do not mutate it. A handler
that throws is caught and reported, so one broken listener cannot silence
every other listener on the same event; `Bus.error()` reads the last one back.
Who calls it: every slice. The house emits doors and pickups, the monsters emit
their state and a sighting, the survival systems emit noise, damage and clues,
the interface listens to most of it, and the audio director listens to nearly
all of it.
# game.monsters.MonsterBrain
What a creature decides, frame by frame. **Policy only** — it reads what the world told
it and writes a destination. It never touches an entity, a path or a raycast; the
`Creature` component does the engine's half and hands the answers in.
The states are the game: `patrol`, `investigate`, `chase`, `search`, `attack`, `recover`.
On every difficulty a creature runs exactly this logic — difficulty moves only how far it
sees, how far it hears and how long it looks before giving up.
**It never knows where the player is.** It knows where the player *was* — a sighting, or
a sound it heard. That is the difference between a hunter and a cheat.
```lua
local agent = Brain.new("resident", position)
Brain.hear(agent, senses, "sprint", noisePosition) -- true when it heard it
local state = Brain.tick(agent, senses, dt, ctx) -- ctx carries what the component saw
Brain.speedFor(agent, senses)
```
`ctx` is the component's half: `playerPosition`, `canSee` (physics line of sight),
`playerHidden`, `angleToPlayer`, `arrived`, `difficulty`, `rand`. `agent.pending` comes
back with what happened this frame (`spotted`, `attack`, `lostSight`, `gaveUp`).
# game.monsters.NavGraph
How a creature finds its way through the house.
**The graph is the house.** Nodes are the twelve areas and the doorways between them;
edges are the doorways and the stairways. So a creature routes the way a person does —
room, doorway, room — and it uses the same doors the player uses.
A doorway is a **node**, not just an edge, so a creature walks *to* the door and then
*through* it rather than straight at a wall corner.
Why not a voxel grid: a grid over a two-storey house is thousands of nodes built from
raycasts, and it would have to be rebuilt whenever a door moved. The room graph is about
thirty nodes, comes free from the plan the house is already built from, and **cannot
disagree with the geometry, because it is that plan**.
```lua
local NavGraph = require("game.monsters.NavGraph")
local points, status = NavGraph.route(from, to) -- plain world points, first to last
local spot = NavGraph.randomRoom(rand) -- somewhere to wander to
local rooms = NavGraph.roomsNear(point, 4) -- the rooms a searcher checks first
```
# game.GameRules
The constants and rules of **The House That Knows You** — the one module every
part of the game reads, so two systems written in different sessions agree on
what a room is called, how loud a sprint is, how long a torch battery lasts and
which ending the player earned.
It holds **no behaviour and no entities**: pure data plus a handful of pure
functions. Require it and read it; never write to it.
```lua
local RULES = require("game.GameRules")
```
## What is in it
- **`ART_DIRECTION`** — the one sentence every generation prompt reuses word for
word, and **`REFERENCES`** — the pictures the game is judged against.
- **`PALETTE`** — that sentence as numbers, for the interface and for materials.
- **`HOUSE`** — the wall height, the wall thickness, the doorway size, the room
module, the storey height and the player's own dimensions. Every prop in the
game is sized against these.
- **`AREAS`** / **`AREA_BY_ID`** — the twelve areas, each with its floor, its
nominal centre on the ground plan and the item that unlocks it.
- **`OBJECTIVES`** — the twelve-step chain, in order, each naming the area it
happens in and the item it needs.
- **`ITEMS`**, **`REQUIRED_CLUES`**, **`CLUE_COUNT_FOR_TRUTH`** — what can be
picked up, and what the ending is decided on.
- **`ENDINGS`** and **`selectEnding(cluesFound, secretRoomOpened)`** — the three
endings and the rule that picks one, stated once so the interface and the
systems cannot disagree.
- **`SURVIVAL`** — speeds, stamina, health, torch battery, interaction ranges.
- **`DIFFICULTY`** — easy, normal, nightmare. These change the monster's
persistence, reach and the supply density **only**; all three run the same
monster logic.
- **`MONSTERS`** and **`MONSTER_STATES`** — THE RESIDENT and THE BROODMOTHER,
and the states both run: patrol, investigate, chase, search, attack, recover.
- **`NOISE`** — the interface between what a player *does* and what a monster
*hears*. A system emits a noise id; the monster AI turns it into a reach.
Nothing else may write a raw radius.
- **`SPIDERS`** — the baby-spider event: five presses, six seconds, the
slow-motion tutorial, the prompts, the damage.
- **`ENDLESS`** / **`endlessDifficultyFor(floor)`** — Endless Nightmare, and a
floor number that never stops climbing.
- **`MODES`**, **`MAX_PLAYERS`**, **`DATA`** — the game modes and the keys shared
state lives under.
## Who calls it
Every slice: the house builder, both monsters, the survival systems, the
interface and the audio director. Every component that runs in play reads its
numbers from here rather than carrying its own copy.