The m4nfo User manual and Technical Report

Properties for houses

Defining properties of town buildings

Introduction

Town buildings (or simply 'houses') have IDs unique within each newGRF file, and in total each game can only have 255 IDs in TTDPatch and 512 IDs in OpenTTD, for all active newGRF files.

To define a new house and to allocate a house-ID, you must first define it by setting its property function substitutetype(). In case of a multi-part building, you'll have to supply as many parameters as there are house tiles in total, even if you're substituting the same old house-ID (see examples there). If you try to modify a house-ID whose substitutetype() property isn't set, your request is ignored, but not reported as an error, either.

House-IDs need not be set in order, so you can use the skipif() function to skip the definehouse() functions of those houses you don't currently need (for example those houses that don't appear on the current climate anyway). You are advised to do so in order to define as few IDs as possible, leaving space for other newGRFs. You don't need to skip all action property functions for a house-ID to disable it; skipping property function substitutetype() is enough.

All house properties are defined inside the definehouse() function. Depending on the type of building, different properties would have to be used. See the example. All properties are given by the property functions below.

Properties

Property function Description
anim_info(<Byte> [,LOOP])Animation information
anim_speed(<Byte>)Animation speed
anim_triggers(<List::trigger>)Animation triggers
callbacks(<List::Callback>)List of callbacks
cargotypes(<CargoType>*3)Accepted cargo types
cargowatch(<List::CargoType>)Cargo acceptance watch list
class(<Byte>)Class of building
climate(<List::Climate>)Climate availability
flags(<List>)House flags
goodsaccept([0 .. 8]) (*)Goods acceptance
housename(<String>)Text ID for the house's name
lifespan(<Byte>)Minimum life span in years
mailgen(<Byte>) (*)Amount of mail generation
mailaccept([0 .. 8]) (*)Mail acceptance
overridetype(<House-ID>) (*)House override type
passaccept([0 .. 8]) (*)Passenger acceptance
population(<Byte>)Number of inhabitants
probability(<Byte>)Relative probability of appearing
randomcolours(<Byte>*4) (*)Four random colours to use
rating(<Word>)LA rating decrease on removal
refresh(<Byte>)Periodic refresh multiplier
removalcost(<Byte>)House removal cost factor
size(1 | 2, 1 | 2)House size in x and y
substitutetype(<House-ID>, <House-ID> | <House-ID>*2 | <House-ID>*4) (*)House substitution type
timeframe(<Date> .. <Date>)House availability timeframe
townzone(<List::TownZone>)Town zone(s) the house can be built in

The number of parameters for some of the functions listed above, marked (*), are depending from the number of tiles a building is composed of. Most of the above functions take only one parameter, even for a multi-tile house. This is usually the case when a building is taken as a whole, e.g. function climate() always refers to the whole building, simply because in case of a multi-tile building, all tiles are necessarily for the same climate.

In each of these cases, information is only stored in the main tile of a building, which is generally its northern tile.

On the other hand, all tiles which might be handled 'independently', like amount of cargo acception or generation of mail may be given either one parameter, which is interpreted as if up to four equal parameters have been given, or you'll have to supply as many parameters as house tiles have been defined in substitutetype().

Example 1 (4-tile building):
mailgen(1)
Example 2 (4-tile building):
mailgen(1,0,0,1)

Description

anim_info(<Byte> [,LOOP])

The parameter specifies the number of animation frames to use. Maximum number of frames is 128. The optional second parameter LOOP may be added for looping animations.

A looping animation starts again from the first frame after showing the last frame. Non-looping animations stop after the last frame, leaving it on the screen. Both kinds of animations start automatically when the building is created. It's recommended to use callback CB_ACONTROL with non-looping animations, so they are played multiple times.

In case of multiple building parts, anim_info()'s extended parameter has to be quoted like this:

anim_speed(<Byte>)

This is the amount of time between switching frames.

The default value is 2, which means the switch occurs every 108 milliseconds. Increasing this value by one doubles the wait, i.e. 3 will cause 216 ms delay, while 4 will pause 432 ms, and so on. Values below 2 have the same effect as 2, so the default is the fastest possible setting. The maximum is 16, which means 1769 seconds (approx. half an hour) delay. Settings above this value may cause strange behaviour.

