168 lines
11 KiB
JavaScript
168 lines
11 KiB
JavaScript
"use strict";
|
|
|
|
function fulfillPrimaryReason(tarinai, action = null) {
|
|
const behavior = typeof currentTarinaiBehavior === "function" ? currentTarinaiBehavior(tarinai) : tarinai?.behavior;
|
|
const actionId = action?.id || behavior?.actionId || "";
|
|
if (actionId === "build_grass_bed") return "\u5bdd\u5e8a\u304c\u307b\u3057\u3044";
|
|
if (actionId === "build_plushie") return "\u306c\u3044\u3050\u308b\u307f\u304c\u307b\u3057\u3044";
|
|
if (actionId === "return_owned_structure" || actionId === "hide_at_owned_structure") return "\u81ea\u5206\u306e\u5834\u6240\u304c\u6c17\u306b\u306a\u308b";
|
|
if (actionId === "use_plushie") return "\u306c\u3044\u3050\u308b\u307f\u3092\u62b1\u3048\u305f\u3044";
|
|
if (actionId === "play") return "\u9000\u5c48\u3057\u3066\u3044\u308b";
|
|
if (actionId === "wander_lightly") return "\u5c11\u3057\u9000\u5c48\u3057\u3066\u3044\u308b";
|
|
|
|
const parts = tarinai?.fulfillReasonParts || {};
|
|
const candidates = [
|
|
["bed", "\u5bdd\u5e8a\u304c\u307b\u3057\u3044", parts.bed],
|
|
["plushie", "\u306c\u3044\u3050\u308b\u307f\u304c\u307b\u3057\u3044", parts.plushie],
|
|
["boredom", "\u9000\u5c48\u3057\u3066\u3044\u308b", parts.boredom],
|
|
["material", "\u8349\u3067\u306a\u306b\u304b\u4f5c\u308c\u305d\u3046", parts.material],
|
|
["openness", "\u65b0\u3057\u3044\u3053\u3068\u304c\u6c17\u306b\u306a\u308b", parts.openness],
|
|
].filter(([, , v]) => Number(v || 0) > 0);
|
|
candidates.sort((a, b) => Number(b[2] || 0) - Number(a[2] || 0));
|
|
return candidates[0]?.[1] || TARINAI_NEED_PHRASES.fulfill || "\u306a\u306b\u304b\u6e80\u305f\u3055\u308c\u306a\u3044";
|
|
}
|
|
|
|
function needPhraseForReason(need, tarinai = null, action = null) {
|
|
if (need === "fulfill") return fulfillPrimaryReason(tarinai, action);
|
|
if (need === "social" && action?.subNeed === "mate") return "\u7e41\u6b96\u3067\u304d\u308b\u76f8\u624b\u304c\u6c17\u306b\u306a\u308b";
|
|
if (need === "social" && action?.id === "birth_ritual") return "\u76f8\u624b\u3068\u7e41\u6b96\u3057\u3066\u3044\u308b";
|
|
if (need === "social" && action?.subNeed === "conflict") return "\u6c17\u306b\u5165\u3089\u306a\u3044\u76f8\u624b\u304c\u3044\u308b";
|
|
if (need === "social" && action?.subNeed === "family") return "\u5bb6\u65cf\u304c\u6c17\u306b\u306a\u308b";
|
|
if (need === "social" && action?.subNeed === "bond") return "\u4ef2\u9593\u304c\u6c17\u306b\u306a\u308b";
|
|
if (need === "safety" && action?.id === "panic_escape") return "\u6016\u3044";
|
|
return TARINAI_NEED_PHRASES[need] || need;
|
|
}
|
|
|
|
function actionTextForReason(action = null, tarinai = null) {
|
|
const behavior = typeof currentTarinaiBehavior === "function" ? currentTarinaiBehavior(tarinai) : tarinai?.behavior;
|
|
const id = action?.id || behavior?.actionId || "";
|
|
const target = tarinai?.target || currentBehaviorTarget?.(tarinai) || null;
|
|
const name = target?.name || "\u76f8\u624b";
|
|
if (id === "birth_ritual") return target?.name ? `${name}とへこへこしている` : "へこへこしている";
|
|
if (id === "fight_rival") {
|
|
const cause = String(behavior?.causeText || "");
|
|
if (cause.includes("\u3051\u3093\u304b\u3092\u58f2\u3089\u308c")) return "\u53cd\u6483\u3057\u3066\u3044\u308b";
|
|
return target?.name ? `${name}\u3068\u55a7\u5629\u3057\u3066\u3044\u308b` : "\u55a7\u5629\u3057\u3066\u3044\u308b";
|
|
}
|
|
if (id === "panic_escape" || id === "flee") return "\u30d1\u30cb\u30c3\u30af\u306b\u306a\u3063\u3066\u3044\u308b";
|
|
return String(action?.label || action?.phrase || behavior?.label || "ぼーっとしている").replace(/[\u3002\uff01\uff1f]+$/, "");
|
|
}
|
|
|
|
function forcedCausePhrase(source = "", fallback = "") {
|
|
const key = String(source || "");
|
|
if (key === "love_mochi") return "\u3078\u3053\u9905\u306e\u52b9\u679c";
|
|
if (key === "fight_mochi") return "\u3051\u3093\u304b\u9905\u306e\u52b9\u679c";
|
|
if (key === "sleep_drug") return "\u306d\u3080\u308a\u85ac\u306e\u52b9\u679c";
|
|
if (key === "drug") return "\u85ac\u306e\u52b9\u679c";
|
|
return String(fallback || "").replace(/[\u3002\uff01\uff1f]+$/, "");
|
|
}
|
|
|
|
function formatCauseActionText(cause = "", actionText = "\u884c\u52d5\u3057\u3066\u3044\u308b") {
|
|
const c = String(cause || "").replace(/[\u3002\uff01\uff1f]+$/, "").trim();
|
|
const a = String(actionText || "\u884c\u52d5\u3057\u3066\u3044\u308b").replace(/[\u3002\uff01\uff1f]+$/, "").trim();
|
|
if (!c) return `${a}\u3002`;
|
|
if (c.endsWith("\u52b9\u679c") || c.endsWith("\u5f71\u97ff")) return `${c}\u3067\u3001${a}\u3002`;
|
|
if (c.endsWith("\u6c17\u4ed8\u3044\u305f")) return `${c.replace(/\u6c17\u4ed8\u3044\u305f$/, "\u6c17\u4ed8\u3044\u3066")}\u3001${a}\u3002`;
|
|
if (c.endsWith("\u6c17\u3065\u3044\u305f")) return `${c.replace(/\u6c17\u3065\u3044\u305f$/, "\u6c17\u3065\u3044\u3066")}\u3001${a}\u3002`;
|
|
if (c.endsWith("\u3051\u3093\u304b\u3092\u58f2\u3089\u308c\u305f")) return `${c.replace(/\u3051\u3093\u304b\u3092\u58f2\u3089\u308c\u305f$/, "\u3051\u3093\u304b\u3092\u58f2\u3089\u308c")}\u3001${a}\u3002`;
|
|
if (c.endsWith("\u5a01\u5687\u3055\u308c\u305f")) return `${c.replace(/\u5a01\u5687\u3055\u308c\u305f$/, "\u5a01\u5687\u3055\u308c")}\u3001${a}\u3002`;
|
|
return `${c}\u306e\u3067\u3001${a}\u3002`;
|
|
}
|
|
|
|
function causePhraseForReason(chosenNeed, action, tarinai = null, options = {}) {
|
|
if (options?.causeText) return String(options.causeText || "").replace(/[\u3002\uff01\uff1f]+$/, "");
|
|
const b = (typeof currentTarinaiBehavior === "function" ? currentTarinaiBehavior(tarinai) : tarinai?.behavior) || {};
|
|
if (b.causeText) return String(b.causeText).replace(/[\u3002\uff01\uff1f]+$/, "");
|
|
if ((typeof isTarinaiBehaviorValueForced === "function" ? isTarinaiBehaviorValueForced(b) : Boolean(b.forcedId || b.forcedRequest)) || b.source) {
|
|
const forced = forcedCausePhrase(b.source || "", b.sourceReasonText || b.sourceReasonText || "");
|
|
if (forced) return forced;
|
|
}
|
|
if (action?.id === "panic_escape" && tarinai?.lastPanicDetail) return String(tarinai.lastPanicDetail).replace(/[\u3002\uff01\uff1f]+$/, "");
|
|
if (action?.id === "fight_rival") {
|
|
const target = currentBehaviorTarget?.(tarinai) || tarinai?.target || null;
|
|
if (tarinai?.counterAttackFromId && target?.id === tarinai.counterAttackFromId) return `${target.name || "\u76f8\u624b"}\u306b\u3051\u3093\u304b\u3092\u58f2\u3089\u308c\u305f`;
|
|
if (target?.name) return `${target.name}\u304c\u6c17\u306b\u5165\u3089\u306a\u3044`;
|
|
}
|
|
if (action?.id === "birth_ritual" || action?.subNeed === "mate") {
|
|
if ((tarinai?.loveMochiTimer || 0) > 0.04) return "\u3078\u3053\u9905\u306e\u52b9\u679c";
|
|
}
|
|
return needPhraseForReason(chosenNeed, tarinai, action);
|
|
}
|
|
|
|
function buildReasonText(chosenNeed, tiedNeeds, action, tarinai = null, world = null, options = {}) {
|
|
const actionText = actionTextForReason(action, tarinai);
|
|
const cause = causePhraseForReason(chosenNeed, action, tarinai, options);
|
|
const tied = Array.isArray(tiedNeeds) ? tiedNeeds.filter(key => key !== chosenNeed) : [];
|
|
const main = formatCauseActionText(cause, actionText);
|
|
if (tied.length) {
|
|
const ignored = TARINAI_NEED_PRIORITY.find(key => tied.includes(key)) || tied[0];
|
|
return `${needPhraseForReason(ignored, tarinai, action)}\u3051\u3069\u3001${main}`;
|
|
}
|
|
return main;
|
|
}
|
|
|
|
|
|
function needsForBehaviorText(tarinai, behavior = {}, fallbackNeed = "fulfill") {
|
|
const primary = String(behavior?.need || fallbackNeed || "fulfill");
|
|
const raw = tarinai?.needRaw || tarinai?.needs || {};
|
|
const list = Array.isArray(behavior?.tiedNeeds) && behavior.tiedNeeds.length ? [...behavior.tiedNeeds] : [primary];
|
|
if (!list.includes(primary)) list.unshift(primary);
|
|
return list.filter((key, idx) => key && (idx === 0 || Number(raw?.[key] || 0) > 0.5));
|
|
}
|
|
|
|
function causeForBehaviorText(tarinai, behavior = {}, action = null, options = {}) {
|
|
const request = behavior?.forcedRequest || (typeof currentForcedBehaviorRequest === "function" ? currentForcedBehaviorRequest(tarinai) : null) || null;
|
|
const directCause = options?.causeText || behavior?.causeText || request?.causeText || "";
|
|
if (directCause) return String(directCause || "").replace(/[。!?]+$/, "");
|
|
if ((typeof isTarinaiBehaviorValueForced === "function" ? isTarinaiBehaviorValueForced(behavior) : Boolean(behavior?.forcedId || behavior?.forcedRequest)) || request) {
|
|
const source = request?.source || behavior?.source || "external";
|
|
const sourceReason = request?.reasonText || behavior?.sourceReasonText || behavior?.sourceReasonText || "";
|
|
const forcedCause = forcedCausePhrase(source, sourceReason);
|
|
if (forcedCause) return forcedCause;
|
|
}
|
|
return causePhraseForReason(behavior?.need || action?.need || "fulfill", action, tarinai, options);
|
|
}
|
|
|
|
function composeTarinaiBehaviorText(tarinai, behavior = null, options = {}) {
|
|
const b = behavior || (typeof currentTarinaiBehavior === "function" ? currentTarinaiBehavior(tarinai) : tarinai?.behavior) || null;
|
|
if (!b) return "";
|
|
const stored = String(b.text || b.reason || "").trim();
|
|
if (stored && options.regenerate !== true) return stored;
|
|
const action = options.action || actionById(b.specId || b.actionId) || actionById(b.actionId) || null;
|
|
const need = String(options.need || b.need || action?.need || "fulfill");
|
|
const tiedNeeds = Array.isArray(options.tiedNeeds) && options.tiedNeeds.length ? [...options.tiedNeeds] : needsForBehaviorText(tarinai, b, need);
|
|
const causeText = causeForBehaviorText(tarinai, { ...b, need }, action, options);
|
|
const generated = action ? buildReasonText(need, tiedNeeds, action, tarinai, tarinai?.world || null, { ...options, causeText }) : "";
|
|
const actionLabel = typeof textTarinaiAction === "function" ? textTarinaiAction(action || b.actionId, tarinai, tarinai?.world || null, { ...options, behavior: b, need, tiedNeeds, causeText, phase: options.phase || b.phase || "active" }) : "";
|
|
const rawFallback = String(actionLabel || b.label || b.reason || b.text || "").trim();
|
|
const catalog = globalThis.TEXT_CATALOG || (typeof window !== "undefined" ? window.TEXT_CATALOG : null);
|
|
const fallback = catalog?.cleanBehaviorText
|
|
? catalog.cleanBehaviorText(rawFallback, b.actionId || b.specId || "")
|
|
: rawFallback;
|
|
return String(generated || fallback || "").trim();
|
|
}
|
|
|
|
function patchBehaviorTextFromComposer(tarinai, behavior = null, options = {}) {
|
|
const b = behavior || (typeof currentTarinaiBehavior === "function" ? currentTarinaiBehavior(tarinai) : tarinai?.behavior) || null;
|
|
if (!b) return "";
|
|
const prevReason = String(b.reason || "");
|
|
const text = composeTarinaiBehaviorText(tarinai, b, { ...options, regenerate: true });
|
|
if (!text) return "";
|
|
const tiedNeeds = Array.isArray(options.tiedNeeds) && options.tiedNeeds.length ? [...options.tiedNeeds] : needsForBehaviorText(tarinai, b, b.need || options.need || "fulfill");
|
|
if (text !== b.reason || text !== b.text || JSON.stringify(tiedNeeds) !== JSON.stringify(b.tiedNeeds || [])) {
|
|
if (typeof patchTarinaiBehavior === "function") patchTarinaiBehavior(tarinai, { reason: text, text: text, tiedNeeds });
|
|
else { b.reason = text; b.text = text; b.tiedNeeds = tiedNeeds; }
|
|
}
|
|
if (text && (!tarinai.thought || tarinai.thought === prevReason || tarinai.thought === b.label)) tarinai.thought = text;
|
|
return text;
|
|
}
|
|
|
|
function refreshBehaviorReasonText(tarinai, action = null) {
|
|
const behavior = typeof currentTarinaiBehavior === "function" ? currentTarinaiBehavior(tarinai) : tarinai?.behavior;
|
|
if (!behavior?.need) return "";
|
|
return patchBehaviorTextFromComposer(tarinai, behavior, { action });
|
|
}
|
|
|
|
|
|
|
|
|