first commit
This commit is contained in:
196
api/app/models/items.py
Normal file
196
api/app/models/items.py
Normal file
@@ -0,0 +1,196 @@
|
||||
"""
|
||||
Item system for equipment, consumables, and quest items.
|
||||
|
||||
This module defines the Item dataclass representing all types of items in the game,
|
||||
including weapons, armor, consumables, and quest items.
|
||||
"""
|
||||
|
||||
from dataclasses import dataclass, field, asdict
|
||||
from typing import Dict, Any, List, Optional
|
||||
|
||||
from app.models.enums import ItemType, DamageType
|
||||
from app.models.effects import Effect
|
||||
|
||||
|
||||
@dataclass
|
||||
class Item:
|
||||
"""
|
||||
Represents an item in the game (weapon, armor, consumable, or quest item).
|
||||
|
||||
Items can provide passive stat bonuses when equipped, have weapon/armor stats,
|
||||
or provide effects when consumed.
|
||||
|
||||
Attributes:
|
||||
item_id: Unique identifier
|
||||
name: Display name
|
||||
item_type: Category (weapon, armor, consumable, quest_item)
|
||||
description: Item lore and information
|
||||
value: Gold value for buying/selling
|
||||
is_tradeable: Whether item can be sold on marketplace
|
||||
stat_bonuses: Passive bonuses to stats when equipped
|
||||
Example: {"strength": 5, "constitution": 3}
|
||||
effects_on_use: Effects applied when consumed (consumables only)
|
||||
|
||||
Weapon-specific attributes:
|
||||
damage: Base weapon damage
|
||||
damage_type: Type of damage (physical, fire, etc.)
|
||||
crit_chance: Probability of critical hit (0.0 to 1.0)
|
||||
crit_multiplier: Damage multiplier on critical hit
|
||||
|
||||
Armor-specific attributes:
|
||||
defense: Physical defense bonus
|
||||
resistance: Magical resistance bonus
|
||||
|
||||
Requirements (future):
|
||||
required_level: Minimum character level to use
|
||||
required_class: Class restriction (if any)
|
||||
"""
|
||||
|
||||
item_id: str
|
||||
name: str
|
||||
item_type: ItemType
|
||||
description: str
|
||||
value: int = 0
|
||||
is_tradeable: bool = True
|
||||
|
||||
# Passive bonuses (equipment)
|
||||
stat_bonuses: Dict[str, int] = field(default_factory=dict)
|
||||
|
||||
# Active effects (consumables)
|
||||
effects_on_use: List[Effect] = field(default_factory=list)
|
||||
|
||||
# Weapon-specific
|
||||
damage: int = 0
|
||||
damage_type: Optional[DamageType] = None
|
||||
crit_chance: float = 0.05 # 5% default critical hit chance
|
||||
crit_multiplier: float = 2.0 # 2x damage on critical hit
|
||||
|
||||
# Armor-specific
|
||||
defense: int = 0
|
||||
resistance: int = 0
|
||||
|
||||
# Requirements (future expansion)
|
||||
required_level: int = 1
|
||||
required_class: Optional[str] = None
|
||||
|
||||
def is_weapon(self) -> bool:
|
||||
"""Check if this item is a weapon."""
|
||||
return self.item_type == ItemType.WEAPON
|
||||
|
||||
def is_armor(self) -> bool:
|
||||
"""Check if this item is armor."""
|
||||
return self.item_type == ItemType.ARMOR
|
||||
|
||||
def is_consumable(self) -> bool:
|
||||
"""Check if this item is a consumable."""
|
||||
return self.item_type == ItemType.CONSUMABLE
|
||||
|
||||
def is_quest_item(self) -> bool:
|
||||
"""Check if this item is a quest item."""
|
||||
return self.item_type == ItemType.QUEST_ITEM
|
||||
|
||||
def can_equip(self, character_level: int, character_class: Optional[str] = None) -> bool:
|
||||
"""
|
||||
Check if a character can equip this item.
|
||||
|
||||
Args:
|
||||
character_level: Character's current level
|
||||
character_class: Character's class (if class restrictions exist)
|
||||
|
||||
Returns:
|
||||
True if item can be equipped, False otherwise
|
||||
"""
|
||||
# Check level requirement
|
||||
if character_level < self.required_level:
|
||||
return False
|
||||
|
||||
# Check class requirement
|
||||
if self.required_class and character_class != self.required_class:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def get_total_stat_bonus(self, stat_name: str) -> int:
|
||||
"""
|
||||
Get the total bonus for a specific stat from this item.
|
||||
|
||||
Args:
|
||||
stat_name: Name of the stat (e.g., "strength", "intelligence")
|
||||
|
||||
Returns:
|
||||
Bonus value for that stat (0 if not present)
|
||||
"""
|
||||
return self.stat_bonuses.get(stat_name, 0)
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Serialize item to a dictionary.
|
||||
|
||||
Returns:
|
||||
Dictionary containing all item data
|
||||
"""
|
||||
data = asdict(self)
|
||||
data["item_type"] = self.item_type.value
|
||||
if self.damage_type:
|
||||
data["damage_type"] = self.damage_type.value
|
||||
data["effects_on_use"] = [effect.to_dict() for effect in self.effects_on_use]
|
||||
return data
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: Dict[str, Any]) -> 'Item':
|
||||
"""
|
||||
Deserialize item from a dictionary.
|
||||
|
||||
Args:
|
||||
data: Dictionary containing item data
|
||||
|
||||
Returns:
|
||||
Item instance
|
||||
"""
|
||||
# Convert string values back to enums
|
||||
item_type = ItemType(data["item_type"])
|
||||
damage_type = DamageType(data["damage_type"]) if data.get("damage_type") else None
|
||||
|
||||
# Deserialize effects
|
||||
effects = []
|
||||
if "effects_on_use" in data and data["effects_on_use"]:
|
||||
effects = [Effect.from_dict(e) for e in data["effects_on_use"]]
|
||||
|
||||
return cls(
|
||||
item_id=data["item_id"],
|
||||
name=data["name"],
|
||||
item_type=item_type,
|
||||
description=data["description"],
|
||||
value=data.get("value", 0),
|
||||
is_tradeable=data.get("is_tradeable", True),
|
||||
stat_bonuses=data.get("stat_bonuses", {}),
|
||||
effects_on_use=effects,
|
||||
damage=data.get("damage", 0),
|
||||
damage_type=damage_type,
|
||||
crit_chance=data.get("crit_chance", 0.05),
|
||||
crit_multiplier=data.get("crit_multiplier", 2.0),
|
||||
defense=data.get("defense", 0),
|
||||
resistance=data.get("resistance", 0),
|
||||
required_level=data.get("required_level", 1),
|
||||
required_class=data.get("required_class"),
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""String representation of the item."""
|
||||
if self.is_weapon():
|
||||
return (
|
||||
f"Item({self.name}, weapon, dmg={self.damage}, "
|
||||
f"crit={self.crit_chance*100:.0f}%, value={self.value}g)"
|
||||
)
|
||||
elif self.is_armor():
|
||||
return (
|
||||
f"Item({self.name}, armor, def={self.defense}, "
|
||||
f"res={self.resistance}, value={self.value}g)"
|
||||
)
|
||||
elif self.is_consumable():
|
||||
return (
|
||||
f"Item({self.name}, consumable, "
|
||||
f"effects={len(self.effects_on_use)}, value={self.value}g)"
|
||||
)
|
||||
else:
|
||||
return f"Item({self.name}, quest_item)"
|
||||
Reference in New Issue
Block a user