Ultima VIII internal formats

From Ultima Codex
Jump to navigation Jump to search

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

Files[edit]

These are the files in an Ultima VIII installation, and what is known about them.

Common Formats[edit]

All multi-byte data are stored in little-endian order. For example, 1122h could be stored as the bytes (22h 11h). Signed values are stored as two's-complement. For example, the signed byte -1 is stored as FFh. These are the basic types that are referred to throughout this document:

  • uint8/16/24/32 - Unsigned one, two, three, and four-byte integers.
  • int8/16/32 - Signed one, two, and four-byte integers.
  • char - ASCII character stored as uint8.
  • zero - A single byte that is always zero.

FLX Archives[edit]

Files with a ".flx" extension, and many without, are stored in a common archive file format. The header has this format:

Offset Size Type Name Description
0 82/52h char[82] Comment Always filled with 26/1Ah, which in ASCII is SUB (indicates an invalid character).
82/52h 2 zero[2] - Might be part of the comment.
84/54h 4 uint32 Count The number of records in the archive.
88/58h 4 uint32 Version? Always 1.
92/5Ch 4 uint32 TotalSize Either the size in bytes of the archive file, including the header, or zero.
96/60h 4 uint32 CRC? Seems to be some kind of CRC.
100/64h 100/64h zero[100] - Padding or space for expansion.
144/90h 8*Count Record[Count] Records Record offset and length values, as described below.
Record format:
00h 4 uint32 Offset Offset from the beginning of the file for the record. This is zero if there is no record at this index.
04h 4 uint32 Length Length in bytes of the record, or zero if there is no record at this index.

The interpretation of record data depends upon the file itself. All records in an archive have the same format.

Palettes[edit]

Palettes are stored as (Color[256] Colors), where Color is (uint8 Red, uint8 Green, uint8 Blue), and each component is from 0 (darkest) to 63 (brightest). Index 255 is transparent.

Shapes[edit]

Shapes are used as the record format in the FLX Archives "static/u8shapes.flx", "static/u8fonts.flx", and "static/u8gumps.flx" files, as well as a single standalone shape in the "static/u8mouse.shp" file. It has this format:

Offset Size Type Name Description
00h 2 uint16 MaximumSizeX In u8fonts.flx and u8mouse.shp, contains the maximum width of the shape's frames. In u8shapes.flx, sometimes contains the ShapeIndex.
02h 2 uint16 MaximumSizeY In u8fonts.flx and u8mouse.shp, contains the maximum height of the shape's frames.
04h 2 uint16 Count The number of frames in the shape.
06h 6*Count FrameHeader[Count] FrameHeaders The offsets and byte sizes of the frames.
FrameHeader has this format:
00h 3 uint24 FrameOffset Offset from the start of the shape to the beginning of the frame in bytes.
03h 1 uint8 ?? This is 128 in "static/u8shapes.flx", and 0 everywhere else. Its meaning is a mystery.
04h 2 uint16 FrameSize The size in bytes of a frame.
At the FrameOffset for each frame is the frame data:
00h 2 uint16 ShapeIndex Always either the zero-based index of the shape in its archive or zero. Seems meaningless either way.
02h 2 uint16 FrameIndex Always either the zero-based index of the frame in its shape or zero. Seems meaningless either way.
04h 4 zero[4]    
08h 2 uint16 Compression Either 0 or 1; this has relevance to the RLE data below.
0Ah 2 uint16 SizeX Horizontal size of the frame in pixels.
0Ch 2 uint16 SizeY Vertical size of the frame in pixels.
0Eh 2 uint16 OffsetX Horizontal offset of the hot spot of the frame in pixels.
10h 2 uint16 OffsetY Vertical offset of the hot spot of the frame in pixels.
12h 2*SizeY uint16[SizeY] RowOffsets Relative offset to the start of the row data, from the start of the offset. For example, the offset relative to the beginning of the frame data would be (16 + Offset + Index * 2), where Offset is the row offset and Index is the row index.
... ... ... RowData[SizeY] The rows of the frame in order.

RowData is stored as RLE data. Describing this is easiest in pseudocode:

int x = 0;

while(x < SizeX) {
    x += ReadUInt8();
    if(x >= SizeX)
        break;

    uint8 length = ReadUInt8();
    uint8 type = 0;

    if(Compression == 1) {
        type = length & 1;
        length >>= 1;
    }

    // Read length bytes to the output.
    if(type == 0)
        ReadData(x, y, length);
    else {
        // Copy value length times to the output.
        uint8 value = ReadUInt8();
        ReadRun(x, y, length, value);
    }
    
    x += length;
}

File Structure[edit]

This section discusses individual files within their subsystem.

Game Logic[edit]

Type flags (static/typeflag.dat)[edit]

This contains information about each type in the game. Each type info record is 8 bytes long; there are 2048 records in Ultima 8 (one for each entry in "static/u8shapes.shp"). Each record has this bit format:

Offset Shift Bits Mask Name Description
00h 0 8 255 ?? ??
01h 0 3 7 ?? ??
  3 1 1 Translucent Whether to use translucency rendering for this shape.
  4 4 15 QualityUse How the Quality field is used by the type. 1 for Quality, 2 for Quantity, 6 for Container.
