Spaces:
Build error
Location & World Map System
Overview
The D&D RAG system uses a hybrid approach combining fixed starter locations with LLM-enhanced procedural generation for endless exploration.
β LLM-Enhanced Location Generation (IMPLEMENTED!)
New implementation (/explore command):
How It Works:
Player: /explore
1. Python determines structure:
- Location type (weighted random based on current location)
- Safety level (safe/dangerous)
- Connections (bidirectional link to current location)
2. LLM generates flavor (ONCE per location):
Prompt includes:
- Current location context
- Recent battles (defeated enemies)
- Time of day
- NPCs present
- Weather/day
LLM Response:
NAME: Shadowfang Grotto
DESCRIPTION: A damp cavern where goblin corpses still litter the floor...
3. Location CACHED in world_map:
session.world_map["Shadowfang Grotto"] = Location(...)
4. On revisit:
- Load from cache (no regeneration!)
- LLM only narrates travel
- Can reference state changes (defeated_enemies, moved_items)
Key Features:
β
Generated ONCE - LLM creates name + description on first /explore
β
CACHED forever - Stored in world_map, never regenerated
β
Context-aware - LLM sees game state (battles, NPCs, time, weather)
β
Graceful fallback - If LLM fails, falls back to template generation
β
Unique names - No more "Dark Cavern #3" duplicates
β
Rich descriptions - Atmospheric, specific to your adventure
Code Location:
- LLM enhancement:
world_builder.py::generate_llm_enhanced_location()(lines 329-434) - Integration:
gm_dialogue_unified.py/explorecommand (lines 365-416) - Template fallback:
world_builder.py::generate_random_location()(still available)
Testing:
pytest tests/test_llm_location_generation.py # 5/5 passing β
pytest tests/test_location_generation.py # 11/11 passing β
How It Works
1. Fixed Starting World
dnd_rag_system/systems/world_builder.py::create_starting_world()
Pre-built locations:
- Town Square (hub) β connects to everything
- The Prancing Pony Inn (safe, has inn)
- Market Square (safe, has shop)
- Temple District (safe, healing)
- Adventurer's Guild Hall (safe, has shop)
- Town Gates (safe, transition point)
- Forest Path (dangerous)
- Mountain Road (dangerous)
- Dark Cave (dangerous, undiscovered initially)
- Old Ruins (dangerous, undiscovered)
- Dragon's Lair (dangerous, undiscovered)
- MΓΌrren (dangerous mountain village with shop/inn)
All locations are pre-connected with bidirectional paths defined in the connections field.
2. Procedural Location Generation
dnd_rag_system/systems/world_builder.py::generate_random_location()
How /explore works:
- Player types
/exploreor/search - System checks current location
- Checks if location already has 6+ connections (max explored)
- If space available:
- Generates new location based on current location type
- Creates procedural name (e.g., "Dark Cavern", "Ancient Ruins")
- Adds procedural description
- Creates bidirectional connection
- Adds to world map
Generation Rules:
From TOWN/TAVERN/SHOP:
- 40% Forest
- 40% Wilderness
- 20% Mountain
From FOREST/WILDERNESS:
- 30% Cave
- 20% Ruins
- 25% More Forest
- 25% More Wilderness
From MOUNTAIN:
- 50% Cave
- 20% Castle
- 30% Ruins
From DUNGEON/CAVE:
- 40% Cave
- 30% Ruins
- 30% Dungeon (deeper)
3. World Map Storage
In GameSession (game_state.py):
world_map: Dict[str, Location] = {} # location_name -> Location object
Location object fields:
name: str- Location namelocation_type: LocationType- TOWN, CAVE, FOREST, etc.description: str- Text descriptionconnections: List[str]- Connected location namesis_safe: bool- Safe for resting?is_discovered: bool- Has player found it?has_shop: bool- Can buy/sell items?has_inn: bool- Can rest here?resident_npcs: List[str]- NPCs that live hereitems: List[str]- Items available to takevisit_count: int- Times visitedlast_visit_day: int- Game day of last visit
4. Map Commands
/map - Show current location + discovered areas
πΊοΈ WORLD MAP
π Current Location: Town Square
The heart of the town, bustling with activity...
π§ You can travel to:
β
The Prancing Pony Inn (tavern)
β
Market Square (shop)
βοΈ Forest Path (forest)
β ??? (undiscovered area)
π All Discovered Locations (8):
π β
Town Square (town) [3x]
β
Market Square (shop)
βοΈ Dark Cavern (cave)
...
π‘ Use `/travel <location>` to move, `/explore` to discover new areas.
/locations - Simple list of discovered locations
πΊοΈ Discovered Locations:
- Town Square (town) (visited 3x)
- Market Square (shop)
- Dark Cavern (cave)
...
/travel <location> - Move to connected location
# In gm_dialogue_unified.py (lines 249-262)
if lower_input.startswith('/travel '):
destination = player_input[8:].strip()
success, message = self.session.travel_to(destination)
# Returns success/failure message
/explore or /search - Generate new random location
# In gm_dialogue_unified.py (lines 365-394)
new_location = generate_random_location(current_loc)
self.session.add_location(new_location)
self.session.connect_locations(current_loc.name, new_location.name)
5. Connection Management
Bidirectional connections:
# When connecting locations
self.session.connect_locations("Town Square", "Forest Path")
# This updates BOTH locations:
# - Town Square.connections includes "Forest Path"
# - Forest Path.connections includes "Town Square"
Max connections: 6 per location (prevents infinite branching)
Travel validation:
def travel_to(self, destination: str) -> Tuple[bool, str]:
# Check if destination is in current location's connections
# Check if destination exists in world_map
# If valid: update current_location, record visit, return description
6. Discovery System
Locations have is_discovered flag:
- Fixed locations start as
discovered=True(except caves/dungeons) - Generated locations start as
discovered=False - Becomes discovered when:
- Player travels there
- Location is mentioned in narrative
- Player uses
/exploreto create it
In map display:
- Discovered: Shows full name and type
- Undiscovered: Shows "β ??? (undiscovered area)"
7. Key Files
Core Implementation:
dnd_rag_system/systems/world_builder.py- Location generationdnd_rag_system/systems/game_state.py- Location storage, travel logicdnd_rag_system/systems/gm_dialogue_unified.py- Map commands (lines 249-394)
Location Types (enum):
class LocationType(Enum):
TOWN = "town"
TAVERN = "tavern"
SHOP = "shop"
TEMPLE = "temple"
GUILD_HALL = "guild_hall"
FOREST = "forest"
MOUNTAIN = "mountain"
CAVE = "cave"
RUINS = "ruins"
CASTLE = "castle"
DUNGEON = "dungeon"
WILDERNESS = "wilderness"
Summary
Locations are:
- β Fixed for the starting world (12 hand-crafted locations)
- β
Procedurally generated via
/explorecommand (unlimited) - β Fully connected via bidirectional graph
- β Stored in world_map dictionary in GameSession
- β Tracked with visit counts, discovery status, connections
- β
Displayed via
/mapand/locationscommands - β
Navigable via
/travel <location>command
The mapping is dynamic and grows as players explore! πΊοΈ