Skip to content

Grid object system

Query, move, and theme engineering-grid objects on player ships.

Overview

Engineering-grid objects are the nodes visible on the damage-control console: system rooms (weapon, engine, sensor, shield), hallways, damcon-team crew, markers, and tools. Each is an Agent with a host ship ID and a position in a 2D grid coordinate space.

Common tasks:

  • grid_objects(ship_id) — get the set of all grid-object IDs on a ship. Combine with role() to filter by type: grid_objects(ship_id) & role("engine").
  • grid_objects_at(ship_id, x, y) — get objects at a specific cell.
  • grid_closest(id, candidates) — find the nearest grid object to another.
  • grid_move(id, x, y) — path the grid object to a target cell.
  • grid_pos_data(id) — get current (x, y, path_length) of a moving object.

The theme system controls icon appearance. grid_get_grid_theme and grid_get_item_theme_data look up icon indices, colors, and damage colors by role, falling back to "default" entries.

Quick example

== repair_run ==
    damaged = grid_objects(ship_id) & role("__damaged__")
    if len(damaged) == 0: jump done
    target_go = to_object(next(iter(damaged)))
    x, y, _ = grid_pos_data(target_go.id)
    grid_move(damcon_id, int(x), int(y))
from sbs_utils.procedural.grid import (
    grid_objects, grid_objects_at, grid_closest,
    grid_move, grid_pos_data, grid_get_grid_theme,
)
from sbs_utils.procedural.roles import role

damaged_engines = grid_objects(ship_id) & role("__damaged__") & role("engine")
grid_move(damcon_id, target_x, target_y)
curx, cury, path_len = grid_pos_data(damcon_id)

Grid roles

Role Objects
"weapon" Weapon system nodes
"engine" Engine system nodes
"sensor" Sensor system nodes
"shield" Shield system nodes
"damcons" / "lifeform" Damcon crew members
"marker" Position marker
"rally_point" Damcon idle point
"hallway" Damage-fire hallway markers
"__undamaged__" / "__damaged__" Damage state

API

get_open_grid_points(id_or_obj)

Gets a list of open grid locations

Parameters:

Name Type Description Default
id_or_obj agent

agent id or object to check

required

Returns:

Name Type Description
set set[Vec3]

a set of Vec3 with x and y set

grid_clear_detailed_status(id_or_obj)

Clear the detailed status (info text) of a grid object.

Parameters:

Name Type Description Default
id_or_obj Agent | int

Agent ID or object.

required

grid_clear_speech_bubble(id_or_obj)

Clear the speech bubble for a grid object

Parameters:

Name Type Description Default
id_or_obj Agent | int

agent id or object of the grid object

required

grid_clear_target(grid_obj_or_set)

Clear the movement target of a grid object, stopping it in place.

Parameters:

Name Type Description Default
grid_obj_or_set Agent | int | set

Agent, ID, or set of grid object(s) to stop.

required

grid_close_list(grid_obj, the_set, max_dist=None, filter_func=None)

Find and target the closest object matching the criteria

Parameters:

Name Type Description Default
grid_obj Agent | int

The agent or id

required
the_set set[Agent]

The items to test. Defaults to None.

required
max_dist float

max distance. Defaults to None.

None
filter_func Callable

additional filer function. Defaults to None.

None

Returns:

Type Description
list[CloseData]

list[CloseData]: The gird close data of the closest objects

grid_closest(grid_obj, target_set=None, max_dist=None, filter_func=None)

Find and target the closest object matching the criteria

Parameters:

Name Type Description Default
grid_obj Agent | int

The agent or id

required
target_set set[Agent]

The items to test. Defaults to None.

None
max_dist float

max distance. Defaults to None.

None
filter_func Callable

additional filer function. Defaults to None.

None

Returns:

Name Type Description
CloseData CloseData

The gird close data of the closest object

grid_data_is_loaded()

Reset-ledger probe: 1 while grid data (possibly mod-merged) is held, else 0.

grid_delete_object(host_id_or_obj, id_or_obj)

Delete a single grid object, deferring the native free.

Tombstones the grid agent now (dropped from Agent.all/roles, so object_exists()/to_object() report it gone this instant) and enqueues the native sbs.delete_grid_object(host_id, id) to run at the end of the event handler. Mirrors SpaceObject.delete_object for grid objects, closing the same-tick use-after-free window. See DeleteQueue.

