tarinai/js/freeze_system.js
2026-06-26 19:04:32 +09:00

158 lines
5.2 KiB
JavaScript

"use strict";
(function (global) {
function deps() {
return {
Store: global.TarinaiFreezeStore,
Adapter: global.TarinaiFreezeSnapshotAdapter,
Panel: global.TarinaiFreezePanel,
};
}
function depsReady() {
const d = deps();
return Boolean(d.Store && d.Adapter && d.Panel);
}
function warnMissing(context) {
if (global.console?.warn) console.warn(`freeze_system.js dependencies are not available yet (${context})`);
}
let pendingThawId = "";
function frozenList(worldRef = global.world) {
const { Store } = deps();
if (!Store?.frozenList) return [];
return Store.frozenList(worldRef);
}
function renderFrozenPanel(worldRef = global.world) {
const { Panel } = deps();
if (!Panel?.render) return;
Panel.render(frozenList(worldRef));
}
function saveFrozenStore(worldRef = global.world) {
const { Store } = deps();
if (!Store?.save) return;
Store.save(worldRef);
}
function loadFrozenStore(worldRef = global.world) {
const { Store } = deps();
return Store?.load ? Store.load(worldRef) : [];
}
function refreshWorldAfterFreezeChange(worldRef = global.world, selected = null) {
if (!worldRef) return;
if (selected !== undefined) worldRef.selected = selected;
worldRef.drawListDirty = true;
worldRef.familyTreeDirty = true;
worldRef.updateItemCounts?.();
worldRef.rebuildSpatial?.(true);
saveFrozenStore(worldRef);
worldRef.emit?.("freeze:changed", { world: worldRef, selected, renderWorld: true });
}
function freezeTarinai(t, worldRef = global.world) {
const { Adapter } = deps();
if (!Adapter?.makeEntry) { warnMissing("freezeTarinai"); return false; }
if (!t || t.dead || !worldRef) return false;
const entry = Adapter.makeEntry(t, worldRef);
worldRef.clearLiveReferencesTo?.(t);
if (t.id && worldRef.liveTarinai?.has?.(t.id)) worldRef.liveTarinai.delete(t.id);
worldRef.tarinai = (worldRef.tarinai || []).filter(o => o !== t);
if (worldRef.selected === t) worldRef.selected = null;
frozenList(worldRef).push(entry);
refreshWorldAfterFreezeChange(worldRef, worldRef.selected);
global.showToast?.(`${t.name}を冷凍保存しました。`);
worldRef.log?.(`${t.name}をフィールド外で冷凍保存した。`, "observe", { participants: [t] });
worldRef.emit?.("tarinai:frozen", { entry, tarinai: t });
return true;
}
function thawFrozen(freezeId, x, y, worldRef = global.world) {
const { Adapter } = deps();
if (!Adapter?.thawEntry) { warnMissing("thawFrozen"); return false; }
const list = frozenList(worldRef);
const index = list.findIndex(e => (e.freezeId || e.id) === freezeId);
if (index < 0 || !worldRef) return false;
const entry = list[index];
let t = null;
try {
t = Adapter.thawEntry(entry, x, y, worldRef);
} catch (_) {
return false;
}
worldRef.tarinai.push(t);
worldRef.recordFamily?.(t);
list.splice(index, 1);
refreshWorldAfterFreezeChange(worldRef, t);
global.showToast?.(`${t.name}を解凍しました。`);
worldRef.log?.(`${t.name}を解凍してフィールドに戻した。`, "birth", { participants: [t] });
worldRef.emit?.("tarinai:thawed", { entry, tarinai: t });
return true;
}
function bindFreezeSystem() {
if (!depsReady()) {
warnMissing("bindFreezeSystem");
global.setTimeout?.(() => { if (depsReady()) bindFreezeSystem(); }, 0);
return false;
}
const { Panel } = deps();
const worldRef = global.world;
loadFrozenStore(worldRef);
worldRef?.emit?.("freeze:changed", { world: worldRef, renderWorld: false });
Panel.bind({
onSelect(id) {
pendingThawId = id || "";
global.showToast?.("フィールドをクリックすると解凍します。ドラッグ&ドロップでも配置できます。");
},
onDrop(id, x, y) {
thawFrozen(id, x, y, global.world);
},
});
return true;
}
function tryPendingThawAt(x, y, worldRef = global.world) {
if (!pendingThawId) return false;
const id = pendingThawId;
pendingThawId = "";
deps().Panel?.clearPending?.();
return thawFrozen(id, x, y, worldRef);
}
function afterWorldRestored(worldRef = global.world) {
deps().Store?.ensure?.(worldRef);
saveFrozenStore(worldRef);
worldRef?.emit?.("freeze:changed", { world: worldRef, renderWorld: false });
}
function patchWorldPrototype() {
const apply = (proto) => {
const originalHandleClick = proto.handleClick;
proto.handleClick = function (x, y) {
if (tryPendingThawAt(x, y, this)) return;
return originalHandleClick.call(this, x, y);
};
};
if (global.TarinaiPatcher?.patchWorld?.("freezeSystem", apply)) return;
const World = global.World;
if (!World || World.prototype.__freezeSystemPatched) return;
World.prototype.__freezeSystemPatched = true;
apply(World.prototype);
}
patchWorldPrototype();
global.TarinaiFreezeSystem = {
bindFreezeSystem,
renderFrozenPanel,
freezeTarinai,
thawFrozen,
frozenList,
loadFrozenStore,
saveFrozenStore,
afterWorldRestored,
};
})(typeof window !== "undefined" ? window : globalThis);