Daggerfall Mod:SaveTree.Dat

Mod / Daggerfall: Daggerfall Mod: File Formats

Fundamental Data TypesEdit

DateTimeEdit

A Daggerfall DateTime structure is a UInt32 value, indicating the count of minutes since the epoch's origin. In Daggerfall, the epoch begins at 00:00, 1st of Morning Star, 3E 400. Since the game starts 0x07fd0a minutes into the epoch, all DateTime values should be greater than this number. Given there are 60 minutes per hour, 24 hours per day, 30 days per month, and 12 months per year, computing the absolute date-time from a Daggerfall DateTime is trivial. Ex: 0x00080488 computes to 364.21:28:00 from the epoch origin, or 21:28, 5th of Morning Star, 3E 401.

RecordType enumerationEdit

The RecordType enumeration is by no means complete. Only those values which are thoroughly understood are described. The RecordType value associated with each Record instance determines how the associated data is to be interpretted, assumedly via a factory design pattern.

RecordType enumeration
Value Name Description
0x01 CharacterPostion The character's position, expressed as a three-dimensional coordinate.
0x02 Item The character's inventory is described, item-for-item, via these types of records.
0x03 Character This fully describes the character's attributes and stats, including modifications from spells, diseases, potions, etc., et al.
0x04 CharacterParent This record is a parent record for the character record. The purpose is not fully understood.
0x07 DungeonInformation This record seems to describe the interior of the current dungeon the character occupies. This record is absent when outside dungeons. When interpreting DungeonInformation records, the recordLength field MUST be multiplied by 39 (0x27) to properly process the record and remaining file.
0x09 Spell These records describe the spells the character can cast from his spell book, or invoke from an enchanted item.
0x0a GuildMembership These records indicate the character's standing and status with the various guilds and orders found within the game.
0x0e QuestBinary Active quests are stored in these records. In this way a given quest template could be active multiple times without ill effect, since they each quest's state data would be separate and private from the other quests.
0x17 ControlSetting The detail, volume, etc, values configurable by the player via the options screen. Includes sight-distance fogging.
0x19 BankAccount The various bank accounts the character has open/outstanding are described in these records.
0x22 Mobile1 The various monsters and mobile town citizens are described in these records.
0x2c Mobile2 The various monsters and mobile town citizens are described in these records.
0x34 Container The containment hierarchy of how/where all the Item records are stored are described via these records.
0x36 Repair Items left at a shop for repair are described via these records.

RecordRoot structureEdit

Not all fields are known, but the following appear to be uniform and consistent.

RecordRoot structure
Offset Type Name Description
6 Position Position The position (if applicable) of the record, as it exists within the game world as a 3d point.
30 UInt32 RecordId A 32-bit, unsigned integer, serving as a unique identifier for this record.
37 UInt8 QuestId Identifies to which quest this record should be associated, or 0x00 if the record should not be associated with any quest.
38 UInt32 ParentRecordId The RecordId of the record to which ought to contain this record, or to which this record is to be considered subordinate.
66 Int32 ParentRecordType This field indicates the type of the records parent. The values of this field must conform to the values of the RecordType enumeration, and are stored as a 32-bit integer.

Position structureEdit

Position structure
Offset Type Name Description
0-3 Int32 X The longitude (X-axis) of the object in the game world.
4-5 UInt16 YOffset The altitude (Y-axis) offset of the object in the game world, from some reference altitude.
6-7 UInt16 YBase This value appears to always be 0xFF, and behaves as the reference altitude from which the YOffset field should be interpretted.
8-11 Int32 Z The object's longitude (Z-axis) within the game world.

The object's true altitude within the game world appears to be computed via YBase - YOffset, plus the baseAltitude value of the current Woods.Wld map pixel.

SaveTree.Dat coarse structureEdit

SaveTree.Dat coarse structure
Header
LocationDetail
RecordElement+

Header structureEdit

LocationDetail structureEdit

Immediately following the Header structure, is a variably-sized LocationDetail strcuture. If the character is within a town or dungeon, this structure will contain one or more records specific to that town or dungeon. If the character is overland, there will typically either be no records, or only empty (zero-length) records.

LocationDetail structure
Offset Type Name Description
0 Int8 LocationDetailCount The count of RecordElement structures which immediately follow.
1… RecordElement[ locationDetailCount ] Record The records which describe the dungeon or town immediately occupied by the character.

RecordElement structureEdit

RecordElement structure
Offset Type Name Description
0-3 Int32 RecordLength The length of the following Record structure. If the recordLength field is 0, then there is no following Record structure.
4… Byte[ recordLength ] Data The actual data of the Record. This field is not present if the recordLength field reports 0.

RecordBase structureEdit

Most records within the SaveTree.Dat file inherit from the RecordBase template. The first byte of the RecordElement.Data field is a RecordType value which indicates how the following data should be interpreted and parsed. There are very few exceptions to this format. Notably the records found within the LocationDetail do not follow this pattern, and DungeonInformation records (RecordType 0x07) misreport their size; one must multiply the recordSize field by 39 to determine the true size of a DungeonInformation record.

RecordBase structure
Offset Type Name Description
0 RecordType RecordType Describes how the following data should be interpreted.
1-70 RecordRoot RecordRoot Basic, fundamental data common to almost all records.
71-(recordLength - 71) Byte[ recordLength - 71 ] RecordData The data payload for this specific record. The recordType field implies how this binary data is to be interpretted.

Record structuresEdit

The following records document how the RecordData field is to be interpreted, based on the RecordType field. Offsets are given from the beginning of the RecordData field, which immediately follows the RecordRoot structure.

BankAccountEdit

The character's banking records are stored within a BankAccount record, one per character. This single record contains 62 entries, one AccountInformation structure for each of the 62 regions within the Iliac Bay.

AccountInformationEdit

AccountInformation structure
Offset Type Name Description
0 Int32 Balance The character's balance in that region's bank.
4 Int32 Debt The character's currently outstanding debt with that region's bank; the amount of any loan plus any interest.
8 DateTime DatePayable The loan schedule, if the Debt field is not zero.
12 UInt8 Default Whether the player defaulted on their loan.

BankAccount structureEdit

BankAccount structure
Offset Type Name Description
0 AccountInformation[ 62 ] AccountInformation The character's banking information is stored as a contiguous list of AccountInformation structures, indexed by region number. Ex: Ykalon banking information is the 41st element in the list.

Working with SaveTree.DatEdit

After reading all the records, one must then reconstruct the hierarchy of association and/or containment. Root records are identified as having no parent (ParentRecordId is 0). Subordinate records must then matched up with their superior records, such as the character's inventory must be grouped with the various container records, which are then grouped with the character's character record, which is itself subordinate to another record.