/** Draws ammo for a `Magazine`'s reload from wherever the reserve pool actually lives. */ export interface MagazineReserve { current(): number; spend(amount: number): boolean; gain?(amount: number): void; } /** Tuning for `createMagazine`: mag capacity, reload delay, and where reserve ammo is drawn from. */ export interface MagazineConfig { capacity: number; reloadMs: number; /** Starting loaded count; defaults to `capacity` (a full mag). */ loaded?: number; /** * A plain number seeds a self-contained reserve pool; a `MagazineReserve` bridges reload draws * into an externally-owned pool (a shared ammo-type stat, another `ResourcePool`); omitted means * an infinite reserve (classic arcade shooter, never locked out of reloading). */ reserve?: number | MagazineReserve; } /** Live magazine tuning; shrinking below loaded rounds rejects unless overflow is explicit. */ export interface MagazineTuning { capacity?: number; reloadMs?: number; /** Defaults to `reject`; returning rounds requires a finite reserve with `gain`. */ overflow?: "reject" | "discard" | "return-to-reserve"; } /** Complete serializable state for a {@link Magazine}; `reserve: null` means infinite reserve. */ export interface MagazineSnapshot { loaded: number; reloadElapsedMs: number | null; reserve: number | null; /** Present and `true` only while a reload is suspended, so idle snapshots keep their shape. */ paused?: boolean; } /** * A per-weapon magazine: discrete loaded rounds, a timed reload that refills from a reserve pool, * and the reserve-pool interaction itself — the primitive that replaces hand-rolling mag size, * reload delay, and reserve bookkeeping per game (#536.2). */ export interface Magazine { loaded(): number; capacity(): number; /** Retune without granting ammo or resetting reload elapsed time; false leaves all state unchanged. */ retune(tuning: MagazineTuning): boolean; /** Reserve rounds available to reload from, or `null` when the reserve is infinite. */ reserve(): number | null; isReloading(): boolean; /** Reload progress in `[0, 1]`; 0 while idle. */ reloadFraction(): number; isEmpty(): boolean; isFull(): boolean; canFire(rounds?: number): boolean; /** Spend `rounds` (default 1) loaded ammo; returns false without effect when insufficient. */ fire(rounds?: number): boolean; /** True when a reload could start: not already full, not already reloading, reserve has rounds. */ canReload(): boolean; /** Begin the reload timer if `canReload()`; returns whether it started. */ startReload(): boolean; /** Suspend an in-progress reload, keeping its elapsed progress, so it can be resumed later. */ pauseReload(): boolean; /** Continue a paused reload from the progress it kept. */ resumeReload(): boolean; /** True while a reload is suspended by `pauseReload()`. */ isPaused(): boolean; /** Abort an in-progress reload; loaded/reserve are unchanged (only completion moves ammo). */ cancelReload(): void; /** Add `amount` to a self-contained numeric reserve (a pickup); a no-op against an infinite or externally-owned reserve without a `gain`. */ addReserve(amount: number): void; /** Advance the reload timer; completes the reload once `reloadMs` has elapsed. */ tick(dtSeconds: number): void; /** Return detached plain data for save, rollback, replay, or worker transfer. */ snapshot(): MagazineSnapshot; /** * Restore decoded snapshot data. Returns false without changing loaded/reload * state when reserve kinds differ or an external reserve cannot reconcile. */ restore(snapshot: MagazineSnapshot): boolean; } /** * Builds a {@link Magazine}: discrete loaded ammo, a timed reload, and reserve-pool interaction. * * @capability magazine a weapon magazine with capacity, timed reload, and reserve-pool interaction */ export declare function createMagazine(config: MagazineConfig): Magazine;