NML:Vehicles

From GRFSpecs
Jump to navigationJump to search
Props, Vars and 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_CLIMATE
CLIMATE_TEMPERATE
CLIMATE_ARCTIC
CLIMATE_TROPICAL
CLIMATE_TOYLAND
NO_CLIMATE
Vehicle is availble in no climate (e.g. for articulated parts)
ALL_CLIMATES
Vehicle is available irrespective of climate

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 As of NML 0.3, do not use this. Use cargo_[dis]allow_refit (see below) instead.
cargo_allow_refit Array of cargo labels from the cargotable Yes Supported by OpenTTD 1.2 (r23291)1.2 Not supported by TTDPatch A list of cargo types to allow refitting to, irrespective of cargo classes. Example: [COAL, IORE]
cargo_disallow_refit Array of cargo labels from the cargotable Yes Supported by OpenTTD 1.2 (r23291)1.2 Not supported by TTDPatch A list of cargo types to disallow refitting to, irrespective of cargo classes. Example: [MAIL]
loading_speed 0 ... 255 (cargo units) yes Units of cargo loaded per time unit. Default vehicles use 5 for trains and road vehicles, 10 for ships and 20 for aircraft. This amount of cargo is loaded to or unloaded from the vehicle every 40 ticks for trains, every 20 ticks for road vehicles and aircraft and every 10 ticks for ships.
cost_factor 0 ... 255 Set to 0 multiplier to the base purchase cost
running_cost_factor 0 ... 255 Set to 0 multiplier to the base running costs
cargo_age_period 0 ... 65535 yes

Supported by OpenTTD 1.2 (r22713)1.2 This property specifies after how many ticks cargo is aged. Default value is 185. 74 ticks is equal to 1 day. If set to 0, cargo does not age. Repeated tests have shown that the gameplay effects of this property often do not match the expectations of grf authors. Explaining why requires a detailed understanding of the OpenTTD cargo aging algorithm, and how that works with e.g. different map sizes, vehicle speeds, multi-leg feeder systems, etc. TL;DR avoid using this property unless you absolutely understand the effect it will have.

variant_group Vehicle ID or alternatively the vehicle numeric ID (0 ... 65535) no

Supported by OpenTTD 1313 This property supports grouping vehicles in the purchase menu (also the autoreplace menu). The property value is the ID of another vehicle in the same GRF which will act as the parent for vehicles in the group.

Groups can also be nested (this is experimental as of December 2022 and may change with testing).

See also vehicle extra_flags which can influence the behaviour of vehicles in variant groups.

See also https://github.com/OpenTTD/OpenTTD/pull/10220

extra_flags bitmask(VEHICLE_FLAG_XXX, ...) no Supported by OpenTTD 1313
VEHICLE_FLAG_DISABLE_NEW_VEHICLE_MESSAGE
Disable "New Vehicle" news message for this engine
VEHICLE_FLAG_DISABLE_EXCLUSIVE_PREVIEW
Disable "Exclusive Preview" for this engine
VEHICLE_FLAG_SYNC_VARIANT_EXCLUSIVE_PREVIEW
Variants - Include this variant when primary engine has "Exclusive Preview"
VEHICLE_FLAG_SYNC_VARIANT_RELIABILITY
Variants - (Attempt to) Synchronize reliability the primary engine.

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 cargo_allow_refit Cargo in cargo_disallow_refit Result
Yes No Doesn't matter No Refittable
No Doesn't matter No Doesn't matter Not refittable
Doesn't matter Doesn't matter Yes No Refittable
Doesn't matter Doesn't matter Doesn't matter Yes Not refittable

For those that prefer boolean logic, the formula is as follows:

refittable = ((cargo classes in refittable_cargo_classes AND NOT cargo classes in non_refittable_cargo_classes) OR cargo in cargo_allow_refit) AND NOT (cargo in cargo_disallow_refit)

In general, you should use refittable_cargo_classes and non_refittable_cargo_classes to decide to which cargos your vehicle is refittable, and only then use cargo_allow_refit and cargo_disallow_refit to allow/disallow specific cargos.

Engine life cycle

