158 lines
6.4 KiB
Python
158 lines
6.4 KiB
Python
"""
|
|
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
|
|
from dataclasses import dataclass
|
|
|
|
|
|
@dataclass
|
|
class Item:
|
|
"""Represents a game item"""
|
|
id: str
|
|
name: str
|
|
description: 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
|
|
# 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
|
|
|
|
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 = []
|
|
self.craft_materials = []
|
|
|
|
|
|
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,
|
|
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', [])
|
|
)
|
|
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)
|