feat(api): implement inventory service with equipment system
Add InventoryService for managing character inventory, equipment, and consumable usage. Key features: - Add/remove items with inventory capacity checks - Equipment slot validation (weapon, off_hand, helmet, chest, gloves, boots, accessory_1, accessory_2) - Level and class requirement validation for equipment - Consumable usage with instant and duration-based effects - Combat-specific consumable method returning effects for combat system - Bulk operations (add_items, get_items_by_type, get_equippable_items) Design decision: Uses full Item object storage (not IDs) to support procedurally generated items with unique identifiers. Files added: - /api/app/services/inventory_service.py (560 lines) - /api/tests/test_inventory_service.py (51 tests passing) Task 2.3 of Phase 4 Combat Implementation complete.
This commit is contained in:
@@ -708,6 +708,149 @@ success = service.soft_delete_message(
|
||||
- **Consumable:** One-time use (potions, scrolls)
|
||||
- **Quest Item:** Story-related, non-tradeable
|
||||
|
||||
---
|
||||
|
||||
## Procedural Item Generation (Affix System)
|
||||
|
||||
The game uses a Diablo-style procedural item generation system where weapons and armor
|
||||
are created by combining base templates with random affixes.
|
||||
|
||||
### Core Models
|
||||
|
||||
#### Affix
|
||||
|
||||
Represents a prefix or suffix that modifies an item's stats and name.
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `affix_id` | str | Unique identifier |
|
||||
| `name` | str | Display name ("Flaming", "of Strength") |
|
||||
| `affix_type` | AffixType | PREFIX or SUFFIX |
|
||||
| `tier` | AffixTier | MINOR, MAJOR, or LEGENDARY |
|
||||
| `description` | str | Affix description |
|
||||
| `stat_bonuses` | Dict[str, int] | Stat modifications |
|
||||
| `damage_bonus` | int | Flat damage increase |
|
||||
| `defense_bonus` | int | Flat defense increase |
|
||||
| `resistance_bonus` | int | Flat resistance increase |
|
||||
| `damage_type` | DamageType | For elemental affixes |
|
||||
| `elemental_ratio` | float | Portion of damage converted to element |
|
||||
| `crit_chance_bonus` | float | Critical hit chance modifier |
|
||||
| `crit_multiplier_bonus` | float | Critical damage modifier |
|
||||
| `allowed_item_types` | List[str] | Item types this affix can apply to |
|
||||
| `required_rarity` | str | Minimum rarity required (for legendary affixes) |
|
||||
|
||||
**Methods:**
|
||||
- `applies_elemental_damage() -> bool` - Check if affix adds elemental damage
|
||||
- `is_legendary_only() -> bool` - Check if requires legendary rarity
|
||||
- `can_apply_to(item_type, rarity) -> bool` - Check if affix can be applied
|
||||
|
||||
#### BaseItemTemplate
|
||||
|
||||
Foundation template for procedural item generation.
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `template_id` | str | Unique identifier |
|
||||
| `name` | str | Base item name ("Dagger") |
|
||||
| `item_type` | str | "weapon" or "armor" |
|
||||
| `description` | str | Template description |
|
||||
| `base_damage` | int | Starting damage value |
|
||||
| `base_defense` | int | Starting defense value |
|
||||
| `base_resistance` | int | Starting resistance value |
|
||||
| `base_value` | int | Base gold value |
|
||||
| `damage_type` | str | Physical, fire, etc. |
|
||||
| `crit_chance` | float | Base critical chance |
|
||||
| `crit_multiplier` | float | Base critical multiplier |
|
||||
| `required_level` | int | Minimum level to use |
|
||||
| `min_rarity` | str | Minimum rarity this generates as |
|
||||
| `drop_weight` | int | Relative drop probability |
|
||||
|
||||
**Methods:**
|
||||
- `can_generate_at_rarity(rarity) -> bool` - Check if template supports rarity
|
||||
- `can_drop_for_level(level) -> bool` - Check level requirement
|
||||
|
||||
### Item Model Updates for Generated Items
|
||||
|
||||
The `Item` dataclass includes fields for tracking generated items:
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `applied_affixes` | List[str] | IDs of affixes on this item |
|
||||
| `base_template_id` | str | ID of base template used |
|
||||
| `generated_name` | str | Full name with affixes (e.g., "Flaming Dagger of Strength") |
|
||||
| `is_generated` | bool | True if procedurally generated |
|
||||
|
||||
**Methods:**
|
||||
- `get_display_name() -> str` - Returns generated_name if available, otherwise base name
|
||||
|
||||
### Generation Enumerations
|
||||
|
||||
#### ItemRarity
|
||||
|
||||
Item quality tiers affecting affix count and value:
|
||||
|
||||
| Value | Affix Count | Value Multiplier |
|
||||
|-------|-------------|------------------|
|
||||
| `COMMON` | 0 | 1.0× |
|
||||
| `UNCOMMON` | 0 | 1.5× |
|
||||
| `RARE` | 1 | 2.5× |
|
||||
| `EPIC` | 2 | 5.0× |
|
||||
| `LEGENDARY` | 3 | 10.0× |
|
||||
|
||||
#### AffixType
|
||||
|
||||
| Value | Description |
|
||||
|-------|-------------|
|
||||
| `PREFIX` | Appears before item name ("Flaming Dagger") |
|
||||
| `SUFFIX` | Appears after item name ("Dagger of Strength") |
|
||||
|
||||
#### AffixTier
|
||||
|
||||
Affix power level, determines eligibility by item rarity:
|
||||
|
||||
| Value | Description | Available For |
|
||||
|-------|-------------|---------------|
|
||||
| `MINOR` | Basic affixes | RARE+ |
|
||||
| `MAJOR` | Stronger affixes | RARE+ (higher weight at EPIC+) |
|
||||
| `LEGENDARY` | Most powerful affixes | LEGENDARY only |
|
||||
|
||||
### Item Generation Service
|
||||
|
||||
**Location:** `/app/services/item_generator.py`
|
||||
|
||||
**Usage:**
|
||||
```python
|
||||
from app.services.item_generator import get_item_generator
|
||||
from app.models.enums import ItemRarity
|
||||
|
||||
generator = get_item_generator()
|
||||
|
||||
# Generate specific item
|
||||
item = generator.generate_item(
|
||||
item_type="weapon",
|
||||
rarity=ItemRarity.EPIC,
|
||||
character_level=5
|
||||
)
|
||||
|
||||
# Generate random loot drop with luck influence
|
||||
item = generator.generate_loot_drop(
|
||||
character_level=10,
|
||||
luck_stat=12
|
||||
)
|
||||
```
|
||||
|
||||
**Related Loaders:**
|
||||
- `AffixLoader` (`/app/services/affix_loader.py`) - Loads affix definitions from YAML
|
||||
- `BaseItemLoader` (`/app/services/base_item_loader.py`) - Loads base templates from YAML
|
||||
|
||||
**Data Files:**
|
||||
- `/app/data/affixes/prefixes.yaml` - Prefix definitions
|
||||
- `/app/data/affixes/suffixes.yaml` - Suffix definitions
|
||||
- `/app/data/base_items/weapons.yaml` - Weapon templates
|
||||
- `/app/data/base_items/armor.yaml` - Armor templates
|
||||
|
||||
---
|
||||
|
||||
### Ability
|
||||
|
||||
Abilities represent actions that can be taken in combat (attacks, spells, skills, item uses).
|
||||
|
||||
Reference in New Issue
Block a user