The Codex of Editable Wisdom

Ultima VI Internal Formats

2,975pages on
this wiki
Add New Page
Add New Page Talk0

This page deals with the details on the specifications of the file formats for the different files included in Ultima VI.

Files Edit

These are the files in an Ultima VI installation, and what is known about them. Files that are marked "(LZW)" use the LZW compression scheme described below. Files that are marked "(stored)" don't. Files that aren't marked are unknown.

  • all.con
  • animdata
  • animmask.vga
  • basetile
  • blocks.shp
  • book.dat
  • bootup.m
  • brit.m
  • chunks - Map chunk templates (Template[1024]), where Template is (uint8[8 * 8]), where each value is a map tile index (see the Tile Graphics section) in [x + y * 8] order.
  • config.u6
  • converse.a
  • converse.b
  • convert.pal
  • create.m
  • dither
  • dungeon.m
  • end.m
  • end.shp
  • endpal.lbm
  • engage.m
  • forest.m
  • gargoyle.m
  • gypsy.shp
  • hornpipe.m
  • intro.m
  • intro.ptr
  • intro.shp
  • intro_#.shp (# is 1 to 3)
  • look.lzd
  • lzdngblk
  • lzmap
  • lzobjblk
  • mainmenu.shp
  • map
  • maptiles.vga (stored) - Map tile graphics data (see the Tile Graphics section).
  • masktype.vga (LZW) - Tile graphics information (see the Tile Graphics section).
  • midi.dat
  • montage.shp
  • newmagic.bmp
  • objtiles.vga (LZW)
  • (stored) - Cutscene palettes (see the Palettes section).
  • paper.bmp
  • portrait.a
  • portrait.b
  • portrait.z
  • schedule
  • starpos.dat
  • stones.m
  • tileflag
  • tileindx.vga (stored) - Tile graphics file offsets (see the Tile Graphics section).
  • titles.shp
  • u6.# (# is 1-8)
  • u6.set
  • u6mcga.ptr
  • u6pal (stored) - In-game palete (see the Palettes section).
  • ultima.m
  • vellum1.shp
  • woods.shp
  • worldmap.bmp

These files are for the CGA, EGA, and Tandy graphics versions, which won't be relevant to most:

  • u6curs.cga
  • u6curs.ega
  • u6curs.tga

These files are not relevant to most people:

  • copyu6.bat, insub.bat - Batch files for performing various tasks.
  • cgadrv.bin, eegadrv.bin, egadrv.bin, mcgadrv.bin, tgadrv.bin - Video graphics driver programs.
  • end.exe, game.exe, install.exe, makemode.exe, t2cga.exe, t2ega.exe, t2hrc.exe, 2tga.exe, tandypin.exe, u.exe,, ultima6.exe - Game executables.
  • u6adlib.drv, u6cga.drv, u6cms.drv, u6covox.drv, u6ega.drv, u6innova.drv, u6mcga.drv, u6roland.drv, u6tandy.drv, u6tmus.drv - Sound and video graphics drivers.

Formats Edit

LZW Compressed Data Edit

Some files or blocks inside files are LZW compressed. LZW compressed data has the following format:

Part Description Size
Header Size of the Body part after being decompressed.
If the size is zero, it means the Body will already be uncompressed.
4 bytes, least significant byte first.
Body The compressed data.
If the data is actually compressed, the first byte is always 0x00, and the second one always has its first bit set to 1, as this is the reset code for LZW.
After being decompressed, the resulting block can have any format.
Variable, depending on the data itself.


Libraries are contain several items of the same type, inside the same file. Libraries have the following structure:

Part Description Size
File Size Optional, contains the length of the entire library file. 4 bytes (if present) or 0 bytes (if missing), least significant byte first.
Index A list of offsets. Each offset indicates where a Data Block starts.
If an offset has a value of zero, it is an invalid offset and must be ignored.
Variable, depending on the number of offsets.
Each offset may be 4 bytes long, or 2 bytes long, but for one file, all the offsets must be of the same size (either 4 or 2 bytes long).
Notice that as all offsets have the same size, and the first offset gives the start of the first Data Block, the first offset can be used to calculate the size of the Index part.
Data Block 1 The first block of data. The blocks can be in any format, but all blocks must be in the same format. Variable, depending on the data itself.
... ... ...
Data Block N The last block of data. Variable, depending on the data itself. Notice that if there are invalid offsets, there will be more offsets than data blocks, but there can never be more data blocks than offsets.

For simplicity, the following names are used for specific types of library files:

  • s_lib_16: a library file which does contain the File Size part, and where each offset in the Index part is 2 bytes (16 bits) long.
  • s_lib_32: a library file which does contain the File Size part, and where each offset in the Index part is 4 bytes (32 bits) long.
  • lib_16: a library file which does not contain the File Size part, and where each offset in the Index part is 2 bytes (16 bits) long.
  • lib_32: a library file which does not contain the File Size part, and where each offset in the Index part is 4 bytes (32 bits) long.

Game DataEdit


