This commit is contained in:
33333-33333 2026-06-30 10:57:06 +09:00
commit f941200504
70 changed files with 1856 additions and 429 deletions

View file

@ -89,7 +89,7 @@ function createSleepBuildGrassBedActionSpec() {
state: "build",
label: "\u5bdd\u308b\u5834\u6240\u304c\u306a\u3044\u306e\u3067\u304b\u3093\u305f\u3093\u30d9\u30c3\u30c9\u3092\u4f5c\u3063\u3066\u3044\u308b",
phrase: "\u304b\u3093\u305f\u3093\u30d9\u30c3\u30c9\u3092\u4f5c\u3063\u305f",
weight: 18,
weight: 26,
timerBacked: true,
selectTarget(t, world) { return (typeof findNearbyBuildMaterial === "function" ? findNearbyBuildMaterial(world, t, "grass_bed", 520) : null) || findNearbyMaterial(world, t, "grassMaterial", 520); },
canStart(t, world, ctx = {}) {
@ -201,6 +201,56 @@ function createSunbathActionSpec() {
};
}
function createTemperatureComfortActionSpec() {
return {
id: "seek_comfort_temperature",
need: "health",
subNeed: "temperature",
state: "seek_temperature",
label: "快適な温度帯へ移動している",
phrase: "快適な温度帯を探している",
text(t, world) {
const felt = world?.temperatureAt?.(t?.x, t?.y) ?? t?.feltTemperature ?? t?.tempComfort ?? (CONFIG.standardTemperature ?? 15);
const status = world?.temperatureStatusFor?.(felt) || t?.temperatureStatus || null;
return status?.direction === "cold" ? "寒いので温まろうとしている。" : "暑いので涼もうとしている。";
},
weight: 42,
selectTarget(t, world, ctx = {}) {
return world?.findComfortTemperatureSpot?.(t, { force: !!ctx.force, requireComfort: true }) || null;
},
canStart(t, world, ctx = {}) {
const felt = world?.temperatureAt?.(t.x, t.y);
const status = world?.temperatureStatusFor?.(Number.isFinite(Number(felt)) ? felt : (t?.feltTemperature ?? CONFIG.standardTemperature ?? 15));
if (!status || status.comfortable || (status.discomfort || 0) < 2.5) return false;
return !!(ctx.target ?? this.selectTarget(t, world, ctx));
},
start(t, world, ctx = {}) {
const status = world?.temperatureStatusFor?.(world?.temperatureAt?.(t.x, t.y) ?? t?.feltTemperature ?? (CONFIG.standardTemperature ?? 15));
const label = status?.direction === "cold" ? "あたたかい場所へ移動している" : (status?.direction === "hot" ? "涼しい場所へ移動している" : this.label);
const target = ctx.target ?? this.selectTarget(t, world, ctx);
return moveToOrUse(t, target, "seek_temperature", label);
},
tick(t, world, dt, needs, ctx = {}) {
const felt = world?.temperatureAt?.(t.x, t.y) ?? t?.feltTemperature ?? (CONFIG.standardTemperature ?? 15);
const status = world?.temperatureStatusFor?.(felt);
if (status?.comfortable || (status?.discomfort || 0) <= 1.5) {
if (typeof applyNeedSatisfaction === "function") applyNeedSatisfaction(t, { health: 10, safety: 8 }, "temperature");
t.goIdle?.("快適な温度になった");
return "finished";
}
const target = t.target && !t.target.dead ? t.target : (ctx.target ?? this.selectTarget(t, world, { force: true, requireComfort: true }));
if (!target) return false;
t.target = target;
if (distXY(t.x, t.y, target.x, target.y) < Math.max(24, (t.radius || 20) * 0.9)) {
const next = this.selectTarget(t, world, { force: true, requireComfort: true });
if (!next || distXY(t.x, t.y, next.x, next.y) < Math.max(28, (t.radius || 20))) return "finished";
t.target = next;
}
return true;
},
};
}
function createWanderActionSpec() {
function targetFor(t, world) {
const radius = rand(80, 180);
@ -350,12 +400,12 @@ function createFightRivalActionSpec() {
const parts = t?.socialReasonParts || {};
const conflict = Number(parts.conflict || 0) || 0;
const socialPull = Math.max(Number(parts.bond || 0) || 0, Number(parts.mate || 0) || 0, Number(parts.family || 0) || 0);
if (!candidate?.target || conflict < 30 || conflict < socialPull * 0.82) return false;
if (!candidate?.target || conflict < 22 || conflict < socialPull * 0.68) return false;
}
return !!(ctx.target ?? candidate?.target ?? this.selectTarget(t, world, ctx));
},
start(t, world, ctx = {}) {
const candidate = conflictTargetFor(t, world, (t?.fightMochiTimer || 0) > 0.04 || isCurrentBehaviorForced(t) ? 18 : 34);
const candidate = conflictTargetFor(t, world, (t?.fightMochiTimer || 0) > 0.04 || isCurrentBehaviorForced(t) ? 18 : 26);
const rival = ctx.target ?? this.selectTarget(t, world, ctx);
if (!isLiveTarinaiEntity(rival)) return false;
t.conflictTargetId = rival.id;
@ -381,9 +431,9 @@ function createIntimidateEnemyActionSpec() {
timerBacked: true,
selectTarget(t) { return t.recentFightRival?.(80, 180) || null; },
canStart(t, world, ctx = {}) {
// 威嚇は通常の欲求行動としては選ばず、喧嘩判定時の30%分岐で実行する。
if (!isCurrentBehaviorForced(t)) return false;
if ((t.intimidateTimer || 0) > 0.04 || (t.postConflictPeaceTimer || 0) > 0.04) return false;
const parts = t?.socialReasonParts || {};
if ((t.fightMochiTimer || 0) <= 0.04 && Number(parts.conflict || 0) < 24) return false;
return basicCanStartWithTarget.call(this, t, world, ctx);
},
start(t, world, ctx = {}) {
@ -453,6 +503,7 @@ const TARINAI_ACTION_DEFINITIONS = [
}),
createRestActionSpec(),
createSunbathActionSpec(),
createTemperatureComfortActionSpec(),
createPanicEscapeActionSpec(),
{
id: "hide_at_owned_structure",