The m4nfo User manual and Technical Report

Ship callbacks

Using callbacks for ships

Introduction

This is an in-depth description of ship callbacks. More basic information about callbacks can be found here.

A 'callback' is a special action that TTDPatch 'calls' in order to modify various attributes of a feature (e.g., a ship) previously defined. An example being the modification of the speed of a ship or its capacity.

This is done by identifying the incidence and the possible type of a callback in the callback() function. Depending on the type of the callback, control is handed over eventually to a function which handles the callback, or lets it fail. In the latter case, the value previously set by the appropriate property function will be kept using.

This is a list of all available callbacks for ships. Please note, that not all of them need to be activated in the callbacks() property function during the ship's definition stage:

Callback Description
Callbacks needing activation
CB_LOAD Load amount
CB_RCAP Set refitted capacity
CB_RCOL Select color mapping for ship
CB_SOUND Set sound effect
CB_TSFX Show a suffix after the cargo type name
Callbacks always activated
CB_ARVS Autoreplace ship selection
CB_PROP Change ship properties
CB_RCOST Refit cost callback
CB_STOP Start/stop check
CB_TEXT Additional text in purchase screen
CB_32DAY 32-day callback

Description

CB_LOAD - load amount callback

This callback is used instead of property loadamount() when loading a game or re-arranging a ship in a depot (or when buying other ships). If the callback fails, the value of the property function is used instead.

Example (adjust for certain cargo):
def(1) callback(
	cbr(230) if(CB_RCAP) // capacity := 230 t
	cbr(46) if(CB_LOAD)  // load amount := 46 t/tick
	ref(0) else	     // graphics
)

CB_RCAP - refitted capacity callback

This callback is used when a ship is refitted, to find the new capacity. It allows return values up to 32511 (0x7EFF) units of cargo.

Function cargo() will return the new, climate-specific cargo type, or a value of "255" when only checking whether the ship is refittable.

Unlike regular refitted capacities (including those from CB_PROP), the return value is not subject to the usual division of capacities for cargoes other than passengers on ships and planes, instead the capacity is used exactly as returned by the callback. See example above.

CB_RCOL - select colour mapping for ship

This callback is called while drawing the ship. It should return the number of the colour mapping to be used on the ship's sprites. If the callback fails, the company colour of the owner is used.

Single colour maps are adressed by function getcolour(). For colour maps including the company colour, function getcolour_pluscc() is used, which needs to adress a block of 16 colour maps (one for each company colour). If the ship also has the 2CC flag set (two company colours), a block of 256 colour maps needs to be allocated. Alternatively, a return value of "0xC000" to use the default two-colour maps might be supplied.

The return value is cached to speed up sprite processing, and only updated via callback CB_32DAY (or when loading/starting a game or rearranging the consist).

Example (cargo recolouring):
def(_COAL) getcolour_pluscc(0)    // COAL
def(_IORE) getcolour_pluscc(0x10) // IORE, SCRP 

...

def(3) callback(
	ref(_IORE) if(CB_RCOL) // IORE, SCRP
	ref(0) else            // graphics
)

CB_RCOST - Refit cost callback

This callback can be used to override the refit cost of ships as specified in property function refitcost(). The callback will also be called in the purchase list, so you should either limit the used performance functions to what is available in the purchase list, or branch on the special purchase list cargo MENU.

Performance functions rcost_cargotype(), rcost_cargosubtype() and rcost_cargoclass() contain information about the target cargo type.

Return values: p>

As usual, function cbr() may be used for returning the callback value. In this case, use eval() to set bit14 as well (by OR-ing with 16384) if needed: cbr(eval(<value> | 16384)), or use callback helper function autorefit()

If the callback fails, the value specified by refitcost() is used.

This callback is only available since OpenTTD r23086.

CB_SOUND - Sound effect callback

This callback is called for all vehicles (and as generic callback for bridges), for various events that support playing sound effects. The type of event is checked by function soundevent().

The return value is a sound effect number. Values from 0 to 72 (decimal) are TTD's built-in sound effects, values beyond that refer to the sounds from defined by defsnd(). If the callback returns a failure code (not a callback result), the default TTD sound effect will be played. If the callback returns a sound number that is neither a TTD sound, nor a sound from action 11, nothing will be played.

EventMeaning
SND_STARTStart sound, called when leaving a station or depot
SND_TUNNELTunnel sound, called when vehicle enters tunnel
SND_BRKDOWNBreakdown sound, called when vehicle breaks down
SND_RUNNINGRunning sound, called once per engine tick, but no more than once per vehicle motion
SND_EFFECTShip visual effect generation (steam plume, diesel smoke, electric spark)
SND_RUN16Running sound, called every 16 engine ticks if in motion
SND_STOP16Stopped sound, called every 16 engine ticks if stopped (e.g. at signal/in station)
SND_LOADLoad/unload sound, called when consist loads or unloads cargo