The life cycle of a vehicle model consists of three phases, as outlined in the following table. The length of each phase and the starting, peak, and final reliabilities are randomized for each engine when starting a new game. Also note that phase 2 (the vehicle's peak performance) is actually about 8 years shorter than the model_life parameter.

phase duration reliability
1 7 to 38 months increases from 48-73% to 75-100%
2 model_life - 8 years + (0 to 15 months) stays constant at peak, 75-100%
3 10 to 20.6 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.

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 TO the same value as the 1st part
TRAIN_FLAG_TILT
enable the tilt bonus (20% speed in curves, if all vehicles in consist have it set). See also curve_speed_mod property.
TRAIN_FLAG_2CC
Enable use of the 2nd company colour
TRAIN_FLAG_MU
act as multiple unit (used for livery selection only)
TRAIN_FLAG_FLIP
Allow vehicle to be flipped (reversed) in depot. Supported by OpenTTD 1313 Not supported by TTDPatch this flag is no longer required, flip is always allowed, except for multi-header or articulated vehicles which cannot be flipped. For vehicles shorter than 8/8, see this note about sprite offsets
TRAIN_FLAG_AUTOREFIT
Allow autoreffitting. To enable autorefit, furthermore the refit_cost-callback has to allow it, or else (if this callback is not implemented or fails) the refit_cost-property (see below) must be set to 0.
TRAIN_FLAG_NO_BREAKDOWN_SMOKE
NML 0.3 Supported by OpenTTD 1.3 (r24124)1.3 Not supported by TTDPatch Disable breakdown smoke effect
TRAIN_FLAG_SPRITE_STACK
Supported by OpenTTD 1.7 (r27668)1.7 Not supported by TTDPatch Enable composition from multiple sprites.
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
AI_FLAG_PASSENGER
Tell computer players that it's an engine that should only be used for passenger service.
power 0 ... 65000 hp (float, power units) Set to 0
running_cost_base RUNNING_COST_XXX Set to RUNNING_COST_NONE
RUNNING_COST_STEAM
RUNNING_COST_DIESEL
RUNNING_COST_ELECTRIC
RUNNING_COST_ROADVEH
RUNNING_COST_NONE
no running costs
dual_headed [0 | 1] Set to 0 for all parts of an articulated vehicle 1 = dual_headed, otherwise normal engine
default_cargo_type An identifier from the cargo table, or DEFAULT_CARGO_FIRST_REFITTABLE Yes If the vehicle is refittable to at least one cargo, but the chosen default cargo is not available or is set to DEFAULT_CARGO_FIRST_REFITTABLE, then the first refittable cargo is used. The first refittable is chosen according to the order in your cargo table. If this property is set to a valid cargo but the vehicle cannot refit to any cargo type, then the vehicle will be able to carry only this cargo, but it cannot be refitted (like e.g. the default train wagons).
cargo_capacity 0 .. 255 yes By default, passenger capacity is 4x, and mail/goods capacity 2x larger than capacity for other cargoes. The capacity set here is used for the default (i.e. first refittable) cargo. Use the cargo_capacity callback to avoid this effect.
weight 0 .. 1279 ton (float, mass units) Set to 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

Defines which livery colour settings apply to the vehicle. It also sets the corresponding sound effect of the engine, and if visual_effect_and_powered is not set, the visual effect as well.

ENGINE_CLASS_STEAM
ENGINE_CLASS_DIESEL
ENGINE_CLASS_ELECTRIC
ENGINE_CLASS_MONORAIL
ENGINE_CLASS_MAGLEV
extra_power_per_wagon 0 ... 65000 hp (float, power units) Set to 0 Only wagons with a livery override for this engine will add power
tractive_effort_coefficient 0 ... 1 (float) Set to 0 Fraction of the vehicle weight that is available as tractive effort. Tractive effort (in kN) is calculated as (TE coefficient) * 9.8 * weight (in tons), with 9.8 being an approximation of the acceleration of gravity (9.81 m/s).
air_drag_coefficient 0 ... 1 (float) Set to 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.
length 1 ... 8 yes Length of the vehicle in arbitrary units. Use a value of 8 (equal to the predefined constant VEHICLE_LENGTH) for a full-length vehicle.
visual_effect_and_powered visual_effect_and_powered (VISUAL_EFFECT_XXX, offset, ENABLE_WAGON_POWER or DISABLE_WAGON_POWER) yes

There are two methods to set the visual effect of a vehicle:

  • visual_effect_and_powered: Easy method for simple effects.
  • effect_spawn_model_and_powered + callback create_effect: Supported by OpenTTD 1.5 (r26747)1.5 Not supported by TTDPatch Harder to use, but also more powerful.

For each vehicle you have to decide for the method. You cannot use them both for the same vehicle 'item'.

Set the type of visual effect for the vehicle and its positional offset with respect to the vehicle. An offset of 0 is default, negative values mean more to the front and positive values are backwards. Minimum offset is -8, maximum is 7.

VISUAL_EFFECT_DEFAULT
No effect, unless for the default vehicles
VISUAL_EFFECT_STEAM
Steam like from steam engine
VISUAL_EFFECT_DIESEL
Steam from internal combustion engine
VISUAL_EFFECT_ELECTRIC
Electric sparks
VISUAL_EFFECT_DISABLE
No effect
effect_spawn_model_and_powered EFFECT_SPAWN_MODEL_XXX or EFFECT_SPAWN_MODEL_XXX | ENABLE_WAGON_POWER yes

There are two methods to set the visual effect of a vehicle:

  • visual_effect_and_powered: Easy method for simple effects.
  • effect_spawn_model_and_powered + callback create_effect: Supported by OpenTTD 1.5 (r26747)1.5 Not supported by TTDPatch Harder to use, but also more powerful.

For each vehicle you have to decide for the method. You cannot use them both for the same vehicle 'item'.

Supported by OpenTTD 1.5 (r26747)1.5 Not supported by TTDPatch Set the spawning model of visual effects for the vehicle, that is when the vehicle emits visual effects. The visual appearance itself is defined by the callback 'create_effect'.

EFFECT_SPAWN_MODEL_NONE
Do not spawn any effects.
EFFECT_SPAWN_MODEL_STEAM
Gradually less effects when approaching max speed.
EFFECT_SPAWN_MODEL_DIESEL
Effect proportional to acceleration, no effect when idling at top speed.
EFFECT_SPAWN_MODEL_ELECTRIC
Random effect, gradually less likely when approaching max speed.
extra_weight_per_wagon 0 ... 255 ton (float, mass units) Set to 0 Adds extra weight for powered wagons, see extra_power_per_wagon
bitmask_vehicle_info 8-bit bitmask yes

Used for obtaining bitmask_consist_info

curve_speed_mod -128 ... 127.996 (float) yes NML 0.7 Supported by OpenTTD 12.012.0 Maximum curve speed modifier.

The modifier is applied after the normal curve speed calculation is done using the formula max_curve_speed * (1 + curve_speed_mod). This means that the default property value of 0 is equivalent to no change. Negative values are supported, but the resulting vehicle curve speed is clamped at 2 mph-ish to make sure vehicles don't become permanently stuck.

If different vehicles in a train have different curve speed modifiers, the lowest value wins.

See also TRAIN_FLAG_TILT, which is an older and less flexible way of managing vehicle curve speed.

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 ... 511km/h (float, speed units) no
road_type or tram_type item from roadtypetable or tramtypetable must be the same as front Only one of these properties may be set.

If tram_type is set, ROADVEH_FLAG_TRAM must also be set for the vehicle in misc_flags.

If not set, road vehicles will default to ROAD and tram vehicles will default to RAIL (this does not overlap with railtype RAIL).

misc_flags bitmask(ROADVEH_FLAG_XXX, ...) partly; tram flag must the same
ROADVEH_FLAG_TRAM
The vehicle requires tram tracks to run on
ROADVEH_FLAG_2CC
Enable 2nd company colour
ROADVEH_FLAG_AUTOREFIT
Allow autorefitting. To enable autorefit, furthermore the refit_cost-callback has to allow it, or else (if this callback is not implemented or fails) the refit_cost-property (see below) must be set to 0.
ROADVEH_FLAG_NO_BREAKDOWN_SMOKE
NML 0.3 Supported by OpenTTD 1.3 (r24124)1.3 Not supported by TTDPatch Disable breakdown smoke effect
ROADVEH_FLAG_SPRITE_STACK
Supported by OpenTTD 1.7 (r27668)1.7 Not supported by TTDPatch Enable composition from multiple sprites.
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
RUNNING_COST_STEAM
RUNNING_COST_DIESEL
RUNNING_COST_ELECTRIC
RUNNING_COST_ROADVEH
RUNNING_COST_NONE
no running costs
power 0 ... 2550hp (float, power units) Set to 0
weight 0 ... 63.75ton (float, mass units) Set to 0
tractive_effort_coefficient 0 ... 1 (float) Set to 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) Set to 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.
default_cargo_type An identifier from the cargo table, or DEFAULT_CARGO_FIRST_REFITTABLE Yes If the vehicle is refittable to at least one cargo, but the chosen default cargo is not available or is set to DEFAULT_CARGO_FIRST_REFITTABLE, then the first refittable cargo is used. The first refittable is chosen according to the order in your cargo table. If this property is set to a valid cargo but the vehicle cannot refit to any cargo type, then the vehicle will be able to carry only this cargo, but it cannot be refitted (like e.g. the default train wagons).
cargo_capacity 0 ... 255 yes By default, passenger capacity is 4x, and mail/goods capacity 2x larger than capacity for other cargoes. The capacity set here is used for the default (i.e. first refittable) cargo. Use the cargo_capacity callback to avoid this effect.
sound_effect SOUND_XXX no

