Feature 03: Items & Inventory
Overview
The item system: gear templates, item instances with random properties, inventory management (backpack, equipped slots, bank), equipping/unequipping, and salvaging. This must be in place before combat or quests, since characters need gear to do anything.
Dependencies
- Feature 02 (Character Creation)
Technical Tasks
1. Static Game Data — Item Templates
- Create
data/items/directory with TOML files organized by category:weapons/swords.toml,weapons/axes.toml,weapons/daggers.toml,weapons/bows.toml,weapons/staves.toml,weapons/wands.toml,weapons/shields.tomlarmor/heavy.toml,armor/medium.toml,armor/light.tomlaccessories/rings.toml,accessories/amulets.toml,accessories/cloaks.toml,accessories/belts.tomlconsumables/potions.toml,consumables/scrolls.toml,consumables/supplies.tomlmaterials/crafting.toml(placeholder — filled in Feature 09)
- Define item template struct:
name, item_type, subtype, slot, rarity, level_req, base_stats: { damage?, armor?, evasion?, speed? }, signature_effect? (for Rare+), skill_granted? (for Legendary/Artifact weapons) - Start with Tier 1 (level 1-10) items — enough to test the full system. Higher tiers added later.
- Create
crates/game/src/items.rs:load_item_templates()→HashMap<String, ItemTemplate>ItemTemplatestructEquipmentSlotenum: MainHand, OffHand, Head, Chest, Hands, Feet, Cloak, Ring1, Ring2, Amulet, Belt
2. Random Bonus Property System (crates/game)
- Create
src/item_generation.rs:- Define bonus property pools:
- Offensive: bonus damage, crit chance, attack speed, armor penetration
- Defensive: bonus armor, evasion, HP, damage reduction
- Attribute: +might, +logic, +speed, +presence, +fortitude, +luck
- Resource: +max resource, +resource regen
- Utility: +gold find, +XP gain, +crafting speed
- Define potency tiers: Minor, Standard, Major, Grand
generate_item(template_id: &str, rng: &mut impl Rng) -> Item:- Common: base stats only
- Uncommon: base stats + 1 random bonus
- Rare: base + signature effect + 1-2 random bonuses
- Very Rare: base + signature + 2-3 random bonuses
- Legendary: base + signature + 3 random bonuses + gear skill
- Artifact: hand-defined (no random generation)
- Bonus selection uses weighted random from the appropriate pool
- Define bonus property pools:
3. Item & Inventory Tables Migration
- Create migration
0004_create_items.sql:itemstable: id, owner_id, template_id, rarity, enhancement, bonus_properties (JSONB), location, slot_index, created_at- Index on (owner_id), (owner_id, location)
artifactstable: template_id (PK), held_by, acquired_at
4. Item Model & Queries (crates/db)
- Create
src/models/item.rs:Itemstruct with FromRowItemLocationenum serialized as textBonusPropertystruct (for JSONB deserialization)
- Create
src/queries/items.rs:create_item(pool, owner_id, template_id, rarity, bonuses, location) -> Itemfind_items_by_owner(pool, owner_id) -> Vec<Item>find_items_by_location(pool, owner_id, location) -> Vec<Item>find_equipped_items(pool, owner_id) -> Vec<Item>find_item_by_id(pool, id) -> Option<Item>update_item_location(pool, item_id, new_location, slot_index)delete_item(pool, item_id)count_items_in_location(pool, owner_id, location) -> i64
5. Equip/Unequip Logic (crates/game)
- Create
src/equipment.rs:can_equip(character: &Character, item: &Item, slot: EquipmentSlot) -> Result<()>:- Check level requirement
- Check class restrictions (if any)
- Check slot compatibility (e.g., can’t put a sword in head slot)
- Check two-handed weapon rules (main hand + off hand)
get_equipped_stats(items: &[Item]) -> EquippedStats:- Sum all base stats + bonus properties from equipped items
- Return aggregated damage, armor, evasion, attribute bonuses, etc.
6. Salvage System (crates/game)
- Create
src/salvage.rs:salvage_item(item: &Item) -> Vec<SalvageMaterial>:- Returns materials based on rarity (NOT level — per design doc)
- Common → Common Fragments
- Uncommon → Uncommon Shards
- Rare → Rare Cores
- Very Rare → Prismatic Essences
- Legendary → Legendary Sparks
- Material quantities scale with rarity, not item level
7. Inventory Routes (crates/api)
- Create
src/routes/inventory.rs:GET /api/characters/:id/inventory:- Return all items grouped by location:
{ equipped: [], backpack: [], bank: [] } - Each item includes resolved template data (name, base stats) merged with instance data (bonuses, enhancement)
- Return all items grouped by location:
POST /api/characters/:id/equip:- Body:
{ item_id, slot } - Validate ownership, slot compatibility, level requirement
- If slot already occupied, swap to backpack
- Update item locations in DB
- Body:
POST /api/characters/:id/unequip:- Body:
{ slot } - Move equipped item to backpack
- Check backpack isn’t full
- Body:
POST /api/characters/:id/salvage:- Body:
{ item_ids: [uuid] } - Validate all items owned and in backpack/bank
- Cannot salvage equipped items
- Delete items, grant materials (materials are items in backpack with
type: material) - Return list of materials gained
- Body:
POST /api/characters/:id/move-item:- Body:
{ item_id, to_location, to_index? } - Move between backpack ↔ bank
- Validate capacity limits
- Body:
8. Starting Equipment
- Update character creation (Feature 02) to grant starting gear:
- Each class gets a weapon + basic armor appropriate to their archetype
- Items are Common rarity, level 1
- Created as item instances and placed in equipped slots
9. Client — Inventory UI
- Create
routes/(game)/inventory/+page.svelte:- Equipment panel: visual grid of 11 gear slots (character paper doll layout)
- Backpack panel: grid of items with drag-and-drop support
- Bank panel: accessible tab, grid layout
- Item tooltip on hover/tap: name, rarity color, base stats, bonus properties, level req, slot
- Equip: drag from backpack to slot, or right-click → “Equip”
- Unequip: click equipped item → “Unequip”
- Salvage: select multiple items → “Salvage” button with confirmation
- Create
lib/types/item.ts— TypeScript types for items - Create
lib/components/inventory/ItemTooltip.svelte— reusable tooltip component - Create
lib/components/inventory/ItemGrid.svelte— reusable grid component
Tests
Unit Tests
generate_item: Common items have no bonus propertiesgenerate_item: Rare items have signature effect + 1-2 bonusesgenerate_item: Legendary items have 3 bonuses + gear skill referencegenerate_item: deterministic with seeded RNG (same seed → same item)can_equip: accepts valid weapon in main handcan_equip: rejects item below level requirementcan_equip: rejects sword in head slotcan_equip: handles two-handed weapon (clears off-hand)get_equipped_stats: correctly sums stats from multiple itemsget_equipped_stats: includes bonus propertiessalvage_item: Common → correct Common Fragments countsalvage_item: Rare → Rare Cores (not affected by item level)- Item template loading: all templates load without error, no missing references
Integration Tests
GET /api/characters/:id/inventoryreturns equipped + backpack + bank itemsPOST /api/characters/:id/equipmoves item from backpack to slotPOST /api/characters/:id/equipswaps existing equipped item to backpackPOST /api/characters/:id/equiprejects item not owned by characterPOST /api/characters/:id/unequipmoves item to backpackPOST /api/characters/:id/unequipfails when backpack is fullPOST /api/characters/:id/salvagedeletes items and returns materialsPOST /api/characters/:id/salvagerejects equipped itemsPOST /api/characters/:id/move-itemmoves item between backpack and bank- Character creation grants starting equipment in correct slots
- Inventory respects backpack capacity limit (default 30 slots)
- Bank respects bank capacity limit (default 50 slots, upgradeable)