This commit is contained in:
33333-33333 2026-06-22 02:03:19 +09:00
commit e8f1d1db1e
60 changed files with 2417 additions and 612 deletions

View file

@ -344,7 +344,7 @@
if (!other || other === dead || other.dead) continue;
if (other.target === dead || other.target?.id === deadId) {
other.target = null;
if (["seek_friend", "panic", "fight", "intimidate"].includes(other.state)) other.state = "idle";
if (["seek_friend", "panic", "fight", "intimidate"].includes(other.state)) other.goIdle?.("参照していた相手がいなくなった");
changed = true;
}
if (other.panicTarget === dead || other.panicTarget?.id === deadId) { other.panicTarget = null; changed = true; }
@ -374,6 +374,7 @@
this.markFamilyTreeDirty("death");
}
}
this.notifyDeathToRelations?.(t, finalReason);
this.familyPrunePending = true;
},
@ -382,38 +383,12 @@
const family = this.family || {};
const nodes = Object.values(family).filter(Boolean).filter(n => n.hasPaired || (n.parents || []).length || (n.children || []).length);
if (!nodes.length) return;
const ids = new Set(nodes.map(n => n.id));
const graph = new Map();
const add = (id) => { if (!graph.has(id)) graph.set(id, new Set()); };
const link = (a, b) => {
if (!a || !b || !ids.has(a) || !ids.has(b)) return;
add(a); add(b);
graph.get(a).add(b);
graph.get(b).add(a);
};
for (const n of nodes) {
add(n.id);
for (const p of n.parents || []) link(n.id, p);
for (const c of n.children || []) link(n.id, c);
}
const seen = new Set();
const remove = [];
for (const n of nodes) {
if (seen.has(n.id)) continue;
const stack = [n.id];
const comp = [];
seen.add(n.id);
while (stack.length) {
const id = stack.pop();
comp.push(id);
for (const next of graph.get(id) || []) {
if (seen.has(next)) continue;
seen.add(next);
stack.push(next);
}
}
if (!comp.some(id => family[id]?.alive)) remove.push(...comp);
}
const components = globalThis.TarinaiFamilyGraph?.connectedComponents
? globalThis.TarinaiFamilyGraph.connectedComponents(nodes)
: [];
const remove = components.length
? components.filter(comp => !comp.some(n => family[n.id]?.alive)).flat().map(n => n.id)
: [];
if (!remove.length) return;
for (const id of remove) delete family[id];
this.familyVersion = (this.familyVersion || 0) + 1;
@ -455,9 +430,8 @@
b.birthRitualRole = 1;
a.birthRitualLeader = true;
b.birthRitualLeader = false;
a.state = b.state = "birth_ritual";
a.target = b;
b.target = a;
a.setActionState("birth_ritual", { target: b, reason: "近くで体をゆすっている" });
b.setActionState("birth_ritual", { target: a, reason: "近くで体をゆすっている" });
a.reproductionTimer = CONFIG.reproductionCooldown + rand(2, 10);
b.reproductionTimer = CONFIG.reproductionCooldown + rand(2, 10);
a.surpriseTimer = Math.max(a.surpriseTimer, 0.35);
@ -471,7 +445,8 @@
a.birthRitualTimer = b.birthRitualTimer = 0;
a.birthPartnerId = b.birthPartnerId = null;
a.birthRitualLeader = b.birthRitualLeader = false;
a.state = b.state = "idle";
a.goIdle("誕生の前ぶれが終わった");
b.goIdle("誕生の前ぶれが終わった");
if (reproductionBlockedByDisease || (!!a.isZunchiSlave !== !!b.isZunchiSlave)) {
a.birthRitualRole = b.birthRitualRole = 0;
return null;
@ -621,8 +596,7 @@
t.defeatedTimer = 0;
t.defeatedById = null;
t.fightWinnerId = null;
t.target = null;
t.state = "idle";
t.goIdle("");
}
this.startFightMochiIntimidation(a, b);
this.startFight(a, b);
@ -695,7 +669,7 @@
target.fightCooldown = CONFIG.fightCooldown + rand(1, 4);
actor.intimidateTimer = Math.max(actor.intimidateTimer, rand(2.45, 3.35));
actor.intimidateTargetId = target.id;
actor.state = "intimidate";
actor.setActionState("intimidate", { target, reason: "相手を威嚇している" });
this.effects.push(new Effect("ring", actor.x, actor.y - actor.radius * 0.65, {
life: 0.42,
size: actor.radius * 0.55,
@ -710,8 +684,8 @@
actor.intimidateTimer = 0;
actor.intimidateTargetId = null;
target.intimidatedTimer = 0;
if (actor.state === "intimidate") actor.state = "idle";
if (target.state === "panic") target.state = "idle";
if (actor.state === "intimidate") actor.goIdle("威嚇に失敗した");
if (target.state === "panic") target.goIdle("威嚇から戻った");
actor.spriteLockUntil = 0;
target.spriteLockUntil = 0;
this.startFight(actor, target);
@ -721,10 +695,9 @@
target.defeatedById = actor.id;
target.fightWinnerId = actor.id;
target.defeatedTimer = Math.max(target.defeatedTimer, rand(2.8, 4.2));
target.fearTimer = Math.max(target.fearTimer, 1.35 * target.personalityProfile().fear);
target.intimidatedTimer = Math.max(target.intimidatedTimer || 0, rand(2.4, 3.4));
target.state = "panic";
target.target = actor;
if (target.enterPanic) target.enterPanic({ threat: actor, target: actor, reason: "威嚇されて逃げている", fear: 1.35, wake: true, cause: "intimidated" });
else { target.fearTimer = Math.max(target.fearTimer, 1.35 * target.personalityProfile().fear); target.setActionState?.("panic", { target: actor, reason: "威嚇されて逃げている", wake: true }); }
this.spawnBubble(target.x, target.y - target.radius * 1.28, "\u306f\u3041\u3041\u3041\uff01", "rgba(84,66,86,0.80)");
target.vx += (target.x < actor.x ? -1 : 1) * rand(26, 54);
target.vy += rand(-18, 18);
@ -741,7 +714,8 @@
if (!a || !b || a.dead || b.dead) return;
if (!this.canFightPair(a, b) && !this.canFightPair(b, a)) return;
if ((a.postBirthPeaceTimer || 0) > 0 || (b.postBirthPeaceTimer || 0) > 0) return;
a.state = "fight"; b.state = "fight";
a.setActionState("fight", { target: b, reason: `${b.name || "相手"}と喧嘩している` });
b.setActionState("fight", { target: a, reason: `${a.name || "相手"}と喧嘩している` });
a.fightTimer = Math.max(a.fightTimer, rand(4.5, 7.0));
b.fightTimer = Math.max(b.fightTimer, rand(4.5, 7.0));
a.nextHeadbutt = this.time + rand(0.08, 0.18);