Safe-Room Ambience
The key words MUST, MUST NOT, SHOULD, and MAY are used as in RFC 2119.
This page governs the ambient creatures and heal pads of the safe rooms — the start (sa1) and goal (ga1) rooms that never carry an enemy wave — plus one boss-arena flourish. It says which rooms get fauna, where the creatures stand, what they are forbidden to touch, and what the goal room's heal pad does.
The rule, from psz-re
The original authors its ambient creatures into exactly the rooms that terminate a section, per the decoded object tables (data/re_reference/room_objects.json, cross-checked against room_reference.json; psz-re data/object_placement_per_room.json, docs/godot-field-parity.md §8):
| Object | Instances | Where |
|---|---|---|
o0c_butterfly | 16 | valley (s01) sa1 + ga1, a+b — 2–8 per room, groups 0 and 4 |
o0c_dragonfly | 8 | wetlands (s02) sa1 + ga1, a+b — 2 per room |
o0c_bird | 1 | paru's boss arena (s05z_na1) — a one-off |
o0c_healhp | 14 | every area's ga1 carries exactly one (s01–s07, a+b) |
So each area's safe rooms carry the area's creature instead of a wave: butterflies are the valley's, dragonflies the wetlands'. s03–s07 author no creatures in the decoded table (snowfield reads as ambient through weather instead) — and psz-godot MUST NOT invent fauna for them. Faithful means the barren areas stay barren; the heal pad, not invented animals, is what those rooms gain.
Placement
- Critters MUST spawn at their authored positions, selected by the same layout-mask draw as every authored kind (key placement documents the shared draw). Valley swarms sit in group 0 — always eligible for a safe room's group table — with group-4 duplicates that never build, exactly as the mask rule intends.
- A start room MUST build authored ambience and MUST NOT build any other authored kind: no wave, no loot, no traps in the room the player spawns into.
- The start room's layout draw comes from a dedicated side stream seeded with the field, so a seed's field MUST populate byte-identically to before ambience existed — adding ambience MUST NOT reshuffle every later cell's rolls.
- A room whose table exists only outside the deploy set still gets its authored fauna: the city start room (
s00e_sa1) authors its two butterflies under setcand has nodrow at all, so it resolves through a cross-set fallback that builds flat, at the authored spots, and draws nothing from the field's streams. The set's other kinds stay unimported — the deploy roll never reads them. The city market is a hand-built scene, not a field cell, so its controller spawns the room's authored ambience directly. - The rule reaches quest-authored start rooms too: the original authors its fauna into
sa1whether the field is free-roam or a quest, and a quest's stage JSON carries its objects verbatim — so at cell entry ansa1whose objects carry no ambience MUST gain its authored fauna, ambience only (no wave, no loot, no traps leak into a hand-authored room). A quest's other rooms stay exactly what its JSON authors. - The near-spawn flair is OURS, and says so (kion's playtest call, a recorded divergence from the faithful rule): butterflies also stand at invented spots chosen for presence — two beside the city spawn, two at each valley start room, two in the valley E corridor, two before the valley boss warp. The authored placements stay where psz-re measured them; the flair is additive, equally stateless, and lives in
FieldPopulation.FLAIRplus the market controller for the city. - The boss arena's bird rides the single-room path, and only ambience does: those rooms stay a fight and a warp.
Inertness
An ambient critter is scenery that moves. It MUST NOT collide, interact, appear on the minimap, join the enemy or box counts, enter the cell save, or wedge the autopilot's nav backbone. There is deliberately no PSZ_AUTOPILOT_NO_* gate for it: nothing about it can obstruct, so there is nothing to gate.
The models are unlit single-frame billboards with no embedded animation — the original animates them in runtime code, and psz-re publishes positions and facings only. The motion is psz-godot's own and deliberately near-stationary (kion's playtest of the original: the butterflies "mostly stuck to one place") — a slight drift around the anchor and a gentle bob, never a path. The quads render as true camera-facing billboards, like the original's JIT sprites — the GLB bind poses are tilted planes that read tipped (or upside down) under any yaw-only facing — so the material carries BILLBOARD_ENABLED and the authored facing is not applied. The wing beat is, for now, a deliberately simple vertical squash — all faces visible, texture untouched — a placeholder by decision after prototyping the real mechanics (the mesh is two crossed quads; pose swaps, UV windows, and hinge folds were all tried) in the Flap Lab, which stays the workbench for the eventual fidelity pass. The quads are ~30 cm tall and centred on their origin, so an authored y of 0 would sink half the billboard under the floor — butterflies and the bird lift their anchor by 1 m, while the dragonflies are authored at 1.5 and keep it. Taste here is ours and labelled as such in ambient_critter.gd.
The goal-room heal pad
Since the goal-room terminal work, ga1 ends every generated a/b section — which is what makes its heal pad worth porting: a pad in every section's terminal, before the next one begins.
- Every generated
ga1MUST carry its heal pad at the authored position, under every layout draw. - The pad restores HP to full and is consumed by that one heal: the states are the storybook's (
unused→used), both frames on the one texture sheet, the state shifting the window ±0.5 offsetX with a 450ms ease so the pad reads as draining. How much the original restores is not measured (psz-re publishes the placement, not the parameter block); the object's own name — heal hp — is the reading, and it heals HP only, not PP. A full-HP step MUST NOT spend the pad. - Nothing about the pad persists — a revisit rebuilds it charged. A per-visit resource, like the original's room.
- Like the critters it is trigger-only — no solid body, nothing to wedge on.