Files
healer-man/src/game/useArenaInput.ts
T
2026-09-11 14:26:15 -04:00

99 lines
4.8 KiB
TypeScript

import { useEffect, useRef } from "react";
import type { CharacterProfile } from "../app/types";
import { controlledArenaActor } from "./arenaPlayer";
import { useArenaStore } from "./arenaStore";
import { createArenaCharacterKit } from "./arenaCharacter";
import { actionBindingId, type ActionBindingLayer } from "./actionBindings";
import { activeUiLayout, currentUiDevice } from "./uiLayoutStore";
import { actionKeyForEvent, desktopSlotForKey } from "./uiLayout";
import { endMouseLookDrag, installInput, isDesktopCameraLookPointer } from "./inputManager";
import { useGameStore } from "./store";
export function useArenaInput(options: {
character: CharacterProfile | null;
blocked: boolean;
cast: (id: string) => void;
togglePause: () => void;
setLayer: (layer: ActionBindingLayer) => void;
setInputMode: (mode: "keyboard" | "gamepad") => void;
groundTargetActive: () => boolean;
confirmGroundTarget: () => void;
cancelGroundTarget: () => void;
}) {
const current = useRef(options);
current.current = options;
useEffect(() => {
const cycle = (direction: 1 | -1, friendly: boolean) => {
const state = useArenaStore.getState();
const actor = controlledArenaActor(state.snapshot, current.current.character);
if (!actor) return;
const targets = state.snapshot!.actors.filter((candidate) => candidate.alive && (friendly ? candidate.team === actor.team : candidate.team !== actor.team));
const index = targets.findIndex((candidate) => candidate.id === actor.targetActorId);
const selected = targets[(index + direction + targets.length) % targets.length];
if (selected) state.intent({ type: "target", targetActorId: selected.id });
};
const noop = () => {};
const uninstall = installInput({
desktopActionBarsActive: () => currentUiDevice() === "pc" && activeUiLayout().wowBars,
castDesktopSlot: (bar, slot) => {
const id = activeUiLayout().bars[bar]?.slots[slot]?.abilityId;
if (id) current.current.cast(id);
},
handleCustomKey: (event) => {
if (current.current.blocked || currentUiDevice() !== "pc") return false;
const slot = desktopSlotForKey(activeUiLayout(), actionKeyForEvent(event));
if (!slot) return false;
if (!event.repeat && slot.abilityId) current.current.cast(slot.abilityId);
current.current.setInputMode("keyboard");
return true;
},
togglePause: () => current.current.togglePause(),
toggleMap: () => useGameStore.getState().toggleOverlay("map"),
toggleInventory: () => useGameStore.getState().toggleOverlay("inventory"),
toggleSpellbook: () => useGameStore.getState().toggleOverlay("spellbook"),
toggleTalents: () => useGameStore.getState().toggleOverlay("talents"),
togglePanel: (panel) => useGameStore.getState().toggleOverlay(panel),
lootActiveBoss: () => false,
castActionBinding: (layer, control) => {
const character = current.current.character;
if (!character) return;
const actor = controlledArenaActor(useArenaStore.getState().snapshot, character);
const bindings = actor?.actionBindings ?? createArenaCharacterKit(character).actionBindings;
const id = bindings[actionBindingId(layer, control)];
if (id) current.current.cast(id);
},
cycleTarget: (direction) => cycle(direction, false),
cyclePartyTarget: (direction) => cycle(direction, true),
setPartyCommand: (command) => useArenaStore.getState().intent({ type: "command", command }),
recallParty: () => useArenaStore.getState().intent({ type: "command", command: "recall" }),
clearTarget: () => useArenaStore.getState().intent({ type: "target", targetActorId: "" }),
groundTargetActive: () => current.current.groundTargetActive(),
confirmGroundTarget: () => current.current.confirmGroundTarget(),
cancelGroundTarget: () => current.current.cancelGroundTarget(),
gameplayActionsBlocked: () => current.current.blocked,
setCameraLookActive: noop,
setInputMode: (mode) => current.current.setInputMode(mode),
setActionLayer: (layer) => current.current.setLayer(layer),
});
const stopMovement = () => {
endMouseLookDrag();
useArenaStore.getState().intent({ type: "movement", movement: { x: 0, z: 0 } });
};
const mouseUp = (event: MouseEvent) => { if (isDesktopCameraLookPointer("mouse", event.button)) endMouseLookDrag(); };
window.addEventListener("mouseup", mouseUp, true);
window.addEventListener("blur", stopMovement);
return () => {
window.removeEventListener("mouseup", mouseUp, true);
window.removeEventListener("blur", stopMovement);
stopMovement();
uninstall();
};
}, []);
useEffect(() => {
if (options.blocked) {
endMouseLookDrag();
useArenaStore.getState().intent({ type: "movement", movement: { x: 0, z: 0 } });
}
}, [options.blocked]);
}