Advanced Sprite Layout

Implemented in r22518.

Contents

Goal

When coding houses, industries, airports or objects you are having a hard time, if the tiles are slope- or climate-aware. You have to code a lot of spritelayouts which mostly consist of the same sprites and bounding boxes, and only vary in some groundsprite or some offsets.

To solve that burden it would be nice if register values could be added to certain parts of the spritelayout. Examples:

Technical Interpretation

Technical Restrictions

Proposal for new Action2 format

Industries/Houses/Airports/Objects

<Sprite-number> * <Length> 02 07/09/0F/11 <set-id>
                  <0x40 + num-sprites>
                  <groundsprite> <flags> [<register/value>]...
                  [<buildingsprite> <flags>
                    (<xoffset> <yoffset> <zoffset> <xextent> <yextent> <zextent> | <xpixeloffset> <ypixeloffset> 80)
                    [<register/value>]...
                  ]...

The spritelayout defines fixed spritesets to use from the Action 1. The registers can be used to individually select sprites from the spritesets instead of always using the construction stage. The registers are evaluated and their values are saved when the Action 2 sprite layout is evaluated. Other callbacks called during drawing (like CB 1E) have no effect on the used values of the registers.

Stations

<Sprite-number> * <Length> 00 04 <num-props> <num-info> <id>
                  1A <num-layouts>
                  <0x40 + num-sprites>
                  <groundsprite> <flags> [<register/value>]...
                  [<buildingsprite> <flags>
                    (<xoffset> <yoffset> <zoffset> <xextent> <yextent> <zextent> | <xpixeloffset> <ypixeloffset> 80)
                    [<register/value>]...
                  ]...

Property 1A defines the spritelayout using the same format as the action 2 above. Setting property 1A overrides properties 09 and 0A and vice verse, just like setting properties 09 and/or 0A multiple times. The used Action 1 and the used spriteset is selected via an Action 1/2/3 chain and using the usual "loading stages" for "litte" or "lots of cargo". With similar means as Action 0 property 13 bit 0 multiple spritesets from different Action 1 can be used.

The sprites and the registers in the spritelayout define which sprite to use from the selected spriteset. The registers are evaluated and their values are saved when the Action 2 responsible for a particular entry in the spritelayout is resolved.

Details

<0x40 + num-sprite>: Number of sprites in the layout. Add 0x40 to identify the new format with register modifiers.

<flags>: Word value with these flags:

Bit Hex Parentsprite Groundsprite/Childsprite
0 0001 Skip bounding box including child sprites Skip sprite
1 0002 Add offset to sprite, disable default usage of construction stage or railtype-offset
2 0004 Add offset to recoloursprite
3 0008 Recolour sprite is from Action 1 (will be affected by the same construction stage resp. railtype-offsets as sprites, unless bit 2 is set)
4 0010 Add offset for <xoffset> and <yoffset> Add offset for <xpixeloffset>
5 0020 Add offset for <zoffset> Add offset for <ypixeloffset>
6 0040 Resolve sprite with Variable 10 set to a specific value (*)
7 0080 Resolve recoloursprite with Variable 10 set to a specific value (*)
8..15

Reserved, should be zero. If the GRF sets unknown bits, it will be disabled.

(*) The Action 1/2/3 chain is resolved multiple times, sprites can be part of different Action 1:

The associated value in <register/value> is the raw value (not a register!) to put into Variable 10 while resolving the sprites.

  • Only valid for stations,
  • only allowed values currently 0-7,
  • the value '2' is used when resolving custom foundations, (so, do not conflict with that)
  • even if the sprite is not from an Action 1, the value still defines which Action2 chains defines the values for the referenced registers.
  • The register for "Add offset to recoloursprite" is defined by the Action 1/2/3 chain with Variable 10 as defined for the recolour sprite. :*The other registers are defined by the Action 1/2/3 chain with Variable 10 as defined for the sprite.
  • If no variable 10 values are defined, then station property 13 bit 0 takes effect; i.e. variable 10 is set to 0 or 1 depending on the bit and whether the first groundsprite is resolved or a different sprite. This applies to both the groundsprite and the palette of the groundsprite.

<register/value>: Temporary storage registers to add to the individual parts. The register values are considered signed. The order of the registers is the same as the bits in <flags>. If a bit is not set, then no registers appears for it. Most bits require one register.

Example

The example consists of

-1 * -1    02 0F 40 81          // Procedure to compute the slope-dependent spriteoffset
                    41    00 1F
           \b 18
                \wx 8000  00 00 // flat
                \wx 8001  01 01 // normal slopes
                \wx 8002  02 02
                \wx 8003  03 03
                \wx 8004  04 04
                \wx 8005  05 05
                \wx 8006  06 06
                \wx 8007  07 07
                \wx 8008  08 08
                \wx 8009  09 09
                \wx 800A  0A 0A
                \wx 800B  0B 0B
                \wx 800C  0C 0C
                \wx 800D  0D 0D
                \wx 800E  0E 0E
                \wx 800F  1D 1D // steep slopes
                \wx 8010  1B 1B
                \wx 8011  17 17
                \wx 8012

-1 * -1    02 0F 41 81          // Procedure to compute the climate-dependent spriteoffset
                    62 00 0A 07
                \wx 91C6  01 01 // desert
                \wx 91C6  04 04 // snow
                \wx 8F8D        // normal

-1 * -1    02 0F 42 82          // Procedure to compute the height offset in the middle of the tile
                    41    00 1F
           \b 9
                \wx 8004  03 03 // 2-corner inclined slopes
                \wx 8004  06 06
                \wx 8004  09 09
                \wx 8004  0C 0C
                \wx 8008  07 07 // 3-corner slopes
                \wx 8008  0B 0B
                \wx 8008  0D 0D
                \wx 8008  0E 0E
                \wx 8008  10 1F // steep slopes
                \wx 8000        // rest, no offset

-1 * -1    01 0F \b 2 \b* 1
-1         ugly_building.png  ? ? 01 ? ? ? ?
-1         pretty_snow.png    ? ? 01 ? ? ? ?

-1 * -1    02 0F 00 42
           \dx 0        \wx02                    10       // Draw groundsprite from register 0x10.
           \dx 80000000 \wx20  00 00 00 10 10 30 11       // Draw building sprite at z-postion from register 0x11.
           \dx 80000001 \wx01  00 00 80          12       // Draw snow-overlay relative to building sprite, but only if register 0x12 is zero.

-1 * -1    02 0F 00 81
                    7E 40 20 FF                           // Get slope offset from procedure 40
             \2+    7E 41 20 FF                           // Add climate offset from procedure 41
             \2sto  1A    20 10                           // Store in register 0x10
             \2rst  7E 42 20 FF                           // Get height offset in the middle of the tile
             \2sto  1A    20 11                           // Store in register 0x11
             \2rst  62 00 2C 01                           // Test snow bit, 1 if snowy, 0 if not
             \2sto  1A    00 12                           // Store in register 0x12
           \b 1
                \wx 0     00 00                           // always procede at 00
                \wx 0

-1 * -1    03 0F 01 ?? \b 0 00                            // always procede at 00