m4nfo train properties are based on plain nfo's action0 properties. Most of them are mapped in a straightforward way, but some of m4nfo's train property functions are based on custom calculations, or based on using more than one nfo property.
| m4nfo function | nfo property | custom |
| airdrag | 0x20 | |
| aiusage | 0x18 + 0x08 | yes |
| callbacks | 0x1E | yes |
| capacity | 0x14 | |
| cargoaging | 0x2B | |
| cargoclasses | 0x28 + 0x29 | yes |
| cargolist | 0x2C | |
| cargomask | 0x1D | |
| cargotype | 0x15 | |
| climate | 0x06 | |
| effort | 0x1F | yes |
| enginetype | 0x19 + 0x0E | yes |
| flags | 0x27 | |
| intro | 0x00 + 0x2A | yes |
| loadamount | 0x07 | |
| modlife | 0x04 | |
| newgraphics | 0x12 | |
| power | 0x0B | yes |
| price | 0x17 | |
| refitcost | 0x1C | yes |
| reliability | 0x02 | |
| retire | 0x26 | |
| runningcost | 0x0D | |
| seteffect | 0x22 | |
| shortening | 0x21 | |
| sortbefore | 0x1A | |
| speed | 0x09 | yes |
| railtype | 0x05 | |
| userdata | 0x25 | |
| vehlife | 0x03 | |
| weight | 0x16 + 0x24 | yes |
| Flag label | Bit | Value |
| TILTING | 0 | 0x01 |
| 2CC | 1 | 0x02 |
| DEMU | 2 | 0x04 |
| FLIPPING | 3 | 0x08 |
| AUTOREFITTING | 4 | 0x10 |
| CARGOMULTIPLIER | 5 | 0x20 |
| NOBRKEFFECT | 6 | 0x40 |
| STACKEDSPRITES | 7 | 0x80 |
m4nfo combines two different nfo properties for AI handling: the AI 'engine rank' (0x18) and the AI special flag (0x08), which is set if the vehicle is 'optimized' for passenger service, i.e. the AI won't use it for other cargo.
Enabling callbacks in plain nfo means to set bits in property (0x1E). Unfortunately, these bits have no numerical relation to the corresponding callback values returned by nfo's variable (0x0C). In m4nfo, both property function callbacks() and performance function callback() are using the same callback labels.
This m4nfo property function combines the two nfo properties for cargo class inclusion (0x28) and exclusion (0x29).
Plain nfo handles tractive effort as a coefficient. It sets what fraction of the vehicle weight is equal to the maximum tractive effort. The default value of 0x4C represents a friction coefficient of ยต = 0.3.
m4nfo property function effort() takes a real tractive effort value, given either in [kn, KN, kp, KP, lbf, LBF], and re-calculates the nfo coefficient by taking into account the engine's weight.
If the engine's weight has not been specified at the time of this function's call, error message ERR_NOWEIGHT is shown.
This m4nfo property function combines the two nfo properties for engine traction type (0x19), either steam, diesel, electric, monorail or maglev, and an appropriate running cost base (0x0E).
Each traction type is combined with its appropriate cost base table, i.e. traction type 'steam' is combined with the cost base table for steam engines (0x4C30), etc.
Unline nfo, which again uses two properties for the introduction date (0x00 and 0x2A), this m4nfo function takes an introduction date in different formats and re-formats it for the appropriate nfo properties, i.e. if the given year is after 1920, only nfo property 0x00 will be used.
Plain nfo allows to specify the power of an engine in 'hp' only, but m4nfo allows to use either [hp, HP, ps, PS, kw, KW].
In m4nfo, the refit cost can be given either as a Byte value, with its maximum value "255" correlating to 50% of the vehicle's purchase price cost base (this is the original nfo behaviour), or directly as a percent value.
Plain nfo allows to specify the speed of an engine in units of mph*1.6, i.e. approximately km/h only, but m4nfo allows to use either [km/h, KM/H, mph, MPH].
Again, plain nfo uses two properties for a vehicle's weight: (0x16) as a Byte value may only represent a vehicle's weight up to 255 tons. And only by using property 0x24, which represents the 'high byte' of the vehicle's weight, larger weights can be specified.
m4nfo's function makes this limitation obsolete and, in addition, makes available the weight value for internal tractive effort calculations.
m4nfo train performance functions are based on plain nfo's Variational Action2 variables. Again, most of them are mapped in a straightforward way, but some of m4nfo's train performance functions are based on custom calculations, or based on use of more than one nfo variable.
Please note that functions return either Byte, Word or Dword values, depending on the context they're used in.
| m4nfo function | nfo var | Byte | Word/Dword |
| ageindays | 0xC0 | 85/86 C0 00 FF FF | |
| ageinyears | 0x24/0x49 | 89/8A (custom) | |
| animation | 0x46 | 82 46 08 03 (*) | |
| articulated | 0x10 | 81 10 00 FF | |
| autoreplace | 81 10 00 FF | ||
| callback | 0x0C | 81 0C 00 FF | 85 0C 00 FF FF |
| cargo | 0xB9 | 81 B9 00 FF | |
| clrubit | 0x42 | (custom) | |
| cnst_cargo | 81/82 42 08 FF | ||
| cnst_cargoclasses | 81/82 42 00 FF (*) | ||
| cnst_refit | 81/82 42 10 FF | ||
| current_capacity | 0xBA | 85 BA 00 FF FF | |
| current_load | 0xBC | 85 BC 00 FF FF | |
| current_speed | 0xB4 | 85 B4 00 FF FF | |
| curvature_front | 0x45 | 81 45 00 0F | |
| curvature_back | 81 45 08 0F | ||
| curvature_triplet | 81 45 10 0F | ||
| daycounter | 0xC9 | 81 C9 00 FF | |
| daysintravel | 0xF0 | 85 F0 00 FF FF | |
| dayspastservice | 0x23/0x4B | (custom) | |
| direction | 0x9F | 81 9F 00 FF | |
| displaymode | 0x10 | 81 10 00 FF | |
| else | n/a | ||
| flipped | 0xC8 | 81/82 C8 00 FF | |
| getubits | 0x42 | (custom) | |
| getubyte | (custom) | ||
| idcount | 0x60 | 81/82 60 <par> 00 FF (*) | |
| incline | 0x9E | (custom) | |
| indepot | 0xE2 | 82 E2 00 FF | |
| islast | 0xDA | 81 DA 00 FF | |
| lastmaintenance | 0x92 | 85/86 92 00 FF FF | |
| lastservicedate | 0x4B | 89/8A 4B 00 FF FF FF FF | |
| lastserviceyear | (custom) | ||
| loadtime | 0x90 | 85 90 00 FF FF | |
| maxspeed | 0x98 | 85 98 00 FF FF | |
| property | 0x10 | 81 10 00 FF | |
| randombits | 0x5F | 81/82 5F 08 FF (*) | |
| randomtriggers | 81/82 5F 00 FF (*) | ||
| rcost_cargotype | 0x10 | 81 10 00 FF | |
| rcost_cargosubtype | 81 10 08 FF | ||
| rcost_cargoclass | 81 10 10 FF (*) | ||
| refitted | 0xF2 | 81/82 F2 00 FF | |
| reliabilitystate | 0xCE | 85 CE 00 FF FF | |
| reversed | 0xFF | 82 FF 00 01 | |
| servint | 0x94 | 85 94 00 FF FF | |
| setubit | 0x42 | (custom) | |
| setubyte | (custom) | ||
| shorter | 0xF3 | 81 F3 00 FF | |
| soundevent | 0x10 | 81 10 00 FF | |
| speedlimit | 0xF4 | 86 F4 00 FF FF | |
| spritelayer | 0x10 | 81 10 08 FF | |
| spritestack | (custom) | ||
| veh_cargoclass | 0x47 | 81 47 10 FF (*) | |
| veh_cargotype | 81/82 47 00 FF | ||
| veh_cargoweight | 81 47 08 FF | ||
| veh_getinfo | 0x61 | (custom) (*) | |
| veh_getinfoabs | (custom) (*) | ||
| veh_id | 0xC6 | 81/82 C6 00 FF | |
| veh_ispowered | 0xFE | 81 FE 00 05 | |
| veh_marketinfo | 0x48 | 81/82 48 00 07 | |
| veh_maypowered | 0xFE | 81 FE 00 06 | |
| veh_num | 0x40 | 81/82 40 10 FF | |
| veh_posabs | 0x40 | 81/82 40 | |
| veh_posart | 0x4D | 81/82 4D | |
| veh_posrel | 0x41 | 81/82 41 | |
| veh_railtype | 0x4A | 81 4A 00 FF | |
| veh_status | 0xB2 | 81 B2 00 FF | |
| veh_zpos | 0x9E | 81/82 9E 00 FF | |
| yearbuilt | 0x49 | 85/86 49 00 FF FF | |
(*) - may be adjusted by use of auxiliary function shiftmask().
(custom) - these functions are using more than one TTD variable and/or make use of auxiliary functions shiftmask() and/or engine().
These functions allow manipulation of plain nfo's vehicle 'user bits' (property 0x25) in a most handy way, by splitting the user data area into a range used for bit setting and checking, and a second part for writing and reading numerical values. Both are handled independently, and need initialisation by auxiliary function allocuserdata()
m4nfo train callbacks are based on plain nfo's callbacks. They're all mapped in a straightforward way.
Callbacks from the first section of the table below have to be enabled by property function callbacks(), but those from the second section do not need to be: they're always active and will be used automatically if needed.
idcount(<Veh-ID>, <block>)
incline(<block>)
veh_getinfo([-]<Byte>, <function>, <block>),
veh_getinfoabs(FRONT | BACK, <Byte>, <function>, <block>>)
veh_posrel/veh_posabs(FRONT | BACK | MOD2 | MOD3 | MOD4 | MOD6, <block>)
yearbuilt(<block>)
| m4nfo callback | nfo callback |
| CB_ARTI | 0x16 |
| CB_WLEN | 0x11 |
| CB_LOAD | 0x12 |
| CB_POWR | 0x10 |
| CB_RCAP | 0x15 |
| CB_RCOL | 0x2D |
| CB_SOUND | 0x33 |
| CB_TSFX | 0x19 |
| CB_ARVS | 0x34 |
| CB_ATAC | 0x1D |
| CB_PROP | 0x36 |
| CB_RCOST | 0x15E |
| CB_STOP | 0x31 |
| CB_TEXT | 0x23 |
| CB_32DAY | 0x32 |
Callback helper functions are based on m4nfo's function cbr() which returns a parameter as a callback return value.
| m4nfo function | definition |
| addveh | cbr($1) |
| addvehrev | cbr($1+0x80) |
| attach | cbr($1) |
| effect | cbr($1) |
| seteffort | (custom) |
| autorefit | cbr(eval($1 | 16384)) |
| refsnd | cbr(_S_$1) |
| grftext | cbr($1) |
| reftxtcb | (custom) |
In nfo, randomized Action2s are used to either randomize the vehicle (0x80) based on itself, based on the first vehicle of its consist (0x83), or based on any vehicle in the consist (0x84).
| m4nfo function | nfo random Action2 type | randomrel | 0x80 | randomabs | 0x83 | randomcount | 0x84 |
| m4nfo trigger | nfo trigger | bit | value | CONSTRUCT | n/a | 0 | LOAD | 0 | 1 | SERVICE | 1 | 2 | UNLOAD | 2 | 4 | ANYLOAD | 3 | 8 | CB32 | 4 | 16 | ALLTRIGGERS | 7 | 128 |
| m4nfo function | nfo var | Byte | Word |
| anim_counter | 0x0A | 81 0A | 85 0A |
| cargotranslationtable | General Action0 | 00 09 | |
| checkparameter | 0x7F | 81 7F | 85 7F |
| incrbasecost | General Action0 | 00 08 | |
| grf_override | General Action0 | 00 11 | |
| setproperties | Action0 | 00 xx |
Each entry of a cargo translation table represents a corresponding cargo which is meant when using its ID in various cargo-related functions. E.g., given this cargo translation table:
cargotranslationtable(
{"PASS"}, {"COAL"}, {"MAIL"}, {"OIL_"},
{"LVST"}, {"GOOD"}, {"GRAI"}, {"WOOD"},
{"IORE"}, {"STEL"}, {"VALU"}, {"FOOD"},
{"PAPR"}, {"FRUT"}, "FISH", "WOOL,
"LIME", "SAND", "GLAS", "WDPR",
"DYES", "FERT", "OLSD", "RFPR",
"VEHI", "PETR", "AORE", {"WATR"},
"BDMT", "FICR", "TOUR", "CERE",
"MILK", "SGBT", "CLAY", "MNSP",
"SCMT", "POTA", "SULP", "FMSP",
"ENSP", "GRVL", "BEER", "RCYC"
)
To support distributed source code, the list of thus defined cargo-IDs is written to an intermediary file named "m4_ctt":
define({PASS},0)
define({COAL},1)
define({MAIL},2)
define({OIL_},3)
define({LVST},4)
define({GOOD},5)
define({GRAI},6)
define({WOOD},7)
define({IORE},8)
define({STEL},9)
define({VALU},10)
define({FOOD},11)
define({PAPR},12)
define({FRUT},13)
define({FISH},14)
define({WOOL},15)
define({LIME},16)
define({SAND},17)
define({GLAS},18)
define({WDPR},19)
...
This file needs to be included into other source files referencing any of those newly declared cargo types, by using function import_ctt(). When using a dependency-tracking build utility ("Make"), you might set up a dependency for file "m4_ctt" to assure consistency.