engine/destructibles

PURPOSE — Runtime lifecycle for boss-arena terrain: materializes a pattern’s pillars and hazard zones into the live world at encounter start, removes them at encounter end, applies damage and death state to pillars, ticks hazard-zone overlap damage against the ship, and reaps dead pillars after their death effects play.

OWNS

  • Boss-terrain pillar entries (position, radius, current HP, max HP, alive flag, boss-terrain tag, kind discriminator).
  • Boss-terrain hazard-zone entries (position, radius, damage-per-second, wall-clock pulse phase, boss-terrain tag, kind discriminator).
  • The boss-terrain tag (_isBossTerrain) used to distinguish this module’s entries from other entries that may share the destructibles array.
  • Pillar HP bookkeeping and the alive → dead transition.
  • Hazard-zone pulse-phase accumulator advanced each tick.

READS FROM

  • data/terrain-patterns for the pattern registry, per-pattern destructible specs, and per-pattern hazard-zone specs (radius, HP, damage-per-second, position-resolver callbacks).
  • engine/boss/arena for the arena reference passed to each spec’s position-resolver callback.
  • The host world’s destructibles array (read for cull / reap sweeps, read for hazard-zone iteration each tick).

PUSHES TO

  • The host world’s destructibles array — appends pillars and hazard zones on apply, splice-removes on cull and reap.
  • Caller-supplied damage callback — invoked from the hazard tick with the per-frame overlap damage amount; the caller decides which ship-damage path it lands on.

DOES NOT

  • Resolve bullet, contact, or AOE damage onto pillars — callers route hits through the damage entry point with a pre-resolved amount.
  • Render pillars, hazard zones, telegraphs, or pulse halos — only writes the state the renderer reads.
  • Decide which terrain pattern an encounter uses, define the pattern set, or compute per-pattern positions — those live in data/terrain-patterns and the boss-encounter layer.
  • Schedule pattern apply or cull — the boss-encounter layer drives the lifecycle.
  • Run hazard-zone overlap on entities other than the ship.
  • Award score, drops, or upgrade rolls when a pillar dies.
  • Play death VFX, audio, or screen shake when a pillar dies — the cleanup pass assumes those have already happened upstream.
  • Pool or recycle entries — apply allocates fresh, cull and reap discard.

Signals fired / Signals watched — none. The module is driven by direct function calls from the boss-encounter layer and the main update loop, and pushes damage back through a caller-supplied callback.

Entry points

  • applyTerrainPattern — materializes the pattern’s pillars and hazard zones into the world; culls any leftover boss-terrain entries first; no-op for empty patterns.
  • cullTerrainPattern — sweeps every boss-terrain-tagged entry out of the world’s destructibles array; safe when no pattern is active.
  • damageBossPillar — applies an amount of damage to a pillar, flips it to dead when HP hits zero, returns whether this call killed it.
  • tickHazardZones — per-frame: advances each hazard zone’s pulse phase, tests ship overlap, and routes per-frame damage through the supplied callback.
  • reapDeadBossPillars — splice-removes pillars whose alive flag is false; meant to run after death effects.

Pattern notes

  • Pillars and hazard zones share the host’s destructibles array and are distinguished from other entries by the _isBossTerrain tag and from each other by a kind discriminator. Cull and reap walk the array and filter by tag.
  • Apply is idempotent by construction: it culls existing boss-terrain entries before pushing the new pattern, so callers don’t need to track previous state.
  • Cull and reap both use swap-with-last-then-pop while iterating in reverse — entry order is not preserved.
  • The hazard tick takes a caller-supplied damage callback rather than knowing about the ship-damage path itself, keeping the module decoupled from combat resolution.
  • The host-world contract is intentionally narrow (only the destructibles array) so tests can pass a stripped-down stand-in without standing up a full world state.
  • Hazard-zone pulse phase advances on the same dt passed to the tick; the renderer reads it for visual pulsing but the module makes no assumption about which clock (wall vs. game) the caller uses.
  • Pillar death is a two-step lifecycle: the damage entry point flips the alive flag in place, and a separate reap pass removes the entry later — mid-frame death is safe.