Ultima IX internal formats
Here is a description of various data files used by Ultima IX. This compiles information from the sources given in the links, as well as information discovered by various contributors and the Forgotten World Team.
Definitions[edit]
These are definitions for byte formats used on this page:
- char - An 8-bit (1-byte) character code in Windows-1252 encoding.
- charz - As with char, but a nul character (code 0) terminates a string.
- cstring - A uint32 string length followed by that many chars.
- cstringz - A uint32 string length followed by that many chars, with a NUL (code 0) character as the last character.
- float32 - A 32-bit floating point value in IEEE-754's binary32 format, in little-endian byte order; this is the same floating-point format used natively on X86 machines.
- uint8 - Unsigned 8-bit (1-byte) integer, between 0 and 255 (2^8-1).
- uint16 - Unsigned 16-bit (2-byte) integer, between 0 and 65535 (2^16-1), in little-endian byte order.
- uint32 - Unsigned 32-bit (4-byte) integer, between 0 and 4294967295 (2^32-1), in little-endian byte order.
- vec3 - A 3-D vector stored as three float32 for x, y, and z.
Files[edit]
This is a hierarchical index of the files in Ultima IX and what is known about them. This assumes that everything is installed from the CD, using a custom install.
- 00000409.016, 00000409.256 - Installation background images in BMP format. No use to the game.
- autorun.exe, autorun.ico, eahelp.hlp, FinalSetup.exe, ip.cfg, ip.exe, Uninst.isu - Installation files with no use to the game.
- clcd16.dll, clcd32.dll, clokspl.exe, ConfigINI.exe, dplayerx.dll, drvmgt.dll, Dsetup.dll, secdrv.sys - Executable files with limited apparent applicability.
- D3D.TXT, Eula.txt, keymap.new, options.new, OPTIONS.TXT, PATCH.TXT, PERFORM.TXT, Readme.txt - Text files with no use to the game.
- Default.kmp - Keymap in INI format.
- Options.ini - Game options in INI format.
- u9.exe - Main executable.
- EREG/ - Electronic registration files; no use to the game.
- Movies/ - The game's movies files is in a MPEG (MPG) sequence, v1, system multiplex, video format.
- runtime/ - Data that can be modified during the game.
- nonfixed.%d, where %d is between 0 and 239.
- npc.flx - Contains a single record, which is a list of NPCs. Since "u9game0.sav" appears to be used for initial state and it also has a list of NPCs, it's not clear whether this is used by the game.
- savegame/ - Save files, as well as what looks to be temporary unpacked files used while playing.
- savegame/u9game%d.sav, where %d is a number between 1 and infinity - The packed savegames, using the Savegame file format.
- sound/ - Speech, sound effects, and music files.
- sound/music.flx
- sound/sfx.flx
- sound/sfxassoc.flx
- sound/sfxcat.flx
- sound/sfxenv.flx
- sound/sfxtmpl.flx
- sound/Speech.flx
- static/ - Data that cannot be modified during the game.
- static/activity.flx
- static/anim.flx - Animations for the NPCs and books, using the Animation FLX record format.
- static/ankh.pal - Palette used in 8-bit rendering mode and in the pictures in the savegames, using the Palette file format.
- static/areas.flx
- static/bitmap16.flx, static/bitmapC.flx, static/bitmapsh.flx
- static/books-en.flx - Books and stores files, using the Book FLX record format.
- static/dimension.dat
- static/fixed.%d, where %d is 0 to 239 - Immovable objects within the region, using the Fixed file format.
- static/highway.dat
- static/Mbrk.br, static/Mbrk.fn, static/Mbrk.ns, static/Mbrk.vl
- static/misctext.flx - Miscellaneous text strings, in the Wide String FLX record format.
- static/registry.txt - Appears to be a list of bone names and numbers.
- static/rgbccube.dat, static/shade.tbl, static/shadegry.tbl, static/yiqccube.dat - Used in 8-bit rendering mode.
- static/sappear.flx - 3D mesh data, in the Mesh FLX record format.
- static/sdInfo.flx, static/sdInfo16.flx, static/sdInfoC.flx
- static/spaces.flx
- static/Tbrk.br, static/Tbrk.fn, static/Tbrk.ns, static/Tbrk.vl
- static/terrain.%d, where %d is 0 to 239 - Terrain height map information, in the Terrain file format.
- static/text.dat
- static/text.flx - Text strings, in the Wide String FLX format.
- static/Texture8.9, static/Texture8.14, static/texture16.9, static/texture16.14 - Textures where each panel is a 16x16 segment from the terrain for the given region. This may be used for the low-detail terrain rendering.
- static/Tnbrk.br, static/Tnbrk.fn, static/Tnbrk.ns, static/Tnbrk.vl
- static/treedat.flx
- static/triggers.flx
- static/typename.flx - Type name and icons, in the Type Name FLX format.
- static/types.dat
- static/u9game0.sav - Initial save state used when starting a new game, using the Savegame file format.
FLX Format[edit]
This is an archive file used extensively throughout the game. The header for each flx files contains records throughout the file for what are essentially subfiles.
Header format[edit]
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 4Ch | text | Optional comment; always blank. | |
4Ch | 4 | uint32 | ||
50h | 4 | uint32 | count | Number of entries. |
54h | 4 | uint32 | ||
58h | 4 | uint32 | size | Total file size. |
5Ch | 4 | uint32 | size2 | Also total file size. |
60h | 20h | ?? | ?? | |
80h | 8n | dir. | List of directory entries, as below. | |
x | x | data | Actual data. |
Directory entry format[edit]
Offset | Length | Format | Description |
---|---|---|---|
0 | 4 | uint32 | Offset of the record from the start of the file, or 0 if there is no record in this entry. |
4 | 4 | uint32 | Length of the record in bytes. |
Map Files[edit]
Terrain files[edit]
This is the format for the "static/terrain.%d" files, where %d is between 0 and 239 with some gaps for nonexistent regions. This contains the height map information for that region, and is present even if the region doesn't have any visible terrain. The terrain is cut into 16x16 point tiles, which are 8x8 world coordinates each. Each tile refers to a chunk, and it is possible for a chunk to be used by multiple tiles (such as if it's the bottom of the ocean). Curiously, there are always more chunks than tiles. This is the format of the header:
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 4 | uint32 | width | Width in tiles of the region. |
04h | 4 | uint32 | height | Height in tiles of the region. |
08h | 80h | charz | name | Name of the region. This appears to only be used for internal purposes. |
88h | 4 | uint32 | waterlevel | |
8Ch | 4 | uint32 | waveamplitude | |
90h | 4 | uint32 | flags | |
94h | 4 | uint32 | chunkCount | The number of chunks. |
This is followed by the tile indices into the chunks:
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 2*width*height | uint16 | indices | Index of the chunk for each tile, in [x + y * width] order. |
The chunk data itself then follows:
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 4*16*16 | uint32 | points | Points in the chunk. |
Each tile is a bitmask with the following format:
First bit | Last bit | Bits | Mask | Name | Description |
---|---|---|---|---|---|
0 | 11 | 12 | 4095 | height | Height of the point, between 0 and 4095 (realistically much less). Each value is 0.25 world coordinates. |
12 | 12 | 1 | 1 | hole | If this is set, this quadrangle should be removed when the terrain is viewed at maximum detail, and it should not impede movement. |
13 | 13 | 1 | 1 | swap | Swap the X and Y axes for the texture coordinates. |
14 | 14 | 1 | 1 | mirror | Mirror the X and Y axes for the texture coordinates. |
15 | 15 | 1 | 1 | ?? | |
16 | 21 | 5 | 31 | frame | The index of the frame within the texture to use. |
22 | 31 | 10 | 1023 | texture | The index of the texture to use in the "static/bitmaps8.flx" or "static/bitmaps16.flx" files. Texture index 29 is used but cannot be visible, so it can safely be discarded even if the point is not a hole. |
Fixed Files[edit]
This is the format for the "static/fixed.%d" files, where %d is between 0 and 239 with some gaps for nonexistent regions. This contains the objects which cannot be moved or interacted with, such as trees or houses. The region is cut into 32x32 point blocks. The format of the block is not known, but they somehow map to pages, which store a sequence of fixed objects. This is the format of the header:
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 4 | uint32 | ?? | |
04h | 4 | uint32 | ?? | |
08h | 4 | uint32 | pagesSize | The size in bytes of all the pages. |
0Ch | 4 | uint32 | ?? | |
10h | 4 | uint32 | width | The number of tiles the region is wide. This is the same as the terrain height map's width divided by two. |
14h | 4 | uint32 | height | The number of tiles the region is tall. This is the same as the terrain height map's height divided by two. |
18h | 4 | uint32 | ?? | |
1Ch | 4 | uint32 | ?? |
This is followed by some kind of value related to the tiles:
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 4*width*height | uint32 | ?? | These are either 0 or a number in the form nnnn001h, where nnnn is a number that may be a page index. This may be in [x + y * width] order, but that doesn't seem to corroborate with where objects are located in the maps. |
The pages themselves follow. Each is 1000h (4096) bytes long:
Offset | Length | Format | Name | Description |
---|---|---|---|---|
000h | 4 × 3 | uint32 | ?? | |
00Ch | 4 | uint32 | baseX | The base X coordinate to add to the X coordinate of all objects in the page. This is divisible by 4096. |
010h | 4 | uint32 | baseY | The base Y coordinate to add to the Y coordinate of all objects in the page. This is divisible by 4096. |
014h | 4 × 13h (19) | uint32 | ?? | |
060h | 18h × A6h (24 × 166) | Fixed object | objects | The list of objects in the page. |
FF0h | 10h | zero | Padding to a 1000h (4096)-byte boundary. |
The fixed objects are 18h (24) bytes long:
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 4 | uint32 | reference | A byte offset from the start of the file to another object, or 0. Some objects have invalid references, and some are circular. |
04h | 2*3 | uint16 | position | The location of the object within the tile, between 0 and 4095. This means that for each terrain quad there are 128 discrete positions. |
0Ah | 2 | uint16 | type | The type index. |
0Ch | 2*3 | int16 | angle | Angle of the fixed stored in 0.16 fixed point as a conjugated normalized quaternion. This means that to convert to a regular quaternion, if we consider the input values x, y, z, and w, then you compute the angle as Quaternion(-x / 32767.0, -y / 32767.0, -z / 32767.0, w / 32767.0). |
12h | 2 | uint16 | Flags | Flags for the object. |
14h | 4 | uint32 | ? |
The flags have these known values:
First bit | Last bit | Bits | Mask | Name | Description |
---|---|---|---|---|---|
0 | 0 | 1 | 1 | Required | Crashes the game if this is not set. |
1 | 1 | 1 | 1 | CollideWithPlayer | Collide with the player, and maybe other NPCs. |
12 | 12 | 1 | 1 | Semitransparent | Render the object as semi-transparent. |
Nonfixed Files[edit]
This is the format for the "runtime/nonfixed.%d" files, where %d is between 0 and 239 with some gaps for nonexistent regions. This holds dynamic objects whose state can change. This is the format of the header:
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 4 × 5 | uint32 | ?? | |
14h | 4 | uint32 | Width | Width of the region in chunks. |
18h | 4 | uint32 | Height | Height of the region in chunks. |
1Ch | 4 | uint32 | ?? | |
20h | Width × Height × 4 | uint32 | Byte offset of the first page in the chunk, relative to the end of the header. | |
?? | 4 | uint32 | ?? |
This is then followed by the pages. Each starts with the following header, which is 60h/96 bytes long:
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 4 | uint32 | nextPage | Offset of the next page in this chunk, relative to the end of the header minus 1, or 0 for none. |
04h | 4 | uint32 | endEntityOffset | |
08h | 4 | uint32 | endTriggerOffset | |
0Ch | 4 | uint32 | baseX | Base X coordinate of the chunk. |
10h | 4 | uint32 | baseY | Base Y coordinate of the chunk. |
14h | 4 | uint32 | entityCount | Number of entities in the chunk. |
18h | 4 | uint32 | triggerCount | Number of triggers in the chunk. |
1Ch | 4 × 17 | uint32 | Further offsets to either entities or extra data. (It's not currently clear how to distinguish them.) |
This is then followed by entityCount entities:
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 2 | uint16 | nextEntitiy | Offset to the next entity in a linked list. |
02h | 2 | uint16 | ?? | |
04h | 2 | uint16 | offsetX | X offset of the entity relative to the chunk's baseX value. |
06h | 2 | uint16 | offsetY | Y offset of the entity relative to the chunk's baseY value. |
08h | 2 | uint16 | z | Z position of the entity; the elevation. |
0Ah | 2 | uint16 | typeIndex | Type index. |
0Ch | 2 × 4 | int16 | rotation | Rotation of the entity expressed as an 0.16 quaternion (divide integer values by 32767). |
14h | 4 | uint32 | flags | Entity flags. |
18h | 2 | uint16 | meshIndex | The mesh index to render for this entity. |
1Ah | 2 | uint16 | triggerId | |
1Ch | 4 | uint32 | extraDataOffset | Offset of the extra data, relative to the end of the file header. |
If extraDataOffset is not zero, extra data is present at the given relative offset. It has this format:
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 1 | byte | argCount | Number of parameters in this structure. |
01h | 3 x 1 | byte | arguments | First, second, and third parameter type (or 0 for none). For example, 66 indicates scaling across all axes. |
04h | 3 x 4 | uint32 | values | Arguments for each of the 1-3 parameters indicated above. For example, for scaling, this is the scaling factor. |
Graphics Files[edit]
The following sub-sections contain the record formats for graphics related FLX files along the file formats for other graphics based files.
Palette files[edit]
This is used with "static/ankh.pal", which is the master palette used in 8-bit mode and for the pictures in savegames.
Offset | Length | Format | Name | Description |
---|---|---|---|---|
0 | 256*4 | uint32 | palette | 256 colors, each using the format below. |
Each color has the following format:
Offset | Length | Format | Name | Description |
---|---|---|---|---|
0 | 1 | uint8 | blue | Blue component, from 0 (black) to 255 (most intense). |
1 | 1 | uint8 | green | Green component, from 0 (black) to 255 (most intense). |
2 | 1 | uint8 | red | Red component, from 0 (black) to 255 (most intense). |
3 | 1 | uint8 | zero | Must be zero. |
Texture8 FLX record format[edit]
This is the format for the items in the texture8.* files.
NOTE: len is the length of the item
Header[edit]
Offset | Length | Format | Description |
---|---|---|---|
0 | 4 | uint32 | width |
4 | 4 | uint32 | height |
8 | ?? | ?? | ?? |
len-width*height | width*height | data | image data, each byte indexes a palette entry in ankh.pal |
Bitmap Format[edit]
Header[edit]
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 2 | uint16 | width | Maximum width in pixels of all frames. |
02h | 2 | uint16 | Possibly format-related. | |
04h | 2 | uint16 | height | Maximum height in pixels of all frames. |
06h | 2 | uint16 | compression | 0 = uncompressed, 1 = 8-bit compression of some sort. |
08h | 4 | uint32 | frameCount | Number of frames. |
0Ch | 3 | ?? | ?? | |
0Fh | 1 | uint8 | frameCount - 1 | |
10h | 8frm | Frame Record | Offset and length for each frame. |
Frame Record[edit]
Offset | Length | Format | Description |
---|---|---|---|
0 | 4 | uint32 | Offset of the frame from the beginning of the file. |
4 | 4 | uint32 | Length of the frame in bytes. |
Frame[edit]
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 4 | uint16 | ?? | The second uint16 is usually 6000h. |
04h | 4 | uint32 | width | Width in pixels of this frame. |
08h | 4 | uint32 | height | Height in pixels of this frame. |
0Ch | 8 | uint32 | ?? | Both almost always zero. |
14h | 4*height | uint32 | rowOffsets | Table of 'height' 4-byte entries (offset table of some kind, probably for speed). |
x | width*height*depth | ?? | Bitmap data. | |
x | ? | ? | Mipmaps. |
The "depth" above means the bytes per pixel, which is 1 for "static/bitmaps8.flx" or 2 for "static/bitmaps16.flx". 16-bit pixels use this bitmask:
First bit | Last bit | Bits | Mask | Name | Description |
---|---|---|---|---|---|
0 | 4 | 5 | 31 | red | Red component, with 0 as black and 31 as most intense. |
5 | 9 | 5 | 31 | green | Green component, with 0 as black and 31 as most intense. |
10 | 14 | 5 | 31 | blue | Blue component, with 0 as black and 31 as most intense. |
15 | 15 | 1 | 1 | alpha | If set, the pixel is opaque; otherwise it is transparent. |
Sappear FLX record format[edit]
This is used for "static/sappear.flx". It defines the 3D meshes, aside from the terrain. Each record begins with this header:
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 4 | uint32 | Submesh Count | Number of submeshes. |
04h | 4 | uint32 | LOD Count | Number of level-of-detail stages. |
08h | 12 | vec3 | Cylinder Base Centre | Centre of the Cylinder Base. |
14h | 4 | float32 | Cylinder Base Height | The height of the Cylinder |
18h | 4 | float32 | Cylinder Base Radius | The radius of the Cylinder. |
1Ch | 12 | vec3 | Sphere Center | Center of Sphere |
28h | 4 | float32 | Sphere Radius | Radius of the Sphere |
2Ch | 4 | float32 | ?? | ?? |
30h | 12 | vec3 | Minimum Bounds | Minimum bounds of a bounding box for the mesh. |
3Ch | 12 | vec3 | Maximum Bounds | Maximum bounds of a bounding box for the mesh. |
48h | 4 | uint32 | LOD Threshold 0 | Thresholds 0 |
4Ch | 4 | uint32 | LOD Threshold 1 | Thresholds 1 |
50h | 4 | uint32 | LOD Threshold 2 | Thresholds 2 |
54h | 4 | uint32 | LOD Threshold 3 | Thresholds 3 |
58h | 12 | vec3 | Center of Mass | Center of Mass |
64h | 4 | float32 | Mass or Volume? | ?? |
68h | 36 | matrix | Inertia Matrix | Matrix for the inertia for the model |
8Ch | 4 | float32 | Inertia related? | Usually 1 or close to zero. |
90h | 4 × meshCount × lodCount | uint32 | Submesh Map | Offsets from the start of the record for each submesh in (lod + mesh * lodCount) order. |
Submesh format[edit]
At each submesh offset is a submesh header:
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 4 | uint32 | Limb ID | The ID of this submesh |
04h | 4 | uint32 | Parent ID | The ID of the parent mesh |
08h | 4 | uint32 | Scale X | Scale of the submesh in the X direction |
0Ch | 4 | uint32 | Scale Y | Scale of the submesh in the Y direction |
10h | 4 | uint32 | Scale Z | Scale of the submesh in the Z direction |
14h | 12 | vec3 | Position | Position/Offset coordinates to parent mesh |
18h | 4 | float32 | Orientation W | Rotation Scalar |
1Ch | 4 | float32 | Orientation X | Rotation X |
20h | 4 | float32 | Orientation Y | Rotation Y |
24h | 4 | float32 | Orientation Z | Rotation Z |
Following the header are the LOD levels.
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 4 | uint32 | Mesh Size | The size of the submesh in bytes, excluding this value, or 0 if there is no such submesh at this LOD level. |
04h | 4 | uint32 | Flags | Appears to be a bitmask, with 4 and 8 being most common. |
08h | 4 | uint32 | Unused? | |
0Ch | 12 | vec3 | Sphere Center | LOD level's sphere center |
18h | 4 | float | Sphere Radius | LOD level's sphere radius |
1Ch | 12 | vec3 | Minimum Bounds | Minimum bounding box. |
28h | 12 | vec3 | Maximum Bounds | Maximum bounding box. |
34h | 4 | uint32 | ignorable | |
38h | 4 | uint32 | ignorable | |
3Ch | 4 | uint32 | Face Count | Number of faces in the submesh. |
40h | 4 | uint32 | Mount Face Count | |
44h | 4 | uint32 | Vertex Count | Number of vertices in the submesh. |
48h | 4 | uint32 | Mount Vertex Count | |
4Ch | 4 | uint32 | Max Face Count | |
50h | 4 | uint32 | Material Count | Number of materials. |
54h | 4 | uint32 | Face Offset | Offset of the faces relative to the start of the detail level plus 4. |
58h | 4 | uint32 | Mount Face Offset | |
5Ch | 4 | uint32 | Vertex Count | Offset of the vertices relative to the start of the detail level plus 4. |
60h | 4 | uint32 | Mount Vertex Count | |
64h | 20 | uint32 | Material Offset | Offset of the materials relative to the start of the detail level plus 4. |
68h | 16 | uint32 | Sorted Faces Offset | |
78h | 8 | uint32 | probably unused | |
Face Offset + 4 | 7Ch × Face Count | Face | Faces | The list of faces. |
Vertex Offset + 4 | 0Ch × Vertex Count | vec3 | Vertices | The list of vertices. |
Material Offset + 4 | 18h × Material Count | Material | Materials | The list of materials. |
Sorted Faces Offset + 4 | × Faces Count |
Face format[edit]
Each triangle is 7Ch (124) bytes long, and has this format:
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 1Ch × 3 | point | Points | Points in the face, described below. |
54h | 4 | bits[32] | Flags | only first 12 bits appear to be used |
58h | 4 | bits[32] | Flags2 | unused? |
60h | 12 (0Ch) | vec3 | Normal Vector | |
6Ch | 4 | float32 | Vector W? | |
6Ch | 4 | uint32 | Material | Sometimes a zero-based index into the bitmap16.flx/bitmapC.flx/bitmapsh.flx file (whichever is the active option) for the texture to use. In other cases this has a pattern but no strict correlation to the material. Use the material list instead to select textures. |
70h | 4 | uint8[4] | color | Color of the face in RGBA order, each element being between 0 (black/transparent) and 255 (bright/opaque). |
74h | 4 × 2 (8) | uint8[8] | Collision Related | for collision system (index list [so only values from 0, 1, or 2] that contains the index of the vertex that is closest to each of the faces [order is: left,right,front,back,bottom,top] |
Point format[edit]
This is the format for a point in a face, which is 1Ch (28) bytes long:
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 4 | uint32 | Point | Point index. |
04h | 4 | uint32 | Point Offset | Offset to the point in bytes. |
08h | 12 | vec3 | Normal | Not always a unit vector. |
14h | 8 | vec2 | UV Coordinates | UV coordinates. |
Material format[edit]
This is the format for a material that is applied to a set of triangles. Each is 18h (24) bytes long:
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 2 | uint16 | Texture ID | Zero-based index of the texture to use from the bitmap16.flx/bitmapC.flx/bitmapsh.flx file (whichever is the active option). |
02h | 2 | bits[16] | Flags | |
04h | 2 | uint16 | Subtexture Count | |
06h | 2 | bits[16] | Flags2 | |
08h | 2 | uint16 | First Face ID | Zero-based index of the first face with this material. |
0Ah | 2 | uint16 | Face Count | The number of faces with this material. |
0Ch | 1 | uint8 | Default Alpha | |
0Dh | 1 | uint8 | Modified Alpha | |
0Eh | 1 | uint8 | Animation Start | Starting Frame for animation |
0Fh | 1 | uint8 | Animation End | Ending Frame for animation |
10h | 1 | uint8 | CurFrame | |
11h | 1 | uint8 | Animation Speed | Speed of animation in frames per second |
12h | 1 | uint8 | Animation type | |
13h | 1 | uint8 | Playback direction | 0 - forward, 1 - backward |
14h | 4 | uint32 | Animation Timer related | Animation timer value |
Animation FLX record format[edit]
This is used by the "static/anim.flx" file. It contains all the body part animations for the NPCs, and animations for the books.
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 4 | uint32 | index | Same as the record index. |
04h | 8 | uint32 | ?? | |
08h | 4 | uint32 | totalFrameCount | The maximum number of frames. |
0Ch | 8 | uint32 | ?? | Always [1Eh, 21H]. |
10h | 4 + filename.length | cstringz | filename | The source filename. |
14h + filename.length = 0 | 4 | uint32 | headerLength | The number of elements in the header. |
04h | 4 × headerLength | uint32 | ?? | The start appears to be repeats of part ids. |
04h + 4 × headerLength = 0 | 4 | uint32 | partCount | The number of parts in the animation. |
04h | varies | part | parts | The list of parts. |
04h + varies = 0 | 4 | uint32 | suffixCount | The number of suffixes. |
04h | 4 × 3 × suffixCount | uint32 | suffixes | The list of suffixes, each of which is a uint32 triple. These may be segments of the animation. |
Parts for the Animation FLX record format[edit]
This is the format of a part.
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 4 | uint32 | id | A one-based identifier of the part. This corresponds to a limb ID from the mesh. Values above 255 appear to be unrelated parts from the LightWave file (such as the camera and light rigging). |
04h | 4 + name.length | cstringz | name | Length-prefixed name of the part. |
08h + name.length = 0 | 4 | uint32 | frameCount | Number of frames. |
04h | 2Ch (44) × frameCount | frame | frames | List of frames. |
Frames for the Animation FLX record format[edit]
This is the format of a frame within a part. The transformation replaces the transformation of the corresponding mesh when this frame is active.
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 4 | uint32 | ms | The number of milliseconds from the start of the animation to display this frame for this part. |
10h | 4 × 4 | float32 | rotation | Rotation quaternion, this time given in the order W, X, Y, Z. |
04h | Ch (12) | vec3 | position | The relative transform for positioning the part. |
20h | Ch (12) | vec3 | scale | The scaling factor. |
Item Files[edit]
Types Database File[edit]
Offset | Length | Format | Name | Description |
00h | 4 | uint32 | ?? | Either 0 or CDCDCDCDh, with no apparent reason. |
04h | 2 | uint16 | Usecode ID | Refers to an entry in the usecode list, which is within the game engine. |
06h | 2 | uint16 | Default Model ID | Refers to a model entry in the "static/sappear.flx". This model ID is used by default but the model ID used per instance in the nonfixed map file takes priority. |
08h | 2 | bits | Type Flags | Each bit of this word is a separate type flag: Never Hidden(0x01), NPC Only Collision(0x02), Partial Collision(0x04), Non Camera Block (see Spaces FLX)(0x08),
Portal Block (see Spaces FLX)(0x10), Unique Model (Final Art I'm guessing for the modelers)(0x20), ??(0x40), Not used, Vestigial(0x80), Mesh Collision(0x0100) |
0Ah | 1 | uint8 | Object Weight | Weight used for Physics gravity, FF are not player movable, FE appears to be the same |
0Bh | 1 | uint8 | Volume | Probably used for collision cylinder |
0Ch | 1 | uint8 | Book Number | Vestigial parameter, may not even be recognized by the engine. |
0Dh | 1 | uint8 | Hitpoints | Vestigial parameter, handled with NPC.flx or type's instance nonfixed property. |
0Eh | 2 | uint16 | ?? | Always 0. |
Type name FLX record format[edit]
This is the record type used in "static/typename.flx". This includes the tooltip icon and text used with the inventory and examine features in the game. Each typename entry corresponds to an object type in "static/types.dat".
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 4 | uint32 | ?? | Either 0, -1, or rarely a value above 255. Possibly script-related. |
04h | 2 | uint16 | Icon ID | Inventory Icon ID for an image in "static/bitmaps16.flx" or "static/bitmaps8.flx". |
06h | - | charz | Tooltip Text | Tooltip for the type. Null-terminated text. |
Book FLX record format[edit]
The format for records in "static/books-en.flx" is as follows. This format is more than likely also used for the other languages as well.
Offset | Length | Format | Description |
---|---|---|---|
0 | 4+ | cstringz | Title string in the form "(id number): (book title)". This doesn't appear to be used. |
x | 4+ | cstring | Book text body. |
The body format depends upon whether this is a book or a store record. A book has significant newlines. A line beginning with ` changes the font, and can be:
- `p - Apparently the intent is for a new page, but it's always at the beginning of the book.
- `f1 - Blue font.
- `f2 - Red font.
- `f3 - Black italic font.
- `f5 - Gargish font.
`f4 is not used, but would probably be runic.
Stores have a line-oriented format. The first line is the name of the store. Subsequent lines may begin with "!", indicating that they are a comment. Otherwise they have the form '#(number) "(name)" $(price)', where (number) is the item number, (name) is the name to display (which is adjusted to fit the size of the GUI), and (price) is the price of the item.
Text and MiscText FLX record format[edit]
This is the format for records in "static/text.flx" and "static/misctext.flx". Each record is a UCS-2 string that is nul-terminated. It is possible, but unlikely, that it is in UTF-16.
NPC FLX record format[edit]
Each record is 143h/323 bytes in size.
Offset | Length | Format | Name | Description |
---|---|---|---|---|
000h | 4 | ?? | ?? | ?? |
004h | 32 | charz[32] | Name | Name of the NPC. |
024h | 1 | uint8 | Gender | 0: Male, 1: Female. |
025h | 15 | ?? | ?? | ?? |
034h | 2 | uint16 | HealthCurrent | Current health. |
036h | 2 | uint16 | HealthMaximum | Maximum health. |
038h | 2 | uint16 | HealthMaximum2 | Also maximum health. |
03Ah | 2 | uint16 | ManaCurrent | Current mana. |
03Ch | 2 | uint16 | ManaMaximum | Maximum mana. |
03Eh | 2 | uint16 | ManaMaximum2 | Also maximum mana. |
040h | 24 | ?? | ?? | ?? |
058h | 4 | uint32 | Region | Region index the NPC is in. |
05Ch | 4 | uint32 | PositionX | X coordinate of the NPC. |
060h | 4 | uint32 | PositionY | Y coordinate of the NPC. |
064h | 2 | uint16 | PositionZ | Z coordinate of the NPC (elevation). |
068h | 4 | ?? | ?? | ?? |
06Ch | 1 | uint8 | ScaleX | X scale in percent. |
06Dh | 1 | uint8 | ScaleY | Y scale in percent. |
06Eh | 1 | uint8 | ScaleZ | Z scale in percent. |
06Fh | 212 | ?? | ?? | ?? |
Scripting Files[edit]
Activity FLX record format[edit]
Triggers FLX record format[edit]
Highway Database record format[edit]
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 4 | uint32 | Number of Highway Points | Number of Highway Points in file |
04h | 4 | uint32 | Number of Highway Segments | Number of Highway Segments in file |
Following the header are a bunch of highway points, which define the location of cross objects (patheggs in the U7 vernacular). Each Highway point has the following format.
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 4 | uint32 | Trigger ID | Trigger ID for a highway pathegg. |
04h | 4 | uint32 | X coordinate | Absolute X coordinate of the map for the corresponding highway pathegg. |
08h | 4 | uint32 | Y coordinate | Absolute Y coordinate of the map for the corresponding highway pathegg. |
Following the highway points is a unint32 containing the total number of bytes for the highway segments. After that are the highway segments, which have the following format.
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 2 | uint16 | Start Trigger ID | Trigger ID for the first highway pathegg. |
02h | 2 | uint16 | Last Trigger ID | Trigger ID for the last highway pathegg. |
04h | 2 | uint16 | Path Length | Number of highway points in segment. |
06h | 2 | uint16 | Route Distance | Total distance to travel for route. |
08h | 2 | uint16 | Nulls | part of distance or unused bytes |
Following each highway segment is a sequence of uint16's that define the exact route of highway point trigger IDs.
Sound Files[edit]
Sound FLX record format[edit]
This is used for "sounds/sfx.flx", "sounds/music.flx", "sounds/speech.flx", maybe others.
The format of the type 1 encoding was determined by Josef Drexler.
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 4 | uint32 | id | Identification number. |
04h | 20h | asciiz | description | Description. |
24h | 4 | ? | probably more description? | |
28h | 4 | uint32 | length | Sample data length in bytes. |
2Ch | 4 | uint32 | frequency | Frequency in hertz. |
30h | 4 | uint32 | Bits per sample? | |
34h | 4 | uint32 | Channel count? | |
38h | 4 | uint32 | encoding | Encoding method; see below. |
3Ch | length | x | data | Sample data, in the encoding method. |
These are the encoding methods:
Value | Meaning |
---|---|
0 | PCM (ie. no compression/encoding) |
1 | ADPCM |
2 | EA MicroTalk - used by speech |
Miscellaneous Files[edit]
Savegame files[edit]
This is used with the "savegame/u9game%d.sav" files, as well as "static/u9game0.sav". These contain packed savegame data. This is the basic format:
Header[edit]
The Header contains the Start.dat file, the title of the savegame, possibly some current camera data, and a low-res screenshot for the savegame.
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 6 | char | magic | Always "U9:008". |
06h | 4 | uint32 | Savegame Number | Null Field to record the savegame number for the Start.dat file used by the engine to determine, which savegame was last loaded. |
0Ah | 4 | uint32 | description.length | Length of Savegame title |
0Eh | description.length | cstringz | Savegame Title | The title input into the save game dialog. |
0Eh + description.length | 25h | ?? | ?? | Could be data for the camera's position and properties |
33h + description.length | 4 | uint32 | Map Number | Map number for player's location for that savegame |
37h + description.length | 23h | ?? | ?? | More data for the camera's position and properties |
Game Picture[edit]
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 4 | uint32 | width | Width of the picture in pixels. This is always 256. |
04h | 4 | uint32 | height | Height of the picture in pixels. This is always 128. |
08h | 4 × 2 | uint32 | ?? | |
10h | 4 × height | uint32 | rowOffsets | Appears to be offsets to the rows. This is constant, but the base seems unclear. |
10h + 4 × height | width × height | uint8 | pixels | Picture data in [x + y * width] order, in 8-bit indexed mode, using "static/ankh.pal" for colors. |
Processes Database[edit]
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 4 | uint32 | size | Size in bytes of the processes data. |
04h | size | ?? | ?? | Process data. The First part contain variables. Second part starts at 58h/88 is the NPC.flx data. |
Diary Text[edit]
Offset | Length | Format | Name | Description |
---|---|---|---|---|
00h | 4 | uint32 | diary.length | Length of the current Diary in bytes. |
04h | diary.length | cstringz | All Diary Entries | Each entry in the diary except the last one ends with the byte sequence [0Ah 09h 09h 09h BCh BDh BEh 0Ah], which translates to the formating: ENTER + TAB + TAB + TAB + <Unknown> + ENTER |
Nonfixed Files[edit]
The remainder of the file are current state for all encountered nonfixed.# files as of that save.
External Links[edit]
- U9Tools - a collection of tools that allow the user to extract and modify the contents of various Ultima IX data files.
- U9Decode - Joseph Drexler's utility that allows the user to extract Ultima IX's music.
- Paeron - Paeron's documentation, supplementing information from Tumbleweed.
Technical Details | |
---|---|
Game | Ultima III ☥ Ultima IV ☥ Ultima V ☥ Ultima VI ☥ Ultima VII ☥ Ultima VIII ☥ Ultima IX ☥ Ultima Underworld |