Ultima V internal formats
This text was originally copied from "Nodling's", but has been refined extensively.
LZW compressed[edit]
Some files from the PC version of Ultima V have been compressed with the LZW algorithm:
- .4
- .16
(and possibly others)
The compressed files are stored as (uint32 uncompressedLength, uint8[] compressedData).
Graphics files (*.4 and *.16 extensions)[edit]
These are all LZW-compressed image files. Those with a .4 extension have four-colour, two-bit data; those with a .16 extension have 16-colour, four-bit data.
Pixels are stored in descending bit order. So for a 16-color byte the first pixel is mask 0xF0, and the second is mask 0x0F. For a 4-color byte, the first pixel is mask 0xC0, the second pixel is mask 0x30, the third pixel is mask 0x0C, and the fourth pixel is mask 0x03.
Rows of pixels are padded to a four-pixel (byte) boundary for 4-color data, and an eight-pixel (four byte) boundary for 16-color data. So for a given width in pixels, a 4-color row is ((width + 3) / 4) bytes long, while a 16-color row is ((width + 7) / 8 * 4) bytes long.
"tiles.4" and "tiles.16"[edit]
These files, when uncompressed, contain 512 (0x200) tiles that are each 16x16 pixels stored in order without any headers. Using the above rules, the 4-color rows are stored as 4 bytes per row, and the 16-color rows are 8 bytes per row.
The 16-color tile sets are :
PC:
Here is the 4-color tileset using a gray-scale scheme with this file:
All other *.4 and *.16 files[edit]
These LZW-compressed files are composed of a number of images of varying sizes. The header is (uint16 count, uint32[count] offsets), where count is the number of images, and offsets is the start of an image from the beginning of the file, or zero if there is no image in that slot (this only occurs in "dng*.16" files).
Each image is composed of (uint16 width, uint16 height, ImageRow[height] data). Each row has the number of bytes discussed above.
"items.*" and "mon*.*" contain dungeon ladders, chests, and monster graphics, and have an additional twist:
- The offsets are actually in uint16 and not uint32
- Immediately following the image data is an image mask, composed of (uint16 width, uint16 height, uint8[(width + height + 7) / 8] data); width and height must be identical to those in the image. Pixels are stored in descending bit order with no padding, so the first pixel is mask 0x80, the second pixel is mask 0x40, and so on. If a value is set, then that pixel is masked and should not be drawn.
*.CBT[edit]
The combat files define a series of combat maps that are 11 x 11 in size.
File Format[edit]
struct CBT_File { Combat_Map c_maps[n]; };
Offset | Length (in bytes) | Purpose |
---|---|---|
0x0 | 352 | Map 1 |
0x160 | 352 | Map 2 |
... | ... | Rest |
Each map row consists of 11 columns of tile data followed by 21 bytes of special data.
Special data:
New tile IDs: Tile IDs that each trigger creates
Party positions: 6 bytes of X coords followed by 6 bytes of Y coords, then 9 bytes of padding
Monster tiles: 16 tiles of monster IDs, then 5 bytes of padding
Monster coordinates: 16 X or Y coordinates, no padding
Trigger positions: 8 bytes of X coords followed by 8 bytes of Y coords, then 5 bytes of padding. Each activates a pair of new tiles: one from the corresponding index of Row 10, and one from Row 11
New tile positions: 8 bytes of X coords followed by 8 bytes of Y coords, then 5 bytes of padding
Still unknown: Where are object qualities stored? For example, a room containing a scroll has the scroll tile as one of its "monsters", but the monster "quality" (i.e., the type of scroll) doesn't seem to be stored anywhere.
Offset | Length (in bytes) | Purpose |
---|---|---|
0x0 | 32 | Map Row 1 and new tile IDs, then 5 bytes of padding |
0x20 | 32 | Map Row 2 and party positions from east |
0x40 | 32 | Map Row 3 and party positions from west |
0x60 | 32 | Map Row 4 and party positions from south or below |
0x80 | 32 | Map Row 5 and party positions from north or above |
0xA0 | 32 | Map Row 6 and monster tiles |
0xC0 | 32 | Map Row 7 and monster X coords |
0xF0 | 32 | Map Row 8 and monster Y coords |
0x100 | 32 | Map Row 9 and trigger positions |
0x120 | 32 | Map Row 10 and new tile positions |
0x140 | 32 | Map Row 11 and new tile positions |
Example of a dungeon room[edit]
Here is an example of a dungeon room entirely decoded.
#Level 1 FF 4F 44 44 44 44 44 4F FF FF FF #New tiles for the changes 4F 4F 4F 44 44 44 44 44 #Unknown 00 00 00 00 00 00 00 00 #Unkown 00 00 00 00 00
#Level 2 FF 4F 44 44 44 44 44 4F 4F 4F 4F #Position X (east) 08 09 09 0A 0A 0A #Position Y (east) 04 03 05 04 02 06 #Unkown 00 00 00 00 00 00 00 00 00 #Level 3 FF 4F 44 44 44 44 44 44 44 44 44 #Position X (west) 00 00 00 00 00 00 #Position Y (west) 00 00 00 00 00 00 #Unkown 00 00 00 00 00 00 00 00 00 #Level 4 FF 4F 4F 44 44 44 44 44 44 44 44 #Position X (south) 04 05 03 04 06 02 #Position Y (south) 08 09 09 0A 0A 0A #Unkown 00 00 00 00 00 00 00 00 00 #Level 5 FF FF 4F 4F 44 44 44 44 44 44 44 #Position X (north) 04 03 05 04 02 06 #Position Y (north) 02 01 01 00 00 00 #Unkown 00 00 00 00 00 00 00 00 00 #Level 6 FF FF FF 4F 44 44 44 44 44 44 44 #Monster tiles (what monsters are in the room) DC D0 D0 D0 94 94 94 94 DC 00 00 00 00 00 00 00 #Unkown 00 00 00 00 00
#Level 7 FF FF 4F 4F 44 44 44 44 44 44 44 #Initial X position for monsters 09 02 01 01 01 01 01 01 09 00 00 00 00 00 00 00 #Unkown 00 00 00 00 00 #Level 8 FF 4F 4F 44 44 44 44 44 44 46 46 #Initial Y position for monsters 09 05 04 06 05 05 05 05 08 00 00 00 00 00 00 00 #Unkown 00 00 00 00 00
#Level 9 FF 4F 44 44 44 44 44 44 46 44 46 #Position X of trigger for 2 elements of level 1, positions are in level 10 and level 11 06 06 06 06 06 06 06 06 #Position Y of trigger for 2 elements of level 1, positions are in level 10 and level 11 06 06 06 06 06 06 06 06 #Unknown 00 00 00 00 00
#Level 10 FF 4F 44 44 44 44 44 46 44 44 46 #Position X of changes in map from trigger in Level 9 00 00 00 01 01 02 02 03 #Position Y of changes in map from trigger in Level 9 03 05 07 04 06 04 06 05 #Unkown 00 00 00 00 00
#Level 11 FF 4F 44 44 44 44 44 46 46 46 46 #Position X of changes in map from trigger in Level 9 00 00 00 01 02 03 03 03 #Position Y of changes in map from trigger in Level 9 04 06 06 05 05 04 06 05 #Unknown 00 00 00 00 00
Tiles for each monster[edit]
In the case of dungeon maps, the tile for each monster gives the engine which monster to load where. With the initial_X and initial_Y fields of the Map_MonsterX_Row or Map_MonsterY_Row, the system can load up any dungeon map with a maximum of 16 monsters in a given room.
The values of the the monster_tile array in the Map_MonsterTile_Row element coincide with the elements of the tile set. However, since we are considering monsters the first 256 tiles are ignored.
Thus 1 is a chest, 2 is gold, 3 is a potion, etc.
Notes:
- For some reason, certain values provide unexpected results
- 5C would normally be the bard but is the jocker instead
- EC, ED, EE, and EF seem to be a random monster value
- Though the system seems to use the first frame of each element, any frame seems to work indifferently:
- 0x78 is Blackthorn but so is: 0x79, 0x7A, and 0x7B
Combat maps[edit]
BRIT.CBT[edit]
DUNGEON.CBT[edit]
*.CH and *.HCS files[edit]
Font files with 128 characters each, encoded as simple bitmaps. Within a byte, the most significant bit represents the leftmost pixel, and the least significant bit represents the rightmost pixel. Characters in the *.CH files are 8x8, and ones in the *.HCS files are 16 wide, 12 tall.
- IBM.* contain the Latin characters and a number of symbols:
- Characters 1-4 are triangles pointing in four directions
- 5-8 are the animation frames of the cursor
- 11-12 are the male/female symbols
- 14 is a staff
- 15 is a dot
- 16-23 (except 18) are the borders of a scroll
- 18 and 24-27 are directional arrows
- 28 is the Crown
- 29 is the Badge
- 30-31 are half-height directional triangles
- 32-122 are the corresponding ASCII characters
- 123-126 are quadrants of a solid circle
- 127 is a solid square
- RUNES.* contain the Britannian runes and the remaining symbols:
- 1: Helm
- 2: Shield
- 3: Armor
- 4: Dagger
- 5: Sling
- 6: Club
- 7: Flaming Oil
- 8: Arrow (ammunition)
- 9: Throwing Axe
- 11: Sword
- 12: Mace
- 14: Sun symbol?
- 15: Bow
- 16: Crossbow
- 17: Two-handed hammer
- 18: Two-handed axe
- 19: Glass Sword, maybe?
- 20: Halberd
- 21: Jeweled Sword
- 22: Magic Bow
- 23: Magic Axe
- 24: Ring
- 25: Amulet
- 26: Spiked Collar
- 27: Ankh
- 28: Scroll
- 29: Potion
- 30: Morning Star
- 43: High underscore?
- 45-47: Ladders going down, up, and in both directions (for dungeon gems)
- 48-55: Moon phases, starting with New
- 56-59: Rounded border corners
- 64: High dot
- 65-90: Runes corresponding to the ASCII capital letters
- 91-95: TH, EE, NG, EA, and ST runes (corresponding to ASCII [\]^_ characters)
- 96: Diamond
- 97-102: Scroll borders
- 103-108: Square borders (like for a sign)
- 109-110: Signpost top and bottom
- 111: Staff
- 112: Dungeon treasure
- 113: Dungeon trap (looks like a trapezoid)
- 114: "x"?
- 115: Dungeon room (looks like box)
- 116: Dungeon sign (looks like pixel-inverted equals sign)
- 117: Dungeon skeletons-on-wall symbol
- 118: Dungeon secret door
- 119: Dungeon door
*.DAT[edit]
BRIT.DAT[edit]
The Britannian map. Its size is 256x256 tiles. It is divided into 256 chunks. Each chunk has a size of 16x16 tiles, and each tile is stored as a uint8 (in Ultima IV, the chunk size was 32x32 tiles).
To save space, chunks that are all water (tile 0x1) were left out. The location of the all-water chunks is stored in DATA.OVL. The chunks are stored from west to east, north to south, i.e. the first chunk in the uncompressed map is the one in the northwest corner.
The tiles in a chunk are also stored from west to east, north to south.
The complete map of Britannia is:
The complete map of Britannia with the original tileset is: [1]
CASTLE.DAT[edit]
The castle file contains all the maps concerning the castles.
- Lord British's Castle
- Blackthorn's Castle
- Britannys
- Small towns
DUNGEON.DAT[edit]
The DUNGEON.DAT file contains the dungeon maps for the game. It is made of 8 * 8 * 8 * 8 tiles where :
- The first 8 is a line of Deceit
- The first 8 * 8 is the first level of Deceit
- The first 8 * 8 * 8 is the dungeon Deceit, each level being 8 * 8
The code for each tile is actually divided in two groups of 4-bits:
Higher 4 bits:
- 0: Open hallway
- Lower bits = 8: Visible ceiling hole
- 1: Ladder Up
- 2: Ladder Down
- 3: Ladder Up and Down
- 4: Chest
- Lower bits:
- 0: normal chest
- 1, 2: trapped
- 4: poisoned
- Lower bits:
- 5: Fountain
- Lower bits:
- 0: cure poison
- 1: heal
- 2: poison
- anything else: bad taste, damage
- Lower bits:
- 6: Trap or pit
- Lower bits:
- (None): Visible floor hole
- 1: Invisible floor hole trap
- 2: Bomb trap (no floor hole)
- 8: Visible ceiling hole
- 9: Visible ceiling hole and invisible floor hole trap
- Lower bits:
- 7: Open chest
- 8: Energy fields
- Lower 3 bits:
- 0: Poison
- 1: Sleep
- 2: Fire
- 3: Energy
- Lower 3 bits:
- 9: Unused
- A: Unused
- B: Normal wall
- Lower values:
- 1: Text
- Lower values:
- C: Alternate wall (e.g., skeleton in manacles)
- D: Secret door
- E: Normal door
- F: Room
TOWNE.DAT[edit]
This data file contains the cities of Ultima 5:
DWELLING.DAT[edit]
The dwelling data contains the various dwellings of the game.
KEEP.DAT[edit]
The keep data contains the various keeps of the game.
- The Serpent's Hold
LOOK2.DAT[edit]
This file contains the "look" descriptions for the 0x200 tiles. Each description is a zero-terminated ASCII string. Some descriptions consist only of an asterisk, which the game displays as a diamond. The offsets are relative to the beginning of the file.
look2.dat = set(0x200) of offset16, set(0x200) of ascii_string
offset16 = uint16 ascii_string = set of ascii_char, terminator ascii_char = uint8 terminator = (uint8) 0
MISCMAPS.DAT[edit]
This file contains:
- 4x Cutscene Screens (11x11 tiles)
- 4x Intro Screens (19x4 tiles)
- Intro Script Data
Offset | Length (in bytes) | Purpose |
---|---|---|
0x0 | 704 | Cutscene Maps |
0x2C0 | 512 | Intro Maps |
0x4C0? | 655 | Script Data [0x28F] |
Cutscene Maps[edit]
The four cutscenes are:
- Blackthorn's interrogation (slightly different from the way his dungeon actually looks, probably revealing an older design
- Shrine of Virtue interior
- Shrine of the Codex interior
- Lord British's mirror room
Offset | Length (in bytes) | Purpose |
---|---|---|
0x0 | 16 | Map Row 1 |
0x20 | 16 | Map Row 2 |
0x30 | 16 | Map Row 3 |
... | ||
0xA0 | 16 | Map Row 11 |
Offset | Length (in bytes) | Purpose |
---|---|---|
0x0 | 1 | Tile 1 |
0x1 | 1 | Tile 2 |
0x2 | 1 | Tile 3 |
... | ||
0xA | 1 | Tile 11 |
0xB | 5 | Zero Padding |
Intro Maps[edit]
- Earth bedroom
- Circle of stones
- Shadowlord encounter (not actually a place on the map)
- Iolo's Hut (slightly different from the in-game version)
Offset | Length (in bytes) | Purpose |
---|---|---|
0x0 | 32 | Map Row 1 |
0x20 | 32 | Map Row 2 |
0x40 | 32 | Map Row 3 |
0x60 | 32 | Map Row 4 |
Offset | Length (in bytes) | Purpose |
---|---|---|
0x0 | 1 | Tile 1 |
0x1 | 1 | Tile 2 |
0x2 | 1 | Tile 3 |
... | ||
0x12 | 1 | Tile 19 |
0x13 | 13 | Zero Padding |
Notes:
- The intro maps are stored in the order in which they appear during the introduction:
- "The Summoning"
- "The Journey"
- "The Arrival"
- "The Welcoming"
- the script data controls the movement of NPCs in the introduction
- TODO: battle screen descriptions, script format
SIGNS.DAT[edit]
This file contains the set of 33 (0x21) sign groups in this game. First the 16-bit offsets to each sign are stored; after that comes the data for each sign. Each offset represents 0 or more sign groups for a single location, with differing XY coordinates and floors.
signs.dat = set(0x21) of offset16, set(0x21) of sign_group
offset16 = uint16 sign_group = set of sign_data
sign_data = header4, set of sign_char, terminator
header4 = location, coord_Z, coord_X, coord_Y location, coord_Z, coord_X, coord_Y = uint8 sign_char = uint8 terminator = (uint8)
Offset | Length (in bytes) | Purpose |
---|---|---|
0x0 | 66 | 16-bit Offsets of each Sign |
0x42 | To End of File | Sign Data |
Offset | Length (in bytes) | Purpose |
---|---|---|
0x0 | 1 | Location |
0x1 | 1 | Z Coordinate |
0x2 | 1 | X Coordinate |
0x3 | 1 | Y Coordinate |
0x4 | varies | Sign text |
varies | 1 | terminator (0x0) |
Notes:
- offset16[i] points to the signs in location i. For locations without signs, the corresponding offset16 is 0. If you remove the zero values, you'll find that the remaining offset16's are sorted in ascending order.
- each sign starts with a 4-byte header, specifying location (shown below), z, x and y coordinates.
- the data between your current offset and proceeding offset will contain 1..N signs (sign group) separated by a single NULL (0) byte
- in some of the eight virtue towns, there are signs that refer to the laws - if there are two then one is defined by only a "\n", the second definition contains the strings.
Value | Location |
---|---|
0x00 | Britannia/Underworld |
0x01 | Moonglow |
0x02 | Britain |
0x03 | Jhelom |
0x04 | Yew |
0x05 | Minoc |
0x06 | Trinsic |
0x07 | Skara Brae |
0x08 | New Magincia |
0x09 | Fogsbane |
0x0A | Stormcrow |
0x0B | Greyhaven |
0x0C | Waveguide |
0x0D | Iolo's hut |
0x0E | Sutek's hut |
0x0F | Sin'Vraal's hut |
0x10 | Grendel’s hut |
0x11 | Lord British's Castle |
0x12 | Palace of Blackthorn |
0x13 | West Britanny |
0x14 | North Britanny |
0x15 | East Britanny |
0x16 | Paws |
0x17 | Cove |
0x18 | Buccaneer's Den |
0x19 | Ararat |
0x1A | Bordermarch |
0x1B | Farthing |
0x1C | Windemere |
0x1D | Stonegate |
0x1E | Lycaeum |
0x1F | Empath Abbey |
0x20 | Serpent's Hold |
Name | Value |
---|---|
0x00 | Britannia/Ground |
0x01 | First Floor |
0x02 | Second Floor |
0x03 | Third Floor |
0xFF | Basement/Underworld |
- The game may not support signs in dungeons.
- Signs can contain characters from both ibm.ch and runes.ch:
0 <= sign_char <= 0x7F --> runes.ch[sign_char] 0x80 <= sign_char <= 0xFF --> ibm.ch[sign_char - 0x80]
- If you want to review the plaintext string of a sign, simply subtract 128 (0x80) from any character > 127 (0x7F)
- The signs each have the lines denoted as lower case alphabet characters.
UNDER.DAT[edit]
The Underworld map
Its size is 256x256 tiles.
It is divided into 256 chunks. Each chunk has a size of 16x16 tiles, and each tile is stored as a uint8 (in Ultima IV, the chunk size was 32x32 tiles). Unlike BRIT.DAT, it is not compressed (no chunks were left out).
The chunks are stored from west to east, north to south, i.e. the first chunk in the map is the one in the northwest corner. The tiles in a chunk are also stored from west to east, north to south.
SHOPPE.DAT[edit]
Shoppe.dat is a fairly straight forward file. It is a list of null byte terminated strings that also use the same compressed word methods used with the NPC dialogue (as referenced in data.ovl position 0x104c).
Symbol | Meaning |
---|---|
% | how much gold thing thing will cost or sell for |
& | the current piece of equipment |
# | current business name |
$ | merchants name |
@ | barkeeps food/drink etc |
* | location of thing (ie, see so-and-so at "location") |
^ | quantity of thing (ie. reagent) |
*.NPC[edit]
Each file contains 4608 bytes.
There are of course : - CASTLE.NPC - DWELLING.NPC - KEEP.NPC - TOWNE.NPC
CASTLE.NPC[edit]
Todo.
DWELLING.NPC[edit]
Todo.
KEEP.NPC[edit]
Todo.
TOWNE.NPC[edit]
It is divided into 8 parts.
These files contain information about NPCs.
The general structure of the whole file is :
struct NPC_File { NPC_Info info[8]; // each NPC file has information for 8 maps };
For each city, we have an information entry for the Npcs of the map:
struct NPC_Info { NPC_Schedule schedule[32]; uint8 type[32]; // merchant, guard, etc. uint8 dialog_number[32]; };
The dialog number gives the entry index to the *.TLK file.
Finally, the schedule says how the Npc moves around in the city and especially when:
struct NPC_Schedule { uint8 AI_types[3]; uint8 x_coordinates[3]; uint8 y_coordinates[3]; sint8 z_coordinates[3]; uint8 times[4]; };
Notes:
1) All maps can hold a maximum of 31 (not 32) NPC's. In every map, schedule[0], type[0] and dialog_number[0] are not used. However, type[0] is sometimes 0 and sometimes 0x1C, so perhaps it has some unknown purpose.
2) Each NPC_Schedule contains information about 3 locations that the NPC will go to at different times of day. The x and y coordinates are between 0 and 31, because each map has a size of 32x32 tiles. The z coordinates represent the level, relative to level 0. 0xFF would make the NPC go to the level below level 0, while 0x1 would make the NPC go to the level above level 0.
The times are given in hours, so they range from 0 to 23.
times[0] --> NPC goes to location 0
times[1] --> NPC goes to location 1
times[2] --> NPC goes to location 2
times[3] --> NPC goes to location 1
Values for the dialog_number[edit]
Value | Meaning |
---|---|
0 | "No response" characters, including the guards who leave you alone |
>0 && < Nbr defined in the value of the TLK file | Defined by that talk information. Add 256 + dialog_number to get the first sprite. For example dialog_number=68 would be a bard because the bard sprite is 68+256=324. |
129 | Weapon dealer |
130 | Barkeeper |
131 | Horse seller |
132 | Ship seller |
133 | Magic seller |
134 | Guild Master |
135 | Healer |
136 | Innkeeper |
255 | Guards who will harass you |
*.OVL[edit]
Code or data overlays.
DATA.OVL[edit]
Here is the data layout for this file:
Mapping of Data.ovl
Offset | Length | Notes |
---|---|---|
0 | 0x18 | Unknown |
0x18 | 0x38 | Licence for the MS-Runtime |
0x52 | 0xa6 | Armour strings (13 of them) |
0xf8 | 0x81 | Weapon strings (10 of them) |
0x179 | 0x5a | Ring and amulet strings (5 of them) |
0x1d3 | 0x158 | Character type, monster names (44 of them) |
0x32b | 0x165 | Character type, monster names in capital letters (44 of them) |
0x490 | 0x33 | Abbreviated scroll names |
0x4c3 | 0x2b | Item names (5 of them) |
0x4ee | 0x18 | "(x" where x goes from 0 to 7 |
0x506 | 0x28 | Shard names (3 of them) |
0x52f | 0x43 | Additional item names (6 of them) |
0x572 | 0x11a | Shortened names (29 of them) |
0x68c | 0x30 | Potion colors (8 of them) |
0x6bc | 0x4d | Reagents (8 of them) |
0x709 | 0x1bb | Spell names |
0x8c4 | 0x54 | Character type and names (11 of them) |
0x918 | 0x29 | Health text (5 of them) |
0x941 | 0x64 | Spell runes (26 of them) |
0x9a5 | 0xa8 | Words of power for each spell, alphabetized (e.g., Kal Xen Corp is encoded as CKX; spells may be cast with the words in any order) |
0xa4d | 0x111 | City names (in caps) (26 of them) |
0xb5e | 0x3a | Dungeon names (8 of them) |
0xb98 | 0x48 | Virtue names (8 of them) |
0xbe0 | 0x1e | Virtue mantras (8 of them) |
0xbfe | 0x2fc | Store names |
0xefa | 0x152 | Barkeeper names |
0x104c | 0x24e | Compressed words used in the conversation files |
0x129a | 0x11c | Filenames |
0x13b6 | 0x3a6 | Unknown |
0x160c | 0x37 | Armour, weapon and scroll Attack values
See below for ordered list of armour, weapons and scrolls |
0x1644 | 0x2F | Armour and Weapon Defensive values
See below for ordered list of armour, weapons and scrolls |
0x1674 | 0x37 | Armour, weapon and scroll range values (ignore scrolls)
See below for ordered list of armour, weapons and scrolls |
0x1674 | 0x2F | Scroll range values (start at 0x30) |
0x175c | 0xa9 | Weapon strings (add + 0x10) |
0x1806 | 0x70 | Armor index (add + 0x10) |
0x187a | 0x1ee | Text index (add + 0x10) |
0x1e2a | 0x8 | Which Map index do we start in (for TOWNE.DAT) |
0x1e32 | 0x8 | Which Map index do we start in (for DWELLING.DAT) |
0x1e3a | 0x8 | Which Map index do we start in (for CASTLE.DAT) |
0x1e42 | 0x8 | Which Map index do we start in (for KEEP.DAT) |
0x1e4a | 0x1a (13 * 2) | Name of cities index (13 shorts, add 0x10) |
0x1e6e | 0x2c (22 * 2) | Name of dwellings/castle/keeps/dungeons index (22 shorts, add 0x10) |
0x1e9a | 0x28 | X-coordinates to Towns, Dwellings, Castles, Keeps, Dungeons |
0x1ec2 | 0x28 | Y-coordinates to Towns, Dwellings, Castles, Keeps, Dungeons |
0x1f5e | 0x20 | Virtue and mantra index (add + 0x10) |
0x1f7e | 0x33b | Unknown |
0x22da | 0x12 | Arms seller's name index |
0x22ec | 0x20c | Unknown |
0x22da | 0x12 | Arms seller's name index |
0x24f8 | 0x13e | Indexes to the dialog text (add + 0x10) (see .TLK) |
0x2636 | 0x2b | .DAT file names (4 files) |
0x2661 | 0x9 | Unknown |
0x266a | 0x269 | Text strings (some unknown in the middle) |
0x28d3 | 0x83 | Unknown |
0x23ea | 0x09 | Shoppe Keeper – Towne indexes that have a tavern |
0x23fa | 0x04 | Shoppe Keeper – Towne indexes that sell horses |
0x240a | 0x04 | Shoppe Keeper – Towne indexes that sell ships |
0x241a | 0x05 | Shoppe Keeper – Towne indexes that sell reagents |
0x242a | 0x03 | Shoppe Keeper – Towne indexes that sell provisions (Guild) |
0x243a | 0x07 | Shoppe Keeper – Towne indexes that sell healing |
0x244a | 0x06 | Shoppe Keeper – Towne indexes that have an inn |
0x2df4 | 0x14d | Unknown |
0x2f41 | 0x5b | Initial string |
0x2f9d | 0xa | STORY.DAT string |
0x2fa7 | 0x175 | Unknown |
0x311c | 0x76 | Menu texts (6 texts) |
0x3192 | 0x22 | ibm.hcs, rune.hcs, ibm.ch, runes.ch strings |
0x31b4 | 0x42 | Random texts |
0x31f6 | 0xa | SAVED.GAM string |
0x3202 | 0x462 | Random texts |
0x3664 | 0x2a | Unknown |
0x3683 | 0x100 | Bitmap of which of the first 256 tiles an NPC will walk on (i.e., which things are solid, though there are some surprises in here) |
0x3783 | 0x103 | Unknown |
0x3886 | 0x100 | Chunking information for Britannia's map, 0xFF the chunk only consists of tile 0x1, otherwise see BRIT.DAT |
0x3986 | 0xaf | Random filenames, texts and unknown |
0x3a35 | 0xd | Unknown |
0x3a42 | 0x28 | Reagent base prices (towne by towne) |
0x3a6a | 0x28 | Reagent quantities (towne by towne) |
0x3a92 | 0x60 (UINT16) | Armour/Weapons/Rings base prices
See Ordered list of Armour, Weapons and Scrolls |
0x3af2 | 0x48 (9 groups of 8 bytes) | What weapons are sold by the merchant in cities: Britain, Jhelom, Yew, Minoc, Trinsic, British Castle, Buccaneer's Den, Bordermarch, Serpent’s Hold |
0x3b3a | 0x38 | Unknown |
0x3b72 | 0x8 | Innkeeper welcome text index into SHOPPE.DAT (+0x0, 2 bytes for each index) |
0x41e4 | 0x8c1 | Random texts |
0x4aa5 | 0x2f2 | Unknown |
0x4d97 | 0x361 | Random texts |
0x4e7e | 0xc | Inn room description text |
0x4e8a | 0x5 | Inn bed X-coordinate |
0x4e90 | 0x5 | Inn bed Y-coordinate |
The old list is here for the moment:
offset length purpose // monster flags 0x154C 0x30*2 flags that define the special abilities of monsters during combat; 16 bits per monster 0x0020 = undead (affected by An Xen Corp) todo: - passes through walls (ghost, Shadowlord) - can become invisible (wisp, ghost, Shadowlord) - can teleport (wisp, shadowlord) - can't move (reaper, mimic) - able to camouflage itself - may divide when hit (slime, Stone gargoyles) // moon phases 0x1EEA 28*2 moon phases (28 byte pairs, one for each day of the month) // shrines and mantras 0x1F7E 8 x coordinates of shrines 0x1F86 8 y coordinates of shrines // this section contains information about hidden, non-regenerating objects that you can search for // (e.g. the magic axe in the dead tree in Jhelom); there are 0x71 such objects; the last entry // in each table is 0. 0x3E88 0x72 tile to draw when found (beginning at 0x100 in the tile table, the one that looks like a circle of dots) 0x3EFA 0x72 quality (number of gems/torches, or item number for single-quantity tiles) 0x3F6C 0x72 location number (see "Party Location") 0x3FDE 0x72 z coordinate 0x4050 0x72 x coordinate 0x40C2 0x72 y coordinate 0x4513 0x8 Sprite indexes of dungeons after word of power has opened them // dock coordinates (where purchased ships/skiffs are placed) // 0 = Jhelom // 1 = Minoc // 2 = East Brittany // 3 = Buccaneer's Den 0x4D86 0x4 x coordinate 0x4D8A 0x4 y coordinate // scan code translation table: // when the player presses a key that produces one of the scan codes in // the first table, the game translates it to the corresponding code in // the second table 0x541E 8 scancodes 0x5426 8 internal codes // wells 0x7252 0x32 wishing for one of these keywords at a wishing well gets you a horse
The other OVL[edit]
The other OVL files, as far as we can tell are actually binary files containing code. The base executable actually loads these up on a need to execute basis.
*.TLK[edit]
These files contain conversation scripts. Here is the transcript for Ultima V. There are 4 files for each group of Maps :
FileName | Size (in bytes) |
---|---|
CASTLE.TLK | 21868 |
DWELLING.TLK | 7979 |
KEEP.TLK | 17947 |
TOWNE.TLK | 26835 |
The format for each of these files is:
Full file | |||
---|---|---|---|
Number of entries into the set of script indices | Set of script index | Script data | |
uint16 | Npc index | Offset | Set of uint8 filling the file |
uint16 | uint16 |
Notes:
1) The first NPC number is 1.
2) The script_indexes are sorted by NPC number, in ascending order.
3) The script_data blocks are sorted by NPC number, in ascending order.
4) The conversations appear to be scripted, like the ones in Ultima VI.
The way this is linked together is via the NPC information since it gives us the dialogue index which links itself to the script index.
The text encoding[edit]
For each NPC, there are a certain number of '\0' terminated strings which are encodings of what is the name, job, etc. of the NPC. To decode these texts, I've taken Nodling's decoder and tweaked it a bit.
First part: fixed entries[edit]
For each NPC, it starts with a certain number of fixed entries:
- Name, Description, Greeting, Job, Bye
Second part: key words[edit]
We specify it by:
<Key word> (Therefore text only) [<OR character code (see below)> <0 set byte> <Key word> [<OR character code> <0 set byte> <Key word>]...] <Answer text> (Potentially anything
Third part : labels[edit]
Then it's question/answers with labels.
Todo
Generalities[edit]
For the moment, for each entry, I do :
if((c >= 160) && (c < 255)) { c -= 128; } else { special = true; }
If it's a special case, then we have two cases : it's a code based symbol, it's an entry to an array of texts from DATA.OVL (the offset table starts at 0x24f8).
For the moment, I've confirmed these bindings :
Symbol value | Meaning |
---|---|
c < 129 | entry to the offset table |
129 | Insert Avatar’s name |
131 | Conversation pause |
135 | Or in the key words |
136 | Ask for avatar's name |
140 | If/Else the NPC knows the Avatar's name |
141 | New line |
143 | Key wait |
145 ~ 155 | Labels 1 to 10 |
If it's not a special case, then I just copy the character in the string.
General Notes[edit]
1) Wishing Wells
There are two wishing wells in the game: - Paws (location 0x16) - Empath Abbey (location 0x1F)
These locations are hard-coded into the game. There is no difference between horses from wishing wells and horses from vendors. It also doesn't make any difference if you wish for "horse" or a car brand.
EGA.DRV[edit]
See u5_ega_drv.txt
INIT.GAM[edit]
Initial "SAVED.GAM".
SAVED.GAM and RAM[edit]
Ultima V (PC version) SAVED.GAM
This file contains the current saved game, which is just a copy of the game's working RAM up to a certain point (there's no need to waste disk space saving, say, the in-memory copy of the current map, since that will just be loaded from the read-only file on demand anyway).
When you start a new game, "SAVED.GAM" is initialized from "INIT.GAM".
Beginning with the leather helm, item numbers are marked below. For instance, "0. Leather helm" means it's Item 0. These numbers are used in the *.TLK files in situations where an NPC gives the party an item, to indicate which item it is. They're also the order items show up in the party inventory listing.
Offset | Length (in bytes) | Range | Purpose |
---|---|---|---|
0x0 | 2 | ? | ? |
0x2 | 32 | n/a | character record 1 (Avatar) |
0x22 | 32 | n/a | character record 2 |
0x42 | 32 | n/a | character record 3 |
0x62 | 32 | n/a | character record 4 |
0x82 | 32 | n/a | character record 5 |
0xA2 | 32 | n/a | character record 6 |
0xC2 | 32 | n/a | character record 7 |
0xE2 | 32 | n/a | character record 8 |
0x102 | 32 | n/a | character record 9 |
0x122 | 32 | n/a | character record 10 |
0x142 | 32 | n/a | character record 11 |
0x162 | 32 | n/a | character record 12 |
0x182 | 32 | n/a | character record 13 |
0x1A2 | 32 | n/a | character record 14 |
0x1C2 | 32 | n/a | character record 15 |
0x1E2 | 32 | n/a | character record 16 |
0x202 | 2 | 0-9999 | food |
0x204 | 2 | 0-9999 | gold |
0x206 | 1 | 0-99 | keys |
0x207 | 1 | 0-99 | gems |
0x208 | 1 | 0-99 | torches |
0x209 | 1 | 0,0xFF | grapple |
0x20A | 1 | 0-99 | magic carpets |
0x20B | 1 | 0-99 | skull keys |
0x20C | 1 | 1-28 | Last day Minoc skull keys were taken |
0x20D | 1 | 0,0xFF | Amulet of Lord British |
0x20E | 1 | 0,0xFF | Crown of Lord British |
0x20F | 1 | 0,0xFF | Sceptre of Lord British |
0x210 | 1 | 0,0xFF | Shard of Falsehood |
0x211 | 1 | 0,0xFF | Shard of Hatred |
0x212 | 1 | 0,0xFF | Shard of Cowardice |
0x213 | 1 | ? | ? |
0x214 | 1 | 0-99 | spy glasses |
0x215 | 1 | 0,0xFF | HMS Cape plans |
0x216 | 1 | 0-99 | Sextants |
0x217 | 1 | 0,0xFF | Pocket watch |
0x218 | 1 | 0,0xFF | Black badge |
0x219 | 1 | 0,0xFF | Sandalwood box |
0x21A | 1 | 0-99 | 0. Leather helm |
0x21B | 1 | 0-99 | 1. Chain coif |
0x21C | 1 | 0-99 | 2. Iron helm |
0x21D | 1 | 0-99 | 3. Spiked helm |
0x21E | 1 | 0-99 | 4. Small shield |
0x21F | 1 | 0-99 | 5. Large Shield |
0x220 | 1 | 0-99 | 6. Spiked Shield |
0x221 | 1 | 0-99 | 7. Magic Shield |
0x222 | 1 | 0-99 | 8. Jewelled Shield |
0x223 | 1 | 0-99 | 9. Cloth |
0x224 | 1 | 0-99 | 10. Leather |
0x225 | 1 | 0-99 | 11. Ring mail |
0x226 | 1 | 0-99 | 12. Scale mail |
0x227 | 1 | 0-99 | 13. Chain mail |
0x228 | 1 | 0-99 | 14. Plate mail |
0x229 | 1 | 0-99 | 15. Mystic Armour |
0x22A | 1 | 0-99 | 16. Dagger |
0x22B | 1 | 0-99 | 17. Sling |
0x22C | 1 | 0-99 | 18. Club |
0x22D | 1 | 0-99 | 19. Flaming oil |
0x22E | 1 | 0-99 | 20. Main gauche |
0x22F | 1 | 0-99 | 21. Spear |
0x230 | 1 | 0-99 | 22. Throwing axe |
0x231 | 1 | 0-99 | 23. Short sword |
0x232 | 1 | 0-99 | 24. Mace |
0x233 | 1 | 0-99 | 25. Morning star |
0x234 | 1 | 0-99 | 26. Bow |
0x235 | 1 | 0-99 | 27. Arrows |
0x236 | 1 | 0-99 | 28. Crossbow |
0x237 | 1 | 0-99 | 29. Quarrels |
0x238 | 1 | 0-99 | 30. Long sword |
0x239 | 1 | 0-99 | 31. 2-H hammer |
0x23A | 1 | 0-99 | 32. 2-H axe |
0x23B | 1 | 0-99 | 33. 2-H sword |
0x23C | 1 | 0-99 | 34. Halberd |
0x23D | 1 | 0-99 | 35. Chaos sword |
0x23E | 1 | 0-99 | 36. Magic bow |
0x23F | 1 | 0-99 | 37. Silver sword |
0x240 | 1 | 0-99 | 38. Magic Axe |
0x241 | 1 | 0-99 | 39. Glass sword |
0x242 | 1 | 0-99 | 40. Jeweled sword |
0x243 | 1 | 0-99 | 41. Mystic sword |
0x244 | 1 | 0-99 | 42. Invisibility Ring |
0x245 | 1 | 0-99 | 43. Protection Ring |
0x246 | 1 | 0-99 | 44. Regeneration Ring |
0x247 | 1 | 0-99 | 45. Amulet of Turning |
0x248 | 1 | 0-99 | 46. Spiked collar |
0x249 | 1 | 0-99 | 47. Ankh |
0x24A | 1 | 0-99 | 48. mixed In Lor |
0x24B | 1 | 0-99 | 49. mixed Grav Por |
0x24C | 1 | 0-99 | 50. mixed An Zu |
0x24D | 1 | 0-99 | 51. mixed An Nox |
0x24E | 1 | 0-99 | 52. mixed Mani |
0x24F | 1 | 0-99 | 53. mixed An Ylem |
0x250 | 1 | 0-99 | 54. mixed An Sanct |
0x251 | 1 | 0-99 | 55. mixed An Xen Corp |
0x252 | 1 | 0-99 | 56. mixed Rel Hur |
0x253 | 1 | 0-99 | 57. mixed In Wis |
0x254 | 1 | 0-99 | 58. mixed Kal Xen |
0x255 | 1 | 0-99 | 59. mixed In Xen Mani |
0x256 | 1 | 0-99 | 60. mixed Vas Lor |
0x257 | 1 | 0-99 | 61. mixed Vas Flam |
0x258 | 1 | 0-99 | 62. mixed In Flam Grav |
0x259 | 1 | 0-99 | 63. mixed In Nox Grav |
0x25A | 1 | 0-99 | 64. mixed In Zu Grav |
0x25B | 1 | 0-99 | 65. mixed In Por |
0x25C | 1 | 0-99 | 66. mixed An Grav |
0x25D | 1 | 0-99 | 67. mixed In Sanct |
0x25E | 1 | 0-99 | 68. mixed In Sanct Grav |
0x25F | 1 | 0-99 | 69. mixed Uus Por |
0x260 | 1 | 0-99 | 70. mixed Des Por |
0x261 | 1 | 0-99 | 71. mixed Wis Quas |
0x262 | 1 | 0-99 | 72. mixed In Bet Xen |
0x263 | 1 | 0-99 | 73. mixed An Ex Por |
0x264 | 1 | 0-99 | 74. mixed In Ex Por |
0x265 | 1 | 0-99 | 75. mixed Vas Mani |
0x266 | 1 | 0-99 | 76. mixed In Zu |
0x267 | 1 | 0-99 | 77. mixed Rel Tym |
0x268 | 1 | 0-99 | 78. mixed In Vas Por Ylem |
0x269 | 1 | 0-99 | 79. mixed Quas An Wis |
0x26A | 1 | 0-99 | 80. mixed In An |
0x26B | 1 | 0-99 | 81. mixed Wis An Ylem |
0x26C | 1 | 0-99 | 82. mixed An Xen Ex |
0x26D | 1 | 0-99 | 83. mixed Rel Xen Bet |
0x26E | 1 | 0-99 | 84. mixed Sanct Lor |
0x26F | 1 | 0-99 | 85. mixed Xen Corp |
0x270 | 1 | 0-99 | 86. mixed In Quas Xen |
0x271 | 1 | 0-99 | 87. mixed In Quas Wis |
0x272 | 1 | 0-99 | 88. mixed In Nox Hur |
0x273 | 1 | 0-99 | 89. mixed In Quas Corp |
0x274 | 1 | 0-99 | 90. mixed In Mani Corp |
0x275 | 1 | 0-99 | 91. mixed Kal Xen Corp |
0x276 | 1 | 0-99 | 92. mixed In Vas Grav Corp |
0x277 | 1 | 0-99 | 93. mixed In Flam Hur |
0x278 | 1 | 0-99 | 94. mixed Vas Rel Por |
0x279 | 1 | 0-99 | 95. mixed An Tym |
0x27A | 1 | 0-99 | 96. Vas Lor (scroll) |
0x27B | 1 | 0-99 | 97. Rel Hur (scroll) |
0x27C | 1 | 0-99 | 98. In Sanct (scroll) |
0x27D | 1 | 0-99 | 99. In An (scroll) |
0x27E | 1 | 0-99 | 100. In Quas Wis (scroll) |
0x27F | 1 | 0-99 | 101. Kal Xen Corp (scroll) |
0x280 | 1 | 0-99 | 102. In Mani Corp (scroll) |
0x281 | 1 | 0-99 | 103. An Tym (scroll) |
0x282 | 1 | 0-99 | 104. Blue potion |
0x283 | 1 | 0-99 | 105. Yellow potion |
0x284 | 1 | 0-99 | 106. Red potion |
0x285 | 1 | 0-99 | 107. Green potion |
0x286 | 1 | 0-99 | 108. Orange potion |
0x287 | 1 | 0-99 | 109. Purple potion |
0x288 | 1 | 0-99 | 110. Black potion |
0x289 | 1 | 0-99 | 111. White potion |
0x28A | 8 | n/a | 0-0xFF Moonstone X-coordinates (valid only if buried) |
0x292 | 8 | n/a | 0-0xFF Moonstone Y-coordinates (valid only if buried) |
0x29A | 8 | n/a | 0=buried,0xFF=Inventory moonstone flags |
0x2A2 | 8 | n/a | 0=Britannia,0xFF=Underworld moonstone Z-coordinates (valid only if buried) |
0x2AA | 1 | 0-99 | 144. Sulphurous ash |
0x2AB | 1 | 0-99 | 145. Ginseng |
0x2AC | 1 | 0-99 | 146. Garlic |
0x2AD | 1 | 0-99 | 147. Spider silk |
0x2AE | 1 | 0-99 | 148. Blood moss |
0x2AF | 1 | 0-99 | 149. Black pearl |
0x2B0 | 1 | 0-99 | 150. Nightshade |
0x2B1 | 1 | 0-99 | 151. Mandrake root |
0x2B2 | 3 | ? | Day each of the three nightshade/mandrake spots was last harvested |
0x2B5 | 1 | 1-6 | # Party members |
0x2B6 | 0xF | n/a | Non-regenerating object flags[1] |
0x2C5 | 1 | ? | ? |
0x2C6 | 1 | ? | ? |
0x2C7 | 1 | ? | ? |
0x2C8 | 1 | ? | ? |
0x2C9 | 1 | ? | ? |
0x2CA | 1 | ? | ? |
0x2CB | 1 | ? | ? |
0x2CC | 1 | ? | ? |
0x2CD | 1 | ? | ? |
0x2CE | 2 | 1-? | Current year |
0x2D0 | 2 | 0-? | # of active monsters & charmed PCs[2] |
0x2D2 | 2 | 0-? | # of active PCs and charmed monsters[2] |
0x2D4 | 1 | n/a | Icon shown between stats window and the food/gold/date window (from one of the *.CH files) |
0x2D5 | 1 | 0-5,0xFF=None | Active character |
0x2D6 | 1 | n/a | Mode of transportation (foot, ship, skiff, horse, carpet) [3] |
0x2D7 | 1 | 1-13 | Current month |
0x2D8 | 1 | 1-28 | Current day |
0x2D9 | 1 | 0-23 | Current hour |
0x2DA | 1 | 0-23 | copy of 0x2D9 |
0x2DB | 1 | 0-59 | Current minute |
0x2DC | 1 | ? | ? |
0x2DD | 1 | ? | ? |
0x2DE | 1 | ? | ? |
0x2DF | 1 | 0x30-0x37 | Phase of Trammel [4] |
0x2E0 | 1 | 0x30-0x37 | Phase of Felucca [5] |
0x2E1 | 1 | 0-0x10 | Current moongate height (in pixels) [6] |
0x2E2 | 1 | 0-255 | Karma |
0x2E3 | 1 | ? | ? |
0x2E4 | 1 | ? | ? |
0x2E5 | 1 | 0-0xFF | # of turns since game began of (stops at 0xFF) |
0x2E6 | 1 | 0-0xE | # of hours until party heals again via camping [7] |
0x2E7 | 1 | ? | ? |
0x2E8 | 1 | n/a | Protective spell duration [8] |
0x2E9 | 1 | ? | ? |
0x2EA | 1 | ? | ? |
0x2EB | 1 | 0,1,0xFF | Animations during next frame [9] |
0x2EC | 1 | 0-4 | Wind direction (0=calm, 1=N, 2=S, 3=E, 4=W) |
0x2ED | 1 | s.b. | Current party location |
0x2EE | 1 | s.b. | Combat backup of 0x2ED |
0x2EF | 1 | 0xFF,0-7 | Z-coordinate of party [10] |
0x2F0 | 1 | 0xFF] | X-coordinate of party |
0x2F1 | 1 | 0xFF] | Y-coordinate of party |
0x2F2 | 1 | 0=hidden,1=visible | Crosshair visibility (combat only, 0=hidden, 1=visible) |
0x2F3 | 1 | 0-0xA | X-coord of crosshair |
0x2F4 | 1 | 0-0xA | Y-coord of crosshair |
0x2F5 | 1 | 0-0xF0 | X-coord of upper left chunk [11] |
0x2F6 | 1 | 0-0xF0 | Y-coord of upper left chunk |
0x2F7 | 1 | 0-? | Attacker's weapon [12] |
0x2F8 | 1 | ? | ? |
0x2F9 | 1 | 0=hidden,1=visible | Visibility state of focus rectangle & crosshair |
0x2FA | 1 | 0-6 | Exit direction from combat map 0=None,1=W,2=E,3=N,4=S,5=U,6=D |
0x2FB | 1 | s.d. | Combat type flags [13] |
0x2FC | 1 | ? | ? |
0x2FD | 1 | 0,1 | "No more enemies" flag (whether or not Esc leaves combat) |
0x2FE | 1 | 0,1 | Update/animate 2-D map? [14] |
0x2FF | 1 | 0-? | Current light intensity |
0x300 | 1 | 0-0xFF | Remaining light spell duration (in turns) [15] |
0x301 | 1 | 0-0xF0 | Remaining rorch duration (in turns) [15] |
0x302 | 0x20 | (1 per creature) | n/a Monster interference table [16] |
0x322 | 1 | 0-8,0xFF | Location of the Shadowlord of Falsehood [17] |
0x323 | 1 | 0-8,0xFF | Location of the Shadowlord of Hatred ([17] |
0x324 | 1 | 0-8,0xFF | Location of the Shadowlord of Cowardice [17] |
0x325 | 1 | ? | ? |
0x326 | 1 | 0-0xFF |
This is set when you first chant the mantra at the shrine. |
0x327 | 1 | ? | ? |
0x328 | 1 | 0-0xFF | Completed Shrine quests. The bits map to shrines similar to 0x326. |
0x329 | 1 | ? | ? |
0x32A | 8 | n/a |
|
0x332 | 8 | n/a |
|
0x33A | 0xE | n/a |
dungeon room cleared flags (7 dungeons, 2 bytes per dungeon) when you kill all monsters in a dungeon room, two things happen:
Note: there are no flags for Doom, because you can't leave Doom (except by winning the game) |
0x348 | 0x20 | n/a | X-coordinates of annotations |
0x368 | 0x20 | n/a | Y-coordinates of annotations |
0x388 | 0x20 | n/a | Annotation tiles |
0x3A8 | 1 | 0-0x20 | Number of entries in the annotation
table (see below) |
0x3A9 | 1 | s.d. | When you open a door, the game stores door tile in this byte. Only onedoor can be open at any time. |
0x3AA | 1 | 0-0x1F | X-coord of open door |
0x3AB | 1 | 0-0x1F | Y-coord of open door |
0x3AC | 1 | 0-FF | Number of turns the door stays open. Decremented every turn, wraps aroundto 0xFF. |
0x3AD | 1 | 0-0xFF | X-coord of purchased ship (see 0x105F) |
0x3AE | 1 | 0-0xFF | Y-coord of purchased ship (see 0x105F) |
0x3AF | 1 | 0-4 |
|
0x3B0 | 1 | 0,1 |
|
0x3B1 | 1 | 0-0x19 | Number of drunken moves until you can move normally again; set to 0x19 when you get drunk |
0x3B2 | 1 | ? | ? |
0x3B3 | 1 | ? | ? |
0x3B4 | 0x200 | n/a | Map of the current dungeon 8 levels, 8x8 tiles per level |
0x5B4 | 0x80 | n/a |
|
0x634 | 0x80 | n/a |
Note: ("met" means that the NPC has asked the Avatar's name and received a truthful answer) |
0x6B4 | 0x100 | n/a | Monster table (has 0x20 slots)
monster format: see below |
0x7B4 | 4 | ? | ? |
0x7B8 | 0x200 | n/a | NPC schedules
See *.NPC in u5tech.txt (used only in settlements) |
0x9B8 | 0x200 | 0x20 * 0x10 | Character/monster states (32 of them, each 16 bytes; see below) |
0xBB8 | 0x400 | n/a | Movement list table (see below) |
0xFB8 | 0x40 | n/a | Movement list pointers (see below) |
0xFF8 | 0x20 | n/a | NPC types. These are the sprite numbers for the NPCs on the current map (must add 0x100 because they are in bytes, but extend to top half of sprite grid)
(See *.NPC in u5tech.txt (used only in settlements) |
0x1018 | 0x44 | ? | ? |
0x105C | 1 | ? | Copy of 0x105D? |
0x105D | 1 | 0-3 |
|
0x105E | 1 | 1-3 |
|
0x105F | 1 | s.d. |
When you buy a ship or skiff, the game encodes your purchase in this byte: 0x40 = skiff n = frigate with (n-0x80) skiffs on board, n >= 0x80 when you leave the settlement where you bought the vessel, the game creates it at the coordinates stored in 0x3AD and 0x3AF |
Beyond this point is data that is only kept in RAM and is not included in the save file.
Offset | Length (in bytes) | Range | Purpose |
---|---|---|---|
0x1060 | 2 | ? | ? |
0x1062 | 0x400 | 0-0xFF | 32x32 grid of the current map's ground tiles |
Notes:
NoteNum | Note |
---|---|
[1] |
|
[2] |
|
[3] | Add 0x100 to get the real tile |
[4] | If the hour is 0-4, this byte determines where moongates take the party. |
[5] | If the hour is 20-23, this byte determines where moongates take the party. |
[6] | |
[7] | This is set to 0xE when the party gets healed by camping; it is decremented every full hour.
If this byte is 0 at the end of your camping rest, the party gets healed, but only if you rested for 6-9 hours; camping for 1-5 hours never heals the party |
[8] |
|
[9] |
|
[10] |
|
[11] | |
[12] | (combat only)
When a PC attacks a monster during combat, the game stores the attack method in this byte. The attack method can be a weapon or a spell. |
[13] | |
[14] |
Ignored in dungeons. Set to 1 when you enter or leave a settlement. I don't know if the game ever sets it to 0. |
[15] |
In Lor spell, borrowed torch = 0x64 Vas Lor spell = 0xFF Vas Lor scroll, ignited torch = 0xF0 |
[16] | 0xFF = no monster interferes with this creature else = index of the monster that interferes with this creature |
[17] |
|
[18] |
|
--- Movement Lists ---
When it's time for an NPC to move to a new location (as dictated by his schedule), the game calculates a path to the new location and stores this path in the NPC's movement list.
The movement lists are stored at 0xBB8. There are 0x20 lists (one for eachNPC). Each list can store up to 0x10 movement commands.
The movement commands are made up of two bytes: the number of repetitions and the direction.
struct Movement_List_Table { Movement_List mov_lists[0x20]; } struct Movement_List { Movement_Command mov_commands[0x10]; } struct Movement_Command { uint8 repeats; // 1 = east // 2 = north // 3 = west // 4 = south uint8 direction; }
The table at 0xFB8 contains 0x20 word offsets (one for each NPC). Entries can have the following values:
- 0xFFFF = movement list for the NPC is empty
- else = offset into the NPC's movement list (must be a multiple of 2)
If the NPC hasn't reached his destination after going through the movement commands, the game calculates a new path and stores it in the NPC's movement list.
Notes:
- There are no up/down movement commands. When an NPC wants to move to a location on another level, he goes to the nearest stair/ladder and then teleports to his destination.
----Character/Monster States---
offset | Description |
---|---|
0 | ? |
2 | Current position - x |
4 | Current position - y |
6 | Current position - z (floor) |
8 | Tile reference number (add 0x100) |
10 | ? |
12 | Character animation state index |
14 | (?) if > 0, then the character is active on the map |
Note: referenced in MapCharacterState.cs
--- Monster Format ---
offset | length | purpose |
---|---|---|
0 | 1 | Tile (always the first of an animated group regardless of animation frame) |
1 | 1 | Tile of current animation frame |
2 | 1 | X-coordinate |
3 | 1 | Y-coordinate |
4 | 1 | Z-coordinate (level) |
5 | 1 | Value 1; nonzero seems to correspond to item numbers (e.g., amulet is 243) |
6 | 1 | Value 2; nonzero seems to correspond with literal monsters |
7 | 1 | Value 3 |
Notes:
- The monster table contains not only monsters, but also inanimate objects (e.g. empty ships) and the party.
- The party is always in slot 0.
- Non-empty entries don't have to be contiguous.
- For frigates, Value 1 is their hull strength and Value 3 is the number of skiffs on board.
- Value 2 might be commonly used as a bitmap; common values include 0, 16, 32, 48, 64, and 80, corresponding to the bits 0xxx0000. It also seems to change even when the player is not doing anything, so it might have to do with animations.
Todo: empty entries, object-specific fields
--- Character record format ---
Offset | Length | Purpose | Range |
---|---|---|---|
0 | 9 | Character name | Zero-terminated string (length = 8+1) |
9 | 1 | Gender |
|
0xA | 1 | class | |
0xB | 1 | Status | 'G'ood, etc. |
0xC | 1 | Strength | 1-50 |
0xD | 1 | Dexterity | 1-50 |
0xE | 1 | Intelligence | 1-50 |
0xF | 1 | Current MP | 0-50 |
0x10 | 2 | Current HP | 1-240 |
0x12 | 2 | Maximum HP | 1-240 |
0x14 | 2 | Exp points | 0-9999 |
0x16 | 1 | Level | 1-8 |
0x17 | 1 | Months at inn | 0-25 (updated when month rolls; capped at 25) |
0x18 | 1 | ? | Seems to always be set to 7, even in INIT.GAM |
0x19 | 1 | Helmet | 0-0x2F,0xFF |
0x1A | 1 | Armor | 0-0x2F,0xFF |
0x1B | 1 | Weapon or shield (left hand) | 0-0x2F,0xFF |
0x1C | 1 | Weapon or shield (right hand) | 0-0x2F,0xFF |
0x1D | 1 | Ring | 0-0x2F,0xFF |
0x1E | 1 | Amulet | 0-0x2F,0xFF |
0x1F | 1 | Inn/party | n/a |
Notes:
- If the character is staying at an inn, the byte at offset 0x1F contains the settlement number (see "Party Location") of the inn.
- If the character is in the party, it contains 0.
- If the character hasn't joined the party yet, it contains 0xFF.
- If the character has been permanently killed, it contains 0x7F.
--- Party Location ---
index | Location |
---|---|
0x0 | Britannia/Underworld |
0x1 | Moonglow |
0x2 | Britain |
0x3 | Jhelom |
0x4 | Yew |
0x5 | Minoc |
0x6 | Trinsic |
0x7 | Skara Brae |
0x8 | New Magincia |
0x9 | Fogsbane |
0xA | Stormcrow |
0xB | Greyhaven |
0xC | Waveguide |
0xD | Iolo's hut |
0xE | Sutek's hut |
0xF | Sin'Vraal's hut |
0x10 | Grendel's hut |
0x11 | Castle British |
0x12 | Castle Blackthorn |
0x13 | West Britanny |
0x14 | North Britanny |
0x15 | East Britanny |
0x16 | Paws |
0x17 | Cove |
0x18 | Buccaneer's Den |
0x19 | Ararat |
0x1A | Bordermarch |
0x1B | Farthing |
0x1C | Windemere |
0x1D | Stonegate |
0x1E | The Lycaeum |
0x1F | Empath Abbey |
0x20 | Serpent's Hold |
0x21 | Deceit |
0x22 | Despise |
0x23 | Destard |
0x24 | Wrong |
0x25 | Covetous |
0x26 | Shame |
0x27 | Hythloth |
0x28 | Doom |
0xFF | Combat/resting/shrine |
Sources[edit]
Nytegard <email: append "at yahoo dot com" to his nick>
http://nodling.nullneuron.net/nytegard/nytegard.html
http://nodling.nullneuron.net/ultima/ultima.html
http://martin.brenner.de/ultima/u5save.html
http://www.cosy.sbg.ac.at/~lendl/ultima/ultima5/ on the Internet Archive
http://www.wi.leidenuniv.nl/~psimoons/ultima5t.htm on the Internet Archive
Sheng Long Gradilla <email: replace the two spaces in his name with dots and append "at gmail dot com">
Brad Hannah <email: wellthisisfunsoftware at gmail dot com>
Technical Details | |
---|---|
Game | Ultima III ☥ Ultima IV ☥ Ultima V ☥ Ultima VI ☥ Ultima VII ☥ Ultima VIII ☥ Ultima IX ☥ Ultima Underworld |