The m4nfo User Manual and Report

Sprite layout

Defining graphics set IDs

Content


Introduction

Sprite layouts are used to access (and arrange) sprites defined in a previous spriteblock() function. Sprite layouts are different depending on the feature in use. For vehicles, they simply represent the sprites to use for loading and moving states of a vehicle, but for stations, buildings, industry tiles and objects they define compositions from single sprites including 3D information. For stations, they also represent the amount of waiting cargo, similar to vehicle loading states.

Therefore, composition of layouts is quite different: vehicles have only one sprite per state, but tiles for buildings, industries and objects may be composed from many sprites, each with its own 3D information or defined as a 'child sprite' sharing the 'bounding boxes' of its 'parent' sprite, including means for transparency and/or recolouring.

For stations, buildings, industry tiles and objects, m4nfo tries to unify the different structure of sprite layouts as best as could be done.

Sprite layout for vehicles

Format

The sprite layout for vehicles has the following format:

spriteset(move([<moving states>]), load([<loading states>]))

Where the move() and load() functions take spriteblock() references as their arguments, and the vehicle's layout will be defined by a single spriteset() function. For examples, see here.

Description

spriteset(move([<moving states>]), load([<loading states>]))

This function is mainly used to define sets of sprites that show one vehicle in various states of load for one particular type of cargo. In general, for each vehicle view, one spriteset() is needed.

Example (mixed coach / mail van):
spriteblock(
  set(template({TMPL_NG_6M},mixte.pcx,x(10,26,58,100,128,144,176,218),y(10)))
  set(template({TMPL_NG_6M},mixte.pcx,x(128,144,176,218,10,26,58,100),y(10)))
)

def(2) spriteset(move(0),load(0)) // passengers first
def(3) spriteset(move(1),load(1)) // mail first

load([<list>])

This function is used to define a set of loading states for the vehicle. The set may be empty in case no sprite set is defined. The numbers in the given list must reference sprite set numbers in a previous spriteblock() function. The numbers representing the graphics the vehicle should show while it's loading or unloading. For example, if it has two states, full or empty, this would need two parameters. If it has three states, full, half full or empty, this would need three.

move([<list>])

This function is used to define a set of moving states for the vehicle. The meaning is the same as above.

Example (freight wagon):
spriteset(move(0,9,11),load(0,8,10))

This wagon uses 3 different sprites for its moving states, and it uses different sprites for its loading states.

Sprite layout for stations, buildings, industry tiles and objects

Format

In general, two different formats are provided for these features. First one is the 'traditional' layout used both by TTDPatch and OTTD, the second one is OTTD's 'advanced sprite layout' which allows dynamic composition by use of registers.

Due to a fundamental difference between station tiles and those for houses, industry tiles and objects, sprite layouts for these features are a bit different, even in m4nfo. Station tiles have to be provided always as pairs for x- and y-direction, but tiles for other features are provided as single tiles, their layout defined by a single spriteset() function. Out of convenience, spriteset()s for stations are called 'tile()s' in m4nfo, while function spriteset() is used for definition of station's graphics sets, representing amount of waiting cargo.

Because a station sprite layout is resolved multiple times in TTDPatch/OTTD, graphics sprites may be part of different sprite blocks (ground sprites, custom foundation sprites, normal sprites), and it is possible to use different sets of sprites in a specific sprite layout.

Both formats allow combination of more than one sprite per tile, as well as the inclusion of 'child sprites', i.e. those sharing their 3D-bounding boxes with the previous sprite:

spriteset(
   <groundsprite>    {<buildingsprite>, <xoffset, yoffset, zoffset>, <xextent, yextent, zextent>)} |
   {(<buildingsprite>, <xpixeloffset, ypixeloffset>)}
)

m4nfo provides auxiliary functions to be used in above sprite layout definitions:

Layout term m4nfo function
<groundsprite>normal() | ground() | NOSPRITE
<buildingsprite>normal() | notransparency() | glass() | recolour() | NOSPRITE
<xoffset, yoffset, zoffset>xyz()
<xoffset, yoffset>xy()
<xextent, yextent, zextent>dxdydz()
<xpixeloffset, ypixeloffset>xyoff()

Example 1 (simple sprite layout):
def(16) spriteset(NOSPRITE, normal(0), xy(0,0), dxdydz(16,16,16))

This sprite layout uses no ground sprite, uses the first sprite from the coresponding sprite block as its building sprite, and its bounding box covers the whole tile (16 * 16) and has a height of 16 pixels.