Parameters:

Name Type Description Default
host_id_or_obj Agent | int

The host ship the grid object lives on.

required
id_or_obj Agent | int

The grid object (or its id) to delete.

required

grid_delete_objects(ship_id_or_obj)

Delete all grid objects belonging to a ship.

Parameters:

Name Type Description Default
ship_id_or_obj Agent | int

Agent or ID of the ship whose grid objects should be removed.

required

grid_detailed_status(id_or_obj, status, color=None)

Set the detailed status (info text) of a grid object.

Parameters:

Name Type Description Default
id_or_obj Agent | int

Agent ID or object.

required
status str

Status string to display.

required
color str

Text color. None keeps the current value. Defaults to None.

None

grid_get_damcons(ship_key, layout=None)

The damcon-team declaration for a hull (or one of its layouts), or None.

None - which is what every hull that says nothing returns, and that is nearly all of them - means "three teams, wherever the engine puts them", exactly as before. That sentinel is what keeps the shipped floor plans and every third-party hull working unchanged.

Otherwise {"count": int, "posts": [[x, y], ...]}: how many damage-control teams this interior has, and where they are stationed. Fewer posts than teams is fine - the rest are engine-placed. A post is also the team's permanent rally point, because the prefab spawns the rally marker on the cell it is given, so posting a team by the nacelles is all it takes to keep it there.

Read as a sibling of grid_objects/theme, at the entry level or inside a named layout, most specific winning - the same shape :func:grid_get_theme_name uses. A layout expressed as a bare list has nowhere to hold one and falls back to the entry.

Parameters:

Name Type Description Default
ship_key str

Ship key as defined in shipData.

required
layout str

Layout name. Defaults to "default".

None

Returns:

Type Description

dict | None: Normalized declaration, or None when the hull declares nothing.

grid_get_grid_current_theme()

Get the currently active grid theme data.

Returns:

Name Type Description
dict

Theme dict with keys such as name, colors, icons, damage_colors, etc.

grid_get_grid_data()

Get the grid data from all the grid_data.json files

Returns:

Name Type Description
dict dict

a dictionary of grid data objects.

dict
  • key (str): The key of the dict, which is a ship key as defined in shipData.
dict
  • value (dict): A dict with grid_objects as a key, and a list of grid object data as the value.

grid_get_grid_named_theme(name)

Get a grid theme by name, falling back to the current theme if not found.

Parameters:

Name Type Description Default
name str | None

Theme name to look up (case-insensitive), or None to return the current theme.

required

Returns:

Name Type Description
dict

Theme dict with keys such as name, colors, icons, damage_colors, etc.

grid_get_grid_theme()

Get the grid data from all the grid_data.json files

Returns:

Name Type Description
dict

a dictionary of grid theme data

  • key (str): The ship key associated with the grid theme
  • value (dict): The grid theme data

grid_get_item_theme_data(roles, name=None)

Get icon, scale, color, and damage color for a set of roles from the grid theme.

Roles are matched in reverse priority order so the last role in the list takes precedence. Falls back to "default" entries when no role matches.

Parameters:

Name Type Description Default
roles str

Comma-separated role names.

required
name str | None

Theme name to use. None uses the current theme. Defaults to None.

None

Returns:

Name Type Description
RetVal

Object with .icon (int), .scale (float), .color (str), and .damage_color (str) attributes.

grid_get_layout(ship_key, layout=None)

The grid-object list for one hull's layout.

A hull has N named LAYOUTS, not one interior - a full authored interior, a cheap systems-only one, a jump-drive refit of the same hull. grid_objects at the top level is still read as the default, so every existing entry keeps working::

{"tsn_light_cruiser": {"grid_objects": [...]}}                    # still valid
{"pirate_brigantine": {"layouts": {"default": {...},
                                   "systems": {...}}}}

A layout may be either {"grid_objects": [...]} or a bare list.

Parameters:

Name Type Description Default
ship_key str

Ship key as defined in shipData.

required
layout str

Layout name. Defaults to "default", then to the top-level grid_objects.

None

Returns:

Type Description

list | None: The grid object dicts, or None when there is no such interior.

grid_get_mod(ship_key)

