MegaTech VOL Format

From ModdingWiki
Jump to navigation Jump to search
MegaTech VOL Format
Format typeArchive
Max filesUnlimited
File Allocation Table (FAT)Beginning
Filenames?No
Metadata?None
Supports compression?No
Supports encryption?No
Supports subdirectories?No
Hidden data?No
Games

The MegaTech VOL Format is an archive used by Cobra Mission to store all the game data. The following .VOL files are included with the game:

File format

There is no header. The format is simply a list of offsets, repeated until the file data begins:

Data type Name Description
UINT32LE offset Offset of this file, relative to start of archive file

Usually the above structure is repeated until it is 256 bytes long (with unused offsets as zero), but it can be smaller (pcm6.vol has a 64 byte header).

The last entry in the list is the file size, followed by zero offsets as needed to pad the list to the required length.

! Will the game accept files that lack this padding?

Instances

Graphics VOL files

  • CUT1.VOL
  • CUT2.VOL
  • CUT3.VOL
  • CUTA.VOL
  • ENM.VOL
  • ENMA.VOL
  • MAP.VOL
  • OPENING.VOL
  • PIC1.VOL
  • PIC2.VOL
  • PIC3.VOL
  • PICA.VOL

The listed VOL files contain the graphics for the game.

  • OPENING.VOL contains the graphics for the intro sequence
  • MAP.VOL contains the graphics for the inventory map items.

! Below are assumptions on the other files

  • CUT1 - CUTA : Cutscenes
  • ENM - ENMA : Enemy graphics
  • PIC1 - PICA : Inventory items (magazines and photos)

These VOL files contain graphics chunks with the following structure

GC Entry

  • 00 - 01 : UINT16LE signature 47 43 "GC"
  • 02 - 03 : UINT16LE Version 02.00
  • 04 - 05 : UINT16LE Flag that indicates whether a palette is present.
  • 06 - 07 : UINT16LE Points to the location of the sub-chunk table.
  • 08 - 0B : UINT32LE Number of sub-chunks in the entry. Very often only 1, but sometimes more.
  • 0C - 0D : UINT16LE Size of the chunk.
  • 0E : UINT8 Padding (always 0)
  • 0F : UINT8 Checksum; add up all the bytes from 00 to 0E and place the 2's complement of that sum here. To check, add all bytes from 00 to 0F and the result of that should be 0.

If the palette bit is set in the header, a palette will follow.

  • 10 - 2F : The colors are stored as an array[16] of UINT16LE. See MED.VOL for example code on how to read the palette.

After the palette there's a subchunk table with N+1 values, where N is the number of subchunks. Each chunk runs from offset[X] to offset[X+1]. For a single chunk file, this has two values.

  • (10 or 30) - xx : Offset pointers in the chunk stored as UINT32LE. The amount is indicated by the number of sub-chunks, plus one.
GC data chunks

The GC data chunks have their own 10-byte header. Preliminary documentation below (not validated yet!):

  • 00 : UINT8 Always 0xA4
  • 01 : UINT8 Probably a checksum.
  • 02 : UINT8 X offset to display at
  • 03 : UINT8 Y offset to display at
  • 04 : UINT8 Width of contained image
  • 05 : UINT8 Height of contained image
  • 06 - 07 : UINT16LE Subchunk size.
  • 08 - 09 : UINT16LE Always 0?

In the game the art looks like it contains a lot of dithering and the graphics chunks look like they are storing this in a clever way.

The data format is not clear, but tinkering with values has given some information on how the pixel data is stored.

It seems that pixel data is stored as rows of 8 pixels, and somehow the format gives the following information to these rows:

  • Palette values for each pixel in the row
  • Dithering pattern for the row
  • Possibly locations where these rows should be placed