See available sound effects.
Supported by OpenTTD 1.6 (r27507)1.6 Not supported by TTDPatch Since OpenTTD r27507 also sound("sound.wav") and import_sound(grfid, number) are valid here.

visual_effect visual_effect( VISUAL_EFFECT_XXX, offset) yes

There are two methods to set the visual effect of a vehicle:

  • visual_effect: Easy method for simple effects.
  • effect_spawn_model + callback create_effect: Supported by OpenTTD 1.5 (r26747)1.5 Not supported by TTDPatch Harder to use, but also more powerful.

For each vehicle you have to decide for the method. You cannot use them both for the same vehicle 'item'.

Set the type of visual effect for the vehicle and its positional offset with respect to the vehicle. An offset of 0 is default, negative values mean more to the front and positive values are backwards. Minimum offset is -8, maximum is 7.

VISUAL_EFFECT_DEFAULT
No effect, unless for the default vehicles
VISUAL_EFFECT_STEAM
Steam like from steam engine
VISUAL_EFFECT_DIESEL
Steam from internal combustion engine
VISUAL_EFFECT_ELECTRIC
Electric sparks
VISUAL_EFFECT_DISABLE
No effect
effect_spawn_model EFFECT_SPAWN_MODEL_XXX yes

There are two methods to set the visual effect of a vehicle:

  • visual_effect: Easy method for simple effects.
  • effect_spawn_model + callback create_effect: Supported by OpenTTD 1.5 (r26747)1.5 Not supported by TTDPatch Harder to use, but also more powerful.

For each vehicle you have to decide for the method. You cannot use them both for the same vehicle 'item'.

Supported by OpenTTD 1.5 (r26747)1.5 Not supported by TTDPatch Set the spawning model of visual effects for the vehicle, that is when the vehicle emits visual effects. The visual appearance itself is defined by the callback 'create_effect'.

