Files
org_web/assets/scripts/pages/archive-world-state.js
gitea-actions 7afc554f5d
All checks were successful
Build Org Website / build (push) Successful in 44s
Refactor org web content and simplify shared UI
2026-07-29 15:17:17 +01:00

115 lines
3.0 KiB
JavaScript

(function (root, factory) {
"use strict";
const api = factory();
if (typeof module === "object" && module.exports) module.exports = api;
root.ArchiveWorldState = api;
}(typeof globalThis !== "undefined" ? globalThis : this, function () {
"use strict";
const VERSION = 1;
const STORAGE_KEY = "zxh_archive_world_v1";
const PALETTES = Object.freeze(["brass", "moss", "berry"]);
const LANDMARK_IDS = Object.freeze([
"gate",
"library",
"study",
"inn",
"workshop",
"playroom",
"museum",
"garden"
]);
const SPAWN = Object.freeze({ x: 640, y: 830 });
function validateName(value) {
const name = String(value || "").trim().replace(/\s+/g, " ");
return name.length >= 1 && name.length <= 20 ? name : null;
}
function validatePalette(value) {
return PALETTES.includes(value) ? value : null;
}
function fresh(name, palette) {
return {
version: VERSION,
name: validateName(name) || "",
palette: validatePalette(palette) || "brass",
discovered: [],
complete: false,
position: { x: SPAWN.x, y: SPAWN.y },
soundEnabled: false
};
}
function clamp(value, min, max, fallback) {
const number = Number(value);
return Number.isFinite(number) ? Math.min(max, Math.max(min, number)) : fallback;
}
function normalize(candidate) {
if (!candidate || candidate.version !== VERSION) return null;
const name = validateName(candidate.name);
const palette = validatePalette(candidate.palette);
if (!name || !palette) return null;
const discovered = Array.isArray(candidate.discovered)
? Array.from(new Set(candidate.discovered.filter((id) => LANDMARK_IDS.includes(id))))
: [];
return {
version: VERSION,
name,
palette,
discovered,
complete: LANDMARK_IDS.every((id) => discovered.includes(id)),
position: {
x: clamp(candidate.position && candidate.position.x, 36, 1244, SPAWN.x),
y: clamp(candidate.position && candidate.position.y, 36, 924, SPAWN.y)
},
soundEnabled: candidate.soundEnabled === true
};
}
function parse(raw) {
if (!raw) return null;
try {
return normalize(JSON.parse(raw));
} catch (_error) {
return null;
}
}
function discover(state, landmarkId) {
const current = normalize(state);
if (!current || !LANDMARK_IDS.includes(landmarkId)) return current;
if (!current.discovered.includes(landmarkId)) current.discovered.push(landmarkId);
current.complete = LANDMARK_IDS.every((id) => current.discovered.includes(id));
return current;
}
function withPosition(state, x, y) {
const current = normalize(state);
if (!current) return null;
current.position.x = clamp(x, 36, 1244, SPAWN.x);
current.position.y = clamp(y, 36, 924, SPAWN.y);
return current;
}
return Object.freeze({
VERSION,
STORAGE_KEY,
PALETTES,
LANDMARK_IDS,
SPAWN,
validateName,
validatePalette,
fresh,
normalize,
parse,
discover,
withPosition
});
}));