66 lines
2.9 KiB
JavaScript
66 lines
2.9 KiB
JavaScript
"use strict";
|
|
|
|
// Layer: entity-runtime/items/decay-system
|
|
// Owns passive amount decay and spoilage side effects 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 (typeof isServingFoodType !== "function" || !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 penalty = global.TarinaiItemRegistry?.food?.hygienePenalty?.(item.type) ?? PASSIVE_FOOD_HYGIENE_PENALTY_PER_SERVING;
|
|
worldRef?.registerFoodSpoilage?.(lost * penalty, item);
|
|
worldRef?.markTerrainDirty?.("food-passive-decay");
|
|
worldRef?.emit?.("item:decayed", { item, type: item.type, amount: lost, passive: 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;
|
|
const penalty = global.TarinaiItemRegistry?.food?.hygienePenalty?.(item.type) ?? 0.002;
|
|
worldRef?.registerFoodSpoilage?.(lost * penalty, item);
|
|
worldRef?.markTerrainDirty?.("food-passive-decay");
|
|
worldRef?.emit?.("item:decayed", { item, type: item.type, amount: lost, passive: 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") item.amount -= dt * 1.05;
|
|
if (item.type === "ant_corpse") item.amount -= dt * 0.018;
|
|
return { done: false };
|
|
}
|
|
|
|
global.TarinaiItemDecaySystem = Object.freeze({
|
|
MEDICINE_LIKE_FOOD_TYPES,
|
|
decayServingFood,
|
|
update,
|
|
});
|
|
})(typeof window !== "undefined" ? window : globalThis);
|