""" Validation utilities for game objects """ from typing import List, Dict, Any, Tuple from src.models.character import Character, DnDRace, DnDClass from src.models.campaign import Campaign def validate_character(character: Character) -> Tuple[bool, List[str]]: """ Validate character data Returns: Tuple of (is_valid, error_messages) """ errors = [] # Name validation if not character.name or len(character.name.strip()) == 0: errors.append("Character name cannot be empty") # Stats validation stats = character.stats for stat_name in ['strength', 'dexterity', 'constitution', 'intelligence', 'wisdom', 'charisma']: stat_value = getattr(stats, stat_name) if stat_value < 1 or stat_value > 30: errors.append(f"{stat_name.title()} must be between 1 and 30") # HP validation if character.current_hit_points < 0: errors.append("Current HP cannot be negative") if character.current_hit_points > character.max_hit_points: errors.append("Current HP cannot exceed max HP") if character.max_hit_points < 1: errors.append("Max HP must be at least 1") # AC validation if character.armor_class < 1: errors.append("Armor class must be at least 1") # Level validation if character.level < 1 or character.level > 20: errors.append("Level must be between 1 and 20") # XP validation if character.experience_points < 0: errors.append("Experience points cannot be negative") return len(errors) == 0, errors def validate_campaign(campaign: Campaign) -> Tuple[bool, List[str]]: """ Validate campaign data Returns: Tuple of (is_valid, error_messages) """ errors = [] # Name validation if not campaign.name or len(campaign.name.strip()) == 0: errors.append("Campaign name cannot be empty") # Summary validation if not campaign.summary or len(campaign.summary.strip()) == 0: errors.append("Campaign summary cannot be empty") # Main conflict validation if not campaign.main_conflict or len(campaign.main_conflict.strip()) == 0: errors.append("Main conflict cannot be empty") # Party size validation if campaign.party_size < 1 or campaign.party_size > 10: errors.append("Party size must be between 1 and 10") # Session validation if campaign.current_session < 1: errors.append("Current session must be at least 1") if campaign.total_sessions < 0: errors.append("Total sessions cannot be negative") return len(errors) == 0, errors def validate_stat_array(stats: Dict[str, int]) -> Tuple[bool, List[str]]: """Validate D&D ability score array""" errors = [] required_stats = ['strength', 'dexterity', 'constitution', 'intelligence', 'wisdom', 'charisma'] for stat in required_stats: if stat not in stats: errors.append(f"Missing required stat: {stat}") else: value = stats[stat] if value < 1 or value > 30: errors.append(f"{stat.title()} must be between 1 and 30, got {value}") return len(errors) == 0, errors def is_valid_race(race: str) -> bool: """Check if race is valid""" try: DnDRace(race) return True except ValueError: return False def is_valid_class(character_class: str) -> bool: """Check if class is valid""" try: DnDClass(character_class) return True except ValueError: return False def get_available_races() -> List[str]: """Get list of available races""" return [race.value for race in DnDRace] def get_available_classes() -> List[str]: """Get list of available classes""" return [cls.value for cls in DnDClass]