NML:Vehicles
Vehicles, Stations, Canals, Bridges, Towns, Houses, Industries (Tiles), Cargos, Airports+Tiles, Objects, Railtypes, Roadtypes, Tramtypes, Terrain
- common props | vars | CBs
- train | roadveh | ship | aircr props
- common variables
- industry props | vars | CBs
- tile props | vars | CBs
- airport props | vars | CBs
- tile props | vars | CBs
Properties common to all vehicle types
property | value range | available for articulated vehicle |
comment |
---|---|---|---|
name
|
(string) | yes | for example string(STR_NAME_HEREFORD_TRAM)
|
climates_available
|
bitmask(CLIMATE_XXX, CLIMATE_YYY, ...) | set to NO_CLIMATES
|
XXX = [TEMPERATE | ARCTIC | TROPICAL | TOYLAND], alternatively NO_CLIMATE or ALL_CLIMATES . To make a vehicle available in all climates except toyland you could use: ALL_CLIMATES & ~bitmask(CLIMATE_TOYLAND) .
|
introduction_date
|
date (yyyy,mm,dd)
|
no | Valid range for yyyy is 0 ... 5000000. In TTDPatch, dates after 2044 will be limited to 2044. Unless the engine is introduced within two years after game-start (always 1920 in TTDPatch), a random number of days between 0 and 511 will be added to this. |
model_life
|
0 ... 254 (years) or VEHICLE_NEVER_EXPIRES
|
no |
Number of years a model is "supported" by the manufacturer, see below. |
retire_early
|
-128 ... 127 (years) | no |
Retire the vehicle (make it unavailable in the purchase menu) this many years before reliability starts dropping, see below. May be negative. |
vehicle_life
|
0 ... 255 (years) | no | Life length of an individual vehicle, before it is considered too old and in need of replacement. |
reliability_decay
|
0 ... 255 | no | Default vehicles use 20. The higher the value the faster reliability decays, the more frequent service is needed. 0 means reliability never decreases if the vehicle is not too old |
refittable_cargo_classes
|
bit set of cargo classes |
yes | for example: bitmask(CC_BULK, CC_COVERED)
|
non_refittable_cargo_classes
|
bit set of cargo classes |
yes | for example: bitmask(CC_OVERSIZED, CC_SPECIAL)
|
refittable_cargo_types
|
bit mask of entries into the cargo translation table | yes | example: bitmask(PASS, MAIL, GOOD)
|
cargo_allow_refit
|
Array of cargo labels from the cargotable | Yes | 1.2 Example: [COAL, IORE]
|
cargo_disallow_refit
|
Array of cargo labels from the cargotable | Yes | 1.2 Example: [MAIL]
|
loading_speed
|
0 ... 255 (cargo units) | yes | Units of cargo loaded per tick. Default vehicles use 5 for trains and road vehicles, 10 for ships and 20 for aircraft |
cost_factor
|
0 ... 255 | =0 | multiplier to the base purchase cost |
running_cost_factor
|
0 ... 255 | =0 | multiplier to the base running costs |
cargo_age_period
|
0 ... 65535 | yes |
1.2 This property specifies after how many ticks cargo is aged. Default value is 185. 74 ticks is equal to 1 day. |
Refittability
To determine whether your vehicle can be refitted to a certain cargo, OpenTTD uses the following table
Cargo matches refittable_cargo_classes | Cargo matches non_refittable_cargo_classes | Cargo in refittable_cargo_types | Result |
---|---|---|---|
No | Doesn't matter | No | Not refittable |
No | Doesn't matter | Yes | Refittable |
Yes | No | No | Refittable |
Yes | No | Yes | Not refittable |
Yes | Yes | No | Not refittable |
Yes | Yes | Yes | Refittable |
The results from the above table are always overriden by cargo_allow_refit and cargo_disallow_refit. Whatever the table says, if the cargo is in cargo_allow_refit the vehicle will always be refitable to that cargo.
You should use refittable_cargo_classes and non_refittable_cargo_classes to decide to which cargos your vehicle is refittable, and only use refittable_cargo_types as a last resort to include/exclude some cargo type.
Note that the default cargo cannot be selected explicitly. Instead it is automatically set to use the first refittable cargo, whenever one of the refitting properties is set.
Engine life cycle
The life cycle of a vehicle model consists of three phases, as outlined in the following table.
phase | duration | reliability |
---|---|---|
1 | 7 to 38 months | increases from 48-73% to 75-100% |
2 | model_life - 8 years
|
stays constant at peak, 75-100% |
3 | 10 to 20.5 years | decreases from peak to 25-50% |
If model_life
is set to VEHICLE_NEVER_EXPIRES
, the engine remains in phase 2 forever.
Normally, the vehicle is removed from the purchase menu at the and of phase 3. However if you set the retire_early
property, it will be retired this many years before (or after, if the value is negative) the end of phase 2.
Sorting vehicles in the purchase list
This is a special property that is not encoded in an item/property-block like most other properties but it has it's own block instead. The syntax is as follows:
sort(<feature>, [<ID>, <ID>, <ID>...]);
The engines will be sorted in the given order on the position where originally the first element was. Say the original engine sorting is this: A B C D E and you use this code sort(FEAT_TRAINS, [D, B, A]);
the final sorting will be this: C D B A E
Train properties
property | value range | available for articulated vehicle |
comment |
---|---|---|---|
sprite_id
|
SPRITE_ID_NEW_TRAIN
|
yes | Set this property to enable new graphics |
speed
|
0 ... 65000 (float, speed units) | no | Max speed for engines, speed limit for wagons |
misc_flags
|
bitmask(TRAIN_FLAG_XXX, ...) | FLIP should not be set, TILT and MU the same value | XXX=[TILT | 2CC | MU | FLIP | AUTOREFIT] which allows the train to enjoy the tilt bonus, use the 2nd company colour, act as a multiple unit (used for livery selection only) or allow the vehicle to be flipped (reversed) in the depot |
refit_cost
|
0 ... 255 | yes | in 50% units of the purchase price cost base |
callback_flags
|
bitmask(VEH_CBF_XXX, ...) | yes |
Do not set this, unless you use old-style callbacks. |
track_type
|
item from railtypetable | must be the same as front | Default railtype table: RAIL, MONO, MGLV. If you install a railtypetable yourself you'll always get the railtype you specified. If you want a vehicle to run on electric rail and you don't have a railtypetable, set track_type to RAIL and make sure that you set engine_class to ENGINE_CLASS_ELECTRIC .
|
ai_special_flag
|
[AI_FLAG_PASSENGER | AI_FLAG_CARGO ]
|
no | Set to AI_FLAG_PASSENGER to tell computer players that it's an engine that should only be used for passenger service.
|
power
|
0 ... 65000 hp (float, power units) | =0 | |
running_cost_base
|
RUNNING_COST_XXX | =0 | XXX = [STEAM | DIESEL | ELECTRIC | ROADVEH | NONE] |
dual_headed
|
[0 | 1] | =0 for both parts | 1 = dual_headed, otherwise normal engine |
cargo_capacity
|
0 .. 255 | yes | |
weight
|
0 .. 1279 ton (float, mass units) | =0 | |
ai_engine_rank
|
0 ... 255 | no | TTDPatch only: Higher values make the engine for the TTDPatch AI more attractive |
engine_class
|
ENGINE_CLASS_XXX | no | XXX=[STEAM | DIESEL | ELECTRIC | MONORAIL | MAGLEV] |
extra_power_per_wagon
|
0 ... 65000 hp (float, power units) | =0 | Only wagons with a livery override for this engine will add power |
tractive_effort_coefficient
|
0 ... 1 (float) | =0 | Fraction of the vehicle weight that is available as tractive effort. Tractive effort (in kN) is calculated as (TE coefficient) * 10 * weight (in tons), with 10 being an approximation of the acceleration of gravity (9.81 m/s). Default value is 0.3. |
air_drag_coefficient
|
0 ... 1 (float) | =0 | Coefficient of the relative air drag, in arbitrary units. The default value is approximately (8 / max_speed), with max_speed in km/h, clamped to the range 0.004 .. 0.75. |
shorten_vehicle
|
SHORTEN_TO_XXX | yes | XXX=[8_8 | 7_8 | ... | 1_8] |
visual_effect_and_powered
|
visual_effect_and_powered (VISUAL_EFFECT_XXX, offset, ENABLE_WAGON_POWER or DISABLE_WAGON_POWER )
|
yes | XXX=[DEFAULT | STEAM | DIESEL | ELECTRIC | DISABLE], it is the type of the visual effect you want for this vehicle. Default means "take from engine_class property". Offset is the position of the effect. 0 is default, negative values mean more to the front and positive values are backwards. Minimum offset is -8, maximum is 7. |
extra_weight_per_wagon
|
0 ... 255 ton (float, mass units) | =0 | Adds extra weight for powered wagons, see extra_power_per_wagon
|
bitmask_vehicle_info
|
8-bit bitmask | yes |
Used for obtaining |
Road vehicle properties
property | value range | available for articulated vehicle |
comment |
---|---|---|---|
sprite_id | SPRITE_ID_NEW_ROADVEH | yes | Set this property to enable new graphics |
speed | 0 ... 514km/h (float, speed units) | no | |
misc_flags | bitmask(ROADVEH_FLAG_XXX, ...) | partly; tram flag must the same | The following flags are defined: ROADVEH_FLAG_TRAM, ROADVEH_FLAG_2CC, ROADVEH_FLAG_AUTOREFIT. Use 0 if you don't want to set any of these flags. |
refit_cost | 0 ... 255 | yes | in 25% units of the purchase price cost base |
callback_flags | bitmask(VEH_CBF_XXX, ...) | yes |
Do not set this, unless you use old-style callbacks. |
running_cost_base | RUNNING_COST_XXX | set to RUNNING_COST_NONE | XXX = [STEAM | DIESEL | ELECTRIC | ROADVEH | NONE] |
power | 0 ... 2550hp (float, power units) | =0 | |
weight | 0 ... 63.75ton (float, mass units) | =0 | |
tractive_effort_coefficient | 0 ... 1 (float) | =0 | Fraction of the vehicle weight that is available as tractive effort. Tractive effort (in kN) is calculated as (TE coefficient) * 10 * weight (in tons), with 10 being an approximation of the acceleration of gravity (9.81 m/s). Default value is 0.3. |
air_drag_coefficient | 0 ... 1 (float) | =0 | Coefficient of the relative air drag, in arbitrary units. The default value is approximately (8 / max_speed), with max_speed in km/h, clamped to the range 0.004 .. 0.75. |
cargo_capacity | 0 ... 255 | yes | |
sound_effect | SOUND_XXX | no |
See available sound effects. |
visual_effect | visual_effect(VISUAL_EFFECT_XXX, offset) | yes | XXX=[DEFAULT | STEAM | DIESEL | ELECTRIC | DISABLE], it is the type of the visual effect you want for this vehicle. Default means no effect. Offset is the position of the effect. 0 is default, negative values mean more to the front and positive values are backwards. Minimum offset is -8, maximum is 7. |
Ship properties
property | value range | comment |
---|---|---|
sprite_id | SPRITE_ID_NEW_SHIP | Set this property to enable new graphics |
speed | 0 ... 127 km/h (float, speed units) | |
misc_flags | bitmask(SHIP_FLAG_2CC, SHIP_FLAG_AUTOREFIT) | Bitmask with two possible flags, set to 0 to disable |
refit_cost | 0 ... 255 | in 1/32 of the default refit cost base |
callback_flags | bitmask(VEH_CBF_XXX, ...) |
Do not set this, unless you use old-style callbacks. |
is_refittable | [0 | 1] | 0=false, 1=true. Note: if you do not set this property to 1, then refittable_cargo_classes / non_refittable_cargo_classes have no effect. |
cargo_capacity | 0 ... 255 | |
sound_effect | SOUND_XXX |
See available sound effects. |
ocean_speed_fraction | 0 ... 1 (float) | |
canal_speed_fraction | 0 ... 1 (float) | |
visual_effect | visual_effect(VISUAL_EFFECT_XXX, offset) | XXX=[DEFAULT | STEAM | DIESEL | ELECTRIC | DISABLE], it is the type of the visual effect you want for this ship. Default means no effect. Offset is the position of the effect. 0 is default, negative values mean more to the front and positive values are backwards. Minimum offset is -8, maximum is 7. |
Plane properties
property | value range | comment |
---|---|---|
sprite_id | SPRITE_ID_NEW_AIRCRAFT | Set this property to enable new graphics |
speed | 0 .. 3280 km/h (float, speed units) | |
misc_flags | bitmask(AIRCRAFT_FLAG_2CC, AIRCRAFT_FLAG_AUTOREFIT) | Bitmask with two possible flags, set to 0 to disable both |
refit_cost | 0 ... 255 | in 1/32 of default refit cost base |
callback_flags | bitmask(VEH_CBF_XXX, ...) |
Do not set this, unless you use old-style callbacks. |
is_helicopter | AIRCRAFT_TYPE_XXX | XXX=[NORMAL | HELICOPTER] |
is_large | AIRCRAFT_SIZE_XXX | XXX=[SMALL | LARGE]. Set to AIRCRAFT_SIZE_SMALL for helicopters. |
acceleration | 0 ... 255 | In arbitrary units |
passenger_capacity | 0 ... 65536 | |
mail_capacity | 0 ... 255 | |
sound_effect | SOUND_XXX |
See available sound effects. |
Vehicle variables
Below an overview of all vehicle-specific variables. Not that in the purchase list, the vehicle is not built yet and as such many variables are not available. All general variables are available, refer to the table for info on vehicle-specific variables. Trying to access a non-available variable invokes undefined behaviour. Please note that while all variables are available for all vehicles types, some of them only make sense for one or more vehicle types. For example checking current_railtype for a non-rail vehicle doesn't make sense at all.
Variables without parameter
name | value range | available in purchase list? |
comment |
---|---|---|---|
position_in_consist | 0 ... 255 | No | The position of the current vehicle-part from the start of the vehicle. The engine will get value 0, the first wagon (or second engine) gets value 1, etc. |
position_in_consist_from_end | 0 ... 255 | No | Same as position_in_consist but counted from the end. The last wagon will get value 0. |
num_vehs_in_consist | 1 ... 256 | No | The total number of vehicles-parts in this vehicle. For aircraft this will include the shadow and the rotor. |
position_in_vehid_chain | 0 ... 255 | No | See position_in_consist, but not of the complete vehicle but only all consecutive parts with the same id. |
position_in_vehid_chain_from_end | 0 ... 255 | No | See position_in_consist_from_end, but not of the complete vehicle but only all consecutive parts with the same id. |
num_vehs_in_vehid_chain | 1 ... 256 | No | See num_vehs_in_consist, but not of the complete vehicle but only all consecutive parts with the same id. |
cargo_classes_in_consist | Bitmask of CC_XXX | No | |
most_common_refit | No | cargo class most often refit to | |
bitmask_consist_info | Bitmask 8 bit | No |
Binary OR of the values of bitmask_vehicle_info of all vehicles (engines, wagons) in the consist. Only available for rail vehicles. |
company_num | 0 ... 14 | Yes | company number of the vehicle owner. TTDPatch only supports up to 8 companies (0 ... 7) |
company_type | PLAYERTYPE_XX | Yes | PLAYERTYPE_HUMAN, PLAYERTYPE_AI, PLAYERTYPE_HUMAN_IN_AI (human managing AI company) or PLAYERTYPE_AI_IN_HUMAN (AI managing human company). OpenTTD only uses PLAYERTYPE_HUMAN and PLAYERTYPE_AI. If you cheat yourself to be part of an AI company OpenTTD will still report PLAYERTYPE_AI for the company with yourself and the AI and it'll report PLAYERTYPE_HUMAN for the now uncontrolled company. |
company_colour1 | COLOUR_XXX | Yes |
Refer to the table here for possible values. |
company_colour2 | COLOUR_XXX | Yes |
Same as company_colour1, if no 2nd company colour is chosen. Refer to the table here for possible values. |
aircraft_height | 0 ... 255 | No | Height difference between the aircraft and its shadow. 8 Units are equivalent to one height level on the map. |
airport_type | AIRPORTTYPE_XX | No | AIRPORTTYPE_SMALL, AIRPORTTYPE_LARGE, AIRPORTTYPE_HELIPORT or AIRPORTTYPE_OILRIG |
curv_info_prev_cur | -2 ... 2 | No | Difference in direction between the previous (towards engine) vehicle and this vehicle. Curvature to the right is positive. 1 unit is 45 degrees. |
curv_info_cur_next | -2 ... 2 | No | Difference in direction between this vehicle and the next (towards rear end) vehicle. Curvature to the right is positive. 1 unit is 45 degrees. |
curv_info_prev_next | -4 ... 4 | No | Difference in direction between the previous (towards engine) and next (towards rear end) vehicle. Curvature to the right is positive. 1 unit is 45 degrees. Equal to curve_invo_prev_cur + curv_info_cur_next .
|
curv_info | vehicle_curv_info(prev_cur, cur_next)' | No |
Returns a magic number that represents the curvature state of the prev-cur-next vehicle triplet. Do not try to make sense of this magic number, use the builtin function |
motion_counter | 0 ... 15 | Yes, always 0 | Is increased every time the vehicle moves a single step on the map. Useful for animations. |
cargo_type_in_veh | entry in cargo translation table | Yes, for the default cargo | 0xFF if not present in the table |
cargo_unit_weight | weight per unit in 1/16t | Yes, for the default cargo | |
cargo_classes | Yes, for the default cargo | class of the currently transported cargo | |
vehicle_is_available | [0 | 1] | Yes | Value is 1 if the vehicle is available on the open market |
vehicle_is_testing | [0 | 1] | Yes | Value is 1 if the vehicle is currently being tested |
vehicle_is_offered | [0 | 1] | Yes | Value is 1 if the vehicle is currently being offered for exclusive preview |
build_year | 0 ... 5000000 | Yes | 0-based year when the vehicle was built, current year if the vehicle is not built yet |
direction | DIRECTION_XX | No |
See here for an overview of possible values and their meaning. |
cargo_capacity | 0 ... 65535 | No | Cargo capacity (number of units) of the vehicle |
cargo_count | 0 ... 65535 | No | Number of cargo units of cargo in the vehicle |
vehicle_type_id | No | ID of the vehicle | |
cargo_subtype | 0 ... 255 | Yes, always 0 | Cargo subtype, used to provide more than one refit option for the same cargo type. See also the cargo_subtype_text callback.
|
vehicle_is_powered | [0 | 1] | No | Vehicle provides power and is on the correct track type |
vehicle_is_not_powered | [0 | 1] | No | Vehicle is either on a wrong track type or it doesn't provide power at all |
vehicle_is_potentially_powered | [0 | 1] | No | Vehicle provides power, if it is on a suitable track type |
vehicle_is_reversed | [0 | 1] | No | Value is 1 if the vehicle has reversed an odd number of times |
built_during_preview | [0 | 1] | No | Value is 1 if the vehicle was built during the exclusive preview stage |
current_railtype | No | Entry from railtype translation table or 0xFF | Don't use this variable unless you've defined a railtype translation table. If the train is running on a railtype that is not listed in your railtype translation table this variable will contain 0xFF. Available since OpenTTD r20164. |
waiting_triggers | No |
Random triggers waiting to be matched. (see Random switch) | |
random_bits | 0 ... 255 | No |
Random data that can be used to randomize certain descisions. (see Random switch) |
grfid | 0 ... 0xFFFFFFFF | No |
GRFID that defined the graphics-block for this vehicle. To compare this with other grfids, use the builtin function |
vehicle_is_hidden | [0 | 1] | No | Value is 1 if the vehicle is hidden in a depot or tunnel. |
vehicle_is_stopped | [0 | 1] | No | Value is 1 if the vehicle is stopped, or if it is braking for a stop (trains only). |
vehicle_is_crashed | [0 | 1] | No | Value is 1 if the vehicle has crashed. |
vehicle_is_broken | [0 | 1] | No | Value is 1 if the vehicle is broken down. |
date_of_last_service | date(year, month, day) | No | Not valid before 1920 and after 2090. |
breakdowns_since_last_service | 0 ... 255 | No | Number of breakdowns since the last service |
reliability | 0 ... 100 | No | Reliability (percentage) |
age_in_days | 0 ... 65535 | No | Vehicle age in days. |
max_age_in_days | 0 ... 65535 | No | Maximum vehicle age in days. |
current_speed | (speed units) | No | The current speed of the vehicle in m/s |
max_speed | (speed units) | No | The maximum speed of the vehicle in m/s |
vehicle_is_in_depot | [0 | 1] | No | Value is 1 if the vehicle is inside a depot |
Variables that require an argument
name | Argument | value range | available in purchase list? |
comment |
---|---|---|---|---|
count_veh_id | The vehicle ID to look for. | 0..255 | No | The number of vehicles in the current consist that have the given ID. |
Vehicle callbacks
Name | Available for | In purchase menu? | value range | comment |
---|---|---|---|---|
default | All | Yes, unless purchase is set separately
|
Sprite group | 'Normal' vehicle graphics |
purchase | All | Yes, only | Sprite group | Graphics to show in the buy menu (only the horizontal view is needed) |
rotor | Aircraft (helicopters) | No | Sprite group | Graphics for the helicopter rotor (4 sprites; 1 stopped and 3 moving) |
random_trigger | All | No | N/A |
See random switch for more information. |
cargo_subtype_text | All | No | String, or 0xFF | With this callback, you can display extra text after the cargo in the vehicle information window. This callback is called during refitting, with succesively increased values of the cargo_subtype variable, until the callback returns 0xFF. All returned strings are then displayed as refit options. The chosen refit option is saved in the cargo_subtype variable, so it can be used later for other things. In HEQS for example, this mechanism is used to let the user choose between different capacities of the same vehicle.
|
additional_text | All | Yes, only | String | Additional text to show in the purchase list. |
colour_mapping | All | Yes, unless purchase_colour_mapping is set separately
|
Recolour sprite number |
With this callback, you can use a different recolour sprite instead of the standard 1cc / 2cc company colour remappings. See here for a list of default palettes. See the builtin function |
start_stop | All | No | String or 0xFF | Called when starting or stopping a vehicle. Mainly useful to prevent vehicles from leaving the depot unless a certain condition is met. Return 0xFF to allow or a string (containing an error message) to disallow starting/stopping. |
every_32_days | All | No | bitmask(CB_RESULT_32_DAYS_XXX, ...) | Called every 32 days. Set CB_RESULT_32_DAYS_TRIGGER in the bitmask to trigger TRIGGER_VEHICLE_32_CALLBACK. Set CB_RESULT_32_DAYS_COLOUR_MAPPING in the bitmask to update the colour mapping by re-running the colour_mapping callback.
|
sound_effect | All | No | SOUND_XXX, sound("sound.wav"), import_sound(grfid, number) or CB_RESULT_NO_SOUND |
Called to play various vehicle sounds. |
articulated_part | Trains, Road Vehicles | Yes (no separate callback) | Vehicle ID, or 0xFF | With this callback, you can add articulated parts (e.g. tenders) to your vehicle. Called repeatedly, until 0xFF is returned. After each call, the returned vehicleID is added to your vehicle. extra_callback_info1 contains 1 during the first call, 2 during the second, etc. Note that callback may be called from the purchase list, using vehicle variables is not possible. Add 128 to the returned vehicle ID to display the vehicle backwards. This has the unfortunate side-effect of requiring the vehicle ID of the articulated part to be in the range 0 .. 127, currently there's no way around this limitation.
|
can_attach_wagon | Trains | No | String or CB_RESULT_ATTACH_XXX | Called when a wagon is being attached, to allow or disallow attaching. This callback has to be defined at the engine. However, variables in the SELF scope refer to the wagon being attached, the PARENT scope refers to the engine that the wagon is being attached to. Return a string to disallow with the string as error message. Return CB_RESULT_ATTACH_DISALLOW to disallow with standard message ("incompatible railtypes"), CB_RESULT_ATTACH_ALLOW to allow or CB_RESULT_ATTACH_ALLOW_IF_RAILTYPES to allow if the railtypes match (default).
|
The following callbacks all have an equivalent property. The property description applies here also, except where otherwise noted.
Sound events
Event | Description |
---|---|
SOUND_EVENT_START | Vehicle leaves station or depot, plane takes off |
SOUND_EVENT_TUNNEL | Vehicle enters tunnel |
SOUND_EVENT_BREAKDOWN | Vehicle breaks down (not for planes) |
SOUND_EVENT_RUNNING | Once per engine tick, but no more than once per vehicle motion |
SOUND_EVENT_TOUCHDOWN | Aircraft touches down |
SOUND_EVENT_VISUAL_EFFECT | Visual effect is generated (steam plume, diesel smoke, electric spark) |
SOUND_EVENT_RUNNING_16 | Every 16 engine ticks if in motion |
SOUND_EVENT_STOPPED | Every 16 engine ticks if stopped |
SOUND_EVENT_LOAD_UNLOAD | Consist loads or unloads cargo |