EFFECT_SPAWN_MODEL_NONE
Do not spawn any effects.
EFFECT_SPAWN_MODEL_STEAM
Gradually less effects when approaching max speed.
EFFECT_SPAWN_MODEL_DIESEL
Effect proportional to acceleration, no effect when idling at top speed.
EFFECT_SPAWN_MODEL_ELECTRIC
Random effect, gradually less likely when approaching max speed.
length 1 ... 8 yes Length of the vehicle in arbitrary units. Use a value of 8 (equal to the predefined constant VEHICLE_LENGTH) for a full-length vehicle.

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) Supported by OpenTTD 1414NML 7.5 0 .. 32767 km/h (float, speed units)
misc_flags bitmask(SHIP_FLAG_XXX) Bitmask with to possible flags, set to 0 to disable all.
SHIP_FLAG_2CC
Enable use of the 2nd company colour
SHIP_FLAG_AUTOREFIT
llow autorefitting. To enable autorefit, furthermore the refit_cost-callback has to allow it, or else (if this callback is not implemented or fails) the refit_cost-property (see below) must be set to 0.
SHIP_FLAG_NO_BREAKDOWN_SMOKE
NML 0.3 Supported by OpenTTD 1.3 (r24124)1.3 Not supported by TTDPatch Disable breakdown smoke effect
SHIP_FLAG_SPRITE_STACK
Supported by OpenTTD 1.7 (r27668)1.7 Not supported by TTDPatch Enable composition from multiple sprites.
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.
default_cargo_type An identifier from the cargo table, or DEFAULT_CARGO_FIRST_REFITTABLE If the vehicle is refittable to at least one cargo, but the chosen default cargo is not available or is set to DEFAULT_CARGO_FIRST_REFITTABLE, then the first refittable cargo is used. The first refittable is chosen according to the order in your cargo table. If this property is set to a valid cargo but the vehicle cannot refit to any cargo type, then the vehicle will be able to carry only this cargo, but it cannot be refitted (like e.g. the default train wagons).
cargo_capacity 0 ... 255 For ships (unlike other vehicle types) the capacity set here is not affected by the cargo type.
sound_effect SOUND_XXX

See available sound effects.
Supported by OpenTTD 1.6 (r27507)1.6 Not supported by TTDPatch Since OpenTTD r27507 also sound("sound.wav") and import_sound(grfid, number) are valid here.

ocean_speed_fraction 0 ... 1 (float)

Supported by OpenTTD 1.2 (r22639)1.2 fraction of base speed on ocean tiles (default: 1)

canal_speed_fraction 0 ... 1 (float)

Supported by OpenTTD 1.2 (r22639)1.2 fraction of base speed on canal tiles (default: 1)

visual_effect visual_effect(VISUAL_EFFECT_XXX, offset)

There are two methods to set the visual effect of a vehicle:

  • visual_effect: Easy method for simple effects.
  • effect_spawn_model + callback create_effect: Supported by OpenTTD 1.5 (r26747)1.5 Not supported by TTDPatch Harder to use, but also more powerful.

For each vehicle you have to decide for the method. You cannot use them both for the same vehicle 'item'.

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.

effect_spawn_model EFFECT_SPAWN_MODEL_XXX

There are two methods to set the visual effect of a vehicle:

  • visual_effect: Easy method for simple effects.
  • effect_spawn_model + callback create_effect: Supported by OpenTTD 1.5 (r26747)1.5 Not supported by TTDPatch Harder to use, but also more powerful.

For each vehicle you have to decide for the method. You cannot use them both for the same vehicle 'item'.

Supported by OpenTTD 1.5 (r26747)1.5 Not supported by TTDPatch Set the spawning model of visual effects for the vehicle, that is when the vehicle emits visual effects. The visual appearance itself is defined by the callback 'create_effect'.

EFFECT_SPAWN_MODEL_NONE
Do not spawn any effects.
EFFECT_SPAWN_MODEL_STEAM
Gradually less effects when approaching max speed.
EFFECT_SPAWN_MODEL_DIESEL
Effect proportional to acceleration, no effect when idling at top speed.
EFFECT_SPAWN_MODEL_ELECTRIC
Random effect, gradually less likely when approaching max speed.
acceleration 1 ... 255 Supported by OpenTTD 1414 Acceleration in units of ~0.5 km/h per tick. 1 is the default and is the acceleration of default ships.

Aircraft 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)
range 0 .. 2894 NML 0.3 Supported by OpenTTD 1.2 (r23504)1.2 Not supported by TTDPatch Maximum (euclidean) distance the aircraft can cover between two airports. Set to 0 for unlimited range.
misc_flags bitmask(AIRCRAFT_FLAG_2CC, AIRCRAFT_FLAG_AUTOREFIT) Bitmask with to possible flags, set to 0 to disable all.
AIRCRAFT_FLAG_2CC
Enable 2nd company colour
AIRCRAFT_FLAG_AUTOREFIT
Allow autorefitting. To enable autorefit, furthermore the refit_cost-callback has to allow it, or else (if this callback is not implemented or fails) the refit_cost-property (see below) must be set to 0.
AIRCRAFT_FLAG_NO_BREAKDOWN_SMOKE
NML 0.3 Supported by OpenTTD 1.3 (r24124)1.3 Not supported by TTDPatch Disable breakdown smoke effect
AIRCRAFT_FLAG_SPRITE_STACK
Supported by OpenTTD 1.7 (r27668)1.7 Not supported by TTDPatch Enable composition from multiple sprites. This also affects custom rotor sprites.
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.

