Boss Behavior (DRAFT)

The key words MUST, MUST NOT, REQUIRED, SHOULD, MAY, and OPTIONAL below are used as in RFC 2119.

Status: DRAFT. The shared contract below (schema, timeline reuse, anchor semantics) is normative now — it is what the tooling and data are built against. The per-boss tables are first drafts read off the rig clip vocabularies (#/boss-room, #493) and MUST be verified by observation — in the boss rooms and against original-game capture — before any Godot implementation starts. Unverified clip readings are marked in the data's clip_notes / note fields. Godot work on a boss MUST NOT begin while its table still carries unresolved readings for the attacks being implemented.

Why bosses are not enemy-room archetypes

Per /mechanics/enemy-attacks, bosses are out of scope for the flat enemy sandbox: each of the five vocabularies is unique, and the behavior is arena-bound — fly passes, surfacing pools, relocation spots are positions in the boss's own stage. The observation tool is #/boss-room (one room per boss, loaded inside its arena); the data is data/boss_arenas.json (schema_version: 2).

Shared contract

Data model (boss_arenas.json v2)

FieldSemantics
phases[]Ordered; the first phase is the opener. hp_frac on a phase means it is entered when the boss's HP fraction drops to that value; a phase without hp_frac has a per-boss trigger (documented in its note — timer, attack-string completion, break threshold). A phase MAY be a modifier overlay rather than a moveset switch: speed_mult / cooldown_mult apply from entry onward (Reyburn's enrage).
attacks[]Reuses the enemy attack model: unset numeric fields (weight, ranges, window fractions, hit shape, damage_mult) default per that spec's defaults. phases gates availability (omitted = all phases); selection within a phase follows the enemy rules (range bands, weighted random). Boss-only attack fields: knockback (a hit also shoves the player that many units along the boss's facing — Reyburn's wing flap), lp_loops (repeat count for lp chain tokens; for projectile attacks one shot fires per rep — the fireball volley), split (a lob payload splits into this many impact points around the target).
attacks[].chainExplicit clip-token sequence — the generalization of the enemy model's windup_clips. Tokens resolve per the enemy clip-resolution order (exact, then *_<token> suffix); tokens ending in lp loop. Every clip before the last is pure telegraph; the timeline fractions (windup_frac / damage_end_frac) apply to the final clip of the chain.
anchors[]Named positions in the boss's default arena frame (meaningless elsewhere), authored with the room's click tool and round-tripped via its config export. Relocation targets and anchor-bound attacks (attacks[].anchor) reference them by name.
spawn_posAuthored boss position in the default arena frame — trusted verbatim including y, because the spot may be off the walkable collider (Humilias stands at the broken stage edge and attacks into the field). Authored in the room: move boss click → the config export captures the current position. Omitted = the room settles the boss at the collider center.
parts[].instances[]Placed copies of a multi-part rig piece in the boss's local frame (+z = facing): pos plus yaw_deg/pitch_deg. A part MAY set animated: false — the piece never mirrors the body's clips and holds its wrapper/curve pose while only the boss body animates (the octopus tentacles); default true (Humilias's faces play in sync). A tube-rigged instance (the octopus tentacles — flat sibling bones evenly spaced along local +X, clips pose bones absolutely) MAY instead carry curve: ≥2 control points in the boss's local frame, authored with the room's spline poser (#508). When curve is set it — not pos/yaw_deg — places the piece: the runtime MUST fit a Catmull-Rom through the points and pose each bone at its rest arc-offset along the fit (arc-length parameterized; past the curve's end the pose extrapolates straight along the end tangent so the tube never stretches or bunches), keep the bone's rest lateral offset in the tangent frame (the z_002_st tip prongs), and align bone +X to the tangent. A playing clip MAY overlay the curve: the clip's bone positions are read as (arc, lateral) curvilinear coordinates and re-mapped onto the authored curve, so the rig's wave animation rides the authored bend. The Godot implementation reads the same data.
clip_notesDocumentational clip semantics (MAY), same as the enemy schema — the draft's observation notebook. Unverified readings say so.
stats / fsmDraft sim tuning (hp, move/turn speed, attack cooldown, flight cadence, punish break/multiplier) driving the room's behavior simweb/src/boss-room/sim.ts, the runnable form of these tables (attack selection and the melee arc are imported from the enemy room's normative fsm.ts). Sim numbers are tuning draft, not observed truth; they harden through the same workflow below.

Attack kinds

Boss attacks reuse the enemy kinds (melee_arc, projectile, lob, charge, leap) and add the boss-only kinds below. The additions extend — and MUST NOT alter — the enemy set:

