import { DefaultValue, getUniqueID, Persistent, persistent, PersistentRef, Replace, SetupPersistence } from "@/features/feature"; import { globalBus } from "@/game/events"; import { GenericLayer } from "@/game/layers"; import Decimal from "@/lib/break_eternity"; import { Computable, GetComputableType, processComputable } from "@/util/computed"; import { createProxy } from "@/util/proxies"; import { Unsubscribe } from "nanoevents"; import { computed, isRef, unref } from "vue"; export const ResetType = Symbol("Reset"); export interface ResetOptions { thingsToReset: Computable[]>; onReset?: VoidFunction; } interface BaseReset { id: string; reset: VoidFunction; type: typeof ResetType; } export type Reset = Replace< T & BaseReset, { thingsToReset: GetComputableType; } >; export type GenericReset = Reset; export function createReset(options: T & ThisType>): Reset { const reset: T & Partial = options; reset.id = getUniqueID("reset-"); reset.type = ResetType; reset.reset = function() { const handleObject = (obj: Record) => { Object.keys(obj).forEach(key => { const value = obj[key]; if (value && typeof value === "object") { if (SetupPersistence in value && isRef(value)) { if (DefaultValue in value) { (value as PersistentRef).value = (value as PersistentRef)[DefaultValue]; } else if (DefaultValue in obj) { (value as PersistentRef).value = ((obj as unknown) as Persistent)[ DefaultValue ]; } } else { handleObject(value as Record); } } }); }; unref(proxy.thingsToReset).forEach(handleObject); globalBus.emit("reset", proxy); proxy.onReset?.(); }; processComputable(reset as T, "thingsToReset"); const proxy = createProxy((reset as unknown) as Reset); return proxy; } export function setupAutoReset( layer: GenericLayer, reset: GenericReset, autoActive: Computable = true ): void { const isActive = typeof autoActive === "function" ? computed(autoActive) : autoActive; layer.on("update", () => { if (unref(isActive)) { reset.reset(); } }); } const listeners: Record = {}; export function trackResetTime(layer: GenericLayer, reset: GenericReset): PersistentRef { const resetTime = persistent(new Decimal(0)); listeners[layer.id] = layer.on("preUpdate", (diff: Decimal) => { resetTime.value = Decimal.add(resetTime.value, diff); }); globalBus.on("reset", currentReset => { if (currentReset === reset) { resetTime.value = new Decimal(0); } }); return resetTime; } globalBus.on("removeLayer", layer => { // unsubscribe from preUpdate listeners[layer.id]?.(); delete listeners[layer.id]; }); declare module "@/game/events" { interface GlobalEvents { reset: (reset: GenericReset) => void; } }