feat(api): integrate equipment stats into combat damage system
Equipment-Combat Integration: - Update Stats damage formula from STR//2 to int(STR*0.75) for better scaling - Add spell_power system for magical weapons (staves, wands) - Add spell_power_bonus field to Stats model with spell_power property - Add spell_power field to Item model with is_magical_weapon() method - Update Character.get_effective_stats() to populate spell_power_bonus Combatant Model Updates: - Add weapon property fields (crit_chance, crit_multiplier, damage_type) - Add elemental weapon support (elemental_damage_type, physical_ratio, elemental_ratio) - Update serialization to handle new weapon properties DamageCalculator Refactoring: - Remove weapon_damage parameter from calculate_physical_damage() - Use attacker_stats.damage directly (includes weapon bonus) - Use attacker_stats.spell_power for magical damage calculations Combat Service Updates: - Extract weapon properties in _create_combatant_from_character() - Use stats.damage_bonus for enemy combatants from templates - Remove hardcoded _get_weapon_damage() method - Handle elemental weapons with split damage in _execute_attack() Item Generation Updates: - Add base_spell_power to BaseItemTemplate dataclass - Add ARCANE damage type to DamageType enum - Add magical weapon templates (wizard_staff, arcane_staff, wand, crystal_wand) Test Updates: - Update test_stats.py for new damage formula (0.75 scaling) - Update test_character.py for equipment bonus calculations - Update test_damage_calculator.py for new API signatures - Update test_combat_service.py mock fixture for equipped attribute Tests: 174 passing
This commit is contained in:
@@ -22,12 +22,18 @@ class Stats:
|
||||
wisdom: Perception and insight, affects magical resistance
|
||||
charisma: Social influence, affects NPC interactions
|
||||
luck: Fortune and fate, affects critical hits, loot, and random outcomes
|
||||
damage_bonus: Flat damage bonus from equipped weapons (default 0)
|
||||
spell_power_bonus: Flat spell power bonus from staves/wands (default 0)
|
||||
defense_bonus: Flat defense bonus from equipped armor (default 0)
|
||||
resistance_bonus: Flat resistance bonus from equipped armor (default 0)
|
||||
|
||||
Computed Properties:
|
||||
hit_points: Maximum HP = 10 + (constitution × 2)
|
||||
mana_points: Maximum MP = 10 + (intelligence × 2)
|
||||
defense: Physical defense = constitution // 2
|
||||
resistance: Magical resistance = wisdom // 2
|
||||
damage: Physical damage = int(strength × 0.75) + damage_bonus
|
||||
spell_power: Spell power = int(intelligence × 0.75) + spell_power_bonus
|
||||
defense: Physical defense = (constitution // 2) + defense_bonus
|
||||
resistance: Magical resistance = (wisdom // 2) + resistance_bonus
|
||||
"""
|
||||
|
||||
strength: int = 10
|
||||
@@ -38,6 +44,12 @@ class Stats:
|
||||
charisma: int = 10
|
||||
luck: int = 8
|
||||
|
||||
# Equipment bonus fields (populated by get_effective_stats())
|
||||
damage_bonus: int = 0 # From weapons (physical damage)
|
||||
spell_power_bonus: int = 0 # From staves/wands (magical damage)
|
||||
defense_bonus: int = 0 # From armor
|
||||
resistance_bonus: int = 0 # From armor
|
||||
|
||||
@property
|
||||
def hit_points(self) -> int:
|
||||
"""
|
||||
@@ -62,29 +74,65 @@ class Stats:
|
||||
"""
|
||||
return 10 + (self.intelligence * 2)
|
||||
|
||||
@property
|
||||
def damage(self) -> int:
|
||||
"""
|
||||
Calculate total physical damage from strength and equipment.
|
||||
|
||||
Formula: int(strength * 0.75) + damage_bonus
|
||||
|
||||
The damage_bonus comes from equipped weapons and is populated
|
||||
by Character.get_effective_stats().
|
||||
|
||||
Returns:
|
||||
Total physical damage value
|
||||
"""
|
||||
return int(self.strength * 0.75) + self.damage_bonus
|
||||
|
||||
@property
|
||||
def spell_power(self) -> int:
|
||||
"""
|
||||
Calculate spell power from intelligence and equipment.
|
||||
|
||||
Formula: int(intelligence * 0.75) + spell_power_bonus
|
||||
|
||||
The spell_power_bonus comes from equipped staves/wands and is
|
||||
populated by Character.get_effective_stats().
|
||||
|
||||
Returns:
|
||||
Total spell power value
|
||||
"""
|
||||
return int(self.intelligence * 0.75) + self.spell_power_bonus
|
||||
|
||||
@property
|
||||
def defense(self) -> int:
|
||||
"""
|
||||
Calculate physical defense from constitution.
|
||||
Calculate physical defense from constitution and equipment.
|
||||
|
||||
Formula: constitution // 2
|
||||
Formula: (constitution // 2) + defense_bonus
|
||||
|
||||
The defense_bonus comes from equipped armor and is populated
|
||||
by Character.get_effective_stats().
|
||||
|
||||
Returns:
|
||||
Physical defense value (damage reduction)
|
||||
"""
|
||||
return self.constitution // 2
|
||||
return (self.constitution // 2) + self.defense_bonus
|
||||
|
||||
@property
|
||||
def resistance(self) -> int:
|
||||
"""
|
||||
Calculate magical resistance from wisdom.
|
||||
Calculate magical resistance from wisdom and equipment.
|
||||
|
||||
Formula: wisdom // 2
|
||||
Formula: (wisdom // 2) + resistance_bonus
|
||||
|
||||
The resistance_bonus comes from equipped armor and is populated
|
||||
by Character.get_effective_stats().
|
||||
|
||||
Returns:
|
||||
Magical resistance value (spell damage reduction)
|
||||
"""
|
||||
return self.wisdom // 2
|
||||
return (self.wisdom // 2) + self.resistance_bonus
|
||||
|
||||
@property
|
||||
def crit_bonus(self) -> float:
|
||||
@@ -171,6 +219,10 @@ class Stats:
|
||||
wisdom=data.get("wisdom", 10),
|
||||
charisma=data.get("charisma", 10),
|
||||
luck=data.get("luck", 8),
|
||||
damage_bonus=data.get("damage_bonus", 0),
|
||||
spell_power_bonus=data.get("spell_power_bonus", 0),
|
||||
defense_bonus=data.get("defense_bonus", 0),
|
||||
resistance_bonus=data.get("resistance_bonus", 0),
|
||||
)
|
||||
|
||||
def copy(self) -> 'Stats':
|
||||
@@ -188,6 +240,10 @@ class Stats:
|
||||
wisdom=self.wisdom,
|
||||
charisma=self.charisma,
|
||||
luck=self.luck,
|
||||
damage_bonus=self.damage_bonus,
|
||||
spell_power_bonus=self.spell_power_bonus,
|
||||
defense_bonus=self.defense_bonus,
|
||||
resistance_bonus=self.resistance_bonus,
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
@@ -197,6 +253,7 @@ class Stats:
|
||||
f"CON={self.constitution}, INT={self.intelligence}, "
|
||||
f"WIS={self.wisdom}, CHA={self.charisma}, LUK={self.luck}, "
|
||||
f"HP={self.hit_points}, MP={self.mana_points}, "
|
||||
f"DMG={self.damage}, SP={self.spell_power}, "
|
||||
f"DEF={self.defense}, RES={self.resistance}, "
|
||||
f"CRIT_BONUS={self.crit_bonus:.1%}, HIT_BONUS={self.hit_bonus:.1%})"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user