The m4nfo User manual and Technical Report

Functions for Rail types

Using functions for rail types

Introduction

In m4nfo, rail types are using only two types of functions:

Functions for sprite layout definition

Format

The sprite layout for rail types is very simple:

spriteset(<number>)

Example 1 (defining rail type features):
def(6) spriteset(0) // level crossing open
def(7) spriteset(1) // level crossing closed

Functions for rail type performance

These functions are used to evaluate game-intrinsic variables, and make them accessible to the rail type's activation function.

Function Description
depotage(<block>)Depot age in years (since m4nfo_railtypes r13)
depotdate(<block>)Depot construction date (since m4nfo_railtypes r13)
displaymode(<block>)Set display mode for custom signal sprites
gatesclosed(<block>)Level crossing status: "0" = open (or not a crossing), "1" = closed.
terrain(<block>)Terrain type: NORMAL (0), DESERT (1), RAINFOREST (2), SNOW (4, on or above snowline).
townzone(<block>)Town zone of level crossing or depot (since OTTD r23866)
tunneltype(<block>)Type of tunnel (0 = plain portal) (since OTTD r23952)
signal_type(<block>), signal_variant(<block>), signal_state(<block>), signal_restricted(<block>), signal(<block>)Custom signal sprites information (since OTTD r24367)
randomrel(0, <randombit> <List::ref()>)Get random reference

depotage(<block>) / depotdate(<block>)

These two functions are used to check a depot's age in years and/or a depot's building date:

Example 1 (check a depot's age):
def(1) depotage(
	ref(7) if(>20) // older than 20 years
	ref(6) else
)
Example 2 (check a depot's building date):
def(2) depotdate(
	ref(7) if(<date(1-1-1970)) // built before 1970
	ref(6) else
)

displaymode(<block>)

This function returns the actual display mode associated with custom signal sprites. In this way, it is possible to use different sprites for the signal in question, depending on the display mode (on map, or in the GUI window).

ValueMeaning
DP_VIEWPORTSignal is drawn in a viewport, i.e. on the map
DP_SIGNALGUISignal is drawn in the signal GUI. The returned sprite set must still have 8 sprites, but OpenTTD will only use the 7th sprite, so all other sprites can be empty.

All other values are reserved and must not be used.

This feature is only available in OTTD since r24367.

townzone(<block>)

This function returns the town zone, from centre to outmost, where the current level crossing or depot is situated. Returned values are as follows:

ValueLabelMeaning
4TZ_CENTREInnermost zone, street lights
3TZ_COMMERCIALTrees
2TZ_RESIDENTIALPaved roads
1TZ_PERIPHERYOuter zones, plain roads
0TZ_OUTSKIRTS

Please note that smaller towns might have fewer zones.

signal_type(<block>), signal_variant(<block>), signal_state(<block>), signal_restricted(<block>), signal(<block>)

These functions return extra information about custom signal sprites.

Function
Value Description
signal_type(<block>)
0Normal block signal
1Entry pre-signal
2Exit pre-signal
3Combo pre-signal
4Two-way path signal
5One-way path signal
signal_variant(<block>)
0Light signal
1Semaphore signal
signal_state(<block>)
0Red signal
1Green signal
signal_restricted(<block>)
0no routing restrictions
1routing restrictions attached

All other values are reserved and must not be used in "trunk" OpenTTD. The JGR PatchPack includes custom features to support both programmable (signal type 6) and restricted signals with custom graphics.

Function signal() returns a combined value for a signal's variant, type and state:

  Light signals Semaphore signals
descriptionlabel value labelvalue
block BLK_LIT_RED0 BLK_SEM_RED64
BLK_LIT_GRN128 BLK_SEM_GRN192
entry ENT_LIT_RED1 ENT_SEM_RED65
ENT_LIT_GRN129 ENT_SEM_GRN193
exit EXT_LIT_RED2 EXT_SEM_RED66
EXT_LIT_GRN130 EXT_SEM_GRN194
combo CMB_LIT_RED3 CMB_SEM_RED67
CMB_LIT_GRN131 CMB_SEM_GRN195
PBS 2-way PBS2_LIT_RED4 PBS2_SEM_RED68
PBS2_LIT_GRN132 PBS2_SEM_GRN196
PBS 1-way PBS1_LIT_RED5 PBS1_SEM_RED69
PBS1_LIT_GRN133 PBS1_SEM_GRN197

Examples

Example 1 (handling level crossings):
def(1) gatesclosed(
	ref(7) if(1) // closed
	ref(6) else  // open
)
Example 2 (town zones):
def(2) townzone(
	ref(4) if(TZ_PERIPHERY)
	ref(5) if(TZ_RESIDENTIAL)
	ref(6) if(TZ_COMMERCIAL)
	ref(7) if(TZ_CENTRE)
	ref(8) else  // TZ_OUTSKIRTS
)
Example 3 (custom signals):
def(3) signalvariant(
	ref(5) if(1) // semaphores
	ref(6) else  // light signals
)
Example 4 (custom signals):
def(4) signal(
	ref(0) if(PBS2_SEM_RED) // PBS german semaphores 2-way RED
	ref(2) if(PBS1_SEM_RED) // PBS german semaphores 1-way RED
	ref(1) if(PBS2_SEM_GRN) // PBS german semaphores 2-way GREEN
	ref(3) if(PBS2_SEM_GRN) // PBS german semaphores 1-way GREEN
	ref(0) else
)

randomrel(<trigger>, <randombit> <List::ref()>)

Unlike the performance functions above, whose results are always determined by a predictable decision, one can also use random functions to pick one of several graphics sets or callback results.

Description

trigger

There are no triggers for railtypes, hence you must always define 0 (or CONSTRUCT).

randombit

Setting randombit determines the first bit to be re-randomized, as well as basing the random graphics on. The total number of bits used is the 2-logarithm of the number of references used, e.g., for 16 references, 4 bits are used.

Rail tiles have 2 pseudo random bits, based on tile location.

List::ref()

The number of referenced sets to choose from must be a power of 2, i.e. 2, 4, 8, 16 etc.

Example (old/modern level crossing transition in-game):
define(_YEAR,1959) // transition year

def(12) randomrel(0,1,ref(10),ref(10),ref(10),ref(11)) // 25%
def(13) randomrel(0,1,ref(10),ref(10),ref(11),ref(11)) // 50%
def(14) randomrel(0,1,ref(10),ref(11),ref(11),ref(11)) // 75%

def(5) year(
	ref(10) if(<_YEAR)               // all old
	ref(12) if(_YEAR .. _YEAR+4)     // 25% modern
	ref(13) if(_YEAR+5 .. _YEAR+9)   // 50% modern
	ref(14) if(_YEAR+10 .. _YEAR+14) // 75% modern
	ref(11) else                     // all modern
)