The mod that supplied a hull's interior, or None for built-in data.

grid_get_theme_name(ship_key, layout=None)

The theme a hull (or one of its layouts) asks for, or None for the current one.

Theme selection used to be a single module-level index - a whole-game setting - which made per-race themes impossible. A hull, or a single layout of it, can now name its own: a captured TSN hull refitted by pirates is the same mesh with a different interior AND a different vocabulary.

grid_merge_ascii(content, mod=None, ship_key=None)

Merge one ASCII floor plan (see :mod:grid_ascii) into the grid data.

The one-line form an addon's __init__.mast uses::

grid_merge_ascii(media_read_relative_file("tsn_light_cruiser.grid"), "interiors_tsn")

A plan naming a layout: other than default is merged INTO the hull's existing entry as a named layout rather than replacing it, so a hull's variants can arrive from separate files - and, later, from separate mods.

Returns the entry that was merged, or None if the text could not be read (which is logged, not raised: one unreadable floor plan should not take a mission down).

grid_merge_mod_data(content, mod=None)

Merge grid data supplied as a JSON/YAML string into the grid data cache.

The counterpart of :func:sbs_utils.procedural.ship_data.merge_mod_ship_yaml, and the one change that lets an ADDON ship ship interiors. grid_get_grid_data reads only two places - the engine's grid_data.json and the mission directory's extra_grid_data.json - so an addon inside a .mastlib could not contribute at all. Pair it with media_read_relative_file, which reads from the addon's zip when it is packaged and from its folder in dev::

grid_merge_mod_data(media_read_relative_file("extra_grid_data.json"), "PirateMod")

Unlike ship data, this needs no build step: grid objects are not engine content - grid_rebuild_grid_objects creates every one at runtime through grid_spawn - so the engine never has to pre-know an interior. See SHIP_MOD_PLAN.md s3.

Merging is whole-entry replace, matching the |= the mission file has always used: a mod supplies a hull's whole interior and cannot add a room to someone else's. Layout variants are how one hull legitimately has more than one interior.

Two mods claiming the same hull is reported by name. It is a warning rather than an error because failing here would take down a mission at load over a cosmetic clash, but silent last-writer-wins is how interiors start feeling haunted.

Parameters:

Name Type Description Default
content str

JSON or YAML text (YAML is a JSON superset, so both parse).

required
mod str

Name of the mod these entries come from; stamped on each entry as #mod and used to name collisions.

None

Returns:

Type Description

dict | None: The updated grid data, or None if content was empty or unparseable.

grid_merge_mod_theme(content)

Append themes supplied as a JSON/YAML string, so an addon can ship its own.

Companion to :func:grid_merge_mod_data; same reason it exists - the built-in reader only looks in the engine data dir and the mission dir, so a .mastlib addon had no way in. A race mod's room VOCABULARY lives here: new room names need theme icon entries or they fall back to the generic icon 120.

A theme with a name that already exists REPLACES it, so a mod can re-skin a built-in theme rather than only adding beside it.

Parameters:

Name Type Description Default
content str

JSON or YAML text - one theme dict, or a list of them.

required

Returns:

Type Description

list | None: The updated theme list, or None if nothing parsed.

grid_object_valid(id_or_obj)

Return whether a grid object still has a valid backing space object.

Returns False once the host ship is destroyed, even though the grid object's Agent may still resolve. See :func:grid_valid_blob.

Parameters:

Name Type Description Default
id_or_obj Agent | int

Agent id or object.

required

Returns:

Name Type Description
bool bool

True if the grid object's blob can be safely accessed.

grid_objects(so_id)

Get a set of agent ids of the grid objects on the specified ship

Parameters:

Name Type Description Default
so_id Agent | int

agent id or object

required

Returns:

Type Description
set[int]

set[int]: a set of agent ids

grid_objects_at(so_id, x, y)

Get a set of agent ids of the grid objects on the specified ship, at the location specified

Parameters:

Name Type Description Default
so_id Agent | int

agent id or object

required
x int

The x grid location

required
y int

The y grid location

required

Returns:

Type Description
set[int]

set[int]: A set of agent ids

grid_pos_data(id)

Return the current position and path length of a grid object.

Parameters:

Name Type Description Default
id Agent | int

Agent ID or object.

required

Returns:

Type Description

