Enemy Waves
The key words MUST, MUST NOT, SHOULD, and MAY are used as in RFC 2119.
This page governs how many waves a room runs and when each arrives. It does not govern which enemies a wave contains (the wave-template roll — see Free Field) nor where they stand (the slot placement — see Enemy Placement). Those three are independent: a room picks a count of waves here, draws a template for each on the Free Field page, and places each template's enemies on the Enemy Placement page.
A room runs several waves, not one
A room in the original clears in 1–3 waves, run in sequence. This is measured: a room with 8 slots was observed producing three waves of 4, 3 and 4 enemies — 11 in total (see Enemy Placement, slot reuse). A port that spawns a single wave per room is refuted: it fights one of the room's several fights and calls the room clear.
The wave count is a per-room min/max, rolled per instance
Each room's deploy record carries a wave-count pair. psz-re decoded the per-room table as 20-byte records {roomCodePtr, listPtr, count, w3, w4}: w3 is the minimum wave count and w4 the maximum. For a given field instance, a room MUST run a number of waves in the inclusive range [w3, w4]. The count is a draw from the room's own per-room RNG seed (record +0x14, confirmed by psz-re as a full-range RNG draw — the same seed that drives slot selection), so it MUST be deterministic for a given field and MUST NOT be re-rolled on re-entry.
Example (psz-re enemy_room_assignment, set d): s01a_ib1 carries w3 = 2, w4 = 3 — two or three waves. The pair varies by room type, which is why a field shows anywhere from one to three waves per room.
The exact distribution within [w3, w4] is the seeded draw and is not claimed to match the original's bit-for-bit until the draw is decoded; only the bound [w3, w4] is normative.
Each wave is its own draw
A room's N waves are not one template repeated. Each wave MUST independently draw a template from the room's weighted pool (the roll defined on the Free Field page), so a three-wave room makes three draws and may see three different templates. The pool is the same for every wave of a room; only the draw is per-wave.
Later waves wait for the player
A room's waves MUST NOT all spawn at once. The first wave spawns on room entry; each subsequent wave is gated and arrives only after the previous wave is cleared. psz-re's note that "a room runs several waves and some of them WAIT FOR YOU" identifies the deploy record's optional ninth slot as a trigger volume — the region whose entry releases the next wave. Where a room carries that trigger, the next wave SHOULD release on the trigger rather than on clear; where the exact trigger is not decoded, releasing on clear is the accepted approximation.
Rooms with no waves
The start and goal rooms carry no waves (their assignment is empty; equivalently w4 = 0) and MUST spawn nothing — consistent with Free Field. A room whose assignment is empty is not a bug to fill in; it is authored to be quiet.
What the port owes
Two gaps, both concrete:
- Data.
data/re_reference/enemy_room_assignment.jsoncurrently keeps only{template, weight}per room; it MUST carry the per-roomw3/w4pair (and the per-entryfield3) re-imported from psz-re, or there is no wave-count data to roll against. - Runtime.
FieldPopulation.roll_waveis singular — one draw per room. It MUST become a count-driven loop: roll a count in[w3, w4]from the room seed, then draw and deploy that many waves, gating the later ones per the trigger rule above.
Tests
Per the two-layer rule, this behavior is verified at both layers:
- A seeded
test_runnerunit test: a room's wave count lands in[w3, w4]; the count is stable for a fixed field seed; each wave is an independent draw from the pool; start/goal rooms produce zero waves. - An autopilot probe: a field run actually fights more than one wave in a multi-wave room (a single-wave clear is the regression this guards).