Biomass Wave Spawning + Boss/Elite/Minion Taxonomy — Design
Biomass Wave Spawning + Boss/Elite/Minion Taxonomy — Design
Section titled “Biomass Wave Spawning + Boss/Elite/Minion Taxonomy — Design”Status: draft for review (Phase 1 of the larger feedback batch)
Date: 2026-06-28
Scope: Replace the cycle-22b survival ramp/boss-rotation with a wave-based, biomass-driven
spawner and a Boss → Waves macro loop. Applies to survival + crystal modes (both use the
survival spawner). Story/tutorial unaffected (they use authored encounters, story != null).
Spawning becomes a wave → clear → boss → repeat rhythm with a natural ebb and flow, where the amount of on-screen pressure is a single readable number (“biomass”), and bosses always get a clean arena. This is the canonical fix for the “central cluster + bosses lost in the swarm” feel.
The macro loop (Sim phase machine)
Section titled “The macro loop (Sim phase machine)”A Sim.spawn_phase enum drives everything (survival/crystal only; guarded by story == null):
- WAVES (duration
WAVE_PHASE_S= 300s): waves spawn (see below). - At 300s → WIND_DOWN: no new waves; the player clears whatever’s left.
- When
total_biomass == 0→ BOSS_PREP (10s): show “BOSS APPROACHING” + a countdown. - After 10s → BOSS: spawn one boss into the now-empty arena.
- Boss defeated → REST (10s): show “AREA CLEAR” → back to WAVES (next cycle; endless).
Timers + the current phase are render-readable so the HUD can show wave/boss banners.
Biomass model
Section titled “Biomass model”- Every standard enemy and elite carries a
biomassscore (a newEnemyPoolcolumn, swap-removed in lockstep). Bosses and minions carry 0 (excluded from pressure accounting). Sim.total_biomass()= sum of the column over live enemies. Cheap; computed on each wave check.- Biomass ≈ how much pressure that enemy adds. Proposed starting values (tunable in
bible.json):- swarmer 2 · spider 3 · shooter 4 · splitter 4 · scatterer 6 · zapper 6 · orbiter 8 · lancer 8 · bomber 9 · ghost 10 · pyromancer 10 · elite 12 · brute 16 · accumulator 16
- Elites: Warden 110 · Boss2 100 (high — usually alone in a wave).
BIOMASS_TRIGGER = 100(a wave fires when total drops below this) ·BIOMASS_TARGET = 400(spawn until total ≥ this).
Enemy taxonomy
Section titled “Enemy taxonomy”- Standard enemies — spawn in large waves, low biomass. (The current spawn pool minus zapper/rusher, which stay removed from the normal pool per earlier feedback.)
- Elites (Warden, Boss2 — demoted from bosses) — spawn in waves at hard-coded times, high
biomass, coexist with the wave (do NOT clear the arena). Keep their existing attack patterns. Still
pooled
BEHAVIOR_BOSSentities, but counted as biomass and spawned by the wave system. - Bosses (FunZo, Graviton, Eye now; Giant Zombie added in a follow-up chunk) — spawn only in the BOSS phase, alone, biomass 0. Rotate through the pool per boss cycle.
- Minions — boss-summoned, downgraded standard enemies, low HP, biomass 0 (a per-enemy
minionflag, or biomass set to 0 at summon). Existing boss adds (FunZo jesters, boss-add trickle) become minions.
Wave generation
Section titled “Wave generation”When a wave fires (total_biomass < 100, in the WAVES phase):
- Elites first (non-probabilistic): each elite has a hard-coded spawn time (e.g. Warden @ 90s, Boss2 @ 210s — tunable). If an elite is due this cycle and not yet spawned, it’s added to the wave before anything else.
- Probabilistic fill: sample the time-based probability table (below) and spawn standard enemies
at off-screen ring positions (existing
SPAWN_RING) untiltotal_biomass >= 400, then stop. All in one tick. A “WAVE INCOMING” banner shows.
Probability table
Section titled “Probability table”- A fixed
const SPAWN_TABLE: Arrayof probability vectors, one entry per 30s of run time. Each vector maps enemy-type → weight, summing to 1. Most weights are 0 (only a few types active at once). Authored to keep the mix varied over time (early: swarmer/spider; mid: + shooter/scatterer/ ghost/orbiter; late: + lancer/bomber/accumulator/brute/pyromancer). - For a time
t, lerp between the floor/ceil 30s entries. - Endless: once past the authored table, loop a designated endless segment (the last N entries) so the mix keeps cycling. (Auto-generation deferred — a fixed looping tail is simpler + balanceable.)
- Sampling + spawning is deterministic via
Sim.rng.
UI / text
Section titled “UI / text”A small centered banner (new lightweight HUD element or reuse RegionTitle’s sweep) shows:
- “WAVE INCOMING” when a wave fires.
- “BOSS APPROACHING N” countdown during BOSS_PREP.
- “AREA CLEAR” during REST.
Driven by render-reads of
spawn_phase+ the phase timer (no sim coupling).
Determinism
Section titled “Determinism”The spawner is rewritten, so the survival determinism baseline WILL change — a one-time, honest
re-pin of snapshot_string().hash() + state_checksum() in test_determinism_checksum.gd, noted in
CLAUDE.md. The sim stays deterministic (waves/biomass/boss-gate all flow through Sim.rng; run twice →
identical). The crystal determinism baseline re-pins in lockstep.
Out of scope for Phase 1 (explicit)
Section titled “Out of scope for Phase 1 (explicit)”These are the rest of the batch, done after the spawn system ships + is playtested:
- Giant Zombie boss (promote the Brute) — a new boss + minions. Built right after the spawner so the boss pool is initially FunZo/Graviton/Eye; Giant Zombie joins once built.
- Dash rework (Spider + Accumulator: slower dash, no pause-between, lower frequency → ~1.5× avg speed, less agile).
- Spider-web: much longer duration.
- Passive HP regen (small) + convert stand-still regen into an upgrade.
Open tunables (safe to pick now, tune later)
Section titled “Open tunables (safe to pick now, tune later)”- Exact biomass values,
BIOMASS_TRIGGER/TARGET,WAVE_PHASE_S, prep/rest 10s, elite spawn times, and the full probability table. I’ll author sensible starting values; all live as constants/data.