The m4nfo User manual and Technical Report

Text handling

Defining and handling texts for properties and callbacks

Introduction

Due to the rather complicated handling of texts in TTD, this is a bit complicated in m4nfo too. In TTD, and hence in m4nfo, texts may appear in many different locations and in many different contexts. Firstly, there are texts appearing in property functions, like names for vehicles, houses, stations, objects, ... Secondly, there are newGRF-related texts, both temporary and persistent, and at last, there are original TTD texts which may be changed by newGRFs in TTDPatch.

Properties

Text function Description
defgrftext(<Text-ID>,<Language-ID>,{<String>})Define newGRF-related texts
grftext(<Text-ID>)Reference text as callback result
deftxt(<String>,{<Language-ID>,<String>})Allocate text to be used in property functions
reftxt(<String>) / reftxtcb(<String>)Reference allocated text as text-ID or callback
makettdtext(<Text-ID>,<Language-ID>,{<String>})Set original TTD texts
subtext(<Text-ID>)Use allocated text as subtext in other text

Description

defgrftext(<Text-ID>,<Language-ID>,{<String>})

This function defines and allocates newGRF-related texts like cargo sub-type texts, locomotive help texts, error messages, etc. Its first parameter must be a text-ID, starting with "0" for the first text to be defined. More texts should be using consecutive IDs.

The second parameter is a language-ID. At the time being, following language-IDs may be used:

US US English   UK British English   D German   F French   E Spanish
RUS Russian SRB Serbian NL Dutch H Hungarian I Italian
S Swedish PL Polish HR Croatian N Norwegian CZ Czech
  ALL default (usually English)

Please note that this function may only use one language, but more than one text string. In fact, you'll need to use one defgrftext() function per language.

This function is used in connection with grftext() and callbacks CB_TEXT (additional text in purchase menu) and CB_TSFX (cargo sub-type text).

Example 1 (cargo sub-texts for piece goods):
defgrftext(TSF_PGOOD,I,
	" (imballati)"," (container)",
	" (compensato)"," (liquido)",
	" (macchinari)"," (frigorifero)",
	" (automobili)"," (pallettizzata)",
	" (paglia)"," (birra)", " (vino)"
)

Example 2 (error messages):
define(ATT_OK,0x400)
define(ATT_VAN,0x60)
define(ATT_CAR,0x61)
define(ATT_REQLDCAR,0x62)
...

defgrftext(ATT_VAN,ALL,
	" (freight car cannot be attached)",
	" (coach cannot be attached)",
	" (long-distance cars required)",
	...
)

grftext(<Text-ID>)

This function references a text-ID, defined by defgrftext() and returns a callback result. It should be used in connection with callbacks CB_TEXT and CB_TSFX (see above). In GRF version 8 it is possible to return NONE to display no text at all.

Example (cargo sub-texts for piece goods):
def(3) refitted(
	grftext(TSF_BRCK) if(0) // "bricks"
	grftext(TSF_PLYW) if(1) // "plywood"
	grftext(NONE) else	// no text
)

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

deftxt(<String>,{<Language-ID>,<String>})

This function allocates text for feature properties like 'names' (classname, objectname) for features like objects and houses. It is used to define one text string in many languages in connection with reftxt() to return a text-ID, or reftxtcb() to return a callback result in connection with CB_TEXT.

First parameter of this function is a label which is mutually used by its fellow functions reftxt() and reftxtcb(). The label is initially defined by deftxt() and undefined at the end of the source file.

Example (object class and name):
deftxt(molelight,
	US, "Mole lights",
	UK, "Mole lights",
	D, "Molenbefeuerung",
	F, UTF8 "Feux de jetée",
	E, "Luces de muelle",
	I, "Luci del molo"
)

defineobject(_LIGHTS,
	...
	objectname(molelight)
	climate(TEMPERATE, ARCTIC, TROPIC)
	size(1,1)
	price(80)
	timeframe(1.1.1880 .. 1.1.2050)
	...
)

In case you want to use labels in distributed source files, this is possible in a limited way. First, you'd have to define all the labels you want to access from a successive file, in a previous file. And secondly, you may not define any more labels in one of the successor files, except after a prior call to function import() (once per file), else all the newly defined text-IDs would get mixed up with those already defined in previous files.

