Escape from Haunted House formats

IMV archive format

  8 bytes - "IMV 0.67"
  8 bytes - unknown
  4 bytes - record block size
  N bytes - record block
  4 bytes - size of block with filenames
  M bytes - filenames (zero-terminated)
  4*K bytes - some variables for each filename
  [data referenced in record block]

Record block contains variable-length records with various entries metadata or even actual content. Each record starts with 16-bit type. Known record types are:

  • 0x00 – end marker
  • 0x01 – some marker
  • 0x02 – some marker
  • 0x0A – 4 bytes, unknown
  • 0x0B – 4 bytes size + 11-byte payload, unknown
  • 0x0C – 4 bytes, unknown
  • 0x0D – 4 bytes, unknown
  • 0x0E – 4 bytes – unknown, 4 bytes – unknown, 4 bytes – following payload size minus one
  • 0x0F – payload size is src[4] * 8 + *(int*)(src+5) + 1
  • 0x14 – bitmap: 4 bytes – size, 4 bytes – offset, 10 bytes – bitmap header (dimensions, compression, palette present flag);
  • 0x15 – cursor? 130 bytes of payload
  • 0x16 – video file, 4 bytes – size, 10 bytes – header, 4 bytes – offset
  • 0x17 – 30 bytes, unknown
  • 0x18 – 4 bytes – unknown, 4 bytes – number of 12-byte payload entries
  • 0x19 – 4 bytes – unknown, 4 bytes – number of 4-byte payload entries
  • 0x1E – audio files (loaded from SF.DLL?)
  • 0x20 – some marker
  • 0x21 – some marker
  • 0x23 – one byte of payload
  • 0x28 – contains the name of PUZZLES.DLL plus some other data in 13 bytes of payload
  • 0x29 – 20 bytes of payload
  • 0x33 – 2 byte – ?, 2 byte – ?, 4 bytes – ?, 4 bytes – payload size minus one
  • 0x34 – 4 bytes, unknown

Image format

Images are stored in 8-bit paletted format compressed with compression 1 or 3 from video. Image properties like dimensions or compression method are stored in the record block, the rest (1024-byte palette and compressed data) is stored in IMV at the offset provided at the end of image record.

Audio format

Music is stored in SF.DLL resources in 5BS format (short for 5-bit compression) sampled at 22050 Hz with the following header:

  3 bytes - "5BS"
  1 bytes - 'M' for mono, 'S' for stereo
  4 bytes - audio data size
  4 bytes - always -1?
  4 bytes - sample -2 for prediction
  4 bytes - sample -1 for prediction
  4 bytes - sample -2 for prediction for right channel?
  4 bytes - sample -1 for prediction for right channel?
  16 bytes - unused?
  [compressed audio samples]

Audio samples are grouped by eight (i.e. a group occupying 5 bytes). In case of stereo it should be 5 bytes for left samples, 5 bytes for right samples, 5 bytes for left samples etc. Each channel is decompressed independently.

Audio compression

Data is stored LSB first, first it’s 4-bit step index update plus seven, then 1-bit difference sign.

Overall decoding looks like this:

  for (all samples) {
    step += get_bits(4) - 7;
    sign = get_bit();
    diff = step_table[step];
    if (sign)
      diff = -diff;
    sample[x] = sample[x - 1] * 2 - sample[x - 2] + diff;
  }

Step table:

        0x0,    0x5,    0xB,   0x24,   0x57,    0xAA,   0x127,   0x1D5,
      0x2BC,  0x3E5,  0x557,  0x71C,  0x93B,   0xBBC,   0xEA8,  0x1207,
     0x15E1, 0x1A3F, 0x1F28, 0x24A4, 0x2ABD,  0x3179,  0x38E2,  0x40FF,
     0x49DA, 0x5379, 0x5DE5, 0x6927, 0x7546,  0x824B,  0x903E,  0x9F27,
     0xAF0E, 0xBFFC, 0xD1F9, 0xE50D, 0xF940, 0x10E9A, 0x12524, 0x13CE6

Video format

File structure:

  4 bytes - " AN "
  4 bytes - some number in text form like 1.10 or 0.60
  2 bytes - frames per second (usually 12)
  1 byte  - compression (0/1/3/5)
  4 bytes - number of chunks
  2 bytes - width
  2 bytes - height
  2 bytes - tile width (for dirty rectangles update in methods 1/5)
  2 bytes - tile height
  1 byte  - palette present flag
  1 byte  - unknown
  1 byte  - flags
  1 byte  - audio is raw flag
  30 bytes - unknown/unused
  1024 bytes - palette (in R,G,B,4 format)
  N*5 bytes - chunk records:
     1 byte  - chunk type (0 - video, 2 - sound)
     4 bytes - chunk size
  chunk data

