The m4nfo User Manual and Report

Recolour sprites


Introduction

In comparison to TTD's 'real' sprites (displayable graphics), 'recolour sprites' are not meant for graphics display. In fact, they are a re-mapping of TTD's original colour table, used to modify the colours of real sprites.

Format

In m4nfo, a recolour sprite has the following two formats:

colourtable(<byte*256>)
colourtable(<table>,{<dest>,<source>})
<dest>,<source> ::= <range> | {<byte>}

A (re-)colour table may be defined in two different ways. One way is to supply the whole colour table as a block of 16 * 16 bytes which are indices into TTD's original colour table(s). This procedure should be prefered when setting extensive colour maps, e.g. for tinted glass effects.

The other method is more suited for simple recolouring purposes, by only supplying the modifications to either TTD's DOS or Windows colour table. In this case, <source> specifies a range of colour indices to be overwritten by those indices given in <dest>. Note that both ranges must be identical in size and must be contiguous.

Please note that both methods require to specify the bytes as hexadecimals numbers.

Description

Each index in a colour table (or colour map, palette, ..) specifies a colour to be drawn. Note that TTD's colour tables are different depending on whether the GRF is being loaded in TTD DOS or TTD Win. If you create a GRF that contains recolour sprites, you may find it necessary to maintain two separate versions, and/or use the skipif() function to check for the DOS or windows version of TTD.

In OpenTTD since r??? you might use either DOS or windows colour tables, depending on a parameter set in the 'advanced settings'.

Both DOS and Windows colour tables are depicted here.

You might notice that the DOS colour table includes 6 colours more than the windows table does, so for a graphics designer it would make more sense to use the DOS table. Note also that both colour tables include 'special' colours which provide special effects in-game like 'company colours', 'water cycle', 'fire cycle', etc, rather than to be displayed as the colour you see in the table. In fact, these colours are recoloured in-game in the same way like manual recolouring will work.

This is how recolouring works. Assume the original TTD colour table:

colourtable(
      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
      10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
      20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
      30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
      40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
      50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
      60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
      70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
      80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
      90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
      A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
      B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
      C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
      D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
      E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
      F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
)

Note that the range [C6 .. CD] is set by default with 'company blue', used to be recoloured by TTD to the 16 available company colours. Now, when modifying the colour indices at these positions like this:

colourtable(
      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
      10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
      20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
      30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
      40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
      50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
      60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
      70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
      80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
      90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
      A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
      B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
      C0 C1 C2 C3 C4 C5 11 12 13 14 15 16 17 18 CE CF
      D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
      E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
      F0 F1 F2 F3 F4 F5 00 00 00 00 00 00 00 00 00 FF
)

TTD will now show 'silver' colours when trying to display the original 'company blue' colours. In this way, lots of colour tables could be made with different colours in the range [C6 .. CD], and by switching colour tables in game, the same real sprites would be drawn in different colours, sparing lots of explicitly coloured graphic sprites.

Note that you are not limited to the 'company blue' range of colour entries. In fact, you may use every colour entry and set it to every other colour entry you like. In this way, interesting recolour tables can be produced. E.g., by modifying only three colour entries you could set up a recolouring table for forward/backward train lights, or you could invent 'shadow' or 'tinted glass' effects for transparent and semi-transparent station roofs, etc.

Usage

In m4nfo, functions colourtable() and sprite() are handled equally, i.e. both have to be used inside a set() and a spriteblock() function. The only difference is that colour tables have to be 'allocated', i.e. m4nfo has to provide some 'space' for them, but a real sprite is simply read from its file (there is an exception with graphics sprites allocated for bridges, see there). Hence, the usual way to set up colour tables will look like this:

Example (allocating 2 colour tables):
spriteblock(ALLOCATE,
// +00 "PETROL"
  set(
    colourtable(
      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
      ...
      F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
    )
// +01 "BLACK"
    colourtable(
      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
      ...
      F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
    )
  )
)

The 'incremental' way of setting up recolour tables would look like this:

Example (allocating 2 recolour tables):
spriteblock(ALLOCATE,
// +00 "LI_HEAD"
  set(
    colourtable(DOSMAP,
      ce .. d1, 0a 0a c5 c5
    )
// +01 "LI_TAIL"
    colourtable(DOSMAP,
      ce .. d1, a4 0a 0a 0a
    )
  )
)
Example (changing two colour ranges in one table):
colourtable(DOSMAP,
    62 .. 67, _OILSEED,
    c6 .. cd, B4 B5 A2 B6 A3 B7 A4 A5
)

Now, with the colour tables defined, e.g. vehicles might use them by a callback CB_RCOL, as decribed in the example there.

