import type { UnlockCatalog } from "../game/unlocks.js"; import type { Standing, StandingRequirement } from "./standing.js"; /** What a gate is evaluated against: standing by track and money by currency. */ export interface GateFacts { standing(trackId: string): number; balance(currency: string): number; } /** Every condition a gate can require; all named conditions must hold. */ export interface GateRequirement { standing?: StandingRequirement; /** Smallest balance of `currency` that passes. */ balance?: { currency: string; min: number; }; } /** * A milestone: content that opens exactly when its requirements hold and names the unlock it * grants. `unlock` must resolve in the catalog the set is built with, or the set refuses to load. */ export interface GateDef { id: string; unlock: string; label?: string; category?: string; requires?: GateRequirement; } /** Which named condition a closed gate still needs. */ export type GateMiss = "standing" | "balance"; /** One gate against live facts. */ export interface GateStatus { gate: GateDef; open: boolean; missing: readonly GateMiss[]; } /** Evaluated gate content: the table, its status against facts, and the grants a caller applies. */ export interface GateSet { gates(): readonly GateDef[]; gate(gateId: string): GateDef | null; status(facts: GateFacts): readonly GateStatus[]; isOpen(gateId: string, facts: GateFacts): boolean; open(facts: GateFacts): readonly GateDef[]; /** Gates met now whose `unlock` is not in `granted` — the unlocks to grant this pass. */ claim(facts: GateFacts, granted: readonly string[]): readonly GateDef[]; } /** Content and the resolvers a {@link GateSet} is built from. */ export interface GateSetConfig { gates: readonly GateDef[]; /** The ids an unlock may resolve to; normally the game's content catalog. */ catalog: Pick; /** The standing a requirement reads; also validates every requirement's track at load. */ standing?: Pick; } /** Read a {@link Standing} and a balance record as {@link GateFacts}. */ export declare function gateFacts(standing: Pick, actorId: string, balances?: Readonly>): GateFacts; /** Check an authored gate table against the content it grants; throws `RangeError` naming the gate. */ export declare function assertGates(config: GateSetConfig): void; /** * Authored unlock gates: each one names the unlock it grants and the standing or balance it reads. * Evaluated against caller-supplied facts, so one table serves a single-player save, a server actor * or a probe. Load refuses a gate whose unlock id resolves to nothing (the D3.8 class), so a dead * milestone fails at startup instead of in play. A gate with no requirements is open from the start. * * @capability unlock-gates milestones gated by standing or money, validated against the content they grant */ export declare function createGateSet(config: GateSetConfig): GateSet;