The m4nfo User manual and Technical Report

Custom Features

Using non-standard features provided by patchpacks and/or forks

Content



Introduction

In addition to the official OpenTTD implementation ("trunk") there exist a couple of "patchpacks" implementing non-standard game additions and even non-standard newgrf features, namely the JGR Patch Pack (JGRPP), or the New Map Features (NMF). The first one provides an interface for seamless inclusion of non-standard newgrf additions which are supported in this very patch pack.

For this to work, JGRPP introduces a "feature test" mechanism to be used also on implementations which do not use either this test mechanism nor any of its newgrf additions. It also provides a "property mapping" mechanism, to define non-standard property functions and include them into the set of existing "trunk" properties.

As of today, JGR's patchpack provides some more custom features (special real sprites, nfo action5) than implemented in the current m4nfo release. These will be implemented in m4nfo at a later date.

Supported custom features

At the time being, following custom features for JGRPP are handled in m4nfo:

Features

Custom feature Description Custom property
PROP_MAPPING defines a property mapping no
STAT_TRACKTYPE considers track type in station building menu no
STAT_BRIDGES sets minimum height for bridges over stations yes
STAT_PILLARS disallows specified bridge pillars on stations
BRDG_MORE allows for more bridges (16 instead of 13) no
BRDG_ICONS sets menu icons for (extra) bridges yes
BRDG_PILLARS disallows specified bridge pillars
BRDG_AVAIL makes bridges unavailable for towns or AIs
RAIL_PROGRAM Railtype custom signal sprites (programmable) yes
RAIL_RESTRICT Railtype custom signal sprites (restricted)
ROAD_EXTRAFLAGS Extra road/tram type flags yes

<PROP_MAPPING>

By using PROP_MAPPING, additional properties, e.g. for stations and bridges can be included. This is done by defining them inside m4nfo's grfinit() function by user-defined functions (see examples). Prior to that, a test should be carried out to assure that the property mapping process is available at all, using function feature_test().

<STAT_TRACKTYPE>

This custom feature allows to check the track type for a yet to be build station tile. Thus, it can be used to decide whether to allow building of certain station tiles, depending on the given track type. Use function tinfo_tracktype() for querying the track type.

<STAT_BRIDGES>

The user-supplied function for this custom feature defines minimum clearances required for a bridge for each of the eight tile types of this station (or zero to not allow any bridge). Values are given in "height level" units (1 level == 8px), and need not to be the same for the tile types in question for both x- and y-direction.

<STAT_PILLARS>

The user-supplied function for this custom feature decribes which pillars are not allowed on each of the eight tile types of this orstation. Values are given as flag bits in each of the 8 parameter bytes:

Bit Value Description
0WESTpillar on west corner
1SOUTHpillar on south corner
2EASTpillar on east corner
3NORTHpillar on north corner
4NORTHEASTpillar on north-east edge
5SOUTHEASTpillar on south-east edge
6SOUTHWESTpillar on south-west edge
7NORTHWESTpillar on north-west edge
STAT_NOPILLARSpillars/nopillars on all corners/edges
BRDG_ALLPILLARS

<BRDG_ICONS>

The user-supplied function for this custom feature property allows to set the menu icon for a bridge type, being displayed when constructing a bridge. Parameters are of type Word, first one for the bridge menu graphics sprite and the second one for its recolour sprite.

<BRDG_PILLARS>

The user-supplied function for this custom feature property allows to define pillars present for each bridge sprite table. It consists of 6 pairs of pillar flags, for bridge tables 0 .. 5. Each pair consists of x-direction and y-direction flags, with each set of flags being one Byte, see table of STAT_PILLARS above.

<RAIL_PROGRAM>

This user supplied property function enables performance and activation functions for railtype custom signal sprites for programmable pre-signals. Associated signaltype value is 06. Parameter is "1" to enable, and "0" to disable the feature.

<RAIL_RESTRICT>

This user supplied property function applies to performance and activation functions for custom signal sprites. When enabled by supplying "1" as its parameter, function signalrestricted() will return "1" as well, if the signal is restricted., i.e. has a routing restriction mechanism attached. In addition, the "show electric signals using default graphics" client setting and signal post recolouring is not applied. This custom feature should only be enabled if performance and activation functions actually supply a different sprite when signalrestricted() returns the correct result.

<ROAD_EXTRAFLAGS>

This user supplied property function sets extra flags for this road/tram type by the given parameter. The format is:

Value Description
1AI/GS may not build this road/tram type
2Towns may not modify tiles of this road/tram type in any way
3Both limitations as above


Functions

Format

<feature> ::= [STAT_BRIDGES | STAT_PILLARS | STAT_TRACKTYPE | BRDG_ICONS | BRDG_PILLARS | BRDG_MORE ...]

