Ultima 6 Notes
Author: Jim Ursetto
$Id: u6notes.txt,v 1.8 2003/03/18 21:17:28 jim Exp $
==============================

This is a collection of notes on Ultima 6 I wrote while developing
my world editor, u6edit.  It assumes you have familiarity with the 
other U6 information out there, and gets right to the new stuff.

In developing the editor, I used a lot of publically available information, 
some of which I've included in the u6edit package.  Visit the following
sites for the original documents and much more:

http://www.geocities.com/nodling/
http://www.it-he.org/u6_tools.htm
http://red5.graf.torun.pl/~rackne/u6like.html

basetile: object -> tile mapping
--------------------------------
(uncompressed)
0x400 shorts, mapping object number (the index) to tile number (the short value).
Tile is the -first- frame of the object.

look.lzd: Object descriptions
-----------------------------
Format: record = uint16 tile_number, ASCIIZ string
        file   = record, record, record, ..., dummy_short

Tile numbers are sorted in ascending order, and may skip numbers.  When
numbers are skipped, the next highest number with a valid record is used
for the corresponding tile.  e.g. 0 Nothing, 1 grass, 4 swamp -> tile
numbers 2, 3, 4 are all considered 'swamp'.  At the end of the file is a
single short followed by nothing.

More examples:
egg         (object 0x14f) => basetile(0x14f) == 0x4e8.  Matches look.lzd's tile number 0x4e8.
sea serpent (object 0x15a) => basetile(0x15a) == 0x514.  Matches look.lzd's tile number 0x51b,
                                                         which is the last frame of the sea serpent.

NOTE: you may not assume that look data is linked to the last frame of every object.
Several objects can share the same description.

Only objects that are stackable (can have quantity > 0, like gold coins) should
(hopefully will) contain pluralizing modifiers such as "\s".

objblk: Object blocks
---------------------
	objblks are arranged 1 per superchunk -- so there are 64 (8x8) surface 
	chunks [a-h][a-h], plus five dungeon chunks [a-e]i.

	There are 128x128 tiles / superchunk, so x coord can be represented in 7 bits.  
	There are 1024x1024 tiles / world, so world x coordinate can be represented in 10 bits (0 - 0x3ff).

	file format: 
		uint16 num_objects;
		struct objentry[num_objects];

	objentry (according to obed):
		struct objentry {     
			uint8 status;
			uint8  h;
			uint8  d1;
			uint8  d2;
			uint16 type;
			uint8  quantity;
			uint8  quality;
		};    

	type: 
		bits 0-9 (0x3ff): Object number.
		bits 10-15      : Frame number.

	status:
		bit 0 (0x01): 0=stealing, 1=ok to take
		bit 3 (0x08): object in a container [including eggs and readied items]
		bit 4 (0x10): object in party inventory
		bit 5 (0x20): seen eggs with this attribute: hatch once only?

		'charges' have status 0x2b.  I've seen eggs with status 0x20 and 0x28 -- the
		coordinates are as for regular eggs.  However, the charges with status 0x2b have an
		unknown coordinate scheme.

	h:
		bits 0-7 (0xff): lower 8 bits of x coordinate
	d1:
		bits 0-1 (0x03): Upper 2 bits of x coordinate
		bits 7-2 (0xFC): Lower 6 bits of y coordinate
	d2:
		bits 0-3 (0x0F): Upper 4 bits of y coordinate
		bits 4-7 (0xF0): z coordinate [presumption, not verified]

	quantity:
		Represents number of objects for stackable objects, or number of charges for wands, etc.
		Some containers (chests, crates, but not bags) have a quantity of 10.
		If 0, this object is singular (non-stackable).

	Objects are listed in ascending order: sweeping left to right, starting
	at the top of the block.  So y is monotonically increasing, while x 
	increases monotonically for identical values of y.
	Overlapping objects (at the same coordinates) are listed from frontmost to rearmost.
	This means they should be drawn in -reverse- order, assuming a painter's algorithm.

	Objects in containers come directly after the container, and have status 0x08.  The first
	object is the first to be removed when searching the container (and will wind up on the
	bottom of the pile).

	Containers:
		Objects in containers (status == 0x08) have special coordinates:
			x: the index of the parent container in the objblk.  
			   0 being the first object, 1 the second, etc.
			y: unknown.  I've seen values of 0, 0x40, 0x80, 0xC0, 0x2C0, 0x300, 0x340,
			   0x380, which would indicate they increase in 64-byte quantities.  Can't
			   work out how the game sets these.  However, setting y to -any- of those
			   values is apparently acceptable to the game; any other value and the
			   object will disappear.

		Eggs are considered to be containers, containing the object to spawn.  The spawned
		object data [coordinates, etc.] is not fully understood yet.

		I set up a chest followed by gold (status 0) outside the chest, followed by a fence
		(status 0x08) pointing into the chest.  [Did this by flipping the objects at 111,144.]
		This was successful, meaning contained objects don't necessarily have to follow their containers.

		Unfortunately, this pattern is not perfect.  First, objects must come somewhere
		after their containers in the file, or they are ignored.  Upon next save, the object
		is lost.  Second, there is a limit to how far apart they can be.  This seems to
		occur when an object with unusual status (0x18, 0x31, 0x42) is placed between
		them--objects afterward are no longer matched up.  These objects are also lost upon
		save.  Third, the game always groups the objects together upon save.  This leads me
		to believe the ability to separate objects from containers is never relied upon by
		the game.  Therefore, it is highly recommended to group them together.

		Any object can apparently be a container.  You can change a crate to a brazier, and
		when looking at it the items will appear ("Searching here, you find...").  The item simply
		needs to be followed with objects of status 0x08 (and the requisite coordinates).  Note:
		crates, chests, barrels need to be opened (used) before they can be searched, but this is
		not true for all containers (bags, braziers, pennants ;)
		
	Other objects:
		Objects in party inventory have their own meaning for their coordinates [NPC coords].
		The x coords for these seems to refer to NPC number, but is not verified.

		Readied items [0x18] have also NPC coordinates.  NPC containers have status 0x10 (and therefore 
		cannot be readied).  Items in NPC containers have status 0x08, with standard container coordinates.


