Enemy Spawning System
This document describes the enemy spawning system implemented in openRoads, which automatically spawns enemies in rooms based on their defined wander ranges.
Overview
The enemy spawning system reads enemy definitions from world/enemies.json (read-only template) and spawns them in appropriate rooms based on their min-wander and max-wander parameters. The system respects enemy limits, timing constraints, provides automatic cleanup, and persists spawn tracking data separately from the template. The spawning runs as a persistent goroutine that automatically recovers from crashes.
How It Works
Enemy Definitions
Each enemy in world/enemies.json has a mechanics section with spawning parameters:
{
"rat": {
"mechanics": {
"min-wander": "750",
"max-wander": "756",
"max-instances": "2",
"ticks-to-make": "1"
}
}
}min-wander: Lowest room number where the enemy can spawn
max-wander: Highest room number where the enemy can spawn
max-instances: Maximum number of this enemy type that can exist simultaneously
ticks-to-make: Minimum time (in seconds) between spawns of this enemy type
Data Separation
The system maintains a clear separation between template data and runtime data:
world/enemies.json: Read-only template containing enemy definitionsworld/spawn_tracker.json: Persistent spawn tracking data (instances, timing)Room enemies: Stored in the world state (
formatted_rooms.json)
This ensures the enemy template remains unchanged while spawn data persists across server restarts.
Spawning Process
Room Range Calculation: The system calculates valid rooms from
min-wandertomax-wanderExistence Check: Only rooms that actually exist in the world are considered
Instance Limit: Checks if the current number of spawned enemies is below
max-instancesTiming Check: Ensures enough time has passed since the last spawn based on
ticks-to-makeProbability Check: Uses a configurable spawn probability (default 30%)
Room Selection: Randomly selects from valid, existing rooms
Duplicate Prevention: Won't spawn if the enemy already exists in the selected room
Persistence: Saves spawn tracking data after each spawn/removal
Configuration
The spawning system uses a SpawnConfig structure:
type SpawnConfig struct {
SpawnInterval time.Duration // How often to check for spawning (default: 30s)
MaxEnemyAge time.Duration // Max age before cleanup (default: 30m)
SpawnProbability float64 // Chance to spawn when possible (default: 0.3)
EnableCleanup bool // Enable automatic cleanup (default: true)
}Key Features
Automatic Spawning
Runs as a persistent goroutine in the game engine
Automatically recovers from crashes and restarts itself
Checks for spawning opportunities every 30 seconds (configurable)
Respects all enemy constraints and limits
Continues running until the server shuts down
Instance Tracking
Tracks all spawned enemy instances with timestamps
Prevents exceeding maximum instance limits
Maintains spawn timing constraints
Room Validation
Only spawns in rooms that actually exist in the world
Validates room numbers against the wander range
Prevents duplicate enemies in the same room
Automatic Cleanup
Removes old enemies after a configurable time period
Cleans up spawn tracking data
Maintains world state consistency
API Functions
Core Functions
LoadEnemyDefinitions()- Loads enemy data from JSONCanSpawnEnemy(name, definition)- Checks if enemy can spawnGetValidRoomsForEnemy(definition)- Gets valid room rangeSpawnEnemyInRoom(name, roomID, world)- Spawns enemy in specific roomRemoveEnemyFromRoom(name, roomID, world)- Removes enemy from room
Utility Functions
GetEnemyCount(name)- Current instances of specific enemyGetTotalEnemyCount()- Total spawned enemiesHasEnemyInRoom(name, roomID, world)- Check if enemy in roomCleanupDeadEnemies(world, maxAge)- Remove old enemies
Administrative Functions
ForceSpawnEnemy(name, roomID, loader, saver)- Force spawn for testingGetSpawnStatistics()- Current spawn statistics
Integration
The spawning system is automatically started when the game engine initializes:
// In routines/engine.go
spawnConfig := DefaultSpawnConfig()
StartEnemySpawning(loadWorld, saveWorld, spawnConfig)Example Usage
Checking Enemy Status
// Load definitions
enemies, _ := lib.LoadEnemyDefinitions()
ratDef := enemies["rat"]
// Check if rat can spawn
canSpawn := lib.CanSpawnEnemy("rat", ratDef)
// Get valid rooms for rat (750-756)
validRooms, _ := lib.GetValidRoomsForEnemy(ratDef)
// Check current rat count
ratCount := lib.GetEnemyCount("rat")Manual Spawning
// Force spawn a rat in room 750
err := lib.ForceSpawnEnemy("rat", "750", loadWorld, saveWorld)Logging
The spawning system provides detailed logging with the SPAWN prefix:
INFO: System startup and successful spawnsDEBUG: Spawn cycle statistics and detailsWARNING: Failed spawns and invalid configurationsERROR: Critical failures like world loading issues
Performance Considerations
Spawning checks run every 30 seconds by default
Only processes enemies that can potentially spawn
Efficient room validation and duplicate prevention
Automatic cleanup prevents memory leaks
World saves only occur when spawns are successful
Troubleshooting
No Enemies Spawning
Check that enemy definitions loaded correctly
Verify rooms exist in the wander range
Ensure max-instances limit not reached
Check ticks-to-make timing constraints
Verify spawn probability settings
Too Many Enemies
Adjust spawn probability downward
Reduce max-instances for specific enemies
Increase ticks-to-make timing
Enable cleanup with shorter max age
Performance Issues
Increase spawn interval
Reduce number of enemy types
Limit wander ranges to existing rooms
Enable cleanup to remove old enemies
Last updated
Was this helpful?