Worms DC File Formats

Back to asset tool

General

WormsDC asset files are mostly structured like IFF chunks, with some non-standard chunks. Some chunks are optional: Many custom levels contain a starting quote and custom mountain palettes, some don’t, etc.

Many MNT and DIY files that come with WormsDC are CrunchMania-compressed. If you want to import them, you have to decompress them first.

For the impatient: Skip right to the meat: WRM16, DIY, MNT

What files contain which chunks?

File typeWhatChunks
.WRM16 Custom level FORM WRM2 [QUOT] [MNT1 MNT2] BMHD CMAP BODY [BACK]
.WRM16 Custom level
(alternative format)
FORM WORM [WORM] BMHD CMAP BODY [BACK]
.DIY Landscape WRM2LAND* CMAP [MNT1 MNT2] DATA*
* not really a chunk
.MNT Mountains WRM2MNTS* MNT1 MNT2 DATA*
* not really a chunk

What’s in those chunks?

ChunkWhatDescription
FORM Standard IFF header File length and sub-type (ILBM)
WRM2 Level settings Gravity, friction, flags, sky, water, which mountains to use
WORM Level settings Similar to WRM2, not fully analyzed
QUOT Quote Text that scrolls by when a round starts
CMAP Palette Image palette
MNT1
MNT1
Mountain palette CMAP chunks with a different name
BMHD Bitmap header Standard IFF chunk with width, height, color depth
BODY Bitmap Standard IFF chunk with run-length-compressed bitmap data
BACK Custom level background BODY chunk with a different name
WRM2LAND Landscape settings Non-standard chunk; contents similar to WRM2
WRM2MNTS Mountain settings Non-standard chunk; Sky colors, HSV flag
DATA Bitmap collection Non-standard chunk; header with number of bitmaps and the bitmaps themselves

Recap: What’s in an IFF file?

A series of chunks. Each chunk contains its name and its length, so you can skip chunks you want to ignore or don’t know how to handle.

Examples:

If a file starts with FORM, that’s a special chunk:

There’s no end chunk like with PNGs.

File details

Presented as walkthroughs of example files.

Noteworthy:

WRM16 – custom level

Basically an IFF ILBM image with extra chunks.

Start of file
464f 524d 0002 2174 494c 424d            FORM..!tILBM
Type Length What
char[] 4 Chunk ID FORM
uint32 4 Chunk size (here: length of file - 12)
char[] 4 Format ID ILBM
Level settings
                              5752 4d32              WRM2
0000 002c 0100 0303 5455 5252 4943 414e  ...,....TURRICAN
0000 0099 0000 ff00 0001 0001 ff80 80ff  ................
0000 0000 0000 0000 0000 0000 0000 0000  ................
Type Length What
char[] 4 Chunk ID WRM2
uint32 4 Chunk size
uint8 1 Dual layer level? (0/1)
uint8 1 Destroy background? (0/1)
uint8 1 Gravity (1 to 5, default 3)
uint8 1 Friction (1 to 5, default 3)
string variable Mountain set name, 0-terminated (here: TURRICAN)
uint8 1 Use palettes of mountain set? (0/1)
0 means: custom palettes, expected in MNT1 and MNT2 chunks
uint8 1 Use sky colors of mountain set? (0/1)
0 means: custom zenith and horizon colors
rgb 3 Custom zenith color (R, G, B as bytes; present even if unused), here: 990000
rgb 3 Custom horizon color (present even if unused), here: ff0000
uint8 1 Sky gradient with HSV? (0/1)
uint8 1 Water type (0=normal, 1=gloop, 2=fire)
uint8 1 Use default color for the selected water type? (0/1)
0 means: custom water base color
1 means: water=blue, gloop=green, fire=yellow
rgb 3 Custom water color (present even if unused), here: ff8080
uint8[] 17 Epilog of unknown function. Starts with 255, then zeroes, i.e.
ff 00 00 00 00 00...
unit8 0 or 1 Optional padding byte, only inserted if the WRM2 payload has an odd length at this point (which depends on the mountain set name)
Quote (optional)
5155 4f54 0000 0022 5745 4c43 4f4d 4520  QUOT..."WELCOME
544f 2054 5552 5249 4341 4e2c 2048 412d  TO TURRICAN, HA-
4841 2d48 412d 4841 2100                 HA-HA-HA!.      
Type Length What
char[] 4 Chunk ID QUOT
uint32 4 Chunk size
string variable 0-terminated string, uppercase, max. length 40
unit8 0 or 1 Optional padding byte, only inserted if the QUOT payload has an odd length at this point)
Bitmap header
                         424d 4844 0000            BMHD..
0014 03c0 015e 0000 0000 0400 0100 0000  .....^..........
0101 03c0 015e                           .....^          
Type Length What
char[] 4 Chunk ID BMHD
uint32 4 Chunk size
uint16 2 Width (03c0=960)
uint16 2 Height (015e=350)
int16 2 X (usually 0, not important)
int16 2 Y (usually 0, not important)
unit8 1 Number of bit planes; should be 4 for 16 colors
unit8 1 Masking active? (0/1), should be 0 (no masking/stencil in file)
unit8 1 Compression type (should be 1 for run-length encoding)
unit8 1 Reserved (0)
uint16 2 Transparent color index (usually 0)
unit8 1 X aspect (1, not important)
unit8 1 Y aspect (1, not important)
uint16 2 Page width (same as width, not important)
uint16 2 Page height (same as height, not important)
Custom mountain colors (optional)
               4d4e 5431 0000 0030 6400        MNT1...0d.
afe2 0080 e200 80e2 0080 e200 80e2 0080  ................
e200 80e2 0080 e200 80e2 0080 e200 80e2  ................
0080 e200 80e2 0080 e200 8000 ffaa 4d4e  ..............MN
5432 0000 0030 6400 afe0 0082 e000 82e0  T2...0d.........
0082 e000 82e0 0082 e000 82e0 0082 e000  ................
82e0 0082 e000 82e0 0082 e000 82e2 0080  ................
bba0 af00 ffaa                           ......
Type Length What
char[] 4 Chunk ID MNT1 (mountain layer 1 palette)
uint32 4 Chunk size of palette, should be hex 30=48 for 16 colors (3*16)
rgb[] 3*number of colors List of R, G, B bytes, should be 16 entries for 4 bit planes
Here: 6400af, e20080, ... 00ffaa
char[] 4 Chunk ID MNT2 (mountain layer 2 palette)
uint32 4 Chunk size of palette, should also be 48
rgb[] 3*number of colors List of R, G, B bytes, should be 16 entries
Palette for foreground and background
               434d 4150 0000 0030 00ff        CMAP...0..