Audio compression

Audio compression is the same 5BS compression. Output is 22050 Hz 16-bit mono. Each block starts with 4-byte number of samples in the block.

Video compression 0

Frame is compressed as series of opcodes with optional follow-up pixel data.
Opcode is stored as oolsssss where oo is operation type (0 – skip, 1 – forbidden, 2 – copy bytes from the stream, 3 – fill the specified amount of pixels with the next byte from the stream), l signals that sssss is top bits of the operation length (next byte is bottom eight bits), otherwise sssss is the full length.

Video compression 1

The data is compressed as tiles with data grouped in three parts:

2 bytes - first part length (including this field)
[first part] - bitmask for (usually 40x40) tiles telling which of them are updated
2 bytes - second part length (including all fields)
2 bytes - tile width (usually 8)
2 bytes - tile height (usually 8)
[the rest of second part] - tile types
[third part] - tile colours and indices

Decoding goes as following: for each tile a bit is read (from part 2) which signals if tile is updated), if it is so then 3-bit tile type is read and tile is processed.

Tile types (all data here is read from part 3, bits are read MSB first, bit position after reading indices is aligned to byte):

  • 0 – do nothing
  • 1 – read one byte and fill tile with it
  • 2 – read two bytes for colours and then 1-bit indices for each tile pixel telling which colour to use;
  • 3 – read three colours, indices in this case are 0/10/11;
  • 4 – read four colours, use 2-bit indices;
  • 5 – read a byte for a number of colours to read (should be 5-8), use 3-bit indices;
  • 6 – read a byte for a number of colours to read (should be 9-16), use 4-bit indices;
  • 7 – read raw tile pixels.

Video compression 3

This compression has both intra and inter variants, images and first frames of videos use intra variant, the rest of frames use inter coding.

This compression scheme codes a pair of lines at once by either coding literals or references to either already-decoded part or previous frame. For intra compression it looks like this (bits are stored MSB first):

  for each pair of lines {
   for (x = 0; x < w; ) {
     length = get_length_code();
     if (length == 0) {
       line0[x] = get_bits(8);
       line1[x] = get_bits(8);
       x++;
     } else {
       top = get_top_part();
       offset = ((top << 12) | get_bits(12)) - 1;
       flg = offset & 7;
       offset >>= 3;
       soff = x + (y / 2) * w;
       soff = ((soff - offset) % w) + ((soffset - i) / w) * w * 2;
       if (!(flg & 4))
         soff -= w;
       if (flg & 2) {
         src0 = buf + soff;
         src1 = buf + soff + w;
       } else {
         src0 = buf + soff + w;
         src1 = buf + soff;
       }
       step = (flg & 1) ? 1 : -1;
       for (i = 0; i < length; i++) {
         line0[x + i] = src0[i * step];
         line1[x + i] = src1[i * step];
       }
       x += length;
     }
   }
  }
}

For inter compression in case of copy it also reads a bit telling which source to use (self or previous frame) and it does copy a bit differently:

  • in either case it uses 11-bit value as a base instead of 12-bit;
  • only last bit of offset is used for flags (telling to go one line higher);
  • for previous frame copy it does not subtract one from the initial value;
  • copying from previous frame uses additional offset 0x2000 / w * w.

Length codes:

00 - 0
100 - 2
110 - 3
010 - 4
1010 - 5
0110 - 6
0111 - 7
10110 - 8
11100 - 9
101110 - 10
111010 - 11
1011110 - 12
1110110 - 13
1111000 - 14
10111110 - 15
10111111 - 16
11101110 - 17
11101111 - 18
11110010 - 19
111100110 - 20
111100111 - 21
111101000 - 22
111101001 - 23
111101010 - 24
111101011 - 25
111101100 - 26
111101101 - 27
111101110 - 28
111101111 - 29
11111 - 30

Self-reference offset top part:

00 - 0
010 - 1
100 - 2
0110 - 3
1010 - 4
1011 - 5
1100 - 6
1110 - 7
11010 - 8
11011 - 9
11110 - 10
11111 - 11
011100 - 12
011101 - 13
011110 - 14
011111 - 15

Previous frame reference offset top part:

000 - 0
100 - 1
0010 - 2
0100 - 3
0101 - 4
0011 - 5
101 - 6
110 - 7
0110 - 8
1110 - 9
01110 - 10
11110 - 11
011110 - 12
011111 - 13
111110 - 14
111111 - 15

Video compression 5

This method is the same as compression 1 but it uses 4-bit tile types with value 8 meaning "copy from the previous frame".

Comments are closed.