aircraft_type AIRCRAFT_TYPE_XXX
AIRCRAFT_TYPE_HELICOPTER
Can land on helipad
AIRCRAFT_TYPE_SMALL
Can land on all airports with runway
AIRCRAFT_TYPE_LARGE
Can land on all airports with runway. But have a high crash chance on small airports
acceleration Supported by OpenTTD 1.3.11.3.1 0 ... 255
Supported by OpenTTD <1.3.1<1.3.1 0 ... 19
Supported by OpenTTD 1.3.11.3.1 Default aircraft use values in the range 18 to 50 (= 6.75 to 18.75 mph/tick = 499.5 to 1387.5 mph/day), which is generally considered quite fast.

Supported by OpenTTD <1.3.1<1.3.1 In older OpenTTD, aircraft provided by NewGRF accelerate 166% faster than intended.

passenger_capacity 0 ... 65536 Capacity for the passenger compartment. See also the notes at mail_capacity below.
mail_capacity 0 ... 255 Capacity for the mail compartment, if refitted to a cargo in the CC_PASSENGERS class. When refitted to other cargoes, this capacity is added to the passenger capacity to determine the base capacity. The actual capacity is set to this base capacity divided by 1 for mail, 2 for goods and 4 for all other cargoes. To override this effect, use the passenger_capacity and mail_capacity callbacks.
sound_effect SOUND_XXX

See available sound effects.
Supported by OpenTTD 1.6 (r27507)1.6 Not supported by TTDPatch Since OpenTTD r27507 also sound("sound.wav") and import_sound(grfid, number) are valid here.

Vehicle variables

Below an overview of all vehicle-specific variables. Note 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, similarly checking current_roadtype for a tram won't return a useful result.

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.
position_in_articulated_veh 0 ... 255 No NML 0.3 Supported by OpenTTD 1.4 (r26157)1.4 Not supported by TTDPatch The position of the current articulated vehicle from the start of the vehicle. The first will get value 0, the second one gets value 1, etc.
position_in_articulated_veh_from_end 0 ... 255 No NML 0.3 Supported by OpenTTD 1.4 (r26157)1.4 Not supported by TTDPatch The position of the current articulated vehicle from the end of the vehicle. The last will get value 0, the second last one gets value 1, etc.
cargo_classes_in_consist Bitmask of CC_XXX No

cargo classes

most_common_cargo_type

Cargo label

No The most common cargo type in the consist. Prior to nml r2320 this was known as most_common_refit, and didn't work, and was also incorrectly documented :)
most_common_cargo_subtype 0 ... 255 No The most common cargo subtype for most_common_cargo_type
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
human player
PLAYERTYPE_AI
AI player
PLAYERTYPE_HUMAN_IN_AI
human managing AI company
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
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 vehicle_curv_info() instead to make comparisons. curv_info == vehicle_curv_info(a, b) is equivalent to (curv_info_prev_cur == a) && (curv_info_cur_next == b), however the former can easily be used in a switch-block.

motion_counter 0 ... 0xFFFFFF Yes, always 0 Is increased every time the vehicle moves a single step on the map. Useful for driving animations.

For that, make the animation use a number of frames, which is a power of two, i.e. 2, 4, 8, 16, 32, ... frames, and then use the lower n bits of motion_counter.

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 Bitmask of cargo class 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
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_flipped [0 | 1] No Value is 1 if the sprite is reversed via flip-vehicle-in-depot (trains only), or if it's the rear-most part of a dual-head engine.
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 Entry from railtype translation table or 0xFF No This variable is useless due to equivalent railtypes, use tile_xxx_railtype instead. If you do use this variable, it will not work as expected 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.
current_roadtype Entry from current_roadtype translation table or 0xFF No NML 0.5 Supported by OpenTTD 1.101.10 Not supported by TTDPatch This variable is useless due to equivalent roadtypes, use tile_xxx_roadtype instead. Don't use this variable unless you've defined a roadtype translation table. If the road vehicle is running on a roadtype that is not listed in your roadtype translation table this variable will contain 0xFF. Checking this for a tram is not supported and will not return a useful result.
current_tramtype Entry from tramtype translation table or 0xFF No NML 0.5 Supported by OpenTTD 1.101.10 Not supported by TTDPatch This variable is useless due to equivalent tramtypes, use tile_xxx_tramtype instead. Don't use this variable unless you've defined a tramtype translation table. If the road vehicle is running on a tramtype that is not listed in your tramtype translation table this variable will contain 0xFF. Checking this for a road vehicle that is not a tram is not supported and will not return a useful result.
tile_has_catenary No [0 | 1] Supported by OpenTTD 1.111.11 Not supported by TTDPatch True if the track_type on the tile has catenary. This is a little simplified as it is intended for sprite changes (e.g. raise/lower pantograph) and only checks for "some catenary". To distinguish different types of electric track, AC and DC voltages etc, ... use tile_xxx_railtype/tile_xxx_roadtype/tile_xxx_tramtype instead.
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 str2number() to convert the other GRFID to a number as well.