tuple[float, float, float]: (curx, cury, path_length).

grid_remove_move_role(event)

Remove the _moving_ role when a grid object finishes its path.

Parameters:

Name Type Description Default
event

Engine event; only acts when event.sub_tag == "finished_path".

required

grid_reset_caches()

Drop the loaded grid data and themes at a mission boundary.

_grid_data merges the mission's extra_grid_data.json (and, once mods can contribute, every enabled mod's interiors) into the base table, and _grid_theme does the same for themes - so both are PER-MISSION state wearing the clothes of a module-level cache. Left alone, the next mission inherits the previous one's interiors and its theme index.

The engine forks a fresh process per mission and hides this; cosmos_dev reuses one interpreter and does not. Registered in the reset ledger.

grid_set_grid_current_theme(i)

Set the active grid theme by index.

Parameters:

Name Type Description Default
i int

Index into the loaded grid theme list.

required

grid_set_grid_named_theme(name)

Set the active grid theme by name.

Parameters:

Name Type Description Default
name str

Theme name (case-insensitive), e.g. "cosmos" or "Retro".

required

grid_short_status(id_or_obj, status, color=None, seconds=0, minutes=0)

Set the tooltip and speech bubble text of a grid object.

Parameters:

Name Type Description Default
id_or_obj Agent | int

Agent ID or object.

required
status str

Status string for both the tooltip and speech bubble.

required
color str

Text color. None keeps the current value. Defaults to None.

None
seconds int

Duration for the speech bubble. Defaults to 0 (permanent).

0
minutes int

Additional minutes for the bubble duration. Defaults to 0.

0

grid_speech_bubble(id_or_obj, status, color=None, seconds=0, minutes=0)

Sets the speech bubble text of a grid object. The text will disappear if the seconds/minutes are set

Parameters:

Name Type Description Default
id_or_obj Agent | int

Agent id or object

required
status str

The detailed status string

required
color str

change the color of the detailed status text. None does not change the current value

None
seconds int

The seconds for the speech bubble

0
minutes

(int): The minutes for the speech bubble

0

grid_target(grid_obj_or_set, target_id, speed=0.01)

Set a grid object to target the location of another grid object

Parameters:

Name Type Description Default
grid_obj_or_set Agent | int | set[Agent | int]

an id, object or set of agent(s)

required
target_id Agent

an agent id or object

required
speed float

the speed to move. Defaults to 0.01.

0.01

grid_target_closest(grid_obj_or_set, target_set=None, max_dist=None, filter_func=None)

Find and target the closest object matching the criteria

Parameters:

Name Type Description Default
grid_obj_or_set Agent | int | set[Agent | int]

The agent or set

required
target_set set[Agent]

The items to test. Defaults to None.

None
max_dist float

max distance. Defaults to None.

None
filter_func Callable

additional filer function. Defaults to None.

None

Returns:

Name Type Description
GridCloseData CloseData

The gird close data of the closest object

grid_target_pos(grid_obj_or_set, x, y, speed=0.01)

Set a grid object to move toward a specific grid coordinate.

Parameters:

Name Type Description Default
grid_obj_or_set Agent | int | set

Agent, ID, or set of grid object(s) to move.

required
x float

Target x grid coordinate.

required
y float

Target y grid coordinate.

required
speed float

Movement speed. Defaults to 0.01.

0.01

grid_theme_current_index()

Reset-ledger probe: the selected theme index, which must be back to 0 (default).

Not a container - a setting. A mission that selected theme 1 would silently hand it to the next mission, which is a whole game re-skinned for no reason anyone could see.

grid_theme_is_loaded()

Reset-ledger probe: 1 while theme data is held, else 0.

grid_valid_blob(id_or_obj)

Return a grid object's engine blob only if its backing space object is still valid, otherwise None.

A destroyed host ship leaves the grid object's Agent and its cached blob wrapper in place, so to_blob still returns a non-None wrapper -- but the engine raises ValueError: invalid space object on any get/set of that wrapper. This probes cheaply so callers can guard the dead-object case with a plain is None check, the same as a missing object.

Parameters:

Name Type Description Default
id_or_obj Agent | int

Agent id or object.

required

Returns:

Type Description

data_set | None: The live blob, or None if the object is gone or its host space object has been destroyed.