"use strict"; const HEALTH = (() => { const MAJOR_DAMAGE_WINDOW = 24; const WEAKENED_TRACE_WINDOW = 45; const WEAKENED_SUFFIX = "\u3067\u8870\u5f31"; const CAUSES = Object.freeze({ fight: "\u55a7\u5629", hunger: "\u98e2\u9913", stress: "\u30b9\u30c8\u30ec\u30b9\u904e\u591a", poke: "\u3064\u3064\u304b\u308c\u3059\u304e", firecracker: "\u7206\u7af9", genkotsu: "\u3052\u3093\u3053\u3064", accident: "\u4e8b\u6545", collision: "\u885d\u7a81", outOfBounds: "\u4ed5\u69d8\u306b\u3088\u308a\u753b\u9762\u5916\u3067\u524a\u9664", lifespan: "\u5929\u5bff\u3092\u5168\u3046\u3057\u305f", sleepDisease: "\u306d\u3080\u308a\u75c5", explosionDisease: "\u7206\u767a\u75c5", fightDisease: "\u304d\u305a\u3064\u304d\u75c5", zunchiDisease: "\u305a\u3093\u3061\u75c5", antEaten: "\u30a2\u30ea\u306b\u98df\u3079\u3089\u308c\u305f", giantDrug: "\u5de8\u5927\u85ac", dwarfDrug: "\u77ee\u5c0f\u85ac", }); const DISEASE_RE = /([^\u3001\u3002\s]+\u75c5)/; function causeLabel(reason = "") { const text = String(reason || ""); if (!text) return ""; if (text.includes(WEAKENED_SUFFIX)) return text.replace(/\u3067\u8870\u5f31.*$/, ""); if (/\u55a7\u5629|fight|headbutt/.test(text)) return CAUSES.fight; if (/\u3052\u3093\u3053\u3064|genkotsu/.test(text)) return CAUSES.genkotsu; if (/\u5de8\u5927\u85ac|giant/.test(text)) return CAUSES.giantDrug; if (/\u77ee\u5c0f\u85ac|dwarf/.test(text)) return CAUSES.dwarfDrug; if (/\u7206\u7af9|firecracker|explosion/.test(text)) return CAUSES.firecracker; if (/\u4ed5\u69d8\u306b\u3088\u308a\u753b\u9762\u5916\u3067\u524a\u9664|\u753b\u9762\u5916\u3067\u524a\u9664|out.*bounds|offscreen/.test(text)) return CAUSES.outOfBounds; if (/\u885d\u7a81|collision/.test(text)) return CAUSES.collision; if (/\u3064\u3064\u304b\u308c|\u3064\u3064\u304d|poke/.test(text)) return CAUSES.poke; if (/\u306d\u3080\u308a\u75c5|sleep.*disease/.test(text)) return CAUSES.sleepDisease; if (/\u7206\u767a\u75c5|explosion.*disease/.test(text)) return CAUSES.explosionDisease; if (/\u3051\u3093\u304b\u75c5|\u304d\u305a\u3064\u304d\u75c5|fight.*disease/.test(text)) return CAUSES.fightDisease; if (/\u305a\u3093\u3061\u75c5|zunchi_sick|zunchi.*\u75c5/.test(text)) return CAUSES.zunchiDisease; if (/\u30a2\u30ea\u306b\u98df\u3079\u3089\u308c\u305f|eaten.*ant|ant.*eaten/.test(text)) return CAUSES.antEaten; if (/\u75c5/.test(text)) { const disease = text.match(DISEASE_RE); return disease ? disease[1] : CAUSES.zunchiDisease; } if (/\u98e2|\u7a7a\u8179|\u98df\u3079\u7269|hunger/.test(text)) return CAUSES.hunger; if (/\u30b9\u30c8\u30ec\u30b9|stress/.test(text)) return CAUSES.stress; if (/\u30dc\u30fc\u30eb|\u843d\u3061|\u843d\u4e0b|\u77f3|\u9053\u5177|\u4e8b\u6545|\u5f53\u305f|ball|drop|stone|accident/.test(text)) return CAUSES.accident; if (/\u5bff\u547d|\u5929\u5bff/.test(text)) return CAUSES.lifespan; return ""; } function recentDamageCause(t, maxAge = MAJOR_DAMAGE_WINDOW) { const now = t.world?.time || 0; if (t.lastDamageCause && now - (t.lastDamageAt || -999) <= maxAge) return t.lastDamageCause; return ""; } function rememberDamage(t, amount, reason = "") { const cause = causeLabel(reason) || CAUSES.accident; const now = t.world?.time || 0; t.lastDamageCause = cause; t.lastDamageAmount = Math.max(0, amount || 0); t.lastDamageAt = now; if (t.lastDamageAmount >= 6 || t.lastDamageAmount >= Math.max(4, (t.energy || 0) * 0.22)) { t.lastMajorDamageCause = cause; t.lastMajorDamageAmount = t.lastDamageAmount; t.lastMajorDamageAt = now; } return cause; } function weakenedDeathReasonFor(cause = "") { const text = String(cause || "").trim(); if (!text) return ""; return text.includes(WEAKENED_SUFFIX) ? text : `${text}${WEAKENED_SUFFIX}`; } function hasRecentMajorDamage(t) { const now = t.world?.time || 0; return Boolean(t.lastMajorDamageCause && now - (t.lastMajorDamageAt || -999) <= MAJOR_DAMAGE_WINDOW); } function isFightingContext(t, recent) { return Boolean(t.fightTimer > 0.04 || t.defeatedTimer > 0.04 || t.defeatedById || t.fightWinnerId || recent === CAUSES.fight); } function dominantDeathCause(t, reason = "", opts = {}) { const text = String(reason || "").trim(); const direct = causeLabel(text); const recentMajor = hasRecentMajorDamage(t); const recent = recentDamageCause(t, 20); const fighting = isFightingContext(t, recent); if (recentMajor && t.lastMajorDamageCause === CAUSES.collision) return CAUSES.collision; if (recentMajor && (!direct || direct === t.lastMajorDamageCause || opts.fromDamage || t.energy <= 18 || t.mood <= 16 || t.stress >= 124 || t.hunger >= 112)) { return weakenedDeathReasonFor(t.lastMajorDamageCause); } const weakenedTrace = recentDamageCause(t, WEAKENED_TRACE_WINDOW); const traceCanWeaken = weakenedTrace && weakenedTrace !== CAUSES.stress && weakenedTrace !== CAUSES.hunger && weakenedTrace !== CAUSES.lifespan && weakenedTrace !== CAUSES.outOfBounds; if (traceCanWeaken && (!direct || direct === CAUSES.stress || direct === CAUSES.hunger || direct === weakenedTrace || opts.fromDamage) && (t.energy <= 20 || t.mood <= 16 || t.stress >= 124 || t.hunger >= 114)) { return weakenedDeathReasonFor(weakenedTrace); } if (direct && direct !== CAUSES.stress) return direct; if (t.zunchiDisease && ((t.zunchiDiseaseSeverity || 0) >= 0.30 || /\u75c5|zunchi/.test(text))) return CAUSES.zunchiDisease; if (t.hunger >= 108 || (t.hunger >= 94 && t.energy <= 26) || /\u98e2|\u7a7a\u8179|hunger/.test(text)) return CAUSES.hunger; if (fighting && (t.energy <= 44 || t.stress >= 112 || t.mood <= 22 || opts.fromDamage)) return CAUSES.fight; if (recent && recent !== CAUSES.stress && (t.energy <= 22 || t.mood <= 14 || t.stress >= 126 || opts.fromDamage)) return weakenedDeathReasonFor(recent); if (text.includes(CAUSES.lifespan) || text.includes("\u5bff\u547d")) return CAUSES.lifespan; if (direct) return direct; if (t.stress >= 118 || /\u30b9\u30c8\u30ec\u30b9|stress|\u6c17\u5206/.test(text)) return CAUSES.stress; if (t.energy <= 0.5) return CAUSES.accident; return ""; } function normalizeDeathReason(t, reason = "", opts = {}) { const text = String(reason || "").trim(); if (text.includes(WEAKENED_SUFFIX)) return text; const cause = dominantDeathCause(t, text, opts) || CAUSES.accident; if (cause.includes(WEAKENED_SUFFIX)) return cause; const canWeaken = cause && !cause.endsWith("\u75c5") && cause !== CAUSES.hunger && cause !== CAUSES.stress && cause !== CAUSES.lifespan && cause !== CAUSES.outOfBounds && cause !== CAUSES.collision && cause !== CAUSES.genkotsu; if (canWeaken && (opts.weakened || (hasRecentMajorDamage(t) && cause === t.lastMajorDamageCause))) return weakenedDeathReasonFor(cause); return cause; } function applyDamage(t, amount, reason = "") { const before = t.energy; const loss = Math.max(0, amount || 0); t.energy = clamp(t.energy - loss, 0, 100); const actualLoss = Math.max(0, before - t.energy); let cause = ""; if (actualLoss > 0.01) { cause = rememberDamage(t, actualLoss, reason); t.world?.emit?.("tarinai:damaged", { tarinai: t, amount: actualLoss, cause, reason }); if (cause === CAUSES.fight || /\u55a7\u5629|fight/.test(String(reason || ""))) t.recordBleedExposure(); audio.damage?.(actualLoss); if (t.sleepDisease) t.recoverSleepDisease("\u30c0\u30e1\u30fc\u30b8\u3067\u306d\u3080\u308a\u75c5\u304c\u6cbb\u3063\u305f"); if (t.wakeFromDamage) t.wakeFromDamage(cause || reason); if (t.maybeBecomeTimidAfterDamage) t.maybeBecomeTimidAfterDamage(cause || reason); t.showHpBar(); } if (t.energy <= 0.5) { const majorNow = actualLoss >= Math.max(10, before * 0.42); t.die(normalizeDeathReason(t, reason || cause, { fromDamage: true, weakened: majorNow })); } } function briefDeathReason(t, reason = t.deathReason) { const text = String(reason || ""); if (!text) return ""; const normalized = normalizeDeathReason(t, text); return normalized.length > 12 ? `${normalized.slice(0, 12)}\u2026` : normalized; } return Object.freeze({ MAJOR_DAMAGE_WINDOW, WEAKENED_TRACE_WINDOW, CAUSES, causeLabel, recentDamageCause, rememberDamage, weakenedDeathReasonFor, dominantDeathCause, normalizeDeathReason, applyDamage, briefDeathReason, }); })(); window.HEALTH = HEALTH;