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]); }