The m4nfo User Manual and Report

Real sprites


Real sprites are the graphical part of GRF files, they are what the user actually sees in-game. Since OpenTTD version 1.2, there are two distinctly different ways to write real sprites, depending on the info version you use.

TTDPatch and OpenTTD until version 1.2 only understand GRF info version 7.

Format info version 7

A real sprite has the following format:

<sprite_attributes> ::= [<label>,] <filename> <xpos> <ypos> <flags> <ysize> <xsize> <xrel> <yrel>

Element Size Description
<label> string A label for optional referencing this sprite
<filename> string* The name of the file in which the sprite will be found
<xpos> dec The x position of the upper-left corner of the sprite in the file
<ypos> dec The y position of the upper-left corner of the sprite in the file
<flags> B The "flags", see below
<ysize> dec The y size of the sprite
<xsize> dec The x size of the sprite
<xrel> dec The x position of the upper-left corner of the sprite, relative to the "center" (usually negative)
<yrel> dec The y position of the upper-left corner of the sprite, relative to the "center" (usually negative)

* Unlike text strings in GRF code, this string should not have a terminating "00" and should not be placed in quotes.



A sprite can be given a label. Usually this makes no sense because there may be thousands of sprites in a sprite block, but there might be cases where this would be helpful in managing large but structured sprite sets. Those labels can be used also in tile layouts for stations:

	sprite(__platform, modern_set.pcx 210 1432 09 24 42 -31 -3) // platforms start

		normal(__platform, xyz(0,0,0), dxdydz(5,16,12))
		normal(__platform+1, xyz(0,0,0), dxdydz(16,16,35))


This specifies the name of the graphics file containing the sprites. Inclusion of the file name in every sprite() function allows to have them distributed in different files. The path should be a relative path, resp omitted at all, and instead be given by an external variable in one of your local .m4 files, or been set by function setpath(). See example.

<xpos, ypos, ysize, and xsize>

These are pretty easy to set, as long as you remember that the order is X, Y, Y, X, and not X, Y, X, Y.

Also, no sprite may contain zero pixels; ysize and xsize must both be at least 1.

There is a bug in grfcodec 0.9.7 and earlier that prevents them from properly encoding a sprite with a smaller ypos value than any earlier sprite. The best way to circumvent this bug is to upgrade to the newest version.


Unlike the other numbers, this is a hexadecimal byte. Currently, the following bits are supported:

Bit Value Meaning
0 1 Colour index 0 is transparent (should be always set; ignored if bit 3 is set)
1 2 Store compressed sprite in memory
3 8 Sprite is in chunked data format (aka "tile compression")
6 40 Sprite should not be cropped [*]. (obeyed by GRFCodec r1604 and later)

The chunked data format is designed to compress tiles and diagonal views of vehicles; things with lots of transparency around the edges, and a contiguous block of non-transparent pixels in the middle. Using the chunked data format may provide advantages in drawing speed.

[*] Usually grfcodec crops transparent border pixels off the sprite to the minimum size possible without loosing information. This could be avoided by setting this flag in cases where actual sprite size matters, i.e. when child sprites rely on it.

The most common values for the flags are "01" and "09". "03" is useful for large sprites that are infrequently used, as it reduces memory usage at the cost of slower drawing speed. It is generally a bad idea to use any other value, as that may cause problems. "255" is an especially bad idea.

<xrel and yrel>

These two numbers will probably become the bane of your existence.

TTD stores a single point for every sprite. xrel and yrel specify how far right and down (respectively) to go from the TTD point to the upper-left hand corner of the sprite. See the entry about coordinates in the TTDPatch Tutorial.

Halving xsize and ysize and negating the results produces a decent starting point for these values, and further adjustments may be done manually, with NFOEditor, or (in TTDPatch 2.0.1 alpha 69 and later) with the GRFAuthorHelperWindow.


The ranges for the four numbers after the flags are as follows:

ysize: 1 .. 255
xsize: 1 .. 65535
xrel: -32768 .. 32767
yrel: -32768 .. 32767

Note that ysize*xsize may not exceed 65535.

Transparency and glass effects can be achieved by means of RecolourSprites

Format info version 32

In OpenTTD info version 32, a real sprite has the following format:

<sprite_attributes> ::= [<label>,] <filename> 8bpp <xpos> <ypos> <xsize> <ysize> <xrel> <yrel> normal <flags>

Please note that parameters <xsize> and <ysize> have been swapped in info version32!

It is also possible to define 32bpp sprites for a number of zoom levels. For these, the format is as follws:

<sprite_attributes> ::= [<label>,] <filename> 8bpp <xpos> <ypos> <xsize> <ysize> <xrel> <yrel> normal <flags>
| <filename> 8bpp <xpos> <ypos> <xsize> <ysize> <xrel> <yrel> <zoomlevel> <flags>
| <filename> 32bpp <xpos> <ypos> <xsize> <ysize> <xrel> <yrel> <zoomlevel> <flags>
| <filename> mask <xsize> <ysize>

The type of the first sprite must always be 8bpp and of 'normal' zoom level (see below). Subsequent lines for alternative sprites can be of any type and zoom level. Available types are:

Type Description
8bpp Sprite with 8 bit colour depth in one of the accepted palettes
32bpp True colour sprite with 32 bit colour depth
mask If used, this type must follow a 32bpp entry immediately. It defines the colour translation for a preceeding 32bpp sprite and must be a 8bpp paletted sprite of the exact same size as the preceeding 32bpp sprite. Palette entry 0 means to draw the 32bpp as usual, other colours define replacement colours where the preceeding 32bpp sprite is interpreted as intensity and alpha channel information

OpenTTD supports a number of zoom levels. Available zoom levels are:

name zoom
ground sprite
(zig-zag border)
ground sprite
(smooth border)
xrel, yrel
(smooth border)
zo8 8x out 8 x 3 8 x 4 8 x 3 -3, 0 zoomed out
zo4 4x out 16 x 8 16 x 7 16 x 7 -7, 0
zo2 2x out 32 x 16 32 x 15 32 x 15 -15, 0
normal none 64 x 32 64 x 31 64 x 31 -31, 0 standard
zi2 2x in 128 x 64 128 x 62 128 x 63 -62, -1 zoomed in
zi4 4x in 256 x 128 256 x 124 256 x 127 -124, -2

Info version 32 only supports two types of flags: 'nocrop' and 'chunked'. These have the same meanings as bits 6 and 3 in info version 7.

In addition, you should call function zoom32_on() once in every source file for handling full path names for additional 32 bpp and/or zoom sprites in function sprite().

Please note that compiling files including 32bpp graphics and/or graphics with zoom levels needs file "count32.m4" (this sets format info version 32 for grfcodec) instead of "count.m4".


In m4nfo, real sprites are handled by function sprite():

Example (real sprite):
// info version 7
sprite(120T.pcx 10 10 01 14 6 -2 -11)

// info version 32 sprite(120T.pcx 8bpp 10 10 14 6 -2 -11 normal | 120T_z2.pcx 32bpp 10 10 28 12 -4 -22 zi2 | 120T_z4.pcx 32bpp 10 10 56 24 -8 -44 zi4 )


In m4nfo, real sprites have to be used inside of a spriteblock() function, depending on the feature (trains, stations, houses, ...) in question. See the chapter about sprite grouping for information.