tarinai/js/ui_input_shared.js
2026-07-01 14:41:05 +09:00

620 lines
25 KiB
JavaScript

"use strict";
(function (global) {
function cursorForTool(tool) {
if (tool === "water_hose") return "crosshair";
if (tool === "shoot") return "none";
if (tool === "pinch") return "grab";
if (tool === "observe") return "default";
if (tool === "poke" || tool === "delete" || tool === "area_delete") return "pointer";
return "crosshair";
}
function createInputContext({ canvas, world, ui, uiCache }) {
if (!canvas || !world || !uiCache) return null;
const inputModeManager = global.TarinaiInputMode;
function setMobileInputMode(mode = "auto") {
mode = inputModeManager?.setMode?.(mode) || (["auto", "camera", "tool"].includes(mode) ? mode : "auto");
uiCache.mobileInputMode = mode;
ui.mobileModeControls?.querySelectorAll("[data-mobile-mode]").forEach(btn => btn.classList.toggle("active", btn.dataset.mobileMode === mode));
document.body.classList.toggle("mobile-mode-auto", mode === "auto");
document.body.classList.toggle("mobile-mode-camera", mode === "camera");
document.body.classList.toggle("mobile-mode-tool", mode === "tool");
global.syncMobileRotateControls?.();
return mode;
}
function updateTouchMobileUiClass() {
const enabled = Boolean(inputModeManager?.refresh?.().touchFirst);
document.body.classList.toggle("touch-mobile-ui", enabled);
if (ui.mobileModeControls) ui.mobileModeControls.hidden = !enabled;
global.syncMobileRotateControls?.();
return enabled;
}
function mobileInputMode() {
return inputModeManager?.currentMode || uiCache.mobileInputMode || "auto";
}
function bindMobileModeControls() {
updateTouchMobileUiClass();
window.addEventListener("resize", updateTouchMobileUiClass, { passive: true });
window.matchMedia?.("(pointer: coarse)")?.addEventListener?.("change", updateTouchMobileUiClass);
setMobileInputMode(uiCache.mobileInputMode || "auto");
const root = ui.mobileModeControls;
if (!root || root.dataset.bound === "1") return;
root.dataset.bound = "1";
const activate = (e) => {
const btn = e.target?.closest?.("[data-mobile-mode]");
if (!btn || !root.contains(btn)) return;
const now = performance?.now?.() ?? Date.now();
if (now - Number(root.dataset.lastActivateAt || 0) < 180) return;
root.dataset.lastActivateAt = String(now);
e.preventDefault?.();
e.stopPropagation?.();
window.TarinaiTooltips.hide();
audio.uiClick?.();
setMobileInputMode(btn.dataset.mobileMode || "auto");
showToast(`\u30b9\u30de\u30db\u64cd\u4f5c: ${btn.textContent || btn.dataset.mobileMode}`);
};
root.addEventListener("pointerup", activate, { passive: false });
root.addEventListener("touchend", activate, { passive: false });
root.addEventListener("click", activate);
}
function touchPoint(touches, index = 0) {
const t = touches?.[index];
if (!t) return null;
return { clientX: t.clientX, clientY: t.clientY };
}
function touchCenter(touches) {
const a = touchPoint(touches, 0);
const b = touchPoint(touches, 1);
if (!a) return null;
if (!b) return a;
return { clientX: (a.clientX + b.clientX) / 2, clientY: (a.clientY + b.clientY) / 2 };
}
function touchDistance(touches) {
const a = touchPoint(touches, 0);
const b = touchPoint(touches, 1);
if (!a || !b) return 0;
return Math.hypot(a.clientX - b.clientX, a.clientY - b.clientY);
}
function screenToWorldClient(clientX, clientY) {
const rect = canvas.getBoundingClientRect();
const sx = clientX - rect.left;
const sy = clientY - rect.top;
return world.screenToWorld ? world.screenToWorld(sx, sy) : { x: sx, y: sy, inside: sx >= 0 && sy >= 0 };
}
function screenToWorldEvent(e) {
return screenToWorldClient(e.clientX, e.clientY);
}
function clientToWorldRaw(clientX, clientY) {
const rect = canvas.getBoundingClientRect();
const sx = clientX - rect.left;
const sy = clientY - rect.top;
const scale = world.viewScale ? world.viewScale() : 1;
const off = world.fieldScreenOffset ? world.fieldScreenOffset() : { x: 0, y: 0 };
const rawX = (sx - off.x) / scale + (world.cameraX || 0);
const rawY = (sy - off.y) / scale + (world.cameraY || 0);
return { x: rawX, y: rawY, inside: rawX >= 0 && rawY >= 0 && rawX <= world.w && rawY <= world.h };
}
function setZoomAroundClientPoint(clientX, clientY, nextZoom) {
if (!world.setFieldZoom) return false;
const rect = canvas.getBoundingClientRect();
const sx = clientX - rect.left;
const sy = clientY - rect.top;
const focus = world.screenToWorld ? world.screenToWorld(sx, sy) : { x: sx, y: sy };
if (!world.setFieldZoom(nextZoom)) return false;
const off = world.fieldScreenOffset ? world.fieldScreenOffset() : { x: 0, y: 0 };
const scale = world.viewScale ? world.viewScale() : 1;
world.cameraX = focus.x - (sx - off.x) / scale;
world.cameraY = focus.y - (sy - off.y) / scale;
world.clampCamera?.();
return true;
}
function rememberGrabOrigin(target) {
if (!target || uiCache.grabKind !== "tarinai") return;
uiCache.grabOrigin = { x: target.x, y: target.y, vx: target.vx || 0, vy: target.vy || 0 };
}
function finishTarinaiGrab(target, clientX, clientY) {
if (!target || uiCache.grabKind !== "tarinai") return false;
const p = screenToWorldClient(clientX, clientY);
if (!p.inside && uiCache.grabOrigin) {
target.x = uiCache.grabOrigin.x;
target.y = uiCache.grabOrigin.y;
target.vx = uiCache.grabOrigin.vx || 0;
target.vy = uiCache.grabOrigin.vy || 0;
target.thought = "\u30d5\u30a3\u30fc\u30eb\u30c9\u306b\u623b\u3055\u308c\u305f";
target.pinchThoughtTimer = Math.max(target.pinchThoughtTimer || 0, 0.8);
showToast("\u30d5\u30a3\u30fc\u30eb\u30c9\u5916\u306a\u306e\u3067\u5143\u306e\u4f4d\u7f6e\u306b\u623b\u3057\u307e\u3057\u305f\u3002");
uiCache.grabOrigin = null;
return true;
}
uiCache.grabOrigin = null;
return false;
}
function syncGrabbedPhysicsItem(target, reason = "pinch-move") {
if (!target || target.dead) return false;
const pb = global.TarinaiPhysicsBodySystem;
const isBody = typeof pb?.isBodyType === "function"
? pb.isBodyType(target)
: Boolean(typeof pb?.isPhysicsType === "function" && pb.isPhysicsType(target) && typeof pb?.ensureBody === "function" && pb.ensureBody(target, null, { syncFromLegacy: false }));
if (!isBody) return false;
pb.syncPoseFromItem(target);
pb.setScalar(target, "awakeUntil", Math.max(Number(pb.scalar(target, "awakeUntil", 0) || 0), (world.time || 0) + 0.65), reason);
pb.markBodyChanged(target, reason);
global.TarinaiMechanicalSystem.invalidateGeometry(target);
return true;
}
function prepareGrabTarget(target) {
if (uiCache.grabKind === "tarinai") {
const lodged = target.currentLodgedPin?.() || (world.items || []).find(it => it && isPinType(it.type) && it.pinState === "lodged" && it.pinTargetId === target.id);
if (lodged) global.TarinaiItemDynamicPinSystem.detach(lodged, world, "pinch");
target.sleeping = false;
if (target.state === "sleep" || target.state === "seek_bed") target.goIdle?.("\u3064\u307e\u307e\u308c\u3066\u3044\u308b");
target.surpriseTimer = Math.max(target.surpriseTimer || 0, 0.18);
target.thought = "\u3064\u307e\u307e\u308c\u3066\u3044\u308b";
target.pinchThoughtTimer = Math.max(target.pinchThoughtTimer || 0, 1.2);
} else {
if (isPinType(target.type) && target.pinState === "lodged") global.TarinaiItemDynamicPinSystem.detach(target, world, "pinch");
target.dropTimer = 0;
target.dropMax = 0;
target.dropImpactDone = true;
}
}
function beginGrab(p, clientX, clientY, options = {}) {
const target = world.findGrabTargetAt ? world.findGrabTargetAt(p.x, p.y) : null;
if (!target) {
if (options.notifyNoTarget) showToast("\u3064\u307e\u3081\u308b\u5bfe\u8c61\u304c\u3042\u308a\u307e\u305b\u3093\u3002");
return false;
}
global.TarinaiHistory.capture(world, "pinch");
audio.grab?.();
uiCache.grabbing = true;
uiCache.grabMoved = false;
uiCache.grabTarget = target;
uiCache.grabKind = target instanceof Tarinai ? "tarinai" : "item";
rememberGrabOrigin(target);
uiCache.grabLastWorldX = p.x;
uiCache.grabLastWorldY = p.y;
uiCache.grabVelocityX = 0;
uiCache.grabVelocityY = 0;
uiCache.grabLastMoveAt = performance?.now?.() ?? Date.now();
uiCache.grabStartX = clientX || 0;
uiCache.grabStartY = clientY || 0;
target.playerHeld = true;
target._heldByPlayer = true;
if (uiCache.grabKind === "item") syncGrabbedPhysicsItem(target, "pinch-start");
if (target.type === "duplicator") {
target.duplicatorLoadSuppressedUntil = Math.max(target.duplicatorLoadSuppressedUntil || 0, (world.time || 0) + 1.0);
}
prepareGrabTarget(target);
if (options.touchMode) uiCache.touchMode = options.touchMode;
renderStats();
return true;
}
function moveGrab(p, clientX, clientY, options = {}) {
const target = uiCache.grabTarget;
if (!target || target.dead) {
uiCache.grabbing = false;
uiCache.grabTarget = null;
if (options.touch) uiCache.touchMode = "";
canvas.style.cursor = world.tool === "pinch" ? "grab" : "default";
return false;
}
const dx = p.x - (uiCache.grabLastWorldX ?? p.x);
const dy = p.y - (uiCache.grabLastWorldY ?? p.y);
const moveNow = performance?.now?.() ?? Date.now();
const moveDt = Math.max(0.012, Math.min(0.18, (moveNow - (uiCache.grabLastMoveAt || moveNow)) / 1000));
uiCache.grabLastMoveAt = moveNow;
uiCache.grabVelocityX = clamp(dx / moveDt, -820, 820);
uiCache.grabVelocityY = clamp(dy / moveDt, -820, 820);
uiCache.grabLastWorldX = p.x;
uiCache.grabLastWorldY = p.y;
const beforeX = Number(target.x || 0) || 0;
const beforeY = Number(target.y || 0) || 0;
const pad = target.radius || target.r || 16;
if (uiCache.grabKind === "tarinai" && !p.inside) {
const raw = clientToWorldRaw(clientX, clientY);
target.x = raw.x;
target.y = raw.y;
} else {
target.x = clamp(p.x, CONFIG.worldPadding + pad * 0.15, world.w - CONFIG.worldPadding - pad * 0.15);
target.y = clamp(p.y, CONFIG.worldPadding + pad * 0.15, world.h - CONFIG.worldPadding - pad * 0.15);
}
const movedX = (Number(target.x || 0) || 0) - beforeX;
const movedY = (Number(target.y || 0) || 0) - beforeY;
if (uiCache.grabKind === "item" && target.type === "reciprocator") {
const pb = (typeof window !== "undefined" ? window : globalThis).TarinaiPhysicsBodySystem;
pb?.setScalar?.(target, "railAnchorX", (Number(pb?.scalar?.(target, "railAnchorX", beforeX)) || beforeX) + movedX, "grab-move");
pb?.setScalar?.(target, "railAnchorY", (Number(pb?.scalar?.(target, "railAnchorY", beforeY)) || beforeY) + movedY, "grab-move");
target.prevX = target.x;
target.prevY = target.y;
}
if (uiCache.grabKind === "item") syncGrabbedPhysicsItem(target, "pinch-move");
target.vx = clamp(uiCache.grabVelocityX || dx * 16, -820, 820);
target.vy = clamp(uiCache.grabVelocityY || dy * 16, -820, 820);
if (uiCache.grabKind === "tarinai") {
target.goIdle?.("\u3064\u307e\u307e\u308c\u3066\u3044\u308b");
if (options.touch) target.pinchThoughtTimer = Math.max(target.pinchThoughtTimer || 0, 0.8);
} else if (target.type === "ball") {
target.prevX = target.x - dx;
target.prevY = target.y - dy;
target.spinVelocity = clamp((target.spinVelocity || 0) + dx * 0.06, -38, 38);
}
world.drawListDirty = true;
const now = performance.now();
if (!uiCache.grabLastSpatialAt || now - uiCache.grabLastSpatialAt > 80) {
world.rebuildSpatial?.();
uiCache.grabLastSpatialAt = now;
}
canvas.style.cursor = "grabbing";
if (options.renderFrame) render();
return true;
}
function endGrab(clientX, clientY) {
if (!uiCache.grabbing) return false;
const target = uiCache.grabTarget;
if (target) {
if (uiCache.grabKind === "tarinai") {
target.target = null;
target.targetKey = "";
target.surpriseTimer = Math.max(target.surpriseTimer || 0, 0.15);
finishTarinaiGrab(target, clientX, clientY);
} else if (uiCache.grabKind === "item") {
const releaseVx = clamp(Number(uiCache.grabVelocityX || target.vx || 0) || 0, -900, 900);
const releaseVy = clamp(Number(uiCache.grabVelocityY || target.vy || 0) || 0, -900, 900);
const releaseSpeed = Math.hypot(releaseVx, releaseVy);
if (target.type === "plushie" && typeof target.fling === "function") {
const sourceX = Number(uiCache.grabLastWorldX ?? target.x) || target.x;
const sourceY = Number(uiCache.grabLastWorldY ?? target.y) || target.y;
const vx = releaseSpeed > 80 ? releaseVx : 0;
const vy = releaseSpeed > 80 ? releaseVy : 0;
target.fling(world, sourceX, sourceY, { source: "pinch", vx, vy, speed: Math.max(620, releaseSpeed * 1.05), life: 2.8 });
} else if (releaseSpeed > 18) {
target.vx = releaseVx;
target.vy = releaseVy;
const frameDt = Math.max(1 / 90, Math.min(1 / 30, Number(world.dt || 1 / 60) || 1 / 60));
target.prevX = target.x - releaseVx * frameDt;
target.prevY = target.y - releaseVy * frameDt;
if (target.type === "ball") target.spinVelocity = clamp((target.spinVelocity || 0) + releaseVx * 0.018, -42, 42);
} else if (target.type === "ball") {
target.prevX = target.x;
target.prevY = target.y;
}
}
if (uiCache.grabKind === "item") syncGrabbedPhysicsItem(target, "pinch-release");
target.playerHeld = false;
target._heldByPlayer = false;
if (target.type === "duplicator") {
target.duplicatorLoadSuppressedUntil = Math.max(target.duplicatorLoadSuppressedUntil || 0, (world.time || 0) + 1.2);
}
}
audio.drop?.();
uiCache.grabbing = false;
uiCache.grabTarget = null;
uiCache.grabKind = "";
uiCache.grabVelocityX = 0;
uiCache.grabVelocityY = 0;
uiCache.grabLastMoveAt = 0;
world.rebuildSpatial?.();
uiCache.grabLastSpatialAt = 0;
canvas.style.cursor = cursorForTool(world.tool);
renderStats();
return true;
}
function beginHose(p, clientX, clientY, options = {}) {
global.TarinaiHistory.capture(world, "water-hose");
audio.waterHose?.();
uiCache.hosing = true;
uiCache.hoseMoved = false;
uiCache.hoseLastWorldX = p.x;
uiCache.hoseLastWorldY = p.y;
uiCache.hoseStartX = clientX;
uiCache.hoseStartY = clientY;
uiCache.hoseLastApplyAt = global.performance?.now?.() || Date.now();
world.applyWaterHose?.(p.x, p.y, 0, 0, 0.18);
if (options.touchMode) uiCache.touchMode = options.touchMode;
render();
return true;
}
function moveHose(p, clientX, clientY, options = {}) {
uiCache.hoseLastClientX = clientX;
uiCache.hoseLastClientY = clientY;
const dx = p.x - (uiCache.hoseLastWorldX ?? p.x);
const dy = p.y - (uiCache.hoseLastWorldY ?? p.y);
uiCache.hoseLastWorldX = p.x;
uiCache.hoseLastWorldY = p.y;
const totalMove = Math.hypot(clientX - (uiCache.hoseStartX || clientX), clientY - (uiCache.hoseStartY || clientY));
if (totalMove > 3) {
uiCache.hoseMoved = true;
if (options.touch) uiCache.touchMoved = true;
}
if (p.inside) {
const now = global.performance?.now?.() || Date.now();
const elapsed = Math.max(0.06, Math.min(0.22, (now - (uiCache.hoseLastApplyAt || now)) / 1000));
uiCache.hoseLastApplyAt = now;
world.applyWaterHose?.(p.x, p.y, dx, dy, elapsed);
}
canvas.style.cursor = "crosshair";
render();
}
function endHose() {
if (!uiCache.hosing) return false;
uiCache.hosing = false;
uiCache.hoseLastApplyAt = 0;
canvas.style.cursor = cursorForTool(world.tool);
world.rebuildSpatial?.();
renderStats();
return true;
}
function beginShoot(p, clientX, clientY, options = {}) {
if (!p?.inside) return false;
global.TarinaiHistory.capture(world, "shoot");
uiCache.shooting = true;
uiCache.shootSuppressClick = true;
uiCache.shootFired = false;
uiCache.shootStartX = clientX;
uiCache.shootStartY = clientY;
world.pointer.x = p.x;
world.pointer.y = p.y;
world.pointer.inside = true;
world.setShootCursorFromPointer?.(p);
uiCache.shootLastRawWorldX = p.x;
uiCache.shootLastRawWorldY = p.y;
uiCache.shootFired = Boolean(world.fireShootTool?.()) || Boolean(uiCache.shootFired);
if (options.touchMode) uiCache.touchMode = options.touchMode;
if (uiCache.shootHoldTimer) clearInterval(uiCache.shootHoldTimer);
uiCache.shootHoldTimer = setInterval(() => {
if (!uiCache.shooting) {
clearInterval(uiCache.shootHoldTimer);
uiCache.shootHoldTimer = null;
return;
}
uiCache.shootFired = Boolean(world.fireShootTool?.()) || Boolean(uiCache.shootFired);
}, 120);
canvas.style.cursor = "none";
render();
return true;
}
function moveShoot(p, clientX, clientY, options = {}) {
const rawDx = (Number(p.x) || 0) - (Number(uiCache.shootLastRawWorldX ?? p.x) || 0);
const rawDy = (Number(p.y) || 0) - (Number(uiCache.shootLastRawWorldY ?? p.y) || 0);
uiCache.shootLastRawWorldX = p.x;
uiCache.shootLastRawWorldY = p.y;
world.pointer.x = p.x;
world.pointer.y = p.y;
world.pointer.inside = !!p.inside;
if (p.inside) world.moveShootCursorBy?.(rawDx, rawDy);
const totalMove = Math.hypot(clientX - (uiCache.shootStartX || clientX), clientY - (uiCache.shootStartY || clientY));
if (totalMove > 3) {
if (options.touch) uiCache.touchMoved = true;
}
canvas.style.cursor = "none";
render();
return true;
}
function endShoot() {
if (!uiCache.shooting) return false;
uiCache.shooting = false;
if (uiCache.shootHoldTimer) {
clearInterval(uiCache.shootHoldTimer);
uiCache.shootHoldTimer = null;
}
if (uiCache.shootFired) audio.boltAction?.();
uiCache.shootFired = false;
canvas.style.cursor = cursorForTool(world.tool);
renderStats();
return true;
}
function beginAreaDelete(p, clientX, clientY, options = {}) {
global.TarinaiHistory.capture(world, "area-delete");
uiCache.areaDeleting = true;
uiCache.areaDeleteMoved = false;
uiCache.areaDeleteStartX = clientX;
uiCache.areaDeleteStartY = clientY;
world._areaDeleteDragRemoved = 0;
if (p.inside) world.deleteItemsInArea?.(p.x, p.y, { silentEmpty: true, silentLog: true, drag: true });
if (options.touchMode) uiCache.touchMode = options.touchMode;
render();
return true;
}
function moveAreaDelete(p, clientX, clientY, options = {}) {
const totalMove = Math.hypot(clientX - (uiCache.areaDeleteStartX || clientX), clientY - (uiCache.areaDeleteStartY || clientY));
if (totalMove > 3) {
uiCache.areaDeleteMoved = true;
if (options.touch) uiCache.touchMoved = true;
}
if (p.inside) world.deleteItemsInArea?.(p.x, p.y, { silentEmpty: true, silentLog: true, drag: true });
canvas.style.cursor = "crosshair";
render();
return true;
}
function endAreaDelete() {
if (!uiCache.areaDeleting) return false;
uiCache.areaDeleting = false;
const removed = world._areaDeleteDragRemoved || 0;
world._areaDeleteDragRemoved = 0;
canvas.style.cursor = cursorForTool(world.tool);
world.rebuildSpatial?.();
renderStats();
if (removed > 0) {
world.log?.(`\u7bc4\u56f2\u524a\u9664\u3067${removed}\u500b\u6d88\u3057\u305f\u3002`, "observe");
showToast(`${removed}\u500b\u6d88\u3057\u307e\u3057\u305f\u3002`);
}
return true;
}
function beginPan(clientX, clientY, button = null) {
uiCache.panning = true;
uiCache.panMoved = false;
uiCache.panButton = button;
uiCache.panStartX = clientX;
uiCache.panStartY = clientY;
uiCache.panLastX = clientX;
uiCache.panLastY = clientY;
}
function movePan(clientX, clientY) {
if (!uiCache.panning) return false;
const dx = clientX - uiCache.panLastX;
const dy = clientY - uiCache.panLastY;
uiCache.panLastX = clientX;
uiCache.panLastY = clientY;
const totalMove = Math.hypot(clientX - uiCache.panStartX, clientY - uiCache.panStartY);
if (totalMove > 8) {
canvas.style.cursor = "grabbing";
world.panCamera?.(-dx, -dy);
uiCache.panMoved = true;
render();
}
return true;
}
function endPan(button = null) {
if (!uiCache.panning) return false;
if (uiCache.panButton !== null && button !== null && button !== uiCache.panButton) return false;
uiCache.panning = false;
uiCache.panButton = null;
canvas.style.cursor = cursorForTool(world.tool);
return true;
}
function updatePointerFromEvent(e) {
const p = screenToWorldEvent(e);
const prevX = world.pointer.x;
const prevY = world.pointer.y;
world.pointer.x = p.x;
world.pointer.y = p.y;
world.pointer.inside = !!p.inside;
const delta = Math.hypot((p.x || 0) - (prevX || 0), (p.y || 0) - (prevY || 0));
world.pointer.motion = clamp(delta / 18, 0, 2);
if (world.tool === "shoot") {
if (p.inside) {
if (world.shootCursorActive) {
const lastRawX = Number.isFinite(Number(world.shootPointerRawX)) ? Number(world.shootPointerRawX) : prevX;
const lastRawY = Number.isFinite(Number(world.shootPointerRawY)) ? Number(world.shootPointerRawY) : prevY;
world.moveShootCursorBy?.((Number(p.x) || 0) - (Number(lastRawX) || 0), (Number(p.y) || 0) - (Number(lastRawY) || 0));
} else {
world.setShootCursorFromPointer?.(p);
}
world.shootPointerRawX = p.x;
world.shootPointerRawY = p.y;
}
canvas.style.cursor = "none";
} else if (world.tool === "pinch" && p.inside && !uiCache.grabbing && !uiCache.panning && !uiCache.hosing && !uiCache.areaDeleting && !uiCache.shooting) {
const target = world.findGrabTargetAt ? world.findGrabTargetAt(p.x, p.y) : null;
if (world.hoverGrabTarget !== target) {
world.hoverGrabTarget = target || null;
world.drawListDirty = true;
}
if (world.hoverDeleteTarget) { world.hoverDeleteTarget = null; world.drawListDirty = true; }
canvas.style.cursor = target ? "grab" : "default";
} else if (world.tool === "delete" && p.inside && !uiCache.grabbing && !uiCache.panning && !uiCache.hosing && !uiCache.areaDeleting && !uiCache.shooting) {
const target = world.findDeleteToolTargetAt ? world.findDeleteToolTargetAt(p.x, p.y) : null;
if (world.hoverDeleteTarget !== target) {
world.hoverDeleteTarget = target || null;
world.drawListDirty = true;
}
if (world.hoverGrabTarget) { world.hoverGrabTarget = null; world.drawListDirty = true; }
canvas.style.cursor = target ? "pointer" : "default";
} else {
if (world.hoverGrabTarget) {
world.hoverGrabTarget = null;
world.drawListDirty = true;
}
if (world.hoverDeleteTarget) {
world.hoverDeleteTarget = null;
world.drawListDirty = true;
}
}
}
function cancelPointerActions() {
uiCache.touchMode = "";
uiCache.touchMoved = false;
uiCache.hosing = false;
if (uiCache.hoseHoldTimer) { clearInterval(uiCache.hoseHoldTimer); uiCache.hoseHoldTimer = null; }
uiCache.shooting = false;
uiCache.shootFired = false;
if (uiCache.shootHoldTimer) { clearInterval(uiCache.shootHoldTimer); uiCache.shootHoldTimer = null; }
uiCache.areaDeleting = false;
uiCache.grabbing = false;
uiCache.grabTarget = null;
uiCache.grabKind = "";
uiCache.grabVelocityX = 0;
uiCache.grabVelocityY = 0;
uiCache.grabLastMoveAt = 0;
if (world) {
world.hoverGrabTarget = null;
world.hoverDeleteTarget = null;
}
}
return {
canvas,
world,
ui,
uiCache,
cursorForTool,
setMobileInputMode,
updateTouchMobileUiClass,
mobileInputMode,
bindMobileModeControls,
touchPoint,
touchCenter,
touchDistance,
screenToWorldClient,
screenToWorldEvent,
clientToWorldRaw,
setZoomAroundClientPoint,
beginGrab,
moveGrab,
endGrab,
beginHose,
moveHose,
endHose,
beginShoot,
moveShoot,
endShoot,
beginAreaDelete,
moveAreaDelete,
endAreaDelete,
beginPan,
movePan,
endPan,
updatePointerFromEvent,
cancelPointerActions,
};
}
global.TarinaiUIInputShared = Object.freeze({ createInputContext, cursorForTool });
})(window);