View Format: Multi-Page Single Page

Simple Enemy Forge

Generate Complete Enemy Databases, Squads, Spawn Tables, and More in Minutes.

Spawn Forge

Spawn Forge creates spawn tables with weighted pools, conditional activation, and context-aware entry selection. It is the most complex of the seven forges, combining hierarchical data (Table → Pool → Entry) with a powerful condition system that reacts to game state at runtime.

Spawn tables reference enemies from your Enemy Database and optionally squads from your Squad Database. Each entry can be either a single enemy or an entire squad group.

Open the wizard via Window › Simple Enemy Forge › Spawn Table Forge Wizard.

The wizard has 5 steps: Setup, Definitions, Spawn Tables, Settings, Generate.

Understanding the Spawn Table Hierarchy

Spawn tables use a three-level hierarchy. Each level adds its own logic:

Spawn Table: "Forest Enemies" | +-- Pool: "Common" (2-4 rolls, 100% chance) | +-- Entry: Goblin Warrior (weight: 40) | +-- Entry: Forest Spider (weight: 30) | +-- Entry: Wolf Pack [squad] (weight: 30) | +-- Pool: "Elite" (1 roll, 20% chance) | +-- Entry: Orc Chieftain (weight: 60) | +-- Entry: Dark Treant (weight: 40) | +-- Pool: "Boss" (1 roll, 5% chance, condition: PlayerLevel >= 10) +-- Entry: Forest Dragon (weight: 100)

How a Roll Works

1 Evaluate pool conditions against the current SimpleSpawnContext. If conditions fail, skip the entire pool.
2 Check rollChance (0-100%). If the roll fails, skip the pool.
3 Determine roll count — random between rollCountMin and rollCountMax.
4 For each roll, filter entries by their conditions, apply weight modifiers to eligible entries, then perform weighted random selection.

The Condition System

Conditions check values from the current game context (passed via SimpleSpawnContext) to decide whether a pool activates or an entry is eligible. The same condition structure is used at both pool and entry level.

SimpleSpawnCondition Fields

Field Type Description
logic SimpleSpawnConditionLogic Chaining operator: None (first condition), And, Or, Not
sourceType SimpleSpawnConditionSourceType What to check: Category, Flag, or Numeric
sourceIndex int Index into the relevant context definition array
comparison SimpleSpawnConditionComparison Equals, NotEquals, GreaterThan, GreaterThanOrEqual, LessThan, LessThanOrEqual
value float Value to compare against (category index, flag 0/1, or numeric value)

Pool Conditions vs Entry Conditions

  • Pool conditions — Gate the entire pool. If the conditions fail, none of the entries in the pool are considered. Use these for broad context checks like "only activate in nighttime" or "only at difficulty 3+."
  • Entry conditions — Gate individual entries within an active pool. Use these for fine-grained control like "include Fire Dragon only when Biome is Volcano."

Condition Chaining

Multiple conditions are evaluated left-to-right. The first condition always has logic = None. Subsequent conditions use And, Or, or Not to combine with the running result:

// Example: Player Level >= 10 AND Biome == Forest Condition 1: logic=None, sourceType=Numeric, sourceIndex=0, comparison=GreaterThanOrEqual, value=10 Condition 2: logic=And, sourceType=Category, sourceIndex=0, comparison=Equals, value=2 // Example: Is Night OR Difficulty > 5 Condition 1: logic=None, sourceType=Flag, sourceIndex=0, comparison=Equals, value=1 Condition 2: logic=Or, sourceType=Numeric, sourceIndex=1, comparison=GreaterThan, value=5

Weight Modifier System

Weight modifiers dynamically adjust an entry's base weight based on context numeric values. This lets spawn probabilities shift with game state without needing separate condition logic.

Modifier Types

Type Formula Example
FlatPerPoint finalWeight = baseWeight + (numericValue * modifierValue) Base weight 40, modifier +2 per Player Level. At level 5: 40 + (5 * 2) = 50
PercentPerPoint finalWeight = baseWeight * (1 + numericValue * modifierValue / 100) Base weight 40, modifier +10% per Difficulty. At difficulty 3: 40 * (1 + 3 * 0.1) = 52

Weight modifiers stack. If an entry has multiple modifiers, they are applied sequentially. The final weight is clamped to a minimum of 0 (negative weights are not allowed).

Step 1 — Setup

Link Databases