In game, animation speed can be set by using callback CB_ASPEED.

anim_triggers(<List::trigger>)

Parameter is a list of events that should trigger callback CB_ACONTROL, allowing to change the animation state:

TriggerMeaningHappens on
BUILThouse is builtall tiles
PERIODICPeriodic tile loopsingle tile
SYNCHRONSynchronised periodic tile loopall tiles

The synchronised periodic tile loop is called directly after the (unsynchronised) periodic tile loop of the northern tile.

callbacks(<List::Callback>)

For houses, the following callbacks can be defined by setting the corresponding parameter list:

CallbackMeaning
CB_ACONTROLPeriodically start/stop the animation
CB_AFRAMEDecide next animation frame
CB_ASPEEDDecide animation speed
CB_ASTAGEChange animation when construction state changes
CB_AUTOSLOPEAllow/disallow autosloping
CB_BUILDDecide whether the house can be built on a given tile
CB_CARGOAMOUNTDecide the cargos amounts accepted
CB_CARGOPRODCustom cargo production
CB_CARGOTYPESDecide the cargo types accepted
CB_COLOURDecide colour of building
CB_DESTRUCTTrigger destruction of building
CB_FOUNDATIONDecide if default foundations need to be drawn
CB_PROTECTConditional protection

Callbacks are being set only for the main tile of a building, i.e. the callback() function may be provided with only one parameter, see below.

Example 1 (4-tile building):
callbacks(CB_BUILD)
Example 2 (4-tile building):
callbacks({CB_BUILD, CB_FOUNDATION})

Note that you won't need brackets if a list consists of only one member.

cargotypes(<CargoType>*3)

There may be cases when you want your house to accept something other than the default types (passenger, mail, goods and food). This property allows you to do that. If this property is set to (255,255,255) (the default), the meaning of properties passaccept(), mailaccept() and goodsaccept() aren't changed, that is, they are the passenger, mail and goods/food acceptances, accordingly. If this property is set to any other values than (255,255,255), the given values must be climate-dependent cargo slot numbers. In this case passaccept() is the amount of acceptance of the first cargo type given, mailaccept() is the same for the second type and goodsaccept() is the same for the third type.

From GRF version 7 and above, the meaning of this property changes: instead of climate-dependent cargo slot numbers, you have to give climate-independent cargo IDs. If your newGRF has a cargo translation table, then this ID is the index in that table; otherwise, it's the cargo slot number. Acceptance of cargoes not currently present will automatically be disabled.

cargowatch(<List::CargoType>)

This function accepts a list of cargo types whose acceptance should be 'watched'. If your newGRF is version 7 or above, and has a cargo translation table, the given values are indexes in the table; otherwise, they are cargo slot numbers. When a cargo from this list is accepted by the current tile, callback CB_WATCH is called on all tiles of the building.

This property has no effect if the station2 structure in TTDPatch isn't present. The station2 structure is present if any of the following is true:


class(<Byte>)

Houses that were given the same class byte are considered to be in the same class. If you don't explicitly set this value, the type is considered to have no class (it won't be considered to be class 0). The scope of a class is the current newGRF file, so two types are never in the same class if they were defined by different newGRF files. Currently, this property affects performance functions classcount() and typecount() only.

This property is a per-tile one, you can set it for additional tiles as well. It's a better idea, however, to set it for the main tile only, since classcount()/typecount() count tiles, not buildings, and you may count multi-tile multiple times otherwise.

Please see example here how to specify class values when defining multiple houses in a single definehouse() function.

flags(<List>)

The parameter for this function is a list of flags, controlling this house's behaviour. Please note that changing flags for already constructed houses will have no effect.

Flags are being set for the main tile only, except the HASANIMATION flag, if additional tiles of multi-tile buildings need to be animated.

