""" Game objects: Items, Encounters, Locations """ from datetime import datetime from typing import Optional, List, Dict, Any from enum import Enum from pydantic import BaseModel, Field # ==================== ITEMS ==================== class ItemRarity(str, Enum): """D&D item rarity""" COMMON = "Common" UNCOMMON = "Uncommon" RARE = "Rare" VERY_RARE = "Very Rare" LEGENDARY = "Legendary" ARTIFACT = "Artifact" class ItemType(str, Enum): """Item categories""" WEAPON = "Weapon" ARMOR = "Armor" POTION = "Potion" SCROLL = "Scroll" WAND = "Wand" RING = "Ring" WONDROUS = "Wondrous Item" TOOL = "Tool" TREASURE = "Treasure" CONSUMABLE = "Consumable" class Item(BaseModel): """Magic items and equipment""" id: Optional[str] = Field(default=None) name: str = Field(min_length=1, max_length=100) item_type: ItemType rarity: ItemRarity = Field(default=ItemRarity.COMMON) description: str = Field(description="Item description") properties: List[str] = Field(default_factory=list, description="Magical properties") requires_attunement: bool = Field(default=False) attunement_requirements: Optional[str] = Field(default=None) value_gp: int = Field(ge=0, default=0, description="Value in gold pieces") weight_lbs: float = Field(ge=0, default=0, description="Weight in pounds") charges: Optional[int] = Field(default=None, description="Current charges") max_charges: Optional[int] = Field(default=None, description="Maximum charges") flavor_text: str = Field(default="", description="Flavor/lore text") history: str = Field(default="", description="Item history") campaign_id: Optional[str] = Field(default=None) owner_id: Optional[str] = Field(default=None, description="Current owner") created_at: datetime = Field(default_factory=datetime.now) # ==================== ENCOUNTERS ==================== class EncounterDifficulty(str, Enum): """Encounter difficulty""" EASY = "Easy" MEDIUM = "Medium" HARD = "Hard" DEADLY = "Deadly" class EncounterType(str, Enum): """Type of encounter""" COMBAT = "Combat" SOCIAL = "Social" EXPLORATION = "Exploration" PUZZLE = "Puzzle" TRAP = "Trap" MIXED = "Mixed" class Encounter(BaseModel): """Combat/challenge encounter""" id: Optional[str] = Field(default=None) name: str = Field(min_length=1, max_length=100) encounter_type: EncounterType difficulty: EncounterDifficulty party_level: int = Field(ge=1, le=20, description="Expected party level") party_size: int = Field(ge=1, le=10, default=4, description="Expected party size") description: str = Field(description="Encounter description") setup: str = Field(default="", description="How to set up the encounter") # Combat specific enemies: List[Dict[str, Any]] = Field(default_factory=list, description="Enemy creatures") enemy_tactics: str = Field(default="", description="How enemies fight") # Environment location: str = Field(default="", description="Where encounter takes place") terrain_features: List[str] = Field(default_factory=list, description="Terrain elements") environmental_effects: List[str] = Field(default_factory=list, description="Environmental hazards/effects") # Rewards experience_reward: int = Field(ge=0, default=0) treasure: List[str] = Field(default_factory=list, description="Treasure rewards") # Alternatives alternative_solutions: List[str] = Field(default_factory=list, description="Non-combat solutions") scaling_suggestions: str = Field(default="", description="How to scale difficulty") # Metadata campaign_id: Optional[str] = Field(default=None) session_number: Optional[int] = Field(default=None) completed: bool = Field(default=False) notes: str = Field(default="", description="GM notes") created_at: datetime = Field(default_factory=datetime.now) # ==================== LOCATIONS ==================== class LocationType(str, Enum): """Location categories""" CITY = "City" TOWN = "Town" VILLAGE = "Village" DUNGEON = "Dungeon" WILDERNESS = "Wilderness" CASTLE = "Castle" TEMPLE = "Temple" TAVERN = "Tavern" SHOP = "Shop" RUINS = "Ruins" CAVE = "Cave" FOREST = "Forest" MOUNTAIN = "Mountain" COAST = "Coast" PLANE = "Plane" class Location(BaseModel): """Places in the campaign world""" id: Optional[str] = Field(default=None) name: str = Field(min_length=1, max_length=100) location_type: LocationType description: str = Field(description="Location description") atmosphere: str = Field(default="", description="Mood/feeling of the place") # Geography region: Optional[str] = Field(default=None, description="Larger region") parent_location: Optional[str] = Field(default=None, description="Contains this location") sub_locations: List[str] = Field(default_factory=list, description="Locations within this one") # Details population: Optional[int] = Field(default=None) government: Optional[str] = Field(default=None) notable_features: List[str] = Field(default_factory=list) points_of_interest: List[str] = Field(default_factory=list) # NPCs & Factions notable_npcs: List[str] = Field(default_factory=list, description="NPC IDs") controlling_faction: Optional[str] = Field(default=None) # Resources available_services: List[str] = Field(default_factory=list, description="Services available") shops: List[str] = Field(default_factory=list, description="Shops/merchants") # Secrets & hooks secrets: List[str] = Field(default_factory=list, description="Hidden information") rumors: List[str] = Field(default_factory=list, description="Local rumors") plot_hooks: List[str] = Field(default_factory=list, description="Adventure hooks") # Map map_description: str = Field(default="", description="Layout/map description") connected_locations: List[str] = Field(default_factory=list, description="Connected locations") travel_times: Dict[str, str] = Field(default_factory=dict, description="Travel times to other locations") # Metadata campaign_id: Optional[str] = Field(default=None) visited: bool = Field(default=False) first_visit_session: Optional[int] = Field(default=None) notes: str = Field(default="", description="GM notes") created_at: datetime = Field(default_factory=datetime.now) def mark_visited(self, session_number: int): """Mark location as visited""" if not self.visited: self.visited = True self.first_visit_session = session_number