import type { StatModifierSet } from "../stats/statModifiers.js"; /** * A game-owned named input value. The engine ships no attribute vocabulary — ids, * bounds, defaults, and metadata are entirely caller data, so the same graph can * model STR/AGI/INT, SPECIAL scores, skills, difficulty knobs, or anything else. */ export interface StatInputDef { id: string; /** Default base value a fresh sheet starts at. Defaults to `min ?? 0`. */ base?: number; /** Lower bound applied to the resolved value. */ min?: number; /** Upper bound applied to the resolved value. */ max?: number; /** Free-form, engine-ignored metadata (labels, descriptions, UI hints). */ meta?: Readonly>; } /** How a single contribution folds into a running value. */ export type StatOp = "add" | "mul" | "override" | "clampMin" | "clampMax"; /** * One folded contribution to a value, retained so a sheet can explain * "why is this value 42?" — every step carries the source that produced it. */ export interface StatContribution { /** Provenance label — who/what produced this contribution. */ source: string; op: StatOp; value: number; } /** A modifier entry targeting one stat: a single contribution or an ordered list. */ export type StatModEntry = StatContribution | readonly StatContribution[]; /** The read-only view a derived formula gets: resolved values of its declared dependencies. */ export interface StatDeriveContext { /** Resolved (fully modified) value of a declared dependency (input or derived). */ value(id: string): number; } /** * A derived value whose formula and dependencies are caller-owned. `compute` may * return a scalar (shorthand for a single `add`) or an ordered list of contributions * folded left-to-right, so additive/multiplicative/clamped and conditional modifiers * are all expressed as plain data or branches inside the function. */ export interface StatDerivedDef { id: string; /** ids (inputs or other derived) this formula reads — drives ordering, cycle detection, and selective recompute. */ deps?: readonly string[]; min?: number; max?: number; round?: "floor" | "ceil" | "round"; meta?: Readonly>; compute(ctx: StatDeriveContext): number | readonly StatContribution[]; } /** The full schema of a stat graph: its named inputs and caller-authored derived formulas. */ export interface StatGraphDef { inputs: readonly StatInputDef[]; derived?: readonly StatDerivedDef[]; } /** Plain-data, JSON-safe sheet state: input base values plus registered modifier sources. */ export interface StatSheetState { base: Record; sources: Record>; } /** One line of a provenance trace: a contribution plus the running total after it folds in. */ export interface StatContributionStep extends StatContribution { /** Running total after this contribution folds in. */ subtotal: number; } /** A full provenance trace for one stat: the ordered steps that produced its value. */ export interface StatExplanation { id: string; value: number; steps: StatContributionStep[]; } /** A live per-entity instance of a {@link StatGraph}: mutable base values and modifier sources over a shared schema. */ export interface StatSheet { /** Resolve the fully modified value of an input or derived stat. */ get(id: string): number; /** The stored base of an input stat (before modifiers/clamping). */ getBase(id: string): number; setBase(id: string, value: number): void; /** Register (or replace) a named modifier source targeting one or more stats. */ addSource(sourceId: string, mods: Record): void; removeSource(sourceId: string): boolean; hasSource(sourceId: string): boolean; sources(): string[]; /** Resolve every input and derived stat into a plain record. */ values(): Record; /** Ordered contribution trace explaining a stat's current value. */ explain(id: string): StatExplanation; /** Resolve values under a proposed, uncommitted mutation (e.g. a previewed allocation). */ preview(mutate: (draft: StatSheet) => void): Record; toJSON(): StatSheetState; } /** A compiled, immutable stat-graph schema that mints per-entity {@link StatSheet}s from base values or saved state. */ export interface StatGraph { readonly inputIds: readonly string[]; readonly derivedIds: readonly string[]; create(base?: Record): StatSheet; restore(state: StatSheetState): StatSheet; } /** * A data-driven stat graph: game-owned named inputs feed caller-authored derived * formulas, with contribution provenance, uncommitted previews, cycle detection, and * selective recomputation. Formula semantics and numeric tables stay entirely game-defined. * * @capability stat-graph derive game-defined stats from named inputs with provenance and preview */ export declare function createStatGraph(def: StatGraphDef): StatGraph; /** * Bridge the shared {@link StatModifierSet} shape (add/multiply, used by talents, items, * and buffs) into stat-graph contributions, so a ranked talent tree or gear roll feeds * the graph as one named source instead of a parallel store. * * @capability stat-graph-bridge feed an existing StatModifierSet into a stat-graph source */ export declare function statModifierContributions(source: string, set: StatModifierSet): Record;