<feature_version> ::= [1 .. n]

<feature_test> ::= {<feature> <feature_version>}

<mapping> ::= {<feature> <user_func>}

<property_mapping> ::= {<feature> <user_func>}

<fallback> ::= [0,1,2]

<feature_propertymapping> ::= {<mapping> <fallback>

Function Description
feature set feature to test for (see table above)
feature_version set version of feature to test for
feature_test install test for feature availability
mapping map user-defined function to newly available feature property
property_mapping mapping function for distributed source files (w/o grfinit())
feature_propertymapping mapping wrapper function to be used in grfinit()
fallback set fallback mode


feature_version(<min>[,<max>])

Sets min (and max) version of feature, with <min> ≥ 1, and <max> ≤ 65535. Custom feature version numbers are defined by the current JGRPP implementation. At the time being, the min version number is 1.

feature_test()

Installs test for availability of given feature. The test itself must be done by function skipif(), using variable FEATURE:

Example 1 (set custom feature property for bridge height in case feature is available):
skipif(1, FEATURE, !=, STAT_BRIDGES)
setproperties(WAYP0,
	bridge_height(3,3,3,3,3,3,3,3)
)

Be aware that you cannot use function setproperties() for multiple station/bridge IDs in combination with user-defined functions. Instead, setproperties() should be used inside a loop:

Example 2 (test and set custom feature property 'bridge height' for multiple IDs):
skipif(4, FEATURE, !=, STAT_BRIDGES)
forloop(X,{setproperties(WAYP{}X,
	bridge_height(3,3,3,3,3,3,3,3)
)},0 .. 3)

mapping(<feature>,<user-function>)

This function links a user-defined function to the custom feature property given. I.e., for custom feature 'bridge height' (STAT_BRIDGES) a freely chosen name like "bridge_height" might be specified, which will be used later to define the max bridge's height for station tiles. See examples above.

Be aware that custom feature property functions need different type and numbers for their parameters:

Custom feature Function parameter
STAT_BRIDGES 8 Bytes
STAT_PILLARS 8 Bytes
BRDG_ICONS 2 Words
BRDG_PILLARS 12 Bytes
BRDG_AVAIL 1 Byte (values 0,1,2)

Function mapping() is used as a parameter to function feature_propertymapping(), together with function fallback(). Apart from binding user-defined functions to allocated custom feature properties, it does all the other internal assignments needed. As such, function feature_propertymapping() should be part of grfinit(), i.e. only once present in a grf file.

Successful outcome of a mapping is checked by function skipif(), very much like the custom feature availability check above, but using variable MAPPING:

Example 3 (test mapping success and set bridge height and pillar positions for station):
skipif(1, MAPPING, !=, STAT_BRIDGES)
setproperties(ROOFS,
	bridge_height(2,2,2,2,2,2,2,2)
)

skipif(1, MAPPING, !=, STAT_PILLARS)
setproperties(ROOFS,
	bridge_pillars(0,0,NORTH+EAST+SOUTH+WEST,NORTH+EAST+SOUTH+WEST,
		STAT_NOPILLARS,STAT_NOPILLARS,STAT_NOPILLARS,STAT_NOPILLARS)
)

The feature mapping process also works for distributed source files. In this case, source files without the grfinit() function, making use of user-defined custom feature mapping functions, should use function propertymapping(), which other than function mapping() is lacking internal variable setup, but only instantiates the property mapping process..

fallback(<[0 | 1 | 2]>)

The fallback function specifies following modes:

Value Description
0default. Attempts to map an unknown custom feature property name are ignored. Use of the mapped property is ignored.
1attempts to map an unknown custom feature property name are ignored. Use of the mapped property is an error.
2attempts to map an unknown custom feature property name is an error.

Examples

Example 4 (grfinit() setup):
grfinit(GRF_NEWSTATIONS,
	grfname(ALL, "NewStations v0.7 05.05.2020")
	...
	grfparameter(
		grfsetting(
			settype(BOOL,0,0,1)
			setname(STR_PARAMETER)
			setdescription(STR_DESCRIPTION)
		)
	)
	feature_test(
		feature(PROP_MAPPING)
		feature_version(1)
	)
	feature_propertymapping(
		mapping(STAT_BRIDGES, {bridge_height})
		fallback(0)
	)
	feature_propertymapping(
		mapping(STAT_PILLARS, {bridge_pillars})
		fallback(0)
	)
)

Example 5 (use in distributed source file):
...

// prepare for custom feature "bridge_height"
property_mapping(STAT_BRIDGES,{bridge_height}) // set up user-supplied function

skipif(2, MAPPING, !=, STAT_BRIDGES)
forloop(X,{setproperties(X,
	bridge_height(1,1,1,1,1,1,1,1)
)},VOIDZ .. VOIDZ+1)

...