122 lines
5.9 KiB
JavaScript
122 lines
5.9 KiB
JavaScript
"use strict";
|
|
|
|
// Layer: entity-runtime/items/support
|
|
// Owns shared lifecycle support helpers used by dynamic item systems and
|
|
// placement/tool commands. The runtime imports these via
|
|
// globals instead of carrying helper implementations inline.
|
|
(function (global) {
|
|
const DUPLICATOR_STORABLE_TYPES = new Set([
|
|
"food", "sweet", "love_mochi", "fight_mochi", "sleep_drug", "first_aid", "sedative",
|
|
"laxative", "protein", "niteropu", "ammo", "mystery_drug", "mercury", "giant_drug", "dwarf_drug",
|
|
"zunda_juice", "water", "pushpin", "oshibyo"
|
|
]);
|
|
|
|
function duplicatorLoadTypeForItem(item) {
|
|
if (!item || item.dead || item.type === "duplicator") return "";
|
|
const type = String(item.type || "");
|
|
if (!type || type === "grass") return "";
|
|
if ((isPinType(type)) && item.pinState === "lodged") return "";
|
|
if (type === "slave_chain" || type === "golden_crown") return "";
|
|
// Explicit list first. \u3053\u308c\u3067\u300c\u305a\u3093\u3060\u9905\u300d\u300c\u3078\u3053\u9905\u300d\u300c\u3051\u3093\u304b\u9905\u300d\u304c
|
|
// serving-food \u5224\u5b9a\u3084 medicine role \u306e\u63fa\u308c\u306b\u5de6\u53f3\u3055\u308c\u305a\u8907\u88fd\u6a5f\u3078\u5165\u308b\u3002
|
|
if (DUPLICATOR_STORABLE_TYPES.has(type)) return type;
|
|
if (isServingFoodType(type)) return type;
|
|
if (isParamEffectItemType(type)) return type;
|
|
const foodDef = global.TarinaiItemRegistry.food?.get?.(type);
|
|
if (foodDef && (Number(foodDef.nutrition || 0) > 0 || foodDef.effectId)) return type;
|
|
if (typeof roleMatches === "function" && roleMatches(item, "medicine")) return type;
|
|
return "";
|
|
}
|
|
|
|
|
|
|
|
function duplicatorLoadPoint(duplicator) {
|
|
const r = duplicator?.r || 34;
|
|
return { x: (duplicator?.x || 0) + r * 0.62, y: (duplicator?.y || 0) + r * 0.24 };
|
|
}
|
|
|
|
function syncDuplicatorRoles(item) {
|
|
if (!item || item.type !== "duplicator") return;
|
|
const type = String(item.storedFoodType || "");
|
|
const pinLoaded = Boolean(type && isPinType(type));
|
|
item.roles.food = Boolean(type && !pinLoaded);
|
|
item.roles.medicine = Boolean(type && !pinLoaded && (type === "sweet" || type === "water" || type === "zunda_juice" || type === "sleep_drug" || (isParamEffectItemType(type))));
|
|
item.roles.drink = Boolean(!pinLoaded && (type === "water" || type === "zunda_juice"));
|
|
item.roles.danger = pinLoaded;
|
|
}
|
|
|
|
function duplicatorSetStoredType(duplicator, storedType = "", worldRef = null, options = {}) {
|
|
if (!duplicator || duplicator.type !== "duplicator") return false;
|
|
if (options.direct !== true && options.force !== true) return false;
|
|
const type = String(storedType || "");
|
|
if (!type) return false;
|
|
const probe = { type, amount: 1, foodServingsRemaining: 1, dead: false };
|
|
const loadType = duplicatorLoadTypeForItem(probe);
|
|
if (!loadType) return false;
|
|
const changed = duplicator.storedFoodType !== loadType;
|
|
if (!changed && duplicator.storedFoodType && !options.force) return true;
|
|
const def = itemDefinition(loadType);
|
|
const newLabel = def?.label || toolLabel(loadType);
|
|
duplicator.storedFoodType = loadType;
|
|
duplicator.storedFoodLabel = newLabel;
|
|
syncDuplicatorRoles(duplicator);
|
|
duplicator.duplicatorPinFlash = isPinType(loadType) ? 0.28 : (duplicator.duplicatorPinFlash || 0);
|
|
const consume = options.consumeItem;
|
|
if (consume && typeof consume === "object") {
|
|
consume.amount = 0;
|
|
consume.foodServingsRemaining = 0;
|
|
}
|
|
worldRef?.markItemBucketsDirty?.(changed ? "duplicator-direct-reloaded" : "duplicator-direct-loaded");
|
|
worldRef?.markSpatialDirty?.(changed ? "duplicator-direct-reloaded" : "duplicator-direct-loaded");
|
|
worldRef?.markTerrainDirty?.(changed ? "duplicator-direct-reloaded" : "duplicator-direct-loaded");
|
|
if (options.log !== false) worldRef?.log?.(`\u8907\u88fd\u6a5f\u306b${duplicator.storedFoodLabel}\u3092\u30bb\u30c3\u30c8\u3057\u305f\u3002`, isPinType(loadType) ? "observe" : "food");
|
|
return true;
|
|
}
|
|
|
|
function duplicatorApplyStoredPin(duplicator, worldRef) {
|
|
const storedType = String(duplicator?.storedFoodType || "");
|
|
if (!duplicator || duplicator.type !== "duplicator" || !isPinType(storedType)) return false;
|
|
if (globalThis.TarinaiSignalSystem?.powerOverride?.(duplicator) === false) return false;
|
|
const now = Number(worldRef?.time || 0);
|
|
if (now < Number(duplicator.nextDuplicatedPinAt || 0)) return false;
|
|
const dish = duplicatorLoadPoint(duplicator);
|
|
const reach = Math.max(24, (duplicator.r || 34) * 0.56);
|
|
const candidates = worldRef?.nearbyTarinai?.(dish.x, dish.y, reach + 72, true) || [];
|
|
for (const t of candidates) {
|
|
if (!t || t.dead || worldRef?.isTarinaiHiddenInNestBox?.(t)) continue;
|
|
if (t.stuckPushpinId || t.currentLodgedPin?.()) continue;
|
|
const hit = reach + Math.max(10, (t.radius || 18) * 0.78);
|
|
if (distXY(dish.x, dish.y, t.x, t.y) > hit) continue;
|
|
const pin = new Item(storedType, dish.x, dish.y);
|
|
pin.amount = 999;
|
|
pin.noStickUntil = 0;
|
|
pin.noStickTargetId = "";
|
|
pin.noStickTargetUntil = 0;
|
|
const added = worldRef?.addItem?.(pin, "duplicator-pin", { terrain: false }) || null;
|
|
if (!added) return false;
|
|
const ok = global.TarinaiItemDynamicPinSystem.attach(pin, t, worldRef, distXY(dish.x, dish.y, t.x, t.y));
|
|
if (!ok) {
|
|
pin.amount = 0;
|
|
continue;
|
|
}
|
|
duplicator.usedCount = (duplicator.usedCount || 0) + 1;
|
|
duplicator.nextDuplicatedPinAt = now + 0.82;
|
|
duplicator.duplicatorPinFlash = 0.24;
|
|
worldRef.effects?.push(new Effect("ring", dish.x, dish.y, { size: Math.max(15, (duplicator.r || 34) * 0.62), life: 0.18, color: storedType === "oshibyo" ? "rgba(73,119,205,0.40)" : "rgba(214,72,72,0.42)" }));
|
|
worldRef.drawListDirty = true;
|
|
worldRef.markSpatialDirty?.("duplicator-pin-lodged");
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
global.TarinaiItemLifecycleRuntimeSupport = Object.freeze({
|
|
duplicatorLoadTypeForItem,
|
|
duplicatorLoadPoint,
|
|
syncDuplicatorRoles,
|
|
duplicatorSetStoredType,
|
|
duplicatorApplyStoredPin,
|
|
});
|
|
|
|
|
|
})(typeof window !== "undefined" ? window : globalThis);
|