66 lines
2.7 KiB
JavaScript
66 lines
2.7 KiB
JavaScript
"use strict";
|
|
|
|
// Layer: entity-runtime/items/decay-system
|
|
// Owns passive amount decay for water, food, transient traces, splats,
|
|
// and ant corpses. The lifecycle step is now only a
|
|
// thin pipeline adapter.
|
|
(function (global) {
|
|
const MEDICINE_LIKE_FOOD_TYPES = Object.freeze([
|
|
"sweet", "love_mochi", "fight_mochi", "sleep_drug", "laxative", "protein",
|
|
"niteropu", "ammo", "mystery_drug", "mercury", "giant_drug", "dwarf_drug", "zunda_juice",
|
|
]);
|
|
|
|
function decayServingFood(item, dt, worldRef) {
|
|
if (!isServingFoodType(item.type)) return false;
|
|
const interval = passiveFoodDecayInterval(worldRef);
|
|
item.passiveFoodDecayTimer = (item.passiveFoodDecayTimer || 0) + dt;
|
|
let changed = false;
|
|
let ticks = 0;
|
|
while (item.passiveFoodDecayTimer >= interval && ticks < 3) {
|
|
item.passiveFoodDecayTimer -= interval;
|
|
ticks++;
|
|
if (Number.isFinite(item.foodServingsRemaining)) {
|
|
const before = Math.max(0, item.foodServingsRemaining || 0);
|
|
const lost = Math.min(before, interval * passiveFoodDecayRate(item));
|
|
if (lost > 0) {
|
|
changed = true;
|
|
item.foodServingsRemaining = Math.max(0, before - lost);
|
|
item.amount = item.foodServingsRemaining;
|
|
const resized = (typeof updateServingFoodVisualSize === "function" ? updateServingFoodVisualSize(item) : false);
|
|
if (resized) {
|
|
worldRef?.markItemBucketsDirty?.("food-passive-resize");
|
|
worldRef?.markSpatialDirty?.("food-passive-resize");
|
|
if (worldRef) worldRef.drawListDirty = true;
|
|
}
|
|
if (item.foodServingsRemaining <= 0.015) item.amount = 0;
|
|
}
|
|
} else if (MEDICINE_LIKE_FOOD_TYPES.includes(item.type)) {
|
|
const before = item.amount || 0;
|
|
const lost = Math.min(before, interval * 0.12);
|
|
item.amount -= lost;
|
|
if (lost > 0) {
|
|
changed = true;
|
|
}
|
|
}
|
|
}
|
|
return changed;
|
|
}
|
|
|
|
function update(item, dt, worldRef) {
|
|
if (!item || item.dead) return { done: true };
|
|
if (item.type === "water") item.amount -= dt * 0.9;
|
|
decayServingFood(item, dt, worldRef);
|
|
if (item.type === "trace") item.amount -= dt * 1.35;
|
|
if (item.type === "splat") {
|
|
const before = Number(item.amount || 0) || 0;
|
|
item.amount -= dt * 1.05;
|
|
if (Math.floor(before / 18) !== Math.floor(Math.max(0, item.amount) / 18)) {
|
|
worldRef?.markTerrainDirtyAt?.(item.x, item.y, Math.max(item.r || item.radius || 24, 36), "splat-fade");
|
|
}
|
|
}
|
|
if (item.type === "ant_corpse") item.amount -= dt * 0.018;
|
|
return { done: false };
|
|
}
|
|
|
|
global.TarinaiItemDecaySystem = Object.freeze({ update });
|
|
})(typeof window !== "undefined" ? window : globalThis);
|