Location Structure
The GameLocation interface defines all properties available for creating locations in the game world.
Required Fields
Every location must define these core properties:
Basic Information
name: string; // Unique identifier used internally
displayName?: string; // Optional display name (defaults to name)
description: string; // Narrative description shown to players
The name field serves as the location’s unique identifier throughout the game. Use the displayName field when you want to show a different name to players.
Visual Properties
image: string; // Background image path
icon: string; // Map icon image path
screenEffect: ScreenEffectType; // Visual atmosphere effect
Available screen effects:
'none'- No effect'sun'- Bright sunlight'rain'- Falling rain'snow'- Snowfall'smoke'- Smoky atmosphere'dust'- Dusty particles'driftingLeaves'- Floating leaves'flyingPetals'- Cherry blossoms or similar
Audio Properties
music: MusicName; // Background music track
ambience: AmbienceName; // Ambient sound effects
Music and ambience names must match registered audio files in the game.
Map Properties
position: { x: number; y: number }; // World map coordinates
size: 'tiny' | 'small' | 'normal' | 'large'; // Icon size on map
Position coordinates determine where the location appears on the world map. Size affects how prominently it displays.
Connections
unlocks: (ConditionalLink | ExplorationLink)[]; // Connected locations
Every location must define its connections to other locations, even if the array is empty. See Connecting Locations for details.
Optional Fields
Realm Requirements
realm?: Realm; // Minimum realm to access
realmProgress?: RealmProgress; // Specific progress level
Example:
realm: 'qiCondensation',
realmProgress: 'Middle',
Buildings
buildings?: LocationBuilding[]; // Interactive structures
Buildings provide services and interactions. See Building Types for all available options.
Combat Content
enemies?: LocationEnemy[]; // Combat encounters
Enemy encounters with intro events:
enemies: [
{
enemy: gorashi,
rarity: 'qitouched',
condition: '1',
intro: [
{
kind: 'text',
text: 'A Gorashi emerges from the undergrowth...'
}
]
}
]
Enemy Integration: Enemies must be defined as EnemyEntity objects before being added to locations. See the Enemy Entities documentation for complete enemy design and implementation guidance, including stance systems, behavior patterns, and combat mechanics.
Events
events?: LocationEvent[]; // Random events
explorationEvent?: LocationEvent[]; // First-time exploration events
mapEvents?: LocationMapEvent[]; // Timed map events
Location Events
Random events that can trigger when visiting:
events: [
{
event: [...], // Event steps
rarity: 'mundane', // Spawn frequency
triggerChance: 0.1, // Override rarity (optional)
noCooldown: true, // Skip the between-event cooldown (optional)
condition: 'realm >= qiCondensation', // When available
cooldown: { // Optional per-event cooldown
key: 'my_event_key', // Unique flag key for this event
min: 5, // Minimum days before can retrigger
max: 15 // Maximum days before can retrigger
},
pity: true // Optional: include in global pity pool
}
]
triggerChance: Overrides the rarity-based probability for this event.
noCooldown: When true, this event bypasses the standard between-event cooldown, allowing it to fire on consecutive explorations.
cooldown: Prevents an event from firing again for a random number of days in [min, max]. The key must be unique across your mod’s events — it is stored as a flag to track the cooldown.
pity: Marks the event as part of the global pity pool. All pity events share a counter (globalSpecialEventPity) that increments each exploration where at least one pity event was eligible but none fired. Any pity event firing resets the counter to zero. The event’s effective rarity weight is multiplied by min(1 + counter × 0.1, 5) — reaching 5× after roughly 40 consecutive failed attempts. Each player also receives a fixed per-event multiplier (drawn from a shuffled odds list seeded by their name), so some events are naturally easier or harder to find for a given player. Setting pity: true on rare one-time discovery events ensures no player is permanently locked out of them.
Exploration Events
Special events that trigger during exploration:
explorationEvent: [
{
event: [...],
rarity: 'mundane',
condition: 'exploreWarning == 0'
}
]
Map Events
Timed events that appear on the map:
mapEvents: [
{
name: 'Training Beast',
realm: 'meridianOpening',
condition: 'trainingFlag == 1',
image: beastIcon,
persist: 2, // Days visible
cooldown: { min: 5, max: 16 }, // Days between spawns
event: [...]
}
]
Gathering Event
gatheringEvent?: LocationGatheringEvent;
A special event that fires when the player visits a location that currently has multiple named characters present. Use it to create social or atmospheric scenes — moments that emerge naturally from character congregation rather than from exploration or time.
gatheringEvent: {
steps: [
{
kind: 'text',
text: 'The tavern is unusually crowded tonight...'
},
// ...more event steps
],
triggerChance?: 0.3, // Probability of firing (0–1, optional)
resetMonths?: { min: 2, max: 6 }, // Cooldown before it can fire again (optional)
minCharacters?: 3 // Minimum characters present to trigger (default: 3)
}
The gathering event respects both the global encounter cooldown and a per-location gathering cooldown. It will not fire if fewer than minCharacters named characters are currently at this location (the default threshold is 3).
Missions
missions?: SectMission[]; // Sect mission board
crafting?: CraftingMission[]; // Crafting hall missions
Mission definitions for mission halls:
missions: [
{
realm: 'bodyForging',
rarity: 'mundane',
quest: 'leachongCulling',
condition: '1'
}
]
Reputation
reputationName?: string; // Reputation faction name
If defined, the location tracks player reputation for shops and other features.
Exploration Override
explorationCountOverride?: number; // Custom exploration count
Override the default exploration requirement (normally 3 explorations per unlock).
Complete Example
export const liangTiaoVillage: GameLocation = {
// Required fields
name: 'Liang Tiao Village',
description: 'A small village at the crux of two rivers...',
image: villageBg,
icon: villageIcon,
screenEffect: 'rain',
music: 'Liangtiao',
ambience: 'Rain',
position: { x: 2019, y: 406 },
size: 'normal',
// Connections
unlocks: [
{
location: lingyuMoor,
condition: 'moorUnlocked == 1',
distance: 3
}
],
// Optional features
reputationName: 'Liang Tiao Village',
buildings: [
{ kind: 'healer' },
{ kind: 'crafting' },
{
kind: 'market',
itemPool: { ... },
costMultiplier: 1.7,
refreshMonths: 3
}
],
missions: [
{
realm: 'bodyForging',
rarity: 'qitouched',
quest: 'clothingBlankDelivery',
condition: '1'
}
],
gatheringEvent: {
steps: [
{
kind: 'text',
text: 'The village is busier than usual. Stalls have sprung up along the main road...'
}
],
resetMonths: { min: 3, max: 8 },
minCharacters: 3
}
};
Registering Locations
Add locations to your mod using the global mod API:
// Access the mod API via window.modAPI
window.modAPI.actions.addLocation(myCustomLocation);
The mod API is globally available through window.modAPI and provides access to all game data and actions for modifying the game.