This commit is contained in:
33333-33333 2026-07-05 18:01:36 +09:00
commit 8f9f5b5100
108 changed files with 2139 additions and 1500 deletions

View file

@ -55,10 +55,6 @@ function forceBuiltStructureVisualRefresh(world, structure, reason = "structure-
if (structure) {
structure.world = world;
}
if (typeof globalThis.render === "function") {
globalThis.render();
globalThis.requestAnimationFrame?.(() => globalThis.render?.());
}
}
function findStructureBuildSpot(t, world, type) {
@ -108,25 +104,42 @@ function grassMaterialAvailableStages(material) {
return Math.max(0, Math.floor(Number(stage) || 0) + 1);
}
function reservedBuildGrassStages(world, material, type, self = null) {
if (!world || !material) return 0;
const id = material.id || "";
if (!id) return 0;
let reserved = 0;
function buildGrassReservationIndex(world, self = null) {
const index = new Map();
if (!world) return index;
for (const other of world.tarinai || []) {
if (!other || other.dead || other === self) continue;
const plan = other.buildPlan || null;
const planType = plan?.type || (/build_plushie/.test(other.behavior?.actionId || "") ? "plushie" : (/build_grass_bed/.test(other.behavior?.actionId || "") ? "grass_bed" : ""));
if (type && planType && planType !== type) continue;
const targetId = plan?.materialId || other.target?.id || "";
if (targetId !== id) continue;
if (!targetId) continue;
const state = String(other.state || "");
const actionId = String(other.behavior?.actionId || other.currentActionId || "");
if (state === "seek_material" || state === "build" || /build_grass_bed|build_plushie|seek_material/.test(actionId)) {
reserved += structureGrassStageCost(planType || type);
if (state !== "seek_material" && state !== "build" && !/build_grass_bed|build_plushie|seek_material/.test(actionId)) continue;
const cost = structureGrassStageCost(planType || "");
if (cost <= 0) continue;
let rec = index.get(targetId);
if (!rec) {
rec = { total: 0, byType: Object.create(null), unknownReservations: 0 };
index.set(targetId, rec);
}
rec.total += cost;
if (planType) rec.byType[planType] = (rec.byType[planType] || 0) + cost;
else rec.unknownReservations += 1;
}
return reserved;
return index;
}
function reservedBuildGrassStages(world, material, type, self = null, reservationIndex = null) {
if (!world || !material) return 0;
const id = material.id || "";
if (!id) return 0;
const index = reservationIndex || buildGrassReservationIndex(world, self);
const rec = index.get(id);
if (!rec) return 0;
if (!type) return rec.total || 0;
const unknownCost = (rec.unknownReservations || 0) * structureGrassStageCost(type);
return (rec.byType?.[type] || 0) + unknownCost;
}
function findNearbyBuildMaterial(world, tarinai, type, maxDist = 520) {
@ -134,13 +147,14 @@ function findNearbyBuildMaterial(world, tarinai, type, maxDist = 520) {
let best = null;
let bestScore = Infinity;
const candidates = world?.nearbyItems?.(tarinai.x, tarinai.y, maxDist + 40, true) || world?.items || [];
const reservationIndex = buildGrassReservationIndex(world, tarinai);
for (const item of candidates) {
if (!item || item.dead || !roleMatches(item, "grassMaterial")) continue;
if (tarinai?.shouldAvoidTarget?.(item)) continue;
if (world?.targetBlockedByObstacle?.(tarinai, item, Math.max(18, (tarinai.radius || 20) * 0.65))) continue;
const available = grassMaterialAvailableStages(item);
if (available < required) continue;
const reserved = reservedBuildGrassStages(world, item, type, tarinai);
const reserved = reservedBuildGrassStages(world, item, type, tarinai, reservationIndex);
if (available - reserved < required) continue;
const d = dist(tarinai, item);
if (d > maxDist) continue;