// keyboard + mouse input. GAMEPLAY_FLOW.md controls. export const keys = { up: false, down: false, left: false, right: false }; const handlers = { interact: [], gift: [], escape: [], option: [], mute: [] }; export function on(name, fn) { handlers[name].push(fn); } function fire(name, arg) { handlers[name].forEach((fn) => fn(arg)); } // touch controls fire the same handlers as the keyboard (see touch.js) export function emit(name, arg) { fire(name, arg); } const KEYMAP = { KeyW: "up", ArrowUp: "up", KeyS: "down", ArrowDown: "down", KeyA: "left", ArrowLeft: "left", KeyD: "right", ArrowRight: "right", }; export let typingMode = false; export function setTyping(v) { typingMode = v; Object.keys(keys).forEach((k) => (keys[k] = false)); } window.addEventListener("keydown", (e) => { if (typingMode) return; // text input owns the keyboard if (KEYMAP[e.code]) { keys[KEYMAP[e.code]] = true; e.preventDefault(); return; } if (e.code === "Space" || e.code === "Enter") { fire("interact"); e.preventDefault(); } else if (e.code === "KeyG") fire("gift"); else if (e.code === "Escape") fire("escape"); else if (e.code === "Digit1") fire("option", "a"); else if (e.code === "Digit2") fire("option", "b"); else if (e.code === "KeyM") fire("mute"); }); window.addEventListener("keyup", (e) => { if (KEYMAP[e.code]) keys[KEYMAP[e.code]] = false; }); // click-to-move: main.js registers the stage and receives world coords export function bindStageClick(stageEl, fn) { stageEl.addEventListener("click", (e) => { const r = stageEl.getBoundingClientRect(); const x = ((e.clientX - r.left) / r.width) * 640; const y = ((e.clientY - r.top) / r.height) * 480; fn(x, y); }); }