This commit is contained in:
33333-33333 2026-06-21 22:29:00 +09:00
commit 0a6148c73f
67 changed files with 2653 additions and 1519 deletions

View file

@ -70,7 +70,6 @@
this.updateEffectCounts();
this.markTerrainDirty?.("reset");
this.rebuildSpatial(true);
this.log("\u305f\u308a\u306a\u3044\u3092\u89b3\u5bdf\u7bb1\u306b\u914d\u7f6e\u3057\u307e\u3057\u305f\u3002");
showToast("\u65b0\u3057\u3044\u89b3\u5bdf\u3092\u958b\u59cb\u3057\u307e\u3057\u305f\u3002");
syncTopButtons();
},
@ -130,6 +129,9 @@
const nextParents = uniqueIds(t.parents || []);
const nextChildren = uniqueIds(t.children || []);
const nextPersonalityTags = getPersonalityTraitTags(t);
const nextScale = Number.isFinite(t.scale) ? t.scale : (Number.isFinite(t.adultScale) ? t.adultScale : 0.28);
const nextAdultScale = Number.isFinite(t.adultScale) ? t.adultScale : nextScale;
const nextGrowth = Number.isFinite(t.growth) ? t.growth : 1;
if (!this.family[familyKey]) {
this.family[familyKey] = {
id: familyKey,
@ -142,6 +144,9 @@
parentNames: [...(t.parentNames || [])],
children: nextChildren,
birthTime: t.birthTime,
scale: nextScale,
adultScale: nextAdultScale,
growth: nextGrowth,
alive: !t.dead,
deathReason: t.deathReason || "",
};
@ -154,6 +159,9 @@
if (!sameList(entry.personalityTags, nextPersonalityTags)) changed = true;
if (entry.hasPaired !== !!t.hasPaired) changed = true;
if (entry.generation !== t.generation) changed = true;
if (Math.abs((Number(entry.scale) || 0) - nextScale) > 0.002) changed = true;
if (Math.abs((Number(entry.adultScale) || 0) - nextAdultScale) > 0.002) changed = true;
if (Math.abs((Number(entry.growth) || 0) - nextGrowth) > 0.02) changed = true;
if ((entry.deathReason || "") !== (t.deathReason || entry.deathReason || "")) changed = true;
if (entry.alive !== nextAlive) changed = true;
if (!sameList(entry.parents, nextParents)) changed = true;
@ -164,6 +172,9 @@
entry.personalityTags = nextPersonalityTags;
entry.alive = nextAlive;
entry.generation = t.generation;
entry.scale = nextScale;
entry.adultScale = nextAdultScale;
entry.growth = nextGrowth;
entry.hasPaired = !!t.hasPaired;
entry.deathReason = t.deathReason || entry.deathReason || "";
entry.parents = nextParents;
@ -220,6 +231,9 @@
parentNames: live?.parentNames ? [...live.parentNames] : [...(n.parentNames || [])],
children,
birthTime: live?.birthTime ?? n.birthTime ?? 0,
scale: Number.isFinite(live?.scale) ? live.scale : (Number.isFinite(n.scale) ? n.scale : (Number.isFinite(live?.adultScale) ? live.adultScale : (Number.isFinite(n.adultScale) ? n.adultScale : 0.28))),
adultScale: Number.isFinite(live?.adultScale) ? live.adultScale : (Number.isFinite(n.adultScale) ? n.adultScale : (Number.isFinite(live?.scale) ? live.scale : (Number.isFinite(n.scale) ? n.scale : 0.28))),
growth: Number.isFinite(live?.growth) ? live.growth : (Number.isFinite(n.growth) ? n.growth : 1),
alive: live ? !live.dead : n.alive !== false,
deathReason: live?.deathReason || n.deathReason || "",
};
@ -414,12 +428,13 @@
this.drawListDirty = true;
if (t.hasPaired || (t.parents || []).length || (t.children || []).length) this.recordFamily(t);
this.maxGeneration = Math.max(this.maxGeneration, t.generation);
this.emit?.("tarinai:born", { tarinai: t, source: opts.parents?.length ? "family" : "spawn" });
return t;
},
startBirthRitual(a, b) {
if (!a || !b || a.dead || b.dead) return false;
if (a.isZunchiSlave || b.isZunchiSlave) return false;
if (!!a.isZunchiSlave !== !!b.isZunchiSlave) return false;
if (this.areParentChild(a, b)) return false;
if (a.sleepDisease || b.sleepDisease || a.fightDisease || b.fightDisease) return false;
if (a.birthRitualTimer > 0.04 || b.birthRitualTimer > 0.04) return false;
@ -457,7 +472,7 @@
a.birthPartnerId = b.birthPartnerId = null;
a.birthRitualLeader = b.birthRitualLeader = false;
a.state = b.state = "idle";
if (reproductionBlockedByDisease) {
if (reproductionBlockedByDisease || (!!a.isZunchiSlave !== !!b.isZunchiSlave)) {
a.birthRitualRole = b.birthRitualRole = 0;
return null;
}
@ -526,29 +541,41 @@
},
spawnChild(a, b, index = 0, total = 1) {
const zunchiSlaveChild = !!(a.isZunchiSlave && b.isZunchiSlave);
const inherited = Math.random() < 0.56 ? a.type : b.type;
const mutation = Math.random() < 0.18 ? baseSpriteId() : inherited;
const childBirthPersonality = personalityFromParents(a, b);
const mutation = zunchiSlaveChild ? "zunchi_slave" : (Math.random() < 0.18 ? baseSpriteId() : inherited);
const childSeed = crypto.randomUUID ? crypto.randomUUID() : `${Date.now()}-${Math.random()}-${index}`;
const childGenetics = inheritedGenetics(a, b, childSeed);
const childAdultScale = adultScaleFromGenetics(childSeed, childGenetics);
const childBirthPersonality = zunchiSlaveChild ? zunchiSlavePersonalityValue() : personalityFromParents(a, b);
const child = this.addTarinai({
familyKey: childSeed,
type: mutation,
birthPersonality: childBirthPersonality,
currentPersonality: childBirthPersonality,
name: makeName(),
genetics: childGenetics,
adultScale: childAdultScale,
name: zunchiSlaveChild ? "\u305a\u3093\u3061\u3069\u308c\u3044" : makeName(),
isZunchiSlave: zunchiSlaveChild,
age: 0,
x: (a.x + b.x) / 2 + rand(-14, 14) + (index - (total - 1) / 2) * 18,
y: (a.y + b.y) / 2 + rand(-14, 14) + (total > 1 ? rand(-10, 10) : 0),
scale: rand(0.17, 0.23),
scale: scaleForGrowth(childAdultScale, 0),
hunger: rand(20, 40),
loneliness: rand(30, 56),
energy: rand(55, 95),
stress: rand(0, 14),
need: Math.random() < 0.6 ? pick([a.need, b.need]) : pick(NEEDS),
generation: Math.max(a.generation, b.generation) + 1,
lifeSpan: rand(1500, 2400),
lifeSpan: rand(1500, 2200) * (childGenetics.lifeSpanMul || 1),
parents: [this.tarinaiFamilyKey(a), this.tarinaiFamilyKey(b)],
parentNames: [a.name, b.name],
birthTime: this.time,
powerItemMode: "",
sizeItemMode: "",
lifeItemMode: "",
});
if (zunchiSlaveChild) child.becomeZunchiSlave?.({ birth: true });
this.maxGeneration = Math.max(this.maxGeneration, child.generation);
a.hasPaired = true;
b.hasPaired = true;
@ -654,8 +681,14 @@
if (!actor || !target || actor.dead || target.dead) return false;
if (actor.lowHealthSprite && actor.lowHealthSprite()) return false;
const fearLoad = (target.relationTo(actor.id).fear || 0) * 0.72 + target.personalityProfile().fear * 8;
const resistance = target.energy * 0.30 + target.mood * 0.16 + (target.shouldApplyPersonalityBehavior?.("aggression", 1) ? 5 : 0) + rand(-5, 5);
const successChance = clamp(0.62 + (actorScore - targetScore + fearLoad - resistance) / 76, 0.50, 0.96);
const actorAggression = Math.max(0, actor.currentPersonality?.aggression || 0);
const targetAggression = Math.max(0, target.currentPersonality?.aggression || 0);
const actorSize = actor.effectiveScale ? actor.effectiveScale() : (actor.scale || 0.28);
const targetSize = target.effectiveScale ? target.effectiveScale() : (target.scale || 0.28);
const sizeEdge = clamp((actorSize - targetSize) / 0.16, -1, 1);
const aggressionEdge = clamp(actorAggression - targetAggression * 0.55, -1, 1);
const resistance = target.energy * 0.30 + target.mood * 0.16 + targetAggression * 8 + (target.shouldApplyPersonalityBehavior?.("aggression", 1) ? 5 : 0) + rand(-5, 5);
const successChance = clamp(0.56 + (actorScore - targetScore + fearLoad - resistance) / 82 + aggressionEdge * 0.13 + sizeEdge * 0.16, 0.30, 0.96);
actor.surpriseTimer = Math.max(actor.surpriseTimer, 0.20);
target.surpriseTimer = Math.max(target.surpriseTimer, 0.32);
actor.fightCooldown = CONFIG.fightCooldown + rand(1, 4);
@ -672,9 +705,19 @@
target.intimidatedTimer = Math.max(target.intimidatedTimer || 0, rand(1.65, 2.45));
target.fearTimer = Math.max(target.fearTimer, 0.65 * target.personalityProfile().fear);
if (Math.random() >= successChance) {
actor.adjustPersonality?.("aggression", -0.018, "after failed intimidation");
target.adjustRelation(actor, -0.08, 0.22 * target.personalityProfile().fear, "intimidate");
actor.intimidateTimer = 0;
actor.intimidateTargetId = null;
target.intimidatedTimer = 0;
if (actor.state === "intimidate") actor.state = "idle";
if (target.state === "panic") target.state = "idle";
actor.spriteLockUntil = 0;
target.spriteLockUntil = 0;
this.startFight(actor, target);
return true;
}
actor.adjustPersonality?.("aggression", 0.018, "after successful intimidation");
target.defeatedById = actor.id;
target.fightWinnerId = actor.id;
target.defeatedTimer = Math.max(target.defeatedTimer, rand(2.8, 4.2));