vehicle_type_id 0 ... 65535 or a name defined in item block No GRF-local ID of the vehicle, equal to the item ID. Note that vehicles from other NewGRFs may have the same ID, so you'll generally have to check the grfid as well.
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
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
current_max_speed (speed units) No NML 0.3 Supported by OpenTTD 1.3 (r24246)1.3 Not supported by TTDPatch Current maximum speed of the vehicle in m/s. This includes e.g. track or timetable limits. Only valid for front vehicle.
vehicle_is_in_depot [0 | 1] No Value is 1 if the vehicle is inside a depot
vehicle_is_unloading [0 | 1] No Supported by OpenTTD 1.5 (r26430)1.5 Supported by TTDPatch 2.52.5 Value is 1 if the vehicle is unloading at a station and has not yet started loading new cargo.

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.
other_veh_curv_info Offset in the chain from the current vehicle.[1] -4..4 No Difference in direction between the other vehicle and this vehicle. Curvature to the right is positive. 1 unit is 45 degrees.
other_veh_is_hidden Offset in the chain from the current vehicle.[1] [0 | 1] No 1 the other vehicle is hidden in a depot or tunnel, 0 otherwise
other_veh_x_offset Offset in the chain from the current vehicle.[1] -128..127 No Signed difference in X-position (top-right to bottom-left) between the other vehicle and this vehicle.
other_veh_y_offset Offset in the chain from the current vehicle.[1] -128..127 No Signed difference in Y-position (top-left to bottom-right) between the other vehicle and this vehicle.
other_veh_z_offset Offset in the chain from the current vehicle.[1] -128..127 No Signed difference in Z-position (upwards) between the other vehicle and this vehicle.
tile_supports_railtype
tile_supports_roadtype
tile_supports_tramtype
Entry from rail/road/tram translation table [0 | 1] No Supported by OpenTTD 1.111.11 Not supported by TTDPatch Vehicles of the track_type label used as parameter are compatible with the rail/road/tram track_type on the current tile. Example: tile_supports_railtype(ELRL)
tile_powers_railtype
tile_powers_roadtype
tile_powers_tramtype
Entry from rail/road/tram translation table [0 | 1] No Supported by OpenTTD 1.111.11 Not supported by TTDPatch Vehicles of the track_type label used as parameter are powered on the rail/road/tram track_type on the current tile. Example: tile_powers_railtype(ELRL)
tile_is_railtype
tile_is_roadtype
tile_is_tramtype
Entry from rail/road/tram translation table [0 | 1] No Supported by OpenTTD 1.111.11 Not supported by TTDPatch The track_type label used as parameter is identical or equivalent (listed as alternate label in rail-/road-/tram-type property 1D) to the rail/road/tram track_type on the current tile. Example: tile_is_railtype(ELRL)
  1. 1.0 1.1 1.2 1.3 1.4 Argument range is -128..127. Positive values are interpreted as towards the end, negative values as towards the front. If the offset is outside the vehicle chain, the result value will be 0.

Vehicle callbacks

The following table contains a list of available vehicle callbacks. Additionally, it's possible to provide cargo-specific graphics, using the identifier from the cargo table as callback name. These callbacks will be used if the vehicle is refitted to the corresponding cargo type. If no cargo-specific graphics match the cargo that the vehicle is carrying, the default callback is used instead. Cargo-specific graphics callbacks are never called from the purchase menu, refer to the purchase callback below instead.

Note that the above affects graphics only, other callbacks are unaffected.

Name Available for In purchase menu? value range comment
default All Yes, unless purchase is set separately Sprite group 'Normal' vehicle graphics, if no cargo-specific graphics apply. See also the section on GUI sprites.
purchase All Yes, only Sprite group Graphics to show in the buy menu (only the horizontal view is needed, except for dual-headed trains. With the dual_headed property set, special rules for the purchase menu sprite apply: two sprites are drawn (for front and back) as if the vehicle is normally constructed. If you supply one purchase menu sprite, it will be used for both vehicle parts in the purchase menu. Provide a set of 8 sprites, and the 7th resp. 3rd sprite will be drawn; provide a set of 8 blank sprites except the 7th if you want to fully control a single purchase menu sprite for a dual-headed engine. ) See also the section on GUI sprites.
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 CB_RESULT_NO_TEXT NOTE: As of OpenTTD 13, this feature is considered deprecated for most uses. Use variants instead. 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 CB_RESULT_NO_TEXT. 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 to select specific sprites for the vehicle's current cargo subtype.
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 reserve_sprites() for info on how to allocate your own sprite. For performance, the result is cached and only updated if the every_32_days callback requires so. Add CB_RESULT_COLOUR_MAPPING_ADD_CC to the result to add the company colour to the sprites, this requires 16 (1cc) or 256 (2cc) sprites in total.

start_stop All No String or CB_RESULT_NO_TEXT Called when starting or stopping a vehicle. Mainly useful to prevent vehicles from leaving the depot unless a certain condition is met. Return CB_RESULT_NO_TEXT 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.

  • getbits(extra_callback_info1, 0, 8) The sound event, see the table below.

Return SOUND_XXX (see here) to return a default sound. sound("soundfile") imports a sound from a .wav file. import_sound(grfid, number) imports a sound from another grf. A failed (or not implemented) callback will cause the default sound to be played. Return CB_RESULT_NO_SOUND to play no sound at all.

