This commit is contained in:
33333-33333 2026-06-26 12:46:32 +09:00
commit 86226ccc94
97 changed files with 5790 additions and 2307 deletions

View file

@ -3,9 +3,20 @@
(function (global) {
const Tarinai = global.Tarinai;
if (!Tarinai) throw new Error("Tarinai is not available for mixin: tarinai_identity_social.js");
function relationIdSetFor(tarinai) {
const ids = new Set(Object.keys(tarinai?.relationships || {}));
for (const other of tarinai?.world?.tarinai || []) {
if (!other || other === tarinai || !other.id) continue;
if (other.relationships?.[tarinai.id]) ids.add(other.id);
}
return ids;
}
Object.defineProperties(Tarinai.prototype, Object.getOwnPropertyDescriptors({
get lack() {
return clamp((this.hunger + this.loneliness + this.stress + (100 - this.energy)) / 4, 0, 100);
const healthLack = 100 * (1 - (typeof tarinaiEnergyRatio === "function" ? tarinaiEnergyRatio(this) : clamp((this.energy || 0) / Math.max(1, this.maxEnergy || 100), 0, 1)));
return clamp((this.hunger + this.loneliness + this.stress + healthLack) / 4, 0, 100);
},
get mood() {
@ -152,14 +163,26 @@
rel.fightsLost = rel.fightsLost || 0;
if (event) { rel.lastEvent = event; rel.lastTime = this.world.time; }
this.relationCache = null;
const threshold = typeof FRIEND_AFFINITY_THRESHOLD === "number" ? FRIEND_AFFINITY_THRESHOLD : 14;
if (affinityDelta > 0 && rel.affinity >= threshold && other.relationTo) {
const reverse = other.relationTo(this.id);
const mirrored = Math.max(reverse.affinity || 0, threshold + 0.25, Math.min(rel.affinity, rel.affinity * 0.78));
reverse.affinity = clamp(mirrored, -24, 40);
reverse.fear = clamp(Math.min(reverse.fear || 0, rel.fear || 0), 0, 40);
if (event && !reverse.lastEvent) { reverse.lastEvent = event; reverse.lastTime = this.world?.time || other.world?.time || 0; }
other.relationCache = null;
}
},
strongestRelation(kind = "friend", liveOnly = true) {
let bestId = null;
let bestScore = kind === "fear" ? 5 : FRIEND_AFFINITY_THRESHOLD;
for (const [id, rel] of Object.entries(this.relationships || {})) {
for (const id of relationIdSetFor(this)) {
const rel = this.relationships?.[id] || relationDefaults();
if (liveOnly && (!this.world?.liveTarinaiById?.(id) || id === this.id)) continue;
const score = kind === "fear" ? (rel.fear || 0) : (rel.affinity || 0);
const other = this.world?.liveTarinaiById?.(id) || null;
const reverse = kind === "fear" ? null : (other?.relationships?.[this.id] || null);
const score = kind === "fear" ? (rel.fear || 0) : Math.max(rel.affinity || 0, reverse?.affinity || 0);
if (score > bestScore) { bestId = id; bestScore = score; }
}
return bestId ? { id: bestId, score: bestScore, name: relationDisplayName(this.world, bestId) } : null;
@ -176,9 +199,12 @@
const cacheKey = `${minScore}:${liveOnly ? 1 : 0}`;
if (this.relationCache?.friendCountKey === cacheKey && now < (this.relationCache.friendCountUntil || 0)) return this.relationCache.friendCount;
let count = 0;
for (const [id, rel] of Object.entries(this.relationships || {})) {
if ((rel.affinity || 0) <= minScore) continue;
if (liveOnly && (!this.world?.liveTarinaiById?.(id) || id === this.id)) continue;
for (const id of relationIdSetFor(this)) {
const rel = this.relationships?.[id] || relationDefaults();
const other = this.world?.liveTarinaiById?.(id) || null;
const reverse = other?.relationships?.[this.id] || null;
if (Math.max(rel.affinity || 0, reverse?.affinity || 0) <= minScore) continue;
if (liveOnly && (!other || id === this.id)) continue;
count += 1;
}
this.relationCache = { ...(this.relationCache || {}), friendCountKey: cacheKey, friendCount: count, friendCountUntil: now + 1.4 };
@ -198,10 +224,12 @@
if (cached && (!Number.isFinite(maxDist) || dist(this, cached) <= maxDist)) return cached;
}
let best = null, bestScore = minScore;
for (const [id, rel] of Object.entries(this.relationships || {})) {
const score = rel.affinity || 0;
if (score <= bestScore) continue;
for (const id of relationIdSetFor(this)) {
const rel = this.relationships?.[id] || relationDefaults();
const t = this.world.liveTarinaiById?.(id) || null;
const reverse = t?.relationships?.[this.id] || null;
const score = Math.max(rel.affinity || 0, reverse?.affinity || 0);
if (score <= bestScore) continue;
if (!t) continue;
if (Number.isFinite(maxDist) && dist(this, t) > maxDist) continue;
best = t;
@ -294,7 +322,9 @@
recoverHealth(amount) {
if (this.dead) return;
this.energy = clamp(this.energy + Math.max(0, amount || 0), 0, 100);
const maxEnergy = typeof tarinaiMaxEnergy === "function" ? tarinaiMaxEnergy(this) : (Number(this.maxEnergy) || 100);
this.maxEnergy = maxEnergy;
this.energy = clamp((this.energy || 0) + Math.max(0, amount || 0), 0, maxEnergy);
},
familyJoined() {