"use strict"; // Builds and finalizes Tarinai item-interaction scan context. // This keeps scan radius, candidate collection, and post-interaction clamping in one place. (function (global) { function create(tarinai, dt = 0) { if (!tarinai || !tarinai.world) return null; const foodNeed = Number(tarinai.needRaw?.food ?? tarinai.needs?.food ?? 0) || 0; const healthNeed = Number(tarinai.needRaw?.health ?? tarinai.needs?.health ?? 0) || 0; const currentNeed = getTarinaiBehaviorNeed(tarinai); const foodActionActive = currentNeed === "food" || ["seek_food", "eat", "seek_water"].includes(tarinai.state); const healthActionActive = currentNeed === "health" || tarinai.state === "seek_food"; const mealReady = (tarinai.mealCooldownUntil || 0) <= (tarinai.world?.time || 0) || tarinai.hunger > 92 || foodNeed > 84; const wantsFood = foodActionActive || foodNeed >= needThreshold("food", "start") || tarinai.hunger > 70; const wantsMedicine = healthActionActive || healthNeed >= needThreshold("health", "start"); const canBite = !tarinai.isZunchiSlave && tarinai.eatCooldown <= 0 && mealReady && wantsFood && tarinai.hunger > 18; const canSweetBite = !tarinai.isZunchiSlave && tarinai.eatCooldown <= 0 && mealReady && (wantsFood || wantsMedicine) && tarinai.hunger > 7; const canZunchiBite = tarinai.eatCooldown <= 0 && (tarinai.isZunchiSlave ? tarinai.hunger > 16 : (tarinai.hunger >= 102 || foodNeed >= 92)) && (tarinai.isZunchiSlave || !hasBetterFoodThanZunchiNearby(tarinai, tarinai.world, 260)); const scanLimit = 28; const foodScanRadius = tarinai.radius + 92; const nearbyFood = tarinai.world.nearbyFood?.(tarinai.x, tarinai.y, foodScanRadius, true) || []; const nearbyItems = nearbyFood.length ? nearbyFood : tarinai.world.nearbyItems(tarinai.x, tarinai.y, foodScanRadius); const foodCandidates = []; if (tarinai.target && !tarinai.target.dead && (tarinai.target.type === "duplicator" || roleMatches(tarinai.target, "food") || roleMatches(tarinai.target, "medicine"))) foodCandidates.push(tarinai.target); for (const it of nearbyItems) { if (!it || it.dead || foodCandidates.includes(it)) continue; if (!(it.type === "duplicator" || roleMatches(it, "food") || roleMatches(it, "medicine") || it.type === "water")) continue; foodCandidates.push(it); if (foodCandidates.length >= scanLimit) break; } if (foodCandidates.length > 1 && foodCandidates.length <= scanLimit) { foodCandidates.sort((a, b) => foodPriorityScore(tarinai, b, b?.type === "duplicator" ? foodInteractionDistance(tarinai, b) : dist(tarinai, b)) - foodPriorityScore(tarinai, a, a?.type === "duplicator" ? foodInteractionDistance(tarinai, a) : dist(tarinai, a))); } return { dt, foodNeed, healthNeed, currentNeed, foodActionActive, healthActionActive, mealReady, wantsFood, wantsMedicine, canBite, canSweetBite, canZunchiBite, scanLimit, foodScanRadius, nearbyFood, nearbyItems, foodCandidates, }; } function finalize(tarinai) { if (!tarinai) return false; tarinai.hunger = clamp(tarinai.hunger, 0, 115); tarinai.energy = clamp(tarinai.energy, 0, typeof tarinaiMaxEnergy === "function" ? tarinaiMaxEnergy(tarinai) : (Number(tarinai.maxEnergy) || 100)); tarinai.stress = applyGroundStressModifier(tarinai, calculateStressFromNeeds(tarinai.needRaw || tarinai.needs || createDefaultNeeds())); tarinai.loneliness = clamp(tarinai.loneliness, 0, 110); return true; } function contactForCandidate(tarinai, ctx, item, opts = {}) { if (!tarinai || tarinai.dead || !ctx || !item || item.dead) return null; const role = opts.role || "food"; const d = item.type === "duplicator" ? foodInteractionDistance(tarinai, item) : dist(tarinai, item); const baseReach = foodInteractionReach(tarinai, item, role); const activeBonus = item === tarinai.target && ctx.foodActionActive ? Number(opts.activeTargetBonus ?? (item.type === "duplicator" ? 18 : 4)) : 0; const contactReach = baseReach + activeBonus; if (d > contactReach) return null; return { distance: d, reach: contactReach, baseReach }; } global.TarinaiItemInteractionContext = Object.freeze({ create, finalize, contactForCandidate, }); })(typeof window !== "undefined" ? window : globalThis);