hm
This commit is contained in:
parent
cefa2ace5a
commit
0e432c62ae
87 changed files with 4282 additions and 3066 deletions
|
|
@ -79,19 +79,82 @@ function findStructureBuildSpot(t, world, type) {
|
|||
if (world?.placementBlocked?.(probe)) continue;
|
||||
let nearestSame = Infinity;
|
||||
if (type === "grass_bed") {
|
||||
for (const it of world?.nearbyItems?.(c.x, c.y, 160) || world?.items || []) {
|
||||
const spacing = Math.max(46, (probe.r || 18) * 3.0);
|
||||
for (const it of world?.nearbyItems?.(c.x, c.y, spacing + 90) || world?.items || []) {
|
||||
if (!it || it.dead || it.type !== "grass_bed") continue;
|
||||
nearestSame = Math.min(nearestSame, distXY(c.x, c.y, it.x, it.y));
|
||||
const d = distXY(c.x, c.y, it.x, it.y);
|
||||
const required = spacing + Math.max(0, ((it.r || 18) - (probe.r || 18)) * 0.5);
|
||||
nearestSame = Math.min(nearestSame, d);
|
||||
if (d < required) { nearestSame = -Infinity; break; }
|
||||
}
|
||||
if (nearestSame === -Infinity) continue;
|
||||
}
|
||||
const score = (Number.isFinite(nearestSame) ? nearestSame : 160) - distXY(c.x, c.y, baseX, baseY) * 0.12;
|
||||
if (score > bestScore) { best = c; bestScore = score; }
|
||||
}
|
||||
if (type === "grass_bed") return best;
|
||||
return best || candidates[0] || { x: baseX, y: baseY };
|
||||
}
|
||||
|
||||
|
||||
function structureGrassStageCost(type = "") {
|
||||
return (type === "grass_bed" || type === "plushie") ? 4 : 1;
|
||||
}
|
||||
|
||||
function grassMaterialAvailableStages(material) {
|
||||
if (!material || material.dead || material.type !== "grass" || (material.amount || 0) <= 0) return 0;
|
||||
const stage = typeof normalizeGrassStage === "function"
|
||||
? normalizeGrassStage(material)
|
||||
: (typeof grassStageFromGrowth === "function" ? grassStageFromGrowth(material.growth, material.amount) : Math.floor((Number(material.amount || 0) || 0) / 24) - 1);
|
||||
return Math.max(0, Math.floor(Number(stage) || 0) + 1);
|
||||
}
|
||||
|
||||
function reservedGrassStagesForBuildMaterial(world, material, type, self = null) {
|
||||
if (!world || !material) return 0;
|
||||
const id = material.id || "";
|
||||
if (!id) return 0;
|
||||
let reserved = 0;
|
||||
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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
return reserved;
|
||||
}
|
||||
|
||||
function findNearbyBuildMaterial(world, tarinai, type, maxDist = 520) {
|
||||
const required = structureGrassStageCost(type);
|
||||
let best = null;
|
||||
let bestScore = Infinity;
|
||||
const candidates = world?.nearbyItems?.(tarinai.x, tarinai.y, maxDist + 40, true) || world?.items || [];
|
||||
for (const item of candidates) {
|
||||
if (!item || item.dead || !roleMatches(item, "grassMaterial")) continue;
|
||||
if (tarinai?.shouldAvoidTarget?.(item)) continue;
|
||||
const available = grassMaterialAvailableStages(item);
|
||||
if (available < required) continue;
|
||||
const reserved = reservedGrassStagesForBuildMaterial(world, item, type, tarinai);
|
||||
if (available - reserved < required) continue;
|
||||
const d = dist(tarinai, item);
|
||||
if (d > maxDist) continue;
|
||||
// Prefer nearby grass, but lightly spread simultaneous builders across
|
||||
// separate tufts so a crowd does not all reserve one valid material.
|
||||
const jitter = typeof stableUnit === "function" ? stableUnit(tarinai.id || tarinai.familyKey || "", `build-material:${item.id || ""}`) : Math.random();
|
||||
const score = d + Math.max(0, reserved) * 42 + jitter * 12;
|
||||
if (score < bestScore) { best = item; bestScore = score; }
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
function buildOwnedStructureFromGrass(t, world, type, label) {
|
||||
const material = findNearbyMaterial(world, t, "grassMaterial", 520);
|
||||
const material = findNearbyBuildMaterial(world, t, type, 520);
|
||||
if (!material || !globalThis.StructureRegistry) return false;
|
||||
t.buildPlan = {
|
||||
type,
|
||||
|
|
@ -111,8 +174,8 @@ function continueBuildPlan(t, world, dt) {
|
|||
return false;
|
||||
}
|
||||
let material = (world?.itemById?.(plan.materialId) || null);
|
||||
if (material && (material.dead || !roleMatches(material, "grassMaterial"))) material = null;
|
||||
if (!material) material = findNearbyMaterial(world, t, "grassMaterial", 520);
|
||||
if (material && (material.dead || !roleMatches(material, "grassMaterial") || grassMaterialAvailableStages(material) < structureGrassStageCost(plan.type))) material = null;
|
||||
if (!material) material = findNearbyBuildMaterial(world, t, plan.type, 520);
|
||||
if (!material) {
|
||||
return stopFailedBuildPlan(t, world, plan.type, "\u6750\u6599\u304c\u898b\u3064\u304b\u3089\u306a\u3044");
|
||||
}
|
||||
|
|
@ -125,10 +188,13 @@ function continueBuildPlan(t, world, dt) {
|
|||
plan.timer = Math.max(0, Number(plan.timer || 0) - Math.max(0.05, dt || 0.1));
|
||||
t.setActionState?.("build", { target: material, reason: `${label}\u3092\u4f5c\u3063\u3066\u3044\u308b`, sleeping: false });
|
||||
if (plan.timer > 0) return true;
|
||||
consumeGrassMaterial(material, plan.type === "grass_bed" ? 4 : 1);
|
||||
const spot = plan.type === "plushie"
|
||||
? { x: t.x, y: t.y - Math.max(28, (t.radius || 24) * 1.28) }
|
||||
: findStructureBuildSpot(t, world, plan.type);
|
||||
if (!spot) {
|
||||
return stopFailedBuildPlan(t, world, plan.type, "作る場所が見つからない");
|
||||
}
|
||||
consumeGrassMaterial(material, structureGrassStageCost(plan.type));
|
||||
const structure = globalThis.StructureRegistry.create(plan.type, t, spot.x, spot.y, world);
|
||||
if (!structure) {
|
||||
return stopFailedBuildPlan(t, world, plan.type, "\u4f5c\u308b\u5834\u6240\u304c\u898b\u3064\u304b\u3089\u306a\u3044");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue