"use strict"; (function (global) { const World = global.World; if (!World) throw new Error("World is not available for mixin: world_ants_system.js"); Object.defineProperties(World.prototype, Object.getOwnPropertyDescriptors({ updateAnts(dt) { if (!this.ants) this.ants = []; this.antNestUpdateAccum = (this.antNestUpdateAccum || 0) + dt; if (this.antNestUpdateAccum >= 3.0) { const nestDt = this.antNestUpdateAccum; this.antNestUpdateAccum = 0; const nests = this.itemsOfType?.("ant_nest") || (this.items || []).filter(it => it && !it.dead && it.type === "ant_nest"); for (const nest of nests) { if (global.TarinaiSignalSystem?.powerOverride?.(nest) === false) continue; if (typeof ensureAntNestWorkerPool === "function") ensureAntNestWorkerPool(nest); if (!Number.isFinite(nest.antCount)) nest.antCount = ANT_NEST_START_COUNT || 6; if (typeof syncAntNestCount === "function") syncAntNestCount(this, nest); nest.antSpawnTimer = Math.max(0, (nest.antSpawnTimer || 0) - nestDt); let outside = 0; for (const a of this.ants) if (a && !a.dead && a.kind === "worker" && a.homeId === nest.id) outside += 1; const available = Array.isArray(nest.antWorkers) ? nest.antWorkers.length : Math.max(0, (nest.antCount || 0) - outside); const maxOutside = Math.min(ANT_NEST_MAX_OUTSIDE || 3, nest.antCount || 0); if (available > 0 && outside < maxOutside && (nest.antSpawnTimer || 0) <= 0 && (this.tarinai || []).some(t => t && !t.dead && !t.insideNestBoxId)) { const hp = Array.isArray(nest.antWorkers) && nest.antWorkers.length ? clamp(nest.antWorkers.pop(), 0, ANT_WORKER_HP || 32) : (ANT_WORKER_HP || 32); const a = new AntActor(this, { kind: "worker", homeId: nest.id, x: nest.x + rand(-nest.r * 0.18, nest.r * 0.18), y: nest.y - nest.r * 1.00 + rand(-3, 3), hp, maxHp: ANT_WORKER_HP || 32, }); this.ants.push(a); global.TarinaiAchievements?.recordAntPopulation?.(this); if (typeof syncAntNestCount === "function") syncAntNestCount(this, nest); nest.antSpawnTimer = rand(2.5, 5.5) + outside * 0.65; this.drawListDirty = true; } } } const aliveAntCount = (this.ants || []).reduce((n, a) => n + (a && !a.dead ? 1 : 0), 0); const stride = aliveAntCount >= 28 ? 3 : 2; this.antUpdatePhase = ((this.antUpdatePhase || 0) + 1) % stride; for (let i = 0; i < this.ants.length; i++) { const a = this.ants[i]; if (!a || a.dead) continue; a.updateAccum = (a.updateAccum || 0) + dt; // Keep active hauling responsive, but stagger search/return/wander updates. const force = a.state === "drag" || a.kind === "queen"; if (stride <= 1 || force || ((i + this.antUpdatePhase) % stride === 0)) { const antDt = Math.min(a.updateAccum, 0.18); a.updateAccum = 0; a.update(antDt); } } }, completeAntHaul(home, target) { if (!home || home.dead || home.type !== "ant_nest" || !target || target.dead) return; if (typeof ensureAntNestWorkerPool === "function") ensureAntNestWorkerPool(home); const before = typeof syncAntNestCount === "function" ? syncAntNestCount(this, home) : clamp(Math.round(home.antCount ?? ANT_NEST_START_COUNT ?? 6), 0, ANT_NEST_MAX_COUNT ?? 10); if (before >= (ANT_NEST_MAX_COUNT || 10)) { this.spawnQueenAnt(home); } else { if (Array.isArray(home.antWorkers)) home.antWorkers.push(ANT_WORKER_HP || 32); home.antCount = clamp(before + 1, 0, ANT_NEST_MAX_COUNT || 10); if (typeof syncAntNestCount === "function") syncAntNestCount(this, home); } target.x = home.x; target.y = home.y; audio.antNest?.(); global.TarinaiAchievements?.recordDamageSource?.(target, home, { world: this, reason: "\u30a2\u30ea\u306b\u98df\u3079\u3089\u308c\u305f" }); target.die("\u30a2\u30ea\u306b\u98df\u3079\u3089\u308c\u305f", { achievementDangerKill: true }); this.drawListDirty = true; }, spawnQueenAnt(home) { if (!home || home.dead || home.type !== "ant_nest") return null; if ((home.queenSpawnAt || -999) + (CONFIG.dayLength || 120) > (this.time || 0)) return null; if ((this.ants || []).some(a => a && !a.dead && a.kind === "queen" && a.homeId === home.id)) return null; const spot = this.findAntNestFoundingSpot(home) || { x: clamp((home.x || this.w * 0.5) + rand(-220, 220), 56, this.w - 56), y: clamp((home.y || this.h * 0.5) + rand(-160, 160), 56, this.h - 56), }; home.queenSpawnAt = this.time || 0; const queen = new AntActor(this, { kind: "queen", homeId: home.id, x: home.x, y: home.y - (home.r || 34) * 0.9, foundingX: spot.x, foundingY: spot.y, foundingDelayUntil: (this.time || 0) + 0.35, }); this.ants.push(queen); global.TarinaiAchievements?.recordAntPopulation?.(this); audio.queenAnt?.(); this.drawListDirty = true; return queen; }, findAntNestFoundingSpot(source) { const baseX = Number.isFinite(source?.x) ? source.x : this.w * 0.5; const baseY = Number.isFinite(source?.y) ? source.y : this.h * 0.5; let best = null; let bestD = -Infinity; for (let i = 0; i < 70; i++) { const a = rand(0, Math.PI * 2); const r = rand(150, Math.min(430, Math.max(this.w, this.h) * 0.52)); const x = clamp(baseX + Math.cos(a) * r, 56, this.w - 56); const y = clamp(baseY + Math.sin(a) * r * 0.74, 56, this.h - 56); const nest = new Item("ant_nest", x, y); const spot = this.findPlacementSpot ? this.findPlacementSpot(nest, { allowOriginal: true, maxRadius: 80, attempts: 10 }) : { x, y }; if (!spot) continue; let nearest = Infinity; const nests = this.itemsOfType ? this.itemsOfType("ant_nest") : (this.items || []); for (const it of nests) { if (!it || it.dead || it.type !== "ant_nest") continue; nearest = Math.min(nearest, distXY(spot.x, spot.y, it.x, it.y)); } if (nearest > bestD) { best = spot; bestD = nearest; } if (nearest > 280) break; } return best; } })); })(typeof window !== "undefined" ? window : globalThis);