Tes2Mod:MAPS.BSA

MAPS.BSA is a Name Record (0x0100) BSA file containing the overland data for 62 regions of the game.  The file contains 4 different record types.  Each described region has one of each record type associated with it, for a total of 248 distinct records within the file.  Within each of the region's associated records, all navigable settlements, dungeons, shrines, etc are listed and described.  

General File Layout
Each described region has 4 records associated with it.  Records are all named in 7-bit ASCII string DOS8.3 format.  The 3 character record extension is the ASCII representation of the region's decimal number, with leading 0's.  Ex: Daggerfall (0x11) is identified by records ending with "017", such as "MAPPITEM.017".  The leading 8 characters indicate the specific type of record:
;MapNames
: These records simply lists the names of all navigable locations within the region, stored as an array of 7-bit ASCII strings.  
;MapTable
: These records describe the coarse GPS data, and type of the navigable locations within the region.  
;MapPItem
: These records describe the exterior of each navigable location within the region.  
;MapDItem
: These records describe the dungeon interiors of each navigable location within the region.  

Ex: "MAPNAMES.005" is the list of the names of all navigable places within Dwynnen.

Location Name Record (MapNames)

This type of record contains the count of all navigable locations within the record's associated region, immediately followed by the names of all navigable locations within the record's associated region.  

The first four bytes are the count of name elements as an UInt32, referred to as LocationCount.  This record is variably sized, but must always be 4 + ( 32 * LocationCount ) bytes long.  

Immediately following this count are the actual names of all the navigable locations for the record's associated region, each 32 characters wide, stored as a null-terminated, 7-bit ASCII string.  There are exactly LocationCount elements.

Location GPS Record (MapTable)

These records report the GPS location data, as well as the type of the described location, for each navigable location within the record's associated region.  Each record consists of a contiguous list of MapTable structures. Each MapTable structure is 17 bytes long in size.  

There are exactly MapNames.LocationCount elements in the contained list, and each indexed record is the same location as in the map names.







Width and height are given in 4096 units.

Location Item Records

Basic Structure
The remaining two types of records (MapPItem and MapDItem) each use a common base format for their root data, described here.  Each record consists of a contiguous list of the data for all the navigable locations for that record's associated region.  Since not all locations have dungeons, Location Exterior Data Records may contain more elements than Dungeon Interior Data Records.  

The base format, LocationRecordElement, is variably-sized.  It consists of a DoorHeader, immediately followed by a contiguous list of zero or more Door elements, immediately followed by a LocationRecordElementHeader with its ObjectHeader.  



DoorHeader


Door
Immediately following the DoorHeader is a contiguous list of Door elements, DoorCount in count, each 6 bytes long.  



ObjectHeader
The ObjectHeader immediately follows the contiguous list of Door elements.  The ObjectHeader structure is 71 bytes long, it is the standard Daggerfall object header.  



IsExterior


LocationRecordElementHeader

The LocationRecordElementHeader immediately follows the ObjectHeader. Each LocationRecordElementHeader structure is 48 bytes long.  



After the LocationRecordElementHeader, data specific to the record type (MapPItem or MapDItem) follows.

Location Exterior Data Record (MapPItem)

Each MapPItem record begins with a list of UInt32 values with MapNames.LocationCount elements. This is a list of offsets to the LocationExterior structures for each location. These values are relative to the end of the list, so adding (LocationCount * 4) to the offset locates the actual record. One offset may be greater than a subsequent one; no data order is presumed.

At each offset indicated, a LocationExterior structure is present, which includes all fields from the LocationRecordElement and some data of its own.



BuildingData
Immediately following the LocationRecordElement, is a contiguous list of BuildingData structures.  Each BuildingData is 26 bytes long.  BuildingData structures are associated with buildings within a settlement, such as a tavern.  



ExteriorData


Interpreting the Block Data arrays
The BlockIndex, BlockNumber, and BlockCharacter arrays all have a fixed size of 64 elements, but only the first Width * Height elements are used; the remainder are ignored.  All 64 elements must be read just the same.  These values are used to load the appropriate records from the BLOCKS.BSA file, which contains the automap data and are in turn used to load the appropriate meshes and models from ARCH3D.BSA to actually display the scene.

When accessing the block arrays, they should be synchronized.  This is to say BlockIndex[ 5 ] should refer to the same Block record as BlockCharacter[ 5 ] and BlockNumber[ 5 ].  If one adds, removes, or reorders any array then one must reorder both of the other arrays to keep them synchronized.  

The arrays are stored in west-to-east, south-to-north order.  This means index 0 refers to the southwest corner of the location, and index ( Width * Height ) refers to the northeast corner of the location.  Locations are not required to be squares (Width is not required to equal Height).  

The details of the logic are described in Block Record Indexes.

Dungeon Interior Data Record (MapDItem)

Each MapDItem record begins with an UInt32 count (DungeonCount) of DungeonInterior elements contained within the record.  

Dungeon Offset Section

Immediately following the DungeonCount field is a contiguous list of DungeonOffset values.  Each value is 8 bytes long.  The elements are not required to be in any particular order; That is to say the first element's offset could be higher than the second element's offset.  



Dungeon Record Data

Each DungeonOffset.Offset refers to a DungeonInterior element.  This is also a composite structure, similar to the LocationExterior structure.  



DungeonHeader

Immediately following the LocationRecordElement structure is a DungeonHeader structure.  



Immediately following the DungeonHeader is a contiguous list of DungeonBlock structures, each 4 bytes long.  There are BlockCount elements in this list.  

DungeonBlock Element

Each DungeonInterior structure contains a contiguous list of DungeonBlock structures.  There are exactly DungeonHeader.BlockCount elements in this list.  



The X and Z fields indicate how the blocks should be arranged in a two-dimensional grid.  Dungeons are not required to be uniform such as squares or rectangles.  They can contain empty spaces, or have spurs.  
 
 



Padding

Immediately following the last DungeonBlock element are ( 128 - ( BlockCount * 4 ) ) bytes of padding.  These values are simply padding and can be ignored.  This gives each Dungeon a maximum of 32 DungeonBlock elements.