Example 2 (1 child sprite):
def(22) spriteset(
	set(normal(WATER), normal(1), xyz(0,0,0), dxdydz(16,16,6))
	set(normal(MOLESTAIRS), xyoff(19,6))
)

This sprite layout uses the original water tile as its ground sprite, uses the second sprite from the coresponding sprite block as its building sprite, and its bounding box covers the whole tile (16 * 16) with a height of 6 pixels. There's a child sprite sharing the parent's bounding box with its origin at coordinate x=19 and y=6 with the parent's graphics sprites.

Example 3 (multiple sprites):
def(50) spriteset(
	set(normal(WATER), normal(2), xyz(0,0,0), dxdydz(16,16,6))
	set(normal(LIGREEN5), xyz(1,5,6), dxdydz(8,8,16))
)

This sprite layout uses the original water tile as its ground sprite, uses the third sprite from the coresponding sprite block as its building sprite, and its bounding box covers the whole tile (16 * 16) with a height of 6 px. There's another sprite located at coordinates x=1 and y=5, starting at a height of 6px with its own bounding box of 8 * 8 px and a height of 16 px.

Example 4 (multiple sprites plus child sprite):
def(51) spriteset(
	set(normal(WATER), normal(2), xyz(0,0,0), dxdydz(16,16,6))
	set(normal(LIGREEN5), xyz(1,5,6), dxdydz(8,8,16))
	set(normal(ANIMGREEN), xyoff(4,2))
)

This sprite layout is in principal the same, except of an additional child sprite added to its second sprite. The graphics associated with this child sprite is located at x=4 and y=2 in relation with its parent sprite.

Sprite layout for stations

Format

The sprite layout for stations has the following format:

spriteset(little(<num_littlesets>), lots(<num_lotssets>))

Where the little() and lots() functions take spriteblock() references as their arguments, just as for vehicles.

Stations have yet another similar method to access layouts of sprites when resolving CB_LAYOUT:

cbset(little(<num_littlesets>), lots(<num_lotssets>))

Description

spriteset(little(<num_littlesets>), lots(<num_lotssets>))

This function is used to define sets of sprites that show one station tile in various states of load for one particular type of cargo.

Example (overpass):
spriteblock(
    ...
    sprite(bridge2w.pcx 370 10 09 33 42 -31 -13)
    sprite(bridge2w.pcx 415 10 09 33 42 -9 -13)
    sprite(bridge2w.pcx 460 10 09 44 42 -31 -24)
    sprite(bridge2w.pcx 505 10 09 44 42 -9 -24)
  )
)    

def(2) spriteset(little(0),lots(0))

cbset(little(<num_littlesets>), lots(<num_lotssets>))

This function is used to define sprite layouts showing station tiles in various states of load for one particular type of cargo, in the same way spriteset() does, but when being in a CB_LAYOUT callback chain. The parameters to little() and lots() are tile layout numbers, interpreted as callback results, representing a certain amount of cargo.

Example (show amount of cargo on station tiles):
def(1) cbset(little(6,6,18,30,42,54,66,78),lots(90))
def(2) cbset(little(6,18,30,42,54,66,78,90),lots(102))
def(3) cbset(little(6,30,42,54,66,78,90,102),lots(102))
def(4) random(LOADING,16,ref(1),ref(2),ref(2),ref(3))
...
def(2) plt_numrev(
	ref(4) if(0) // edge: fence
	ref(1) else  // adjoining
)
...
def(15) callback(
	ref(11) if(CB_LAYOUT) // sprite layout
	ref(0) else	      // graphics
)

little(<list>), lots(<list>)

These two auxiliary functions are used to define sets of loading states for the station tile. The numbers in the given lists must reference sprite set numbers from a previous spriteblock() function.

Likewise for vehicles, this decides the graphics set to use depending on the amount of cargo waiting. There are two caveats, though. Firstly, a station can have 12 different cargoes waiting, not just a single one. Secondly, the maximum amount is 4095 for all stations and all cargo types.

Regarding the first issue, the amount of cargo this refers to depends on the makestation() function that triggered this spriteset():

Regarding the second issue, TTDPatch introduces the distinction between "little" and "lots of" cargo. The amount where this occurs is set by property function threshold(), which is zero by default. But if set to a non-zero value, for example 200, then the range 0 to 199 is divided by <numlittlesets>, and the remaining range 200 to 4095 is divided by <numlotssets>. If threshold() is set to zero, the "little" sets are never used, and so <numlittlesets> may be zero. <numlotssets> must never be zero, however.