The spawn module
Create and delete space objects, NPCs, grid objects, and client agents.
Overview
The spawn module wraps the engine's object-creation calls and registers each new object with the Agent system so it can be queried, linked, and targeted by the rest of the procedural API.
Every spawn function returns either an Agent object or a SpawnData handle you can pass to to_id / to_object. Use delete_object to remove objects when no longer needed — the engine and agent registry are both cleaned up.
Key helpers:
spawn_npc— the most common call; creates an enemy or friendly ship.spawn_player— creates a player ship for a client console.grid_spawn— creates an engineering-grid object on a ship.spawn_nebula/spawn_monster— terrain and special NPC variants.
Quick example
== spawn_enemies ==
e1 = spawn_npc("Hive Emperor", "tsc", 5000, 0, 3000, "Raider 01")
add_role(e1, "enemy")
brain_add(e1, patrol_label)
station = spawn_station("Generic Station", "tsn", 0, 0, 0, "Starbase Alpha")
from sbs_utils.procedural.spawn import spawn_npc, spawn_station, delete_object
enemy = spawn_npc("Hive Emperor", "tsc", 5000, 0, 3000, "Raider 01")
station = spawn_station("Generic Station", "tsn", 0, 0, 0, "Starbase Alpha")
# ... later ...
delete_object(enemy)
Spawn functions overview
| Function | Creates |
|---|---|
spawn_npc |
NPC ship (enemy, friendly, neutral) |
spawn_player |
Player-controlled ship |
spawn_station |
Station / base |
spawn_nebula |
Nebula terrain object |
spawn_monster |
Monster / special NPC |
spawn_generic |
Generic space object by art ID |
grid_spawn |
Engineering-grid object on a ship |
delete_object |
Removes any space object |
Creating player ships more than once
Every spawn_* call makes a new object, so setup that runs twice builds everything
twice. Player ships have a natural name — their slot — so they can be created safely:
| Function | Does |
|---|---|
player_ensure(slot, x, y, z, ship_key, name, side) |
The ship for that slot, creating one only if the slot is empty |
player_slot_id(slot) |
The live ship holding a slot, or None |
player_slots() |
Every filled slot, as {slot: id} |
players_reset() |
Delete all player ships, freeing every slot |
player_ensure compares against the live game, not a "have I run before" flag, which
is what keeps deliberate re-runs working: after players_reset() or a new simulation the
ships are gone and the next call rebuilds them, a destroyed ship can be remade, and a
late-joining crew's slot is filled without disturbing the others. An existing ship is
returned untouched — use a2x_place_player to move or rename one in place.
See Signal routes for when to
reach for this instead of a once route.
API
grid_spawn(id, name, tag, x, y, icon_index, color, roles)
Spawn a grid object (engineering component) onto a ship's grid.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
id
|
Agent | int
|
The ship agent ID or object to attach the grid object to. |
required |
name
|
str
|
Display name of the grid object. |
required |
tag
|
str
|
Tag identifying the grid object's side or type. |
required |
x
|
int
|
Column position on the engineering grid. |
required |
y
|
int
|
Row position on the engineering grid. |
required |
icon_index
|
int
|
Icon index for the grid display. |
required |
color
|
str
|
Display color string. |
required |
roles
|
str
|
Comma-separated roles to assign to the grid object. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
GridObject |
The newly created grid object. |
npc_spawn(x, y, z, name, side, ship_key, behave_id)
Spawn a non-player (NPC) ship into the simulation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
float
|
X spawn coordinate. |
required |
y
|
float
|
Y spawn coordinate. |
required |
z
|
float
|
Z spawn coordinate. |
required |
name
|
str
|
Display name, or |
required |
side
|
str
|
Side the ship belongs to. |
required |
ship_key
|
str
|
Ship template key from shipData. |
required |
behave_id
|
str
|
Behavior type identifier. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
SpawnData |
Spawn data for the new NPC. |
player_ensure(slot, x, y, z, ship_key, name=None, side='tsn')
Ensure a player ship occupies slot, spawning one only if it is empty.
Idempotent: returns the existing ship's ID if the slot is already filled, so an
initialization route that gets emitted more than once creates nothing extra.
Because the check is against the live world and not a did-I-run flag, a slot
emptied by sim_create(), a deletion or a destroyed ship is refilled on the
next call - which is what makes reset, respawn and late-joining crew work.
An existing ship is returned UNTOUCHED (not repositioned or renamed); use
a2x_place_player to converge one in place. This mirrors side_ensure /
side_create.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
slot
|
int
|
Player slot, stable across re-runs. |
required |
x
|
float
|
X spawn coordinate. |
required |
y
|
float
|
Y spawn coordinate. |
required |
z
|
float
|
Z spawn coordinate. |
required |
ship_key
|
str
|
Ship template key from shipData. |
required |
name
|
str
|
Display name. |
None
|
side
|
str
|
Side the ship belongs to. Comma tokens become roles. |
'tsn'
|
Returns:
| Type | Description |
|---|---|
|
int|None: The ship's ID, or None if the spawn failed. |
player_slot_id(slot)
The live player ship holding slot, or None.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
slot
|
int
|
The player slot. |
required |
Returns:
| Type | Description |
|---|---|
|
int|None: The ship's ID, or None if the slot is empty. |
player_slot_role(slot)
The role marking the ship that holds slot (e.g. player_slot_3).
A role, because role sets are the only O(1) keyed lookup available and they
self-clean when the object is deleted (Agent._remove purges the registries),
so a slot is freed by deleting its ship with no bookkeeping.
player_slots()
Every filled player slot as {slot: id}.
Returns:
| Name | Type | Description |
|---|---|---|
dict |
Slot number -> ship ID, for live player ships carrying a slot. |
player_spawn(x, y, z, name, side, ship_key)
Spawn a player ship into the simulation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
float
|
X spawn coordinate. |
required |
y
|
float
|
Y spawn coordinate. |
required |
z
|
float
|
Z spawn coordinate. |
required |
name
|
str
|
Display name, or |
required |
side
|
str
|
Side the ship belongs to. |
required |
ship_key
|
str
|
Ship template key from shipData. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
SpawnData |
Spawn data for the new player ship. |
players_reset()
Delete every player ship, freeing all slots.
The explicit path for an INTENTIONAL re-initialization (reset the scenario
without reloading the mission): wipe, then re-emit the create signal and let
player_ensure rebuild the roster. Slot roles are purged by the delete, so
nothing else needs clearing.
Returns:
| Name | Type | Description |
|---|---|---|
int |
How many ships were deleted. |
terrain_spawn(x, y, z, name, side, ship_key, behave_id)
Spawn a passive terrain object into the simulation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
float
|
X spawn coordinate. |
required |
y
|
float
|
Y spawn coordinate. |
required |
z
|
float
|
Z spawn coordinate. |
required |
name
|
str
|
Display name, or |
required |
side
|
str
|
Side the object belongs to, or |
required |
ship_key
|
str
|
Object template key from shipData. |
required |
behave_id
|
str
|
Behavior type identifier. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
SpawnData |
Spawn data for the new terrain object. |