158 lines
5.2 KiB
JavaScript
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);
|