Files
Code_of_Conquest/api/app/models/stats.py
Phillip Tarrant 03ab783eeb Combat Backend & Data Models
- Implement Combat Service
- Implement Damage Calculator
- Implement Effect Processor
- Implement Combat Actions
- Created Combat API Endpoints
2025-11-26 15:43:20 -06:00

203 lines
5.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Character statistics data model.
This module defines the Stats dataclass which represents a character's core
attributes and provides computed properties for derived values like HP and MP.
"""
from dataclasses import dataclass, field, asdict
from typing import Dict, Any
@dataclass
class Stats:
"""
Character statistics representing core attributes.
Attributes:
strength: Physical power, affects melee damage
dexterity: Agility and precision, affects initiative and evasion
constitution: Endurance and health, affects HP and defense
intelligence: Magical power, affects spell damage and MP
wisdom: Perception and insight, affects magical resistance
charisma: Social influence, affects NPC interactions
luck: Fortune and fate, affects critical hits, loot, and random outcomes
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
"""
strength: int = 10
dexterity: int = 10
constitution: int = 10
intelligence: int = 10
wisdom: int = 10
charisma: int = 10
luck: int = 8
@property
def hit_points(self) -> int:
"""
Calculate maximum hit points based on constitution.
Formula: 10 + (constitution × 2)
Returns:
Maximum HP value
"""
return 10 + (self.constitution * 2)
@property
def mana_points(self) -> int:
"""
Calculate maximum mana points based on intelligence.
Formula: 10 + (intelligence × 2)
Returns:
Maximum MP value
"""
return 10 + (self.intelligence * 2)
@property
def defense(self) -> int:
"""
Calculate physical defense from constitution.
Formula: constitution // 2
Returns:
Physical defense value (damage reduction)
"""
return self.constitution // 2
@property
def resistance(self) -> int:
"""
Calculate magical resistance from wisdom.
Formula: wisdom // 2
Returns:
Magical resistance value (spell damage reduction)
"""
return self.wisdom // 2
@property
def crit_bonus(self) -> float:
"""
Calculate critical hit chance bonus from luck.
Formula: luck * 0.5% (0.005)
This bonus is added to the weapon's base crit chance.
The total crit chance is capped at 25% in the DamageCalculator.
Returns:
Crit chance bonus as a decimal (e.g., 0.04 for LUK 8)
Examples:
LUK 8: 0.04 (4% bonus)
LUK 12: 0.06 (6% bonus)
"""
return self.luck * 0.005
@property
def hit_bonus(self) -> float:
"""
Calculate hit chance bonus (miss reduction) from luck.
Formula: luck * 0.5% (0.005)
This reduces the base 10% miss chance. The minimum miss
chance is hard capped at 5% to prevent frustration.
Returns:
Miss reduction as a decimal (e.g., 0.04 for LUK 8)
Examples:
LUK 8: 0.04 (reduces miss from 10% to 6%)
LUK 12: 0.06 (reduces miss from 10% to 4%, capped at 5%)
"""
return self.luck * 0.005
@property
def lucky_roll_chance(self) -> float:
"""
Calculate chance for a "lucky" high damage variance roll.
Formula: 5% + (luck * 0.25%)
When triggered, damage variance uses 100%-110% instead of 95%-105%.
This gives LUK characters more frequent high damage rolls.
Returns:
Lucky roll chance as a decimal
Examples:
LUK 8: 0.07 (7% chance for lucky roll)
LUK 12: 0.08 (8% chance for lucky roll)
"""
return 0.05 + (self.luck * 0.0025)
def to_dict(self) -> Dict[str, Any]:
"""
Serialize stats to a dictionary.
Returns:
Dictionary containing all stat values
"""
return asdict(self)
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> 'Stats':
"""
Deserialize stats from a dictionary.
Args:
data: Dictionary containing stat values
Returns:
Stats instance
"""
return cls(
strength=data.get("strength", 10),
dexterity=data.get("dexterity", 10),
constitution=data.get("constitution", 10),
intelligence=data.get("intelligence", 10),
wisdom=data.get("wisdom", 10),
charisma=data.get("charisma", 10),
luck=data.get("luck", 8),
)
def copy(self) -> 'Stats':
"""
Create a deep copy of this Stats instance.
Returns:
New Stats instance with same values
"""
return Stats(
strength=self.strength,
dexterity=self.dexterity,
constitution=self.constitution,
intelligence=self.intelligence,
wisdom=self.wisdom,
charisma=self.charisma,
luck=self.luck,
)
def __repr__(self) -> str:
"""String representation showing all stats and computed properties."""
return (
f"Stats(STR={self.strength}, DEX={self.dexterity}, "
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"DEF={self.defense}, RES={self.resistance}, "
f"CRIT_BONUS={self.crit_bonus:.1%}, HIT_BONUS={self.hit_bonus:.1%})"
)