Skip to main content
Glama
location-presets.ts29.9 kB
/** * Location Presets - Pre-configured room networks for common locations * * These reduce token overhead by ~80% compared to manual specification. * An LLM can spawn a full location with just: { preset: "generic_tavern" } * * Usage: * getLocationPreset('generic_tavern') -> full location config * listLocationPresets() -> all available presets * getLocationsForCategory('tavern') -> filtered list * * @module data/location-presets */ import { POICategory, POIIcon } from '../schema/poi.js'; /** * A room within a location preset */ export interface PresetRoom { id: string; // Unique ID within preset (e.g., "main_hall") name: string; // Display name description: string; // Base description biome: 'urban' | 'forest' | 'dungeon' | 'cavern' | 'divine' | 'mountain' | 'coastal' | 'arcane'; localX?: number; // Local coordinate for mapping localY?: number; exits: PresetExit[]; // Connections to other rooms } /** * An exit/connection between rooms */ export interface PresetExit { direction: 'north' | 'south' | 'east' | 'west' | 'up' | 'down'; targetRoomId: string; // ID of connected room in preset exitType?: 'OPEN' | 'LOCKED' | 'HIDDEN'; lockDC?: number; // DC to unlock if locked } /** * NPC template for location */ export interface PresetNPC { template: string; // Creature template (e.g., "commoner", "guard") name?: string; // Optional specific name roomId: string; // Which room they're in role?: string; // Narrative role (e.g., "bartender", "patron") behavior?: string; // AI behavior hint } /** * Item placement in location */ export interface PresetItem { itemId: string; // Item ID or template roomId: string; // Which room it's in description?: string; // How it appears } /** * Complete location preset */ export interface LocationPreset { id: string; name: string; description: string; category: POICategory; icon: POIIcon; networkType: 'cluster' | 'linear'; rooms: PresetRoom[]; npcs?: PresetNPC[]; items?: PresetItem[]; suggestedLevel?: { min: number; max: number }; tags: string[]; narrativeHook?: string; } // ═══════════════════════════════════════════════════════════════════════════ // TAVERN / INN PRESETS // ═══════════════════════════════════════════════════════════════════════════ export const LOCATION_PRESETS: Record<string, LocationPreset> = { generic_tavern: { id: 'generic_tavern', name: 'The Weary Traveler', description: 'A modest tavern serving locals and travelers alike. Warm hearth, cold ale, and hot rumors.', category: 'commercial', icon: 'inn', networkType: 'cluster', rooms: [ { id: 'common_room', name: 'Common Room', description: 'A warm common room with a crackling fireplace, several wooden tables, and a long bar. The smell of roasted meat and spilled ale permeates the air.', biome: 'urban', localX: 1, localY: 1, exits: [ { direction: 'north', targetRoomId: 'kitchen' }, { direction: 'east', targetRoomId: 'private_room' }, { direction: 'up', targetRoomId: 'rooms_hallway' }, { direction: 'south', targetRoomId: 'entrance' } ] }, { id: 'entrance', name: 'Tavern Entrance', description: 'The main entrance to the tavern. A worn wooden door leads outside, and a notice board is nailed to the wall.', biome: 'urban', localX: 1, localY: 0, exits: [ { direction: 'north', targetRoomId: 'common_room' } ] }, { id: 'kitchen', name: 'Kitchen', description: 'A busy kitchen with a large hearth, hanging pots, and shelves of ingredients. Steam rises from bubbling stews.', biome: 'urban', localX: 1, localY: 2, exits: [ { direction: 'south', targetRoomId: 'common_room' }, { direction: 'east', targetRoomId: 'storage' } ] }, { id: 'storage', name: 'Storage Room', description: 'A dusty storage room filled with barrels, crates, and sacks. The air is cool and dry.', biome: 'urban', localX: 2, localY: 2, exits: [ { direction: 'west', targetRoomId: 'kitchen' } ] }, { id: 'private_room', name: 'Private Dining Room', description: 'A small private room with a single table and comfortable chairs. Curtains can be drawn for privacy.', biome: 'urban', localX: 2, localY: 1, exits: [ { direction: 'west', targetRoomId: 'common_room' } ] }, { id: 'rooms_hallway', name: 'Upstairs Hallway', description: 'A narrow hallway with several doors leading to guest rooms. The floorboards creak underfoot.', biome: 'urban', localX: 1, localY: 1, exits: [ { direction: 'down', targetRoomId: 'common_room' }, { direction: 'east', targetRoomId: 'guest_room_1' }, { direction: 'west', targetRoomId: 'guest_room_2' } ] }, { id: 'guest_room_1', name: 'Guest Room', description: 'A simple but clean guest room with a bed, small table, and washbasin.', biome: 'urban', localX: 2, localY: 1, exits: [ { direction: 'west', targetRoomId: 'rooms_hallway' } ] }, { id: 'guest_room_2', name: 'Guest Room', description: 'A cozy guest room with two beds, suitable for traveling companions.', biome: 'urban', localX: 0, localY: 1, exits: [ { direction: 'east', targetRoomId: 'rooms_hallway' } ] } ], npcs: [ { template: 'commoner', name: 'Barnaby', roomId: 'common_room', role: 'bartender', behavior: 'friendly' }, { template: 'commoner', roomId: 'common_room', role: 'patron' }, { template: 'commoner', roomId: 'common_room', role: 'patron' }, { template: 'commoner', roomId: 'kitchen', role: 'cook', behavior: 'busy' } ], tags: ['tavern', 'inn', 'urban', 'social', 'rest', 'rumors'], narrativeHook: 'The tavern is bustling tonight. A bard plays in the corner, and you catch snippets of conversation about strange happenings in the nearby forest.' }, rough_tavern: { id: 'rough_tavern', name: 'The Broken Bottle', description: 'A seedy tavern in the rough part of town. Shadowy corners hide questionable dealings.', category: 'commercial', icon: 'inn', networkType: 'cluster', rooms: [ { id: 'common_room', name: 'Common Room', description: 'A dim, smoky room with sticky tables and suspicious stains. The clientele watches newcomers with wary eyes.', biome: 'urban', localX: 1, localY: 1, exits: [ { direction: 'north', targetRoomId: 'back_room', exitType: 'LOCKED', lockDC: 15 }, { direction: 'south', targetRoomId: 'entrance' } ] }, { id: 'entrance', name: 'Tavern Entrance', description: 'A heavy door reinforced with iron bands. A half-orc bouncer eyes you up.', biome: 'urban', localX: 1, localY: 0, exits: [ { direction: 'north', targetRoomId: 'common_room' } ] }, { id: 'back_room', name: 'Back Room', description: 'A private room for special clients. A card game is in progress, and gold changes hands.', biome: 'urban', localX: 1, localY: 2, exits: [ { direction: 'south', targetRoomId: 'common_room' }, { direction: 'down', targetRoomId: 'cellar', exitType: 'HIDDEN' } ] }, { id: 'cellar', name: 'Secret Cellar', description: 'A hidden cellar accessed through a trapdoor. Crates of contraband line the walls.', biome: 'urban', localX: 1, localY: 2, exits: [ { direction: 'up', targetRoomId: 'back_room' } ] } ], npcs: [ { template: 'thug', name: 'Grok', roomId: 'entrance', role: 'bouncer', behavior: 'intimidating' }, { template: 'spy', name: 'Whisper', roomId: 'common_room', role: 'information broker', behavior: 'cautious' }, { template: 'bandit_captain', roomId: 'back_room', role: 'crime boss', behavior: 'calculating' } ], tags: ['tavern', 'urban', 'criminal', 'thieves_guild', 'underground'], narrativeHook: 'The bartender slides a drink toward you without being asked. "First one\'s free," she says. "Information costs extra."' }, // ═══════════════════════════════════════════════════════════════════════════ // DUNGEON ENTRANCE PRESETS // ═══════════════════════════════════════════════════════════════════════════ dungeon_entrance: { id: 'dungeon_entrance', name: 'Ancient Ruins Entrance', description: 'Crumbling stone stairs descend into darkness. The air grows cold and stale.', category: 'dungeon', icon: 'ruins', networkType: 'linear', rooms: [ { id: 'entrance', name: 'Ruined Entrance', description: 'Weathered stone pillars frame a dark passage leading underground. Vines and moss cover the ancient stonework.', biome: 'dungeon', localX: 0, localY: 0, exits: [ { direction: 'down', targetRoomId: 'antechamber' } ] }, { id: 'antechamber', name: 'Antechamber', description: 'A small chamber at the bottom of the stairs. Faded murals depict scenes of a forgotten civilization. Torch sconces line the walls.', biome: 'dungeon', localX: 0, localY: 1, exits: [ { direction: 'up', targetRoomId: 'entrance' }, { direction: 'north', targetRoomId: 'first_corridor' } ] }, { id: 'first_corridor', name: 'Stone Corridor', description: 'A long stone corridor stretches into darkness. The walls are lined with empty alcoves.', biome: 'dungeon', localX: 0, localY: 2, exits: [ { direction: 'south', targetRoomId: 'antechamber' }, { direction: 'east', targetRoomId: 'guard_room' }, { direction: 'north', targetRoomId: 'trapped_hall', exitType: 'HIDDEN' } ] }, { id: 'guard_room', name: 'Guard Room', description: 'An old guard station with rusted weapon racks and overturned furniture. Something moved in the shadows.', biome: 'dungeon', localX: 1, localY: 2, exits: [ { direction: 'west', targetRoomId: 'first_corridor' } ] }, { id: 'trapped_hall', name: 'Trapped Hallway', description: 'This corridor has pressure plates visible in the dusty floor. Holes in the walls suggest dart traps.', biome: 'dungeon', localX: 0, localY: 3, exits: [ { direction: 'south', targetRoomId: 'first_corridor' }, { direction: 'north', targetRoomId: 'treasure_room', exitType: 'LOCKED', lockDC: 18 } ] }, { id: 'treasure_room', name: 'Treasure Chamber', description: 'A sealed chamber containing ancient treasures... and possibly their guardian.', biome: 'dungeon', localX: 0, localY: 4, exits: [ { direction: 'south', targetRoomId: 'trapped_hall' } ] } ], suggestedLevel: { min: 1, max: 5 }, tags: ['dungeon', 'ruins', 'underground', 'traps', 'treasure'], narrativeHook: 'The stairs descend into darkness. Your torchlight reveals ancient carvings - warnings in a language long forgotten.' }, cave_entrance: { id: 'cave_entrance', name: 'Dark Cave Entrance', description: 'A natural cave opening leading into the mountainside. Strange sounds echo from within.', category: 'natural', icon: 'cave', networkType: 'cluster', rooms: [ { id: 'entrance', name: 'Cave Mouth', description: 'A large natural cave opening. Daylight illuminates the first few feet before giving way to darkness. Animal tracks mark the dusty floor.', biome: 'cavern', localX: 0, localY: 0, exits: [ { direction: 'north', targetRoomId: 'entry_cavern' } ] }, { id: 'entry_cavern', name: 'Entry Cavern', description: 'A spacious natural cavern with stalactites hanging from the ceiling. Multiple passages branch off into the darkness.', biome: 'cavern', localX: 0, localY: 1, exits: [ { direction: 'south', targetRoomId: 'entrance' }, { direction: 'east', targetRoomId: 'narrow_passage' }, { direction: 'west', targetRoomId: 'water_chamber' }, { direction: 'north', targetRoomId: 'beast_lair' } ] }, { id: 'narrow_passage', name: 'Narrow Passage', description: 'A tight squeeze between rock walls. Medium or larger creatures must squeeze through.', biome: 'cavern', localX: 1, localY: 1, exits: [ { direction: 'west', targetRoomId: 'entry_cavern' }, { direction: 'east', targetRoomId: 'crystal_grotto' } ] }, { id: 'crystal_grotto', name: 'Crystal Grotto', description: 'A beautiful cavern where natural crystals grow from the walls. They glow faintly with magical energy.', biome: 'cavern', localX: 2, localY: 1, exits: [ { direction: 'west', targetRoomId: 'narrow_passage' } ] }, { id: 'water_chamber', name: 'Underground Pool', description: 'A cavern with a deep pool of crystal-clear water. The ceiling is low, and dripping water echoes loudly.', biome: 'cavern', localX: -1, localY: 1, exits: [ { direction: 'east', targetRoomId: 'entry_cavern' } ] }, { id: 'beast_lair', name: 'Beast Lair', description: 'A large chamber littered with bones and refuse. Something lives here... something big.', biome: 'cavern', localX: 0, localY: 2, exits: [ { direction: 'south', targetRoomId: 'entry_cavern' } ] } ], suggestedLevel: { min: 1, max: 4 }, tags: ['cave', 'natural', 'underground', 'beast', 'wilderness'], narrativeHook: 'The cave mouth looms before you. A low growl echoes from somewhere deep within.' }, // ═══════════════════════════════════════════════════════════════════════════ // URBAN / SOCIAL PRESETS // ═══════════════════════════════════════════════════════════════════════════ town_square: { id: 'town_square', name: 'Market Square', description: 'The bustling heart of the town where merchants hawk their wares and townsfolk gather.', category: 'settlement', icon: 'market', networkType: 'cluster', rooms: [ { id: 'square_center', name: 'Town Square', description: 'A large open square with a central fountain. Market stalls ring the perimeter, and townsfolk bustle about their business.', biome: 'urban', localX: 1, localY: 1, exits: [ { direction: 'north', targetRoomId: 'general_store' }, { direction: 'south', targetRoomId: 'town_hall' }, { direction: 'east', targetRoomId: 'blacksmith' }, { direction: 'west', targetRoomId: 'temple' } ] }, { id: 'general_store', name: 'General Store', description: 'A well-stocked shop selling everything from rations to rope. The shopkeeper greets customers warmly.', biome: 'urban', localX: 1, localY: 2, exits: [ { direction: 'south', targetRoomId: 'square_center' } ] }, { id: 'blacksmith', name: 'Blacksmith', description: 'Heat radiates from the forge where a muscular smith hammers glowing metal. Weapons and armor line the walls.', biome: 'urban', localX: 2, localY: 1, exits: [ { direction: 'west', targetRoomId: 'square_center' } ] }, { id: 'temple', name: 'Town Temple', description: 'A modest temple offering blessings and healing. Incense burns before the altar.', biome: 'divine', localX: 0, localY: 1, exits: [ { direction: 'east', targetRoomId: 'square_center' } ] }, { id: 'town_hall', name: 'Town Hall', description: 'The seat of local government. A notice board outside lists bounties and proclamations.', biome: 'urban', localX: 1, localY: 0, exits: [ { direction: 'north', targetRoomId: 'square_center' } ] } ], npcs: [ { template: 'commoner', name: 'Marcus', roomId: 'general_store', role: 'shopkeeper', behavior: 'friendly' }, { template: 'commoner', name: 'Greta', roomId: 'blacksmith', role: 'blacksmith', behavior: 'gruff' }, { template: 'priest', name: 'Father Aldric', roomId: 'temple', role: 'priest', behavior: 'pious' }, { template: 'noble', name: 'Mayor Thorne', roomId: 'town_hall', role: 'mayor', behavior: 'politician' }, { template: 'guard', roomId: 'square_center', role: 'town guard' }, { template: 'guard', roomId: 'square_center', role: 'town guard' } ], tags: ['town', 'urban', 'market', 'social', 'shopping', 'quests'], narrativeHook: 'The market is alive with activity. A town crier announces news, while children play near the fountain.' }, // ═══════════════════════════════════════════════════════════════════════════ // WILDERNESS PRESETS // ═══════════════════════════════════════════════════════════════════════════ forest_clearing: { id: 'forest_clearing', name: 'Forest Clearing', description: 'A peaceful clearing in the deep forest, touched by dappled sunlight.', category: 'natural', icon: 'tree', networkType: 'cluster', rooms: [ { id: 'clearing_center', name: 'Sunlit Clearing', description: 'A circular clearing where sunlight filters through the canopy. Wildflowers carpet the ground, and birdsong fills the air.', biome: 'forest', localX: 1, localY: 1, exits: [ { direction: 'north', targetRoomId: 'ancient_tree' }, { direction: 'south', targetRoomId: 'forest_path' }, { direction: 'east', targetRoomId: 'berry_bushes' }, { direction: 'west', targetRoomId: 'stream' } ] }, { id: 'forest_path', name: 'Forest Path', description: 'A winding dirt path leading through the trees. It continues both directions into the forest.', biome: 'forest', localX: 1, localY: 0, exits: [ { direction: 'north', targetRoomId: 'clearing_center' } ] }, { id: 'ancient_tree', name: 'Ancient Oak', description: 'A massive ancient oak tree dominates this area. Its gnarled trunk is easily 30 feet across. Offerings are piled at its roots.', biome: 'forest', localX: 1, localY: 2, exits: [ { direction: 'south', targetRoomId: 'clearing_center' }, { direction: 'up', targetRoomId: 'tree_hollow', exitType: 'HIDDEN' } ] }, { id: 'tree_hollow', name: 'Tree Hollow', description: 'A hidden hollow within the ancient tree. Fey creatures may have once lived here.', biome: 'forest', localX: 1, localY: 2, exits: [ { direction: 'down', targetRoomId: 'ancient_tree' } ] }, { id: 'berry_bushes', name: 'Berry Thicket', description: 'Dense bushes laden with ripe berries. Animal tracks suggest this is a popular feeding spot.', biome: 'forest', localX: 2, localY: 1, exits: [ { direction: 'west', targetRoomId: 'clearing_center' } ] }, { id: 'stream', name: 'Forest Stream', description: 'A clear stream babbles over smooth stones. The water is cold and refreshing.', biome: 'forest', localX: 0, localY: 1, exits: [ { direction: 'east', targetRoomId: 'clearing_center' } ] } ], tags: ['forest', 'wilderness', 'nature', 'fey', 'peaceful', 'rest'], narrativeHook: 'The clearing feels untouched by time. As sunlight shifts through the leaves, you could swear you hear distant music...' }, // ═══════════════════════════════════════════════════════════════════════════ // CAMP / REST PRESETS // ═══════════════════════════════════════════════════════════════════════════ roadside_camp: { id: 'roadside_camp', name: 'Roadside Camp', description: 'A small campsite set up beside the road, suitable for a night of rest.', category: 'landmark', icon: 'camp', networkType: 'cluster', rooms: [ { id: 'campfire', name: 'Campfire', description: 'A crackling campfire provides warmth and light. Bedrolls are arranged around it.', biome: 'forest', localX: 1, localY: 1, exits: [ { direction: 'south', targetRoomId: 'road' }, { direction: 'north', targetRoomId: 'treeline' } ] }, { id: 'road', name: 'Road', description: 'The main road continues east and west. The camp is just off to the side.', biome: 'forest', localX: 1, localY: 0, exits: [ { direction: 'north', targetRoomId: 'campfire' } ] }, { id: 'treeline', name: 'Treeline', description: 'The edge of the forest provides cover from prying eyes on the road.', biome: 'forest', localX: 1, localY: 2, exits: [ { direction: 'south', targetRoomId: 'campfire' } ] } ], tags: ['camp', 'rest', 'road', 'travel', 'wilderness'], narrativeHook: 'The fire crackles as night settles in. Who will take first watch?' } }; // ═══════════════════════════════════════════════════════════════════════════ // HELPER FUNCTIONS // ═══════════════════════════════════════════════════════════════════════════ /** * Get a location preset by ID */ export function getLocationPreset(presetId: string): LocationPreset | undefined { return LOCATION_PRESETS[presetId]; } /** * List all available location presets */ export function listLocationPresets(): Array<{ id: string; name: string; category: string; tags: string[] }> { return Object.values(LOCATION_PRESETS).map(preset => ({ id: preset.id, name: preset.name, category: preset.category, tags: preset.tags })); } /** * Get locations filtered by category */ export function getLocationsForCategory(category: POICategory): LocationPreset[] { return Object.values(LOCATION_PRESETS).filter(preset => preset.category === category); } /** * Get locations filtered by tag */ export function getLocationsWithTag(tag: string): LocationPreset[] { return Object.values(LOCATION_PRESETS).filter(preset => preset.tags.includes(tag.toLowerCase()) ); } /** * Get a random location matching criteria */ export function getRandomLocation(options?: { category?: POICategory; tags?: string[]; level?: number; }): LocationPreset | undefined { let candidates = Object.values(LOCATION_PRESETS); if (options?.category) { candidates = candidates.filter(p => p.category === options.category); } if (options?.tags && options.tags.length > 0) { candidates = candidates.filter(p => options.tags!.some(tag => p.tags.includes(tag.toLowerCase())) ); } if (options?.level) { candidates = candidates.filter(p => { if (!p.suggestedLevel) return true; return options.level! >= p.suggestedLevel.min && options.level! <= p.suggestedLevel.max; }); } if (candidates.length === 0) return undefined; return candidates[Math.floor(Math.random() * candidates.length)]; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Mnehmos/rpg-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server