# **Inventory System Specification** This document defines the architecture for item management, covering individual Explorer loadouts and the shared Party/Hub storage. ## **1. System Overview** The Inventory system operates in two distinct contexts: 1. **Run Context (The Expedition):** - **Unit Loadout:** Active gear affecting stats. Locked during combat (usually), editable during rest. - **Run Stash (The Bag):** Temporary storage for loot found during the run. Infinite (or high) capacity. - **Rule:** If the squad wipes, the _Run Stash_ is lost. Only equipped gear might be recovered (depending on difficulty settings). 2. **Hub Context (The Armory):** - **Master Stash:** Persistent storage for all unequipped items. - **Management:** Players move items between the Master Stash and Unit Loadouts to prepare for the next run. - **Extraction:** Upon successful run completion, _Run Stash_ contents are merged into _Master Stash_. ## **2. Visual Description (UI)** ### **A. Unit Loadout (The Paper Doll)** - **Visual:** A silhouette or 3D model of the character. - **Slots:** - **Primary Hand:** Weapon (Sword, Staff, Wrench). - **Off-Hand:** Shield, Focus, Tool, or 2H (occupies both). - **Body:** Armor (Plate, Robes, Vest). - **Accessory/Relic:** Stat boosters or Passive enablers. - **Belt (2 Slots):** Consumables (Potions, Grenades) usable in combat via Bonus Action. - **Interaction:** Drag-and-drop from Stash to Slot. Invalid slots highlight Red. Valid slots highlight Green. ### **B. The Stash (Grid View)** - **Visual:** A grid of item tiles on the right side of the screen. - **Filters:** Tabs for [All] [Weapons] [Armor] [Utility] [Consumables]. - **Sorting:** By Rarity (Color Coded border) or Tier. - **Context Menu:** Right-click an item to "Equip to Active Unit" or "Salvage/Sell". ## **3. TypeScript Interfaces (Data Model)** ```typescript // src/types/Inventory.ts export type ItemType = | "WEAPON" | "ARMOR" | "RELIC" | "UTILITY" | "CONSUMABLE" | "MATERIAL"; export type Rarity = "COMMON" | "UNCOMMON" | "RARE" | "ANCIENT"; export type SlotType = "MAIN_HAND" | "OFF_HAND" | "BODY" | "ACCESSORY" | "BELT"; /** * A specific instance of an item. * Allows for RNG stats or durability in the future. */ export interface ItemInstance { uid: string; // Unique Instance ID (e.g. "ITEM_12345_A") defId: string; // Reference to static registry (e.g. "ITEM_RUSTY_BLADE") isNew: boolean; // For UI "New!" badges quantity: number; // For stackables (Potions/Materials) } /** * The inventory of a single character. */ export interface UnitLoadout { mainHand: ItemInstance | null; offHand: ItemInstance | null; body: ItemInstance | null; accessory: ItemInstance | null; belt: [ItemInstance | null, ItemInstance | null]; // Fixed 2 slots } /** * The shared storage (Run Bag or Hub Stash). */ export interface InventoryStorage { id: string; // "RUN_LOOT" or "HUB_VAULT" items: ItemInstance[]; // Unordered list currency: { aetherShards: number; ancientCores: number; }; } /** * Data payload for moving items. */ export interface TransferRequest { itemUid: string; sourceContainer: "STASH" | "UNIT_LOADOUT"; targetContainer: "STASH" | "UNIT_LOADOUT"; targetSlot?: SlotType; // If moving to Unit slotIndex?: number; // For Belt slots (0 or 1) unitId?: string; // Which unit owns the loadout } ``` ## **4. Logic & Rules** ### **A. Equipping Items** 1. **Validation:** - Check Item.requirements (Class Lock, Min Stats) against Unit.baseStats. - Check Slot Compatibility (Can't put Armor in Weapon slot). - _Two-Handed Logic:_ If equipping a 2H weapon, unequip Off-Hand automatically. 2. **Swapping:** - If target slot is occupied, move the existing item to Stash (or Swap if source was another slot). 3. **Stat Recalculation:** - Trigger unit.recalculateStats() immediately. ### **B. Stacking** - **Equipment:** Non-stackable. Each Sword is a unique instance. - **Consumables/Materials:** Stackable up to 99. - **Logic:** When adding a Potion to Stash, check if defId exists. If yes, quantity++. If no, create new entry. ### **C. The Extraction (End of Run)** ```js function finalizeRun(runInventory, hubInventory) { // 1. Transfer Currency hubInventory.currency.shards += runInventory.currency.shards; // 2. Transfer Items for (let item of runInventory.items) { hubInventory.addItem(item); } // 3. Clear Run Inventory runInventory.clear(); } ``` ## **5. Conditions of Acceptance (CoA)** **CoA 1: Class Restrictions** - Attempting to equip a "Tinker Only" item on a "Vanguard" must fail. - The UI should visually dim incompatible items when a unit is selected. **CoA 2: Stat Updates** - Equipping a `+5 Attack` sword must immediately update the displayed Attack stat in the Character Sheet. - Unequipping it must revert the stat. **CoA 3: Belt Logic** - Using a Consumable in combat (via `ActionSystem`) must reduce its quantity. - If quantity reaches 0, the item reference is removed from the Belt slot. **CoA 4: Persistence** - Saving the game must serialize the `InventoryStorage` array correctly. - Loading the game must restore specific item instances (not just generic definitions).