DnD_Campaign_Manager / src /models /game_objects.py
official.ghost.logic
Deploy D&D Campaign Manager v2
71b378e
"""
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