02h 0 4 15 ?? ??
  4 4 15 SizeX Size in the X direction for this object.
03h 0 4 15 SizeY Size in the Y direction for this object.
  4 4 15 SizeZ Size in the Z direction for this object.
04h 0 4 15 AnimationType How this shape is to be animated; see the details below.
  4 4 15 AnimationData Parameter to AnimationType that depends upon that value.
05h 0 4 15 ?? ??
  4 1 1 HideInGame Hide this shape in game. This is for eggs and invisible walls.
  5 1 1 ?? Only used for flaming oils.
  6 1 1 NonBlocking Tentative.
  7 1 1 ?? Only used for the 'blue field passage gem'.
06h 0 8 255 ?? ??
07h 0 8 255 ?? ??

The AnimationType field changes the conditions where the shape will cycle through a frame during a game update tick, and what frames are cycled through. These conditions are:

Value AnimationData Description
0   Never.
1 and 3 0 Always cycle through all frames.
  1 Cycle through all frames 50% of the time.
  >1 Cycle through some frames (source is unclear).
2 0 Cycle through all frames 50% of the time.
  1 Cycle through all frames 25% of the time.
  >1 Cycle through some frames 50% of the time (source is unclear).
4   Cycle through all frames with a 1 in AnimationData chance of incrementing.
5   Animated by Usecode Event 2.

Usecode game script (static/eusecode.flx)[edit]

This FLX archive contains the game script. Each record corresponds to a class.

Graphics[edit]

Ultima 8 uses 256-colour VGA indexed graphics at a 320x200 resolution. Most notable about the resolution for modern concerns is that the pixels were not square, but were instead vertical rectangles. To display them properly on a modern monitor, the graphics should be 20% vertically taller or they will appear crushed. Fortunately the dimetric projection hides quite a bit of this distortion for the world graphics.

Game palette (static/u8pal.pal)[edit]

This standalone Palette is used during the game.

Game Interface[edit]

Fonts (static/u8fonts.flx)[edit]

Mouse cursors (static/u8mouse.shp)[edit]

This standalone Shape file contains the mouse cursors. These are they:

Index Description
0-7 Short movement north, northeast, east, southeast, south, southwest, west, and northwest.
8-15 Medium movement north, northeast, etc.
16-23 Long movement north, northeast, etc.
24 No movement (blue dot).
25-32 Combat movement north, northeast, etc.
33 No combat movement (red dot).
34 Use target (four blue arrows pointing inwards).
35 Pentagram.
36 Skeleton hand pointer.
37 Crosshair.
38 Quill.
39 Magnifying lens.
40 Red cross.
41 Empty image.

Gumps and windows (static/u8gumps.shp)[edit]

Maps[edit]

Ultima VIII uses a 2:1 dimetric perspective. To translate an (X, Y, Z) coordinate in world space to pixels, Xp will be ((X - Y) / S) and Yp will be ((X + Y) / (S * 2) - Z). S is 2 for objects specified in "static/globs.dat" and 4 everywhere else.

World graphics (static/u8shapes.flx)[edit]

This FLX archive contains Shapes that fill in the world graphics. The OffsetX and OffsetY fields in the individual shape frames indicate the pixels to subtract from an object's world position to the point to draw the object at.

Compressed world graphics (static/u8shapes.cmp)[edit]

Map templates (static/globs.dat)[edit]

This FLX archive contains blocks of objects that can be inserted into a map to save space. Each record has this format:

Offset Size Type Name Description
00h 2 uint16 Count Number of objects in this glob. This is sometimes zero.
02h 6*Count GlobObject[Count] Objects List of objects in the glob, documented below.
This is the format of a GlobObject:
00h 1 uint8 X Horizontal position of the object.
01h 1 uint8 Y Vertical position of the object.
02h 1 uint8 Z Elevation of the object.
03h 2 uint16 ShapeIndex A zero-based index into the "static/shapes.flx" archive for the shape to draw.
05h 1 uint8 FrameIndex The zero-based index of the frame to draw in the shape specified by ShapeIndex above.

World objects (static/fixed.dat, gamedat/nonfixed.dat)[edit]

These FLX archives contains the world objects. "static/fixed.dat" contains those objects that cannot be modified during play. "gamedat/nonfixed.dat" contains those objects which can be changed.

Each record contains a Map, which is simply a list of objects. There are as many objects as the (RecordLength / 16). Each object has the format:

Offset Size Type Name Description
00h 2 uint16 X Horizontal position on the map.
02h 2 uint16 Y Vertical position on the map.
04h 1 uint8 Z Elevation of the object.
05h 2 uint16 ShapeIndex A zero-based index into the "static/shapes.flx" archive for the shape to draw and the type of the object.
07h 1 uint8 FrameIndex The zero-based index of the frame to draw in the shape specified by ShapeIndex above.
08h 2 uint16 Flags General object flags.
0Ah 2 uint16 Quality The meaning depends upon the object type.
0Ch 1 uint8 NpcIndex Which NPC this is an object for, if this is an NPC.
0Dh 1 uint8 MapIndex Which map index the NPC is on (?).
0Eh 2 uint16 NextObjectId Appears to have no use.

References[edit]


Technical Details
Game Ultima IIIUltima IVUltima VUltima VIUltima VIIUltima VIIIUltima IXUltima Underworld