Ultima 3 File Structures ======================== Last updated on 20-March-2004. Please send additions, corrections and feedback to this e-Mail address: Remove space + vowels from "marc winterrowd" and append "at yahoo dot com" SHAPES.ULT ---------- This file contains 0x50 tiles. All tiles are 16*16 pixels. Each tile in stored in CGA-compatible format. The first 0x20 bytes of each tile contain the first bit plane, the following 0x20 bytes contain the second bit plane. offset length purpose 0x0 0x40 tile 0x0 0x40 0x40 tile 0x1 0x80 0x40 tile 0x2 ... 0x13C0 0x40 tile 0x4f CHARSET.ULT ----------- This file contains the 0x80 characters that make up the U3 font. All characters are 8*8 pixels. Each character in stored in CGA-compatible format. The first 0x8 bytes of each character contain the first bit plane, the following 0x8 bytes contain the second bit plane. offset length purpose 0x0 0x10 character 0x0 0x10 0x10 character 0x1 ... 0x7F0 0x10 character 0x7F SOSARIA.ULT ----------- This file contains the world map and information about the game world state. offset length purpose 0x0 0x1000 64*64 world map 0x1000 0x180 not used 0x1180 0x20 tile number of monster 1-32; divide by 4 to get real tile number 0x11A0 0x20 tile number of tile under monster 1-32; divide by 4 to get real tile number 0x11C0 0x20 x coordinate of monster 1-32 0x11E0 0x20 y coordinate of monster 1-32 0x1200 0x20 movement flag of monster 1-32 0x1220 0x1 x coordinate of whirlpool 0x1221 0x1 y coordinate of whirlpool 0x1222 0x1 signed byte to add to x coordinate of whirlpool; possible values: 0, 1, 0xFF 0x1223 0x1 signed byte to add to y coordinate of whirlpool; possible values: 0, 1, 0xFF 0x1224 0x1 current phase of left moon; ranges from 0-7 0x1225 0x1 current phase of right moon; ranges from 0-7 0x1226 0x1 current sub-phase of left moon; ranges from 0-0xB 0x1227 0x1 current sub-phase of right moon; ranges from 0-3 Monsters, horses, ships, chests: U3 stores the location of these objects by writing them directly into the map. 1) Monsters Monsters are stored as base_tile*4. The map tile under the monster is stored in the table at 0x11A0. 2) Horses Horses are stored as 0x28 == horse_tile*4. The tile under the horse can only be 0x1, because you can only dismount a horse on a grass tile. 3) Ships Ships are stored as 0x2C == ship_tile*4. The tile under the ship can only be 0x0. 4) Chests The map tile under the chest is encoded in the lowest 2 bits of the tile: 0x24 == chest_tile*4 + 0 --> chest on bricks (tile 0x8) 0x25 == chest_tile*4 + 1 --> chest on grass (tile 0x1) 0x26 == chest_tile*4 + 2 --> chest on brush (tile 0x2) 0x27 == chest_tile*4 + 3 --> chest on forest (tile 0x3) Monsters can't walk onto chests, so there can only be one chest per map square. Moon phases and sub-phases: Each turn, both sub-phases are decremented. When a sub-phase reaches -1, it is reset to 0xB/3, and the corresponding phase is incremented. The phases are the numbers displayed on the upper border of the game world window. DEMO.ULT -------- This file contains the 19*6 map displayed in the main menu. Each byte represents a tile. MOVES.ULT --------- This file contains the animation script for the main menu map. offset length purpose 0x0 0x200 command table 0x200 0x200 data table ROSTER.ULT ---------- Infomation about all characters the player has created. offset length purpose 0x0 0x40 character record 1 0x40 0x40 character record 2 ... 0x4C0 0x40 character record 20 Character record format: BCD = binary coded decimal (two digits per byte). offset length purpose 0x0 0xA character name; ASCII string, 0-terminated. Padded with 0's. 0xA 0x4 ? 0xE 0x1 marks and cards; bit 0-7 = love, sol, moon, death, force, fire, snake, kings 0xF 0x1 number of torches; BCD 0x10 0x1 0x0 = character is not in party, 0xFF = character is in party 0x11 0x1 status; ASCII character: G,P,D,A 0x12 0x1 strength; BCD 0x13 0x1 dexterity; BCD 0x14 0x1 intelligence; BCD 0x15 0x1 wisdom; BCD 0x16 0x1 race; ASCII character: E,D,F,H,B 0x17 0x1 class; ASCII character: W,R,T,I,A,D,F,L,C,B 0x18 0x1 gender; ASCII character: M,F,O 0x19 0x1 current magic points; BCD 0x1A 0x2 current hit points; BCD 0x1C 0x2 maximum hit points; BCD 0x1E 0x2 experience points; BCD 0x20 0x1 sub-morsels; BCD 0x21 0x2 food; BCD 0x23 0x2 gold; BCD 0x25 0x1 gems; BCD 0x26 0x1 keys; BCD 0x27 0x1 powders; BCD 0x28 0x1 currently worn armor 0x29 0x7 how many of each armor type; BCD 0x30 0x1 currently readied weapon 0x31 0xF how many of each weapon type; BCD Sub-morsels: This field contains 2 digits (those behind the decimal point) of the food field. On the surface, the game subtracts 10 from this field during every turn (remember that it contains a BCD). Everywhere else, the game subtracts 10 every 4 turns. Weapon types: offset letter name 0x31 B Dagger 0x32 C Mace 0x33 D Sling 0x34 E Axe 0x35 F Bow 0x36 G Sword 0x37 H 2H Sword 0x38 I +2 Axe 0x39 J +2 Bow 0x3A K +2 Sword 0x3B L Gloves 0x3C M +4 Axe 0x3D N +4 Bow 0x3E O +4 Sword 0x3F P Exotic Weapon Armor types: offset letter name 0x29 B Cloth 0x2A C Leather 0x2B D Chain 0x2C E Plate 0x2D F +2 Chain 0x2E G +2 Plate 0x2F H Exotic Armor PARTY.ULT --------- Information about the current party. BCD = binary coded decimal (two digits per byte). offset length purpose 0x0 0x1 mode of transportation; 0xA = horse, 0xB = ship, 0x3F = on foot 0x1 0x1 ? 0x2 0x1 party location 0x3 0x4 number of moves; BCD 0x7 0x1 number of characters in the party 0x8 0x1 x coordinate of party (on Sosarian map) 0x9 0x1 y coordinate of party (on Sosarian map) 0xA 0x4 number of PC in slot 1-4 (party order) 0xE 0x4 ? 0x12 0x40 character record for PC 1 0x52 0x40 character record for PC 2 0x92 0x40 character record for PC 3 0xD2 0x40 character record for PC 4 Party location: 0 = Sosaria 1 = dungeon 2 = towne 3 = castle (LB's Castle, Castle Death) 4 = shrine, fountain, mark 0x80 = combat 0xF0 = talking to a merchant 0xFF = Ambrosia You can only save your game in Sosaria, so the party location field in the file is always 0. .ULT files (town maps) ---------------------- These files contain the map and "dialogs" for each town. The tiles are stored as base_tile*4. There are 32 NPC's in every town. (?) BRITISH.ULT Lord British's castle DAWN.ULT Dawn DEATH.ULT Death Gulch DEVIL.ULT Devil Guard EXODUS.ULT Exodus (Castle Death) FAWN.ULT Fawn GREY.ULT Grey LCB.ULT Britain MONTOR_E.ULT Montor East MONTOR_W.ULT Montor West MOON.ULT Moon YEW.ULT Yew offset length purpose 0x0 0x1000 64*64 town map 0x1000 n*0x2 sign text offsets; n <= 8, add 0x1000 to get the real offset 0x1000+n*0x2 variable sign texts and dialog; all texts are 0-terminated ASCII strings 0x1180 0x20 tile number for each NPC; divide by 4 to get real tile number 0x11A0 0x20 tile number of floor under each NPC; divide by 4 to get real tile number 0x11C0 0x20 starting x coordinate of each NPC 0x11E0 0x20 starting y coordinate of each NPC 0x1200 0x20 movement flag + dialog number 0x1220 0x8 not used Movement flag + dialog number: (byte >> 4) == 0 --> NPC walks around (byte >> 4) == 4 --> NPC doesn't move (byte >> 4) == 8 --> NPC is a merchant (byte >> 4) == 0xC --> NPC attacks party (byte % 0xF) == sentence number Still unknown: 0x85, 0x86 .ULT files (dungeon maps) ------------------------- These files contain the dungeon maps and sign texts. DARDIN.ULT Dardin's Pit FIRE.ULT Dungeon of Fire M.ULT Dungeon of Doom MINE.ULT Mines of Morinia P.ULT Dungeon of the Snake PERINIAN.ULT Perinian Depths TIME.ULT Dungeon of Time offset length purpose 0x0 0x100 16*16 map of level 1 0x100 0x100 16*16 map of level 2 ... 0x700 0x100 16*16 map of level 8 0x800 n*0x2 sign text offsets; n = 8, add 0x800 to get the real offset 0x810 0x80 sign texts; every sign text is a 0-terminated ASCII string There is at most one sign per dungeon level. To find out the text for a sign, use (dungeon_level-1) as an index into the table at 0x800. Dungeon tiles: 0x00 = empty 0x01 = vision of the Time Lord 0x02 = fountain (type?) 0x03 = strange wind (extinguishes your torch) 0x04 = trap 0x05 = mark (type depends on dungeon) 0x06 = gremlins (they steal your food) 0x07 = (not used) 0x08 = sign (text depends on dungeon level) 0x10 = ladder up 0x20 = ladder down 0x30 = ladder up/down 0x40 = chest 0x50 = chest + ladder up (can't get chest) 0x60 = chest + ladder down (can't get chest) 0x70 = chest + ladder up/down (can't get chest) 0x80 = wall 0x90 = (not used) 0xA0 = illusionary wall 0xB0 = (not used) 0xC0 = door 0xD0 = (not used) 0xE0 = (not used) 0xF0 = (not used) .ULT files (conflict maps) -------------------------- These files contain the 11*11 conflict maps. CNFLCT_A.ULT land to ship (party on land) CNFLCT_B.ULT brush (tile 0x2) CNFLCT_C.ULT brick floor (tile 0x8) CNFLCT_F.ULT forest (tile 0x3) CNFLCT_G.ULT grass (tile 0x1) CNFLCT_M.ULT land to water (party on land) CNFLCT_Q.ULT ship to water (party on ship) CNFLCT_R.ULT ship to land (party on ship) CNFLCT_S.ULT ship to ship (party on southern ship) offset length purpose 0x0 0x79 11*11 map; each byte represents one tile 0x79 0x7 ? 0x80 0x8 starting x coordinates for monsters 1-8 0x88 0x8 starting y coordinates for monsters 1-8 0x90 0x8 not used 0x98 0x8 not used 0xA0 0x4 starting x coordinates for PC's 1-4 0xA4 0x4 starting y coordinates for PC's 1-4 0xA8 0x4 not used 0xAC 0x4 not used U3 uses the 8 bytes at offset 0x90 (in memory) to store the tiles under monster 1-8. U3 uses the 8 bytes at offset 0x98 (in memory) to store the hit points of monster 1-8. U3 uses the 4 bytes at offset 0xA8 (in memory) to store the tiles under PC 1-4. U3 uses the 4 bytes at offset 0xAC (in memory) to store the base tiles for PC 1-4. U3 doesn't use the values stored at these locations in the conflict files. .IMG files ---------- Each of these files contains an 11*11 tile image. Each byte represents a tile number. BRAND.IMG brand FOUNTAIN.IMG fountain SHRINE.IMG Ambrosian shrine TIME.IMG Time Lord Notes ----- I'm pretty sure that U3 doesn't save the wind direction. Sources: http://www.geocities.com/xenerkes/ http://martin.brenner.de/ultima/u3roster.html http://home.hiwaay.net/~rgregg/ultima/literal/Transcript_U3.html