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
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.
[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.
[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;
[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) = GraveyardUPDATE! From ATLAS.C:
/* The color code has a fine structure as well. When a new character is rolled, the sites tagged 0x8n are rolled against to determine which of them are eligible to include on the overhead map from the beginning. All other 0x8n sites are initially hidden on the map. Conversely, 0xan sites are never obscured on the overhead map. 0xad (not shown) is the code assigned to the ship sites. */
[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.
[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 Faction; Faction number from faction.txt. Usually zero and ranges from 0 to 852. [Bytes 20-21] short Sector; 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). 0x00 = Alchemist 0x01 = For Sale 0x02 = Armorer 0x03 = Bank 0x04 = Town4 0x05 = Book store 0x06 = Clothing shop 0x07 = Furniture shop 0x08 = Jeweler 0x09 = General store 0x0A = Library 0x0B = Guild hall 0x0C = Pawn shop 0x0D = Weapon shop 0x0E = Temple 0x0F = Tavern 0x10 = Palace 0x11 = House1 0x12 = House2 0x13 = House3 0x14 = House4 0x15 = House5 0x16 = House6 0x17 = Town23 [Byte 25] char HouseQuality; Always non-zero and ranges from 1 to 0x14 (20). Divide this by 4 to get the rating on the rusty- relics..incense scale.
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.
[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
[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)
[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).