feat(api): implement Diablo-style item affix system
Add procedural item generation with affix naming system: - Items with RARE/EPIC/LEGENDARY rarity get dynamic names - Prefixes (e.g., "Flaming") add elemental damage, material bonuses - Suffixes (e.g., "of Strength") add stat bonuses - Affix count scales with rarity: RARE=1, EPIC=2, LEGENDARY=3 New files: - models/affixes.py: Affix and BaseItemTemplate dataclasses - services/affix_loader.py: YAML-based affix pool loading - services/base_item_loader.py: Base item template loading - services/item_generator.py: Main procedural generation service - data/affixes/prefixes.yaml: 14 prefix definitions - data/affixes/suffixes.yaml: 15 suffix definitions - data/base_items/weapons.yaml: 12 weapon templates - data/base_items/armor.yaml: 12 armor templates - tests/test_item_generator.py: 34 comprehensive tests Modified: - enums.py: Added AffixType and AffixTier enums - items.py: Added affix tracking fields (applied_affixes, generated_name) Example output: "Frozen Dagger of the Bear" (EPIC with ice damage + STR/CON)
This commit is contained in:
@@ -81,6 +81,24 @@ class Item:
|
||||
required_level: int = 1
|
||||
required_class: Optional[str] = None
|
||||
|
||||
# Affix tracking (for procedurally generated items)
|
||||
applied_affixes: List[str] = field(default_factory=list) # List of affix_ids
|
||||
base_template_id: Optional[str] = None # ID of base item template used
|
||||
generated_name: Optional[str] = None # Full generated name with affixes
|
||||
is_generated: bool = False # True if created by item generator
|
||||
|
||||
def get_display_name(self) -> str:
|
||||
"""
|
||||
Get the item's display name.
|
||||
|
||||
For generated items, returns the affix-enhanced name.
|
||||
For static items, returns the base name.
|
||||
|
||||
Returns:
|
||||
Display name string
|
||||
"""
|
||||
return self.generated_name or self.name
|
||||
|
||||
def is_weapon(self) -> bool:
|
||||
"""Check if this item is a weapon."""
|
||||
return self.item_type == ItemType.WEAPON
|
||||
@@ -166,6 +184,8 @@ class Item:
|
||||
if self.elemental_damage_type:
|
||||
data["elemental_damage_type"] = self.elemental_damage_type.value
|
||||
data["effects_on_use"] = [effect.to_dict() for effect in self.effects_on_use]
|
||||
# Include display_name for convenience
|
||||
data["display_name"] = self.get_display_name()
|
||||
return data
|
||||
|
||||
@classmethod
|
||||
@@ -215,6 +235,11 @@ class Item:
|
||||
resistance=data.get("resistance", 0),
|
||||
required_level=data.get("required_level", 1),
|
||||
required_class=data.get("required_class"),
|
||||
# Affix tracking fields
|
||||
applied_affixes=data.get("applied_affixes", []),
|
||||
base_template_id=data.get("base_template_id"),
|
||||
generated_name=data.get("generated_name"),
|
||||
is_generated=data.get("is_generated", False),
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
|
||||
Reference in New Issue
Block a user