Spawn Forge accepts two types of linked databases:

  • Enemy Databases (required) — Provides enemy codes for spawn entries. You can link multiple databases; first-DB-wins deduplication applies.
  • Squad Databases (optional) — Provides squad codes for entries that spawn entire groups. The squad database must itself link to an enemy database.

Output Configuration

Field Description Example
Database Name Display name for the generated asset My Spawn Tables
Type Prefix Prefix for generated C# types My
Namespace C# namespace for generated code MyGame.Data

Step 2 — Definitions

Definitions in Spawn Forge describe context properties — the game state values that conditions and weight modifiers reference. These are not stored on the spawn tables themselves; they define what the runtime context looks like.

Context Property Types

Type Definition Fields Usage Example
Context Categories Label, entries[] Conditions check: category == entry index Biome (Forest, Desert, Swamp), Time of Day (Dawn, Day, Dusk, Night)
Context Flags Name Conditions check: flag == true/false Is Night, Is Raining, Boss Defeated
Context Numerics Name Conditions + weight modifiers Player Level, Difficulty, Time Survived

Note that Spawn Forge definitions do not include Texts — text properties are not meaningful for runtime condition evaluation.

Schema Export/Import

The same four-button export/import system as other forges. Export Full JSON includes context definitions plus all spawn table data (pools, entries, conditions, weight modifiers). Import presents a 3-choice dialog for definitions and tables. See AI Workflow.

Step 3 — Spawn Tables

The main builder step uses a split-panel layout with nested ReorderableLists:

Left Panel — Table List

  • Search — Filter tables by name or code
  • Sort — Sort alphabetically by name or code
  • Multi-select — Checkbox selection for bulk delete
  • Pagination — Toggle between Show All and paginated view

Right Panel — Table Editor

Select a table from the list to edit:

Identity

Name, Code (with Auto toggle), and Description — same pattern as all forges.

Pools

Each table contains a ReorderableList of pools. Expand a pool's foldout to see:

Field Description
Name Display name (e.g., "Common Enemies", "Elite Reinforcements")
Roll Count Min/Max How many times to roll this pool (random between min and max)
Roll Chance Percentage chance (0-100) that this pool activates at all
Conditions ReorderableList of SimpleSpawnCondition entries. Each shows sourceType, sourceIndex (resolved to name), comparison, and value dropdowns.
Entries ReorderableList of spawn entries (see below)

Entries

Each entry within a pool has:

Field Description
Enemy/Squad Toggle Switch between single enemy code and squad code
Code Enemy code or squad code (with browse button)
Weight Base weight for random selection (higher = more likely)
Conditions Entry-level conditions (same structure as pool conditions)
Weight Modifiers ReorderableList of modifiers that adjust weight based on context numerics

Step 4 — Settings

Configure generation output settings — output folder path and any additional generation options. This step also shows a summary of what will be generated.

Step 5 — Generate

Same two-phase generation as all forges:

1 Phase 1 — Generate Scripts
Writes C# source files, triggers AssetDatabase.Refresh() and domain reload.
2 Phase 2 — Create Asset
[InitializeOnLoad] handler creates the ScriptableObject from temporary JSON data.

Generated Files

File Description
{Prefix}SpawnType.cs Enum with one entry per spawn table code
{Prefix}SpawnDatabase.cs ScriptableObject implementing ISimpleSpawnDataSource
Editor/{Prefix}SpawnDatabaseEditor.cs Custom Inspector with full editing UI
{Prefix}SpawnDatabase.asset The data asset

Runtime Helpers

Spawn Forge includes three runtime helper classes for evaluating and rolling spawn tables in your game code:

SimpleSpawnContext

A struct that holds current game state values, aligned with your context definitions:

// Create a context matching your spawn database's definitions var context = new SimpleSpawnContext( categoryCount: 2, // e.g., Biome, TimeOfDay flagCount: 1, // e.g., IsNight numericCount: 2 // e.g., PlayerLevel, Difficulty ); // Set current game state context.categoryValues[0] = 1; // Biome = Desert context.categoryValues[1] = 3; // TimeOfDay = Night context.flagValues[0] = true; // IsNight = true context.numericValues[0] = 15f; // PlayerLevel = 15 context.numericValues[1] = 3f; // Difficulty = 3

SimpleSpawnRoller

Rolls a spawn table against a context, returning an array of results:

