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

    Source: geocities.com/nodling/ultima/text/ultima3

               ( geocities.com/nodling/ultima/text)                   ( geocities.com/nodling/ultima)                   ( geocities.com/nodling)