Conversations are stored in the files CONVERSE.A and CONVERSE.B, which have the following characteristics:

  • They both are lib_32 library files.
  • Each Data Block consists of LZW compressed data, each corresponding to the conversation lines of one NPC.
  • Both files contain a few invalid offets in the Index parts.
  • Data Block 27 in CONVERSE.B is LZW compressed data, but with a Header equal to zero, meaning it contains uncompressed data.

Conversation EntryEdit

After being decompressed, each Data Block corresponds to a Conversation entry. There is a total of 200 Conversation entries between both files.

Each of these entries consist of a list of several parts.

  • Each part is composed of a Binary Code, and possibly an inner Data Block.
  • Each Binary Code is 1 byte long.
  • The Data Block, if present, can be of any size, and its end is basically marked by the start of the next part's Binary Code.
Part Name Part Type Binary Code Data Block Type Data Block Contents
Identification Data 0xff Text The NPC's name.
Description Data 0xf1 Text The NPC's description; that is, the text given when LOOKing at the NPC.
Keyword List Data 0xef Text A keyword or list of keywords that can be used by the player in the conversation, which lead to a specific answer.
- If there are several keywords that lead to the same answer, they are separated by commas.
- It is always followed by an Answer part (see below).
Answer Data 0xf6 Text The NPC's answer to the given keyword. It is always preceded by a Keyword List part.
- Inside an answer, a keyword will be marked by having a @ sign preceding it, such as "Many @quests".
- Inside an answer, the text "$p" will be replaced by the player's name.
Jump Command 0xb0 Binary, 4 bytes, least significant byte first. Indicates that the conversation must "jump" to the location specified by the offset, which is relative to the start of the conversation entry. An Answer part is always followed by a Jump command.

<to-do: complete table>


The floor map data is stored in the "map" and "chunks" file. A chunk is a 16x16 group of tiles that is used as a template for common shapes, like houses, mountains, and trees. There are five maps for Britannia and the four underworlds, and they are composed of chunks, with Britannia further grouping chunks into blocks.

The "chunks" file is simply (Chunk[1024]), where Chunk is (uint8[8 * 8]). Each value is an index into the map tiles (see Tile Graphics) in [x + y * 8] order.

There are five maps in the "map" file, with some variation in storage. Britannia, the first map, is stored as (Block16[8 * 8]) (once again in [x + y * 8] order), where Block16 is (uint24[8 * 16]). Each uint24 is a pair of chunk indices, with the first in the lower 12 bits (mask 4097), and the second in the upper 12 bits (right shift 12). The next four maps are the underworlds, and they are each Block32, which is (uint24[16 * 32]) and uses the same paired indices.


There are two groups of palettes. The in-game palette is stored in "u6pal". The cutscene palettes are in "".

The "u6pal" format is (Palette palette, uint8[0x100] unknown), where Palette is ((uint8 red, green, blue)[256]). Each color element is from 0 (darkest) to 63 (brightest). The data after it are unknown.

The "" format is (Palette[6] palettes), where Palette is as above. However, each color element is from 0 (darkest) to 255 (brightest).

Tile Graphics Edit

Much of the game's world graphics use the tile graphics, which are 16x16 indexed images. Decoding them requires four files: "maptiles.vga" (LZW-compressed), "objtiles.vga" (not compressed), "tileindx.vga" (not compressed), and "masktype.vga" (LZW-compressed).

There are 2048/800h tiles in total: 512/200h map tiles stored in "maptiles.vga" and 1536/600h object tiles stored in "objtiles.vga".

"tileindx.vga" stores the offset of a tile's data as uint16[800h], where each value needs to be multiplied by 16 to get the byte offset. "maptiles.vga" and "objtiles.vga" are indexed as if they were a contiguous file. So if "maptiles.vga" is 117408 bytes uncompressed (which it is), when an offset of 130412 is actually an offset into "objtiles.vga" of 13004 bytes.

"masktype.vga" contains the storage format of the tiles in its first 2048/800h bytes as a uint8[800h] array. The values are:

  • 0 - Opaque - An opaque tile stored as (uint8[16 * 16]) in [x + y * 16] order.
  • 5 - Transparent - Stored as with Opaque, but pixels with a value of 255 are skipped as transparent.
  • 10/0Ah - Compressed - Described below.

The compressed file type is stored as a sequence of horizontal spans of opaque pixels. It starts with a (uint8 tileLength), which is the size in 16-byte pages of the tile data, and is followed by a sequence of spans. Each span is (uint16 displacement, uint8 length, uint8[length] data). If length is zero, then the graphic is complete. displacement has a complex meaning specific to the U6 engine; the easiest way to deal with it is to convert it into a byte offset with (displacement % 160 + (displacement >= 1760 ? 160 : 0)), and add that to an output offset. Then copy the data to the output, and add length to the offset. Here is pseudo-code for performing these operations:

uint8 tileLength = ReadUInt8();
uint offset = 0;

while(true) {
    uint16 displacement = ReadUInt16();
    uint8 length = ReadUInt8();

    if(length == 0)
    offset += displacement % 160;
    if(displacement >= 1760)
        offset += 160;

    Read(output, offset, length);
    offset += length;

These tiles use the "u6pal" palette.


Also on Fandom

Random Wiki