This commit is contained in:
33333-33333 2026-06-30 13:40:36 +09:00
commit ad2cc76429
34 changed files with 616 additions and 365 deletions

View file

@ -4,6 +4,22 @@
(function (global) {
const Tarinai = global.Tarinai;
if (!Tarinai) throw new Error("Tarinai is not available for mixin: tarinai_social_move_life.js");
function fightHeadbuttDamage(attacker, target, worldRef, salt = "") {
const profile = attacker?.personalityProfile?.() || {};
const aggression = Number(profile.aggression || 1) || 1;
const fear = Number(profile.fear || 1) || 1;
const stress = Number(attacker?.stress || 0) || 0;
const mood = Number(attacker?.mood || 50) || 50;
const personalityCorrection = (aggression - 1) * 4.0 - (fear - 1) * 1.8;
const stateCorrection = clamp((stress - 50) * 0.035 + (50 - mood) * 0.020, -3.2, 4.2);
const typeCorrection = attacker?.type === "angry" ? 2.0 : (attacker?.type === "teary" ? -1.2 : 0);
const drugCorrection = (attacker?.fightMochiTimer || 0) > 0.04 ? 3.0 : 0;
const jitter = deterministicRange(worldRef, `headbutt-damage-jitter-${salt}`, -1.4, 1.4, attacker, target);
const base = 15;
const raw = Math.max(1, base + personalityCorrection + stateCorrection + typeCorrection + drugCorrection + jitter);
return attacker?.outgoingDamage ? attacker.outgoingDamage(raw) : raw;
}
Object.defineProperties(Tarinai.prototype, Object.getOwnPropertyDescriptors({
interactWithOthers(dt) {
let closeCount = 0;
@ -133,8 +149,8 @@
o.vy += ny * deterministicRange(this.world, "headbutt-other-y", 34, 64, this, o);
if (typeof applyNeedShock === "function") applyNeedShock(this, { safety: 8, health: 4 });
if (typeof applyNeedShock === "function") applyNeedShock(o, { safety: 12, health: 6 });
const damageToThis = o.outgoingDamage ? o.outgoingDamage(1.2) : 1.2;
const damageToOther = this.outgoingDamage ? this.outgoingDamage(1.6) : 1.6;
const damageToThis = fightHeadbuttDamage(o, this, this.world, "to-this");
const damageToOther = fightHeadbuttDamage(this, o, this.world, "to-other");
this.world.emit?.("fight:hit", { attacker: o, target: this, amount: damageToThis, cause: "\u55a7\u5629" });
this.world.emit?.("fight:hit", { attacker: this, target: o, amount: damageToOther, cause: "\u55a7\u5629" });
this.damage(damageToThis, "\u55a7\u5629");
@ -155,57 +171,29 @@
this.world.maybeDefeatFromFightDamage?.(o, this, Math.max(damageToOther, 2.4));
}
this.world.spawnHeadbuttEffect((this.x + o.x) / 2, (this.y + o.y) / 2 - 5);
this.nextHeadbutt = this.world.time + deterministicRange(this.world, "next-headbutt", 0.34, 0.55, this, o);
this.nextHeadbutt = this.world.time + deterministicRange(this.world, "next-headbutt", 0.28, 0.46, this, o);
}
}
const relA = this.relationTo(o.id);
const relB = o.relationTo(this.id);
const battleDrug = this.hasFightMochiEffect() || o.hasFightMochiEffect();
const loveDrug = this.hasLoveMochiEffect() || o.hasLoveMochiEffect();
const aggressiveThis = this.shouldApplyPersonalityBehavior("aggression", 1);
const aggressiveOther = o.shouldApplyPersonalityBehavior?.("aggression", 1);
const calmThis = this.shouldApplyPersonalityBehavior("aggression", -1);
const calmOther = o.shouldApplyPersonalityBehavior?.("aggression", -1);
const fightRisk = (this.stress > 46 || o.stress > 46 || (this.needs?.safety || 0) > 60 || (o.needs?.safety || 0) > 60 || this.type === "angry" || o.type === "angry" || closeCount > 3 || aggressiveThis || aggressiveOther || battleDrug || o.isZunchiSlave || this.isZunchiSlave);
const fearBrake = battleDrug ? clamp(1 - ((relA.fear || 0) + (relB.fear || 0)) / 220, 0.74, 1.15) : clamp(1 - ((relA.fear || 0) + (relB.fear || 0)) / 120, 0.34, 1);
const friendBrake = battleDrug ? clamp(1 - Math.max(relA.affinity || 0, relB.affinity || 0) / 180, 0.72, 1.12) : clamp(1 - Math.max(relA.affinity || 0, relB.affinity || 0) / 90, 0.48, 1);
const personalityRisk = this.personalityProfile().fight * o.personalityProfile().fight * (calmThis ? 0.62 : 1) * (calmOther ? 0.62 : 1);
const conflictBias = (battleDrug ? 2.9 : 1) * (o.isZunchiSlave ? 2.2 : 1) * (this.isZunchiSlave ? 1.15 : 1);
const birthPeace = (this.postBirthPeaceTimer || 0) > 0 || (o.postBirthPeaceTimer || 0) > 0;
const familyFightBlocked = this.world.areParentChild ? this.world.areParentChild(this, o) : false;
const pairFightBlocked = this.world.areCoParents ? this.world.areCoParents(this, o) : false;
// regression guard baseline: dt * (battleDrug ? 0.23 : 0.085)
const fightStartChance = dt * (battleDrug ? 0.28 : 0.16) * personalityRisk * fearBrake * friendBrake * conflictBias;
if (this.world.canFightPair?.(this, o) && d < 56 && !familyFightBlocked && !pairFightBlocked && !birthPeace && fightRisk && this.fightCooldown <= 0 && o.fightCooldown <= 0 && deterministicChance(this.world, "social-fight-start", fightStartChance, this, o)) {
this.conflictTargetId = o.id;
o.conflictTargetId = this.id;
const urge = 34 + (battleDrug ? 34 : 0) + (mixedZunchiSlave ? 10 : 0);
this.conflictUrge = Math.max(this.conflictUrge || 0, urge);
o.conflictUrge = Math.max(o.conflictUrge || 0, urge * 0.82);
if (typeof applyNeedShock === "function") applyNeedShock(this, { social: dt * urge * (battleDrug ? 0.32 : 0.18), safety: dt * (battleDrug ? 4 : 0.9) }, o);
if (typeof applyNeedShock === "function") applyNeedShock(o, { social: dt * urge * (battleDrug ? 0.24 : 0.14), safety: dt * (battleDrug ? 4 : 0.9) }, this);
}
const compatibleBirthStatus = this.isZunchiSlave === o.isZunchiSlave;
if (compatibleBirthStatus && !this.sleepDisease && !o.sleepDisease && !this.fightDisease && !o.fightDisease && d < (loveDrug ? 52 : 42) && this.reproductionTimer <= 0 && o.reproductionTimer <= 0 && this.fightTimer <= 0 && o.fightTimer <= 0) {
const enough = loveDrug ? (this.hunger < 90 && o.hunger < 92 && this.energy > 18 && o.energy > 18) : (this.hunger < 55 && o.hunger < 60 && this.energy > 44 && o.energy > 44);
const lonelyBond = loveDrug ? (this.loneliness > 4 || o.loneliness > 4 || this.affection > 0 || o.affection > 0) : (this.loneliness > 24 || o.loneliness > 24);
if (enough && lonelyBond) {
const weights = socialFightMateWeights(this, o, this.world, { mode: "contact", requireBirthReady: true, distance: d, fightRange: 58 });
const combinedStartChance = dt * 0.30 * clamp((weights.totalWeight || 0) / 10, 0, 2.6);
if ((weights.totalWeight || 0) > 0 && deterministicChance(this.world, "social-weighted-fight-mate-start", combinedStartChance, this, o)) {
const choice = pickSocialFightMate(this.world, "social-weighted-fight-mate-pick", weights, this, o);
if (choice === "fight") {
this.conflictTargetId = o.id;
o.conflictTargetId = this.id;
const urge = 26 + Math.min(64, weights.fightWeight * 4.5) + (mixedZunchiSlave ? 10 : 0);
this.conflictUrge = Math.max(this.conflictUrge || 0, urge);
o.conflictUrge = Math.max(o.conflictUrge || 0, urge * 0.82);
if (typeof applyNeedShock === "function") applyNeedShock(this, { social: dt * urge * 0.18, safety: dt * 1.0 }, o);
if (typeof applyNeedShock === "function") applyNeedShock(o, { social: dt * urge * 0.14, safety: dt * 1.0 }, this);
this.world.startConflict?.(this, o);
} else if (choice === "mate") {
if (typeof applyNeedShock === "function") {
applyNeedShock(this, { social: dt * (loveDrug ? 34 : 14) }, o);
applyNeedShock(o, { social: dt * (loveDrug ? 34 : 14) }, this);
}
if (loveDrug && typeof queueForcedTarinaiBehavior === "function") {
queueForcedTarinaiBehavior(this, "approach_mate", { target: o, source: "love_mochi", priority: 150, ttl: 10, causeText: "\u3078\u3053\u9905\u306e\u52b9\u679c" });
queueForcedTarinaiBehavior(o, "approach_mate", { target: this, source: "love_mochi", priority: 150, ttl: 10, causeText: "\u3078\u3053\u9905\u306e\u52b9\u679c" });
}
const selfBehaviorId = getTarinaiBehaviorId(this);
const otherBehaviorId = getTarinaiBehaviorId(o);
const mateIntent = selfBehaviorId === "approach_mate" || otherBehaviorId === "approach_mate" || loveDrug;
if (mateIntent && deterministicChance(this.world, "birth-ritual-start", dt * (loveDrug ? 0.78 : 0.30), this, o)) {
this.world.startBirthRitual(this, o);
applyNeedShock(this, { social: dt * 18 }, o);
applyNeedShock(o, { social: dt * 18 }, this);
}
this.world.startBirthRitual?.(this, o);
}
}
}
@ -535,7 +523,7 @@
temperatureDeathReason() {
const status = this.temperatureStatus || this.world?.temperatureStatusFor?.(this.feltTemperature ?? this.tempComfort ?? (CONFIG.standardTemperature ?? 15)) || null;
const status = this.temperatureStatus || this.world?.temperatureStatusFor?.(this.feltTemperature ?? this.tempComfort ?? (CONFIG.standardTemperature ?? 15), this) || null;
const recent = (this.world?.time || 0) - Number(this.lastTemperatureDamageAt || -999) <= 36;
if (recent && status && (status.harmExcess || 0) > 0) return status.direction === "cold" ? "凍結" : "熱中症";
return "";