This commit is contained in:
33333-33333 2026-06-28 23:07:40 +09:00
commit 0e432c62ae
87 changed files with 4282 additions and 3066 deletions

View file

@ -35,7 +35,7 @@ function roleMatches(item, role) {
if (item.type === "duplicator") return effectiveFoodRoleMatches(item, role);
if (item.roles?.[role]) return true;
if (role === "food" || role === "drink" || role === "medicine") return effectiveFoodRoleMatches(item, role);
if (role === "sleepPlace") return item.type === "bed" || item.type === "nest_box";
if (role === "sleepPlace") return item.type === "bed" || item.type === "nest_box" || item.type === "grass_bed";
if (role === "danger") return ["firecracker", "genkotsu", "pushpin", "oshibyo", "splat"].includes(item.type);
if (role === "grassMaterial") return item.type === "grass";
return false;
@ -65,21 +65,21 @@ function foodPriorityRank(tarinai, item) {
const need = typeof getTarinaiBehaviorNeed === "function" ? getTarinaiBehaviorNeed(tarinai) : tarinai?.behavior?.need;
const socialNeed = Number(tarinai?.needRaw?.social ?? tarinai?.needs?.social ?? 0) || 0;
const healthNeed = Number(tarinai?.needRaw?.health ?? tarinai?.needs?.health ?? 0) || 0;
if (type === "sweet") return 4100 + Math.max(0, healthNeed - 40) * 6;
if (type === "sweet") return 4300 + Math.min(120, Math.max(0, healthNeed - 40) * 3);
if (type === "water") return 3650 + Math.max(0, healthNeed - 42) * 7;
if (type === "zunda_juice") return 3720 + Math.max(0, healthNeed - 42) * 6;
if (type === "love_mochi") return 3300 + Math.max(0, socialNeed - 45) * 7;
if (type === "fight_mochi") return 2600 + Math.max(0, Number(tarinai?.fightMochiTimer || 0)) * 4;
if (type === "sleep_drug") return need === "sleep" ? 3600 : 2450;
if (typeof isParamEffectItemType === "function" && isParamEffectItemType(type)) return 3000 + Math.max(0, healthNeed - 45) * 5;
if (type === "love_mochi") return 3340 + Math.min(120, Math.max(0, socialNeed - 45) * 3);
if (type === "fight_mochi") return 3280 + Math.min(90, Math.max(0, Number(tarinai?.fightMochiTimer || 0)) * 3);
if (type === "sleep_drug") return need === "sleep" ? 3380 : 3220;
if (typeof isParamEffectItemType === "function" && isParamEffectItemType(type)) return 3260 + Math.min(120, Math.max(0, healthNeed - 45) * 3);
if (type === "food" || type === "ant_corpse") return 3300;
if (typeof isServingFoodType === "function" && isServingFoodType(type)) return 3300;
if (type === "grass") {
const hunger = Number(tarinai?.hunger || 0) || 0;
const foodNeed = Number(tarinai?.needRaw?.food ?? tarinai?.needs?.food ?? 0) || 0;
return 2000 + Math.max(0, hunger - 64) * 18 + Math.max(0, foodNeed - 58) * 12;
return 2200 + Math.min(260, Math.max(0, hunger - 64) * 3 + Math.max(0, foodNeed - 58) * 2);
}
if (type === "zunchi") return 1000 + (tarinai?.isZunchiSlave ? 250 : 0);
if (type === "food" || type === "ant_corpse") return 3000;
if (typeof isServingFoodType === "function" && isServingFoodType(type)) return 3000;
if (type === "zunchi") return 900 + (tarinai?.isZunchiSlave ? 180 : 0);
return -1;
}
@ -141,7 +141,9 @@ function findNearestItemWithRole(world, tarinai, role, maxDist = 520) {
: (world?.nearbyItems?.(tarinai.x, tarinai.y, searchDist, true) || world?.items || []);
const candidates = Array.isArray(primary) ? primary.slice() : [];
if (foodEmergency && world?.itemsOfType) {
for (const type of ["food", "sweet", "grass", "zunchi", "ant_corpse", "zunda_juice", "duplicator"]) {
const emergencyTypes = new Set(["food", "sweet", "love_mochi", "fight_mochi", "sleep_drug", "laxative", "protein", "niteropu", "ammo", "mystery_drug", "mercury", "giant_drug", "dwarf_drug", "grass", "zunchi", "ant_corpse", "zunda_juice", "duplicator"]);
if (typeof FOOD_SERVING_TYPES !== "undefined") for (const type of FOOD_SERVING_TYPES) emergencyTypes.add(type);
for (const type of emergencyTypes) {
for (const it of world.itemsOfType(type) || []) {
if (it && !it.dead && !candidates.includes(it)) candidates.push(it);
}
@ -149,6 +151,12 @@ function findNearestItemWithRole(world, tarinai, role, maxDist = 520) {
}
for (const item of candidates) {
if (!roleMatches(item, role)) continue;
if (role === "food" && typeof tarinai?.foodItemHasServingLeft === "function") {
const type = effectiveFoodTypeForItem(item);
if ((item.type === "duplicator" || (typeof isServingFoodType === "function" && isServingFoodType(type))) && !tarinai.foodItemHasServingLeft(item)) continue;
if (item.type === "grass" && (Number(item.amount || 0) || 0) <= 0) continue;
if (item.type === "zunchi" && (Number(item.amount || 0) || 0) <= 0) continue;
}
if (tarinai?.shouldAvoidTarget?.(item)) continue;
const d = item.type === "duplicator" ? foodInteractionDistance(tarinai, item) : dist(tarinai, item);
if (d > searchDist) continue;
@ -164,40 +172,19 @@ function findNearestItemWithRole(world, tarinai, role, maxDist = 520) {
}
function sleepPlaceAvailableFor(world, tarinai, item) {
if (!world || !tarinai || !item || item.dead) return false;
if (!(item.type === "nest_box" || item.type === "bed")) return false;
if (tarinai.shouldAvoidTarget?.(item)) return false;
const capacity = item.type === "nest_box"
? (world.nestBoxCapacity ? world.nestBoxCapacity(item) : 5)
: 1;
const occupancy = item.type === "nest_box"
? (world.nestBoxOccupants ? world.nestBoxOccupants(item, Infinity).length : world.bedOccupancy?.(item) || 0)
: (world.bedOccupancy?.(item) || 0);
return occupancy < capacity;
return globalThis.TarinaiNestSleepSystem?.sleepPlaceAvailableFor?.(world, tarinai, item) || false;
}
function nearestSleepPlaceOfType(world, tarinai, type, maxDist = 520) {
let best = null;
let bestScore = Infinity;
const list = world?.nearbyItems?.(tarinai.x, tarinai.y, maxDist) || world?.items || [];
for (const item of list) {
if (!item || item.dead || item.type !== type) continue;
if (!sleepPlaceAvailableFor(world, tarinai, item)) continue;
const d = dist(tarinai, item);
if (d > maxDist) continue;
const comfort = world?.bedComfort ? world.bedComfort(item) : 1;
const score = d - comfort * 18;
if (score < bestScore) { best = item; bestScore = score; }
}
return best;
return globalThis.TarinaiNestSleepSystem?.nearestSleepPlaceOfType?.(world, tarinai, type, maxDist) || null;
}
function findPrioritySleepPlaceBeforeGrassBedBuild(world, tarinai, maxDist = 520) {
return globalThis.TarinaiNestSleepSystem?.findPrioritySleepPlaceBeforeGrassBedBuild?.(world, tarinai, maxDist) || null;
}
function findNearestSleepPlace(world, tarinai, maxDist = 520) {
return nearestSleepPlaceOfType(world, tarinai, "nest_box", maxDist)
|| nearestSleepPlaceOfType(world, tarinai, "bed", maxDist)
|| findOwnedStructure(world, tarinai, "grass_bed", maxDist)
|| findUnownedStructure(world, tarinai, "grass_bed", maxDist)
|| null;
return globalThis.TarinaiNestSleepSystem?.findNearestSleepPlace?.(world, tarinai, maxDist) || null;
}
function findNearbyDanger(world, tarinai, maxDist = 150) {