Release v0.1.7 2026-07-12
This commit is contained in:
@@ -5,6 +5,7 @@ import { BOSS_DEFINITIONS } from "../game/bossCatalog";
|
||||
import { bossRoomFor } from "../game/bossRooms";
|
||||
import { tankAuraProtects } from "../game/partyCombat";
|
||||
import { BuffDraftPanel } from "./BuffDraftPanel";
|
||||
import { DEFAULT_CONTROLLER_GLYPHS } from "../input/controllerGlyphs";
|
||||
|
||||
const GameScene = lazy(() => import("./GameScene").then((module) => ({ default: module.GameScene })));
|
||||
|
||||
@@ -109,6 +110,9 @@ function EncounterCallout() {
|
||||
function PhaseOverlay() {
|
||||
const phase = useGameStore((state) => state.phase);
|
||||
const runMode = useGameStore((state) => state.runMode);
|
||||
const round = useGameStore((state) => state.round);
|
||||
const endlessMode = useGameStore((state) => state.endlessMode);
|
||||
const endlessBossKills = useGameStore((state) => state.endlessBossKills);
|
||||
const primaryBoss = useGameStore((state) => state.boss);
|
||||
const additionalBosses = useGameStore((state) => state.additionalBosses);
|
||||
if (phase === "intermission") return <BuffDraftPanel className="top-buff-draft" />;
|
||||
@@ -116,6 +120,8 @@ function PhaseOverlay() {
|
||||
const definitions = bosses.map((boss) => BOSS_DEFINITIONS[boss.id]);
|
||||
const room = bossRoomFor(primaryBoss.id);
|
||||
const bossNames = bosses.map((boss) => boss.name).join(" & ");
|
||||
const showEndlessChoice = phase === "victory" && runMode === "rogue-trials" && round === 5 && !endlessMode;
|
||||
const endlessDefeat = phase === "defeat" && endlessMode;
|
||||
const briefingMode = runMode === "rogue-trials"
|
||||
? bosses.length === 3 ? "Rogue Trials · Trio Finale" : "Rogue Trials · Dual Round"
|
||||
: bosses.length > 1 ? "Roguelike PVE · Dual Encounter" : definitions[0].trial;
|
||||
@@ -123,25 +129,25 @@ function PhaseOverlay() {
|
||||
const title = phase === "briefing"
|
||||
? room.name
|
||||
: phase === "victory"
|
||||
? `${bossNames} Broken`
|
||||
: "Party Broken";
|
||||
? showEndlessChoice ? "Rogue Trials Cleared" : `${bossNames} Broken`
|
||||
: endlessDefeat ? "Endless Run Ended" : "Party Broken";
|
||||
const eyebrow = phase === "briefing"
|
||||
? `${briefingMode} · ${room.biome}`
|
||||
: phase === "victory"
|
||||
? "Encounter Complete"
|
||||
: "Encounter Failed";
|
||||
? showEndlessChoice ? "Endless Path Unlocked" : "Encounter Complete"
|
||||
: endlessDefeat ? `${endlessBossKills} Endless Bosses Defeated` : "Encounter Failed";
|
||||
const copy = phase === "briefing"
|
||||
? definitions.map((boss) => boss.briefing).join(" ")
|
||||
: phase === "victory"
|
||||
? "Five entered. Five endured."
|
||||
: definitions.map((boss) => boss.failure).join(" ");
|
||||
? showEndlessChoice ? "Leave with the clear, or continue against an unbroken chain of replacement bosses." : "Five entered. Five endured."
|
||||
: endlessDefeat ? `Run record: ${endlessBossKills} bosses defeated after the trio finale.` : definitions.map((boss) => boss.failure).join(" ");
|
||||
return (
|
||||
<div className={`phase-overlay phase-${phase}`}>
|
||||
<div className="phase-sigil">✦</div>
|
||||
<span>{eyebrow}</span>
|
||||
<h1>{title}</h1>
|
||||
<p>{copy}</p>
|
||||
<small>{phase === "briefing" ? "Begin from lower display" : "Restart from lower display"}</small>
|
||||
<small>{phase === "briefing" ? "Begin from lower display" : showEndlessChoice ? "Choose Continue or Quit on lower display" : "Restart from lower display"}</small>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -168,15 +174,15 @@ function PauseOverlay({ onExit }: { onExit?: () => void }) {
|
||||
onFocus={() => setPauseSelection("resume")}
|
||||
onPointerEnter={() => setPauseSelection("resume")}
|
||||
onClick={() => setPaused(false)}
|
||||
>Resume <small>START / ESC</small></button>
|
||||
>Resume <small>{DEFAULT_CONTROLLER_GLYPHS.start} / ESC</small></button>
|
||||
<button
|
||||
className={`secondary ${selection === "exit" ? "is-controller-focused" : ""}`}
|
||||
onFocus={() => setPauseSelection("exit")}
|
||||
onPointerEnter={() => setPauseSelection("exit")}
|
||||
onClick={exit}
|
||||
>Return to main menu <small>A</small></button>
|
||||
>Return to main menu <small>{DEFAULT_CONTROLLER_GLYPHS.confirm}</small></button>
|
||||
</div>
|
||||
<footer><b>↑ / ↓</b> Choose <i /> <b>A / ENTER</b> Confirm</footer>
|
||||
<footer><b>↑ / ↓</b> Choose <i /> <b>{DEFAULT_CONTROLLER_GLYPHS.confirm} / ENTER</b> Confirm</footer>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -187,6 +193,8 @@ export function TopScreen({ onExit }: { onExit?: () => void }) {
|
||||
const bossCount = useGameStore((state) => state.additionalBosses.length + 1);
|
||||
const round = useGameStore((state) => state.round);
|
||||
const runMode = useGameStore((state) => state.runMode);
|
||||
const endlessMode = useGameStore((state) => state.endlessMode);
|
||||
const endlessBossKills = useGameStore((state) => state.endlessBossKills);
|
||||
const setPaused = useGameStore((state) => state.setPaused);
|
||||
return (
|
||||
<section className="display top-display" aria-label="Main game viewport">
|
||||
@@ -197,11 +205,11 @@ export function TopScreen({ onExit }: { onExit?: () => void }) {
|
||||
<div className="top-hud">
|
||||
<CompactParty />
|
||||
<BossBar />
|
||||
<div className="objective-chip"><span>{runMode !== "encounter" ? `Round ${round}` : "Objective"}</span><strong>{bossCount === 3 ? "Defeat trio · keep five alive" : bossCount === 2 ? "Defeat both · keep five alive" : "Keep all five alive"}</strong></div>
|
||||
<div className="objective-chip"><span>{endlessMode ? `Endless · ${endlessBossKills} kills` : runMode !== "encounter" ? `Round ${round}` : "Objective"}</span><strong>{endlessMode ? "Defeat bosses · replacements incoming" : bossCount === 3 ? "Defeat trio · keep five alive" : bossCount === 2 ? "Defeat both · keep five alive" : "Keep all five alive"}</strong></div>
|
||||
<EncounterCallout />
|
||||
<CastingBar />
|
||||
<div className="control-hint"><b>WASD</b> Move <i /> <b>Q / E</b> Target <i /> <b>1–6</b> Cast</div>
|
||||
{onExit && <button className="game-menu-button" onClick={() => phase === "combat" ? setPaused(true) : onExit()}><b>☰</b> Menu <small>START / ESC</small></button>}
|
||||
{onExit && <button className="game-menu-button" onClick={() => phase === "combat" ? setPaused(true) : onExit()}><b>☰</b> Menu <small>{DEFAULT_CONTROLLER_GLYPHS.start} / ESC</small></button>}
|
||||
</div>
|
||||
<PhaseOverlay />
|
||||
<PauseOverlay onExit={onExit} />
|
||||
|
||||
Reference in New Issue
Block a user