Example (preparing labels to be used in successive files):
deftxt(molelight,
	US, "Mole lights",
	UK, "Mole lights",
	D, "Molenbefeuerung",
	F, UTF8 "Feux de jetée",
	E, "Luces de muelle",
	I, "Luci del molo"
)

export({molelight})

Example (using labels in successive file):
import()

defineobject(_LIGHTS,
	...
	objectname(molelight)
	climate(TEMPERATE, ARCTIC, TROPIC)
	size(1,1)
	price(80)
	timeframe(1.1.1880 .. 1.1.2050)
	...
)

reftxt(<String>) / reftxtcb(<String>)

Both functions reference previously defined text strings by its label. The first one returns a Text-ID and the second one returns a callback result. Most of the time, reftxt() is only used internally. E.g., in the above example, it is used by function objectname().

Function reftxtcb() is very similar to grftext(), but in contrast to defgrftext()/grftext(), the single text string defined by a previous deftxt() may consist of many languages.

Example (error messages):
deftxt(warn_coast,
	US, T_BLACK "Mole with stairs cannot be built on coast tiles.",
	UK, T_BLACK "Mole with stairs cannot be built on coast tiles.",
	D, UTF8 T_BLACK "Mole mit Treppe kann nicht auf Küstenfeldern gebaut werden.",
	F, UTF8 T_BLACK "Une jetée avec des escaliers ne peut pas être construite sur la côte.",
	E, T_BLACK "Muelle con las escaleras no se puede construir en la costa.",
	I, UTF8 T_BLACK "Non si puó costruire un molo con scale sulla costa."
)

def(62) callback(
	reftxtcb(warn_coast) if(CB_TEXT)
	ref(61) else
)

makettdtext(<Text-ID>,<Language-ID>,{<String>})

This function is used to modify or translate original TTD text strings given by their text-IDs. See list of text IDs in the nfo/grf Technical Reference for a list of available strings. Please note that modifying original text strings does not work in OpenTTD.

Example (modifying TTD strings, renaming "ship depot"):
makettdtext(0x3806,ALL,"Floating dock")
makettdtext(0x3806,D,"Schwimmdock")
makettdtext(0x3806,F,"Dock flottante")
makettdtext(0x3806,E,"Dique flotante")

subtext(<Text-ID>)

This function references a text string from a previous defgrftext() and allows to insert it into another defgrftext(). This saves memory and text-IDs, if properly laid out.

Example (use of sub-strings):
defgrftext(0xAC,ALL,
	"Track class: ",
	" (branch line)",
	"ank locomotive",
	"freight service", 
	"Axle scheme: ", 
	"Builder: "
)

define(_TRACK,subtext(0xAC)) // track class
define(_DBNN,subtext(0xAD)) // (branch line)
define(_TANK,subtext(0xAE)) // (t)ank engine
define(_FRS,subtext(0xAF)) // freight service
define(_AXLE,subtext(0xB0)) // Axle scheme:
define(_BUILDER,subtext(0xB1)) // Builder

defgrftext(TLH_BR92,ALL,
	T_BLACK _AXLE T_LORANGE "E   "
	T_BLACK _BUILDER T_LORANGE "Union" CRLF
	T_BLACK _TRACK T_LORANGE "A/B" _DBNN CRLF
	CRLF T_LGREEN
	"Universal t" _TANK " for basic passenger and " _FRS "."
)

Note how an ordinary macro is used here to avoid repeated insertion of the correct subtext() function call and parameter into lengthy sources.

Of course, it is also possible to introduce local macros to define and reference text strings:

Example (use of sub-strings):
define(moreinfo,0xAC)
...
defgrftext(moreinfo,ALL,
	"Track class: ",
	" (branch line)",
	"ank locomotive",
	"freight service", 
	"Axle scheme: ", 
	"Builder: "
)

define(_TRACK,subtext(moreinfo)) // track class
define(_DBNN,subtext(moreinfo + 1)) // (branch line)
define(_TANK,subtext(moreinfo + 2)) // (t)ank engine
define(_FRS,subtext(moreinfo + 3)) // freight service
define(_AXLE,subtext(moreinfo + 4)) // Axle scheme:
define(_BUILDER,subtext(moreinfo + 5)) // Builder