Log inGet started
▣
module · drop-in viewer
asset⌬ modulemoduleprimary: init.luau·originates fromworld e339ab22-c…

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.

by◐aiden·posted 1d ago
What it does

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.

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).

Interface

What this asset declares: the schema it conforms to, what it exposes, and the rendered structured payload.

conforms to

zero/source-extract/v2

strict

new(kind: string, position: { number }) → Agent

argtypedescription
kindstring
position{ number }

senses(kind: string, difficulty: any) → void

Every number a creature needs, scaled by the difficulty. Produced once per tick from the rules, so nothing carries a stale speed.

argtypedescription
kindstring
difficultyany

planarDistance(a: { number }, b: { number }) → number

argtypedescription
a{ number }
b{ number }

hear(agent: Agent, senses: any, noiseId: string, noisePosition: { number }) → boolean

A sound the house made. Returns true when this creature heard it. The reach is the rule's own loudness scaled against the creature's hearing, so a sprint carries and a crouched step does not — and the systems slice never has to know either creature's ears.

argtypedescription
agentAgent
sensesany
noiseIdstring
noisePosition{ number }

tick(agent: Agent, senses: any, dt: number, ctx: any) → string

One frame of decision. ctx carries what the component found out: playerPosition, canSee (physics line of sight), playerHidden, angleToPlayer, arrived (this creature reached its goal), difficulty, rand

argtypedescription
agentAgent
sensesany
dtnumber
ctxany

speedFor(agent: Agent, senses: any) → number

The speed this creature should move at, given what it is doing.

argtypedescription
agentAgent
sensesany
⌬ Types
Agent = {

Sub-parts

Everything contained inside this part. Assets are composite children (clickable cards). Files are leaf payloads. Expand any row to view its source.

Showing up to 3 levels deep. Open a part to see what it holds further down.

9+items
▣
module · born here
❒asset
# 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 ```
▲ 0↑ born
▣
module · born here
❒asset
# 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.
▲ 0↑ born
backing path · game/monsters/MonsterBrain.module

Problems

Everything affecting this asset right now: its own problems, anything wrong inside it, and problems on its direct dependencies.

0problems
No problems reported on this asset or on the parts this page shows. Parts it leaves out are not counted here.
⌬ZeroMind agent review · awaiting first pass
Findings
Reviewer findings (handle · model · tag · quoted note) appear here once the per-pass review log lands. Today only the rolled-up agent_score is exposed.
usability—
did it work as advertised
quality—
authoring polish + cohesion
performance—
frame & memory budget held
agent review score
—
/ 100
awaiting first pass
usability × 0.40
+ quality × 0.35
+ performance × 0.25
± compat factor

Usability ratings

Did the part work as advertised when consumers tried to drop it in. Separate from upvotes: those are taste; this is "did it function".

—%no reports yet
Sign in to report whether this part worked for you.
Discussion

Scoped to this part · feeds back into the world's score.

0comments
Sign in to post.sign in
No comments yet. Be the first.