Files
healer-man/src/GameRuntime.tsx
T
2026-08-20 14:05:50 -04:00

104 lines
4.3 KiB
TypeScript

import { useEffect } from "react";
import { DualDisplayFrame } from "./components/DualDisplayFrame";
import { installInput, releasePointerLock } from "./game/inputManager";
import { CombatBridge } from "./game/CombatBridge";
import { useCombatStore } from "./game/combatStore";
import { releaseDungeonGltfCache } from "./game/dungeonAssetCache";
import { clearDungeonRuntimeCaches } from "./game/dungeonRuntimeReset";
import { requireDungeonDefinition } from "./game/dungeonRegistry";
import { PartyBridge } from "./game/PartyBridge";
import { ManastormBridge } from "./game/ManastormBridge";
import { releaseActiveManastormStage } from "./game/manastormStageLoader";
import { lootCurrentManastormBoss } from "./game/manastormLoot";
import { usePartyStore } from "./game/partyStore";
import { useGameStore } from "./game/store";
import { GameScene } from "./scene/GameScene";
import { LocalCompanionPanel } from "./ui/CompanionPanel";
import { Hud } from "./ui/Hud";
import { GameplayPanels } from "./ui/GameplayPanels";
import { MapPanel } from "./ui/MapPanel";
import { PauseMenu } from "./ui/PauseMenu";
import { SceneErrorBoundary } from "./ui/SceneErrorBoundary";
import { GmWorldEditor } from "./ui/GmWorldEditor";
import { OnlineSessionBridge } from "./game/OnlineSessionBridge";
function InputBridge() {
const overlay = useGameStore((state) => state.overlay);
const companionOpen = useGameStore((state) => state.companionOpen);
useEffect(() => installInput({
togglePause: () => useGameStore.getState().togglePause(),
toggleMap: () => useGameStore.getState().toggleMap(),
toggleInventory: () => useGameStore.getState().toggleOverlay("inventory"),
toggleSpellbook: () => useGameStore.getState().toggleOverlay("spellbook"),
toggleTalents: () => useGameStore.getState().toggleOverlay("talents"),
lootActiveBoss: () => lootCurrentManastormBoss(),
castActionBinding: (layer, control) => {
const game = useGameStore.getState();
useCombatStore.getState().castActionBinding(layer, control, game.playerPosition, Date.now());
},
cycleTarget: (direction) => {
const game = useGameStore.getState();
usePartyStore.getState().clearSelection();
useCombatStore.getState().cycleTarget(direction, game.playerPosition);
},
cyclePartyTarget: (direction) => {
useCombatStore.getState().clearTarget();
usePartyStore.getState().cycleMember(direction);
},
setPartyCommand: (command) => usePartyStore.getState().setCommand(command),
recallParty: () => usePartyStore.getState().recallParty(),
clearTarget: () => {
useCombatStore.getState().clearTarget();
usePartyStore.getState().clearSelection();
},
groundTargetActive: () => useCombatStore.getState().pendingGroundTarget !== null,
confirmGroundTarget: () => { useCombatStore.getState().confirmGroundTarget(); },
cancelGroundTarget: () => useCombatStore.getState().cancelGroundTarget(),
gameplayActionsBlocked: () => {
const game = useGameStore.getState();
return game.overlay !== null || game.companionOpen;
},
setCameraLookActive: (active) => useGameStore.getState().setCameraLookActive(active),
setInputMode: (mode) => useGameStore.getState().setInputMode(mode),
setActionLayer: (layer) => useGameStore.getState().setActionLayer(layer),
}), []);
useEffect(() => () => releasePointerLock(), []);
useEffect(() => {
if (overlay || companionOpen) releasePointerLock();
}, [companionOpen, overlay]);
return null;
}
export default function GameRuntime() {
useEffect(() => () => {
const activeDungeon = requireDungeonDefinition(useGameStore.getState().activeDungeonId);
clearDungeonRuntimeCaches();
releaseDungeonGltfCache(activeDungeon);
releaseActiveManastormStage();
}, []);
return (
<DualDisplayFrame
contextLabel="Tactical"
onActiveSurfaceChange={(surface) => useGameStore.getState().setCompanionOpen(surface === "bottom")}
top={
<main className="game-shell">
<InputBridge />
<OnlineSessionBridge />
<CombatBridge />
<PartyBridge />
<ManastormBridge />
<SceneErrorBoundary><GameScene /></SceneErrorBoundary>
<Hud />
<MapPanel />
<GameplayPanels />
<PauseMenu />
<GmWorldEditor />
</main>
}
bottom={<LocalCompanionPanel />}
/>
);
}