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 The UESP: Daggerfall for the latest version of this document and other DF goodies.
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.
[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.
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).
[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.
[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.
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
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
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
0xA5 (165) = Light Blue, Temple 0xA9 (169) = Dark Blue, Shrine
0xA8 (168) = Light Pink, Palace / Manor 0xAB (171) = Dark Pink, Shack 0xAC (172) = Dark Pink/Red Graveyard (same as 0x8C?)
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 DAThe 'D' values are strange in that there are no RMB files that have a D in the fifth character position.
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)
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.
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 + hSince 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 = 0This 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 + has 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: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.
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