forked from phenom/healer-man
99 lines
4.8 KiB
TypeScript
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]);
|
|
}
|