"use strict"; (function (global) { const ImpactCore = global.TarinaiImpactCoreSystem; const PHYSICAL_DAMAGE_SPEED_THRESHOLD = ImpactCore.PHYSICAL_DAMAGE_SPEED_THRESHOLD || 165; const physicalDamageFromImpactSpeed = ImpactCore.physicalDamageFromImpactSpeed; function itemDropImpact(worldRef, it) { if (!worldRef) return undefined; if (!it || it.dead || it.type === "water") return; const isStone = it.type === "stone"; const isGenkotsu = it.type === "genkotsu"; const dropFallHeight = isGenkotsu ? Math.max(360, (it.r || 88) * 5.8) : 170; const dropDuration = Math.max(0.08, Number(it.dropMax || 0.42) || 0.42); const impactSpeed = dropFallHeight / dropDuration; const radius = Math.max(32, Math.min(220, (it.r || 14) * 1.35 + impactSpeed * 0.055)); const damage = physicalDamageFromImpactSpeed(impactSpeed, { min: 1.2, max: isGenkotsu ? 58 : 34, scale: 8.6 }); const push = clamp((impactSpeed - 120) * 0.62, 42, isGenkotsu ? 1040 : 260); const reason = isGenkotsu ? "\u3052\u3093\u3053\u3064" : (isStone ? "\u77f3\u306b\u6f70\u3055\u308c\u305f" : (impactSpeed >= PHYSICAL_DAMAGE_SPEED_THRESHOLD ? "\u9ad8\u901f\u3067\u843d\u3061\u3066\u304d\u305f\u9053\u5177\u306b\u885d\u7a81" : "\u843d\u3061\u3066\u304d\u305f\u9053\u5177\u306b\u5f53\u305f\u3063\u305f")); if (isGenkotsu) { worldRef.lastGenkotsuAt = worldRef.time || 0; it.impactFlash = 1; it.lingerTimer = Math.max(it.lingerDuration || 2, 2); worldRef.triggerGroundShake?.(2.0, 10); } let hit = 0; for (const t of worldRef.nearbyTarinai(it.x, it.y, radius + 54)) { if (!t || t.dead || worldRef.isTarinaiHiddenInNestBox(t)) continue; const d = Math.max(1, distXY(t.x, t.y, it.x, it.y)); const p = clamp(1 - d / (radius + t.radius), 0, 1); if (p <= 0) continue; let nx = (t.x - it.x) / d; let ny = (t.y - it.y) / d; if (!Number.isFinite(nx) || !Number.isFinite(ny) || Math.abs(nx) + Math.abs(ny) < 0.001) { const a = deterministicAngle(worldRef, "drop-impact-overlap-normal", it, t); nx = Math.cos(a); ny = Math.sin(a); } t.vx += nx * push * (0.35 + p); t.vy += ny * push * (0.35 + p) - Math.min(210, push * 0.22) * p; const dealtDamage = damage * (0.35 + p * 0.65); if (dealtDamage > 0) t.damage(dealtDamage, reason, { source: it }); if (isGenkotsu) { t.fearTimer = Math.max(t.fearTimer || 0, 4.0 + p * 2.2); if (typeof applyNeedShock === "function") applyNeedShock(t, { safety: 18 + p * 30, health: 8 + p * 15 }); t.adjustPersonality?.("openness", -(0.020 + p * 0.030), "after being struck by genkotsu."); t.thought = "\u3052\u3093\u3053\u3064\u304c\u3053\u308f\u3044"; } else { t.thought = isStone ? "\u77f3\u304c\u843d\u3061\u3066\u304d\u3066\u30d1\u30cb\u30c3\u30af\u306b\u306a\u3063\u3066\u3044\u308b" : "\u843d\u3061\u3066\u304d\u305f\u9053\u5177\u306b\u5f53\u305f\u3063\u3066\u6df7\u4e71\u3057\u3066\u3044\u308b"; } t.hurtTimer = Math.max(t.hurtTimer, isGenkotsu ? 3.4 : (isStone ? 2.7 : 1.25)); t.fallTimer = Math.max(t.fallTimer, isGenkotsu ? 0.86 : (isStone ? 0.62 : 0.26)); t.fallMax = Math.max(t.fallMax || t.fallTimer, t.fallTimer); t.fallDir = nx >= 0 ? 1 : -1; hit += 1; } let ballHit = 0; if (isGenkotsu && (worldRef.itemCounts?.ball || worldRef.itemCounts?.balloon)) { const ballRange = radius + Math.max(72, (it.r || 88) * 0.78); const balls = worldRef.nearbyNonGrassItems?.(it.x, it.y, ballRange + 42, true) || worldRef.items || []; for (const ball of balls) { if (!ball || ball.dead || (ball.type !== "ball" && ball.type !== "balloon")) continue; const d = Math.max(1, distXY(ball.x, ball.y, it.x, it.y)); const p = clamp(1 - d / (ballRange + (ball.r || 18)), 0, 1); if (p <= 0) continue; if (ball.type === "balloon") { globalThis.TarinaiItemDynamicBallSystem?.popBalloon?.(ball, worldRef, it); ballHit += 1; continue; } let nx = (ball.x - it.x) / d; let ny = (ball.y - it.y) / d; if (!Number.isFinite(nx) || !Number.isFinite(ny) || Math.abs(nx) + Math.abs(ny) < 0.001) { const a = deterministicAngle(worldRef, "genkotsu-ball-impact-normal", it, ball); nx = Math.cos(a); ny = Math.sin(a); } const ballPush = clamp(push * (0.44 + p * 0.86), 160, 1080); ball.prevX = Number.isFinite(ball.x) ? ball.x : (ball.prevX || 0); ball.prevY = Number.isFinite(ball.y) ? ball.y : (ball.prevY || 0); ball.vx = clamp((ball.vx || 0) + nx * ballPush, -1180, 1180); ball.vy = clamp((ball.vy || 0) + ny * ballPush - Math.min(180, ballPush * 0.12) * p, -1180, 1180); ball.spinVelocity = clamp((ball.spinVelocity || 0) + (nx >= 0 ? 1 : -1) * (10 + p * 12), -48, 48); ball.lastPokedAt = worldRef.time || 0; ballHit += 1; worldRef.effects?.push(new Effect("ring", ball.x, ball.y, { size: Math.max(18, (ball.r || 18) * 1.1), life: 0.20, color: "rgba(255,255,255,0.52)" })); } if (ballHit > 0) worldRef.markSpatialDirty?.("genkotsu-ball-impact"); } const antHit = damage > 0 ? worldRef.damageAntsInRadius(it.x, it.y, radius + 54, p => damage * (0.35 + p * 0.65), reason, { push: p => push * (0.62 + p * 1.25), source: it, }) : 0; if (isGenkotsu) { worldRef.blastZunchiFrom?.(it.x, it.y, radius + 92, 2.75, { limit: 96, effectLimit: 6 }); worldRef.blastLoosePinsFrom?.(it.x, it.y, radius + 92, it, 2.75, "genkotsu-impact"); const existingEffects = (worldRef.effects || []).length; const ringCount = existingEffects > 180 ? 2 : 3; const burstCount = existingEffects > 180 ? 4 : 7; for (let r = 0; r < ringCount; r++) worldRef.spawnEffect("ring", it.x, it.y, { size: 32 + r * 42, life: 0.32 + r * 0.07, color: r % 2 ? "rgba(255,203,54,0.68)" : "rgba(74,57,42,0.38)" }); for (let i = 0; i < burstCount; i++) worldRef.spawnEffect("fight", it.x + deterministicRange(worldRef, "genkotsu-impact-effect-x", -38, 38, it, i), it.y + deterministicRange(worldRef, "genkotsu-impact-effect-y", -22, 28, it, i), { size: deterministicRange(worldRef, "genkotsu-impact-effect-size", 12, 22, it, i), life: deterministicRange(worldRef, "genkotsu-impact-effect-life", 0.22, 0.42, it, i), color: "rgba(255,205,46,0.78)" }); } else { worldRef.spawnEffect("ring", it.x, it.y, { size: isStone ? 32 : 18, life: 0.34, color: isStone ? "rgba(128,96,58,0.76)" : "rgba(174,128,70,0.52)" }); } if (hit > 0 || antHit > 0 || isGenkotsu) worldRef.spawnFallEffect(it.x, it.y + (it.r || 12) * 0.6, isGenkotsu ? 1.32 : (isStone ? 0.9 : 0.45)); if (isGenkotsu) audio.genkotsuImpact?.(); else if (isStone) audio.stoneImpact?.(); else if (hit > 0 || antHit > 0) audio.poke?.(); else audio.drop?.(); if (hit > 0 || antHit > 0) { const label = isGenkotsu ? "\u3052\u3093\u3053\u3064" : (isStone ? "\u77f3" : "\u9053\u5177"); const victims = []; if (hit > 0) victims.push(`${hit}\u5339\u306e\u305f\u308a\u306a\u3044`); if (antHit > 0) victims.push(`${antHit}\u5339\u306e\u30a2\u30ea`); worldRef.log(`${label}\u304c\u843d\u3061\u3001${victims.join("\u3068")}\u304c\u5dfb\u304d\u8fbc\u307e\u308c\u305f\u3002`, "accident"); } } global.TarinaiImpactResponseSystem = Object.freeze({ itemDropImpact, }); })(typeof window !== "undefined" ? window : globalThis);