"use strict"; (function (global) { const Snapshot = global.TarinaiSnapshot; const Codec = global.TarinaiSaveCodec; const Storage = global.TarinaiSaveStorage; const Restore = global.TarinaiRestoreCoordinator; if (!Snapshot || !Codec || !Storage || !Restore) throw new Error("save_system.js dependencies are not available"); const SLOT_COUNT = Storage.SLOT_COUNT; const htmlEscape = global.TarinaiUIHelpers.htmlEscape; function createSnapshot(worldRef = global.world, options = {}) { return Snapshot.createSnapshot(worldRef, options); } function restoreSnapshot(snapshot, worldRef = global.world, options = {}) { return Restore.restoreSnapshot(snapshot, worldRef, { syncUi: options.syncUi }); } async function encodeSnapshot(snapshot = createSnapshot(global.world)) { return Codec.encodeSnapshot(snapshot); } async function decodeSnapshot(text) { return Codec.decodeSnapshot(text); } async function saveSlot(slot) { const snapshot = createSnapshot(global.world); const hash = await encodeSnapshot(snapshot); return Storage.writeSlot(slot, hash, { m: snapshot.m }); } async function loadSlot(slot) { const hash = Storage.requireSlot(slot); const snapshot = await decodeSnapshot(hash); return restoreSnapshot(snapshot, global.world); } function deleteSlot(slot) { Storage.deleteSlot(slot); } function readSlot(slot) { return Storage.readSlot(slot); } function formatSlotSummary(entry) { if (!entry) return "\u7a7a\u304d"; const meta = entry.m || entry; const m = meta.m || []; const date = meta.savedAt ? new Date(meta.savedAt).toLocaleString("ja-JP", { month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit" }) : "\u65e5\u6642\u4e0d\u660e"; const day = m[0] || 1; const population = m[1] || 0; const fieldType = m[2] || "\u5ead"; const hashLen = entry.hash ? ` / ${entry.hash.length}\u5b57` : ""; return `${date} / ${fieldType} / ${day}\u65e5\u76ee / ${population}\u5339${hashLen}`; } function requestConfirmation(options = {}) { return global.TarinaiGameDialogs?.confirm?.(options) || Promise.resolve(false); } function ensureDialog() { let dialog = document.getElementById("saveDialog"); if (dialog) return dialog; dialog = document.createElement("div"); dialog.id = "saveDialog"; dialog.className = "field-dialog hidden"; dialog.setAttribute("role", "dialog"); dialog.setAttribute("aria-modal", "true"); dialog.innerHTML = `

\u30bb\u30fc\u30d6 / \u30ed\u30fc\u30c9

\u30bb\u30fc\u30d6\u306f\u5b9f\u9a13\u7684\u6a5f\u80fd\u3067\u3042\u308a\u4fdd\u8a3c\u5bfe\u8c61\u5916\u3067\u3059\u3002

`; document.body.appendChild(dialog); return dialog; } function renderSlotList() { const dialog = ensureDialog(); const list = dialog.querySelector("#saveSlotList"); if (!list) return; list.innerHTML = ""; for (let i = 1; i <= SLOT_COUNT; i++) { const snapshot = readSlot(i); const row = document.createElement("div"); row.className = "save-slot-row"; row.innerHTML = `
\u30b9\u30ed\u30c3\u30c8 ${i}
${htmlEscape(formatSlotSummary(snapshot))}
`; list.appendChild(row); } } function openDialog() { const dialog = ensureDialog(); renderSlotList(); dialog.classList.remove("hidden"); } function closeDialog() { document.getElementById("saveDialog")?.classList.add("hidden"); } function bindSaveSystem() { const btn = document.getElementById("saveBtn"); if (!btn || btn.dataset.saveBound === "1") return; btn.dataset.saveBound = "1"; btn.addEventListener("click", () => { global.audio?.uiClick?.(); openDialog(); }); const dialog = ensureDialog(); if (dialog.dataset.saveDialogBound === "1") return; dialog.dataset.saveDialogBound = "1"; dialog.addEventListener("click", async (e) => { if (e.target === dialog) { closeDialog(); return; } const saveBtn = e.target.closest("[data-save-slot]"); const loadBtn = e.target.closest("[data-load-slot]"); const deleteBtn = e.target.closest("[data-delete-slot]"); if (saveBtn) { const slot = Number(saveBtn.dataset.saveSlot); try { await saveSlot(slot); renderSlotList(); global.audio?.notify?.(); global.showToast?.(`\u30b9\u30ed\u30c3\u30c8${slot}\u306b\u30bb\u30fc\u30d6\u3057\u307e\u3057\u305f\u3002`); } catch (error) { console.warn(error); global.showToast?.("\u30bb\u30fc\u30d6\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002\u7a7a\u304d\u5bb9\u91cf\u3092\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044\u3002"); } return; } if (loadBtn) { const slot = Number(loadBtn.dataset.loadSlot); if (!await requestConfirmation({ title: "\u30ed\u30fc\u30c9\u524d\u306e\u78ba\u8a8d", message: `\u30b9\u30ed\u30c3\u30c8${slot}\u3092\u30ed\u30fc\u30c9\u3057\u307e\u3059\u3002\u73fe\u5728\u306e\u72b6\u614b\u306f\u4e0a\u66f8\u304d\u3055\u308c\u307e\u3059\u3002`, confirmText: "\u30ed\u30fc\u30c9\u3059\u308b", })) return; try { await loadSlot(slot); closeDialog(); global.audio?.notify?.(); global.showToast?.(`\u30b9\u30ed\u30c3\u30c8${slot}\u3092\u30ed\u30fc\u30c9\u3057\u307e\u3057\u305f\u3002`); } catch (error) { console.warn(error); global.showToast?.("\u30ed\u30fc\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002"); } return; } if (deleteBtn) { const slot = Number(deleteBtn.dataset.deleteSlot); if (!await requestConfirmation({ title: "\u30bb\u30fc\u30d6\u30c7\u30fc\u30bf\u306e\u524a\u9664", message: `\u30b9\u30ed\u30c3\u30c8${slot}\u306e\u30bb\u30fc\u30d6\u30c7\u30fc\u30bf\u3092\u524a\u9664\u3057\u307e\u3059\u3002`, confirmText: "\u524a\u9664\u3059\u308b", danger: true, })) return; deleteSlot(slot); renderSlotList(); global.audio?.delete?.(); global.showToast?.(`\u30b9\u30ed\u30c3\u30c8${slot}\u3092\u6d88\u3057\u307e\u3057\u305f\u3002`); return; } if (e.target.closest("#saveCloseBtn")) closeDialog(); if (e.target.closest("#saveExportBtn")) { const exportBtn = dialog.querySelector("#saveExportBtn"); const area = dialog.querySelector("#saveHashText"); if (exportBtn?.dataset.busy === "1") return; if (exportBtn) { exportBtn.dataset.busy = "1"; exportBtn.disabled = true; exportBtn.textContent = "\u751f\u6210\u4e2d..."; } try { const hash = await encodeSnapshot(createSnapshot(global.world, { includeAchievements: true })); if (!hash || typeof hash !== "string") throw new Error("save text was not generated"); if (area) { area.value = hash; area.focus(); area.select(); } global.showToast?.("\u546a\u6587\u3092\u30bb\u30fc\u30d6\u3057\u307e\u3057\u305f\u3002"); } catch (error) { console.warn("save text generation failed", error); global.showToast?.("\u546a\u6587\u306e\u751f\u6210\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002"); } finally { if (exportBtn) { exportBtn.dataset.busy = "0"; exportBtn.disabled = false; exportBtn.textContent = "\u546a\u6587\u3092\u30bb\u30fc\u30d6"; } } return; } if (e.target.closest("#saveImportBtn")) { const area = dialog.querySelector("#saveHashText"); const text = area?.value || ""; if (!text.trim()) { global.showToast?.("\u30ed\u30fc\u30c9\u3059\u308b\u546a\u6587\u3092\u8cbc\u308a\u4ed8\u3051\u3066\u304f\u3060\u3055\u3044\u3002"); return; } if (!await requestConfirmation({ title: "\u546a\u6587\u306e\u30ed\u30fc\u30c9", message: "\u8cbc\u308a\u4ed8\u3051\u305f\u546a\u6587\u3092\u30ed\u30fc\u30c9\u3057\u307e\u3059\u3002\u73fe\u5728\u306e\u30d5\u30a3\u30fc\u30eb\u30c9\u306f\u4e0a\u66f8\u304d\u3055\u308c\u307e\u3059\u3002", confirmText: "\u30ed\u30fc\u30c9\u3059\u308b", })) return; try { const result = restoreSnapshot(await decodeSnapshot(text), global.world); closeDialog(); global.showToast?.("\u546a\u6587\u304b\u3089\u30ed\u30fc\u30c9\u3057\u307e\u3057\u305f\u3002"); } catch (error) { console.warn(error); global.showToast?.("\u30ed\u30fc\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002\u546a\u6587\u3092\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044\u3002"); } } }); } global.TarinaiSaveSystem = { bindSaveSystem }; })(typeof window !== "undefined" ? window : globalThis);