""" Skills service - loads skill definitions and provides skill availability logic. """ import json from typing import Dict, Any, List, Optional from pathlib import Path class Skill: """Represents a combat skill.""" def __init__(self, skill_id: str, data: Dict[str, Any]): self.id = skill_id self.name = data.get('name', skill_id) self.description = data.get('description', '') self.icon = data.get('icon', '⚔️') self.stat_requirement = data.get('stat_requirement', 'strength') self.stat_threshold = data.get('stat_threshold', 0) self.level_requirement = data.get('level_requirement', 1) self.cooldown = data.get('cooldown', 3) self.stamina_cost = data.get('stamina_cost', 5) self.effects = data.get('effects', {}) class SkillsManager: """Loads and manages skill definitions from JSON.""" def __init__(self, gamedata_path: str = "./gamedata"): self.gamedata_path = Path(gamedata_path) self.skills: Dict[str, Skill] = {} self.load_skills() def load_skills(self): """Load skills from skills.json.""" json_path = self.gamedata_path / 'skills.json' try: with open(json_path, 'r') as f: data = json.load(f) for skill_id, skill_data in data.get('skills', {}).items(): self.skills[skill_id] = Skill(skill_id, skill_data) print(f"⚔️ Loaded {len(self.skills)} skills") except FileNotFoundError: print("⚠️ skills.json not found") except Exception as e: print(f"⚠️ Error loading skills.json: {e}") def get_skill(self, skill_id: str) -> Optional[Skill]: """Get a skill by ID.""" return self.skills.get(skill_id) def get_all_skills(self) -> Dict[str, Skill]: """Get all skills.""" return self.skills def get_available_skills(self, character: Dict[str, Any]) -> List[Dict[str, Any]]: """ Get all skills available to a character based on their stats and level. Returns list of skill dicts with availability info. """ available = [] for skill_id, skill in self.skills.items(): stat_value = character.get(skill.stat_requirement, 0) level = character.get('level', 1) unlocked = (stat_value >= skill.stat_threshold and level >= skill.level_requirement) skill_info = { "id": skill.id, "name": skill.name, "description": skill.description, "icon": skill.icon, "stat_requirement": skill.stat_requirement, "stat_threshold": skill.stat_threshold, "level_requirement": skill.level_requirement, "cooldown": skill.cooldown, "stamina_cost": skill.stamina_cost, "unlocked": unlocked, "effects": skill.effects, } available.append(skill_info) return available class Perk: """Represents a passive perk.""" def __init__(self, perk_id: str, data: Dict[str, Any]): self.id = perk_id self.name = data.get('name', perk_id) self.description = data.get('description', '') self.icon = data.get('icon', '⭐') self.requirements = data.get('requirements', {}) self.effects = data.get('effects', {}) class PerksManager: """Loads and manages perk definitions from JSON.""" def __init__(self, gamedata_path: str = "./gamedata"): self.gamedata_path = Path(gamedata_path) self.perks: Dict[str, Perk] = {} self.load_perks() def load_perks(self): """Load perks from perks.json.""" json_path = self.gamedata_path / 'perks.json' try: with open(json_path, 'r') as f: data = json.load(f) for perk_id, perk_data in data.get('perks', {}).items(): self.perks[perk_id] = Perk(perk_id, perk_data) print(f"⭐ Loaded {len(self.perks)} perks") except FileNotFoundError: print("⚠️ perks.json not found") except Exception as e: print(f"⚠️ Error loading perks.json: {e}") def get_perk(self, perk_id: str) -> Optional[Perk]: """Get a perk by ID.""" return self.perks.get(perk_id) def get_all_perks(self) -> Dict[str, Perk]: """Get all perks.""" return self.perks def check_requirements(self, perk: Perk, character: Dict[str, Any]) -> bool: """Check if a character meets a perk's requirements.""" for req_key, req_value in perk.requirements.items(): if req_key.endswith('_max'): # Max constraint (e.g., endurance_max: 8 means END must be ≤ 8) stat_name = req_key.replace('_max', '') if character.get(stat_name, 0) > req_value: return False else: # Min constraint if character.get(req_key, 0) < req_value: return False return True def get_available_perks(self, character: Dict[str, Any], owned_perk_ids: List[str]) -> List[Dict[str, Any]]: """ Get all perks with availability status for a character. """ available = [] for perk_id, perk in self.perks.items(): meets_requirements = self.check_requirements(perk, character) owned = perk_id in owned_perk_ids perk_info = { "id": perk.id, "name": perk.name, "description": perk.description, "icon": perk.icon, "requirements": perk.requirements, "effects": perk.effects, "meets_requirements": meets_requirements, "owned": owned, } available.append(perk_info) return available # Perk points per level PERK_POINT_INTERVAL = 5 # Every 5 levels def get_total_perk_points(level: int) -> int: """Calculate total perk points available for a given level.""" return level // PERK_POINT_INTERVAL # Global instances skills_manager = SkillsManager() perks_manager = PerksManager()