# Ashen Realms – Playable Slice 0.7.5 ## Monster Categories & Loot Bags **Status:** Implementation Specification **Depends on:** Slice 0.7 V2 **Purpose:** Introduce category-based carrying limits for monster trade goods and create the first logistical reason to return from hunting. --- ## 1. Goal Monster loot should not be infinitely farmable in one trip. The player can carry only a small amount of category-specific trade goods without a bag. Dedicated loot bags increase that capacity. This creates the loop: **Hunt → fill bag → return → exchange goods → upgrade capacity → hunt longer.** The system must be simple, visible and data-driven. --- ## 2. Core Rule Each trade good belongs to exactly one **Loot Category**. A character has a carrying capacity for each loot category. Without a matching bag, the default carrying capacity is: **1 unit per loot category.** Example: ```text Ashen Pelt: HIDE Current HIDE capacity: 1 Player owns 1 Ashen Pelt → another Ashen Pelt cannot be carried ``` A Hide Bag with capacity 5 changes this to: ```text HIDE capacity: 5 ``` --- ## 3. Initial Categories Implement only the categories needed by the current content, but design the enum so future categories can be added. Initial categories: ```text HIDE RAIDER_TROPHY ``` Suggested future categories, not required yet: ```text CHITIN UNDEAD_RELIC ARCANE_REMAINS ``` --- ## 4. Initial Trade Good Mapping | Trade Good | Loot Category | |---|---| | Ashen Pelt | HIDE | | Tough Hide | HIDE | | Raider Insignia | RAIDER_TROPHY | | Charred Raider Insignia | RAIDER_TROPHY | The mapping belongs to content data, not hardcoded monster-specific UI logic. --- ## 5. Monster Categories Monster definitions also receive a broad gameplay category. Initial examples: ```text BEAST HUMANOID ``` Suggested mapping: | Monster | Monster Category | |---|---| | Ash Rat | BEAST | | Feral Road Hound | BEAST | | Road Bandit | HUMANOID | | Charred Raider | HUMANOID | Monster category and loot category are separate concepts. Example: different BEAST monsters can later drop HIDE, CHITIN or another loot category. Do not assume `monsterCategory === lootCategory`. --- ## 6. Bag Model Loot bags are **not normal armor equipment slots**. They belong to a separate character loadout/state. Recommended data model concept: ```text LootBagDefinition - id - key - name - lootCategory - capacity - iconPath CharacterLootBag - characterId - lootBagDefinitionId - equipped / active ``` Only one active bag per loot category is required for V1. No nesting and no physical inventory grid. --- ## 7. Initial Bag Definitions The system must support at least: ### Basic Hide Bag ```text Name: Basic Hide Bag Category: HIDE Capacity: 5 ``` ### Basic Trophy Pouch ```text Name: Basic Trophy Pouch Category: RAIDER_TROPHY Capacity: 5 ``` They do not both need to be obtainable in this slice. Acquisition is handled by the merchant/quest slices. --- ## 8. Capacity Calculation The server is the single authority. Conceptually: ```text capacity(category) = active bag capacity if no active bag exists: capacity(category) = 1 ``` The current amount is the sum of all owned trade-good quantities in that category. Equipment, consumables and normal items are not affected by loot-bag capacity. --- ## 9. Full Bag Behavior If combat loot would exceed the capacity: - the combat victory remains valid - the trade good is not granted beyond capacity - other loot rolls still succeed normally - equipment must not be lost because the hide bag is full - the loot summary explains what was left behind Example: ```text Loot Ashen Pelt ×1 – Left behind (Hide Bag full) Bandit Hood ×1 – Added to inventory ``` Do not silently discard loot without player feedback. --- ## 10. Mixed Loot If one result grants multiple trade goods, grant as many as fit. Example: ```text Current HIDE: 4 / 5 Reward: Tough Hide ×2 Granted: 1 Left behind: 1 ``` The result DTO should make granted and rejected quantities explicit. --- ## 11. API / DTO Requirements The frontend needs enough information to display current carrying state. Example DTO concept: ```json { "category": "HIDE", "current": 4, "capacity": 5, "bag": { "key": "basic-hide-bag", "name": "Basic Hide Bag" } } ``` Provide a server-side way for the player UI to retrieve all relevant category capacities. This can be part of inventory state or a dedicated endpoint, whichever best fits the current codebase. --- ## 12. UI Requirements The current carrying state must be visible during or directly after hunting. Minimum: ```text Hides 4 / 5 Raider Trophies 1 / 1 ``` If a category is full, make it obvious before the player starts another farm cycle. The loot summary must display: - granted trade goods - capacity after loot - left-behind goods when full Do not turn this into a large inventory-management screen. --- ## 13. Tests ### Capacity - no bag gives capacity 1 - Basic Hide Bag gives HIDE capacity 5 - Hide Bag does not increase RAIDER_TROPHY capacity - only active bag affects capacity ### Loot granting - first Ashen Pelt can be carried without a bag - second Ashen Pelt is rejected without a bag - equipment reward still grants when trade-good capacity is full - partial quantity grant works ### Security - client cannot submit a fake capacity - client cannot fake an equipped bag - capacity is derived from persisted character state --- ## 14. Acceptance Criteria - [ ] Monster definitions have a reusable monster category. - [ ] Trade goods have a reusable loot category. - [ ] Default capacity without bag is 1 per loot category. - [ ] Dedicated loot bags increase only their configured category. - [ ] Capacity enforcement is server-authoritative. - [ ] Full bags never invalidate a combat victory. - [ ] Excess trade goods are clearly shown as left behind. - [ ] Equipment/consumables are unaffected by trade-good capacity. - [ ] Current bag capacity can be displayed in the UI. - [ ] Tests cover full, partial and no-bag cases. --- ## 15. Out of Scope Do not implement: - weight - Tetris inventory - bag durability - random bag affixes - crafting bags - upgrades on one physical bag item - more than one active bag per category - automatic sending of excess loot to storage