Storage module
A Storage module is the station component that provides cargo capacity. A station’s total cargo space is the sum of its storage modules’ capacities — but each module is transport-typed: a Solid storage holds ore but not energy cells; a Liquid storage holds methane but not silicon.
Inheritance: component → destructible → module → storagemodule. The datatype itself is tiny — just cargo and waretransport. The interesting modder logic lives on the parent Station or Container, which aggregates all storage modules.
Sibling module subtypes: Production module, Build module, Connection module, Defence module, Habitation module, Welfare module, Pier, Processing module, Venture platform.
Properties
Section titled “Properties”storagemodule
Section titled “storagemodule”| Property | Type | Description |
|---|---|---|
.cargo | modulecargolist | Wares stored in this module |
.waretransport | list | Transport types this module supports (single-element list in vanilla) |
modulecargolist (the cargo accessor)
Section titled “modulecargolist (the cargo accessor)”| Property | Type | Description |
|---|---|---|
.free | int | Free cargo volume remaining |
.capacity | int | Total cargo volume |
.{ware} | int | Amount of {ware} currently stored (inherited from containercargolist) |
.list | warelist | Ware types currently stored |
Inherited from module
Section titled “Inherited from module”| Property | Type | Description |
|---|---|---|
.numdocks.{docksize} | int | Connected dockingbays (rare on storage; mostly zero) |
.haswalkableroom | bool | NPC-accessible interior |
Inherited from destructible
Section titled “Inherited from destructible”| Property | Type | Description |
|---|---|---|
.hull / .hullpercentage | hp / float | Damage state |
Transport types
Section titled “Transport types”waretransport is an enum (scriptproperties.xml:2355). A storage module supports exactly one type; a station typically has multiple modules of different types to cover all its needs.
| Type | Common wares | Notes |
|---|---|---|
waretransport.container | Most manufactured wares (Hull Parts, Microchips, Med Supplies) | The most common type |
waretransport.solid | Ore, Silicon, Ice, Nividium | Mining outputs |
waretransport.liquid | Methane, Hydrogen, Helium | Gas mining outputs |
waretransport.condensate | Specific Ventures wares | Rare type |
waretransport.passenger | Passengers | Not a “ware” per se — passenger transport ships |
The .tag property of each waretransport value (e.g. waretransport.container.tag = tag.container) is the bridge for compatibility checks at the find_* and trade-offer level.
Actions
Section titled “Actions”Storage module has no actions of its own. All meaningful operations are on the station / container level, since cargo is logically a station property.
Read free space across a station (by type)
Section titled “Read free space across a station (by type)”There is no Station.cargo.solid.free shortcut. Iterate the modules:
<set_value name="$SolidFree" exact="0"/>
<do_for_each name="$module" in="$Station.modules"> <do_if value="$module.isclass.{class.storage} and $module.waretransport.indexof.{waretransport.solid} gt 0"> <set_value name="$SolidFree" operation="add" exact="$module.cargo.free"/> </do_if></do_for_each>Pattern: vanilla tutorial_mining.xml:160 uses the same waretransport.indexof predicate.
Find storage modules that match a ware’s transport type
Section titled “Find storage modules that match a ware’s transport type”<do_for_each name="$module" in="$Station.modules"> <do_if value="$module.isclass.{class.storage} and $module.waretransport.indexof.{$ware.waretransport} gt 0"> <!-- this module can hold $ware --> </do_if></do_for_each>Add cargo at the container level (not at the module)
Section titled “Add cargo at the container level (not at the module)”<add_cargo object="$Station" ware="ware.energycells" exact="200"/>add_cargo routes wares automatically to a compatible storage module. You cannot add_cargo object="$Module" — the module is a detail, not the cargo holder.
Force a particular storage module to keep / dump wares
Section titled “Force a particular storage module to keep / dump wares”There is no direct API. To reserve capacity, set ware targets at the station-cargo level:
<set_cargo_target object="$Station" ware="ware.energycells" exact="50000"/>The engine then distributes ware allocation across compatible storage modules.
Libraries
Section titled “Libraries”There are no dedicated LIB_Generic.Storage* helpers. Storage queries are inline. The closest related helpers:
| Library | Purpose | Source line |
|---|---|---|
md.LIB_Generic.FindShipMacroForCargo | Pick a ship macro that can carry given cargo (matches by transport type) | 1427 |
md.LIB_Generic.Add_Wares_For_Module | When new production modules are added, add their wares to the station ware list | 5089 |
Events
Section titled “Events”There is no event_storage_X family. Cargo changes are observed through:
| Indirect signal | Where |
|---|---|
event_trade_completed | A trade landed at the station — cargo content changed |
event_object_destroyed | If event.object is a storage module, station capacity dropped |
event_object_attacked | Storage module under attack (precedes possible destruction) |
Polling $Module.cargo.free | Capacity tracking for triggered alerts |
Common gotchas
Section titled “Common gotchas”- ⚠
$Module.waretransportis a LIST, not a single value. Even though most storage modules support one type, the accessor returns a list. Use.indexof.{waretransport.X} gt 0for membership. - ⚠ There is no
$Station.cargo.{type}.freeshortcut. Free-space-by-type requires iterating modules. Don’t assume a station’s container-level cargo can answer “how much liquid space do I have left”. - ⚠
add_cargo object="$Module"is invalid. The module is just a capacity provider; cargo lives on the container. Alwaysadd_cargo object="$Station". - ⚠ A station with zero matching storage modules cannot hold a ware EVEN if Station.cargo.capacity is huge. A pure-container station rejects ore. Always check the storage-module compatibility before assuming
Station.cargo.freeis usable for a specific ware. - ⚠ Storage modules can be destroyed. A station that lost its only solid-storage module silently becomes unable to accept ore. Listen for
event_object_destroyedand recheckStation.canstore.{$ware}(container-level). - ⚠
.waretransport.indexofreturns the 1-based index, NOT a boolean. A return of1means “first element”. Treat>= 1(gt 0) as truthy; treat0as “not present”. - ⚠ Modded transport types must be added to
libraries/waretransports.xml. A customwaretransport.exoticdeclared in a ware but not in the transport library will fail compatibility checks silently.
Examples
Section titled “Examples”Example 1: Audit player stations’ free capacity by transport type
Section titled “Example 1: Audit player stations’ free capacity by transport type”<find_station_by_true_owner name="$Stations" space="player.galaxy" faction="faction.player" multiple="true"/>
<set_value name="$TotalContainerFree" exact="0"/><set_value name="$TotalSolidFree" exact="0"/><set_value name="$TotalLiquidFree" exact="0"/>
<do_for_each name="$station" in="$Stations"> <do_for_each name="$module" in="$station.modules"> <do_if value="$module.isclass.{class.storage}"> <do_if value="$module.waretransport.indexof.{waretransport.container} gt 0"> <set_value name="$TotalContainerFree" operation="add" exact="$module.cargo.free"/> </do_if> <do_if value="$module.waretransport.indexof.{waretransport.solid} gt 0"> <set_value name="$TotalSolidFree" operation="add" exact="$module.cargo.free"/> </do_if> <do_if value="$module.waretransport.indexof.{waretransport.liquid} gt 0"> <set_value name="$TotalLiquidFree" operation="add" exact="$module.cargo.free"/> </do_if> </do_if> </do_for_each></do_for_each>
<write_to_logbook text="'Player free space — Container: ' + $TotalContainerFree + ' Solid: ' + $TotalSolidFree + ' Liquid: ' + $TotalLiquidFree"/>Example 2: Check if a station can store a given ware
Section titled “Example 2: Check if a station can store a given ware”<set_value name="$canStore" exact="false"/>
<do_for_each name="$module" in="$Station.modules"> <do_if value="$module.isclass.{class.storage} and $module.waretransport.indexof.{$ware.waretransport} gt 0 and $module.cargo.free gt $amount * $ware.volume"> <set_value name="$canStore" exact="true"/> <break/> </do_if></do_for_each>
<do_if value="not $canStore"> <write_to_logbook text="$Station.knownname + ' cannot store ' + $amount + ' × ' + $ware.name"/></do_if>Example 3: Warn when storage drops below threshold
Section titled “Example 3: Warn when storage drops below threshold”<cue name="WatchStorage" instantiate="true"> <conditions> <event_object_destroyed object="$WatchedStation"/> </conditions> <actions> <set_value name="$TotalCap" exact="0"/> <do_for_each name="$module" in="$WatchedStation.modules"> <do_if value="$module.isclass.{class.storage}"> <set_value name="$TotalCap" operation="add" exact="$module.cargo.capacity"/> </do_if> </do_for_each> <do_if value="$TotalCap lt 100000"> <write_to_logbook text="$WatchedStation.knownname + ' storage critical: only ' + $TotalCap + ' total capacity left'"/> </do_if> </actions></cue>Architectural context
Section titled “Architectural context”- How factions decide what storage modules to build: Architectural overview Faction economy —
Econ_Managerreads cargo backlogs (iswaitingforstorageon producers) → schedules new storage of the right type. - How cargo routes through a station: Architectural overview Station cargo flow —
add_cargodispatches to compatible modules; production output is held incontainercargolist; trade subscriptions read from there. - How trade ships pick destinations: Architectural overview Trade routing — pickers filter by
Station.cargo.{$ware}.targetandStation.maybuyfrom/.maysellto.
Related
Section titled “Related”- Module — parent generic-module page.
- Production module — companion module that fills storage.
- Processing module — sibling that fills storage from recyclables.
- Ware —
$ware.waretransportis the compat key. - Station — owner of storage; aggregates
.cargoacross modules. - Container — the type that supplies
Station.cargo.{ware},.buyprice,.sellprice.