// Get your spawn database ISimpleSpawnDataSource spawnDB = mySpawnDatabase as ISimpleSpawnDataSource; SimpleSpawnTable? table = spawnDB.GetSpawnTable("FOREST_SPAWNS"); if (table.HasValue) { // Roll the table with current game context SpawnRollResult[] results = SimpleSpawnRoller.Roll(table.Value, context); foreach (var result in results) { if (result.IsSquad) Debug.Log($"Spawn squad: {result.squadCode} (from pool: {result.sourcePoolName})"); else Debug.Log($"Spawn enemy: {result.enemyCode} (from pool: {result.sourcePoolName})"); } } // For deterministic results (e.g., seeded runs), pass a System.Random: var rng = new System.Random(42); SpawnRollResult[] seededResults = SimpleSpawnRoller.Roll(table.Value, context, rng);

SimpleSpawnEvaluator

Evaluates conditions without performing a roll — useful for checking whether a pool or entry would be active under a given context:

// Check if a specific condition set passes bool passes = SimpleSpawnEvaluator.EvaluateConditions(conditions, context);

Runtime Data Structures

SimpleSpawnCondition

public struct SimpleSpawnCondition { public SimpleSpawnConditionLogic logic; // None, And, Or, Not public SimpleSpawnConditionSourceType sourceType; // Category, Flag, Numeric public int sourceIndex; // Index into context array public SimpleSpawnConditionComparison comparison; // Equals, NotEquals, GT, GTE, LT, LTE public float value; // Value to compare against }

SimpleSpawnWeightModifier

public struct SimpleSpawnWeightModifier { public int numericIndex; // Which context numeric affects weight public SimpleSpawnWeightModifierType modifierType; // FlatPerPoint or PercentPerPoint public float value; // Value per point }

SimpleSpawnEntry

public struct SimpleSpawnEntry { public string squadCode; // Squad code (empty if single enemy) public string singleEnemyCode; // Enemy code (empty if squad) public float weight; // Base selection weight public SimpleSpawnCondition[] conditions; // Entry-level conditions public SimpleSpawnWeightModifier[] weightModifiers; // Dynamic weight adjustments public bool IsSquad => !string.IsNullOrEmpty(squadCode); }

SimpleSpawnPool

public struct SimpleSpawnPool { public string name; // Pool display name public int rollCountMin; // Minimum rolls public int rollCountMax; // Maximum rolls public float rollChance; // Activation chance (0-100) public SimpleSpawnCondition[] conditions; // Pool-level conditions public SimpleSpawnEntry[] entries; // Entries in this pool }

SimpleSpawnTable

public struct SimpleSpawnTable { public string code; // Unique identifier (e.g., "FOREST_SPAWNS") public string name; // Display name public string description; // Optional description public SimpleSpawnPool[] pools; // Pools in this table }

Interface Reference — ISimpleSpawnDataSource

Member Returns Description
SpawnTableCount int Total number of spawn tables
GetSpawnTables() SimpleSpawnTable[] Get all spawn tables
GetSpawnTable(string code) SimpleSpawnTable? Get a spawn table by code
GetSpawnTableCodes() string[] Get all spawn table codes
GetContextCategoryLabels() string[] Get context category labels (e.g., "Biome", "Time of Day")
GetContextCategoryEntries(int index) string[] Get entries for a context category
GetContextFlagNames() string[] Get context flag names
GetContextNumericNames() string[] Get context numeric names
GetTablesContainingEnemy(string enemyCode) SimpleSpawnTable[] Find all tables that can spawn a specific enemy
GetTablesContainingSquad(string squadCode) SimpleSpawnTable[] Find all tables that reference a specific squad

Tips

Layer Your Pools

Use multiple pools per table to create interesting spawn distributions. A "Common" pool with 100% chance and 2-4 rolls plus an "Elite" pool with 20% chance and 1 roll creates natural variety without complex logic.

Use Context Numerics for Scaling

Weight modifiers that reference Player Level or Difficulty let spawn probabilities shift naturally as the game progresses. Stronger enemies gradually become more common without needing separate tables per level range.

Combine Conditions and Weight Modifiers

Conditions are binary (pass/fail) while weight modifiers are gradual. Use conditions to set hard gates ("only after level 10") and modifiers for soft scaling ("more likely at higher levels").

AI-Generated Spawn Tables

Export your schema (including context definitions and enemy/squad codes) to an AI. Describe your game's biomes, difficulty curve, and spawn philosophy. The AI can generate dozens of spawn tables with properly configured pools, conditions, and weights. See AI Workflow.