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 definitions

  • world/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

  1. Room Range Calculation: The system calculates valid rooms from min-wander to max-wander

  2. Existence Check: Only rooms that actually exist in the world are considered

  3. Instance Limit: Checks if the current number of spawned enemies is below max-instances

  4. Timing Check: Ensures enough time has passed since the last spawn based on ticks-to-make

  5. Probability Check: Uses a configurable spawn probability (default 30%)

  6. Room Selection: Randomly selects from valid, existing rooms

  7. Duplicate Prevention: Won't spawn if the enemy already exists in the selected room

  8. 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 JSON

  • CanSpawnEnemy(name, definition) - Checks if enemy can spawn

  • GetValidRoomsForEnemy(definition) - Gets valid room range

  • SpawnEnemyInRoom(name, roomID, world) - Spawns enemy in specific room

  • RemoveEnemyFromRoom(name, roomID, world) - Removes enemy from room

Utility Functions

  • GetEnemyCount(name) - Current instances of specific enemy

  • GetTotalEnemyCount() - Total spawned enemies

  • HasEnemyInRoom(name, roomID, world) - Check if enemy in room

  • CleanupDeadEnemies(world, maxAge) - Remove old enemies

Administrative Functions

  • ForceSpawnEnemy(name, roomID, loader, saver) - Force spawn for testing

  • GetSpawnStatistics() - 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 spawns

  • DEBUG: Spawn cycle statistics and details

  • WARNING: Failed spawns and invalid configurations

  • ERROR: 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

  1. Check that enemy definitions loaded correctly

  2. Verify rooms exist in the wander range

  3. Ensure max-instances limit not reached

  4. Check ticks-to-make timing constraints

  5. Verify spawn probability settings

Too Many Enemies

  1. Adjust spawn probability downward

  2. Reduce max-instances for specific enemies

  3. Increase ticks-to-make timing

  4. Enable cleanup with shorter max age

Performance Issues

  1. Increase spawn interval

  2. Reduce number of enemy types

  3. Limit wander ranges to existing rooms

  4. Enable cleanup to remove old enemies

Last updated

Was this helpful?