starpos.dat: Twinkling stars in the Introduction
------------------------------------------------

starpos.dat is a compressed file that evidently describes the
position of the stars that twinkle in the U6 intro.

Tim Carlsen provided me with the following information:

"I've done some more research, and I'm now pretty sure that the 
uncompressed starpos.dat has the following structure:

struct uncompressed_starpos_dat {
	uint16 x_coordinates[0x190];
	uint16 y_coordinates[0x190];
	uint16 star_colors[0x190];
};

There are 0x190 twinkling stars (the background image probably has more, but
not all of them twinkle).  Ultima 6 makes each star briefly flash white and
then returns it to its original color, which is stored in star_colors[i].  
The star colors are stored as words, though the upper byte is always zero
(because mode 0x13 pixels are bytes)."


tileflag: Information on various tiles.
---------------------------------------

		From 0x000 - 0x7FF, there is one byte for each tile:
			bit 0 (0x01): may have something to do with shoreline -- unknown
			bit 1 (0x02): 0 for passable, 1 for impassable 

		The moongates are 0x40; the 0x40 doesn't do anything I can see.

		When I set an object (e.g. chain coif) to 0xff, it becomes impossible to Get ("Not possible") and 
		it is no longer searched when you look at it.  Neither is true when only set to 0x02.

		Again starting at 0x800, each tile has a byte allocated to it:
			bit 4 (0x10): tile is above any other tiles at this location
			bit 5 (0x20): unknown, but it's pretty common
			bit 6 (0x40): object vertical size (0 for 1 tile, 1 for 2 tiles)
			bit 7 (0x80): object horizontal size (same)

		Bits 6 and 7 control object size.  When objects have size > 1, the other tiles are
		found consecutive and previous to the main tile.  Render them right-to-left,
		bottom-to-top, subtracting one from the tile number each time.  The object
		coordinates specify the bottom right corner of the object.

		Setting a secondary tile (one drawn when size > 1) to 0x10 makes it
		higher (above other objects).  This is used in pillars, for example.
		The exact effects and implementation of this stacking is unknown.

		Then, there's some unknown stuff between 0x1000 and 0x13ff.

		Then, from 0x1400 - 0x1c00, there's another 2048 tile bytes:
			bit 0: unknown; maptiles lava 0xdd, 0xde, 0xdf have this set.
			bit 6, 7 (0xC0): the article prepended to the object description
				00 = no article
				01 = article is "a"
				10 = article is "an"
				11 = article is "the"

		When object quantity is 0, the article is used.  When 1 or above, the number is
		usually used in place of the article.  However, quantity is ignored for
		pluralization purposes (apparently) if the description does not contain a
		plural modifier (chests, mirrors).  Experiment:  try setting a plural modifier 
		on the name of a non-plural object with quantity > 0, such as lightning wand or crate.

		The four object floor tiles from 0x21c - 0x21f (offsets 0x161c-0x161f) have bits 4 and 5 (0x30) set.
			
		For maptiles (0x1400-0x15ff), I've only seen 0x40, 0x80, 0xC0, and 0x01 as values.

		The weight of items may be in tileflag, but I have not found it yet.  Certainly it
		tells you which objects are immovable. 

		tileflag definitely does not contain: ability of objects to stack; what type an
		object is (book, container, weapon); weapons/armour stats.  The equivalent of
		U7 usecode appears to be hardcoded into the game.

Miscellaneous
-------------
palette:
	The missing intervals from u6tech.txt are:
		0xF0 - 0xF3: purple braziers, force fields
		0xF8 - 0xFB: poison fields

books:
	book number = object quality - 1
		quality = 0 is considered to be a regular item.  There's one such book in the Inn in Paws.
		   When looked at, it says "Thou dost see a book.  It weighs 1.0 stones.  
		   Searching here, you find nothing."
	
weapon and armour statistics:
	U6 hardcodes a lot of its data in the game executable, including weapon and armour statistics.
	If you use an unpacker on game.exe, you can find the following (at least in my version):

	0x32521 - 0x32528 are the 8 helmet damage absorption points.
	0x32529 - 0x32530 are the 8 shield damage absorption points 
	0x32531 - 0x32537 are the 8 armour damage absorption points.

	The spiked collar (which absorbs 2 points) is not found yet.  (The next three bytes are 01 02 05,
	which do not correspond to the next three items: collar 2, guild belt 0, gargoyle belt 0.)

	0x325bc - 0x325ca sling - halberd damage infliction points
	0x325cb - 0x325cb boomerang, crossbow damage infliction points (glass sword skipped)


