phase 8: Ouroboros boss fight — pattern puzzle with 3 victory paths

First Archon encounter: a cyclical pattern-recognition puzzle.

Boss AI: 4-phase cycle (Coil → Spray → Lash → Digest) with
escalating difficulty (10% faster per cycle, caps at 5 cycles).

Victory paths (all based on real chemistry):
- Chemical: NaOH during Spray phase (acid-base neutralization, 3x dmg)
- Direct: any projectile during Digest vulnerability window
- Catalytic: Hg poison stacks (mercury poisons catalytic sites, reduces
  regen+armor permanently)

New files: src/boss/ (types, ai, victory, arena, factory, reward),
src/data/bosses.json, src/scenes/BossArenaScene.ts, tests/boss.test.ts

Extended: ECS Boss component, CodexEntry 'boss' type, GameScene
triggers arena on Resolution phase completion.

70 new tests (455 total), all passing.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Денис Шкабатур
2026-02-12 16:12:34 +03:00
parent 0d35cdcc73
commit 7d52d749a3
14 changed files with 2429 additions and 4 deletions

View File

@@ -740,8 +740,8 @@ export class GameScene extends Phaser.Scene {
advancePhase(this.runState); // → Crisis
this.triggerCrisis();
} else if (phase === RunPhase.Resolution) {
// Run complete — could transition to a victory scene
// For now, just keep playing
// Resolution phase complete → enter boss arena
this.enterBossArena();
}
}
@@ -842,6 +842,39 @@ export class GameScene extends Phaser.Scene {
}
}
/** Transition to the boss arena (triggered when Resolution phase ends) */
private enterBossArena(): void {
if (this.playerDead) return;
// Prevent re-entry
this.playerDead = true; // Reuse flag to stop updates
// Auto-deposit discoveries before leaving
if (!this.hasDepositedThisRun) {
depositKnowledge(this.meta.mycelium, this.runState);
this.hasDepositedThisRun = true;
}
this.showInteractionFeedback('collected', '⚔ Вход в арену Уробороса...');
// Fade out and transition
this.time.delayedCall(1500, () => {
this.scene.stop('UIScene');
this.cameras.main.fadeOut(1000, 0, 0, 0);
this.cameras.main.once('camerafadeoutcomplete', () => {
this.scene.start('BossArenaScene', {
meta: this.meta,
runState: this.runState,
inventoryItems: this.inventory.getItems(),
quickSlotItems: this.quickSlots.getAll(),
activeSlot: this.quickSlots.activeIndex,
playerHealth: Health.current[this.playerEid] ?? 100,
playerMaxHealth: Health.max[this.playerEid] ?? 100,
});
});
});
}
private showInteractionFeedback(type: string, itemId?: string): void {
let msg = '';
switch (type) {