KindDraft semantics
beam_sweepA sustained beam/breath swept across an angle while the release clip plays (Reyburn's fire breath, Humilias's laser). Damage is continuous inside the sweep during the window — not a one-shot arc test.
aoe_burstRadial burst centered on the boss at the window open (Dark Falz's radiate).
grabOn connect, the target is held and takes the attack's damage over the hold; damaging the boss past a threshold cancels it (Octo Diablo's absorb→eat, whose rig carries explicit *cnc cancel clips).
fly_passAn airborne strafing run along an anchor path (Reyburn). Anchor-bound by definition.
spoutAn aimed sustained jet from a fixed emplacement/surfacing spot (Octo Diablo). Like beam_sweep but position-locked rather than angle-swept.
healSelf-restore at the window open (Chaos Sorcerer's green gem): heals damage_mult×maxHP.
evadeA no-damage disengage — the boss leaps AWAY from its locked facing during the telegraph (Sinow Beat's backstep).
cloneSpawns split decoy copies of the boss in a ring around the player (fsm.clone_ring_radius). The decoys deal no damage, dispel when hit, and clear when the real boss's next melee_arc lands or it takes a hit (Sinow Beat's transform).
trapDeploys split floor traps scattered within hit_reach of the player. Stepping on one (player, or the boss itself when fsm.self_trap) discharges the attack's freeze Zonde: damage + a fixed-duration freeze (Sinow Beat's Zonde traps).

Boss-only attack fields on top of these: freeze — a hit (a trap, a Zonde projectile, or the post leap) also FREEZES the target in place for that many seconds (Sinow Beat's Zonde). A boss's fsm may set relocate_kind: post (Sinow Beat) — the RELOCATE cycle is a hop onto an authored perimeter-post anchor (fsm.post_height), a brief perch, then a leap-down onto the player with the leap attack.

Breathing room (post-attack disengage)

After an attack resolves the boss MUST disengage — a loafing walk away from the player on a slowly curving path (fsm.loaf_duration_min/max seconds, the enemy model's LOAFING) — before it re-engages. This is the fairness contract: a boss that re-acquires the player immediately after every attack pins them permanently (a downed player could never stand up). Aggression modifiers scale it: an enrage phase's cooldown_mult shortens the disengage along with the cooldown, so "more aggressive" compresses the breathing room without removing it.

Punish windows

Every boss fight MUST expose deliberate vulnerability windows — that is the genre contract. The draft recognizes two shapes, both visible in the rigs:

Per-boss drafts

Numbers live in data/boss_arenas.json — these sections describe the fight shape and flag what is unverified.

Reyburn (boss_dragon — Gurhacia Valley, claiming_a_stake)

Observed patterns (from the real fight — these supersede the earlier clip-derived guesses and are what the table encodes):

Sim'd end-to-end in #/boss-room/reyburn: intro roar → grounded chase/attack from the bands → timer-driven flight cycle → enrage → death, with the J-swing driving HP so every transition is observable.

Octo Diablo (boss_octopus — Ozette Wetlands, poisoned_water)

A different fight shape from Reyburn: a rooted surfacing emplacement (fsm.stationary) that relocates by submerging. The cycle:

Humilias (boss_mother — Dark Shrine A, control_system)

Chaos Mobius (boss_robot — Arca Plant, heretic)

Heaven's Mother (composite — Eternal Tower summit, s087_na1)

Sinow Beat (Paru — Oblivion City, s05z_na1)

The Paru boss room now runs the real PSZ mission extractionshinowa (roster sinow_beat, model_scale 2.0) — replacing the earlier PSO Sinow stand-in (#516). It is a full animation set (tht, wlk, wat/wat2, backstep, atk, atk2, transform, dmg, ded), so it needs no stand-in caveats. The rare sinow_gold palette-swap shares the encounter and is a later tinted-variant follow-up (no separate room). The fight is enhanced above field PSO/PSZ behavior (#516):

PSO stand-in boss — Chaos Sorcerer (Makara)

The Makara arena has no usable PSZ boss rig, so we substitute a PSO asset (per Kion). The rig is ~25–30 units tall; a uniform 0.09 scale is baked into the geometry once (positions, inverse bind matrices, node translations, and animation translation tracks) so it ships pre-sized (~2.3–2.7 m) with identity transforms — no runtime scale to reconcile between three.js and Godot. Textures are embedded, so the GLB is self-contained. Its rig lives on R2 but not yet in the game pack (pack_pending), so the boss room loads it while the pack publish + Godot .tres follow.

Enemy-arena boss room — Snowfield

The Rioh Snowfield arena (s03z_na1) is a pack fight, not a unique boss: it spawns a Hildegao pack. It needs no boss_arenas.json entry — regular enemy spawns in the arena cell cover it, via debug_boss_snowfield.

Dark Falz (boss_darkfalz — Dark Shrine B, dark_castle)

Debug missions (the in-game instrument)

Each boss arena has a debug missiondebug_boss_<id> in data/quests/ — that warps the player straight into the boss cell. They are always unlocked (no parent_quest, never disabled), sit at the end of the guild-counter list with a DEBUG: name prefix, and award nothing (empty rewards). They deliberately ship in beta builds: zero-friction boss testing on real hardware. Remove them from data/quests/manifest.json for a real release.

Draft → normative workflow

  1. Observe in #/boss-room (attack buttons play the drafted chains; anchors are authored with the click tool and round-tripped via the config export) and against original-game capture.
  2. Correct data/boss_arenas.json; resolve or strike each "open" item above.
  3. Lift this page's DRAFT marker per boss — only then does the Godot implementation for that boss start, with the two test layers (seeded test_runner unit test + autopilot probe on the boss's quest) pinned against these tables.

Implemented by

← States