articulated_part Trains, Road Vehicles Yes (no separate callback) Vehicle ID, or CB_RESULT_NO_MORE_ARTICULATED_PARTS With this callback, you can add articulated parts (e.g. tenders) to your vehicle. Called repeatedly, until CB_RESULT_NO_MORE_ARTICULATED_PARTS is returned. After each call, the returned vehicleID is added to your vehicle.
  • getbits(extra_callback_info1, 0, 8) 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. Or CB_RESULT_REVERSED_VEHICLE to the returned vehicle ID to display the vehicle backwards.

For NML 0.2 and lower the vehicle ID of the articulated part must be in the range 0 .. 127.

can_attach_wagon Trains No String or CB_RESULT_ATTACH_XXX Called when a wagon is being attached, to allow or disallow attaching. If a wagon is inserted in the middle, all wagons are removed and attached one-by-one in the new order. This callback has to be defined at the engine. The scopes behave different than usual though:
  • SELF refers to the wagon being attached. (despite the callback being defined at the engine)
  • PARENT refers to the consist of the engine up to the wagon before SELF, i.e. not (yet) including the wagon being attached.

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).

refit_cost Supported by OpenTTD 1.2 (r23089)1.2 Not supported by TTDPatch All Yes -8192 .. 8191 as refit cost. Add CB_RESULT_AUTOREFIT if you want to allow autorefit. When returning a negative value, encode the cost as (cost & CB_RESULT_REFIT_COST_MASK) before (possibly) adding CB_RESULT_AUTOREFIT. To allow autorefitting, the corresponding bit in the misc_flags must be set as well.
  • getbits(extra_callback_info1, 0, 8): The new cargo type.
  • getbits(extra_callback_info1, 8, 8): The new cargo subtype (see cargo_subtype_text-callback).
  • getbits(extra_callback_info1, 16, 16): A bitmask of the cargo classes of the target cargo type.

Note that this callback may also be called when the vehicle does not exist yet, so the available variables are limited.

create_effect Supported by OpenTTD 1.5 (r26747)1.5 Not supported by TTDPatch Trains, Road Vehicles, Ships No 0 .. 3 for number of effects. Optionally add CB_RESULT_CREATE_EFFECT_CENTER and/or CB_RESULT_CREATE_EFFECT_NO_ROTATION Called when a effect spawning model is defined via effect_spawn_model resp. effect_spawn_model_and_powered.

The result specifies how many effects shall be created. The position and appearance of the individual effects is returned via registers 0x100 to 0x103:

switch (FEAT_XXX, SELF, switch_name, [
  STORE_TEMP(create_effect(EFFECT_SPRITE_XXX, 8, -3, 10), 0x100), // first effect,
  STORE_TEMP(create_effect(EFFECT_SPRITE_YYY, 8,  3, 10), 0x101)  // second effect, ...
]) {
return 2; // number of effects
}

The register values are created using the create_effect(effect_sprite, l_x_offset, t_y_offset, z_offset) function:

  • effect_sprite: Sprite for the effect. One of EFFECT_SPRITE_[NONE|STEAM|DIESEL|ELECTRIC|AIRCRAFT_BREAKDOWN_SMOKE].
  • l_x_offset: Longitudinal or X position of the effect, depending on callback result CB_RESULT_CREATE_EFFECT_NO_ROTATION.
  • t_y_offset: Transversal or Y position of the effect, depending on callback result CB_RESULT_CREATE_EFFECT_NO_ROTATION.
  • z_offset: Z position of the effect.

Additional to the number of effects, the callback result may specify these flags:

CB_RESULT_CREATE_EFFECT_CENTER
(Train and road vehicle only) If set, position effect relative to vehicle center instead of relative to vehicle sprite. (behaves the same for vehicles with length 8/8)
CB_RESULT_CREATE_EFFECT_NO_ROTATION
  • If not set, the parameters to effect_sprite describe longitudinal/transversal positions, which are rotate wrt. vehicle orientation.
  • If set, the parameters to effect_sprite describe X and Y positions, which are not automatically rotated.

The following callbacks all have an equivalent property. The property description applies here also, except where otherwise noted.

Name Available for In purchase menu? comment
loading_speed All No
speed All Yes, unless purchase_speed is set separately Units are not (yet) available
cost_factor All Yes, only
running_cost_factor All Yes, unless purchase_running_cost_factor is set separately
cargo_age_period All No
cargo_capacity All except aircraft Yes, unless purchase_cargo_capacity is set separately
passenger_capacity Aircraft Yes, unless purchase_passenger_capacity is set separately
mail_capacity Aircraft Yes, unless purchase_mail_capacity is set separately
range Aircraft Yes, unless purchase_range is set separately
visual_effect_and_powered Trains No
visual_effect Road Vehicles, Ships No
effect_spawn_model_and_powered Trains No
effect_spawn_model Road Vehicles, Ships No
power Trains, Road Vehicles Yes, unless purchase_power is set separately Units are not (yet) available
weight Trains, Road Vehicles Yes, unless purchase_weight is set separately Units are not (yet) available
length Trains, Road vehicles No
tractive_effort_coefficient Trains, Road Vehicles Yes, unless purchase_tractive_effort_coefficient is set separately Value range is 0 .. 255 instead of 0 .. 1.
bitmask_vehicle_info Trains No
curve_speed_mod NML 0.7 Supported by OpenTTD 12.012.0 Trains No
name NML 0.7.2 Supported by OpenTTD 14.014.0 All Yes Can be used to display vehicle name differently depending on context (purchase menu, depot, nested variant depth etc). extra_callback_info1 contains detailed information about context - please see https://newgrf-specs.tt-wiki.net/wiki/Callbacks#Engine_name_.28161.29



