Daggerfall's BSA File Formats by Dave Humphrey - dave@uesp.net 6 April 2002 This is a description of the format of the various .BSA files found in the ARENA2 directory of Elder Scrolls:Daggerfall by Bethesda. The information here is not complete or 100% percent accurate, although the basic formats appears to be well understood. For more information, corrections, or comments, e-mail me at the above address. Check out http://www.uesp.net/dagger/ for the latest version of this document and other DF goodies. CONTRIBUTORS ================================ Significant contributors to these formats include: Michael [subproperty@hotmail.com] - Dungeon Pre/Postrecords - Location types - BLOCKS.BSA RDB format CONTENTS ================================ General BSA Files General File Layout BSA Header BSA Records BSA Directory BSA 0x0100 Directory BSA 0x0200 Directory MAPS.BSA General File Layout Location Offset Section (MapPItem) Location Record Data (MapPItem) Location Records Dungeon Records Location PreRecords Sub-Format Location PostRecords Sub-Format Dungeon Offset Section (MapDItem) Dungeon Record Data (MapDItem) Location Table Section (MapTable) Location Name Section (MapNames) Map Directory ARCH3D.BSA General File Layout BSA Header 3D Object Records 3D Object Header Plane Data Record Section BLOCKS.BSA RMB General File Layout RMB Fixed Length Data (FLD) RMB FLD Record Counts RMB FLD Header RMB FLD Section1 RMB FLD Section2 RMB Section1 Sizes RMB FLD Section3 RMB FLD Section4 RMB FLD Filenames RMB SubRecords RMB SubRecords1 RMB SubRecord1 Header RMB SubRecord1 Section1 RMB SubRecord1 Section2 RMB SubRecord1 Section3 RMB SubRecord1 Section4 RMB SubRecord1 Section5 RMB SubRecords2 RMB SubRecords3 Appendix A - REGION NUMBERS Appendix B - LOCATION TYPES Appendix C - BLOCK INDICES Appendix D - COORDINATE LIMITS Appendix E - UV TEXTURE COORDINATES GENERAL BSA FILES ================================ There are five BSA files in Daggerfall's ARENA2 directory (ARCH3D, MAPS, MONSTER, MIDI, and BLOCKS). Although they contain different data, their overall structure is the same. This format has been derived from all these five files. The following description appears to be complete. General File Layout ------------------------------------- BSA Header ...BSA Records... BSA Directory BSA Header ------------------------------------- This is the first 4 bytes found at the start of a BSA file and gives information about the BSA directory at the end of the file. [Bytes 0-1] short DirectoryCount; Gives the number of entries in the directory at the end of the file. [Bytes 2-3] short DirectoryType; Gives the type of directory at the end of the BSA file (See BSA Directory below). 0x0100 = Directory has records of 18 bytes in size consisting of a 14 byte filename and a long record length. 0x0200 = Directory has records of 8 bytes in size consisting of long ID and a long record size. BSA Records ------------------------------------- This data will depend on the actual BSA file. The basic contents for the five known BSA files are as follows: ARCH3D = 3D Object Information BLOCKS = Dungeon/town block information MAPS = Location information (towns, dungeon, houses, temples, etc...) MONSTER = Monster data (no images) MIDI = HMI formatted music BSA Directory ------------------------------------- The directory contains the information needed to access the various data records in the BSA file. The contents of each record depends on the BSA file. In general, the directory gives an identification number/string and a record length for each record. There are two known types of directories identified by the DirectoryType bytes in the BSA header (0x0100 and 0x0200). BSA 0x0100 Directory (Name) ------------------------------------- The 0x0100 type directory consists of records 18 bytes in size and give a record size and 13 byte name for each BSA record. [Bytes 0-13] char FileName[14]; The filename which identifies this data section. Filenames are in the usual DOS 8.3 format. [Bytes 14-17] long DataSize; The size of the data in bytes. The first record starts at offset 4 in the file, ignoring the 4 bytes of the BSA Header. The subsequent section offsets can be calculated from this. BSA 0x0200 Directory (Number) ------------------------------------- The 0x0200 type directory consists of records 8 bytes in size and give a record size and long identifier for each BSA record. [Bytes 0-3] long RecordID; A long number which assumbly identifies the record somehow. [Bytes 4-7] long DataSize; The size of the data in bytes. The first entry starts at offset 4 in the file, ignoring the 4 bytes of the BSA Header. The subsequent section offsets can be calculated from this. MAPS.BSA ================================ Overall, the Maps.BSA file contains 61 total regions with a combined total of 15251 locations, with 4232 of these being dungeon types. General File Layout ------------------------------------- The file starts with a short BSA header followed by the map data as sorted by map region (the provinces such as Wayrest, Glenpoint, Daggerfall etc... in the game). Each region is furthur divided into other data sections. Each data section is referenced by a directory entry which occurs at the end of the file as per a usual BSA file. BSA Header Begin Region Location Offset Section } MapPItem Location Record Data } MapPItem Dungeon Offset Section } MapDItem Dungeon Record Data } MapDItem Table Data } MapTable Name Data } MapNames End Region ...Other Regions... Map Directory Location Offset Section (MapPItem) ------------------------------------- Offset sections appear before each section of town record data. It is merely a list of 4 byte long values which point to the start of a location record relative to the end of the offset section. Location Record Data (MapPItem) ------------------------------------- Each record is pointed to by one offset record in the preceding offset section. Records are variable length. Contains all locations of the region (town, dungeon, house, etc...). [Bytes 0-3] long PreRecordCount Gives the number of 6 byte records which follow. This value can be 0x00000000 indicating that no records exist. The record data has no visible effect on the location. Values here range from 0 to 555 (confirmed) (around 20% of location and dungeon records have no prerecords). Total of 569407 prerecords in the MAPS.BSA file. [Bytes 4...] unsigned char PreRecords[6] The 6 byte record data if there is any. [Bytes ...] Header Information, 0x47 (71) bytes [Bytes 0-3] long OneValue1 = 0x00000001; Always this value in both location and dungeon records (confirmed). [Bytes 4-5] short NullValue1; [Byte 6] char NullValue2; Always 0 (confirmed). [Bytes 7-10] long XPosition; Position of the location in game position units. Values can range from 51,200 (far West) to around 32,389,120 (far East) (confirmed). [Bytes 11-14] long NullValue3; Always 0 (confirmed). [Bytes 15-18] long YPosition; Position of the location in game position units. Values can range from around 40,961 (far South) to 16,332,801 (far North) (confirmed). [Bytes 19-22] long Unknown1; Location records always have 0x00008000 (32768). In dungeon records this value is always 0 (confirmed). [Bytes 23-26] long Unknown2; Values range from 0 to 18 in location records (is 0 ~75% of the time). In dungeon records this value is always non-zero in the range 65536 to 589824 (confirmed). [Bytes 27-30] long Unknown3; Almost always non-zero in all records. Location record values range from 0 to 1832, dungeon values range from 0 to 684 (confirmed). [Byte 31-32] short OneValue2 = 0x0001; Always 1 in both dungeon/location records (confirmed). [Bytes 33-34] short LocationID; The unique location ID which is used for quests and probably other things. [Bytes 35-38] long NullValue4; Always 0 in both dungeon/location records (confirmed). [Bytes 39-40] short Unknown4; Always 0 in location records and always 1 in dungeon records (confirmed). [Bytes 41-44] long Unknown5; Always 0 in location records and takes a variety of values in dungeon records (always non-zero) (confirmed). These last two might indicate the presence and size (or offset to) dungeon specific data. [Bytes 45-70] char NullValue5[26]; Always 0 in both dungeon/location records (confirmed). [Bytes ...] char LocationName[32] Gives the location name. Data is always 32 bytes in size and string should be NULL terminated. Any extra data after the string is ignored. The name is used when you enter the location but not used when on the travel map (the Name Table is used for that). [Bytes ...] char Unknowns[9]; Unknown values [Bytes ...] short PostRecordCount Gives the number of records which follow. Records appear to be of fixed length 0x1A (26) bytes. Always 0x0000 in dungeon records. From this point on the dungeon/location records differ slightly. Location Records ---------------- [Bytes ...] char Unknowns1[5]; Unknown values. [Bytes ...] char LocationPostRecords[26][] See the Location PostRecords Format section below. Each record is 0x1A (26) bytes in size. [Bytes ...] char AnotherName[32]; Appears to be another name for the location but its purpose is unknown. Changing it has no visible effect. [Bytes ...] long Unknown6; This value is the same as the first 4 bytes in the MapTable for the location. Another location ID perhaps. [Bytes ...] char Unknowns2[4]; [Bytes ...] byte BlockWidth; [Bytes ...] byte BlockHeight; Range from 1 to 8 and give the size of the location in blocks. The BlockWidth*BlockHeight will give the number of block file numbers in the following sections. [Bytes ...] char Unknowns3[7]; [Bytes ...] char BlockFileIndex[64]; Each can be an index, from 0 to 44, of a block file. See Appendix C for more information. Usually just the first index is used and the rest are zero. [Bytes ...] char BlockFileNumber[64]; Similarily gives the block file number, from 0 to 42. [Bytes ...] char BlockFileChar[64]; Similarily gives the block file character, from 0 to 143. See Appendix C for possible values. [Bytes ...] char Unknowns4[32]; Typically zero but almost all values range from 0 to 122. [Byte ...] char Unknown5; Ranges from 0 to 18, usually 0. [Byte ...] char Unknown6; Ranges from 0 to 22, usually 0. [Bytes ...] char NullValues1[9]; Always 0 (confirmed). [Bytes ...] long Unknowns7[22]; [Bytes ...] char NullValues2[40]; Always 0 (confirmed). [Bytes ...] long Unknown8; Dungeon Records --------------- [Bytes ...] long Unknown6; [Bytes ...] long Unknown7; [Bytes ...] short NumDungeonPostRecords; Gives the number of dungeon post records. [Bytes ...] char Unknown8[5] [Bytes ...] char DungeonPostRecords[][4]; Each is 4 bytes in size. [Bytes ...] char Padding[]; Variable size of data which appears to always be zero and may simply be padding for the dungeon post records. The padding size is equal to (128 - NumDungeonPostRecords*4). 2) Location Types In Appendix B, the location types are listed. 0xAC (172) is listed as Dark Pink, but it looks red to me. In fact, the difference between 0xAC and 0x8C is a mystery. Looking at the locations corresponding to each of these, I have come up with names for them: 0x84 (132) = Major Dungeon 0x87 (135) = Fortress (Large Dungeon) 0x8A (138) = Ruins (Small Dungeon) 0x8C (140) = Graveyard 0x8D (141) = Coven 0xA0 (160) = Large Town 0xA1 (161) = Medium Town 0xA2 (162) = Small Town 0xA3 (163) = Farmstead 0xA6 (166) = Tavern 0xA5 (165) = Temple 0xA9 (169) = Shrine 0xA8 (168) = Palace / Manor 0xAB (171) = Shack 0xAC (172) = Graveyard Location PreRecords Sub-Format ------------------------------------- The format for the 6 byte prerecord data found in the location and dungeon record data is as follows: [Bytes 0-1] short PostRecordIndex; Dungeon Records: 0xFFFF - Always this value (confirmed) Location Records: Appears to give be postrecord index which the prerecord may apply to. The same index may be repeated in several prerecords. [Byte 2] char NullValue; Always 0x00 in both dungeon/location records (confirmed). [Byte 3] char Unknown3; Dungeon Records: 0x00 - Only 23 records. 0x10 - About half of records (10334). 0x40 - About half of records (10415). 0x80 - Only 17 records. Location Records: 0x10 - About 20% of records (106905). 0x20 - Around half of records (248908). 0x30 - Only 100 records. 0x40 - About 10% of records (59384). 0x50 - Only 54 records. 0x60 - Only 53 records. 0x80 - Only 17 records. 0xA0 - About 20% of records (133138). 0xB0 - Only 51 records. 0xE0 - Only 25 records. [Byte 4] char Unknown4; Dungeon Records: Always non-zero and usually less than 0x0A but ranges up to 0xE7 (231). Location Records: Takes on a wide range of values 0-0xFF, usually non-zero (confirmed). [Byte 5] char Unknown5; Dungeon Records: 0x00 - Only in 32 records 0x01 - Only in 8 records 0xFA - Occurs in most records (20749) Location Records: Usually always less than 0x09 but 166572 records have the value 0xFA. The arrangement of variables above is arbitrary as the actual purpose of data is currently unknown. PreRecords usually appear in location records. Only 20789 (3.7%) of the 569407 total prerecords in MAPS.BSA occur in dungeon records. The number of prerecords is generally smaller in dungeon records than location records as well. Prerecord numbers range from 0 to 27 in dungeon records while 0 to 555 in location records. The data has no visible effect on the location. The data can be mangled or simply removed with no apparent effect on the location. Location PostRecords Sub-Format ------------------------------------- Records which appear after the location name in the location record are 0x1A (26) bytes in size and have the format listed below. Location postrecords only occur in location records, not dungeon which have their own post record format. The number of prerecords in location records range from 0 to 329 with a total of 328499 in the MAPS.BSA. There are usually no postrecord information (97%). [Bytes 0-1] short HouseNameType; Affect the generation of the house name. Ranges from 0 to 0x81DD (33245). 00 00 = The Dancing Chasm (Tavern) 01 00 = The Knave and Scorpion (Tavern) 02 00 = The Dancing Chasm (Tavern) 00 09 = The Silver Scorpion (Tavern) BA 29 = The Golden Stag (Tavern) BB 29 = People of Alik'r (Temple) EA 7E = The Queen's Dungeon (Tavern) [Bytes 2-17] char NullValues[16]; Always 0 (confirmed). [Bytes 18-19] short Unknown1; Usually zero and ranges from 0 to 852. Appears to be generally zero for residences (unconfirmed). [Bytes 20-21] short Unknown2; This value seems to generally increase with each postrecord. Changing this number at all crashes the game when the location is loaded. Always non-zero and ranges from 4 to 2329. [Bytes 22-23] short LocationID; This value is always the same as the location ID in the the location record header (confirmed). [Byte 24] char HouseType; Something to do with the house name or type, ranges from 0 to 0x18 (24). 0x0E = Temple 0x0F = Tavern 0x10 = Palace 0x11 = Residence 0x12 = Residence 0x13 = Residence [Byte 25] char Unknown3; Always non-zero and ranges from 1 to 0x14 (20). Dungeon PostRecords Sub-Format ------------------------------------- The Dungeon PostRecords are each four bytes long and have the following format: [Byte 0] signed char x [Byte 1] signed char y [Byte 2] unsigned char blockNumber (low byte) [Byte 3] [bits 0-1] (high bits of blockNumber) [bit 2] Set to 1 if the player starts in this block, 0 otherwise [bits 3-7] unsigned char blockType The blockType is actually an index into a character array at offset 001B:3E44 of Fall.exe: const char blockTypes[6] = {'N', 'W', 'L', 'S', 'B', 'M'}; When the appropriate character is concatenated to the seven-digit decimal representation of the blockNumber, the name of an RDB file is constructed. (For example, "N0000019.RDB") The x and y values place the block on a 2D grid. Generally, the central block of the dungeon is at (0,0). Note: the only file that requires the two extra bits of blockNumber is S0000999.RDB. This file is only used in Privateer's Hold. Also note: there are no RDB files that begin with "L" and there are no Dungeon Post-Records that refer to L. Dungeon Offset Section (MapDItem) ------------------------------------- Dungeon Offset sections appear before each section of dungeon record data and follow immediately after the end of the town record data for a region. [Bytes 0-3] long DungeonCount The number of dungeon records which follow. [....] Offset Section Records Records are 8 bytes in length and have the following structure: long Offset = Offset to record data from end of the offset section short Number = 0x0100 usually? short Unknown = Another increasing number Dungeon Record Data (MapDItem) ------------------------------------- Each record is pointed to by one dungeon offset record in the preceding dungeon offset section for the region. Records are variable length. Only locations that are dungeons, ie, that have new interior maps, are included here. Assumably this section defines the map 'blocks' which make up the dungeon. For now this appears to be the same as the Location Record Data. Location Table Section (MapTable) ------------------------------------- Contains data related to to the locations in the previous sections for the current region. Starts immediately after the last dungeon record data. The number of section records is the number of the towns in the current region. Each record is 17 bytes in size and appears to be a bit field (bit fields are identified by the 6.# where # here would represent the #th bit in the 6th byte, the 8th bit would be the 0th bit in the next byte). [Byts 0-3] long Unknown1; (32 bits) This number is repeated in the location record. Perhaps a unique identifier of some sort. [Bytes 1-4] char Unknown2; (8 bits) Possibly always 0. [Bytes 5-6.1] unsigned int XPosition; (17 bits) Gives the X-position of the location for display on the travel map. One pixel appears to equal 128 units with the origin at the bottom-left of the map. Values should range from 0 (far left) to 128000 (far right) (unconfirmed). Each unit is equal to about 256 position units in the game. [Bytes 6.2-8] int LocationType; (15 bits) Type of the location (home, dungeon, town, etc...). This determines the color of the location on the travel map. [Bytes 9-10] unsigned short YPosition; (16 bits) Gives the Y-position of the location for display on the travel map. Ranges from 0 (map bottom) to 64000 (map top) (unconfirmed). [Bytes 11-12] short Value2; (16 bits) [Bytes 13-16] long Value3; (32 bits) Location Name Section (MapNames) ------------------------------------- Repeats all the town names in the current region. Each town name is 32 bytes, NULL terminated, and starts immediately following the town name header section. The town name offset section for the next region starts immediately after this town name data. This is the name used on the travel map. [Bytes 0-3] long LocationCount; Number of locations in list. This value might be used to determine the total number of locations in a region. [Bytes 4...] char Names[32][...]; All the location names (max 32 characters including NULL terminator). Map Directory ------------------------------------- The map directory is the last 4464 bytes of the Maps.BSA file and is the usual 0x0100 BSA directory type. It contains 248 records of 18 bytes each (for 62 regions, 000 to 061). The filenames are of the form MAPPITEM.0## - Place item offset data and records MAPDITEM.0## - Dungeon offset data and records MAPTABLE.0## - Map table MAPNAMES.0## - Name table where ## ranges from 00 to 61 (for each region). Assumably the DF engine requests the data by this filename. See Appendix A for a list of which regions correspond to which values. ARCH3D.BSA ================================ The following description has been tested on all the 3D Objects contained in Arch3D.BSA and appears to be sound. There are two records which have some problems (offsets 0x008B8D58 and 0x013274C6) and don't follow the known format of the other 10249 records. They have a large section of repeating bytes just after the 3D object header and their Data2 section is not the standard. These records could very well be corrupt or not used or of a special, undiscovered, format. General File Layout ------------------------------------- The file is a typical BSA file with a 0x0200 directory at the end. Each BSA record contains the information for one 3D object. BSA Header ...3D Object Records... Object Directory BSA Header ------------------------------------- A typical, 4 byte, BSA header indicating 0x280B records (10251). 3D Object Records ------------------------------------- Each BSA record contains the information for one 3D object. Note that each record appears to be _similar_ to the .3D file format used in Battlespire. One difference is that here the .3D files are contained in one big file, while in Battlespire they are in individual files. Records range from 212 to 81394 bytes in size. The basic record layout is as follows: 3D Object Header (64 Bytes) Always the first 64 bytes in the record. See the header section below for detail format and information. Unknown Data Two files have strange sections of repeating bytes between the record header and point data. Usually, though, the point data follows starting at byte 64. Point Data Contains the point data as given by the number of points previously read. Each point is composed of 3 signed long integers, (X, Y, Z) for 12 bytes per point. Use the PointOffset variable in the header to get the start of the point data. PlaneData See the Plane Data Record section below. There is one record for each plane given by the PlaneCount variable. Use the PlaneOffset variable in the header to get the start of the plane data. Normal? Data Section Appears to have XYZ 12 bytes triplets again with the number of records equal to the number of planes. This appears to be the normals of the planes but not entire confirmed. The offset to this data is also in the header. Offset1 Data Section This section is usually all 0x00's, but the size indicates it should have a record size of 24 bytes with the number of records equal to the number of planes. The offset to the start of this data is also in the header. Offset2 Data Section The number of records in this section is given in the object header. The basic format of each record is as follows: [Bytes 0-15] long Numbers[4]; Looks like 3 or 4 coordinates. [Bytes 16-17] short NumSubRecords; Gives the number of 6 bytes sub-records which follow. [Bytes 18...] char SubRecords[6][] The variable number of sub record data. This data finishes off the object record data. The offset to the start of this data and the number of records the section contains is in the object header. Note that while most 3D objects have this format, some have the sections mixed up slightly (i.e., the data1 section comes before the points). One should use the offset information in the object header to determine where each section starts. 3D Object Header ------------------------------------- The header is always the first 64 bytes in a 3D object record. [Bytes 0-3] char Version[4] = "v2.7"; (or "v2.6" or "v2.5") Appears to be a version number or record identifier. Most of the records have v2.7, though 135 have v2.6 and 9 have v2.5. Note that the trailing NULL character is not included. It is currently unknown what differences the various version records have, although it appears to be minor. [Bytes 4-7] long PointCount; Gives the number of points contained in the 3D object. Each point consists of 3 long integers (X, Y, Z) for a total of 12 bytes per point. Point counts range from 3 to 1010. [Bytes 8-11] long PlaneCount; This gives the number of planes/faces in the 3D object. Plane counts range from 1 to 712. [Byte 12-15] long Unknown1; Has a wide range of values, generally non-zero. [Bytes 16-23] char NullValue1[8]; Always 0x00 bytes (confirmed). [Bytes 24-27] long Data1Offset; [Bytes 28-31] long Data2Offset; Appear to be offsets from the start of an object record Offset1 is always non-zero and Offset2 is zero only 3 times (confirmed). [Bytes 32-35] long NumData2Records; Usually non-zero and less than 0x0010 (maximum around 212). Appears to be the number of records pointed to by Offset2. [Bytes 36-37] short Unknown3; A wide range of repeating values. [Bytes 38-39] short Unknown4; Usually 0x0000 or less than 0x0010 (maximum of 0x0068). [Bytes 40-43] long NullValue3; [Bytes 44-47] long NullValue4; Always 0x00000000 (confirmed). [Bytes 48-51] long PointOffset; Almost always 0x00000040 but also takes on the values 0x00000000 (strange?) 0x00000178 0x00001510 0x000017F8 The offset from the start of the object record to the start of the point data. [Bytes 52-55] long NormalOffset; Offset from the record origin to the next byte after the end of the plane data. Always non-zero (confirmed). [Bytes 56-59] long Unknown6; Always 0x00000000 except for 19 records which it has a number of values from 0x000000F4 to 0x000001FC. Possibly offset? [Bytes 60-63] long PlaneOffset; Offset from start of object to the plane/face data. Plane Data Record Section ------------------------------------- This is a sub-record of the 3D Object Record. Each plane record is (8 + (PlanePointCount*8)) bytes in size. Some of the variables are bit fields written out as [Bytes 2-3.1] which would be a 9 bit field. [Byte 0] unsigned char PlanePointCount; (8 bits) The number of points which makes up the plane. This value ranges from 0x00 to 0x18 (24). [Byte 1] char Unknown1; (8 bits) Usually 0x00 for most plane records (about 2% are non-zero). Values range from 0x00 to 0xFF although most are repeating values in the 0x00 to 0x40 range. [Bytes 2-2.6] unsigned short SubImageIndex; (7 bits) The subimage index in the texture file (0 to 127). [Bytes 2.7-3.7] unsigned short TextureIndex; (9 bits) The texture file index (0 to 474). [Bytes 4-7] long Unknown4; Almost always 0x00000000, 0x00010000, 0x00010001, or 0x00010002 and rarely a wide range of other values. Probably two short values. [Bytes 8...] PlanePointSubRecords For each point in the PlanePointCount variable, there is 8 bytes of data. [Bytes 0-3] long PointOffset; v2.7:This gives the offset of the point used from the beginning of the point data. In other words, divide by 12 to get the point index. This is confirmed for all v2.7 objects except for one which is strange (offset 0x013274C6). v2.6:Appears to be the same as v2.7. v2.5:The point offset is a multiple of 4 and appears to be the offset to the actual XYZ coordinate of the point. To get the point index, divide by 4 (unconfirmed). [Bytes 4-5] short TextureU; [Bytes 6-7] short TextureV; Specifies the texture UV coordinates for the point. See Appendix E for a complete description of how Daggerfall handles UV texture coordinates. Object Directory ------------------------------------- The object directory is at the end of the file and gives the record lengths of all the 3D object records (the usual 0x0200 type BSA directory map). There is also a long value associated with each record which, for most entries, is unique (all but 25 of 10251 records have unique values in the directory). Special Objects ------------------------------------- The following list of objects in the ARCH3D file have special mention. Object 4722 (0x8B8D58) This v2.6 3D object has a truncated, or different, Data2 section which does not conform with the known format. Object 7614 (0x13274C6) This v2.7 object has an invalid offset to the Data2 section (it points to the middle of the data1 section). BLOCKS.BSA ================================ A typical BSA file with a filename type directory at the end with 1295 records. There are three types of records which are contained in this BSA file which can be derived from their directory filenames. FOO. One record is not any real data but actually a DOS directory listing of someones directory (with a hard drive named FireBall). *.RDB Variable length record. 187 files. *.RDI Seems to be a fixed length record of 512 bytes. Appears to contain only 00's and 01's. 187 files. *.RMB Most records are this type of variable length record. 920 files. RMB General File Layout ------------------------------------- The RMB file is the most common type in the blocks file and is organized as follows: RMB File Fixed Length Data (FLD) (6776 bytes total) Record Counts (3 bytes) FLD Header (640 bytes) FLD Section1 (832 bytes) FLD Section2 (128 bytes) FLD Block Data Sizes (128 bytes) FLD Small Maps (520 bytes) FLD Automap (4096 bytes)) FLD Filenames (429 bytes) ...RMB Block Data... (Variable) Outside Header (17 bytes) 3D Object Data (66 byte records) Flat Object Data (17 byte records) Data Section3 (16 byte records) People Data (17 byte records) Door Data (19 byte records) Inside Header (17 bytes) 3D Object Data (66 byte records) Flat Object Data (17 byte records) Data Section3 (16 byte records) People Data (17 byte records) Door Data (19 byte records) Extra Byte (1 byte, optional) ...RMB 3D Objects... (66 byte records) ...RMB Flat Objects... (17 byte records) Note that in the RMB block data section there are two repeating sections. The first section contains data for the outside, or main, object, such as the exterior of a house or tavern. This section usually just has one 3D Object Data section which is the main 3D object for locations. The following section holds the data for the interior object, such as inside a house or tavern. Typically this section holds much more information than the previous one. RMB Fixed Length Data (FLD) ------------------------------------- Each block record appears to begin with 0x1A78 (6776) bytes of fixed length data. This data can be subdivided into the follow records. FLD Record Count (3 bytes) FLD SubBlock Positions (640 bytes) FLD Section1 (832 bytes) FLD Section2 (128 bytes) FLD Block Data Sizes (128 bytes) FLD Small Maps (520 bytes) FLD Automap (4096 bytes) FLD Filenames (429 bytes) In general, each of these subsections can be subdivided into 32 further subrecords as described in each section below. RMB FLD Record Counts ------------------------------------- The first 3 bytes in the fixed length data give the number of various records which appear later on in the block record. [Byte 0] byte NumSubRecords1; Values range from 0 to 28 with a total of 9005 subrecords1 in the blocks file. [Byte 1] byte NumSubRecords2; Values range from 0 to 93 with a total of 9153 subrecords2 in the blocks file. [Byte 2] byte NumSubRecords3; Values range from 0 to 74 with a total of 11732 subrecords3 in the blocks file. RMB FLD Block Positions ------------------------------------- The fixed length data header is found at offsets 0x03 to 0x282 (642) bytes in the FLD for a total of 0x280 (640 bytes). It contains 32 records of 0x1A (20) bytes each which contain the positions for each of the sub-blocks in the file. [Bytes 0 - 3] long XPos1; [Bytes 4 - 7] long ZPos1; Unknown what these coordinates are for. Possibly the subblock size? [Bytes 8 -11] long XPos2; [Bytes 12-15] long ZPos2; Give the position of the subblock in map coordinates. [Bytes 16-19] long YPos2; Unknown. RMB FLD Section1 ------------------------------------- The fixed length data section1 is found at offsets 0x283 (643) to 0x5C2 (1474), just after the FLD header, for a total of 0x340 (832) bytes. It seems to contain 32 records of 0x1A (26) bytes each. It seems to be very similar to the location post-records found in MAPS.BSA. RMB FLD Section2 ------------------------------------- The fixed length data section2 is found at offsets 0x5C3 (1475) to 0x642 (1602), just after the FLD Section1, for a total of 0x80 (128) bytes. It should contain 32 records of 4 bytes each. RMB FLD Block Data Sizes ------------------------------------- This section is found at offsets 0x5C3 (1475) to 0x6C2 (1730), just after the FLD Section2, for a total of 0x80 (128) bytes. It contains 32 records of 4 bytes each and represents the record sizes of the Block Data records which appear later in the file. [Bytes 0-127] long Sizes[32]; RMB FLD Small Map Data ------------------------------------- The fixed length data section3 is found at offsets 0x6C3 (1731) to 0x8CD (2253), just after the FLD Block Data Sizes, for a total of 0x208 (520) bytes. It appears to contain an 8 byte header followed by two sections of 256 bytes each. [Bytes 0- 7] char Header[8]; [Bytes 8-263] char TextureInfo[16][16]; See description which follows. Contains modified texture image indices to use. [Bytes 264-519] char ObjectInfo[16][16]; Currently unknown. The first 256 bytes after the header shows some interesting designs when viewed as a 16x16 image and probably indicates the textures to display on the land under the block. The format for the texture info bytes is a bit field described as follows: [Bits 0-5] int TextureIndex; (6 bits) This value, ranging from 0-63, gives the new texture index to display. The texture file to use will depend on the current location (desert, temperate, etc...) and the time (raining, summer, winter, etc...). [Bit 6] int RotateTexture; (1 bit) Might be a flag indicating that the texture should be rotated 90 degrees so that the width becomes its height and vice-versa. This allows reuse of textures rather than duplicating them in the texture file. [Bit 7] int FlipTexture; (1 bit) Appears to be a flag indicating that the texture should be flipped in both the X and Y directions so that its last pixel becomes its first. The last 256 bytes looks more like a starry night and could indicate how to place scenery around the block, but its purpose is unknown currently. It may be a bit field like the first 256 byte section. RMB FLD Automap ------------------------------------- The fixed length data section4 is found at offsets 0x8CB (2251) to 0x18CA (6346), just after the FLD Small Map Data, for a total of 0x1000 (4096) bytes. It contains a 64x64 bitmap which is seen when you look at the automap while in town. The bitmap also contains extra information which is not displayed. The general pixel values are as follows: 0x00 Background, transparent 0x03 Store? (orange) 0x10 Taverns (green) 0x12 Residence? (gray) 0x13 Residence (gray) 0x14 Residence? (gray) 0xE0 Special Item? (not displayed) 0xFA Object (not displayed) 0xFB Object (not displayed) It is not known what the three types of residences represent. The bitmap probably does not control where things appear but was most likely used as as development tool. RMB FLD Filenames ------------------------------------- The list of component filenames is found at offset 0x18CB (6347) to 0x1A77 (6775), just after the FLD Section4, for a total of 0x1AD (429) bytes. Filenames are 13 bytes which includes the terminating NULL character (regular 8.3 syntax). There may be NULL filenames at the end of the list. The first filename is always the block record file followed by 32 other filenames. [Bytes 0- 12] char BlockFilename[13]; [Bytes 13-428] char Filenames[13][32]; RMB Block Data ------------------------------------- Following the FLD section there are usually one or more blocks of block data which can be described as follows: Header (17 bytes) } Exterior data like that 3D Object Data (66 byte records) } for a house or tavern. Flat Object Data (17 byte records) } Usually contains just Data Section3 (16 byte records) } one 3D object People Data (17 byte records) } Door Data (19 byte records) } Header (17 bytes) } Interior data like 3D Object Data (66 byte records) } that for the inside Flat Object Data (17 byte records) } of a house or tavern. Data Section3 (16 byte records) } Contains much more People Data (17 byte records) } data than the previous Door Data (19 byte records) } section. Extra Byte (Optional 1 byte, 0x96) Some RMB files do not have any subrecords, they simply end after their FLD Filenames. In some subrecords there is an extra byte, 0x96, after the end of the record. It can be identified by the length of the subrecord1 as given in the fixed length data section for the RMB file. RMB Block Header ------------------------------------- The header is always at the start of the block subrecord and appears to be always 0x11 (17) bytes in size. [Byte 0] unsigned char Num3DObjectRecords; [Byte 1] unsigned char NumFlatObjectRecords; [Byte 2] unsigned char NumSection3Records; [Byte 3] unsigned char NumPeopleRecords; [Byte 4] unsigned char NumDoorRecords; The number of records in each of the data sections which follow. [Bytes 5- 6] short Unknown1; [Bytes 7- 8] short Unknown2; (always non-zero) [Bytes 9-10] short Unknown3; [Bytes 11-12] short Unknown4; (always non-zero) [Bytes 13-14] short Unknown5; (always non-zero) [Bytes 15-16] short Unknown6; (always non-zero) The data suggests 3 pairs of shorts but it could be something entirely different. RMB Block Record 3D Object Data ------------------------------------- The data follows immediately after the block header and is composed of 0x42 (66) byte records. It contains the 3D object information for the current block. [Bytes 0- 1] short ObjectID1; Always non-zero in the range 1-511. [Byte 2] char ObjectID2; Ranges from 0 to 63. The required 3DObject to load from Arch3D.BSA can be calculated from: ObjectID1 * 100 + ObjectID2 This appears to give the directory ID for the appropiate object. It may be done this way if the objects are grouped by type in some fashion. [Byte 3] char Unknown1; Always non-zero, ranges from 3 to 67. [Bytes 4- 7] long Unknown2; Non-zero only in 1297 of 236250 records. Seems to repeat within the same file. Could be two or four seperate fields. [Bytes 8-13] long Unknown3; [Bytes 14-17] long Unknown4; Non-zero only in 272 of 236250 records. Seems to repeat within the same file. Could be two or four seperate fields. [Bytes 16-19] long NullValue1; [Bytes 20-23] long NullValue2; Always 0 (confirmed). [Bytes 24-27] long XPos1; ( -896256 to 761856 ) [Bytes 28-31] long YPos1; ( -59136 to 273152 ) [Bytes 32-35] long ZPos1; ( -815360 to 705536 ) Usually 0s, but some (370) records have what look like coordinates here with the given ranges. [Bytes 36-39] long XPos2; ( -1088 to 1096 ) [Bytes 40-43] long YPos2; ( -579 to 518 ) [Bytes 44-47] long ZPos2; ( -512 to 1536 ) Looks to be a coordinate of some form. Values range as indicated above and is usually non-zero. [Bytes 48-51] long NullValue3; Always 0 (confirmed). [Bytes 52-53] short Angle; Almost always non-zero. A value of 0x200 specifies that the object should be rotated 90 degrees about the Y-Axis (vertical). [Bytes 54-55] short Unknown5; Always zero. [Bytes 56-59] long NullValue6; Always 0 (confirmed). [Bytes 60-63] long Unknown8; Only non-zero 16 times in one file (CUSTAA45.RMB) where it is 0x200 (512). [Bytes 64-65] short NullValue5; Always 0 (confirmed). RMB Block Flat Objects ------------------------------------- This data follows immediately after the 3D Object Data in a Block Record and is composed of 0x11 (17) byte records. It contains information about flat objects in the block. Flat objects are just that, merely textures painted on planes which always face the viewer (called decals in Direct3D). [Bytes 0- 3] long XPos; [Bytes 4- 7] long YPos; [Bytes 8-11] long ZPos; Looks like coordinate of some form. [Bytes 12-12.6] int SubImageIndex; (7 bits) The subimage in the texture file to use for the flat. [Bytes 12.7-13.7] int TextureIndex; (9 bits) The texture file index to use. [Bytes 14-15] short Unknown1; Usually non-zero (50%) and ranges from 0 to 65535. Might indicate whether or not to display the flat. The 'debuging' icons usually have a value of 0x0000 or 0xFFFF here. [Byte 16] char Unknown2; Usually non-zero (90%) and ranges from 0 to 105. RMB Block Data Section3 ------------------------------------- This data follows immediately after the Flat Objects Data and is composed of 0x10 (16) byte records. It has an unknown purpose. [Bytes 0- 3] long XPos; [Bytes 4- 7] long YPos; [Bytes 8-11] long ZPos; Looks like coordinate of some form. [Byte 12] char Unknown1; Usually zero (99%) and ranges from 0 to 15. Repeats mostly in each file where it is present. [Byte 13] char Unknown2; Almost always non-zero and ranges from 0 to 45. [Bytes 14-15] short Unknown3; Usually zero and ranges from 0 to 1292. Lower 8 bits are always zero and upper 8 bits range from 0 to 7. RMB Block People Data ------------------------------------- This data follows immediately after the Section3 Data in a Block record and is composed of 0x11 (17) byte records. Appears to be the same format as the Flat Object data. It contains information about the people in a block. [Bytes 0- 3] long XPos; [Bytes 4- 7] long YPos; [Bytes 8-11] long ZPos; Looks like coordinate of some form. [Bytes 12-12.6] int SubImageIndex; (7 bits) The subimage in the texture file to use for the person. [Bytes 12.7-13.7] int TextureIndex; (9 bits) The texturefile to use for the person. [Bytes 14-15] short NPCType; Seems to indicate the type of PC such as weaponsmith, barkeep. etc... 0x0000 - Common person 0x01FE - Barkeep [Byte 16] char Unknown3; Always non-zero and ranges from 1 to 45. RMB Block Door Data ------------------------------------- This data follows immediately after the People Data in a Block and is composed of 0x13 (19) byte records. It seems to give information about the movable doors in a block. [Bytes 0- 3] long XPos; [Bytes 4- 7] long YPos; [Bytes 8-11] long ZPos; Looks like coordinate of some form. [Bytes 12-13] short Unknown1; Usually non-zero in the range 0 to 1536. [Bytes 14-15] short Unknown2; Always non-zero in the range 90 to 98. [Bytes 16-17] short Unknown3; Almost always non-zero in the range 0 to 7173. [Byte 18] char NullValue1; Always 0 (confirmed). RMB 3D Objects ------------------------------------- These appear to be the same format as the RMB Blocks 3D Objects which are 0x42 (66) byte records. It probably lists the 3D Objects which populate the exterior of a block, such as outside a house or tavern (fences, signs, etc...). RMB Flat Objects ------------------------------------- These appear to be the same format as the RMB Block Flat Objects are 0x11 (17) byte records. It probably gives the Flat Objects which appear outside the given block, such as grass, bushes, etc... RDB Files ------------------------------------- RDB files are archived in Blocks.bsa. Each BSA filename begins with a letter and is followed by a 7-digit decimal integer. (For example, "N0000019.RDB") These files are referenced in the dungeon records of Maps.bsa. Each RDB file describes one dungeon 'block' in detail. Each block of dungeon is fits on a 2D grid with other blocks. There are two connecting passages in each of the four cardinal directions, so there are eight paths leading out of each block. RDB General Format ------------------------------------- [Header] [3D Models Section] [3D Model Records] [Additional Data] [Object Section] [Object Header Section] [Object Roots Section] [Object Data Section] RDB Header (20 bytes): ------------------------------------- [Byte 0] char Unknown1; [Byte 1] char Unknown2; [Bytes 2-3] short Unknown3; [Bytes 4-7] long GridWidth; The width of the Object Root Section [Bytes 8-11] long GridHeight; The height of the Object Root Section [Bytes 12-15] unsigned long objectOffset; The offset from the beginning of the RDB file to the Object Root Section [Bytes 16-19] long Unknown4; RDB 3D Models Section (9000 bytes): ------------------------------------- First is a list of 750 3D Model Records of 8 bytes each. Unused records are filled with 0xFF. Each record has the following format. 3D Model Record (8 Bytes) ------------------------- [Bytes 0-4] char modelID[5]; a string containing the five-digit decimal representation of the object's model ID as seen in Arch3D.bsa (not null-terminated) [Bytes 5-7] char objectType[3]; a short string possibly describing the type of object (not null-terminated) Additional Data: ------------------------------------- Next is another list of 750 records, but of only 4 bytes each. They seem to correspond to the 3D Model Records. The format of these bytes is unknown. Unused records are filled with 0x00. RDB Object Section: ------------------------------------- The Object Section is organized as follows: [Object Header Section] [Object Roots Section] [Object Data Section] RDB Object Header Section (512 bytes): ------------------------------------- [Bytes 0-3] long UnknownOffset; An offset from the beginning of the RDB file to a linked list of unknown purpose and format. [Bytes 4-7] long Unknown1; [Bytes 8-11] long Unknown2; [Bytes 12-15] long Unknown3; [Bytes 16-19] long FileSize; The length of the RDB file, in bytes. [Bytes 20-51] char Unknown4[32]; Seem to always be 0xFF [Bytes 52-55] char TagDAGR[4]; Seem to always be the character array "DAGR" [Bytes 56-511] char Unknown5[456]; Seem to be 0xFF RDB Object Roots Section: ------------------------------------- [Bytes 0-...] long Offsets[] The number of longs in the list is GridWidth*GridHeight. Each entry is an offset from the beginning of the file to an Object Record. Any negative value indicates that no object data is present. The meaning of the grid layout is unknown. RDB Object Data Section: ------------------------------------- This section contains numerous records of various types, not in any particular order. Each Object Record is a node of a doubly linked list. Use the Object Roots Section to find the head of the list, and iterate using the offsetNext and offsetPrev fields. Object Record (25 bytes): [Bytes 0-3] long offsetNext; The offset from the beginning of the RDB file to the next Object Record. Any negative value indicates that there is no next item. [Bytes 4-7] long offsetPrev; The offset from the beginning of the RDB file to the previous Object Record. Any negative value indicates that there is no previous item. [Bytes 8-11] long xLoc; [Bytes 12-15] long yLoc; [Bytes 16-19] long zLoc; These three values define the object's location in space. [Byte 20] char objectType; This can take on only these three values: 0x01: The object is a 3D model. 0x02: The object is a light source. 0x03: The object is a flat (including markers and monsters). [Bytes 21-24] long postRecordOffset; The offset from the beginning of the RDB file to the object's type-specific data. Each object has a variable length post record, pointed to by postRecordOffset. The format of this record depends on the objectType. Object Post Record, type 0x01 (3D Object) (23 bytes): [Bytes 0-3] long xAngle; [Bytes 4-7] long yAngle; [Bytes 8-11] long zAngle; the rotation angles about each axis [Bytes 12-13] short ModelIndex; Indexes one of the 750 entries in the 3D Models Section. This model is used for the object. [Bytes 14-17] long Unknown3; (ranges from 0 to 240) [Byte 18] char Unknown4; (ranges from 0 to 108) [Bytes 19-22] long ActionOffset; Offset from the beginning of the RDB file to an Action Record, which contains additional information about how this object behaves. If this value is -2 then no such record exists for this object. Object Post Record, type 0x02 (Light Source) (10 bytes): [Bytes 0-3] long Unknown1; [Bytes 4-7] long Unknown2; [Bytes 8-9] short Unknown3; (Presumably, these values determine light intensity, range, etc.) Object Post Record, type 0x03 (Flat Object) (11 bytes): [Bytes 0-1] { [bits 0-6] int SubImageIndex; (7 bits) [bits 7-15] int TextureIndex; (9 bits) } The texture to use, formatted as in the "RMB Block Flat Objects" section of an RMB file. The TextureIndex identifies the texture file and the SubImageIndex identifies the image within the texture file. [Bytes 2-10] char Unknown1[9]; RDB Action Record (10 Bytes): ------------------------------------- 3D objects may point to an Action Record in ActionOffset. [Bytes 0-4] char DataEntry[5]; [Bytes 5-8] long TargetOffset; The offset from the beginning of the RDB file to the Object Record describing this action's target, negative if there is no target. [Byte 9] char Type; Probably affects how the DataEntry field is interpreted. Ranges from 0 to 100, but most entries use these values: 0x00: Probably used to indicate no action. 0x01: Object Translation 0x08: Object Rotation The target object (and the target object of its action, etc.) is activated simultaneously with this object. In this way targets can be chained together for several simultaneous effects. Both Rotation and Translation actions format the DataEntry field in this way: [Byte 0] char Axis; Takes on values ranging from 1 to 99, but most entries use these values: 0x01: negative x 0x02: positive x 0x03: negative y 0x04: positive y 0x05: negative z 0x06: positive z (Maybe a bit field?) [Bytes 1-2] unsigned short Duration; Determines how long the object takes to reach its destination. [Bytes 3-4] unsigned short Delta; The amount to move along/around the specified axis. Rotations rotate about the Axis while translations move along them. Doors do not appear to use the Action Record. It is not known whether teleporting walls use it. Switches, levers, and moving platforms appear to use it. For example, in Privateer's Hold there is a switch next to a platform with a throne on it. Flipping the switch invokes the switch's action, which rotates it into the flipped position. That action targets the platform, which makes it rise. The platform's action targets the throne, which also rises. All these are performed simultaneously. Appendix A - REGION NUMBERS ================================ The following is a list of region numbers which is used to access the region map data in the Maps.BSA file (and possibly elsewhere). Note that some of the names are not used in the game (marked by an *). 00 = Alik'r Desert 01 = Dragontail Mountains 02 = Glenpoint Foothills* 03 = Daggerfall Bluffs* 04 = Yeorth Burrowland* 05 = Dwynnen 06 = Ravennian Forest* 07 = Devilrock* 08 = Malekna Forest* 09 = Isle of Balfiera 10 = Bantha* 11 = Dak'fron 12 = Islands in the Western Iliac Bay* 13 = Tamarilyn Point* 14 = Lainlyn Cliffs* 15 = Bjoulsae River* 16 = Wrothgarian Mountains 17 = Daggerfall 18 = Glenpoint 19 = Betony 20 = Sentinel 21 = Anticlere 22 = Lainlyn 23 = Wayrest 24 = Gen Tem High Rock village* 25 = Gen Rai Hammerfell village* 26 = Orsinium Area 27 = Skeffington Wood* 28 = Hammerfell bay coast* 29 = Hammerfell sea coast* 30 = High Rock bay coast* 31 = High Rock sea coast 32 = Northmoor 33 = Menevia 34 = Alcaire 35 = Koegria 36 = Bhoriane 37 = Kambria 38 = Phrygias 39 = Urvaius 40 = Ykalon 41 = Daenia 42 = Shalgora 43 = Abibon-Gora 44 = Kairou 45 = Pothago 46 = Myrkwasa 47 = Ayasofya 48 = Tigonus 49 = Kozanset 50 = Satakalaam 51 = Totambu 52 = Mournoth 53 = Ephesus 54 = Santaki 55 = Antiphyllos 56 = Bergama 57 = Gavaudon 58 = Tulune 59 = Glenumbra Moors 60 = Ilessan Hills 61 = Cybiades Appendix B - LOCATION TYPES ================================ The following is a list of location types used in the map tables. The list is not yet exhaustive. Dungeons --------------------- 0x84 (132) = Orange, Major Dungeon 0x87 (135) = Dark Orange, Fortress (Large Dungeon) 0x8A (138) = Medium Red, Ruins (Small Dungeon) 0x8C (140) = Dark Red, Graveyard 0x8D (141) = Black, Covens Towns --------------------- 0xA0 (160) = Light Rose, Large Town 0xA1 (161) = Medium Rose, Medium Town 0xA2 (162) = Medium Rose, Small Town 0xA3 (163) = Medium Rose, Farmstead 0xA6 (166) = Dark Rose, Tavern Temples --------------------- 0xA5 (165) = Light Blue, Temple 0xA9 (169) = Dark Blue, Shrine Homes --------------------- 0xA8 (168) = Light Pink, Palace / Manor 0xAB (171) = Dark Pink, Shack 0xAC (172) = Dark Pink/Red Graveyard (same as 0x8C?) Appendix C - BLOCK INDICES ================================ At offset 0x1BD97F in v2.13 FALL.EXE, there's a listing of 45 RMB files in the format "TVRN????.RMB" to probably be used with a printf() type function to generate the appropiate entry to load from BLOCKS.BSA. The filename list is as follows (13 bytes per record, 8.3 filenames, terminated by a NULL): Index Filename File Chars File Index Description ----- -------------- ------------ ---------- ------------------ 0 TVRN????.RMB A/B/G, L/M/S 0-10 Taverns 1 GENR????.RMB A/B/G, L/M/S 0-3 General Stores 2 RESI????.RMB A/B/G, L/M/S 0-10 Residences 3 WEAP????.RMB A/B/G, L/M/S 0-3 Weaponsmiths 4 ARMR????.RMB A/B/G, L/M/S 0-3 Armourers 5 ALCH????.RMB A/B/G, L/M/S 0-3 Alchemists 6 BANK????.RMB A/B/G, L/M/S 0-3 Banks 7 BOOK????.RMB A/B/G, L/M/S 0-3 Bookstores 8 CLOT????.RMB A/B/G, L/M/S 0-3 Clothing Stores 9 FURN????.RMB A/B/G, L/M/S 0-3 Furniture Stores 10 GEMS????.RMB A/B/G, L/M/S 0-3 Jewelers 11 LIBR????.RMB A/B/G, L/M/S 0-3 Libraries 12 PAWN????.RMB A/B/G, L/M/S 0-3 Pawnshops 13 TEMP????.RMB AA, GG 00-H0 Temples 14 TEMP????.RMB AA, GG 00-H0 Temples 15 PALA????.RMB A/B/G, A 0-4 Knight Guilds? 16 FARM????.RMB AA 0-9 Farms 17 DUNG????.RMB AA 0-18 Dungeons 18 CAST????.RMB AA 0-34 Unknown 19 MANR????.RMB A/B/G, L/M/S 0-3 Manors? 20 SHRI????.RMB AA 0 Shrines? 21 RUIN????.RMB AA 0-28 Ruins? 22 SHCK????.RMB AA 0 Unknown 23 GRVE????.RMB A, L/M/S 0-42 Unknown 24 FILL????.RMB AA 0-15 Unknown 25 KRAV????.RMB A/B/G, L 0-1 Unknown 26 KDRA????.RMB A/B/G, L 0-1 Unknown 27 KOWL????.RMB A/B/G, L 0-1 Unknown 28 KMOO????.RMB A/B/G, L 0-1 Unknown 29 KCAN????.RMB - - No Files 30 KFLA????.RMB A/B/G, L 0-1 Unknown 31 KHOR????.RMB A/B/G, L 0-1 Unknown 32 KROS????.RMB A/B/G, L 0-1 Unknown 33 KWHE????.RMB A/B/G, L 0-1 Unknown 34 KSCA????.RMB A/B/G, L 0-1 Unknown 35 KHAW????.RMB A/B/G, L 0-1 Unknown 36 MAGE????.RMB A/B/G, A 0-14 Mage Guilds 37 THIE????.RMB A, L/M/S 0 Thief Guilds 38 DARK????.RMB AA 0-2 Dark Brotherhood 39 FIGH????.RMB A/B/G, A/L/M/S 0-2 Fighter Guilds 40 CUST????.RMB A/G, A 0-56 Custom? 41 WALL????.RMB AA 0-11 Walls? 42 MARK????.RMB A/B/G, A/L/M/S 0-1 Unknown 43 SHIP????.RMB AA 0-1 Ship 44 WITC????.RMB AA 0-13 Witch Covens File chars fill in the first two ?? and the file index fills in the last two ??. A value of "A/B/G, L/M/S" means the file characters could be one of AL, AM, AS, BL, BM, BS, GL, GM, or GS. The descriptions given are a rough guess based on the RMB file name. The known values for the file chars as given in location post records in MAPS.BSA are shown below. Value File Char ---- -------- 0x00 AA 0x01 AA 0x02 AA 0x07 AA 0x0F DA 0x11 DA 0x13 DA 0x15 DA 0x1F DA 0x2F AL 0x3F DL 0x4F AM 0x5F DM 0x6F AS 0x7F DS 0x8F AA 0x9F DA The 'D' values are strange in that there are no RMB files that have a D in the fifth character position. Appendix D - COORDINATE LIMITS ================================ Coordinates are roughly in centimeters as given in the game by using the ' cheat key for quest info. Coordinates are 256 times smaller than the coordinates used for the 3D objects. X = 0? (As far West as you can go) X = 32,400,000 (As far East as you can go on the map) Z = 2,000,000 (As far South as you can go on the map) Z = 16,367,616 (As far North as you can go) Appendix E - UV TEXTURE COORDINATES ====================================== Note: Much of this information orginated from Craig (cpeterson@ematic.com) and Gavin (interkarma@m0use.net, http://m0use.net/~interkarma). Daggerfall handles UV coordinates a little differently than most 3D programs and require some explanation. The TextureU and TextureV in the plane sub- records hold the texture coordinate data for the face point but, depending on the face, the UV coordinates have different meaning: Point 1: The actual DfUV coordinate for that point. Point 2: The change in DfUV coordiantes relative to Point 0. To get the absolute DfUV values you must add Point 1s to Point 0. Point 3: The change in DfUV coordiantes relative to Point 1. To get the absolute DfUV values you must add Point 2s to Point 1 and 0. Point 4: For faces with more than 3 points, this point is the absolute DF UV coordinate for that point. Tests seem to indicate, though, that the game does not use this data. Point 5+:UV coordinates should be all 0 and are not used. Since all points on the face after the 4th have no UV values, this indicates that we must find a relationship between the XYZ point and the UV coordinate, which is detailed below. The units of DfUV texture coordinates are relative to the size of the texture image. A value of 1024 represents 64 pixels of image data. The conversion between DfUV and standard UV coordinates is detailed below. CONVERTING XYZ to UV Coordinates ------------------------------------- Unfortunately, as of this point, there is no simple way to compute the UV coordinate of a point from its XYZ location, but the best current method is explained as follows. We first assume that the relationship is linear and of the form: U = aX + bY + cZ + d V = eX + fY + gZ + h Since all faces have at least 3 points (confirmed) and we know the UV coordinates for the first 4 points, we should be able to solve for the parameters a...h. We assume d and h are both 0 for this case, though we will use them later. We could solve for the 6 unknowns explicitly but we would have to take into account which points have similar XYZ coordinates which becomes messy (we can't divide by X1-X2 if they are equal). Instead, we will take the similar route of expressing the equations in matrix form and solving the matrix equation (which may turn out to be just as complex). The matrix equation for U is of the form: { X1 Y1 Z1 } { a } { U1 } { X2 Y2 Z2 } * { b } = { U2 } { X3 Y3 Z3 } { c } { U3 } where X1,Y1,Z1,U1 and the coordinates of the first points. To solve for the unknown matrix {a..c} we simple need the inverse of the {X1...Z3} matrix which will be multiplied to left of the {U1..U3} matrix. Using the Jacobian method of matrix inversion we can find the solution to be: /* Compute the determinant of the XYZ matrix */ Determinant = X1*Y2*Z3 + Y1*Z2*X3 + Z1*X2*Y3 - X3*Y2*Z1 - X2*Y1*Z3 - X1*Y3*Z2 /* Compute the inverse of the XYZ matrix */ Xi1 = ( Y2*Z3 - Y3*Z2) / Determinant Xi2 = (-X2*Z3 + X3*Z2) / Determinant Xi3 = ( X2*Y3 - X3*Y2) / Determinant Yi1 = (-Y1*Z3 + Y3*Z1) / Determinant Yi2 = ( X1*Z3 - X3*Z1) / Determinant Yi3 = (-X1*Y3 + X3*Y1) / Determinant Zi1 = ( Y1*Z2 - Y2*Z1) / Determinant Zi2 = (-X1*Z2 + X2*Z1) / Determinant Zi3 = ( X1*Y2 - X2*Y1) / Determinant /* Compute the DfUV conversion parameters */ a = U1*Xi1 + U2*Yi1 + U3*Zi1 b = U1*Xi2 + U2*Yi2 + U3*Zi2 c = U1*Xi3 + U2*Yi3 + U3*Zi3 d = 0 e = V1*Xi1 + V2*Yi1 + V3*Zi1 f = V1*Xi2 + V2*Yi2 + V3*Zi2 g = V1*Xi3 + V2*Yi3 + V3*Zi3 h = 0 This works for more than 90% of the 10251 objects in the ARCH3D.BSA files, but it fails when the Determinant above is 0. This usually occurs when all of the points on a face lie in the X, Y, or Z plane (ie, the X/Y/Z coordinates are identical for all points in the face). In these cases we must use the d and h parameters which were previously assumed to be zero. For example, in the case where all Y's are equal, the equations turn into: U = aX + cZ + d V = eX + gZ + h as b and f are irrelevant due to Y=0. The matrix solution then becomes: { X1 1 Z1 } { a } { U1 } { X2 1 Z2 } * { d } = { U2 } { X3 1 Z3 } { c } { U3 } Determinant = X1*Z3 + Z2*X3 + Z1*X2 - Z1*X3 - X2*Z3 - X1*Z2 Xi1 = ( Z3 - Z2) / Determinant Xi2 = (-X2*Z3 + X3*Z2) / Determinant Xi3 = ( X2 - X3) / Determinant Yi1 = (-Z3 + Z1) / Determinant Yi2 = ( X1*Z3 - X3*Z1) / Determinant Yi3 = (-X1 + X3) / Determinant Zi1 = ( Z2 - Z1) / Determinant Zi2 = (-X1*Z2 + X2*Z1) / Determinant Zi3 = ( X1 - X2) / Determinant a = U1*Xi1 + U2*Yi1 + U3*Zi1 b = 0 c = U1*Xi2 + U2*Yi3 + U3*Zi3 d = U1*Xi2 + U2*Yi2 + U3*Zi2 e = V1*Xi1 + V2*Yi1 + V3*Zi1 f = 0 g = V1*Xi3 + V2*Yi3 + V3*Zi3 h = V1*Xi2 + V2*Yi2 + V3*Zi2 using similar equations for the case of constant X and Z, we can successfully convert XYZ coordinates to DfUV texture coordinates for about 97% of the Arch3D objects. This still leaves arounds 270 objects where the XYZ determinant is zero. All remaining objects can be solved by the following rules: - Ignore faces with 4 or fewer points as the face contains the direct UV information for the first 4 points. - Ignore faces with solid colors (textures 0 and 1). - If the above cases fail to find a valid solution, attempt the remaining cases for a XZ, XY, and YZ solutions (one should work). This is due to some faces having similar/identical X/Z coordinates. To convert from DfUV coordinates (computed above) into 'normal' UV, the following equations can be used: NU = (aX + bY + cZ + d) / (16 * TextureWidth) NV = (eX + fY + gZ + h) / (16 * TextureHeight) Normal UV coordinates are based on a value of 1.0 equaling the texture width or height and are usually used in 3D modelling programs. These equations appear to give the correct texture coordinates for most 3D objects. Appendix F - LAND CREATION NOTES ==================================== Steps to create a map 'block' or pixel. The entire DF map is composed of 1000x500 land pixels, each of which is further divided into 5x5 subpixels as per the WOODS.WLD data. Each pixel can contain only one town or dungeon and has a given terrain type, texture, and roughness. == All Pixels == 1. Generate land pixel from Woods.WLD 2. Smooth edges with adajacent pixels 3. Add flats to landscape (trees, bushes, rocks, etc...) 4. Check for a location within the pixel. Currently, the only known way to do this is to check all the locations within the current region. It may be indicated by the first two bytes in a pixel record in WOODS.WLD, but this is not yet confirmed A. Load just the maptable for the region, if not loaded B. Check all locations or a pixel-coordinate match C. Stop search on first match == Location Only Pixels == 5. Load entire location from MAPS.BSA 6. Smooth appropiate land for location. How to get width/height for location or just smooth entire pixel? Smoothing should not be absolute, there should still be some random 'ripple'. If the entire pixel is to be smoothed, this could be done in Step 1. 6. Parse through the object list in the map record (post records) A. Load appropiate Blocks.BSA record. B. Parse Blocks.BSA record, create block D3D frame i. Load Arch3D.BSA object ii. Add object to frame at required position C. Add block frame to land pixel frame at required position *