""" Standalone items module for the API. Loads and manages game items from JSON without bot dependencies. """ import json from pathlib import Path from typing import Dict, Any, Optional, Union from dataclasses import dataclass @dataclass class Item: """Represents a game item""" id: str name: Union[str, Dict[str, str]] description: Union[str, Dict[str, str]] type: str image_path: str = "" emoji: str = "📦" stackable: bool = True equippable: bool = False consumable: bool = False weight: float = 0.0 volume: float = 0.0 stats: Dict[str, int] = None effects: Dict[str, Any] = None value: int = 10 # Base value for trading # Equipment system slot: str = None # Equipment slot: head, torso, legs, feet, weapon, offhand, backpack durability: int = None # Max durability for equippable items tier: int = 1 # Item tier (1-5) encumbrance: int = 0 # Encumbrance penalty when equipped weapon_effects: Dict[str, Any] = None # Weapon effects: bleeding, stun, etc. # Repair system repairable: bool = False # Can this item be repaired? repair_materials: list = None # Materials needed for repair repair_percentage: int = 25 # Percentage of durability restored per repair repair_tools: list = None # Tools required for repair (consumed durability) # Crafting system craftable: bool = False # Can this item be crafted? craft_materials: list = None # Materials needed to craft this item craft_level: int = 1 # Minimum level required to craft this item craft_tools: list = None # Tools required for crafting (consumed durability) # Uncrafting system uncraftable: bool = False # Can this item be uncrafted? uncraft_yield: list = None # Materials yielded from uncrafting (before loss chance) uncraft_loss_chance: float = 0.3 # Chance to lose materials when uncrafting (0.3 = 30%) uncraft_tools: list = None # Tools required for uncrafting # Combat system combat_usable: bool = False # Can be used during combat combat_only: bool = False # Can ONLY be used during combat combat_effects: Dict[str, Any] = None # Effects applied in combat (damage, status) def __post_init__(self): if self.stats is None: self.stats = {} if self.effects is None: self.effects = {} if self.weapon_effects is None: self.weapon_effects = {} if self.repair_materials is None: self.repair_materials = [] if self.craft_materials is None: self.craft_materials = [] if self.repair_tools is None: self.repair_tools = [] if self.craft_tools is None: self.craft_tools = [] if self.uncraft_yield is None: self.uncraft_yield = [] if self.uncraft_tools is None: self.uncraft_tools = [] if self.combat_effects is None: self.combat_effects = {} class ItemsManager: """Manages all game items""" def __init__(self, gamedata_path: str = "./gamedata"): self.gamedata_path = Path(gamedata_path) self.items: Dict[str, Item] = {} self.load_items() def load_items(self): """Load all items from items.json""" json_path = self.gamedata_path / 'items.json' try: with open(json_path, 'r') as f: data = json.load(f) for item_id, item_data in data.get('items', {}).items(): item_type = item_data.get('type', 'misc') # Automatically mark as consumable if type is consumable is_consumable = item_data.get('consumable', item_type == 'consumable') # Collect effects from root level or effects dict effects = item_data.get('effects', {}).copy() # Add common consumable effects if they exist at root level if 'hp_restore' in item_data: effects['hp_restore'] = item_data['hp_restore'] if 'stamina_restore' in item_data: effects['stamina_restore'] = item_data['stamina_restore'] if 'treats' in item_data: effects['treats'] = item_data['treats'] item = Item( id=item_id, name=item_data.get('name', 'Unknown Item'), description=item_data.get('description', ''), type=item_type, value=item_data.get('value', 10), image_path=item_data.get('image_path', ''), emoji=item_data.get('emoji', '📦'), stackable=item_data.get('stackable', True), equippable=item_data.get('equippable', False), consumable=is_consumable, weight=item_data.get('weight', 0.0), volume=item_data.get('volume', 0.0), stats=item_data.get('stats', {}), effects=effects, slot=item_data.get('slot'), durability=item_data.get('durability'), tier=item_data.get('tier', 1), encumbrance=item_data.get('encumbrance', 0), weapon_effects=item_data.get('weapon_effects', {}), repairable=item_data.get('repairable', False), repair_materials=item_data.get('repair_materials', []), repair_percentage=item_data.get('repair_percentage', 25), repair_tools=item_data.get('repair_tools', []), craftable=item_data.get('craftable', False), craft_materials=item_data.get('craft_materials', []), craft_level=item_data.get('craft_level', 1), craft_tools=item_data.get('craft_tools', []), uncraftable=item_data.get('uncraftable', False), uncraft_yield=item_data.get('uncraft_yield', []), uncraft_loss_chance=item_data.get('uncraft_loss_chance', 0.3), uncraft_tools=item_data.get('uncraft_tools', []), combat_usable=item_data.get('combat_usable', is_consumable), # Default: consumables are combat usable combat_only=item_data.get('combat_only', False), combat_effects=item_data.get('combat_effects', {}) ) self.items[item_id] = item print(f"📦 Loaded {len(self.items)} items") except FileNotFoundError: print("⚠️ items.json not found") except Exception as e: print(f"⚠️ Error loading items.json: {e}") def get_item(self, item_id: str) -> Optional[Item]: """Get an item by ID""" return self.items.get(item_id) def get_all_items(self) -> Dict[str, Item]: """Get all items""" return self.items # Global items manager instance items_manager = ItemsManager() def get_item(item_id: str) -> Optional[Item]: """Convenience function to get an item""" return items_manager.get_item(item_id)