Files
healer-man/src/ui/PauseMenu.tsx
T
2026-09-12 11:07:25 -04:00

109 lines
5.3 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";
import { sessionCanUseShelvedGmTools } from "../app/releaseFeatures";
import { useInputBindingLabels } from "../input/useInputBindingLabels";
import { INPUT_ACTION_BY_ID } from "../input/keybinds";
function PauseDialog() {
const bindingLabel = useInputBindingLabels();
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 session = useShellStore((state) => state.session);
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 isGm = sessionCanUseShelvedGmTools(session);
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-boss-guide", run: () => openOverlay("boss-guide") },
{ id: "pause-spellbook", run: () => openOverlay("spellbook") },
{ id: "pause-bindings", run: () => openOverlay("bindings") },
{ id: "pause-talents", run: () => openOverlay("talents") },
{ id: "pause-keybinds", run: () => openOverlay("keybinds") },
{ id: "pause-options", run: () => openOverlay("options") },
{ id: "pause-ui-layout", run: () => openOverlay("ui-layout") },
...(isGm ? [{ id: "pause-gm", run: () => openOverlay("gm") }] : []),
...(gameMode === "manastorm"
? [{ id: "pause-abandon-manastorm", run: abandonManastorm }]
: [{ id: "pause-entrance", run: returnToEntrance }]),
{ id: "pause-main-menu", run: leaveDungeon },
], [abandonManastormRun, closeOverlay, gameMode, isGm, 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-boss-guide", "Boss guide", () => openOverlay("boss-guide"))}
{menuButton("pause-spellbook", "Spellbook", () => openOverlay("spellbook"))}
{menuButton("pause-bindings", "Ability controls", () => openOverlay("bindings"))}
{menuButton("pause-talents", skillMenuLabel, () => openOverlay("talents"))}
{menuButton("pause-keybinds", "Keybinds", () => openOverlay("keybinds"))}
{menuButton("pause-options", "Options", () => openOverlay("options"))}
{menuButton("pause-ui-layout", "Edit UI & templates", () => openOverlay("ui-layout"))}
{isGm ? menuButton("pause-gm", "GM placement editor", () => openOverlay("gm")) : null}
{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">
{["move-forward", "jump", "target-next", "party-next", "loot", "inventory", "spellbook", "pause"].map((id) => <div key={id}>
<dt>{INPUT_ACTION_BY_ID[id].label}</dt><dd>{bindingLabel("pc", id)} / {bindingLabel("controller", id)}</dd>
</div>)}
<div><dt>Camera</dt><dd>Hold right mouse and drag</dd></div>
<div><dt>All controls</dt><dd>Options → Keybinds</dd></div>
</dl>
</section>
</div>
);
}
export function PauseMenu() {
const open = useGameStore((state) => state.overlay === "pause");
return open ? <PauseDialog /> : null;
}