This commit is contained in:
33333-33333 2026-07-11 21:13:39 +09:00
commit d14550dad6
78 changed files with 2827 additions and 563 deletions

View file

@ -121,6 +121,24 @@
return true;
}
function directFeedTargetAt(p, item = null) {
const feeding = global.TarinaiDirectFeedingSystem;
if (!p?.inside || !feeding) return null;
const type = item?.type || (typeof global.toolItemType === "function" ? global.toolItemType(world.tool || "") : "");
if (!feeding.isDirectFeedType?.(type)) return null;
if (item && !feeding.hasConsumableAmount?.(item)) return null;
return feeding.findTargetAt?.(world, p.x, p.y) || null;
}
function setGiveHover(target = null) {
const next = target && !target.dead ? target : null;
if (world.hoverGiveTarget !== next) {
world.hoverGiveTarget = next;
world.drawListDirty = true;
}
return next;
}
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 };
@ -208,6 +226,9 @@
}
function moveGrab(p, clientX, clientY, options = {}) {
world.pointer.x = p?.x ?? world.pointer.x;
world.pointer.y = p?.y ?? world.pointer.y;
world.pointer.inside = Boolean(p?.inside);
const target = uiCache.grabTarget;
if (!target || target.dead) {
uiCache.grabbing = false;
@ -266,6 +287,7 @@
target.prevY = target.y - dy;
target.spinVelocity = clamp((target.spinVelocity || 0) + dx * 0.06, -38, 38);
}
setGiveHover(uiCache.grabKind === "item" ? directFeedTargetAt(p, target) : null);
world.drawListDirty = true;
const now = performance.now();
if (!uiCache.grabLastSpatialAt || now - uiCache.grabLastSpatialAt > 80) {
@ -280,6 +302,7 @@
function endGrab(clientX, clientY) {
if (!uiCache.grabbing) return false;
const target = uiCache.grabTarget;
let directlyGiven = false;
if (target) {
if (uiCache.grabKind === "tarinai") {
target.target = null;
@ -287,28 +310,36 @@
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.type === "balloon")) target.spinVelocity = clamp((target.spinVelocity || 0) + releaseVx * 0.018, -42, 42);
} else if ((target.type === "ball" || target.type === "balloon")) {
target.prevX = target.x;
target.prevY = target.y;
const releasePoint = screenToWorldClient(clientX, clientY);
const giveTarget = directFeedTargetAt(releasePoint, target);
const result = giveTarget
? global.TarinaiDirectFeedingSystem?.give?.(world, giveTarget, target, { source: "pinch" })
: null;
directlyGiven = Boolean(result);
if (!directlyGiven) {
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.type === "balloon")) target.spinVelocity = clamp((target.spinVelocity || 0) + releaseVx * 0.018, -42, 42);
} else if ((target.type === "ball" || target.type === "balloon")) {
target.prevX = target.x;
target.prevY = target.y;
}
}
}
if (uiCache.grabKind === "item") syncGrabbedPhysicsItem(target, "pinch-release");
if (uiCache.grabKind === "item" && !directlyGiven && !target.dead) syncGrabbedPhysicsItem(target, "pinch-release");
target.playerHeld = false;
target._heldByPlayer = false;
if (uiCache.grabKind === "tarinai") {
@ -317,22 +348,23 @@
target.impulseVx = 0;
target.impulseVy = 0;
target.pinchThoughtTimer = 0;
if (target.thought === "つままれている") target.thought = "";
if (target.thought === "\u3064\u307e\u307e\u308c\u3066\u3044\u308b") target.thought = "";
const behavior = typeof currentTarinaiBehavior === "function" ? currentTarinaiBehavior(target) : null;
const reason = String(behavior?.reason || behavior?.text || behavior?.label || "");
if (reason === "つままれている" && typeof clearBehavior === "function") clearBehavior(target);
if (reason === "\u3064\u307e\u307e\u308c\u3066\u3044\u308b" && typeof clearBehavior === "function") clearBehavior(target);
}
if (target.type === "duplicator") {
target.duplicatorLoadSuppressedUntil = Math.max(target.duplicatorLoadSuppressedUntil || 0, (world.time || 0) + 1.2);
}
}
audio.drop?.();
if (!directlyGiven) audio.drop?.();
uiCache.grabbing = false;
uiCache.grabTarget = null;
uiCache.grabKind = "";
uiCache.grabVelocityX = 0;
uiCache.grabVelocityY = 0;
uiCache.grabLastMoveAt = 0;
setGiveHover(null);
world.rebuildSpatial?.();
uiCache.grabLastSpatialAt = 0;
canvas.style.cursor = cursorForTool(world.tool);
@ -537,7 +569,10 @@
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);
const inactivePointerAction = !uiCache.grabbing && !uiCache.panning && !uiCache.hosing && !uiCache.areaDeleting && !uiCache.shooting;
const giveTarget = inactivePointerAction ? directFeedTargetAt(p) : null;
if (world.tool === "shoot") {
setGiveHover(null);
if (p.inside) {
if (world.shootCursorActive) {
const lastRawX = Number.isFinite(Number(world.shootPointerRawX)) ? Number(world.shootPointerRawX) : prevX;
@ -549,8 +584,14 @@
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) {
canvas.style.cursor = "none";
} else if (giveTarget) {
setGiveHover(giveTarget);
if (world.hoverGrabTarget) { world.hoverGrabTarget = null; world.drawListDirty = true; }
if (world.hoverDeleteTarget) { world.hoverDeleteTarget = null; world.drawListDirty = true; }
canvas.style.cursor = "pointer";
} else if (world.tool === "pinch" && p.inside && inactivePointerAction) {
setGiveHover(null);
const target = world.findGrabTargetAt ? world.findGrabTargetAt(p.x, p.y) : null;
if (world.hoverGrabTarget !== target) {
world.hoverGrabTarget = target || null;
@ -558,7 +599,8 @@
}
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) {
} else if (world.tool === "delete" && p.inside && inactivePointerAction) {
setGiveHover(null);
const target = world.findDeleteToolTargetAt ? world.findDeleteToolTargetAt(p.x, p.y) : null;
if (world.hoverDeleteTarget !== target) {
world.hoverDeleteTarget = target || null;
@ -567,6 +609,7 @@
if (world.hoverGrabTarget) { world.hoverGrabTarget = null; world.drawListDirty = true; }
canvas.style.cursor = target ? "pointer" : "default";
} else {
setGiveHover(null);
if (world.hoverGrabTarget) {
world.hoverGrabTarget = null;
world.drawListDirty = true;
@ -596,6 +639,7 @@
if (world) {
world.hoverGrabTarget = null;
world.hoverDeleteTarget = null;
world.hoverGiveTarget = null;
}
}