Mount
Weld an object into another object's body frame and let the engine hold it there - a weapon turret on a hull, a sensor pod, a parasite craft. Pair with turret and you have an autonomous weapon mount: turret decides what to shoot, mount decides where it rides.
Engine-measured (1.3.5): sim.AddTractorConnection(host, mount, vec3(0,0,200), 0) held a
mount at exactly 200.0u and exactly 0.0 deg off the host's nose while the host's heading
swung 51 deg - the separation vector rotated with the hull. So the engine does the work
every frame: no per-tick reposition, no tick task, and no frame lag.
Do not infer this from grav_tether's docs
grav_tether describes the offset point as world-fixed, which is true only of the case it uses - it never passes an offset, so its load reels to the source's own position. The two modules want opposite things: grav_tether drags a load behind a ship, mount bolts one onto it.
Lifecycle
+z local is forward, +x right, +y up. A mount spawns at the host's position and the
weld pulls it into place.
- A host killed in combat takes its mounts with it, honoring each mount's
delete_with_host- passFalsefor a blown-off turret that survives as salvage. - A host removed by a script fires no destroy event, so
mount_host_of()readsNonefor a vanished host andmount_prune_orphans()cleans up that path. - There is no module-level registry: the engine owns the connection, the host/mount relationship is an Agent link, and per-mount settings live in the mount's inventory - so nothing here can outlive its objects, and nothing needs a reset-ledger entry.
API
Mounts: weld an object into another object's BODY frame, and let the engine hold it.
A mount is any space object rigidly attached to a host at a fixed offset in the host's own
frame - a weapon turret on a hull, a sensor pod, a parasite craft. Pair it with
:mod:sbs_utils.procedural.turret and you have an autonomous weapon mount: the turret
half decides what to shoot, this half decides where it rides. Neither knows about the
other, which is why a tower, a station bolt-on and a ship mount are all the same code.
ENGINE-MEASURED (1.3.5, LM_TestRange/maps/test_tractor_mount.mast): the raw tractor
API holds the target in the source's BODY frame::
sim.AddTractorConnection(host, mount, sbs.vec3(0, 0, 200), 0)
held a mount at exactly 200.0u and exactly 0.0 deg off the host's nose while the host's heading swung 51 deg - the separation vector rotated with the hull, (0,0,200) -> (155.5, 0, 125.8). So the ENGINE does the work every frame: no per-tick reposition, no tick task, and none of the one-frame lag a script-side transform suffers.
Do not infer this from grav_tether's prose. It called the offset point "world-fixed",
which was only ever true of the case that module uses - a tow passes no offset, so its
load reels to the host's own position. (grav_tether_attach's own parameter doc said
"point (relative to source)" all along and was right; the surrounding prose was not.)
Why this does not just wrap grav_tether_lock. It could: that function passes an
offset straight through with stiffness 0, which is the same weld. But grav_tether runs
_enforce_impulse over every live tether, capping the SOURCE ship back to impulse - so
a ship carrying bolted turrets could never warp. A mount is part of the ship; a tether is
a thing the ship is dragging. Same engine call, opposite intent, and they must not share
a registry: a global ClearTractorConnections silently unwelded every mount until
grav_tether_clear_all was made to delete only its own connections.
No module-level state, deliberately. The engine owns the connection; the host->mount
relationship is an Agent LINK and the per-mount settings live in the mount's own
inventory. Agent._remove purges both on delete, so nothing here can outlive its
objects and nothing needs a register_reset_state entry.
Every module-level function is prefixed, private ones included: MAST imports a module's
functions into one flat, mission-wide namespace with no underscore filtering, so a helper
named _key would turn any script's _key = ... into a compile error that empties the
whole story.
mount_attach(host, mount, offset=None, delete_with_host=True)
Weld an existing object into the host's body frame.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
host
|
Agent | int
|
The object to ride on. |
required |
mount
|
Agent | int
|
The object to attach. |
required |
offset
|
Vec3 | tuple
|
Position in the HOST's own frame -
|
None
|
delete_with_host
|
bool
|
Delete this mount when the host is destroyed (default). Pass False to leave it floating as debris - a blown-off turret that can be salvaged. |
True
|
Returns:
| Type | Description |
|---|---|
|
int | None: The mount's id, or None if either object is missing or the engine refused the connection. |
mount_clear_all()
Release every mount without deleting anything.
There is no module-level registry to clear - the relationships live on the agents themselves and are purged with them - so this is for tests, for a mid-mission clean slate, and for reset_mission_state to drop the ENGINE-side welds deliberately.
Tolerates having no frame context: a reset can fire with none, and dropping our own state must never depend on the engine being there.
mount_count()
How many welded mounts exist. Cheap probe for tests and diagnostics.
mount_detach(host, mount, delete=False)
Release a mount. Optionally delete it.
Deletion goes through the procedural delete_object (deferred) rather than the
engine call, which frees the C++ object synchronously and would leave anything still
holding it pointing at freed memory.
mount_detach_all(host, delete=None)
Release every mount on a host.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
delete
|
bool
|
Force-delete (True) or force-keep (False) every mount.
Defaults to None, meaning honor each mount's own |
None
|
Returns:
| Type | Description |
|---|---|
|
list[int]: The mounts released. |
mount_host_of(mount)
The host a mount rides on, or None.
A host that no longer exists reads as None rather than a dangling id. The destroy dispatch cleans up ships killed in COMBAT, but a script can also just delete a ship outright, and that path fires no destroy event - so "my host is gone" has to be answerable from the link alone.
mount_is(obj)
Whether an object is currently mounted on something.
mount_list(host)
Every mount currently welded to a host, as a list of ids.
mount_offset(host, mount)
The body-frame offset a mount was welded at, as a Vec3.
mount_prune_orphans(delete=None)
Release mounts whose host is gone, honoring each one's delete_with_host.
The destroy dispatch covers a host killed in combat. This covers the other way a host vanishes - a script deleting it - which fires no destroy event and would otherwise leave armed objects welded to nothing.
Returns:
| Type | Description |
|---|---|
|
list[int]: The orphans dealt with. |
mount_ring(host, ship_key, count, radius=None, y=0.0, **kwargs)
Spawn count mounts evenly spaced on a ring in the host's body XZ plane.
The common case for bolting turrets onto a hull or a station. Because the offsets are body-frame, a station host and a maneuvering ship host behave identically.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
radius
|
float
|
Ring radius. Defaults to a little outside the host's exclusion radius so the mounts sit clear of the hull. |
None
|
Returns:
| Type | Description |
|---|---|
|
list[int]: The ids created (may be shorter than |
mount_set_offset(host, mount, offset)
Move a mount to a new body-frame offset.
The engine's connection carries its offset point from creation, so this deletes and re-adds it - cheap, and the only way to change where a mount rides.
mount_spawn(host, ship_key, offset=None, name='', side=None, behave_id='behav_station', delete_with_host=True)
Spawn a new object already welded to the host.
Spawns at the host's position and lets the weld pull it into place, so the caller never has to compute a world position - that is the engine's job now.
behav_station is the default because a mount must not steer: a behav_npcship
would fight the tractor with its own helm.
Returns:
| Type | Description |
|---|---|
|
int | None: The new mount's id, or None. |