00ff ffff ef7e eb7b 5327 ad68 1e2e 2f3c  .....~.{S'.h../<
ccc0 7e62 646f a9ab b733 6ce9 256e 1414  ..~bdo...3l.%n..
1414 dfc9 0b59 412c cc14 1448 4848       .....YA,...HHH
Type Length What
char[] 4 Chunk ID CMAP (standard IFF chunk for the palette)
uint32 4 Chunk size of palette, should be hex 30=48 for 16 colors (3*16)
rgb[] 3*number of colors List of R, G, B bytes, should be 16 entries for 4 bit planes
Here: 00f00, ffffff, ... 484848
Foreground bitmap
                                   424f                BO
4459 0001 4ebc 179f efc7 009b 698f 8fe0  DY..N.......i...
99e9 1f8f d1e9 1f8f d18c 489f ef8f 88f4  ..........H.....
...
Type Length What
char[] 4 Chunk ID BODY (standard IFF chunk for the bitmap)
uint32 4 Chunk size
uint8[] variable Interleaved bitmap data according to the compression type in BMHD which is usually 1 for run-length encoding. Decompression code:
bitmap = [];
let pos = 0;
while (pos < bytes.length) {
	let b = bytes[pos++];
	if (b > 128) {
		let repeat = 257 - b;
		b = bytes[pos++];
		for (let i=0; i<repeat; i++) {
			bitmap.push(b);
		}
	} else if (b == 128) {
		break;
	} else {
		let verbatimBytes = b + 1;
		for (let i=0; i<verbatimBytes; i++) {
			bitmap.push(bytes[pos++]);
		}
	}
}
After this, bitmap contains an array of length
bit planes * bytes per row * height
where "bytes per row" is Math.ceil(width/8). A bitmap of width 32 has 4 bytes per row, bitmap widths 33 to 40 needs 5 bytes per row, width 41 has 6 bytes per row, etc.
Background bitmap (optional)
     4241 434b 0000 d181 f2ff 00fc 9900    BACK..........
0fe0 fe01 d038 3f80 740e 0fe0 1d03 83f8  .....8?.t.......
0499 000f 1f01 fe2f c7c0 7f8b f1f0 1fe2  ......./........
...
Type Length What
char[] 4 Chunk ID BACK
uint32 4 Chunk size
uint8[] variable Bitmap data, same format as BODY

DIY – landscape

A mix of proper chunks and custom data blocks, with a special bitmap format. A DIY file always contains 7 special bitmaps of fixed sizes (foreground, background, grass, shade, 3 bridge segments) plus a variable number of decoration elements of any size that are scattered throughout the map when the landscape is generated.

Start of file, settings
5752 4d32 4c41 4e44 1204 0303 4445 4641  WRM2LAND....DEFA
554c 5400 0000 8027 3bf2 c16a 0100 0088  ULT....';..j....
2200 0001 0000 0000 0000 0000 0000 0000  "...............
0000 0000                                ....            
Type Length What
char[] 8 Identifier WRM2LAND
uint8 1 Number of bitmaps including the 7 special ones (so, at least 7, here: hex 12=18)
uint8 1 Landscape ID, here: 4
WormPrefs provides a default value of 128. Assumption: The different DIY files in your TWDIY folder should all have different landscape IDs.
uint8 1 Gravity (1 to 5, default 3)
uint8 1 Friction (1 to 5, default 3)
string variable Mountain set name, 0-terminated (here: DEFAULT)
uint8 1 Use palettes of mountain set? (0/1)
0 means: custom palettes, expected in MNT1 and MNT2 chunks
uint8 1 Use sky colors of mountain set? (0/1)
0 means: custom zenith and horizon colors
rgb 3 Custom zenith color (R, G, B as bytes; present even if unused), here: 80273b
rgb 3 Custom horizon color (present even if unused), here: f2c16a
uint8 1 Sky gradient with HSV? (0/1)
uint8 1 Water type (0=normal, 1=gloop, 2=fire)
uint8 1 Use default color for the selected water type? (0/1)
0 means: custom water base color
1 means: water=blue, gloop=green, fire=yellow
rgb 3 Custom water color (present even if unused), here: 882200
uint8[] 17 Epilog of unknown function. Here:
00 01 00 00 00 00... (rest all zeroes)
unit8 0 or 1 Optional padding byte if the payload so far has an odd length
Palette for all landscape images
          434d 4150 0000 0030 7a00 7aff  ....CMAP...0z.z.
ffff a08a 6630 360e 3a63 0402 0500 585a  ....f06.:c....XZ
565c 8f04 4218 0422 0900 9e95 0e84 3d0a  V\..B.."......=.
bec1 7268 2900 866b 489a 5b1c            ..rh)..kH.[.
Type Length What
char[] 4 Chunk ID CMAP (standard IFF chunk for the palette)
uint32 4 Chunk size of palette, should be hex 30=48 for 16 colors (3*16)
rgb[] 3*number of colors List of R, G, B bytes, should be 16 entries for 4 bit planes
Here: 7a007a, ffffff, ... 9a5b1c
Custom mountain colors (optional)
                              4d4e 5431              MNT1
0000 0030 6400 afa8 8d59 9f89 5195 8548  ...0d....Y..Q..H
8c81 4082 7c38 7977 306a 6f29 5c65 234f  ..@.|8yw0jo)\e#O
5c1d 4352 1837 4913 2c3f 0f23 360c 192c  \.CR.7I.,?.#6..,
0811 2205 4d4e 5432 0000 0030 6400 af99  ..".MNT2...0d...
a5a5 869c 9974 938b 648a 7d53 806b 4577  .....t..d.}S.kEw
5a38 6e48 2c64 3621 5b25 1952 1817 4810  Z8nH,d6![%.R..H.
173f 0a17 3605 162c 0011 2205            .?..6..,..".
Type Length What
char[] 4 Chunk ID MNT1 (mountain layer 1 palette)
uint32 4 Chunk size of palette, should be hex 30=48 for 16 colors (3*16)
rgb[] 3*number of colors List of R, G, B bytes, should be 16 entries
Here: 6400af, a88d59, ... 112205
char[] 4 Chunk ID MNT2 (mountain layer 2 palette)
uint32 4 Chunk size of palette, should also be 48
rgb[] 3*number of colors List of R, G, B bytes, should be 16 entries
Here: 6400af, 99a5a5, ... 112205
Image data header
                              4441 5441              DATA
5342 0012                                SB..            
Type Length What
char[] 4 Identifier DATA
char[] 2 Identifier SB (sub-bitmaps?)
unit16 2 Number of bitmaps that follow (here: hex 12=18)
Sub-bitmap #1 = foreground
          0040 0080 0004 0008 2005 0000      .@...... ...
0000 7832 c7b8 782f eaa0 0400 0500 1000  ..x2..x/........
1400 0000 fffb f7fe ff17 ffbf ffcf ffff  ................
...
Type Length What
unit16 2 Width, here: hex 40=64
unit16 2 Height, here: hex 80=128
unit16 2 Numer of bitplanes, should be 4
unit16 2 Bytes per row, rounded up to multiples of 2

The value counts whole words only and can be calculated by Math.ceil(width/16)*2.

So here it’s 8 for width 64, widths 65 through 79 would have 10 bytes per row, width 80 has 12, etc.
unit16 2 BLTSIZE value
Calculated as (height<<6)|(bytesPerRow/2+1)
Here: (128<<6)|(4+1) = 8192|5 = 8198 = hex 2005
unit16 2 Anchor X (here: 0)
unit16 2 Anchor Y (here: 0)
unit8[] 8 Bitmap ID

Random value (WormPrefs generates a different ID each time), but only certain bits seem to be set. Bit mask:
78 7f ff f8 78 7f ff f8
unit16 2 Plane size, bytesPerRow * height
unit16 2 Plane size with padding word, (bytesPerRow+2) * height
unit16 2 Total size, bytesPerRow * height * planes
unit16 2 Total size with padding word, (bytesPerRow+2) * height * planes
Here: 10*128*4=5120=hex 1400
unit16 2 Always 0
unit8[] variable Uncompressed, non-interleaved bitmap data
Expected size: bytesPerRow * height * planes
Sub-bitmap #2 = background
Sub-bitmap with width 64, height 128, anchor 0,0 (like foreground)
Sub-bitmap #3 = grass
Sub-bitmap with width 32, height 8, anchor 0,0

Note: Since the landscape IFF template only has room for a height of 7, the tool inserts an empty row at the top
Sub-bitmap #4 = shade
Sub-bitmap with width 32, height 8, anchor 0,0

Note: Since the landscape IFF template only has room for a height of 7, the tool inserts an empty row at the bottom
Sub-bitmap #5 = raising bridge
Sub-bitmap with width 32, height 25, anchor 0,0
Sub-bitmap #6 = level bridge
Sub-bitmap with width 32, height 25, anchor 0,0
Sub-bitmap #7 = declining bridge
Sub-bitmap with width 32, height 25, anchor 0,0
Sub-bitmap #8 to n
The landscape elements that get placed on the map. These can be any (reasonable) size and are cropped to the pixel when being imported from a template IFF.

Here, the anchor coordinates are no longer 0,0 but point to the center of the bottom row, i.e. width/2,height-1.

MNT – mountains

Two mountain bitmaps and their palettes. The bitmaps are being preprocessed in a special way.

Start of file, colors
5752 4d32 4d4e 5453 2000 60ff 8e60 0000  WRM2MNTS .`..`..
0000 0000 0000 0000 0000 0000 0000 0000  ................
0000 0000 0000 0000                      ........
Type Length What
char[] 8 Identifier WRM2MNTS
rgb 3 Zenith color (R, G, B as bytes), here: 200060
rgb 3 Horizon color, here: ff8e60
uint8 1 Sky gradient with HSV? (0/1)
uint8[] 25 Padding bytes (all 0), total header payload size will be 32
Mountain layer palettes
                    4d4e 5431 0000 0030          MNT1...0
6400 af7b 9ce0 6982 ce58 71b6 5162 a540  d..{..i..Xq.Qb.@
5195 3742 842f 3274 2d23 632c 1b53 2513  Q.7B./2t-#c,.S%.
4a22 0c3a 2106 2b21 0025 2100 191a 0005  J".:!.+!.%!.....
4d4e 5432 0000 0030 6400 af54 a6f0 428c  MNT2...0d..T..B.
de31 7bc6 296b b518 5aa5 104a 9408 3984  .1{.)k..Z..J..9.
0829 7308 2163 0018 5a00 104a 0008 3900  .)s.!c..Z..J..9.
0031 0000 211a 0005                      .1..!...
Type Length What
char[] 4 Chunk ID MNT1 (mountain layer 1 palette)
uint32 4 Chunk size of palette, 30=48 for 16 colors (3*16)
rgb[] 3*number of colors List of R, G, B bytes, should be 16 entries for 4 bit planes
Here: 6400af, 7b9ce0, ... 1a0005
char[] 4 Chunk ID MNT2 (mountain layer 2 palette)
uint32 4 Chunk size of palette, should also be 48
rgb[] 3*number of colors List of R, G, B bytes, should be 16 entries for 4 bit planes
Here: 6400af, 54a6f0, ... 1a0005
Mountain bitmap header
                    4441 5441 5342 0002          DATASB..
Type Length What
char[] 4 Identifier DATA
char[] 2 Identifier SB (sub-bitmaps?)
unit16 2 Number of bitmaps that follow (always 2)
Mountain bitmap layer 1
0180 001c 0004 0030 0719 0000 0000 7818  .......0......x.
2090 7814 f720 0540 0578 1500 15e0 0000   .x.. .@.x......
0000 0000 0000 0000 0000 0000 0000 0000  ................
...
Sub-bitmap with width 384 (hex 180), height 28 (hex 1c), anchor 0,0 (see the DIY format info above for details)

Special bitmap processing on import:
  • First row is zeroed out (made transparent)
  • Bottom row is completely set to color #15 (counting from 0, i.e. the last palette entry)
Mountain bitmap layer 2
0180 006e 0004 0030 1b99 0000 0000 7819  ...n...0......x.
3488 7819 8710 14a0 157c 5280 55f0 0000  4.x......|R.U...
ffff ffff ffff ffff ffff ffff ffff ffff  ................
...
Sub-bitmap with width 384 (hex 180), height 110 (hex 6e), anchor 0,0

Special bitmap processing on import:
  • First row is completely set to color #15 (counting from 0, i.e. the last palette entry)
  • Bottom row is completely set to color #14

...


Reverse engineering notes

WRM2 chunk

WRM2 block custom gravity max

00 00 05 03 41 4c 50 53 00 01 01 ff 80 80 ff 80 | ....ALPS...ÿ..ÿ.
80 01 00 01 ff 80 80 ff 00 00 00 00 00 00 00 00 | ....ÿ..ÿ........
00 00 00 00 00 00 00 00 | ........

WRM2 block custom gravity min

00 00 01 03 41 4c 50 53 00 01 01 ff 80 80 ff 80 | ....ALPS...ÿ..ÿ.
80 01 00 01 ff 80 80 ff 00 00 00 00 00 00 00 00 | ....ÿ..ÿ........
00 00 00 00 00 00 00 00 | ........

WRM2 block custom friction max

00 00 03 05 41 4c 50 53 00 01 01 ff 80 80 ff 80 | ....ALPS...ÿ..ÿ.
80 01 00 01 ff 80 80 ff 00 00 00 00 00 00 00 00 | ....ÿ..ÿ........
00 00 00 00 00 00 00 00 | ........

WRM2 block custom friction min

00 00 03 01 41 4c 50 53 00 01 01 ff 80 80 ff 80 | ....ALPS...ÿ..ÿ.
80 01 00 01 ff 80 80 ff 00 00 00 00 00 00 00 00 | ....ÿ..ÿ........
00 00 00 00 00 00 00 00 | ........

WRM2 block custom destroy bg yes

00 01 03 03 41 4c 50 53 00 01 01 ff 80 80 ff 80 | ....ALPS...ÿ..ÿ.
80 01 00 01 ff 80 80 ff 00 00 00 00 00 00 00 00 | ....ÿ..ÿ........
00 00 00 00 00 00 00 00 | ........

WRM2 block custom destroy bg no

00 00 03 03 41 4c 50 53 00 01 01 ff 80 80 ff 80 | ....ALPS...ÿ..ÿ.
80 01 00 01 ff 80 80 ff 00 00 00 00 00 00 00 00 | ....ÿ..ÿ........
00 00 00 00 00 00 00 00 | ........

WRM2 block custom destroy custom sky zen 4 8 15 hor 16 23 42 (hex: 4 8 f, 10 17 2a) HSV yes

00 01 03 03 41 4c 50 53 00 01 00 04 08 0f 10 17 | ....ALPS........
2a 01 00 01 ff 80 80 ff 00 00 00 00 00 00 00 00 | *...ÿ..ÿ........
00 00 00 00 00 00 00 00 | ........

WRM2 block custom destroy custom sky zen 4 8 15 hor 16 23 42 (hex: 4 8 f, 10 17 2a) HSV no

00 01 03 03 41 4c 50 53 00 01 00 04 08 0f 10 17 | ....ALPS........
2a 00 00 01 ff 80 80 ff 00 00 00 00 00 00 00 00 | *...ÿ..ÿ........
00 00 00 00 00 00 00 00 | ........

WRM2 block custom destroy custom sky off

00 01 03 03 41 4c 50 53 00 01 01 04 08 0f 10 17 | ....ALPS........
2a 00 00 01 ff 80 80 ff 00 00 00 00 00 00 00 00 | *...ÿ..ÿ........
00 00 00 00 00 00 00 00 | ........

WRM2 block custom destroy custom sky on

00 01 03 03 41 4c 50 53 00 01 00 04 08 0f 10 17 | ....ALPS........
2a 01 00 01 ff 80 80 ff 00 00 00 00 00 00 00 00 | *...ÿ..ÿ........
00 00 00 00 00 00 00 00 | ........

WRM2 block custom: offsets with longer mountain set name - ALPS

W  R  M  2  .  .  .  (  .  .  .  .  A  L  P  S  .             .  .  .  .  .  .  .  *  .  .  .  ÿ  .  .  ÿ  .  .  .  .  .  .  .  .
57 52 4d 32 00 00 00 28 00 01 03 03 41 4c 50 53 00            01 01 04 08 0f 10 17 2a 01 00 01 ff 80 80 ff 00 00 00 00 00 00 00 00

WRM2 block custom: offsets with longer mountain set name - DEFAULT

W  R  M  2  .  .  .  ,  .  .  .  .  D  E  F  A  U  L  T  .    .  .  .  .  .  .  .  *  .  .  .  ÿ  .  .  ÿ  .  .  .  .  .  .  .  .  .
57 52 4d 32 00 00 00 2c 00 01 03 03 44 45 46 41 55 4c 54 00   01 01 04 08 0f 10 17 2a 01 00 01 ff 80 80 ff 00 00 00 00 00 00 00 00 00

A-ha! Flags continue byte-wise immediately after string terminator, even or odd, possible pad byte at the end

WRM2 custom water normal

 W  R  M  2  .  .  .  (  .  .  .  .  A  L  P  S  .  .  .  .  .  .  .  .  *  .  .  .  ÿ  .  .  ÿ  .  .  .  .  .  .  .  .
 57 52 4d 32 00 00 00 28 00 01 03 03 41 4c 50 53 00 01 01 04 08 0f 10 17 2a 01 00 01 ff 80 80 ff 00 00 00 00 00 00 00 00
...................................................  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22

WRM2 custom water gloop

 W  R  M  2  .  .  .  (  .  .  .  .  A  L  P  S  .  .  .  .  .  .  .  .  *  .  .  .  ÿ  .  .  ÿ  .  .  .  .  .  .  .  .
 57 52 4d 32 00 00 00 28 00 01 03 03 41 4c 50 53 00 01 01 04 08 0f 10 17 2a 01 01 01 ff 80 80 ff 00 00 00 00 00 00 00 00
...................................................  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22

WRM2 custom water fire

 W  R  M  2  .  .  .  (  .  .  .  .  A  L  P  S  .  .  .  .  .  .  .  .  *  .  .  .  ÿ  .  .  ÿ  .  .  .  .  .  .  .  .
 57 52 4d 32 00 00 00 28 00 01 03 03 41 4c 50 53 00 01 01 04 08 0f 10 17 2a 01 02 01 ff 80 80 ff 00 00 00 00 00 00 00 00
...................................................  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22

WRM2 custom water fire with custom color 34 35 36

 W  R  M  2  .  .  .  (  .  .  .  .  A  L  P  S  .  .  .  .  .  .  .  .  *  .  .  .  "  #  $  ÿ  .  .  .  .  .  .  .  .
 57 52 4d 32 00 00 00 28 00 01 03 03 41 4c 50 53 00 01 01 04 08 0f 10 17 2a 01 02 00 22 23 24 ff 00 00 00 00 00 00 00 00
...................................................  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22

WRM2 custom: no mountain palettes

 W  R  M  2  .  .  .  (  .  .  .  .  A  L  P  S  .  .  .  .  .  .  .  .  *  .  .  .  ÿ  .  .  ÿ  .  .  .  .  .  .  .  .
 57 52 4d 32 00 00 00 28 00 01 03 03 41 4c 50 53 00 01 01 04 08 0f 10 17 2a 01 00 01 ff 80 80 ff 00 00 00 00 00 00 00 00
...................................................  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22

WRM2 custom: mountain palettes from IFF present

 W  R  M  2  .  .  .  (  .  .  .  .  A  L  P  S  .  .  .  .  .  .  .  .  *  .  .  .  ÿ  .  .  ÿ  .  .  .  .  .  .  .  .
 57 52 4d 32 00 00 00 28 00 01 03 03 41 4c 50 53 00 00 01 04 08 0f 10 17 2a 01 00 01 ff 80 80 ff 00 00 00 00 00 00 00 00
...................................................  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22

^ Also, MNT1 and MNT2 chunks present here

Long quote

...gets ignored? at what length? 34 is fine at least

WRM2 block custom destroy bg yes

 W  R  M  2  .  .  .  (  .  .  .  .  A  L  P  S  .  .  .  .  .  .  .  .  *  .  .  .  ÿ  .  .  ÿ  .  .  .  .  .  .  .  .
 57 52 4d 32 00 00 00 28 00 01 03 03 41 4c 50 53 00 01 01 04 08 0f 10 17 2a 01 00 01 ff 80 80 ff 00 00 00 00 00 00 00 00

WRM2 block custom destroy bg no

 W  R  M  2  .  .  .  (  .  .  .  .  A  L  P  S  .  .  .  .  .  .  .  .  *  .  .  .  ÿ  .  .  ÿ  .  .  .  .  .  .  .  .
 57 52 4d 32 00 00 00 28 00 00 03 03 41 4c 50 53 00 01 01 04 08 0f 10 17 2a 01 00 01 ff 80 80 ff 00 00 00 00 00 00 00 00

Single layer

00 00 04 05 41 4c 50 53 00 00 01 ff c8 0a 00 c8 | ....ALPS...ÿÈ..È

Dual layer

01 00 04 05 41 4c 50 53 00 00 01 ff c8 0a 00 c8 | ....ALPS...ÿÈ..È

WRM2 chunk length - there's padding within the chunk payload!

mountains "DEFAULT"     : WRM2 length = 44
mountains "DEFAULTA"    : WRM2 length = 44
mountains "DEFAULTAB"   : WRM2 length = 46
mountains "DEFAULTABC"  : WRM2 length = 46
mountains "DEFAULTABCD" : WRM2 length = 48

00 00 03 03 44 45 46 41 55 4c 54 00 01 01 ff 80 | ....DEFAULT...ÿ.
80 ff 80 80 01 00 01 ff 80 80 ff 00 00 00 00 00 | .ÿ.....ÿ..ÿ.....
00 00 00 00 00 00 00 00 00 00 00 00 | ............
	
00 00 03 03 44 45 46 41 55 4c 54 41 00 01 01 ff | ....DEFAULTA...ÿ
80 80 ff 80 80 01 00 01 ff 80 80 ff 00 00 00 00 | ..ÿ.....ÿ..ÿ....
00 00 00 00 00 00 00 00 00 00 00 00 | ............

00 00 03 03 44 45 46 41 55 4c 54 41 42 00 01 01 | ....DEFAULTAB...
ff 80 80 ff 80 80 01 00 01 ff 80 80 ff 00 00 00 | ÿ..ÿ.....ÿ..ÿ...
00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ..............

00 00 03 03 44 45 46 41 55 4c 54 41 42 43 00 01 | ....DEFAULTABC..
01 ff 80 80 ff 80 80 01 00 01 ff 80 80 ff 00 00 | .ÿ..ÿ.....ÿ..ÿ..
00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ..............

QUOT chunk has inner-payload padding, too (chunk length is never odd)

WORM chunk

Weird: not generated by WormPrefs, but old WRM16 levels use it. Occurs twice?

WRM2MNTS sub-image headers

A fixed-size, 32 byte data block. Bitmap data starts immediately after it.

DYI sub-images use the same format; seems to start with w, h, planes, stride, but the rest?

Mountain layer 1 (width 384=0x180, height 28=0x1c, planes 4, stride 48=0x30)

01 80 00 1c 00 04 00 30 07 19 00 00 00 00 78 2f | .......0......x/
fe 28 78 2f dc 78 05 40 05 78 15 00 15 e0 00 00 | þ(x/Üx.@.x...à..

Mountain layer 2 (width 384=0x180, height 110=0x6e, planes 4, stride 48=0x30)

01 80 00 6e 00 04 00 30 1b 99 00 00 00 00 78 31 | ...n...0......x1
61 20 78 30 13 30 14 a0 15 7c 52 80 55 f0 00 00 | a x0.0. .|R.Uð..

Bytes after w/h/pl/str block in existing MNT files (highlighted: constant magic numbers, apparently)

ALPS.decr     : image[0] 384* 28 pl 4 str 48, then: 07 19 00 00 00 00 78 2f fe 28 78 2f dc 78 05 40 05 78 15 00 15 e0 00 00
DEFAULT.MNT   : image[0] 384* 28 pl 4 str 48, then: 07 19 00 00 00 00 78 18 20 90 78 14 f7 20 05 40 05 78 15 00 15 e0 00 00
GLACIER.MNT   : image[0] 384* 28 pl 4 str 48, then: 07 19 00 00 00 00 40 1a a8 d0 40 19 a7 80 05 40 05 78 15 00 15 e0 00 00
HELL.MNT.decr : image[0] 384* 28 pl 4 str 48, then: 07 19 00 00 00 00 78 18 1b b8 78 14 f7 20 05 40 05 78 15 00 15 e0 00 00
MARS.MNT.decr : image[0] 384* 28 pl 4 str 48, then: 07 19 00 00 00 00 78 18 21 00 78 14 f7 20 05 40 05 78 15 00 15 e0 00 00
MONEY.MNT     : image[0] 384* 28 pl 4 str 48, then: 07 19 00 00 00 00 00 2b 4b 48 00 2b 2a 38 05 40 05 78 15 00 15 e0 00 00
TURRICAN.MNT  : image[0] 384* 28 pl 4 str 48, then: 07 19 00 00 00 00 08 73 78 f8 08 6f 97 08 05 40 05 78 15 00 15 e0 00 00

ALPS.decr     : image[1] 384*110 pl 4 str 48, then: 1b 99 00 00 00 00 78 31 61 20 78 30 13 30 14 a0 15 7c 52 80 55 f0 00 00
DEFAULT.MNT   : image[1] 384*110 pl 4 str 48, then: 1b 99 00 00 00 00 78 19 34 88 78 19 87 10 14 a0 15 7c 52 80 55 f0 00 00
GLACIER.MNT   : image[1] 384*110 pl 4 str 48, then: 1b 99 00 00 00 00 40 1d 87 40 40 1a f6 10 14 a0 15 7c 52 80 55 f0 00 00
HELL.MNT.decr : image[1] 384*110 pl 4 str 48, then: 1b 99 00 00 00 00 78 19 30 c8 78 19 83 50 14 a0 15 7c 52 80 55 f0 00 00
MARS.MNT.decr : image[1] 384*110 pl 4 str 48, then: 1b 99 00 00 00 00 78 19 36 b8 78 19 89 40 14 a0 15 7c 52 80 55 f0 00 00
MONEY.MNT     : image[1] 384*110 pl 4 str 48, then: 1b 99 00 00 00 00 00 2d fb 60 00 2b 95 58 14 a0 15 7c 52 80 55 f0 00 00
TURRICAN.MNT  : image[1] 384*110 pl 4 str 48, then: 1b 99 00 00 00 00 08 73 e0 88 08 74 33 10 14 a0 15 7c 52 80 55 f0 00 00

In different order:

ALPS.decr     : image[0] 384* 28 pl 4 str 48, then: 07 19 00 00 00 00 78 2f fe 28 78 2f dc 78 05 40 05 78 15 00 15 e0 00 00
ALPS.decr     : image[1] 384*110 pl 4 str 48, then: 1b 99 00 00 00 00 78 31 61 20 78 30 13 30 14 a0 15 7c 52 80 55 f0 00 00
	
DEFAULT.MNT   : image[0] 384* 28 pl 4 str 48, then: 07 19 00 00 00 00 78 18 20 90 78 14 f7 20 05 40 05 78 15 00 15 e0 00 00
DEFAULT.MNT   : image[1] 384*110 pl 4 str 48, then: 1b 99 00 00 00 00 78 19 34 88 78 19 87 10 14 a0 15 7c 52 80 55 f0 00 00
	
GLACIER.MNT   : image[0] 384* 28 pl 4 str 48, then: 07 19 00 00 00 00 40 1a a8 d0 40 19 a7 80 05 40 05 78 15 00 15 e0 00 00
GLACIER.MNT   : image[1] 384*110 pl 4 str 48, then: 1b 99 00 00 00 00 40 1d 87 40 40 1a f6 10 14 a0 15 7c 52 80 55 f0 00 00
	
HELL.MNT.decr : image[0] 384* 28 pl 4 str 48, then: 07 19 00 00 00 00 78 18 1b b8 78 14 f7 20 05 40 05 78 15 00 15 e0 00 00
HELL.MNT.decr : image[1] 384*110 pl 4 str 48, then: 1b 99 00 00 00 00 78 19 30 c8 78 19 83 50 14 a0 15 7c 52 80 55 f0 00 00
	
MARS.MNT.decr : image[0] 384* 28 pl 4 str 48, then: 07 19 00 00 00 00 78 18 21 00 78 14 f7 20 05 40 05 78 15 00 15 e0 00 00
MARS.MNT.decr : image[1] 384*110 pl 4 str 48, then: 1b 99 00 00 00 00 78 19 36 b8 78 19 89 40 14 a0 15 7c 52 80 55 f0 00 00
	
MONEY.MNT     : image[0] 384* 28 pl 4 str 48, then: 07 19 00 00 00 00 00 2b 4b 48 00 2b 2a 38 05 40 05 78 15 00 15 e0 00 00
MONEY.MNT     : image[1] 384*110 pl 4 str 48, then: 1b 99 00 00 00 00 00 2d fb 60 00 2b 95 58 14 a0 15 7c 52 80 55 f0 00 00

TURRICAN.MNT  : image[0] 384* 28 pl 4 str 48, then: 07 19 00 00 00 00 08 73 78 f8 08 6f 97 08 05 40 05 78 15 00 15 e0 00 00
TURRICAN.MNT  : image[1] 384*110 pl 4 str 48, then: 1b 99 00 00 00 00 08 73 e0 88 08 74 33 10 14 a0 15 7c 52 80 55 f0 00 00

Oh! Those mystery bytes are random! Same name, same bitmaps, same values, different exports by WormPrefs:

00000000: 5752 4d32 4d4e 5453 7f7f 00ff 0000 0100  WRM2MNTS........     00000000: 5752 4d32 4d4e 5453 7f7f 00ff 0000 0100  WRM2MNTS........
00000010: 0000 0000 0000 0000 0000 0000 0000 0000  ................     00000010: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000020: 0000 0000 0000 0000 4d4e 5431 0000 0030  ........MNT1...0     00000020: 0000 0000 0000 0000 4d4e 5431 0000 0030  ........MNT1...0
00000030: 5413 54d7 4179 a53e 77df 3f9a ec4a c5f6  T.T.Ay.>w.?..J..     00000030: 5413 54d7 4179 a53e 77df 3f9a ec4a c5f6  T.T.Ay.>w.?..J..
00000040: 49ec e373 5c9f 239f 861f 86bf 31bf e73e  I..s\.#.....1..>     00000040: 49ec e373 5c9f 239f 861f 86bf 31bf e73e  I..s\.#.....1..>
00000050: e7ba 34b8 dc57 6cf8 b23a ee93 4b02 0002  ..4..Wl..:..K...     00000050: e7ba 34b8 dc57 6cf8 b23a ee93 4b02 0002  ..4..Wl..:..K...
00000060: 4d4e 5432 0000 0030 1f04 2829 0a37 1104  MNT2...0..().7..     00000060: 4d4e 5432 0000 0030 1f04 2829 0a37 1104  MNT2...0..().7..
00000070: 184b 1e63 7d3d a134 1448 0803 0c71 e8e3  .K.c}=.4.H...q..     00000070: 184b 1e63 7d3d a134 1448 0803 0c71 e8e3  .K.c}=.4.H...q..
00000080: 3627 5646 3a6e 2d4d 6713 2838 3e73 8b46  6'VF:n-Mg.(8>s.F     00000080: 3627 5646 3a6e 2d4d 6713 2838 3e73 8b46  6'VF:n-Mg.(8>s.F
00000090: aab1 ebfe fe02 0002 4441 5441 5342 0002  ........DATASB..     00000090: aab1 ebfe fe02 0002 4441 5441 5342 0002  ........DATASB..
000000a0: 0180 001c 0004 0030 0719 0000 0000 001c  .......0........     000000a0: 0180 001c 0004 0030 0719 0000 0000 001c  .......0........
000000b0: 1088 001a 0048 0540 0578 1500 15e0 0000  .....H.@.x......  |  000000b0: 1088 0019 ffc8 0540 0578 1500 15e0 0000  .......@.x......
                  * ***                                                                   * ***

	
< 000000a0: 0180 001c 0004 0030 0719 0000 0000 001c  .......0........
< 000000b0: 1088 0019 ffc8 0540 0578 1500 15e0 0000  .......@.x......
---
> 000000a0: 0180 001c 0004 0030 0719 0000 0000 001a  .......0........
> 000000b0: 1000 0019 f5b8 0540 0578 1500 15e0 0000  .......@.x......
350c350
< 000015d0: 1780 001d 6a08 14a0 157c 5280 55f0 0000  ....j....|R.U...
---
> 000015d0: 9098 001a 5ef8 14a0 157c 5280 55f0 0000  ....^....|R.U...

Also, they seem to be used as keys in a hash table and can mess up MNT lookup (map1.MNT can replace map2.MNT if they have the same "hash").

So, which bits are always set and which bits are filled with random data?

SB0 magic or-ed:   07 19 00 00 00 00 78 7f ff f8 78 7f ff f8 05 40 05 78 15 00 15 e0 00 00
SB1 magic or-ed:   1b 99 00 00 00 00 78 7f ff f8 78 7f ff f8 14 a0 15 7c 52 80 55 f0 00 00

SB0 magic and-ed:  07 19 00 00 00 00 00 00 00 00 00 00 00 00 05 40 05 78 15 00 15 e0 00 00
SB1 magic and-ed:  1b 99 00 00 00 00 00 00 00 00 00 00 00 00 14 a0 15 7c 52 80 55 f0 00 00

MNT mystery

WormsPrefs does something to the mountain bitmaps before exporting – I had assumed this happened when the game loads the bitmaps.

MNT layer 1: top row = all 0 (color 0), bottom row = all FF (color 15)

MNT layer 2: top row = all FF (color 15), bottom row = color 14

Without that, weird things happen, especially a solid row of color #10 on top of mountain layer 2

Also, in layer 2 color #8 is copied to color #15?!

When and how does color #15 get replaced? It's not always color #8.

Oh! That makes sense: on export, color #15 of layer 1 ("bottom") is copied to color #15 of layer 2 ("top")!

WORM chunks

Older builtin levels do not have a WRM2 chunk, but one or more WORM chunks. What's in them?

For now, parsing them like WRM2 doesn't do much harm, at least it extracts the mountain set name correctly.

DIY landscapes

Header data is different

ALPS:
57 52 4d 32 4c 41 4e 44 11 0a 03 03 41 4c 50 53 | WRM2LAND....ALPS
W  R  M  2  L  A  N  D  ** ** |  |  A  L  P  S
                        ?  ?  |  |
                              |  friction
                              gravity

                        ^  ^ WRM2 header contains "dual layer", "destroy bg" flags here
                        |  |
                        |  |
                        0x11 == 17 matches the number of images in DATA chunk
                           |
                           0x0a == 10 = maybe "landscape ID"?

00 01 01 80 80 ff 00 00 ff 01 00 01 80 00 ff 00 | .....ÿ..ÿ.....ÿ.

Seems to continue like WRM2 header: sky HSV==1, use MNT palette=01, zenith = 80 80 ff, ...

Test with 16 bitmaps (TEMPLATE.IFF):

57 52 4d 32 4c 41 4e 44 10 ab 01 05 44 45 46 41 | WRM2LAND.«..DEFA
                        images
                           ID
                              gravity
                                 friction

No QUOT? WormPrefs doesn't have it, either.

DIY sub-images

The final tedious task: What to put into the 32-byte sub-image headers of DIY levels? (see .MNT files)

ALPS.DIY

00 40  00 80   00 04   00 08                  20 05 00 00 00 00 78 34 67 d0 78 30 c3 08 04 00 05 00 10 00 14 00 00 00
width  height  planes  bytes per row (stride) |--magic id?-| 00 |--random id?---------| |--another magic id?--| 00 00

Ok, fuck it, let's compare every bitmap type of every known DIY level, then!

Bitmap headers sorted by size:

sub-bitmap  16* 38=0x10*0x26 (KRYON.DIY)           --> 09 82 00 08 00 25 40 18 c5 20 40 17 c6 40 00 4c 00 98 01 30 02 60 00 00
sub-bitmap  16* 38=0x10*0x26 (SCRAPYARD.DECR)      --> 09 82 00 08 00 25 78 32 ed 68 78 30 4c a8 00 4c 00 98 01 30 02 60 00 00
sub-bitmap  17* 14=0x11*0x e (SCRAPYARD.DECR)      --> 03 83 00 08 00 0d 78 30 4b 70 78 2f f2 f0 00 38 00 54 00 e0 01 50 00 00
sub-bitmap  17* 38=0x11*0x26 (KRYON.DIY)           --> 09 83 00 08 00 25 40 19 0e 88 40 17 c7 48 00 98 00 e4 02 60 03 90 00 00
sub-bitmap  19* 13=0x13*0x d (MARS.DECR)           --> 03 43 00 09 00 0c 78 0f 5f 68 78 0f 3b e8 00 34 00 4e 00 d0 01 38 00 00
sub-bitmap  19* 18=0x13*0x12 (SCRAPYARD.DECR)      --> 04 83 00 09 00 11 78 30 4d d8 78 30 4c 58 00 48 00 6c 01 20 01 b0 00 00
sub-bitmap  20* 11=0x14*0x b (FOREST.DECR)         --> 02 c3 00 0a 00 0a 78 0f 5f 68 78 0f 41 c0 00 2c 00 42 00 b0 01 08 00 00
sub-bitmap  20* 11=0x14*0x b (TEST1.DIY)           --> 02 c3 00 0a 00 0a 00 17 2c b0 00 16 a9 90 00 2c 00 42 00 b0 01 08 00 00
sub-bitmap  20* 11=0x14*0x b (TEST2.DIY)           --> 02 c3 00 0a 00 0a 00 17 2c b0 00 16 a9 90 00 2c 00 42 00 b0 01 08 00 00
sub-bitmap  20* 11=0x14*0x b (TEST3.DIY)           --> 02 c3 00 0a 00 0a 00 1a 76 a0 00 17 09 b8 00 2c 00 42 00 b0 01 08 00 00
sub-bitmap  21* 17=0x15*0x11 (CANDY.DIY)           --> 04 43 00 0a 00 10 00 29 ce 30 00 29 8e 50 00 44 00 66 01 10 01 98 00 00
sub-bitmap  21* 31=0x15*0x1f (HELL.DECR)           --> 07 c3 00 0a 00 1e 78 16 f4 c8 78 0f 5e f8 00 7c 00 ba 01 f0 02 e8 00 00
sub-bitmap  22* 38=0x16*0x26 (GOO.DIY)             --> 09 83 00 0b 00 25 40 27 2f 80 40 25 bc 70 00 98 00 e4 02 60 03 90 00 00
sub-bitmap  23* 47=0x17*0x2f (HELL.DECR)           --> 0b c3 00 0b 00 2e 78 1a c7 00 78 0f 60 a0 00 bc 01 1a 02 f0 04 68 00 00
sub-bitmap  24* 19=0x18*0x13 (JUNGLE.DECR)         --> 04 c3 00 0c 00 12 78 30 4b 08 78 30 4c 40 00 4c 00 72 01 30 01 c8 00 00
sub-bitmap  25* 38=0x19*0x26 (HELL.DECR)           --> 09 83 00 0c 00 25 78 19 c4 f0 78 0f 5f 80 00 98 00 e4 02 60 03 90 00 00
sub-bitmap  25* 38=0x19*0x26 (KRYON.DIY)           --> 09 83 00 0c 00 25 40 19 23 48 40 17 c8 58 00 98 00 e4 02 60 03 90 00 00
sub-bitmap  26* 14=0x1a*0x e (BEACH.DECR)          --> 03 83 00 0d 00 0d 78 30 4b e0 78 2f 93 a8 00 38 00 54 00 e0 01 50 00 00
sub-bitmap  26* 63=0x1a*0x3f (CANDY.DIY)           --> 0f c3 00 0d 00 3e 00 2b aa 00 00 2a 2b 30 00 fc 01 7a 03 f0 05 e8 00 00
sub-bitmap  28* 11=0x1c*0x b (CANDY.DIY)           --> 02 c3 00 0e 00 0a 00 29 c8 38 00 29 80 80 00 2c 00 42 00 b0 01 08 00 00
sub-bitmap  28* 20=0x1c*0x14 (BEACH.DECR)          --> 05 03 00 0e 00 13 78 30 4d d8 78 2f f5 f8 00 50 00 78 01 40 01 e0 00 00
sub-bitmap  29* 20=0x1d*0x14 (MONEY.DIY)           --> 05 03 00 0e 00 13 00 2b 9d 30 00 29 f1 08 00 50 00 78 01 40 01 e0 00 00
sub-bitmap  29* 22=0x1d*0x16 (ARCTIC.DECR)         --> 05 83 00 0e 00 15 78 30 4b a0 78 2f f4 00 00 58 00 84 01 60 02 10 00 00
sub-bitmap  29* 27=0x1d*0x1b (ALPS.DECR)           --> 06 c3 00 0e 00 1a 78 30 d5 d0 78 30 d7 88 00 6c 00 a2 01 b0 02 88 00 00
sub-bitmap  29* 31=0x1d*0x1f (ALPS.DECR)           --> 07 c3 00 0e 00 1e 78 30 d3 50 78 30 d5 48 00 7c 00 ba 01 f0 02 e8 00 00
sub-bitmap  29* 32=0x1d*0x20 (DESERT.DECR)         --> 08 03 00 0e 00 1f 78 30 4f 10 78 30 4c 98 00 80 00 c0 02 00 03 00 00 00
...
sub-bitmap  88* 92=0x58*0x5c (GOO.DIY)             --> 17 07 00 2c 00 5b 40 2a 07 40 40 2a 18 88 04 50 05 08 11 40 14 20 00 00
sub-bitmap  89* 56=0x59*0x38 (DESERT.DECR)         --> 0e 07 00 2c 00 37 78 33 25 c0 78 33 30 48 02 a0 03 10 0a 80 0c 40 00 00
sub-bitmap  90* 57=0x5a*0x39 (ARCTIC.DECR)         --> 0e 47 00 2d 00 38 78 32 f6 f8 78 33 01 b0 02 ac 03 1e 0a b0 0c 78 00 00
sub-bitmap  90*114=0x5a*0x72 (KRYON.DIY)           --> 1c 87 00 2d 00 71 40 1b 07 58 40 1b 1c c0 05 58 06 3c 15 60 18 f0 00 00
sub-bitmap  91* 74=0x5b*0x4a (MARS.DECR)           --> 12 87 00 2d 00 49 78 1c 58 90 78 1a c7 00 03 78 04 0c 0d e0 10 30 00 00
sub-bitmap  92*104=0x5c*0x68 (KRYON.DIY)           --> 1a 07 00 2e 00 67 40 1e 24 98 40 1e 38 20 04 e0 05 b0 13 80 16 c0 00 00
sub-bitmap  94* 40=0x5e*0x28 (JUNGLE.DECR)         --> 0a 07 00 2f 00 27 78 33 22 b0 78 33 2a 38 01 e0 02 30 07 80 08 c0 00 00
sub-bitmap  95* 59=0x5f*0x3b (MONEY.DIY)           --> 0e c7 00 2f 00 3a 00 2e 81 28 00 2e 8c 40 02 c4 03 3a 0b 10 0c e8 00 00
sub-bitmap  95* 78=0x5f*0x4e (MONEY.DIY)           --> 13 87 00 2f 00 4d 00 2b a9 38 00 2b b7 e0 03 a8 04 44 0e a0 11 10 00 00
sub-bitmap  96* 96=0x60*0x60 (GOO.DIY)             --> 18 07 00 30 00 5f 40 27 49 38 40 27 5b 40 04 80 05 40 12 00 15 00 00 00
sub-bitmap  98*104=0x62*0x68 (KRYON.DIY)           --> 1a 08 00 31 00 67 40 1d f6 d8 40 1e 0d a0 05 b0 06 80 16 c0 1a 00 00 00
sub-bitmap 103* 55=0x67*0x37 (SCRAPYARD.DECR)      --> 0d c8 00 33 00 36 78 32 f7 98 78 33 03 a8 03 02 03 70 0c 08 0d c0 00 00
sub-bitmap 104* 85=0x68*0x55 (MONEY.DIY)           --> 15 48 00 34 00 54 00 2e 5c a8 00 2e 6f 48 04 a6 05 50 12 98 15 40 00 00
sub-bitmap 109* 57=0x6d*0x39 (WAR.DECR)            --> 0e 48 00 36 00 38 78 34 b4 f8 78 34 c1 78 03 1e 03 90 0c 78 0e 40 00 00
sub-bitmap 111*104=0x6f*0x68 (MONEY.DIY)           --> 1a 08 00 37 00 67 00 2e 8f 10 00 2e a5 d8 05 b0 06 80 16 c0 1a 00 00 00
sub-bitmap 118*113=0x76*0x71 (KRYON.DIY)           --> 1c 49 00 3b 00 70 40 1e 3d 08 40 1e 59 50 07 10 07 f2 1c 40 1f c8 00 00
sub-bitmap 124*116=0x7c*0x74 (GOO.DIY)             --> 1d 09 00 3e 00 73 40 2a 4f 30 40 2a 6c 38 07 40 08 28 1d 00 20 a0 00 00
sub-bitmap 206*237=0xce*0xed (TEST3.DIY)           --> 3b 4e 00 67 00 ec 00 1d b6 50 00 1c b4 b0 18 12 19 ec 60 48 67 b0 00 00
                                                             *****
                                                             w/2
                                                                   *****
                                                                   h-1
w/2 and h-1 == anchor for positioning?
               normal tiles: center, bottom
               bridge tiles, bg, fg, shade, grass: 0,0

updated:

00 40  00 80   00 04   00 08                  20 05 00 00 00 00 78 34 67 d0 78 30 c3 08 04 00 05 00 10 00 14 00 00 00
width  height  planes  bytes per row (stride) |mgc| anchor x/y  |--random id?---------| |magic 2--------------| 00 00
	

Do the first bytes depend on the image size? Let's craft a DIY template, convert it with WormPrefs:

sub-bitmap  32* 25 (20 19 hex) (SZ.DIY#4)          --> 06 43 0000 0000 001be4c80017a9c0 0064 0096 0190 0258 0000
sub-bitmap  32* 25 (20 19 hex) (SZ.DIY#5)          --> 06 43 0000 0000 001c70600017ad60 0064 0096 0190 0258 0000
sub-bitmap  32* 25 (20 19 hex) (SZ.DIY#6)          --> 06 43 0000 0000 001c71f80017e430 0064 0096 0190 0258 0000
sub-bitmap  32* 25 (20 19 hex) (SZ.DIY#12)         --> 06 43 0010 0018 001cf3b00017e690 0064 0096 0190 0258 0000
sub-bitmap  32* 26 (20 1a hex) (SZ.DIY#13)         --> 06 83 0010 0019 001cf5480017f198 0068 009c 01a0 0270 0000
sub-bitmap  32* 27 (20 1b hex) (SZ.DIY#14)         --> 06 c3 0010 001a 001d000000185f58 006c 00a2 01b0 0288 0000
sub-bitmap  32* 28 (20 1c hex) (SZ.DIY#15)         --> 07 03 0010 001b 001d01b800187dd0 0070 00a8 01c0 02a0 0000


sub-bitmap  32* 25 (20 19 hex) (SZ.DIY#12)         --> 06 43 0010 0018 001cf3b00017e690 0064 0096 0190 0258 0000
sub-bitmap  33* 25 (21 19 hex) (SZ.DIY#16)         --> 06 44 0010 0018 001d0380001aaca0 0096 00c8 0258 0320 0000 
sub-bitmap  34* 25 (22 19 hex) (SZ.DIY#17)         --> 06 44 0011 0018 001d05e0001abee8 0096 00c8 0258 0320 0000 
figure out the h bits

sub-bitmap   1*  1 ( 1  1 hex) (SZ.DIY#7)          --> 00 42 00 00 00 00 00 03 9b e0 00 16 20 58 00 02 00 04 00 08 00 10 00 00 
sub-bitmap   1*  2 ( 1  2 hex) (SZ.DIY#8)          --> 00 82 00 00 00 01 00 16 60 98 00 16 22 d0 00 04 00 08 00 10 00 20 00 00 
sub-bitmap   1*  4 ( 1  4 hex) (SZ.DIY#9)          --> 01 02 00 00 00 03 00 16 d4 b8 00 16 29 e8 00 08 00 10 00 20 00 40 00 00 
sub-bitmap   1*  8 ( 1  8 hex) (SZ.DIY#10)         --> 02 02 00 00 00 07 00 17 0b 88 00 16 65 58 00 10 00 20 00 40 00 80 00 00 
sub-bitmap   1* 16 ( 1 10 hex) (SZ.DIY#11)         --> 04 02 00 00 00 0f 00 17 4e e8 00 16 d4 f8 00 20 00 40 00 80 01 00 00 00 
sub-bitmap   1* 32 ( 1 20 hex) (SZ.DIY#12)         --> 08 02 00 00 00 1f 00 17 a8 c0 00 17 10 28 00 40 00 80 01 00 02 00 00 00 
sub-bitmap   1* 64 ( 1 40 hex) (SZ.DIY#13)         --> 10 02 00 00 00 3f 00 1a a8 a0 00 17 4f 70 00 80 01 00 02 00 04 00 00 00 
sub-bitmap   1*128 ( 1 80 hex) (SZ.DIY#16)         --> 20 02 00 00 00 7f 00 1a e8 c8 00 17 e3 98 01 00 02 00 04 00 08 00 00 00 

figure out the w bits

sub-bitmap   1*  1 ( 1  1 hex) (SZ.DIY#9)          --> 00 42 00 00 00 00 00 16 28 a0 00 16 29 d8 00 02 00 04 00 08 00 10 00 00 
sub-bitmap   2*  1 ( 2  1 hex) (SZ.DIY#14)         --> 00 42 00 01 00 00 00 16 2b 80 00 16 2e 78 00 02 00 04 00 08 00 10 00 00 
sub-bitmap   4*  1 ( 4  1 hex) (SZ.DIY#15)         --> 00 42 00 02 00 00 00 16 31 20 00 16 33 08 00 02 00 04 00 08 00 10 00 00 
sub-bitmap   8*  1 ( 8  1 hex) (SZ.DIY#10)         --> 00 42 00 04 00 00 00 16 2a 10 00 16 31 20 00 02 00 04 00 08 00 10 00 00 
sub-bitmap  16*  1 (10  1 hex) (SZ.DIY#11)         --> 00 42 00 08 00 00 00 16 34 58 00 16 36 50 00 02 00 04 00 08 00 10 00 00 
sub-bitmap  32*  1 (20  1 hex) (SZ.DIY#12)         --> 00 43 00 10 00 00 00 16 a1 e8 00 16 3a 30 00 04 00 06 00 10 00 18 00 00 
sub-bitmap  64*  1 (40  1 hex) (SZ.DIY#13)         --> 00 45 00 20 00 00 00 17 13 20 00 16 3f 20 00 08 00 0a 00 20 00 28 00 00 
sub-bitmap 128*  1 (80  1 hex) (SZ.DIY#15)         --> 00 49 00 40 00 00 00 17 1d f8 00 16 a6 68 00 10 00 12 00 40 00 48 00 00
                                                       word1 anchx anchy |-----rnd-------------| word2 word3 word4 word5 |-0-|           
	
              1111_1111 = max
aa = (w and 0b1110_0000) shr 5	or 2

Again...

                                                               word1                             word2            word3            word4            word5  
bmp   1*  1 =  1  1 = 00000001 00000001 (SZ.DIY#9)           = 0000000001000010 [anchor] [8*rnd] 0000000000000010 0000000000000100 0000000000001000 0000000000010000 
bmp   2*  1 =  2  1 = 00000010 00000001 (SZ.DIY#7)           = 0000000001000010 [anchor] [8*rnd] 0000000000000010 0000000000000100 0000000000001000 0000000000010000 
bmp   4*  1 =  4  1 = 00000100 00000001 (SZ.DIY#8)           = 0000000001000010 [anchor] [8*rnd] 0000000000000010 0000000000000100 0000000000001000 0000000000010000 
bmp   8*  1 =  8  1 = 00001000 00000001 (SZ.DIY#10)          = 0000000001000010 [anchor] [8*rnd] 0000000000000010 0000000000000100 0000000000001000 0000000000010000 
bmp  16*  1 = 10  1 = 00010000 00000001 (SZ.DIY#11)          = 0000000001000010 [anchor] [8*rnd] 0000000000000010 0000000000000100 0000000000001000 0000000000010000
bmp  32*  1 = 20  1 = 00100000 00000001 (SZ.DIY#12)          = 0000000001000011 [anchor] [8*rnd] 0000000000000100 0000000000000110 0000000000010000 0000000000011000 
bmp  64*  1 = 40  1 = 01000000 00000001 (SZ.DIY#13)          = 0000000001000101 [anchor] [8*rnd] 0000000000001000 0000000000001010 0000000000100000 0000000000101000 
bmp 128*  1 = 80  1 = 10000000 00000001 (SZ.DIY#15)          = 0000000001001001 [anchor] [8*rnd] 0000000000010000 0000000000010010 0000000001000000 0000000001001000

	w   1 h1 | word2:  2	word3:  4	word1: 1<<6 |  2 = h<<6 | (1 word = 16px + 1 extra word for shifting)
	w   2 h1 | word2:  2	word3:  4	word1: 1<<6 |  2 = h<<6 | (1 word = 16px + 1 extra word for shifting)
	w   4 h1 | word2:  2	word3:  4	word1: 1<<6 |  2 = h<<6 | (1 word = 16px + 1 extra word for shifting)
	w   8 h1 | word2:  2	word3:  4	word1: 1<<6 |  2 = h<<6 | (1 word = 16px + 1 extra word for shifting)
	w  16 h1 | word2:  2	word3:  4	word1: 1<<6 |  2 = h<<6 | (1 word = 16px + 1 extra word for shifting)
	w  32 h1 | word2:  4	word3:  6	word1: 1<<6 |  3 = h<<6 | (2 words= 32px + 1 extra word for shifting)
	w  64 h1 | word2:  8	word3: 10	word1: 1<<6 |  5 = h<<6 | (4 words= 64px + 1 extra word for shifting)
	w 128 h1 | word2: 16	word3: 18	word1: 1<<6 |  9 = h<<6 | (8 words=128px + 1 extra word for shifting)

	word1 = bltsize for 1 plane? bltsize = (height<<6) | width_words
	word2 = single-plane size in bytes? (word-sized, 1 word minimum = 2 bytes)
	word3 = word2*2 + 2? (singe-plane size + extra word, i.e. 2 bytes)
	word4 = word2 * 4?
	word5 = word3 * 4?
	
bmp   1*  1 =  1  1 = 00000001 00000001 (SZ.DIY#9)           = 0000000001000010 [anchor] [8*rnd] 0000000000000010 0000000000000100 0000000000001000 0000000000010000 
bmp   1*  2 =  1  2 = 00000001 00000010 (SZ.DIY#7)           = 0000000010000010 [anchor] [8*rnd] 0000000000000100 0000000000001000 0000000000010000 0000000000100000 
bmp   1*  4 =  1  4 = 00000001 00000100 (SZ.DIY#10)          = 0000000100000010 [anchor] [8*rnd] 0000000000001000 0000000000010000 0000000000100000 0000000001000000 
bmp   1*  8 =  1  8 = 00000001 00001000 (SZ.DIY#11)          = 0000001000000010 [anchor] [8*rnd] 0000000000010000 0000000000100000 0000000001000000 0000000010000000 
bmp   1* 16 =  1 10 = 00000001 00010000 (SZ.DIY#12)          = 0000010000000010 [anchor] [8*rnd] 0000000000100000 0000000001000000 0000000010000000 0000000100000000 
bmp   1* 32 =  1 20 = 00000001 00100000 (SZ.DIY#13)          = 0000100000000010 [anchor] [8*rnd] 0000000001000000 0000000010000000 0000000100000000 0000001000000000 
bmp   1* 64 =  1 40 = 00000001 01000000 (SZ.DIY#16)          = 0001000000000010 [anchor] [8*rnd] 0000000010000000 0000000100000000 0000001000000000 0000010000000000 
bmp   1*128 =  1 80 = 00000001 10000000 (SZ.DIY#17)          = 0010000000000010 [anchor] [8*rnd] 0000000100000000 0000001000000000 0000010000000000 0000100000000000
                                                                 hhhhhhhh......                         hhhhhhhh.       hhhhhhhh..      hhhhhhhh...     hhhhhhhh.... 
	w 1 h   1 | word2:   2
	w 1 h   2 | word2:   4
	w 1 h   4 | word2:   8
	w 1 h   8 | word2:  16
	w 1 h  16 | word2:  32
	w 1 h  32 | word2:  64
	w 1 h  64 | word2: 128
	w 1 h 128 | word2: 256
	
	above with width 32
	
bmp  32*  1 = 20  1 = 00100000 00000001 (SZ.DIY#7)           = 0000000001000011 [anchor] [8*rnd] 0000000000000100 0000000000000110 0000000000010000 0000000000011000 
bmp  32*  2 = 20  2 = 00100000 00000010 (SZ.DIY#8)           = 0000000010000011 [anchor] [8*rnd] 0000000000001000 0000000000001100 0000000000100000 0000000000110000 
bmp  32*  4 = 20  4 = 00100000 00000100 (SZ.DIY#9)           = 0000000100000011 [anchor] [8*rnd] 0000000000010000 0000000000011000 0000000001000000 0000000001100000 
bmp  32*  8 = 20  8 = 00100000 00001000 (SZ.DIY#10)          = 0000001000000011 [anchor] [8*rnd] 0000000000100000 0000000000110000 0000000010000000 0000000011000000 
bmp  32* 16 = 20 10 = 00100000 00010000 (SZ.DIY#11)          = 0000010000000011 [anchor] [8*rnd] 0000000001000000 0000000001100000 0000000100000000 0000000110000000 
bmp  32* 32 = 20 20 = 00100000 00100000 (SZ.DIY#12)          = 0000100000000011 [anchor] [8*rnd] 0000000010000000 0000000011000000 0000001000000000 0000001100000000 
bmp  32* 64 = 20 40 = 00100000 01000000 (SZ.DIY#13)          = 0001000000000011 [anchor] [8*rnd] 0000000100000000 0000000110000000 0000010000000000 0000011000000000 
bmp  32*128 = 20 80 = 00100000 10000000 (SZ.DIY#14)          = 0010000000000011 [anchor] [8*rnd] 0000001000000000 0000001100000000 0000100000000000 0000110000000000
	
	above with width 64
	
bmp  64*  1 = 40  1 = 01000000 00000001 (SZ.DIY#7)           = 0000000001000101 [anchor] [8*rnd] 0000000000001000 0000000000001010 0000000000100000 0000000000101000 
bmp  64*  2 = 40  2 = 01000000 00000010 (SZ.DIY#8)           = 0000000010000101 [anchor] [8*rnd] 0000000000010000 0000000000010100 0000000001000000 0000000001010000 
bmp  64*  4 = 40  4 = 01000000 00000100 (SZ.DIY#9)           = 0000000100000101 [anchor] [8*rnd] 0000000000100000 0000000000101000 0000000010000000 0000000010100000 
bmp  64*  8 = 40  8 = 01000000 00001000 (SZ.DIY#10)          = 0000001000000101 [anchor] [8*rnd] 0000000001000000 0000000001010000 0000000100000000 0000000101000000 
bmp  64* 16 = 40 10 = 01000000 00010000 (SZ.DIY#11)          = 0000010000000101 [anchor] [8*rnd] 0000000010000000 0000000010100000 0000001000000000 0000001010000000 
bmp  64* 32 = 40 20 = 01000000 00100000 (SZ.DIY#12)          = 0000100000000101 [anchor] [8*rnd] 0000000100000000 0000000101000000 0000010000000000 0000010100000000 
bmp  64* 64 = 40 40 = 01000000 01000000 (SZ.DIY#13)          = 0001000000000101 [anchor] [8*rnd] 0000001000000000 0000001010000000 0000100000000000 0000101000000000 
bmp  64*128 = 40 80 = 01000000 10000000 (SZ.DIY#0)           = 0010000000000101 [anchor] [8*rnd] 0000010000000000 0000010100000000 0001000000000000 0001010000000000 
	
	
bmp   2*  2 =  2  2 = 00000010 00000010 (SZ.DIY#8)           = 0000000010000010 [anchor] [8*rnd] 0000000000000100 0000000000001000 0000000000010000 0000000000100000 
bmp   4*  4 =  4  4 = 00000100 00000100 (SZ.DIY#14)          = 0000000100000010 [anchor] [8*rnd] 0000000000001000 0000000000010000 0000000000100000 0000000001000000 
bmp  64* 64 = 40 40 = 01000000 01000000 (SZ.DIY#15)          = 0001000000000101 [anchor] [8*rnd] 0000001000000000 0000001010000000 0000100000000000 0000101000000000 


w,h 63
bmp   1* 63 =  1 3f = 00000001 00111111 (SZ.DIY#15)          = 00001111 11000010 [anchor] [8*rnd] 00000000 01111110 00000000 11111100 00000001 11111000 00000011 11110000 
bmp  63*  1 = 3f  1 = 00111111 00000001 (SZ.DIY#13)          = 00000000 01000101 [anchor] [8*rnd] 00000000 00001000 00000000 00001010 00000000 00100000 00000000 00101000 
bmp  63* 63 = 3f 3f = 00111111 00111111 (SZ.DIY#14)          = 00001111 11000101 [anchor] [8*rnd] 00000001 11111000 00000010 01110110 00000111 11100000 00001001 11011000 

Is this really necessary? Is there a weird/simple hashing of w and h going on? Bits 0 to 4 of width don't even make a difference!

Well, if those are BLTSIZE values etc., probably yes...

DATA sub-image solution first half

Compare what we got: anchord, word1, word3, word4 (OK = matches hypothesis, MIS = mismatch)

bmp  29* 20 = 1d 14 = 00011101 00010100 (MONEY.DIY#7)        = (str   4 pl 4) anchor OK   14, 19 [ 14, 19] word1 OK   20<<6|  3 [ 20<<6|  3] word2 OK    80 [  80] word3 MIS  120 [ 162] word4 OK   320 [ 320] word5 MIS  480 [ 648]
bmp  29* 22 = 1d 16 = 00011101 00010110 (ARCTIC.DECR#7)      = (str   4 pl 4) anchor OK   14, 21 [ 14, 21] word1 OK   22<<6|  3 [ 22<<6|  3] word2 OK    88 [  88] word3 MIS  132 [ 178] word4 OK   352 [ 352] word5 MIS  528 [ 712]
bmp  29* 27 = 1d 1b = 00011101 00011011 (ALPS.DECR#8)        = (str   4 pl 4) anchor OK   14, 26 [ 14, 26] word1 OK   27<<6|  3 [ 27<<6|  3] word2 OK   108 [ 108] word3 MIS  162 [ 218] word4 OK   432 [ 432] word5 MIS  648 [ 872]
bmp  29* 31 = 1d 1f = 00011101 00011111 (ALPS.DECR#7)        = (str   4 pl 4) anchor OK   14, 30 [ 14, 30] word1 OK   31<<6|  3 [ 31<<6|  3] word2 OK   124 [ 124] word3 MIS  186 [ 250] word4 OK   496 [ 496] word5 MIS  744 [1000]
bmp  29* 32 = 1d 20 = 00011101 00100000 (DESERT.DECR#8)      = (str   4 pl 4) anchor OK   14, 31 [ 14, 31] word1 OK   32<<6|  3 [ 32<<6|  3] word2 OK   128 [ 128] word3 MIS  192 [ 258] word4 OK   512 [ 512] word5 MIS  768 [1032]
bmp  30* 22 = 1e 16 = 00011110 00010110 (FOREST.DECR#8)      = (str   4 pl 4) anchor OK   15, 21 [ 15, 21] word1 OK   22<<6|  3 [ 22<<6|  3] word2 OK    88 [  88] word3 MIS  132 [ 178] word4 OK   352 [ 352] word5 MIS  528 [ 712]
bmp  30* 23 = 1e 17 = 00011110 00010111 (FOREST.DECR#9)      = (str   4 pl 4) anchor OK   15, 22 [ 15, 22] word1 OK   23<<6|  3 [ 23<<6|  3] word2 OK    92 [  92] word3 MIS  138 [ 186] word4 OK   368 [ 368] word5 MIS  552 [ 744]
bmp  30* 38 = 1e 26 = 00011110 00100110 (KRYON.DIY#10)       = (str   4 pl 4) anchor OK   15, 37 [ 15, 37] word1 OK   38<<6|  3 [ 38<<6|  3] word2 OK   152 [ 152] word3 MIS  228 [ 306] word4 OK   608 [ 608] word5 MIS  912 [1224]
bmp  30* 71 = 1e 47 = 00011110 01000111 (HELL.DECR#13)       = (str   4 pl 4) anchor OK   15, 70 [ 15, 70] word1 OK   71<<6|  3 [ 71<<6|  3] word2 OK   284 [ 284] word3 MIS  426 [ 570] word4 OK  1136 [1136] word5 MIS 1704 [2280]
bmp  31* 48 = 1f 30 = 00011111 00110000 (DESERT.DECR#15)     = (str   4 pl 4) anchor OK   15, 47 [ 15, 47] word1 OK   48<<6|  3 [ 48<<6|  3] word2 OK   192 [ 192] word3 MIS  288 [ 386] word4 OK   768 [ 768] word5 MIS 1152 [1544]
bmp  32*  8 = 20  8 = 00100000 00001000 (ALIEN.DECR#2)       = (str   4 pl 4) anchor MIS   0,  0 [ 16,  7] word1 OK    8<<6|  3 [  8<<6|  3] word2 OK    32 [  32] word3 MIS   48 [  66] word4 OK   128 [ 128] word5 MIS  192 [ 264]
bmp  46* 59 = 2e 3b = 00101110 00111011 (ALIEN.DIY.WRM16#9)  = (str   6 pl 4) anchor OK   23, 58 [ 23, 58] word1 OK   59<<6|  4 [ 59<<6|  4] word2 OK   354 [ 354] word3 MIS  472 [ 710] word4 OK  1416 [1416] word5 MIS 1888 [2840]
bmp  47* 31 = 2f 1f = 00101111 00011111 (ALPS.DECR#9)        = (str   6 pl 4) anchor OK   23, 30 [ 23, 30] word1 OK   31<<6|  4 [ 31<<6|  4] word2 OK   186 [ 186] word3 MIS  248 [ 374] word4 OK   744 [ 744] word5 MIS  992 [1496]
bmp  47* 34 = 2f 22 = 00101111 00100010 (SCRAPYARD.DECR#16)  = (str   6 pl 4) anchor OK   23, 33 [ 23, 33] word1 OK   34<<6|  4 [ 34<<6|  4] word2 OK   204 [ 204] word3 MIS  272 [ 410] word4 OK   816 [ 816] word5 MIS 1088 [1640]
bmp  48* 33 = 30 21 = 00110000 00100001 (ALPS.DECR#10)       = (str   6 pl 4) anchor OK   24, 32 [ 24, 32] word1 OK   33<<6|  4 [ 33<<6|  4] word2 OK   198 [ 198] word3 MIS  264 [ 398] word4 OK   792 [ 792] word5 MIS 1056 [1592]
bmp  48* 41 = 30 29 = 00110000 00101001 (GRAVEYARD.DECR#12)  = (str   6 pl 4) anchor OK   24, 40 [ 24, 40] word1 OK   41<<6|  4 [ 41<<6|  4] word2 OK   246 [ 246] word3 MIS  328 [ 494] word4 OK   984 [ 984] word5 MIS 1312 [1976]
bmp  50* 38 = 32 26 = 00110010 00100110 (GOO.DIY#9)          = (str   8 pl 4) anchor OK   25, 37 [ 25, 37] word1 OK   38<<6|  5 [ 38<<6|  5] word2 OK   304 [ 304] word3 MIS  380 [ 610] word4 OK  1216 [1216] word5 MIS 1520 [2440]
bmp  51* 17 = 33 11 = 00110011 00010001 (MARS.DECR#8)        = (str   8 pl 4) anchor OK   25, 16 [ 25, 16] word1 OK   17<<6|  5 [ 17<<6|  5] word2 OK   136 [ 136] word3 MIS  170 [ 274] word4 OK   544 [ 544] word5 MIS  680 [1096]

anchor MIS is ok for fixed images: fg, bg, bridges, shade, grass always have anchor 0,0

word3 is something different, but once that's correct, word5 seems to be word3*4

What's with word3, then?

w  h    str  pl                                          
29 20     4   4    word3  120
29 22     4   4    word3  132
29 27     4   4    word3  162
29 31     4   4    word3  186
29 32     4   4    word3  192
30 22     4   4    word3  132
30 23     4   4    word3  138
30 38     4   4    word3  228
30 71     4   4    word3  426
31 48     4   4    word3  288
32  8     4   4    word3   48
46 59     6   4    word3  472
47 31     6   4    word3  248
47 34     6   4    word3  272
48 33     6   4    word3  264
48 41     6   4    word3  328
50 38     8   4    word3  380
51 17     8   4    word3  170

	(str+2)*h? YESS!!

Sub-image header format is go!

So now all mystery bytes are understood! Phew!

[000228] SB  1/18: DESERT.DECR         : w  64 h 128 pl   4 str   8 header = (str   8 pl 4) anchor OK    0,  0 [  0,  0] word1 OK  128<<6|  5 [128<<6|  5] word2 OK  1024 [1024] word3 OK  1280 [1280] word4 OK  4096 [4096] word5 OK  5120 [5120]
[004356] SB  2/18: DESERT.DECR         : w  64 h 128 pl   4 str   8 header = (str   8 pl 4) anchor OK    0,  0 [  0,  0] word1 OK  128<<6|  5 [128<<6|  5] word2 OK  1024 [1024] word3 OK  1280 [1280] word4 OK  4096 [4096] word5 OK  5120 [5120]
[008484] SB  3/18: DESERT.DECR         : w  32 h   8 pl   4 str   4 header = (str   4 pl 4) anchor OK    0,  0 [  0,  0] word1 OK    8<<6|  3 [  8<<6|  3] word2 OK    32 [  32] word3 OK    48 [  48] word4 OK   128 [ 128] word5 OK   192 [ 192]
[008644] SB  4/18: DESERT.DECR         : w  32 h   8 pl   4 str   4 header = (str   4 pl 4) anchor OK    0,  0 [  0,  0] word1 OK    8<<6|  3 [  8<<6|  3] word2 OK    32 [  32] word3 OK    48 [  48] word4 OK   128 [ 128] word5 OK   192 [ 192]
[008804] SB  5/18: DESERT.DECR         : w  32 h  25 pl   4 str   4 header = (str   4 pl 4) anchor OK    0,  0 [  0,  0] word1 OK   25<<6|  3 [ 25<<6|  3] word2 OK   100 [ 100] word3 OK   150 [ 150] word4 OK   400 [ 400] word5 OK   600 [ 600]
[009236] SB  6/18: DESERT.DECR         : w  32 h  25 pl   4 str   4 header = (str   4 pl 4) anchor OK    0,  0 [  0,  0] word1 OK   25<<6|  3 [ 25<<6|  3] word2 OK   100 [ 100] word3 OK   150 [ 150] word4 OK   400 [ 400] word5 OK   600 [ 600]
[009668] SB  7/18: DESERT.DECR         : w  32 h  25 pl   4 str   4 header = (str   4 pl 4) anchor OK    0,  0 [  0,  0] word1 OK   25<<6|  3 [ 25<<6|  3] word2 OK   100 [ 100] word3 OK   150 [ 150] word4 OK   400 [ 400] word5 OK   600 [ 600]
[010100] SB  8/18: DESERT.DECR         : w  32 h  19 pl   4 str   4 header = (str   4 pl 4) anchor OK   16, 18 [ 16, 18] word1 OK   19<<6|  3 [ 19<<6|  3] word2 OK    76 [  76] word3 OK   114 [ 114] word4 OK   304 [ 304] word5 OK   456 [ 456]
[010436] SB  9/18: DESERT.DECR         : w  29 h  32 pl   4 str   4 header = (str   4 pl 4) anchor OK   14, 31 [ 14, 31] word1 OK   32<<6|  3 [ 32<<6|  3] word2 OK   128 [ 128] word3 OK   192 [ 192] word4 OK   512 [ 512] word5 OK   768 [ 768]
[010980] SB 10/18: DESERT.DECR         : w  38 h  22 pl   4 str   6 header = (str   6 pl 4) anchor OK   19, 21 [ 19, 21] word1 OK   22<<6|  4 [ 22<<6|  4] word2 OK   132 [ 132] word3 OK   176 [ 176] word4 OK   528 [ 528] word5 OK   704 [ 704]
[011540] SB 11/18: DESERT.DECR         : w  39 h  27 pl   4 str   6 header = (str   6 pl 4) anchor OK   19, 26 [ 19, 26] word1 OK   27<<6|  4 [ 27<<6|  4] word2 OK   162 [ 162] word3 OK   216 [ 216] word4 OK   648 [ 648] word5 OK   864 [ 864]
[012220] SB 12/18: DESERT.DECR         : w  59 h  66 pl   4 str   8 header = (str   8 pl 4) anchor OK   29, 65 [ 29, 65] word1 OK   66<<6|  5 [ 66<<6|  5] word2 OK   528 [ 528] word3 OK   660 [ 660] word4 OK  2112 [2112] word5 OK  2640 [2640]
[014364] SB 13/18: DESERT.DECR         : w  55 h  50 pl   4 str   8 header = (str   8 pl 4) anchor OK   27, 49 [ 27, 49] word1 OK   50<<6|  5 [ 50<<6|  5] word2 OK   400 [ 400] word3 OK   500 [ 500] word4 OK  1600 [1600] word5 OK  2000 [2000]
[015996] SB 14/18: DESERT.DECR         : w  37 h  56 pl   4 str   6 header = (str   6 pl 4) anchor OK   18, 55 [ 18, 55] word1 OK   56<<6|  4 [ 56<<6|  4] word2 OK   336 [ 336] word3 OK   448 [ 448] word4 OK  1344 [1344] word5 OK  1792 [1792]
[017372] SB 15/18: DESERT.DECR         : w  87 h  70 pl   4 str  12 header = (str  12 pl 4) anchor OK   43, 69 [ 43, 69] word1 OK   70<<6|  7 [ 70<<6|  7] word2 OK   840 [ 840] word3 OK   980 [ 980] word4 OK  3360 [3360] word5 OK  3920 [3920]
[020764] SB 16/18: DESERT.DECR         : w  31 h  48 pl   4 str   4 header = (str   4 pl 4) anchor OK   15, 47 [ 15, 47] word1 OK   48<<6|  3 [ 48<<6|  3] word2 OK   192 [ 192] word3 OK   288 [ 288] word4 OK   768 [ 768] word5 OK  1152 [1152]
[021564] SB 17/18: DESERT.DECR         : w  40 h  70 pl   4 str   6 header = (str   6 pl 4) anchor OK   20, 69 [ 20, 69] word1 OK   70<<6|  4 [ 70<<6|  4] word2 OK   420 [ 420] word3 OK   560 [ 560] word4 OK  1680 [1680] word5 OK  2240 [2240]
[023276] SB 18/18: DESERT.DECR         : w  89 h  56 pl   4 str  12 header = (str  12 pl 4) anchor OK   44, 55 [ 44, 55] word1 OK   56<<6|  7 [ 56<<6|  7] word2 OK   672 [ 672] word3 OK   784 [ 784] word4 OK  2688 [2688] word5 OK  3136 [3136]

[000116] SB  1/16: FOREST.DECR         : w  64 h 128 pl   4 str   8 header = (str   8 pl 4) anchor OK    0,  0 [  0,  0] word1 OK  128<<6|  5 [128<<6|  5] word2 OK  1024 [1024] word3 OK  1280 [1280] word4 OK  4096 [4096] word5 OK  5120 [5120]
[004244] SB  2/16: FOREST.DECR         : w  64 h 128 pl   4 str   8 header = (str   8 pl 4) anchor OK    0,  0 [  0,  0] word1 OK  128<<6|  5 [128<<6|  5] word2 OK  1024 [1024] word3 OK  1280 [1280] word4 OK  4096 [4096] word5 OK  5120 [5120]
[008372] SB  3/16: FOREST.DECR         : w  32 h   8 pl   4 str   4 header = (str   4 pl 4) anchor OK    0,  0 [  0,  0] word1 OK    8<<6|  3 [  8<<6|  3] word2 OK    32 [  32] word3 OK    48 [  48] word4 OK   128 [ 128] word5 OK   192 [ 192]
[008532] SB  4/16: FOREST.DECR         : w  32 h   8 pl   4 str   4 header = (str   4 pl 4) anchor OK    0,  0 [  0,  0] word1 OK    8<<6|  3 [  8<<6|  3] word2 OK    32 [  32] word3 OK    48 [  48] word4 OK   128 [ 128] word5 OK   192 [ 192]
[008692] SB  5/16: FOREST.DECR         : w  32 h  25 pl   4 str   4 header = (str   4 pl 4) anchor OK    0,  0 [  0,  0] word1 OK   25<<6|  3 [ 25<<6|  3] word2 OK   100 [ 100] word3 OK   150 [ 150] word4 OK   400 [ 400] word5 OK   600 [ 600]
[009124] SB  6/16: FOREST.DECR         : w  32 h  25 pl   4 str   4 header = (str   4 pl 4) anchor OK    0,  0 [  0,  0] word1 OK   25<<6|  3 [ 25<<6|  3] word2 OK   100 [ 100] word3 OK   150 [ 150] word4 OK   400 [ 400] word5 OK   600 [ 600]
[009556] SB  7/16: FOREST.DECR         : w  32 h  25 pl   4 str   4 header = (str   4 pl 4) anchor OK    0,  0 [  0,  0] word1 OK   25<<6|  3 [ 25<<6|  3] word2 OK   100 [ 100] word3 OK   150 [ 150] word4 OK   400 [ 400] word5 OK   600 [ 600]
[009988] SB  8/16: FOREST.DECR         : w  20 h  11 pl   4 str   4 header = (str   4 pl 4) anchor OK   10, 10 [ 10, 10] word1 OK   11<<6|  3 [ 11<<6|  3] word2 OK    44 [  44] word3 OK    66 [  66] word4 OK   176 [ 176] word5 OK   264 [ 264]
[010196] SB  9/16: FOREST.DECR         : w  30 h  22 pl   4 str   4 header = (str   4 pl 4) anchor OK   15, 21 [ 15, 21] word1 OK   22<<6|  3 [ 22<<6|  3] word2 OK    88 [  88] word3 OK   132 [ 132] word4 OK   352 [ 352] word5 OK   528 [ 528]
[010580] SB 10/16: FOREST.DECR         : w  30 h  23 pl   4 str   4 header = (str   4 pl 4) anchor OK   15, 22 [ 15, 22] word1 OK   23<<6|  3 [ 23<<6|  3] word2 OK    92 [  92] word3 OK   138 [ 138] word4 OK   368 [ 368] word5 OK   552 [ 552]
[010980] SB 11/16: FOREST.DECR         : w  40 h  19 pl   4 str   6 header = (str   6 pl 4) anchor OK   20, 18 [ 20, 18] word1 OK   19<<6|  4 [ 19<<6|  4] word2 OK   114 [ 114] word3 OK   152 [ 152] word4 OK   456 [ 456] word5 OK   608 [ 608]
[011468] SB 12/16: FOREST.DECR         : w  45 h  47 pl   4 str   6 header = (str   6 pl 4) anchor OK   22, 46 [ 22, 46] word1 OK   47<<6|  4 [ 47<<6|  4] word2 OK   282 [ 282] word3 OK   376 [ 376] word4 OK  1128 [1128] word5 OK  1504 [1504]
[012628] SB 13/16: FOREST.DECR         : w  60 h 108 pl   4 str   8 header = (str   8 pl 4) anchor OK   30,107 [ 30,107] word1 OK  108<<6|  5 [108<<6|  5] word2 OK   864 [ 864] word3 OK  1080 [1080] word4 OK  3456 [3456] word5 OK  4320 [4320]
[016116] SB 14/16: FOREST.DECR         : w  57 h  60 pl   4 str   8 header = (str   8 pl 4) anchor OK   28, 59 [ 28, 59] word1 OK   60<<6|  5 [ 60<<6|  5] word2 OK   480 [ 480] word3 OK   600 [ 600] word4 OK  1920 [1920] word5 OK  2400 [2400]
[018068] SB 15/16: FOREST.DECR         : w  54 h  70 pl   4 str   8 header = (str   8 pl 4) anchor OK   27, 69 [ 27, 69] word1 OK   70<<6|  5 [ 70<<6|  5] word2 OK   560 [ 560] word3 OK   700 [ 700] word4 OK  2240 [2240] word5 OK  2800 [2800]
[020340] SB 16/16: FOREST.DECR         : w  36 h  71 pl   4 str   6 header = (str   6 pl 4) anchor OK   18, 70 [ 18, 70] word1 OK   71<<6|  4 [ 71<<6|  4] word2 OK   426 [ 426] word3 OK   568 [ 568] word4 OK  1704 [1704] word5 OK  2272 [2272]

Also, luckily the SB format is also used for the mountains in exactly this way:

[000160] SB  1/ 2: ALPS.decr           : w 384 h  28 pl   4 str  48 header = (str  48 pl 4) anchor OK    0,  0 [  0,  0] word1 OK   28<<6| 25 [ 28<<6| 25] word2 OK  1344 [1344] word3 OK  1400 [1400] word4 OK   5376 [ 5376] word5 OK   5600 [ 5600]
[005568] SB  2/ 2: ALPS.decr           : w 384 h 110 pl   4 str  48 header = (str  48 pl 4) anchor OK    0,  0 [  0,  0] word1 OK  110<<6| 25 [110<<6| 25] word2 OK  5280 [5280] word3 OK  5500 [5500] word4 OK  21120 [21120] word5 OK  22000 [22000]
[000160] SB  1/ 2: DEFAULT.MNT         : w 384 h  28 pl   4 str  48 header = (str  48 pl 4) anchor OK    0,  0 [  0,  0] word1 OK   28<<6| 25 [ 28<<6| 25] word2 OK  1344 [1344] word3 OK  1400 [1400] word4 OK   5376 [ 5376] word5 OK   5600 [ 5600]
[005568] SB  2/ 2: DEFAULT.MNT         : w 384 h 110 pl   4 str  48 header = (str  48 pl 4) anchor OK    0,  0 [  0,  0] word1 OK  110<<6| 25 [110<<6| 25] word2 OK  5280 [5280] word3 OK  5500 [5500] word4 OK  21120 [21120] word5 OK  22000 [22000]
[000160] SB  1/ 2: GLACIER.MNT         : w 384 h  28 pl   4 str  48 header = (str  48 pl 4) anchor OK    0,  0 [  0,  0] word1 OK   28<<6| 25 [ 28<<6| 25] word2 OK  1344 [1344] word3 OK  1400 [1400] word4 OK   5376 [ 5376] word5 OK   5600 [ 5600]
[005568] SB  2/ 2: GLACIER.MNT         : w 384 h 110 pl   4 str  48 header = (str  48 pl 4) anchor OK    0,  0 [  0,  0] word1 OK  110<<6| 25 [110<<6| 25] word2 OK  5280 [5280] word3 OK  5500 [5500] word4 OK  21120 [21120] word5 OK  22000 [22000]
[000160] SB  1/ 2: SAND.MNT.decr       : w 384 h  28 pl   4 str  48 header = (str  48 pl 4) anchor OK    0,  0 [  0,  0] word1 OK   28<<6| 25 [ 28<<6| 25] word2 OK  1344 [1344] word3 OK  1400 [1400] word4 OK   5376 [ 5376] word5 OK   5600 [ 5600]
[005568] SB  2/ 2: SAND.MNT.decr       : w 384 h 110 pl   4 str  48 header = (str  48 pl 4) anchor OK    0,  0 [  0,  0] word1 OK  110<<6| 25 [110<<6| 25] word2 OK  5280 [5280] word3 OK  5500 [5500] word4 OK  21120 [21120] word5 OK  22000 [22000]
[000160] SB  1/ 2: TOYS.MNT.decr       : w 384 h  28 pl   4 str  48 header = (str  48 pl 4) anchor OK    0,  0 [  0,  0] word1 OK   28<<6| 25 [ 28<<6| 25] word2 OK  1344 [1344] word3 OK  1400 [1400] word4 OK   5376 [ 5376] word5 OK   5600 [ 5600]
[005568] SB  2/ 2: TOYS.MNT.decr       : w 384 h 110 pl   4 str  48 header = (str  48 pl 4) anchor OK    0,  0 [  0,  0] word1 OK  110<<6| 25 [110<<6| 25] word2 OK  5280 [5280] word3 OK  5500 [5500] word4 OK  21120 [21120] word5 OK  22000 [22000]
[000160] SB  1/ 2: TURRICAN.MNT        : w 384 h  28 pl   4 str  48 header = (str  48 pl 4) anchor OK    0,  0 [  0,  0] word1 OK   28<<6| 25 [ 28<<6| 25] word2 OK  1344 [1344] word3 OK  1400 [1400] word4 OK   5376 [ 5376] word5 OK   5600 [ 5600]
[005568] SB  2/ 2: TURRICAN.MNT        : w 384 h 110 pl   4 str  48 header = (str  48 pl 4) anchor OK    0,  0 [  0,  0] word1 OK  110<<6| 25 [110<<6| 25] word2 OK  5280 [5280] word3 OK  5500 [5500] word4 OK  21120 [21120] word5 OK  22000 [22000]