import type { ItemUseInput } from "./use.js"; /** * Per-behavior configuration stored on an item as plain data (e.g. charge time, * projectile id). Kept opaque here so no game noun leaks into item core. */ export type BehaviorConfig = Record; /** * A single behavior's mutable, serializable runtime state (e.g. current charge, * rounds queued). Composed state is a map of these keyed by behavior id. */ export type BehaviorState = Record; /** * A serialized snapshot of every behavior's state on one item, keyed by * behavior id. Round-trips through JSON so it can live in a saved game. */ export type SerializedBehaviorState = Record; /** * The reference an item stores for one composed behavior: a stable behavior id, * optional config, and an optional order override. Pure data — the item core * never holds the implementation, only this reference. */ export interface UseBehaviorRef { id: string; config?: BehaviorConfig; order?: number; } /** * The context handed to each behavior hook: the shared folded `world`, this * behavior's own `config` and `state` slice, and the triggering use input. */ export interface UseBehaviorContext { world: TWorld; config: BehaviorConfig; state: BehaviorState; input: ItemUseInput; } /** * The result of applying one behavior: the (possibly advanced) world, this * behavior's updated state, an optional error that aborts the chain, and an * optional `stop` that ends the chain after a successful apply. */ export interface UseBehaviorOutcome { world: TWorld; state?: BehaviorState; error?: string; stop?: boolean; } /** A reason a behavior refused a use, surfaced from `can`. */ export interface UseBehaviorRejection { reason: string; } /** * A registered behavior implementation. The combat/game side registers these * (charge, thrown-reload, projectile-replacement, …); the item core only ever * stores a {@link UseBehaviorRef} to one by id. Hooks are the lifecycle: `init` * builds serializable state, `can` gates, `apply` folds the world. */ export interface UseBehaviorDef { id: string; /** Lower runs first; ties break on the item's ref order. Default 0. */ order?: number; /** Capability tokens the host must supply at compose time for this behavior. */ requires?: readonly string[]; /** Behavior ids that cannot coexist with this one on the same item. */ conflicts?: readonly string[]; /** Build initial serializable state from config; defaults to an empty object. */ init?(config: BehaviorConfig): BehaviorState; /** Gate the use before applying; return a rejection or null to allow. */ can?(ctx: UseBehaviorContext): UseBehaviorRejection | null; /** Apply the behavior, folding the shared world and this behavior's state. */ apply(ctx: UseBehaviorContext): UseBehaviorOutcome; } /** * A resolved, ordered composition of behaviors for one item. Dispatch is * transactional: `apply` commits the folded world only if every behavior in the * chain succeeds, otherwise it returns the original world and state plus the * first error. */ export interface ComposedUse { /** The resolved run order as behavior ids. */ order(): readonly string[]; /** Fresh per-behavior state for a new item instance, keyed by behavior id. */ initialState(): SerializedBehaviorState; /** First rejection across behaviors (in order), or null if all allow the use. */ can(world: TWorld, state: SerializedBehaviorState, input: ItemUseInput): UseBehaviorRejection | null; /** Run the chain in order; commit folded world+state only on full success. */ apply(world: TWorld, state: SerializedBehaviorState, input: ItemUseInput): { world: TWorld; state: SerializedBehaviorState; error?: string; }; } /** * The outcome of composing an item's behavior refs: either a ready * {@link ComposedUse} or a structured error naming the offending behavior. */ export type CompositionResult = { status: "ok"; composed: ComposedUse; } | { status: "error"; reason: "unknown-behavior"; id: string; } | { status: "error"; reason: "duplicate-behavior"; id: string; } | { status: "error"; reason: "missing-capability"; id: string; capability: string; } | { status: "error"; reason: "conflict"; id: string; conflictsWith: string; }; /** * A registry of use-behavior implementations plus a composer that turns an * item's stored refs into an ordered, conflict-checked {@link ComposedUse}. */ export interface UseBehaviorRegistry { /** Register behavior implementations; throws on a duplicate id. */ register(defs: readonly UseBehaviorDef[]): void; has(id: string): boolean; get(id: string): UseBehaviorDef | null; /** All registered behavior ids, in registration order. */ ids(): string[]; /** Resolve an item's refs into a composed dispatcher, or a structured error. */ compose(refs: readonly UseBehaviorRef[], options?: { capabilities?: readonly string[]; }): CompositionResult; } /** * Create an empty use-behavior registry. Games register their behaviors, then * compose each item's stored refs into a dispatcher whose serializable state * lives with the item. * * @capability item-use-composition compose pluggable, ordered item use-behaviors from serializable references */ export declare function createUseBehaviorRegistry(): UseBehaviorRegistry;