import type { BrainState, Generated, Generation, PetState, View } from "../types.ts"; // `state` is a read-only snapshot of the pet (see engine.ts), replaced after // every change; Preact subscribes to revisions. Animation frames update `view` // without rendering the component tree at 60 Hz. export const store: { state: PetState; badEgg: { raw: string; why: string; newer: boolean } | null; tabOwned: boolean; resetting: boolean; executionRevision: number; } = { state: undefined as unknown as PetState, // set by boot() before rendering badEgg: null, tabOwned: false, resetting: false, executionRevision: 0, }; export const brain: BrainState = { worker: null, state: "off", busy: false, tps: 0, prefillMs: 0, progress: null, threads: 0, id: null, error: "", }; export const upgrade: { state: "idle" | "downloading" | "swapping" | "error"; loaded: number; error: string; } = { state: "idle", loaded: 0, error: "" }; export const view: View = { x: 48, facing: 1, walking: false, target: 48, anim: null, queue: [], effects: [], want: null, wantUntil: 0, dream: null, dreamUntil: 0, game: null, thinking: false, }; export const ui = { live: null as { text: string } | null, diaryWriting: false, diaryDraft: "dear diary,", upgradeOpen: false, storage: "", alertsNote: "", toasts: [] as { id: number; text: string; icon?: string }[], debugLog: [] as (Generated & { at: Date; mode: Generation["mode"] })[], hostingBusy: false, remoteError: "", remoteEndpoint: "", remoteLastSync: 0, remoteGameId: null as string | null, remoteWeather: "", }; let revision = 0; const listeners = new Set<() => void>(); export const snapshot = () => revision; export function subscribe(listener: () => void) { listeners.add(listener); return () => { listeners.delete(listener); }; } export function emit() { revision++; for (const listener of listeners) listener(); } let toastId = 0; export function toast(text: string, icon?: string) { const id = ++toastId; ui.toasts.push({ id, text, icon }); emit(); setTimeout(() => { ui.toasts = ui.toasts.filter((t) => t.id !== id); emit(); }, 4200); } export function liveBubble() { const bubble = { text: "" }; ui.live = bubble; emit(); return { update(text: string) { if (text && ui.live === bubble) { bubble.text = text; emit(); } }, remove() { if (ui.live === bubble) { ui.live = null; emit(); } }, }; }