""" Location data models for the world exploration system. This module defines Location and Region dataclasses that represent structured game world data. Locations are loaded from YAML files and provide rich context for AI narrative generation. """ from dataclasses import dataclass, field from typing import Dict, List, Any, Optional from app.models.enums import LocationType @dataclass class Location: """ Represents a defined location in the game world. Locations are persistent world entities with NPCs, quests, and connections to other locations. They are loaded from YAML files at runtime. Attributes: location_id: Unique identifier (e.g., "crossville_tavern") name: Display name (e.g., "The Rusty Anchor Tavern") location_type: Type of location (town, tavern, wilderness, dungeon, etc.) region_id: Parent region this location belongs to description: Full description for AI narrative context lore: Optional historical/background information ambient_description: Atmospheric details for AI narration available_quests: Quest IDs that can be discovered at this location npc_ids: List of NPC IDs present at this location discoverable_locations: Location IDs that can be revealed from here is_starting_location: Whether this is a valid origin starting point tags: Additional metadata tags for filtering/categorization """ location_id: str name: str location_type: LocationType region_id: str description: str lore: Optional[str] = None ambient_description: Optional[str] = None available_quests: List[str] = field(default_factory=list) npc_ids: List[str] = field(default_factory=list) discoverable_locations: List[str] = field(default_factory=list) is_starting_location: bool = False tags: List[str] = field(default_factory=list) def to_dict(self) -> Dict[str, Any]: """ Serialize location to dictionary for JSON responses. Returns: Dictionary containing all location data """ return { "location_id": self.location_id, "name": self.name, "location_type": self.location_type.value, "region_id": self.region_id, "description": self.description, "lore": self.lore, "ambient_description": self.ambient_description, "available_quests": self.available_quests, "npc_ids": self.npc_ids, "discoverable_locations": self.discoverable_locations, "is_starting_location": self.is_starting_location, "tags": self.tags, } def to_story_dict(self) -> Dict[str, Any]: """ Serialize location for AI narrative context. Returns a trimmed version with only narrative-relevant data to reduce token usage in AI prompts. Returns: Dictionary containing story-relevant location data """ return { "name": self.name, "type": self.location_type.value, "description": self.description, "ambient": self.ambient_description, "lore": self.lore, } @classmethod def from_dict(cls, data: Dict[str, Any]) -> 'Location': """ Deserialize location from dictionary. Args: data: Dictionary containing location data (from YAML or JSON) Returns: Location instance """ # Handle location_type - can be string or LocationType enum location_type = data.get("location_type", "town") if isinstance(location_type, str): location_type = LocationType(location_type) return cls( location_id=data["location_id"], name=data["name"], location_type=location_type, region_id=data["region_id"], description=data["description"], lore=data.get("lore"), ambient_description=data.get("ambient_description"), available_quests=data.get("available_quests", []), npc_ids=data.get("npc_ids", []), discoverable_locations=data.get("discoverable_locations", []), is_starting_location=data.get("is_starting_location", False), tags=data.get("tags", []), ) def __repr__(self) -> str: """String representation of the location.""" return f"Location({self.location_id}, {self.name}, {self.location_type.value})" @dataclass class Region: """ Represents a geographical region containing multiple locations. Regions group related locations together for organizational purposes and can contain region-wide lore or events. Attributes: region_id: Unique identifier (e.g., "crossville") name: Display name (e.g., "Crossville Province") description: Region overview and atmosphere location_ids: List of all location IDs in this region """ region_id: str name: str description: str location_ids: List[str] = field(default_factory=list) def to_dict(self) -> Dict[str, Any]: """ Serialize region to dictionary. Returns: Dictionary containing all region data """ return { "region_id": self.region_id, "name": self.name, "description": self.description, "location_ids": self.location_ids, } @classmethod def from_dict(cls, data: Dict[str, Any]) -> 'Region': """ Deserialize region from dictionary. Args: data: Dictionary containing region data Returns: Region instance """ return cls( region_id=data["region_id"], name=data["name"], description=data["description"], location_ids=data.get("location_ids", []), ) def __repr__(self) -> str: """String representation of the region.""" return f"Region({self.region_id}, {self.name}, {len(self.location_ids)} locations)"