For the running sounds, it is advisable to check the motion counter by function animation() and to only return a successful sound effect number every so many vehicle motion ticks. This way, the sounds will be played more frequently the faster the ship is. Alternatively, you can check and play the sound effect every so many engine ticks, so that it is played at a constant rate, or, of course, switch between both modes depending on vehicle speed.

CB_TSFX - cargo subtype display callback

This callback allows to display some text after the cargo name when refitting, and in the ship's capacity display. This is useful to distinguish several subtypes of a certain cargo, e.g. 'goods' could be cars, petroleum, sheet metal, etc.

The return value must use the function grftext() to reference a previously declared text string set by defgrftext() in the same .grf file.

Normally, you would use the ship's function refitted() to distinguish the various subtypes. During refitting, the callback is called with successively increased values until it returns "255". All the returned variations are then displayed as refitting options when in a depot, with all options that have the same cargo type and callback result (irrespective of refit cycle) grouped together in the same line.

Example (cargo subtext usage):
def(3) refitted(
	grftext(TSF_CONT) if(0) // containers
	grftext(TSF_REEF) if(1) // refrigerated
	ENDLIST else
)

def(4) callback(
	ref(3) if(CB_TSFX) // cargo sub-text
	ref(2) else        // graphics
)

CB_ARVS - Autoreplace vehicle selection

This callback is called whenever an old ship needs replacing. It returns the ship IDs to upgrade the current ship to. The ship variables are available as usual to decide which IDs would be appropriate to upgrade to.

The callback is repeatedly called, with the iteration number returned by function autoreplace(). The GRF file should return all possible IDs one by one, with the best ones listed first. TTDPatch will use the first ship from the list that is available to the player and has the required minimum reliability as set by the autoreplace switch, and abort the callback sequence at this point.

The callback sequence is also aborted when the returned ID is equal to the current ship ID. This is to prevent downgrading, and so you must take care to always return the ID of the ship for which the callback is called at the appropriate place in the sequence.

If the callback fails, i.e. if no suitable ID could be found by any of the callbacks in the generic chain, the ship is not upgraded, and is simply renewed instead. If an ID is available but the player lacks the cash to upgrade, TTDPatch waits for the cash to become available instead of either picking a worse engine or renewing the ship.

The callback is always used when defined, it needs not to be activated.

CB_PROP - Change ship properties

This callback allows modification of certain properties of a ship for which there exists no specific callback (like callback CB_LOAD). The associated function property() is needed to check for the specific property before being set by the callback.

The following properties are supported:

Property Function Min. versionOTTD rev
Cargo capacitycapacity()2.6 rev 1990r9828
Cargo aging periodcargoaging()n/ar22713
Priceprice()2.6 rev 1990r9806
Running cost factorrunningcost()2.6 rev 1510r9808
Speedspeed()2.5 beta 6r9671

Most properties will only change when the ship is bought, serviced (enters a depot), visits a dock or on loading of a saved game.

If the callback fails, the corresponding property value will be used. The callback is always used when defined, it needs not to be activated.

Example (capacity change):
def(8) property(
	cbr(230) if(_CAPACITY) // new capacity := 230 t
	cbfail() else         
)

def(9) callback(
	ref(8) if(CB_PROP)  // set capacity
	ref(0) else
)

CB_STOP - Start/stop check

This callback is called whenever a player (or the AI) tries to start or stop a ship. This is mainly useful for preventing ships from leaving the depot unless a given condition is met. To check whether a ship is being started or stopped, check the result of function veh_status().

The callback return value is a text-ID to use as second line of an error message, or "255" to indicate that the start/stop action should succeed. The callback is always used when defined, it needs not to be activated.

CB_TEXT - additional text in purchase menu

This callback is called when TTDPatch displays the stats of any ship in the purchase menu. The return value is a grftext(), previously defined by defgrftxt(), to be shown below all other stats. The callback is always used when defined, it needs not to be defined by property function callbacks() in the ship definition stage.

How many lines of text are available depends on the type of ship and its other properties, for instance the presence or absence of a "refittable to" line. Lines are wrapped automatically, or may be broken explicitly using the newline character 0D.

If cargo MENU is handled explicitly for a ship, then it must be used in the function chain for the purchase menu, not for the ship graphics.

CB_32DAY - 32-day callback

This callback is called every 32 game days for each ship, although not for all ships on the same day. The callback is always used when defined, it needs not to be activated.

The return value is a bit mask of the following bits:

BitValueMeaning
01Trigger CB32DAY
12Update colour map via callback CB_RCOL

If no bits are set, nothing happens.