tarinai/js/relation_event_system.js
2026-06-23 18:11:42 +09:00

86 lines
4.5 KiB
JavaScript

"use strict";
(function (global) {
const MAX_PENDING_LOSSES = 16;
function relationWithDead(observer, dead, worldRef) {
if (!observer || !dead || observer === dead) return "";
const deadFamily = worldRef?.tarinaiFamilyKey ? worldRef.tarinaiFamilyKey(dead) : (dead.familyKey || "");
const observerFamily = observer.familyKey || observer.archiveKey || observer.id || "";
const deadId = dead.id || dead.releasedLiveId || "";
const observerId = observer.id || observer.liveId || "";
if (deadFamily && (observer.parents || []).includes(deadFamily)) return "親";
if (deadFamily && (observer.children || []).includes(deadFamily)) return "子";
if (observerFamily && (dead.parents || []).includes(observerFamily)) return "子";
if (observerFamily && (dead.children || []).includes(observerFamily)) return "親";
const rel = deadId ? observer.relationships?.[deadId] : null;
const reverse = observerId ? dead.relationships?.[observerId] : null;
if ((rel?.affinity || 0) >= (global.FRIEND_AFFINITY_THRESHOLD || 14) || (reverse?.affinity || 0) >= (global.FRIEND_AFFINITY_THRESHOLD || 14)) return "友達";
return "";
}
function applyLiveDeathShock(observer, dead, relation, worldRef) {
const strong = relation === "親" || relation === "子";
if (observer.state === "sleep" || observer.state === "seek_bed") observer.goIdle?.("身近な個体の死に気づいた");
const stress = strong ? 18 : 11;
const fear = strong ? 2.1 : 1.45;
if (observer.enterPanic) observer.enterPanic({ threat: dead, reason: `${relation}が死んだ`, fear, stress, cause: "relation_death", bubble: "!!", bubbleColor: "rgba(60,50,68,0.82)" });
else {
observer.sleeping = false;
observer.setActionState?.("panic", { target: observer.panicDestination ? observer.panicDestination(dead) : null, reason: `${relation}が死んだ`, wake: true });
observer.fearTimer = Math.max(observer.fearTimer || 0, fear);
if (typeof applyNeedShock === "function") applyNeedShock(observer, { safety: stress * 1.6, social: stress * 1.4 });
observer.bubble?.("!!", 1.0, "rgba(60,50,68,0.82)");
}
observer.recordChangeCause?.(`${relation}の死亡`, "ストレス", { value: stress });
observer.addRecord?.(`${dead.name || "身近な個体"}の死に気づいてパニックになった。`, "death");
}
function notifyDeathToRelations(dead, reason = "") {
const worldRef = this || global.world;
if (!worldRef || !dead) return;
const deadFamily = worldRef.tarinaiFamilyKey ? worldRef.tarinaiFamilyKey(dead) : (dead.familyKey || "");
const deadId = dead.id || dead.releasedLiveId || "";
let liveHits = 0;
for (const other of worldRef.tarinai || []) {
if (!other || other === dead || other.dead) continue;
const relation = relationWithDead(other, dead, worldRef);
if (!relation) continue;
applyLiveDeathShock(other, dead, relation, worldRef);
liveHits += 1;
}
for (const entry of (global.TarinaiFreezeSystem?.frozenList?.(worldRef) || [])) {
const data = entry.data || entry;
const relation = relationWithDead(data, dead, worldRef);
if (!relation) continue;
if (!Array.isArray(entry.pendingLosses)) entry.pendingLosses = [];
const duplicate = entry.pendingLosses.some(l => (deadFamily && l.familyKey === deadFamily) || (deadId && l.liveId === deadId));
if (!duplicate) {
entry.pendingLosses.unshift({
relation,
name: dead.name || "たりない",
familyKey: deadFamily,
liveId: deadId,
reason: reason || dead.deathReason || "死亡",
time: worldRef.time || 0,
});
if (entry.pendingLosses.length > MAX_PENDING_LOSSES) entry.pendingLosses.length = MAX_PENDING_LOSSES;
}
}
if (liveHits) worldRef.log?.(`${dead.name || "たりない"}の死に、身近な個体が動揺した。`, "death", { participants: [dead] });
global.TarinaiFreezeSystem?.saveFrozenStore?.(worldRef);
global.TarinaiFreezeSystem?.renderFrozenPanel?.(worldRef);
}
function patchWorldPrototype() {
const apply = (proto) => { proto.notifyDeathToRelations = notifyDeathToRelations; };
if (global.TarinaiPatcher?.patchWorld?.("relationEvents", apply)) return;
const World = global.World;
if (!World) return;
apply(World.prototype);
}
global.TarinaiRelationEvents = { relationWithDead, applyLiveDeathShock, notifyDeathToRelations, patchWorldPrototype };
patchWorldPrototype();
})(typeof window !== "undefined" ? window : globalThis);