export interface ItemTraits { stackLimit(itemId: string): number; kind?(itemId: string): string | null; } export interface InventoryLayout { slots: number; accepts?: string | readonly string[]; } export type InventorySlot = { itemId: string; count: number; } | null; export interface InventoryState { slots: InventorySlot[]; } export type PutResult = { status: "ok"; state: InventoryState; } | { status: "rejected"; reason: "no-space" | "wrong-kind" | "slot-occupied" | "invalid-slot"; }; export type TakeResult = { status: "ok"; state: InventoryState; } | { status: "rejected"; reason: "insufficient"; }; export type MoveResult = { status: "ok"; from: InventoryState; to: InventoryState; } | { status: "rejected"; reason: "invalid-slot" | "empty-slot" | "wrong-kind" | "no-space"; }; /** Outcome of {@link splitStack}: the new state, or a rejection reason. */ export type SplitResult = { status: "ok"; state: InventoryState; } | { status: "rejected"; reason: "invalid-slot" | "empty-slot" | "invalid-amount" | "no-space" | "slot-occupied" | "over-stack"; }; /** * A bag of stackable items supporting add, remove, count, and move — the base inventory model. * * @capability inventory-grid a bag of stackable items with add, remove, and move */ export declare function createEmptyInventory(layout: InventoryLayout): InventoryState; /** Add `count` of `itemId` — into a specific `options.slot`, or auto-stacked across free/partial slots. Rejects on no space or wrong kind. */ export declare function putItem(state: InventoryState, layout: InventoryLayout, traits: ItemTraits, itemId: string, count: number, options?: { slot?: number; }): PutResult; /** Remove `count` of `itemId`, draining from the last matching stacks first. Rejects if fewer than `count` are held. */ export declare function takeItem(state: InventoryState, itemId: string, count: number): TakeResult; /** Total quantity of `itemId` summed across every stack in the inventory. */ export declare function countItem(state: InventoryState, itemId: string): number; /** True when the inventory holds at least `count` of `itemId`. */ export declare function hasItem(state: InventoryState, itemId: string, count: number): boolean; /** Move the stack at `fromSlot` to `toSlot` (or auto-stack when omitted) — swapping, merging with remainder, or relocating across two inventories. Rejects on empty source, wrong kind, or no space. */ export declare function moveItem(from: InventoryState, fromSlot: number, to: InventoryState, toLayout: InventoryLayout, traits: ItemTraits, toSlot?: number): MoveResult; /** * Splits `amount` off the stack in `slot` into `toSlot` (or the first empty slot when `toSlot` is * omitted). Without `limit` it is limit-agnostic: a same-item target merges by simple addition. * Pass the item's stack limit to keep the merge legal, which rejects `over-stack`. Rejects an empty * source, `amount <= 0`, `amount >= stack count` (a split must leave both sides non-empty), no free * slot, or a target holding a different item. * * @capability inventory-split split a stack into a target or first-empty slot, honoring a stack limit */ export declare function splitStack(state: InventoryState, slot: number, amount: number, toSlot?: number, limit?: number): SplitResult; export interface InventorySet { put(id: TId, itemId: string, count: number, options?: { slot?: number; }): PutResult; take(id: TId, itemId: string, count: number): TakeResult; move(fromId: TId, fromSlot: number, toId: TId, toSlot?: number): MoveResult; count(id: TId, itemId: string): number; has(id: TId, itemId: string, count: number): boolean; state(id: TId): InventoryState; replaceState(id: TId, state: InventoryState): void; /** Detached copy of every declared inventory — a save, never a live alias. */ snapshot(): InventorySetState; /** Replace every declared inventory from a snapshot; returns false without mutation when an entry is malformed or incomplete. */ restore(next: InventorySetState): boolean; /** Empty every declared inventory. */ reset(): void; } /** Every inventory in a set, keyed by id, as plain slot data. */ export type InventorySetState = Record; /** Build a keyed set of named inventories from their `layouts`, sharing one `traits` table — the stateful façade over put/take/move/count. */ export declare function createInventorySet(layouts: Record, traits: ItemTraits): InventorySet;