Enemy Placement
The key words MUST, MUST NOT, SHOULD, and MAY are used as in RFC 2119.
This page governs where a wave's enemies stand. It does not govern which enemies a wave contains — that is the wave template roll, unchanged by this page.
The rule
Every room model in the original has authored spawn slots: 8 or 9 fixed positions per room, 2177 across 257 rooms, decoded by psz-re from enemy_deploy_positions.json. A wave's enemies MUST be placed on those slots.
psz-godot previously ringed enemies at a fixed radius of 5.0 around the cell centre. That is refuted: it ignores the room's geometry entirely, which is why enemies stand on rocks and why a wave can straddle a void (#604). A ring is a shape, not a placement.
| Case | Behaviour |
|---|---|
| Room code has authored slots | Enemies MUST be placed on slots, chosen as below. |
| Wave is smaller than the slot count | A subset MUST be chosen, seeded from the run's RNG so a given field always populates identically. |
| Wave is larger than the slot count | Slots MUST be reused rather than the wave truncated. Slots are known to be reused across waves in the original: a room with 8 slots produced 11 enemies over 3 waves. |
| Room code has no authored slots | Fall back to the ring. This is a fallback for a room code invented later, not a placement policy. |
Slots are positions, not a wave count
A room's slot count MUST NOT be read as the number of enemies in a wave, nor as a per-room total. Measured against the original: a room with 8 slots produced three waves of 4, 3 and 4 enemies — 11 in total. Slots are the positions available to each wave, and the same slot may be used by a later wave.
Coordinates
Slots are room-local, in the same units and orientation as authored objects, with y the floor height at that point. psz-re's source orders each record (x, z, elevation) rather than (x, y, z); the importer converts on read, so consumers see {x, y, z} and MUST NOT re-order.
What this page does not settle
Which subset of slots the original picks for a given wave is not known. The original derives room contents from a per-room RNG seed (record +0x14, confirmed by psz-re as a full-range RNG draw), and the weights that drive placement are still unidentified — psz-re's own note names default_parameters.bytes_4_to_8 as the best candidate. Until those are decoded, the subset here is our own seeded choice and is not claimed to match the original's. The positions are authored data and are exact; the selection among them is ours.