Note that the maximal allowed number of recolour tables in a spriteblock is limited to 32640, in comparison to the max number of real sprites which is 65535.

Default recolour sprites

TTD already defines a number of recolour sprites for various uses, e.g. for the semi-transparency of glass or the re-colouring of the tubular bridges, company colours or some houses.

Sprite numberDescription
(dec)(hex)
7710x303 A pulsating red tile is drawn if you try to build a wrong tunnel or raise/lower land where it is not possible
7720x304 Makes a square red, used when removing rails or other stuff
7730x305 Draws a blueish square (catchment areas for example)
Translations for company colours C6 .. CD to ...
7750x307
... dark blue
7760x308
... pale green
7770x309
... pink
7780x30A
... yellow
7790x30B
... red
7800x30C
... light blue
7810x30D
... green
7820x30E
... dark green
7830x30F
... blue
7840x310
... cream
7850x311
... mauve
7860x312
... purple
7870x313
... orange
7880x314
... brown
7890x315
... grey
7900x316
... white
Translations for "brownish red" colours E3 .. E7, used by some town buildings and bridges
7910x317 bare land, for rail and road (crossings)
7950x31B structure to blue
7960x31C structure to brownish (e.g. cantilever bridges)
7970x31D structure to white
7980x31E structure to red (e.g. bridges)
7990x31F structure to green (e.g. bridges)
8000x320 structure to concrete (e.g. suspension bridge)
8010x321 structure to yellow (e.g. suspension bridge + tubular)
Special colour translations
8020x322 "glass" effect (2-step darkening)
8030x323 mapping to grey (e.g. tubular bridge or newspaper)
8040x324 crashed vehicle (dark grey)
14380x59E church red
14390x59F church cream

Note that for the company colour translation a translation to dark blue (0x307) is the identity translation which replaces every colour with itself. You can use it in cases where a remapping is needed, but you don't want to recolour anything.

Of course you might also use TTD's pre-defined colour tables in m4nfo. For this to work, you'll have to use the sprite numbers given in the table above and format them as a callback result, e.g. by setting bit15 in their sprite numbers (0x307 -> 0x8307, etc), or by using the original sprite numbers in a cbr() function. See example below.

Example (random using of TTD's colour tables):
define(DBLUE,0x8307) 
define(LGREEN,0x8308)
define(PINK,0x8309)
...

def(7) randomrel(LOAD,1,ref(DBLUE),ref(LGREEN),ref(PINK),ref(YELLOW),
                        ref(RED),ref(GREEN),ref(PURPLE),ref(WHITE))

def(8) callback(
         ref(7) if(CB_RCOL) // recolour
         ref(2) else        // graphics
)

Dual company colours

You might also use the dual-company-colour recolour sprites. However, they are no default TTD sprites and thus they do not have fixed sprite numbers. You can determine the spritenumber of the first 2CC recolour sprite via TTDPatch variable 11. You then need Action 6 to put the needed recolourings into actions where needed.

Starting from the spritenumber from TTDPatch variable 11 there are 256 recolour sprites. Their order follows the default company recolourings above. The second company colour changes every 16 sprites, so every combination of first and second colour is available:

Offset from first sprite (dec) Offset from first sprite (hex) First colour (colours 0xC6 to 0xCD) Second colour (colours 0x50 to 0x57)
0 0x00 dark blue dark blue
1 0x01 pale green dark blue
: : : :
15 0x0F white dark blue
16 0x10 dark blue pale green
: : : :
31 0x1F white pale green
32 0x20 dark blue pink
: : : :
255 0xFF white white

You'll notice that the low nibble of the offset represents the first company colour from 0 (dark blue) to F (white), and the high nibble represents the second company colour.

In m4nfo, such a recolour table may be accessed by function getcolour_pluscc().

More technical information

Recolour sprites are applied in one of two ways:

Non-transparently:

Each pixel in the sprite is looked up in the recolour table, and then the color specified at that offset is drawn on the screen. If the resultant color is 00 ("transparent blue"), then if the sprite's compression bit 3 is not set, nothing is drawn; otherwise (i.e. if the sprite is in chunked data format) the actual color 00 (which is black) is drawn.
Transparently:

For each sprite pixel that is not transparent, the current (on-screen) color of the pixel at the location where the sprite pixel would be drawn is looked up in the recolour table, and then redrawn in the new color. If the recolour lookup returns 00 ("transparent blue"), the resultant color is actually black. Other than is-transparent-blue/not-transparent-blue, the actual colors of the pixels in a sprite that is drawn transparently are meaningless.