first commit
This commit is contained in:
181
api/app/models/location.py
Normal file
181
api/app/models/location.py
Normal file
@@ -0,0 +1,181 @@
|
||||
"""
|
||||
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)"
|
||||
Reference in New Issue
Block a user