375 lines
21 KiB
JavaScript
375 lines
21 KiB
JavaScript
"use strict";
|
|
|
|
// Reset preset definitions and world population generators.
|
|
(function (global) {
|
|
|
|
const RESET_PRESETS = Object.freeze({
|
|
empty: { label: "\u7A7A\u767D" },
|
|
default: { label: "\u30C7\u30D5\u30A9\u30EB\u30C8" },
|
|
athletic: { label: "\u30A2\u30B9\u30EC\u30C1\u30C3\u30AF" },
|
|
crowded: { label: "\u904E\u5BC6" },
|
|
family: { label: "\u5BB6\u65CF" },
|
|
war: { label: "\u6226\u4E89" },
|
|
happy: { label: "\u5E78\u798F" },
|
|
});
|
|
|
|
function normalizeResetPresetId(presetId = "default") {
|
|
const id = String(presetId || "default");
|
|
return Object.prototype.hasOwnProperty.call(RESET_PRESETS, id) ? id : "default";
|
|
}
|
|
|
|
global.TarinaiResetPresets = Object.freeze({
|
|
ids: Object.freeze(Object.keys(RESET_PRESETS)),
|
|
definitions: RESET_PRESETS,
|
|
normalize: normalizeResetPresetId,
|
|
});
|
|
|
|
function presetScaleForField(field) {
|
|
const id = field?.id || "garden";
|
|
if (id === "cage") return 0.65;
|
|
if (id === "park") return 1.45;
|
|
return 1;
|
|
}
|
|
|
|
function presetCount(field, base, min = 0, max = Infinity) {
|
|
const value = Math.round((Number(base) || 0) * presetScaleForField(field));
|
|
return Math.max(min, Math.min(Number.isFinite(max) ? max : value, value));
|
|
}
|
|
|
|
function randPoint(worldRef, pad = 78, zone = null) {
|
|
const x0 = Math.max(pad, Number(zone?.x0 ?? pad));
|
|
const x1 = Math.min(worldRef.w - pad, Number(zone?.x1 ?? (worldRef.w - pad)));
|
|
const y0 = Math.max(pad, Number(zone?.y0 ?? pad));
|
|
const y1 = Math.min(worldRef.h - pad, Number(zone?.y1 ?? (worldRef.h - pad)));
|
|
return { x: rand(Math.min(x0, x1), Math.max(x0, x1)), y: rand(Math.min(y0, y1), Math.max(y0, y1)) };
|
|
}
|
|
|
|
function randomPresetAngle(step = Math.PI / 4) {
|
|
const n = Math.max(1, Math.round((Math.PI * 2) / Math.max(0.001, step)));
|
|
return Math.floor(rand(0, n)) * step;
|
|
}
|
|
|
|
function presetShapeExtent(segments) {
|
|
let max = 0;
|
|
for (const seg of segments || []) {
|
|
for (let i = 0; i < 4; i += 2) max = Math.max(max, Math.hypot(Number(seg[i]) || 0, Number(seg[i + 1]) || 0));
|
|
}
|
|
return max;
|
|
}
|
|
|
|
function configurePresetMechanicalItem(item, opts = {}) {
|
|
const body = item?.physicsBody;
|
|
if (!body || (item.type !== "rotator" && item.type !== "reciprocator")) return item;
|
|
body.pose = body.pose || { x: item.x, y: item.y, angle: Number(item.angle) || 0 };
|
|
body.pose.x = item.x;
|
|
body.pose.y = item.y;
|
|
body.pose.angle = Number(item.angle) || 0;
|
|
body.velocity = body.velocity || { x: 0, y: 0, angular: 0, linear: 0 };
|
|
body.velocity.x = 0;
|
|
body.velocity.y = 0;
|
|
body.velocity.angular = 0;
|
|
body.velocity.linear = 0;
|
|
body.shape = body.shape || { model: "segments", thickness: 12, segments: [], version: 0 };
|
|
|
|
if (item.type === "rotator") {
|
|
const segments = opts.segments || [
|
|
[-92, 0, 92, 0],
|
|
[0, -58, 0, 58],
|
|
[-58, -42, 58, 42],
|
|
[-58, 42, 58, -42],
|
|
];
|
|
body.motor = body.motor || { powered: true, speed: Math.PI * 0.18, direction: 1 };
|
|
body.motor.powered = opts.motorOn !== false;
|
|
body.motor.speed = Number.isFinite(Number(opts.motorSpeed)) ? Number(opts.motorSpeed) : Math.PI * 0.18;
|
|
body.motor.direction = Number(opts.direction) < 0 ? -1 : 1;
|
|
body.shape.model = "segments";
|
|
body.shape.thickness = Number.isFinite(Number(opts.thickness)) ? Number(opts.thickness) : 14;
|
|
body.shape.segments = segments.map(seg => seg.slice(0, 4));
|
|
body.shape.version = (Number(body.shape.version) || 0) + 1;
|
|
item.spin = 0;
|
|
item.r = Math.max(item.r || 64, presetShapeExtent(segments) + body.shape.thickness + 8);
|
|
} else if (item.type === "reciprocator") {
|
|
const railAxis = Number.isFinite(Number(opts.railAxis)) ? Number(opts.railAxis) : (Number(item.angle) || 0);
|
|
const segments = opts.segments || [
|
|
[-92, -24, -36, -24],
|
|
[-36, -24, -36, 24],
|
|
[-36, 24, 36, 24],
|
|
[36, 24, 36, -24],
|
|
[36, -24, 92, -24],
|
|
];
|
|
body.motor = body.motor || { powered: true, speed: 36, direction: 1 };
|
|
body.motor.powered = opts.railOn !== false;
|
|
body.motor.speed = Number.isFinite(Number(opts.railMotorSpeed)) ? Number(opts.railMotorSpeed) : 36;
|
|
body.motor.direction = Number(opts.direction) < 0 ? -1 : 1;
|
|
body.rail = body.rail || { axisAngle: railAxis, travel: 120, phase: 0, anchorX: item.x, anchorY: item.y };
|
|
body.rail.axisAngle = railAxis;
|
|
body.rail.travel = Number.isFinite(Number(opts.railTravel)) ? Number(opts.railTravel) : 120;
|
|
body.rail.phase = Number.isFinite(Number(opts.railPhase)) ? Number(opts.railPhase) : 0;
|
|
body.rail.anchorX = item.x;
|
|
body.rail.anchorY = item.y;
|
|
body.shape.model = "segments";
|
|
body.shape.thickness = Number.isFinite(Number(opts.thickness)) ? Number(opts.thickness) : 14;
|
|
body.shape.segments = segments.map(seg => seg.slice(0, 4));
|
|
body.shape.version = (Number(body.shape.version) || 0) + 1;
|
|
item.r = Math.max(item.r || 64, presetShapeExtent(segments) + body.shape.thickness + 8);
|
|
}
|
|
globalThis.TarinaiPhysicsBodySystem?.invalidateItem?.(item, "preset-mechanical-shape");
|
|
globalThis.TarinaiMechanicalSystem?.invalidateGeometry?.(item);
|
|
return item;
|
|
}
|
|
|
|
function syncPresetMechanicalPose(item) {
|
|
const body = item?.physicsBody;
|
|
if (!body) return;
|
|
body.pose = body.pose || { x: item.x, y: item.y, angle: Number(item.angle) || 0 };
|
|
body.pose.x = item.x;
|
|
body.pose.y = item.y;
|
|
body.pose.angle = Number(item.angle) || 0;
|
|
if (body.rail) {
|
|
body.rail.anchorX = item.x;
|
|
body.rail.anchorY = item.y;
|
|
}
|
|
globalThis.TarinaiPhysicsBodySystem?.invalidateItem?.(item, "preset-placement-pose");
|
|
globalThis.TarinaiMechanicalSystem?.invalidateGeometry?.(item);
|
|
}
|
|
|
|
function presetItemFootprintRadius(worldRef, item) {
|
|
const radius = globalThis.TarinaiCollisionFootprints?.itemFootprintRadius?.(worldRef, item);
|
|
if (Number.isFinite(Number(radius))) {
|
|
if (item?.type === "ball") return Math.max(34, Number(radius) * 1.35);
|
|
return Math.max(14, Number(radius));
|
|
}
|
|
return Math.max(14, Number(item?.r || 16) || 16);
|
|
}
|
|
|
|
function presetItemPlacementBlocked(worldRef, item, opts = {}) {
|
|
if (!worldRef || !item || item.dead) return true;
|
|
if (typeof worldRef.placementBlocked === "function" && worldRef.placementBlocked(item)) return true;
|
|
const itemRects = worldRef.solidObstacleRects?.(item) || globalThis.TarinaiCollisionFootprints?.placementRectsFor?.(worldRef, item) || [];
|
|
const itemRadius = presetItemFootprintRadius(worldRef, item);
|
|
const search = Math.max(120, itemRadius * 3.2);
|
|
for (const other of worldRef.nearbyItems?.(item.x, item.y, search) || worldRef.items || []) {
|
|
if (!other || other === item || other.dead) continue;
|
|
const sameType = other.type === item.type;
|
|
const otherIsFence = worldRef.isFenceType?.(other.type) || false;
|
|
const itemIsFence = worldRef.isFenceType?.(item.type) || false;
|
|
if (!opts.avoidAllObstacles && !sameType && !otherIsFence && !itemIsFence) continue;
|
|
const otherRects = worldRef.solidObstacleRects?.(other) || globalThis.TarinaiCollisionFootprints?.placementRectsFor?.(worldRef, other) || [];
|
|
const otherRadius = presetItemFootprintRadius(worldRef, other);
|
|
const margin = (itemIsFence || otherIsFence) ? 4 : Math.max(8, Math.min(itemRadius, otherRadius) * 0.28);
|
|
if (itemRects.length && otherRects.length) {
|
|
if (itemRects.some(a => otherRects.some(b => globalThis.TarinaiCollisionFootprints?.rectsOverlap?.(a, b, margin)))) return true;
|
|
continue;
|
|
}
|
|
if (itemRects.length) {
|
|
if (itemRects.some(r => globalThis.TarinaiCollisionFootprints?.rectCircleOverlap?.(r, other.x, other.y, otherRadius, margin))) return true;
|
|
continue;
|
|
}
|
|
if (otherRects.length) {
|
|
if (otherRects.some(r => globalThis.TarinaiCollisionFootprints?.rectCircleOverlap?.(r, item.x, item.y, itemRadius, margin))) return true;
|
|
continue;
|
|
}
|
|
if (Math.hypot((item.x || 0) - (other.x || 0), (item.y || 0) - (other.y || 0)) < itemRadius + otherRadius + margin) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function findPresetItemSpot(worldRef, item, opts = {}) {
|
|
const allowOriginal = opts.allowOriginal !== false;
|
|
if (allowOriginal && !presetItemPlacementBlocked(worldRef, item, opts)) return { x: item.x, y: item.y };
|
|
const solid = Boolean(worldRef?.isFenceType?.(item.type) || item.type === "rotator" || item.type === "reciprocator" || item.type === "nest_box");
|
|
const count = Math.max(12, Number(opts.attempts || 0) || (solid ? 96 : 58));
|
|
const maxRadius = Math.max(70, Number(opts.maxRadius || 0) || (solid ? 220 : 170));
|
|
const golden = Math.PI * (3 - Math.sqrt(5));
|
|
let best = null;
|
|
let bestD = Infinity;
|
|
const seed = `${item.type}:${Math.round(item.x)},${Math.round(item.y)}`;
|
|
for (let i = 0; i < count; i++) {
|
|
const t = count <= 1 ? 1 : i / (count - 1);
|
|
const radius = Math.max(10, maxRadius * Math.sqrt(t));
|
|
const angle = i * golden + (globalThis.stableUnit ? globalThis.stableUnit(seed, "preset-place") : Math.random()) * Math.PI * 2;
|
|
const rawX = item.x + Math.cos(angle) * radius;
|
|
const rawY = item.y + Math.sin(angle) * radius * 0.74;
|
|
const p = worldRef.placementClampPointFor?.(item, rawX, rawY) || { x: clamp(rawX, 42, worldRef.w - 42), y: clamp(rawY, 42, worldRef.h - 42) };
|
|
const oldX = item.x, oldY = item.y;
|
|
item.x = p.x; item.y = p.y; syncPresetMechanicalPose(item);
|
|
const blocked = presetItemPlacementBlocked(worldRef, item, opts);
|
|
item.x = oldX; item.y = oldY; syncPresetMechanicalPose(item);
|
|
if (blocked) continue;
|
|
const d = Math.hypot(p.x - oldX, p.y - oldY);
|
|
if (d < bestD) { best = p; bestD = d; }
|
|
}
|
|
return best;
|
|
}
|
|
|
|
function addPresetItem(worldRef, type, x, y, opts = {}) {
|
|
const item = new Item(type, x, y);
|
|
if (Number.isFinite(Number(opts.r))) item.r = Number(opts.r);
|
|
if (Number.isFinite(Number(opts.angle))) item.angle = Number(opts.angle);
|
|
if (opts.toolSize) item.toolSize = opts.toolSize;
|
|
if (type === "duplicator") {
|
|
item.storedFoodType = opts.storedFoodType || "sweet";
|
|
item.storedFoodLabel = typeof toolLabel === "function" ? toolLabel(item.storedFoodType) : item.storedFoodType;
|
|
if (item.roles) item.roles.food = true;
|
|
}
|
|
if (type === "rotator" || type === "reciprocator") configurePresetMechanicalItem(item, opts);
|
|
if (opts.avoidOverlap) {
|
|
const spot = findPresetItemSpot(worldRef, item, opts);
|
|
if (!spot) return null;
|
|
item.x = spot.x;
|
|
item.y = spot.y;
|
|
syncPresetMechanicalPose(item);
|
|
}
|
|
if (worldRef.addItem) worldRef.addItem(item, opts.reason || `preset-${type}`);
|
|
else worldRef.items.push(item);
|
|
return item;
|
|
}
|
|
|
|
function addPresetGrass(worldRef, count, zone = null) {
|
|
for (let i = 0; i < count; i++) {
|
|
const p = randPoint(worldRef, 70, zone);
|
|
const grass = addPresetItem(worldRef, "grass", p.x, p.y, { reason: "preset-grass" });
|
|
globalThis.TarinaiGrass?.setStage?.(grass, Math.floor(rand(0, 2.999)), { force: true });
|
|
}
|
|
}
|
|
|
|
function addPresetTarinai(worldRef, count, zone = null, opts = {}) {
|
|
for (let i = 0; i < count; i++) {
|
|
const p = randPoint(worldRef, 82, zone);
|
|
worldRef.addTarinai({ x: p.x, y: p.y, generation: opts.generation || 1 });
|
|
}
|
|
}
|
|
|
|
function addPresetItemsScattered(worldRef, type, count, zone = null, opts = {}) {
|
|
let placed = 0;
|
|
const n = Math.max(0, Number(count) | 0);
|
|
const attempts = opts.avoidOverlap ? Math.max(n * 4, n + 8) : n;
|
|
for (let i = 0; i < attempts && placed < n; i++) {
|
|
const p = randPoint(worldRef, opts.pad || 82, zone);
|
|
const item = addPresetItem(worldRef, type, p.x, p.y, opts);
|
|
if (item) placed++;
|
|
}
|
|
}
|
|
|
|
function addPresetFenceLine(worldRef, count, yRatio, angle = 0, type = "fence_h", opts = {}) {
|
|
const n = Math.max(1, Number(count) | 0);
|
|
const gap = worldRef.w / (n + 1);
|
|
for (let i = 1; i <= n; i++) {
|
|
addPresetItem(worldRef, type, gap * i, worldRef.h * yRatio + rand(-24, 24), { angle, reason: opts.reason || "preset-fence", avoidOverlap: !!opts.avoidOverlap, avoidAllObstacles: !!opts.avoidAllObstacles, attempts: opts.attempts || 96, maxRadius: opts.maxRadius || 190 });
|
|
}
|
|
}
|
|
|
|
function addPresetFencesScattered(worldRef, count, zone = null, opts = {}) {
|
|
const n = Math.max(0, Number(count) | 0);
|
|
let placed = 0;
|
|
const attempts = opts.avoidOverlap ? Math.max(n * 4, n + 8) : n;
|
|
for (let i = 0; i < attempts && placed < n; i++) {
|
|
const p = randPoint(worldRef, opts.pad || 78, zone);
|
|
const vertical = Math.random() < 0.5;
|
|
const item = addPresetItem(worldRef, vertical ? "fence_v" : "fence_h", p.x, p.y, { angle: randomPresetAngle(Math.PI / 4), reason: opts.reason || "preset-fence-scatter", avoidOverlap: !!opts.avoidOverlap, attempts: opts.attempts || 80, maxRadius: opts.maxRadius || 180 });
|
|
if (item) placed++;
|
|
}
|
|
}
|
|
|
|
function generateDefaultPreset(worldRef, field, seedPopulation) {
|
|
const population = seedPopulation ?? field.population ?? CONFIG.initialPopulation;
|
|
const grassCount = field.grass ?? 18;
|
|
addPresetTarinai(worldRef, population);
|
|
addPresetGrass(worldRef, grassCount);
|
|
addPresetItem(worldRef, "stone", worldRef.w * 0.68, worldRef.h * 0.32, { reason: "reset-stone" });
|
|
}
|
|
|
|
function generateAthleticPreset(worldRef, field) {
|
|
const factor = presetScaleForField(field);
|
|
const fieldId = field?.id || "garden";
|
|
const compact = fieldId === "cage" || fieldId === "garden";
|
|
const center = { x0: worldRef.w * 0.10, x1: worldRef.w * 0.90, y0: worldRef.h * 0.14, y1: worldRef.h * 0.86 };
|
|
addPresetTarinai(worldRef, presetCount(field, 14, 7, 24), { x0: worldRef.w * 0.08, x1: worldRef.w * 0.30, y0: worldRef.h * 0.18, y1: worldRef.h * 0.82 });
|
|
// \u7269\u7406\u30D6\u30ED\u30C3\u30AF\u306F\u67F5\u3088\u308A\u5148\u306B\u7F6E\u304F\u3002\u72ED\u3044\u4E2D\u5C0F\u30D5\u30A3\u30FC\u30EB\u30C9\u3067\u306F\u67F5\u5074\u3092\u9593\u5F15\u304D\u3001\u30D6\u30ED\u30C3\u30AF\u3092\u512A\u5148\u3059\u308B\u3002
|
|
addPresetItemsScattered(worldRef, "stone", presetCount(field, compact ? 4 : 6, 3, 9), center, { pad: compact ? 118 : 132, reason: "preset-athletic-physical-block", avoidOverlap: true, avoidAllObstacles: true, attempts: 140, maxRadius: compact ? 260 : 220 });
|
|
addPresetItemsScattered(worldRef, "stove", presetCount(field, 2, 1, 3), center, { pad: 118, reason: "preset-athletic-stove", avoidOverlap: true, avoidAllObstacles: true, attempts: 100, maxRadius: 210 });
|
|
addPresetItemsScattered(worldRef, "ball", presetCount(field, compact ? 8 : 10, 4, 18), null, { pad: 96, reason: "preset-ball", avoidOverlap: true, avoidAllObstacles: true, attempts: 90, maxRadius: compact ? 230 : 190 });
|
|
addPresetFenceLine(worldRef, Math.max(2, Math.round((compact ? 3 : 4) * factor)), 0.36, 0, "fence_h", { avoidOverlap: true, avoidAllObstacles: true, attempts: 120, maxRadius: compact ? 250 : 210, reason: "preset-athletic-fence-line" });
|
|
addPresetFenceLine(worldRef, Math.max(1, Math.round((compact ? 2 : 3) * factor)), 0.62, Math.PI / 2, "fence_v", { avoidOverlap: true, avoidAllObstacles: true, attempts: 120, maxRadius: compact ? 250 : 210, reason: "preset-athletic-fence-line" });
|
|
addPresetFencesScattered(worldRef, Math.max(1, Math.round((compact ? 2 : 4) * factor)), null, { pad: 108, reason: "preset-athletic-fence", avoidOverlap: true, avoidAllObstacles: true, attempts: 120, maxRadius: compact ? 250 : 210 });
|
|
addPresetItemsScattered(worldRef, "rotator", Math.max(1, Math.round(2 * factor)), null, { pad: 148, reason: "preset-rotator-slow-custom", motorSpeed: Math.PI * 0.18, thickness: 14, avoidOverlap: true, avoidAllObstacles: true, attempts: 140, maxRadius: compact ? 280 : 240 });
|
|
addPresetItemsScattered(worldRef, "reciprocator", Math.max(1, Math.round(2 * factor)), null, { pad: 148, reason: "preset-reciprocator-slow-custom", railMotorSpeed: 36, railTravel: 120, thickness: 14, avoidOverlap: true, avoidAllObstacles: true, attempts: 140, maxRadius: compact ? 280 : 240 });
|
|
}
|
|
|
|
function generateCrowdedPreset(worldRef, field) {
|
|
const center = { x0: worldRef.w * 0.18, x1: worldRef.w * 0.82, y0: worldRef.h * 0.18, y1: worldRef.h * 0.82 };
|
|
addPresetTarinai(worldRef, presetCount(field, 36, 18, 58), center);
|
|
addPresetItemsScattered(worldRef, "nest_box", presetCount(field, 13, 7, 22), center, { pad: 96, reason: "preset-nest-box" });
|
|
addPresetItemsScattered(worldRef, "duplicator", presetCount(field, 3, 2, 5), center, { pad: 110, storedFoodType: "sweet", reason: "preset-duplicator-zunda" });
|
|
addPresetGrass(worldRef, presetCount(field, 18, 8, 34), center);
|
|
addPresetItemsScattered(worldRef, "water", presetCount(field, 8, 4, 16), center, { pad: 84, reason: "preset-water" });
|
|
}
|
|
|
|
function generateFamilyPreset(worldRef, field) {
|
|
const cx = worldRef.w * 0.5;
|
|
const cy = worldRef.h * 0.52;
|
|
worldRef.addTarinai({ x: cx - 52, y: cy + 20, generation: 1 });
|
|
worldRef.addTarinai({ x: cx + 52, y: cy + 20, generation: 1 });
|
|
addPresetItem(worldRef, "nest_box", cx, cy - 58, { reason: "preset-family-nest" });
|
|
addPresetItem(worldRef, "duplicator", cx, cy + 112, { storedFoodType: "love_mochi", reason: "preset-family-duplicator" });
|
|
}
|
|
|
|
function generateWarPreset(worldRef, field) {
|
|
const left = { x0: worldRef.w * 0.08, x1: worldRef.w * 0.45, y0: worldRef.h * 0.16, y1: worldRef.h * 0.84 };
|
|
const right = { x0: worldRef.w * 0.55, x1: worldRef.w * 0.92, y0: worldRef.h * 0.16, y1: worldRef.h * 0.84 };
|
|
addPresetTarinai(worldRef, Math.ceil(presetCount(field, 28, 14, 48) / 2), left);
|
|
addPresetTarinai(worldRef, Math.floor(presetCount(field, 28, 14, 48) / 2), right);
|
|
addPresetItemsScattered(worldRef, "duplicator", presetCount(field, 3, 2, 5), { x0: worldRef.w * 0.38, x1: worldRef.w * 0.62, y0: worldRef.h * 0.22, y1: worldRef.h * 0.78 }, { pad: 96, storedFoodType: "fight_mochi", reason: "preset-war-duplicator" });
|
|
addPresetItemsScattered(worldRef, "ball", presetCount(field, 8, 4, 14), null, { pad: 90, reason: "preset-war-ball" });
|
|
addPresetItemsScattered(worldRef, "ant_nest", presetCount(field, 1.25, 1, 2), null, { pad: 116, reason: "preset-war-ant-nest", avoidOverlap: true, attempts: 80, maxRadius: 190 });
|
|
addPresetItemsScattered(worldRef, "pushpin", presetCount(field, 5, 2, 9), null, { pad: 88, reason: "preset-war-pushpin-reduced" });
|
|
addPresetItemsScattered(worldRef, "oshibyo", presetCount(field, 8, 4, 16), null, { pad: 88, reason: "preset-war-oshibyo" });
|
|
addPresetFencesScattered(worldRef, presetCount(field, 8, 4, 14), null, { pad: 94, reason: "preset-war-fence" });
|
|
}
|
|
|
|
function generateHappyPreset(worldRef, field) {
|
|
const center = { x0: worldRef.w * 0.16, x1: worldRef.w * 0.84, y0: worldRef.h * 0.16, y1: worldRef.h * 0.84 };
|
|
addPresetTarinai(worldRef, presetCount(field, 16, 8, 28), center);
|
|
addPresetItemsScattered(worldRef, "nest_box", presetCount(field, 8, 4, 14), center, { pad: 96, reason: "preset-happy-nest-box" });
|
|
addPresetItemsScattered(worldRef, "robot_cleaner", presetCount(field, 2, 1, 3), center, { pad: 110, reason: "preset-happy-robot-cleaner" });
|
|
addPresetItemsScattered(worldRef, "duplicator", presetCount(field, 2, 1, 4), center, { pad: 110, storedFoodType: "sweet", reason: "preset-happy-duplicator-zunda" });
|
|
addPresetItemsScattered(worldRef, "ball", presetCount(field, 6, 3, 10), center, { pad: 88, reason: "preset-happy-ball" });
|
|
}
|
|
|
|
function generatePresetWorld(worldRef, field, presetId, seedPopulation) {
|
|
switch (normalizeResetPresetId(presetId)) {
|
|
case "empty": return;
|
|
case "athletic": return generateAthleticPreset(worldRef, field);
|
|
case "crowded": return generateCrowdedPreset(worldRef, field);
|
|
case "family": return generateFamilyPreset(worldRef, field);
|
|
case "war": return generateWarPreset(worldRef, field);
|
|
case "happy": return generateHappyPreset(worldRef, field);
|
|
case "default":
|
|
default:
|
|
return generateDefaultPreset(worldRef, field, seedPopulation);
|
|
}
|
|
}
|
|
|
|
function groundForResetPreset(presetId = "default") {
|
|
const id = normalizeResetPresetId(presetId);
|
|
if (id === "athletic") return "ice";
|
|
if (id === "war") return "foot_massage";
|
|
if (id === "happy") return "blanket";
|
|
return "soil";
|
|
}
|
|
|
|
function presetLabel(presetId = "default") {
|
|
return RESET_PRESETS[normalizeResetPresetId(presetId)]?.label || "\u30C7\u30D5\u30A9\u30EB\u30C8";
|
|
}
|
|
|
|
const api = Object.freeze({
|
|
ids: Object.freeze(Object.keys(RESET_PRESETS)),
|
|
definitions: RESET_PRESETS,
|
|
normalize: normalizeResetPresetId,
|
|
generatePresetWorld,
|
|
groundForResetPreset,
|
|
label: presetLabel,
|
|
});
|
|
global.TarinaiResetPresets = api;
|
|
global.TarinaiWorldResetPresets = api;
|
|
})(typeof window !== "undefined" ? window : globalThis);
|