99 lines
4.6 KiB
TypeScript
99 lines
4.6 KiB
TypeScript
import { useMemo } from "react";
|
||
import { useShellStore } from "../app/shellStore";
|
||
import { useGameStore } from "../game/store";
|
||
import { useMenuController, type MenuAction } from "../input/useMenuController";
|
||
import { ControllerButton } from "./ControllerButton";
|
||
|
||
function PauseDialog() {
|
||
const closeOverlay = useGameStore((state) => state.closeOverlay);
|
||
const openOverlay = useGameStore((state) => state.openOverlay);
|
||
const reset = useGameStore((state) => state.resetAtEntrance);
|
||
const gameMode = useGameStore((state) => state.gameMode);
|
||
const activeCharacter = useShellStore((state) => state.activeCharacter);
|
||
const returnToMainMenu = useShellStore((state) => state.returnToMainMenu);
|
||
const abandonManastormRun = useShellStore((state) => state.abandonManastormRun);
|
||
|
||
const resume = () => {
|
||
closeOverlay();
|
||
};
|
||
const returnToEntrance = () => {
|
||
reset();
|
||
};
|
||
const leaveDungeon = () => {
|
||
closeOverlay();
|
||
returnToMainMenu();
|
||
};
|
||
const abandonManastorm = () => {
|
||
closeOverlay();
|
||
abandonManastormRun();
|
||
};
|
||
const skillMenuLabel = activeCharacter?.categoryId === "rom" ? "Skills" : "Talents";
|
||
|
||
const actions = useMemo<MenuAction[]>(() => [
|
||
{ id: "pause-resume", run: resume },
|
||
{ id: "pause-party", run: () => openOverlay("party") },
|
||
{ id: "pause-inventory", run: () => openOverlay("inventory") },
|
||
{ id: "pause-map", run: () => openOverlay("map") },
|
||
{ id: "pause-spellbook", run: () => openOverlay("spellbook") },
|
||
{ id: "pause-bindings", run: () => openOverlay("bindings") },
|
||
{ id: "pause-talents", run: () => openOverlay("talents") },
|
||
{ id: "pause-options", run: () => openOverlay("options") },
|
||
...(gameMode === "manastorm"
|
||
? [{ id: "pause-abandon-manastorm", run: abandonManastorm }]
|
||
: [{ id: "pause-entrance", run: returnToEntrance }]),
|
||
{ id: "pause-main-menu", run: leaveDungeon },
|
||
], [abandonManastormRun, closeOverlay, gameMode, openOverlay, reset, returnToMainMenu]);
|
||
const controller = useMenuController(actions, { initialId: "pause-resume", onBack: resume });
|
||
|
||
const menuButton = (id: string, label: string, run: () => void, primary = false) => (
|
||
<ControllerButton
|
||
controlId={id}
|
||
selectedId={controller.selectedId}
|
||
select={controller.select}
|
||
type="button"
|
||
className={`button ${primary ? "button--primary" : ""}`}
|
||
onClick={run}
|
||
>{label}</ControllerButton>
|
||
);
|
||
|
||
return (
|
||
<div className="modal-backdrop" role="presentation">
|
||
<section className="pause-menu" role="dialog" aria-modal="true" aria-labelledby="pause-title">
|
||
<p className="eyebrow">Healer Man paused</p>
|
||
<h2 id="pause-title">The cavern waits.</h2>
|
||
<p>Resume play or open any character and system menu from this hub.</p>
|
||
<div className="pause-menu__actions">
|
||
{menuButton("pause-resume", "Resume expedition", resume, true)}
|
||
{menuButton("pause-party", "Party management", () => openOverlay("party"))}
|
||
{menuButton("pause-inventory", "Inventory & equipment", () => openOverlay("inventory"))}
|
||
{menuButton("pause-map", "Dungeon map", () => openOverlay("map"))}
|
||
{menuButton("pause-spellbook", "Spellbook", () => openOverlay("spellbook"))}
|
||
{menuButton("pause-bindings", "Ability controls", () => openOverlay("bindings"))}
|
||
{menuButton("pause-talents", skillMenuLabel, () => openOverlay("talents"))}
|
||
{menuButton("pause-options", "Options", () => openOverlay("options"))}
|
||
{gameMode === "manastorm"
|
||
? menuButton("pause-abandon-manastorm", "Abandon Manastorm run", abandonManastorm)
|
||
: menuButton("pause-entrance", "Return to entrance", returnToEntrance)}
|
||
{menuButton("pause-main-menu", "Return to main menu", leaveDungeon)}
|
||
</div>
|
||
<dl className="controls-list">
|
||
<div><dt>Move</dt><dd>WASD / Left stick</dd></div>
|
||
<div><dt>Look</dt><dd>Hold right mouse / Arrow keys / Right stick</dd></div>
|
||
<div><dt>Abilities</dt><dd>1–8 / Face, R1, R2, D-pad left/right</dd></div>
|
||
<div><dt>Ability layers</dt><dd>Shift / Alt / Hold L1 / Hold L2</dd></div>
|
||
<div><dt>Targets</dt><dd>Tab / R3 enemy · D-pad up/down party/self · L3 clear</dd></div>
|
||
<div><dt>Party orders</dt><dd>F1 Attack / F2 Defend / F3 Stop / F4 Recall</dd></div>
|
||
<div><dt>Spellbook / {skillMenuLabel}</dt><dd>P / N</dd></div>
|
||
<div><dt>Inventory / Loot</dt><dd>I / E</dd></div>
|
||
<div><dt>Pause</dt><dd>Escape / Start</dd></div>
|
||
</dl>
|
||
</section>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export function PauseMenu() {
|
||
const open = useGameStore((state) => state.overlay === "pause");
|
||
return open ? <PauseDialog /> : null;
|
||
}
|