export const SAVE_VERSION = 1; export const OBJECTIVES = [ { id: "inspect-artwork", label: "Inspect the sealed artwork" }, { id: "collect-document", label: "Collect the covenant document" }, { id: "verify-document", label: "Verify the document in inventory" }, { id: "activate-terminal", label: "Activate the sovereign terminal" }, { id: "exit-chamber", label: "Exit through the unlocked door" }, ]; export function createInitialState() { return { saveVersion: SAVE_VERSION, mode: "BOOT", player: { id: "player.local", spawnId: "chamber.entry", pose: { position: [0, 0.79, 3.35], yaw: 0, pitch: 0 }, checkpoint: { position: [0, 0.79, 3.35], yaw: 0, pitch: 0 }, stance: "STANDING", stability: 100, grounded: false, sitting: false, }, inventory: { capacity: 8, order: [], byId: {} }, world: { entities: { "lamp.floor": { on: true }, "couch.main": { used: false }, "artwork.seal": { inspected: false }, "document.covenant": { present: true, collected: false, verified: false }, "terminal.sovereign": { activated: false }, "door.exit": { locked: true, open: false }, }, }, quest: { id: "trust-chain", stage: 0, status: "ACTIVE" }, settings: { sensitivity: 1, fov: 75, volume: 0.6, invertY: false, reducedMotion: false, highContrast: false, shadows: globalThis.matchMedia?.("(pointer:coarse)")?.matches ? "low" : "high", }, session: { targetId: null, notice: null, returnMode: "PAUSED" }, }; } export function reducer(current, event) { const state = structuredClone(current); const entities = state.world.entities; switch (event.type) { case "MODE_CHANGED": state.mode = event.payload.mode; state.session.returnMode = event.payload.returnMode || state.session.returnMode; break; case "SETTINGS_CHANGED": Object.assign(state.settings, event.payload); break; case "LAMP_ACTIVATED": entities["lamp.floor"].on = true; break; case "LAMP_DEACTIVATED": entities["lamp.floor"].on = false; break; case "ARTWORK_INSPECTED": entities["artwork.seal"].inspected = true; break; case "COUCH_USED": entities["couch.main"].used = true; break; case "DOCUMENT_COLLECTED": { const item = event.payload.item; entities["document.covenant"].present = false; entities["document.covenant"].collected = true; if (!state.inventory.byId[item.id]) { state.inventory.order.push(item.id); state.inventory.byId[item.id] = item; } break; } case "DOCUMENT_VERIFIED": entities["document.covenant"].verified = true; if (state.inventory.byId[event.payload.itemId]) state.inventory.byId[event.payload.itemId].verified = true; break; case "TERMINAL_UNLOCKED": entities["terminal.sovereign"].activated = true; entities["door.exit"].locked = false; break; case "DOOR_OPENED": entities["door.exit"].open = true; break; case "OBJECTIVE_ADVANCED": state.quest.stage = event.payload.stage; state.quest.status = event.payload.status || "ACTIVE"; break; case "MISSION_COMPLETED": state.quest.status = "COMPLETE"; break; case "RESPAWNED": state.player.stability = 100; break; case "CHECKPOINT_RECORDED": state.player.pose = structuredClone(event.payload.pose); state.player.checkpoint = structuredClone(event.payload.pose); break; case "STABILITY_CHANGED": state.player.stability = Math.max(0, Math.min(100, event.payload.value)); break; } return state; } export function durableProjection(state) { return { saveVersion: state.saveVersion, player: { id: state.player.id, spawnId: state.player.spawnId, checkpoint: state.player.checkpoint }, inventory: state.inventory, world: state.world, quest: state.quest, }; } export function currentObjective(state) { const stage = Math.min(state.quest.stage, OBJECTIVES.length - 1); return { ...OBJECTIVES[stage], progress: state.quest.status === "COMPLETE" ? OBJECTIVES.length : stage + 1, total: OBJECTIVES.length, }; }