Tinkering with entry number 3 inside PIC3.VOL gave some information on how this format is working. (This is the second Girl's Photo in inventory)

Shortly after the header the following pattern is found 01 01 01 01. Changing this to FF FF FF FF will make an 8 pixel white line appear in multiple parts of the image.

Originally the pixel data is 7 black pixels and then one white. The palette has entry 0 = black, entry 15 is white and entry 14 is yellow

changing it to 00 01 01 01 changes the rightmost white pixel to yellow.

These blocks work in the following way:

  • 00000001
  • 00000001
  • 00000001
  • 00000001

Makes the rightmost pixel white and the others black

  • 00000000
  • 00000001
  • 00000001
  • 00000001

Makes the rightmost pixel yellow and the others black.

The 4 byte row contains palette entries for each pixel, each bit represents one pixel, and the bit being on and off determines the final palette entry from 0 - 15.

EMI.VOL

EMI.VOL contains the music for the game, it has 41 chunks of data. The first chunk is exactly 4096 bytes and contains the instruments.

Instrument Bank

There are 128 instruments in the chunk and each instrument is 32 bytes.

  • Bytes 0 - 7 of each instrument look like FM parameters. ! Figure out which parameter does what
  • Bytes 8 - 9 contain low numbers numbers from 0 - 3. ! Figure out if these are modulator and carrier wave parameters
  • Bytes 10 - 11 contain numbers between 0 and 16. ! Figure out what these parameters mean
  • Bytes 12 - 15 are all zeroes.
  • Byte 16 increments from 0 - 31, after that it decrements from 255 to 160. Changing this seems to change the instrument type. It looks like the first 32 instruments are percussion.
  • Byte 17 contains a number from 0 - 255. ! Figure out what this byte does.
  • Bytes 18 - 23 contain zeroes.
  • Byte 24 - 31 contains a lot of data, but changing this to all zeroes seemingly does not change the music in-game.

The 40 remaining chunks all have the EM header.

EM Entry

  • 00 - 03 : signature 45 4D 00 06
  • 04 - 05 : Unknown, most of the times 00 00, but values such as 00 03 are also present.! Version?
  • 06 - 07 : UINT16LE, Start index of title, most of the times 1C 00
  • 08 - 09 : UINT16LE, Offset in the EM chunk where the actual data starts
  • 0A - 0B : UINT16LE, Always the same as the previous UINT16LE. (Pointing to data offset)
  • 0C - 0D : UINT16LE, The size of the EM chunk
  • 0E - 0F : Unknown, could be initial tempo or volume or something similar. ! Figure out what this is

After this 6 UINT16LE follow, that indicate the offset in the chunk where data is found for each channel.

6 channels are supported and if there is no data for the channel, the value is 0.

  • 10 - 11 : UINT16LE, Index of track 1 in chunk, usually the same as the UINT16LE from 08-09 and 0A-0B.
  • 12 - 13 : UINT16LE, Index of track 2 in chunk
  • 14 - 15 : UINT16LE, Index of track 3 in chunk
  • 16 - 17 : UINT16LE, Index of track 4 in chunk
  • 18 - 19 : UINT16LE, Index of track 5 in chunk
  • 1A - 1B : UINT16LE, Index of track 6 in chunk
  • 1C : Start of title, if there is no title, the value at this location is FF, otherwise it's FE.

If there is a title, a zero-terminated string follows, it contains japanese characters and at the end a date when it was converted. Finally, it ends with FF.

Pattern data

! Highly experimental reverse-engineering, https://github.com/BlackStar-EoP/cobra-mission-writer/tree/master/emidump is an attempt to convert these to S3M

So far, it seems the pattern data has

  • 2 byte control commands
  • 1 byte control commands
  • 1 byte speed commands
  • note commands

! Check if there are more types, such as 3 or 3 byte commands

2 byte control commands
  • 0xE4: Unknown
  • 0xE7: Unknown
  • 0xE8: Unknown
  • 0xFB: Unknown
  • 0xFD: Select instrument, byte after this indicates the index of the instrument from the instrument bank.
  • 0xF7: Unknown
  • 0xFA: Unknown
  • 0xFC: Unknown
1 byte control commands
  • 0xCD: Unknown
  • 0xCF: Unknown
  • 0xDC: Unknown
  • 0xDD: Unknown
  • 0xCE: Unknown
  • 0xF8: ! Loop command?
1 byte speed commands

These commands look like a delay command of some sort ! It seems these commands can do more than just have a delay for a note, looks like they can delay for a couple of notes and then return to another speed.

  • 0x81: row delay = 2
  • 0x82: row delay = 4
  • 0x83: row delay = 8
  • 0x84: row delay = 16
  • 0x85: row delay = 32
  • 0x86: row delay = 64
  • 0x89: row delay = 12
  • 0x90: row delay = 6
  • 0x8B: row delay = 48
  • 0x8E: row delay = 3
1 byte note commands

The note commands range from 0x00 to 0x7F, where 0x00 is a C, 0x01 is a C-# and so on. It seems that 0x00 is used as a dummy note, it does not get played, but increases the delay.

MCG.VOL

MCG.VOL contains the tilesets for the game. It contains 14 chunks of tile data.

Chunk nr Tileset
0 Character sprites
1 Weapon sprites
2 CASTLE tileset
3 AREA1 tileset
4 AREA2 tileset
5 AREA3 tileset
6 AREA4 tileset
7 AREA5 tileset
8 HOUSE tileset
9 BAR tileset
10 CORP tileset
11 BRICK tileset
12 LAB tileset
13 SEASIDE tileset

The header for this file is 64 bytes and contains the offsets for each tileset. The tilesets consist of a number of tiles, all are 32x32 pixels, each pixel stored as a byte, making each sprite 1024 bytes.

The palette for the tilesets is found inside each entry inside MED.VOL. The colors are stored as an array[16] of UINT16LE. For example white is stored as F0FF, this will be read as 0x0FFF, and here the components are 0GRB.

byte r = (value >> 4) & 0x0F;
byte g = value >> 8;
byte b = value & 0x0F;

This will result in values from 0 to 15. Getting the actual color requires 2 shifts, one left of 4 and added to that one right of 2.

Reading all palette entries would look something like this:

Color parse_color(uint16_t col)
{
	byte r = (col >> 4) & 0x0F;
	byte g = col >> 8;
	byte b = col & 0x0F;
	return Color((r << 4) + (r >> 2), (g << 4) + (g >> 2), (b << 4) + (b >> 2));
}
void parse_palette()
{
	int pal = 0;
	for (int i = 32; i < 64; i += 2)
	{
		uint16_t color = (m_data[i + 1] << 8) | m_data[i];
		m_palette[pal++] = parse_color(color);
	}
}

MED.VOL

MED.VOL contains all the levels for the game. It contains 54 chunks of map data.

MD Entry

Each MD entry inside MED.VOL consists of 5 blocks. The header (96 bytes), a block of unknown data (variable size), the tiledata for all the floors(dependent on size and number of floors), the triggers for all floors (same as the floor sizes, but with most entries 0) and a footer of 256 bytes.

MD Header
  • 0 - 6 : signature 4D 44 03 30 02 02 14
  • 7 - 9 : Unknown, most of the times 77 60 00, but values 9F 60 00, FF 60 00 and 8B 60 00 are also found in a few maps
  • 0A - 0B : UINT16LE, the offset inside this MD chunk where the actual map data starts
  • 0C - 0F : UINT32LE, the size of this MD chunk
  • 10 - 11 : UINT16LE, the width (in tiles) of this map
  • 12 - 13 : UINT16LE, the height (in tiles) of this map
  • 14 - 15 : UINT16LE, the number of floors in this map
  • 16 - 1F : Character array, refers to the used tileset (values can be CASTLE, AREA1, AREA2 etc. See MCG.VOL), rest zeroes
  • 20 - 3F : Palette data, 16 colors, each color stored as UINT16LE, colors are stored as 4 bit nibbles.
  • 40 - 5F : Character array, contains 2 names for the map, or for HOUSE types, the area that is referred. A long and a short version seperated by a pipe character.
Unknown data block

Unknown data block, usually ranging from 0060 to 0420. The data inside looks the same for all the MD chunks. It looks like a lot of 16 bit integers.

Tile data block

The size of the block is width * height * number of floors. Each byte corresponds to the tile number in the used tileset. The floors are stored sequentially.

Triggers block

The same layout as the tile data block, but now most bytes are 00 and the bytes that are not are triggers such as item pickups, stairs, doors etc. Unknown what the numbers mean, but exits are usually 0x20, item pickups range in 0x40 and character sprites are usually 0xC0 and higher.

Footer

At the end of each MD chunk there are 256 bytes, unknown what the data represents, but it looks like it is related to the trigger block.

PCM1.VOL - PCM6.VOL

These files contain PCM data in the form of the Creative Voice Format

Credits

This file format was reverse-engineered by BlackStar. If you find this information helpful in a project you're working on, please give credit where credit is due. (A link back to this wiki would be nice too!)