137 lines
6.4 KiB
TypeScript
137 lines
6.4 KiB
TypeScript
import { useEffect } from "react";
|
|
import "./ui/uiLayout.css";
|
|
import { DualDisplayFrame } from "./components/DualDisplayFrame";
|
|
import { installInput, releasePointerLock } from "./game/inputManager";
|
|
import { CombatBridge } from "./game/CombatBridge";
|
|
import { connectDpsMeter } from "./game/dpsMeterStore";
|
|
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 { 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 { OnlineSessionBridge } from "./game/OnlineSessionBridge";
|
|
import { DungeonRunCheckpointBridge } from "./game/DungeonRunCheckpointBridge";
|
|
import { DungeonRunBridge } from "./game/DungeonRunBridge";
|
|
import { DungeonRunResults } from "./ui/DungeonRunResults";
|
|
import { DungeonEncounterEffectBridge } from "./game/DungeonEncounterEffectBridge";
|
|
import { interactWithActiveDungeonObject } from "./game/dungeonWorldInteraction";
|
|
import { DungeonInteractionPrompt } from "./ui/DungeonInteractionPrompt";
|
|
import { UiLayoutEditor } from "./ui/UiLayoutEditor";
|
|
import { EditableHudElement } from "./ui/EditableHudElement";
|
|
import { activeUiLayout, currentUiDevice } from "./game/uiLayoutStore";
|
|
import { useUiLayoutStore } from "./game/uiLayoutStore";
|
|
import { profileInputBindings } from "./game/keybindPreferences";
|
|
import { KeybindsPanel } from "./ui/KeybindsPanel";
|
|
import { lootShelvedBoss, releaseShelvedGameRuntime, ShelvedGameBridges } from "@shelvedGameRuntime";
|
|
|
|
function InputBridge() {
|
|
const overlay = useGameStore((state) => state.overlay);
|
|
const companionOpen = useGameStore((state) => state.companionOpen);
|
|
|
|
useEffect(() => installInput({
|
|
desktopActionBarsActive: () => currentUiDevice() === "pc" && activeUiLayout().wowBars,
|
|
inputSuspended: () => ["ui-layout", "keybinds", "dungeon-results"].includes(useGameStore.getState().overlay ?? ""),
|
|
getBindings: (device) => {
|
|
const preferences = useUiLayoutStore.getState().preferences;
|
|
const bindings = profileInputBindings(preferences, device);
|
|
for (let b = activeUiLayout().barCount; b < 5; b++) for (let s = 0; s < 12; s++) bindings[`bar:${b}:${s}`] = null;
|
|
return bindings;
|
|
},
|
|
castDesktopSlot: (bar, slot) => {
|
|
const game = useGameStore.getState(); const button = activeUiLayout().bars[bar]?.slots[slot];
|
|
if (button?.abilityId) useCombatStore.getState().castAbility(button.abilityId, game.playerPosition, Date.now());
|
|
},
|
|
togglePanel: (panel) => useGameStore.getState().toggleOverlay(panel),
|
|
togglePause: () => useGameStore.getState().togglePause(),
|
|
toggleMap: () => useGameStore.getState().toggleMap(),
|
|
toggleInventory: () => useGameStore.getState().toggleOverlay("inventory"),
|
|
toggleSpellbook: () => useGameStore.getState().toggleOverlay("spellbook"),
|
|
toggleTalents: () => useGameStore.getState().toggleOverlay("talents"),
|
|
lootActiveBoss: () => interactWithActiveDungeonObject() || lootShelvedBoss(),
|
|
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(connectDpsMeter, []);
|
|
const editingControls = useGameStore((state) => state.overlay === "keybinds" || state.overlay === "ui-layout");
|
|
useEffect(() => () => {
|
|
const activeDungeon = requireDungeonDefinition(useGameStore.getState().activeDungeonId);
|
|
clearDungeonRuntimeCaches();
|
|
releaseDungeonGltfCache(activeDungeon);
|
|
releaseShelvedGameRuntime();
|
|
}, []);
|
|
return (
|
|
<DualDisplayFrame
|
|
contextLabel="Tactical"
|
|
companionDisabled={editingControls}
|
|
onActiveSurfaceChange={(surface) => useGameStore.getState().setCompanionOpen(surface === "bottom")}
|
|
top={
|
|
<main className="game-shell">
|
|
<InputBridge />
|
|
<OnlineSessionBridge />
|
|
<DungeonEncounterEffectBridge />
|
|
<DungeonRunCheckpointBridge />
|
|
<CombatBridge />
|
|
<PartyBridge />
|
|
<DungeonRunBridge />
|
|
<ShelvedGameBridges />
|
|
<SceneErrorBoundary><GameScene /></SceneErrorBoundary>
|
|
<Hud />
|
|
<EditableHudElement id="interaction"><DungeonInteractionPrompt /></EditableHudElement>
|
|
<MapPanel />
|
|
<GameplayPanels />
|
|
<PauseMenu />
|
|
<DungeonRunResults />
|
|
<UiLayoutEditor />
|
|
<KeybindsPanel />
|
|
</main>
|
|
}
|
|
bottom={<LocalCompanionPanel />}
|
|
/>
|
|
);
|
|
}
|