FlagMeaning
CHURCH This building is a church
FLATThis house can be built only on flat land (if clear, foundations are automatically displayed on sloped land)
HASANIMATIONAnimation flag, enable animation
HISTORICThis building appears during the generation of a town, but not later, i.e. will appear in random games, but new ones won't be built during the game. Useful for buildings that are intended to be historical.
PROTECTEDThis building is protected, i.e. towns an AI players won't remove it. Human players can still remove it, so you may need to set a high remove cost/rating to make them think twice.
RANDOMBITSRandom bits in callback CB_AFRAME
STADIUMThis building is a stadium
SYNCHRONIZEDSynchronized callback CB_ACONTROL (for multi-tile buildings)

Please note that only one church and one stadium can exist in a town; the town won't build buildings with the according flag set until an existing church or stadium is removed. (This can be done by either the town or a player)

goodsaccept/mailaccept/passaccept([0 .. 8])

Parameter for all three functions is an acceptance value, given in units of 1/8th which must not be larger than 8 eighths.

For goodsaccept(), positive values indicate that the building accepts goods, and negative values indicate acceptance of food or fizzy drinks (depending on the climate).

Note that the officefood switch may modify acceptance in the sub-arctic and subtropical climates.

All the above three values can be set independently for tiles of multi-tile buildings, since every tile is processed individually when determining what a station accepts.

housename(<String>)

The ID of the text that should be displayed in the land query window, either a TTD textid or a text set via deftxt(). As the house name is the same for all tiles of a multi-tile building, this function always uses only one parameter.

lifespan(<Byte>)

Towns are prevented from destroying the house if it hasn't yet reached the age given here. The default is 0, which means towns are free to remove the house any time they like. Please note that this setting doesn't prevent AI players from removing the house; only towns are affected. If you need to protect your building from AI players as well, you can set the PROTECTED flag, or use callback CB_PROTECT and use custom code to decide who (and when) is allowed to remove the building.

For this to operate consequently on multi-tile buildings, this function always uses only one parameter.

mailgen(<Byte>)

The higher the mail generation multiplier is, the more mail the building generates. For multi-tile buildings, mail generation is done on a per-tile basis, so you can specify different values for every tile, although distributing the generation equally between tiles is suggested.

overridetype(<House-ID>)

Setting this property makes this building appear instead of the given old TTD building type. Setting the property is ignored if the given old house type is already overridden. You can set this property more than once to override more old building types.

No new house of the overridden types will be built in towns.

This property works on a per-tile basis, so you override tiles of old multi-tile buildings individually, although the old type will still be built if you don't override its north tile.

population(<Byte>)

This function sets the amount by which the population of the town will be increased if this house is built. The higher this value is, the more passengers this building generates.

Since this value is only set for the building's main tile, you need to specify it explicitly when defining multiple houses by a single definehouse() function, see example.

Example 1 (4-part house):
population(20)
or
population(20, 0, 0 ,0)

Example 2 (4 single part houses):
population(20, 20, 20, 20)

probability(<Byte>)

This sets the relative probability of this house being built. Old TTD house types have a probability of 16, and this is the default for new types as well.

Increase (or better multiply) this value to make your building appear relatively more often, or decrease (divide) it to make it rarer. If you set this to zero, the house type never appears. The minimal useful value 1 means it's sixteen times less probable to build this type than a normal type, while the maximum setting of 255 means it's almost sixteen times more probable.

The probability is relative since the absolute probability depends on the count and probability of other houses as well: the more types are available (and the higher their probabilities are), the less the chance is that your type will be chosen.

randomcolours(<Byte>*4)

This specifies four colours used for random painting. Each value defines a color, the values are the same as in the default recolour sprites table, except that numbering starts from zero instead of 775. If not set, this defaults to "4" "8" "12" "6" (red, blue, orange and green, the colours of the modern office building). Can be set to different values for tiles of multi-tile buildings.

rating(<Word>)

This property sets the local authority's rating decrease on removal of the current building. For multi-tile buildings, this value should be the same for all tiles.

refresh(<Byte>)

This is used for random triggers, and sets how often the tile is re-randomized. When set to X, the tile will be re-randomized on every (X+1)-th periodic processing. (In other words, every (X+1)*256 game ticks.) If you want all tiles to be re-randomized, you must set this (but not necessarily to the same value) for each tile.