Sprites in GUI

Supported by OpenTTD 1.2 (r23080)1.2 Not supported by TTDPatch Since OpenTTD r23080 you can use variable getbits(extra_callback_info1, 0, 8) to display different sprites in the GUI and on the map. Currently these cases are available:

getbits(extra_callback_info1, 0, 8) Meaning
0x00 Vehicle is drawn in a viewport, i.e. on the map.
0x01..0x0F reserved
0x10 Vehicle is drawn in the depot GUI. [1]
0x11 Vehicle is drawn in the vehicle details GUI. (This includes the refit GUI.)
0x12 Vehicle is drawn in the vehicle list.
0x13..0x1F reserved for other future GUIs.
0x20 Vehicle is drawn in the purchase list. (This includes the autoreplace GUI.)
0x21 Vehicle is drawn in the exclusive preview GUI or in the advertisement news.
0x22..0x2F reserved for other future GUIs with non-purchased vehicles.
0x30..0xFF reserved
  1. OpenTTD also uses this value with the purchase-list chain (cargotype FF) to determine the gridsize in ship and aircraft depots.

The cases 0x20..0x2F are called using the purchase-callback, the other cases are called for the default- or cargo-specific callbacks. Exception is the the special depot-gridsize call, which uses the purchase-callback.

Composing vehicles from multiple sprites

Supported by OpenTTD 1.7 (r27668)1.7 Not supported by TTDPatch Since OpenTTD r27668 you can draw vehicles by drawing multiple sprites on top of each other.

  • The sprites can use different recolouring.
  • When using 32bpp sprites, the sprites can use the alpha channel to blend with the other sprites. In particular you can use this to alpha-blend company colours over other sprites.

To enable this, you need to set XXX_FLAG_SPRITE_STACK in the misc_flags property.

When enabled, sprites are resolved multiple times while incrementing an iteration number, that can be read via getbits(extra_callback_info1, 8, 8)

For OpenTTD 1.7 to 12.0, this is limited to at most 4 sprites per articulated part.

Increased to 8 sprites per articulated part for OpenTTD 13.0 Supported by OpenTTD 13.013.0 Not supported by TTDPatch

In addition you need to set register 100 as additional result:

  • STORE_TEMP(CB_FLAG_MORE_SPRITES | recolouring, 0x100) if there are more sprites to draw.
  • STORE_TEMP(recolouring, 0x100) if there are no more sprites to draw.

"recolouring" can be:

  • PALETTE_USE_DEFAULT to use the default vehicle recolouring.
  • PALETTE_IDENTITY to use no recolouring
  • Any other default or custom recolouring sprite.

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

Vehicle IDs

Picking an item ID requires keeping two cases in mind: OpenTTD with the engine pool enabled and OpenTTD with engine pool disabled / TTDPatch. The status of the engine pool may be checked with the global variable dynamic_engines.

Note that while vehicle ID affects the order in which vehicles appear in the purchase menu, this can be overridden using the sort block.

Engine pool enabled

With the engine pool enabled, each NewGRF has its own ID range, NewGRFs don't influence each other. IDs may freely be chosen between 0 and 65535. If the chosen ID belongs to an existing vehicle, this vehicle is overridden by your vehicle. If another NewGRF is already overriding that vehicle, a new vehicle will be allocated, but all the properties will be copied from the old vehicle. If you define an ID for which no original vehicle exists, a new (blank) vehicle is allocated.

This behaviour can be modified using an engine_override, this allows changing the properties of vehicles defined in other NewGRFs instead of allocating a new vehicle.

TTDPatch / Engine pool disabled

Each new vehicle has to replace an existing vehicle. If multiple NewGRFs try to replace the same vehicle, the last NewGRF loaded 'wins'. This page contains a list of valid vehicle IDs for each vehicle type, look in the 'NML ID' column. Note that IDs are not bound to a specific sort of vehicle (e.g. monorail wagons) but to a feature (e.g. trains, road vehicles).


In general, you should take the following steps:

  • If your NewGRF is intended as a complete replacement for the default vehicles, disable the relevant default vehicles using disable_item.
  • Re-use IDs of existing vehicles as much as possible.
  • If your NewGRF uses IDs outside of the normal range (for example, because you there are more vehicles than slots available), let your code check if dynamic_engies is enabled. If not, skip the vehicles outside the normal range (using an if-statement) and make sure that the remaining vehicles allow for reasonable gameplay. It is recommended to issue a warning to the user about this. Alternatively, it is also possible to disable your entire NewGRF. If you don't do this check and dynamic_engines is off, OpenTTD may disable your NewGRF with the somewhat cryptic message 'Attempt to use invalid ID', which will likely lead to bug reports about your NewGRF and/or your OpenTTD.