If callback CB_ACONTROL is enabled in function property callbacks(), it is also called after re-randomizing random bits.

In TTDPatch versions before 2.6 r1639 and 2.5 beta 9 (including beta 9), this function could return any value between 0 and 255. After these versions, the upper limit has been lowered to 63. To maintain compatibility, values above 63 will be interpreted as 63.

removalcost(<Byte>)

This property sets the removal cost factor for the current building. For multi-tile buildings, this value should be the same for all tiles.

size(1 | 2, 1 | 2)

This function specifies the house size up to 2x2 tiles. The first parameter defines the size in x direction and the second defines the size in y. Valid combinations are (1,1), (1,2), (2,1) and (2,2). The number of house parts (and house-IDs) defined in this way must be consistent with the number of house-IDs given in function substitutetype(). It can be omitted for 1x1 and/or 2x2 houses.

This value is only set for the building's main tile.

substitutetype(<House-ID>, <House-ID> | <House-ID>*2 | <House-ID>*4)

This is the key function for 'houses'. It has a two-fold application in m4nfo: since houses can be made up of more than one part (namely 1, 2, or 4) it'll determine how many parts are constituting a house.

The picture shows the arrangement of house tiles in game: for each house, the main tile is always the north tile (filled rectangle).

For 2x1 buildings, the first additional tile is the east one, for 1x2 buildings, the first additional tile is the west one, and for 2x2 buildings, the first additional tile is the east one, the second is the west part and the third is the south part. 2x2 buildings are always built on flat land no matter how flags() FLAT is set.

In another aspect, it'll define what building type will be used instead of the newly created one if its definition isn't available for any reason (e.g., the newGRF file is not found).

Don't set a substitute building type with a size larger than your new one (for example, don't set a 2x2 stadium for an 1x1 building) because this may corrupt savegames. Setting this property automatically copies every property of the substitute building to your new building, so you don't have to change properties that are the same as the substitute.

House flags CHURCH and STADIUM are exceptions; these flags are never set automatically. Only the first substitutetype() setting copies properties; if you later change it, properties will stay.

There's a special use of this property beginning from alpha 72: if you set it to "255" (or DISABLE), you can disable an old house type. In this case, the ID used must be the number of the old house type you want to disable. Disabling only prevents building the type in towns; houses already present on the map will stay unchanged. The type can still be overridden, and overriding affects houses present on the map.

Example 1 (single-part house):
substitutetype(1, 9)
Example 2 (multi-part house):
substitutetype(1, 9, 9, 9, 9)
substitutetype(1, 20, 21, 22, 23)
Example 3 (disable old house type):
substitutetype(10, DISABLE, DISABLE)

In the first example, a new single-type building with ID "1" is defined, substituting the old type with ID "9" (the 'statue'). In the second example, 4-part buildings are defined both for IDs "1", "2", "3", and "4": the first one substituting the old type with all IDs "9", the second one substituting the old type with IDs "20", "21", "22", and "23" (the 'stadium'). The third example shows how to disable old house types with IDs "10" and "11".

timeframe(<Date> .. <Date>)

The timeframe of an house is specified by giving its first date and the last date it can be built. In TTDPatch, anything before 1920 is considered to be always available, and it should allow for houses to work past 2044, the introduction date is also the very first date you can build the house. Please note that the timeframe must be a minimum of a year (365 days).

townzone(<List::TownZone>)

This function sets the town zone(s) where the building might get placed. Values/labels are like this:

ValueLabel
0TZ_OUTSKIRTS
1TZ_PERIPHERY
2TZ_RESIDENTIAL
3TZ_COMMERCIAL
4TZ_CENTRE

Where 0 / TZ_OUTSKIRTS represents the outermost zone of the town, and 4 / TZ_CENTRE stands for the innermost zone. Smaller towns have fewer zones. Roads are plain in zone 0 / TZ_OUTSKIRTS and 1 / TZ_PERIPHERY, paved in zone 2 / TZ_RESIDENTIAL, have trees in zone 3 / TZ_COMMERCIAL and streetlights in zone 4 / TZ_CENTRE.

This value is only set for the building's main tile.