Daggerfall Mod:Quest hacking guide

The UESPWiki – Your source for The Elder Scrolls since 1995
Jump to: navigation, search

Important Note Before Beginning[edit]

This document was created assuming you know the basics of hex editing and programming (not much), or, for the more technically minded. If you aren't one of these, you may not wish to read further.

All field/attribute definitions are given with conventional C types, a platform-independent byte representation in parenthesis, and the field's name. Field names will always be defined with PascalCaseConvention, and the field's name should be considered similar to a #typedef. Array field definitions will include the element count within square brackets, such as "Foo[10]" to indicate field Foo has ten elements. Instances of a field, the values of a particular file or record, are noted in camelCaseConvention and are enclosed in the <var>…</var> mark-up for "variable", such as "foo[7]". Remember that arrays start with element 0. So foo[6] would actually be the 7th element of the array foo, which corresponds to field definition Foo, which was above defined to be 10 elements (valid indexes range 0-9).

Byte sequences which are SPACE separated are in file-order, such as "76 A4" is equal to the two byte sequence "0xa476". File-order notation is always expressed in hexadecimal.

The marker "(confirmed)" indicates exhaustive testing and verification has been performed, and the marker "(unconfirmed)" indicates speculation or conjecture. A "(confirmed)" mark indicates that all quest file have been looked at, including the CompUSA ones. The absence of a marker does not necessarily imply speculation; sometimes documentation lags behind development considerably. The marker "(observed)" is synonymous with the marker "(known)", and indicates that while no other values have been found in the intrinsic and CompUSA quests, it seems plausible there are other valid values which the Daggerfall Quest Subsystem can handle, but merely have not been applied in the released, official quests.

Quest Filename Format[edit]

Individual quests are composed of two different files found in the ARENA2 Daggerfall directory, the QRC and the QBN file. Each set of QRC/QBN files appear to contain only one quest, which may have different parts. The name of these files affects several aspects of the quest such as which guild the quest belongs to etc... This format is followed by all quests except for ones which begin with $, _, or S. The almost complete filename format of quest files can be found below.

[Byte 0]
Represents which guild the quest belongs to. See Appendix B for a complete list of guild filenames.
[Byte 1]
Always a '0' (0x30)
[Byte 2]
The PC's status relative to guild.
A Joining Guild Quest
B Member's Only Quest
C Non-Member's Quest
[Byte 3]
The minimum reputation (in ASCII representation) with the quest giver required to receive the quest, or minimum player level for certain guilds. Values can range from '0' (0x30) to '9' (0x39) although it is recommended that you not exceed '7' (0x37) for the majority of quests. A value of '5' (0x35) would indicate the quest can only be received by characters with at least 50 reputation.
[Byte 4]
Usually '0' (0x30). If 'X' or 'Y' (0x58 or 0x59), the quest is unavailable with ChildGuard on.
[Byte 5]
Method in which the quest is given to the PC.
Y Quest is Given in Person
L Quest is Given by a Letter
[Bytes 6 and 7]
Any valid filename characters, usually a two-digit number.

The QRC Files[edit]

Each QRC files contains all the text data needed for that quest. The format of these files appears to be completely understood. The file contains variable amounts and variable lengths of data, but the file is nothing more than a Text Record Database; there are no other data elements. Since these files are simply text record databases, modification and enhancement have proved trivial. Because individual TextRecord structures support multiple TextSubrecord structures, a great variety of text can be associated with each type of message or log entry for the quest, which offers to the player considerably variety and diversity.

To briefly summarize, the file opens with a TextRecordDatabaseHeader (at the file's start, Byte 0) which implies how many TextRecord structures the file contains. Following this is a standard TextRecordHeaderList which indicates the TextRecordId and file position for each TextRecord within the file. The remainder of the file is dedicated to the TextRecord structures.

Well-Known TextRecordId Values[edit]

There are some well-known (and indeed appear to be Magic Numbers for the Daggerfall Engine) TextRecordId values. The "get quest" button in the UI, for example, depends on the presence of a TextRecord with an ID# of 0x03e8. While there are numerous OpCodes for displaying (and controlling the display) of any defined TextRecord, these appear to be "Magic Numbers"; they are required for proper function of the engine.

Well-Known TextRecordId values
textRecordId (Hex, file byte order) Text Type
E8 03 Text seen when 'Get Quest' is Pressed
E9 03 When you turn down the quest
EA 03 When you accept the quest
EB 03 'Don't Bother Me' type questor message
EC 03 Guild quest complete message
ED 03 Information/Rumours?
EE 03 Rumours?
F0 03 Information/Rumours?
F1 03 Quest fail message at guild
F2 03 Quest Log Entry
F3 03 Message when Quest item found on body?
10 04 Message when Quest item found on ground?
15 04 Failure message when Quest time expires

These "well-known" values are not necessarily absolute. The "Quest Log Entry" row, for example, is not absolute but merely "most often used"; any TextRecord can be recorded to the player's log via a set of OpCodes depending on various states and events (record an entry when the player meets a specific NPC, or when he acquires a specific item, etc.). More research is necessary with the set of "Magic Numbers". As it stands, the only values of which we are certain are the 0x03e8-0x03eb, 0x03ed-0x03ee, and 0x0415; the remainder seem to be defined on a quest-by-quest basis.

Text Variables[edit]

There are certain sequences of text which the Daggerfall Quest Subsystem will regard as "variables". When a TextSubrecord is displayed, these "variables" are replaced by appropriate text. In essence, they behave like mark-up (wiki, html, sprintf(), etc).

[%string]
Any string preceded with a '%' indicates some sort of variable is to be inserted there. '%pcf' indicates the characters full name, '%pcn' only the first name, etc... A much more complete listing of these can be found in Appendix A at the end of this document.
[=string_]
[==string_]
[===string_]
[_string_]
[__string_]
[___string_]
[____string_]
Any string preceded by and followed with a '_' or '=' indicates some sort of location/item, probably a randomly generated one. This can be a house, dungeon, castle, fort, or some gold, a magic item, etc...
A list of all known underscore-prefixed text variables (and their associated hashes) can be found in the Text Variable Hashes article.
The number of _'s and ='s preceding the string determines how the location type is to be displayed. This is similar to "most specific" or "smallest size" through "most general" or "largest size". There is some overlap, and one would be wise to study and experiment with the quest file sources to determine the effect on a variable-by-variable basis.
Underscore Impacts on Text Variable Display
Modifier Interpretation Item NPC Location Timer Monster
_string_ The name of a person, house, or business. (to do) Name (to do) Duration in minutes Class or creature (like Spriggan)
__string_ The name of a City. (to do) Location name (to do)
___string_ The name of a Place (such as dungeon name or house where someone is) (to do) (to do) (to do)
____string_ The name of a Province (to do) Province name (to do)
=string_ Unknown (to do) Sprite description (to do) Duration in days Name
==string_ Unknown (to do) Faction name (to do)
===string_ Unknown (to do) (to do)

That basically concludes the description of the QRC files, which appears to be very much complete and well understood. We still need, however, a better understanding of the %string variables, including a complete listing of them all (see Appendix A and Text Variable Hashes.

Using TextRecords[edit]

Since a TextRecord is a list of one or more TextSubrecord elements, and a textSubrecord follows a well-known format, some pseudo-code for reading/manipulating TextSubrecord entries is possible.


const SEP = 0xff;
public static String[] GetSubrecords( fileStream, length ) { 
    Char[] chars = (Char[])fileStream.ReadBytes( length );
    totalRecord = new String( chars );
    return totalRecord.Split( SEP );
}

The above exemplifies one means of translating a TextRecord into an array of strings (one for each TextSubrecord). Care should be taken when reading the file. If your language of choice offers 7-bit ASCII mode, the EOL, EOP, and SEP characters might not be read correctly (they each have their 8th-bit set TRUE) while reading files in this mode. If your language of choice offers utf-8 and unicode-16 "auto-detection", the file might not be read correctly at all since the unicode Byte-Order Mark (BOM), 0xfeff, is a valid sequence in a TextRecord. It is suggested when/if creating an editor one reads the data as bytes, and translates into system-characters as per:


public static String[] GetSubrecords( fileStream, length ) { 
    Byte[] bytes = fileStream.ReadBytes( length );
    Char[] chars = new Char[ length ];
    for ( System.Int32 i = 0; i < length; i++ ) { 
        chars[ i ] = (Char)bytes[ i ];
    }
    totalRecord = new String( chars );
    return totalRecord.Split( SEP );
}

This example will eliminate most languages' attempts at "translating" 8-bit bytes into 16-bit unicode chars, thus preserving our 7-bit ASCII chars (the TextSubrecord text) and the 8-bit SEP (0xff) char.

Naturally getting a TextRecord is dependent on reading the TextRecordHeader entry from the file's TextRecordHeaderList. The following code would prove functional:


public struct TextRecordHeader { 
    UInt16 RecordId;
    UInt32 Offset;
}
public static String[] GetSubrecords( fileStream, length, textRecordHeader ) { 
    Int32 oldPosition = fileStream.Position;
    fileStream.Seek( textRecordHeader.Offset );
    Byte[] bytes = fileStream.ReadBytes( length );
    Char[] chars = new Char[ length ];
    for ( System.Int32 i = 0; i < length; i++ ) { 
        chars[ i ] = (Char)bytes[ i ];
    }
    totalRecord = new String( chars );
    fileStream.Seek( oldPosition );
    return totalRecord.Split( SEP );
}

Of course the best solution would be to use a set of Regular Expressions. And that concludes our section on reading/writing the TextRecord file elements.

The QBN Files[edit]

The QBN quest files are the heart and soul of the quest. It is they which tell Daggerfall what kind of quest, quest rewards, location, monsters, items, etc... Unfortunately, discovering the complete format of the QBN file has proved difficult since this file is completely numeric Hex data. The method involves hacking a byte, running Daggerfall to get the quest, and then seeing what, if anything, has changed; definitely a very slow method but significant progress has been made.

QBN Header[edit]

Fortunately there is a regular format to these binary files. Each contains a header preamble, and then a series of "sections". Each section itself contains one or more records, and the format of these records is mostly understood.

[Bytes 0-1] unsigned short (UInt16) QuestId
Reserved, set to 0.
[Bytes 2-3] unsigned short (UInt16) FactionId
Reserved, set to 0.
[Bytes 4-5] unsigned short (UInt16) ResourceId
Reserved, set to 0.
[Bytes 6-14] unsigned char[9] (UInt8[9]) ResourceFilename
Reserved, set to 0.
[Byte 15] unsigned char (UInt8) HasDebugInfo
Non-zero value indicates the presence Text Variable Section, at the end of the file (confirmed). Usually 0.
[Bytes 16-35] unsigned short[10] (UInt16[10]) SectionRecordCount[10]
This is a list of ten ushorts (20 bytes total length), each indicating the count of records contained in the corresponding section.
That is to say, sectionRecordCount[4] indicates how many records are contained in the fifth Section (remember: 0 is the root ordinal in counting, not 1).
If sectionRecordCount[x] is 0x0000, then Section[x] is empty (no entries), and the corresponding sectionOffset[x] can be safely ignored.
Valid value range for a sectionRecordCount[x] element is 0x0000-0x00fd, due to the way the various OpCodes interpret Section elements.
[Bytes 36-57] unsigned short[11] (UInt16[11]) SectionOffset[11]
This is a list of 11 ushorts (22 bytes total length), indicating the offsets (from the start of the file) to each Section.
As with the SectionRecordCount list, this array is associative by index (the sectionOffset[5] reports the offset to the sixth Section).
If sectionRecordCount[x] is 0, then sectionOffset[x] may be ignored.
Only 7 QBN files contain a valid offset for the 11th section (sectionOffset[10]).
[Bytes 58-59] unsigned short (UInt16) Null2
Always 0x0000 (confirmed).

The indexes used in the above SectionOffset and SectionRecordCount arrays are always in the following order:

Section Types by Section Index
Ordinal Index Section Type
0 Items
1 Unimplemented
2 Unimplemented
3 Npcs
4 Locations
5 Unimplemented
6 Timers
7 Mobs
8 OpCodes
9 States
10 Text Variables (optional)

Therefore, sectionRecordCount[6] will report the count of records in the Timers Section, and sectionOffset[3] will report the offset (from the start of the file) to the start of the Npcs Section.

The file up to this point is always the same in structure. What follows depends on the sectionRecordCount[x] and sectionOffset[x] values, because each Section is of variable length and some may even be empty (not all quests have an Items Section, for example).

QBN Section Descriptions[edit]

Each Section's record size varies, but the list below reports the size (in bytes) for each Record of each Section.

Items Section
0x13 Bytes per Record
Section 1
0x5e Bytes per Record
Section 2
0x22 Bytes per Record
NPCs Section
0x14 Bytes per Record
Locations Section
0x18 Bytes per Record
Section 5
0x10 Bytes per Record
Timers Section
0x21 Bytes per Record
Mobs Section
0x0e Bytes per Record
OpCodes Section
0x57 Bytes per Record
States Section
0x08 Bytes per Record
Text Variables Section
0x1b Bytes per Record


Sections 1, 2, and 5 always have a sectionRecordCount of 0 (confirmed). The 11th section, Text Variables Section, is contained in only 7 QBN files. There is no associated sectionRecordCount for the Text Variables Section (a standard "C-Style" array) and that Section is always the last Section in the file (by sectionOffset) and continues to the end of the file (EOF), terminated by the usual null string element.


Items Section[edit]

The Items Section (starting at sectionOffset[0]) describes each of the items specific to the quest (deliverable inventory items such as "drugs", or the infamous "finger", etc). There are sectionRecordCount[0] records in this section, each 0x13 bytes long. Thus, the total length for the Items Section is ( 19 × sectionRecordCount[0] ) bytes long.

[sectionOffset[0] - 0x13 Bytes Long per record]
[Byte 0-1] signed short (Int16) ItemIndex
This is the index number for the item. Some OpCodes will add or remove items from the character's inventory, or "drop" them at certain locations.
Valid value range is 0x0000-00fd (0 through 253). (confirmed)
[Byte 2] unsigned byte (UInt8) Reward
This appears to be an enumeration, since the values below appear to be the only valid values.
While this is related to the base type of reward (such as being paid X gold for successfully completing a quest), each item record must have a value even if it is not a reward, such as items the player must recover from a dungeon or deliver to another NPC.
Well-Known Reward values
Byte 2 Interpreted as
00 Artifact Reward
01 Item Reward
02 Gold Reward
03 Unknown (Appears only in A0C01Y09)
[Bytes 3-4] unsigned long (UInt16) ItemCategory
This value defines the gross category of the item, such as Plant Ingredients, or Drugs.
Valid values are a valid Daggerfall Item Category number ( 0x0000-0x001c ) and 0xffff.
[Bytes 5-6] unsigned short (UInt16) ItemCategoryIndex
Valid values are a valid Daggerfall Item Category Index number and 0xffff.
This value specifies exactly which type of item within the above category, such as Aloe from the Plant Ingredients.
There is no means to specify the material component for any items (if the item can be made from differing materials, such as Iron or Silver). The material of manufacture is determined randomly by the character's level.
If itemCategory is 0xffff and itemCategoryIndex is 0x0000, then this is interpreted as "No Reward", such as the various "Kill the rats" Fighters' Guild quests.
If itemCategory is 0xffff and itemCategoryIndex is 0xffff, then this is interpreted as a random reward. In this mode the reward field determines the type of item.
reward is 0x02
A positive random amount of gold.
reward is 0x01
A single item, selected at random.
reward is 0x00
A single artifact, selected at random.
[Bytes 7-10] unsigned long (UInt32) TextVariableHash
This is the hash value of the variable used in the QRC section.
If the variable "_reward_" should refer to this item, one would supply the value of 0x00001b14.
See the list of list of Text Variable Hashes for the list of known predefined variable hash values.
[Bytes 11-14] unsigned long (UInt32) Null
Always 0x00000000.
[Bytes 15-16] unsigned short (UInt16) TextRecordId1
A valid textRecordId from the associated quest's QRC file, or 0x0000.
If 0x0000, then there is no TextRecord directly associated with this item (although it may still be referenced by the various "display text" OpCodes).
If a valid textRecordId1, this message is displayed when the item is received.
[Bytes 17-18] unsigned short (UInt16) TextRecordId2
A valid textRecordId from the associated quest's QRC file, or 0x0000.
If 0x0000, then there is no TextRecord directly associated with this item (although it may still be referenced by the various "display text" OpCodes).
If a valid textRecordId1, this message is displayed when the item is "used" or "examined" from within the character's inventory screen. This is commonly used for letters, but could be used for anything (such as adding quest-flavour text to mundane quest items).

NPCs Section[edit]

This Section describes all the NPCs (flats) required by the quest, such as those met in Dungeons or Taverns or Temples and so-forth. Each of the sectionRecordCount[5] elements is 0x14 bytes long.

[sectionOffset[3] - 0x14 Bytes per record]
[Bytes 0-1] signed short (Int16) NpcIndexNumber (confirmed)
This index number uniquely identifies the NPC within the quest.
OpCodes which refer to an NPC will specify which NPC by npcIndexNumber, just as items are identified/accessed/associated by their index number.
Valid value range is 0x0000-00fd (0 through 253). (confirmed)
[Byte 2] unsigned char (UInt8) Gender
Valid values may be 0x00ff, 0x01, 0x00, or 0x8c.
If 0xff, the gender of the NPC will be randomly determined. (confirmed)
If 0x01, the gender of the NPC will be Female. (confirmed)
If 0x00, the gender of the NPC will be Male. (confirmed)
Value 0x008c only appears in quest C0B10Y07, and is not understood. (unknown)
[Byte 3] unsigned char (UInt8) FacePictureIndex
This is the index number for the image of the NPC's face in dialog/escort.
It is not completely understood from where the image will be retrieved (FACES.CIF, or TFAC00I0.RCI, or some other source).
It is also not known if the data specified in FLATS.CFG and FACTION.TXT have an effect.
[Bytes 4-5] unsigned short (UInt16) Unknown1
Some purposes of this field are unknown, but observed values are indicative of an enumeration.
Observed values
0x0000, 0x0003, 0x0009, 0x000a-0x000c, 0x000e-0x0012, 0x0014, 0x0015, 0xfff8-0xfffd, 0xffff
(unknown)
0xfffe
The Npc is a Daedra Prince, specified by the FactionIndex field.
[Bytes 6-7] unsigned short (UInt16) FactionIndex (confirmed)
A valid faction number (see FACTION.TXT) or 0x0000.
A value of 0x0000 implies this NPC is not affiliated with any particular faction.
A valid faction number indicates to which faction this NPC is loyal.
Also corresponds to values found in the SAVEVARS.DAT in each save game directory.
If unknown1 is 0xfffe, then factionIndex determines which Daedra Prince. (confirmed)
unknown1 is 0xfffe and factionIndex is 0x0000
The Npc is a random Prince.
unknown1 is 0xfffe and factionIndex is a valid Daedra faction number
The Npc is the Daedra specified by factionIndex
[Bytes 8-11] unsigned long (UInt32) TextVariableHash (confirmed)
This is the hash of the text variable to whom this NPC refers.
Ex: If this NPC should be associated with the variable "_patsy_", then one would specify 0x00000d37
See the list of list of Text Variable Hashes for the list of known predefined variable hash values.
[Bytes 12-15] unsigned long (UInt32) Null
Always 0x00000000 (confirmed).
[Bytes 16-17] unsigned short (UInt16) TextRecordId1 (confirmed)
A valid textRecordId from the quest's QRC file, or 0x0000.
If a valid textRecordId, this Npc will have an entry in the "Tell Me About" conversation topic list.
[Bytes 18-19] unsigned short (UInt16) TextRecordId2 (confirmed)
A valid textRecordId from the quest's QRC file, or 0x0000.
If a valid textRecordId, this Npc will have an entry in the "Tell Me About" conversation topic list.

Locations Section[edit]

This Section describes all the locations which are required for the quest. This includes everything from Taverns and Houses inside towns (same or different), to Dungeons and Shrines and Covens.

[sectionOffset[4] - 0x18 Bytes per record]
[Bytes 0-1] unsigned short (UInt16) LocationIndex (confirmed)
This is the index number of the location, by which other sections of the file will refer to this Location.
Valid value range is 0x00-fd (0 through 253). (confirmed)
[Byte 2] unsigned char (UInt8) Flags
Reserved, set to 0.
[Byte 3] unsigned char (UInt8) GeneralLocation
This field specifies the overland map locale for the Location record.
Valid (observed) values are from 0x00 through 0x02.
If 0x02, this location is outside of the current town (a Dungeon, or another Town).
If 0x01, this location is inside the current town (such as found in the "Kill the monster in the house" quest).
If the value is 0x00, then this location is a specific (not pseudo-random) Location (the storyline quests follow this pattern).
[Bytes 4-5] unsigned short (UInt16) FineLocation
This field is related to the previous, where this determines the Location within the town map.
If the value is 0x0000, then the location is a building within a town.
If the value is 0x0001, then the location is a Dungeon.
If the GeneralLocation is 0, this is the higher 16 bits of the location's ObjectID.
Only the storyline quests have values within the range 0xc3-ff. (confirmed)
[Bytes 6-7] short (Int16) LocationType
Building or dungeon type (-1 means random).
If the GeneralLocation is 0, this is the lower 16 bits of the location's ObjectID.
[Bytes 8-9] short (Int16) DoorSelector
If the value is -1, use any suitable location.
If the value is 0, consider only the doors having a 0x4000 flag set.
If the value is 1, consider only the doors having a 0x1000 flag set.
[Bytes 10-11] unsigned short (UInt16) Unknown2
An unknown value.
[Bytes 12-15] (long) TextVariableHash (confirmed)
This is the hash of the text variable with which this location should be associated.
Ex: If one wanted to associate the text variable "_mondun_" with this location, one would specify 0x00001ae8 for this value.
See the Text Variable Hashes article for the known values.
[Bytes 16-19] unsigned long (UInt32) ObjPtr
Reserved, set to 0.
[Bytes 20-21] unsigned short (UInt16) TextRecordId1 (confirmed)
A valid textRecordId or 0x0000.
If a valid textRecordId this location will be available in the "Tell Me About" conversation dialog. (confirmed)
[Bytes 22-23] unsigned short (UInt16) TextRecordId2 (confirmed)
A valid textRecordId or 0x0000.
If a valid textRecordId, then this location will be available in the "Tell Me About" conversation dialog. (confirmed)

Timers Section[edit]

This Section deals with all the timers, intervals, and durations in the quest (such as "you have 22 days to return with the item"). This Section is also the least understood.

[sectionOffset[6] - 33 Bytes per record]
[Bytes 0-1] signed short (Int16) TimerIndex
This is the index number by which other sections (particularly the OpCodes) may access the timer (starting/stopping it).
Valid value range is 0x0000-00fd (0 through 253). (confirmed)
[Bytes 2-3] unsigned short (UInt16) Flags
Various flags controlling the timer arguments and its current state.
[Byte 4] unsigned char (UInt8) Type
Type of the timer. Possible values:
0 Random duration
1 Fixed duration
2 One location or NPC
3 Two locations/NPCs, only one dungeon (gives extra week in some circumstances)
4 Same as 2?
5 Two locations/NPCs, both are dungeons (gives up to 2 extra weeks in some circumstances)
[Bytes 5-8] signed long (Int32) Minimum
Minimum time value in game minutes.
[Bytes 9-12] signed long (Int32) Maximum
Maximum time limit as above (or 0).
[Bytes 13-16] unsigned long (UInt32) Started
Reserved. Set to 0.
[Bytes 17-20] unsigned long (UInt32) Duration
Reserved. Set to 0.
[Bytes 21-24] (long) (Int32) Link1
The 1st NPC or a location Id associated with this timer
[Bytes 25-28] (long) (Int32) Link2
The 2nd NPC or a location associated with this timer
[Bytes 29-32] unsigned long (UInt32) TextVariableHash
The name of the state this timer controls.
Ex: To associate the state "traveltime" with this timer, one would specify a value of 0x0001c1e3 for this field.
See the Text Variable Hash article for full list of Text Variables and their associated hashes.

A great deal of research is still required to accurately use this Section when authoring quests, but this is the last remaining section of any great mystery.

Mobs Section[edit]

This section defines all the quest-specific mobs found in the quest. First, a "mob" is a "mobile", which comes from the MUD community, which basically means any of the computer controlled monsters. Secondarily, this doesn't impact the random monsters found in a dungeon (that is determined by the player's level); it only relates to quest-specific mobs (such as "assassinate the knight" or "kill the rats" quests).

[sectionOffset[7] - 0x0e Bytes per record]
[Byte 0] unsigned char (UInt8) MobIndex (confirmed)
The value of this index is how other sections will refer to the mobile defined by this record, analogous to ItemIndex or NpcIndex.
Valid value range is 0x00-fd (0 through 253). (confirmed)
[Bytes 1-2] unsigned short (UInt16) Null1
Always 0x0000 (confirmed)
[Byte 3] unsigned char (UInt8) MobType (confirmed)
This value specifies the type of mob (such as a rat or a monk).
Valid values are 0x00-0x28, 0x80-0x8d, which are Daggerfall Mobile Type values.
[Bytes 4-5] unsigned short (UInt16) MobCount (confirmed)
The count of mobiles defined for this index.
Valid value range is 0x01-06.
[Bytes 6-9] unsigned long (UInt32) TextVariableHash (confirmed)
This is the hash of the text variable with which this location should be associated.
Ex: If one wanted to associate the text variable "_knight_" with this Mob record, one would specify 0x00001a68 for this value.
See the Text Variable Hashes article for the known values.
[Bytes 10-13] unsigned long (UInt32) Null2
Always 0x00000000 (confirmed)

OpCodes Section[edit]

This Section actually defines a set of OpCodes which the Daggerfall Quest Subsystem executes in a manner very similar to a Virtual Machine. While this is not as advanced as the Java Virtual Machine, or the .Net Runtime Engine, it has proved to be quite extensible and fairly complete for all quest needs. In simplest terms, it would seem the Daggerfall Quest Subsystem creates an array of function pointers "under the hood", and use the OpCode as the index of the function to execute, passing a pointer to the record (each 0x57 bytes long) as an argument. There are several dozen understood OpCodes, all of which are used by at least one quest within the game's intrinsic quests or CompUSA quests.

[sectionOffset[8] - 0x57 Bytes per record]
See the special section for complete documentation on this Section. As the "brain" of the quest, it tells the game things like what Mobs to add, when to add log entries, so-on and so-forth.

States Section[edit]

State records describe state/flag variables used by the Daggerfall Quest Subsystem for tracking events throughout the quest. For example, slaying a Mob might trigger one state variable to be set TRUE, or meeting an NPC might reset another state variable to FALSE. Some OpCodes even offer rather complex if/else decision branching based on one or more state variable values. Many of the Dark Brotherhood and Vampire quests, for example, make use of around 20 different state variables to offer some of the richest and complex quests.

This entire Section has been confirmed.

[sectionOffset[9] - 0x08 Bytes per record]
[Bytes 0-1] signed short (Int16) FlagIndex
This is the index number of the quest's state variable, and it is by this index number the OpCodes section may refer to a state.
Valid value range is 0x0000-00fd (0 through 253). (confirmed)
[Byte 2] unsigned byte (UInt8) IsGlobal
This value indicates if this quest variable is accessible outside the current quest scope (from another quest).
This value may be treated as a boolean (0 would be FALSE, and any other value TRUE).
This is usually 0 except for storyline quests, where such permanency of state is necessary to offer a continuous story.
[Byte 3] unsigned byte (UInt8) GlobalIndex
If isGlobal is TRUE, this value is the index of the Global state variable to which this quest state variable should be linked.
[Bytes 4-7] unsigned long (UInt32) TextVariableHash
This is the hash of the text variable with which this state should be associated.
Ex: If this NPC should be associated with the variable "_oneday_", then one would specify 0x00001ab3 for this field.
See the list of list of Text Variable Hashes for the list of known predefined variable hash values.

Text Variables Section[edit]

This (optional) Section is only included in 7 files: 80C00Y00.QBN, A0C00Y04.QBN, A0C00Y06.QBN, N0C00Y01.QBN, O0B10Y00.QBN, P0B1XL08.QBN, and R0C40Y23.QBN. This Section is a list of several variable names. Since these define TextVariable objects, valid character range is 0x30-39 and 0x61-7a (TextVariables are always lower-case). If present, this Section always exists at the end of the QBN file and continues through to the file's end (EOF). A variable name beginning with the null-terminator token indicates no more strings follow.

[sectionOffset[10] - 0x1b Bytes per record]
[Bytes 0-19] 7-bit ASCII string TextVariable
This is a standard "C-style" string, where the string is represented as a character array (char[ 20 ]). The end of the string is identified by the null-termination token (0x00).
[Byte 20] unsigned char (UInt8) SectionId
[Bytes 21-22] unsigned short (UInt16) RecordId
The record which is labeled with this variable.
[Bytes 23-26] unsigned int (UInt32) RecordPtr
Reserved; set to 0.
When a QBN file has a Text Variable Section, the table contains all TextVariables whose hash values are used in file's other Section records.
See the Text Variable Hashes article for the algorithm to compute a TextVariableHash from a TextVariable.

Credits[edit]

I could not have done all this without much help from the many other Daggerfall addicts out there (list is in no particular order).

Peggy Hanks - df4@juno.com 
For donating much new information for the quest file formats.
Lord Phoenix - gozer@esoterica.pt 
For donating information on the files formats as well.
Michael Schneider - michael@cybermagician.com 
Maintains a Quest Hacking guide on Daggerweb and has also created a quest editor for Windows, and of course has provided much new information.
Glen Wright - glen@skatter.usask.ca 
Provided some more very useful information on the structure of the QBN files.
Skeleton Man 
Has the most experience in actually editing and creating quests.
Thomas Hautesserres - hautesse@cert.fr 
Author of the fabulous WinQEdit which has helped deciphering QBN format a great deal.

If I've forgotten anyone I can assure you it's not on purpose. Just e-mail me and we'll clear things up in a jiffy (anyone know how long that is perchance?). If you'd like to help out in some way, feel free to make it known to me as I'm sure I could find something you could do. Just e-mail me at aj589@freenet.carleton.ca. I'll take suggestions for the quest editor, comments on this document, and of course any data on the quest formats.

Quest Related Programs[edit]

Many useful files can be found in the Daggerfall Files article. At the moment there are only two Daggerfall quest editors, but they are all you really need.

WINQEdit
A great QBN editor for windows. Requires knowledge of hex-editing and the quest format. Can be downloaded here.
DMPQuest
A great QRC editor for windows. Easy to use since it does not require any hex-editing. Can be downloaded here.

Appendixes[edit]

Appendix A[edit]

Listing of %string Variables==

Variable Description   Variable Description   Variable Description
 %1am 1st + Magnitude    %fx2 Another faction in news    %olf What happened to %ol1
 %1bm 1st base Magnitude    %g He/She etc...    %oth An oath (listed in TEXT.RSC)
 %1com Greeting (?)    %g1 He/She ???    %pcf Character's first name
 %1hn  ?    %g2 Him/Her etc...    %pcn Character's full name
 %2am 2nd + Magnitude    %g2self Himself/Herself etc...    %pct Character's title in guild
 %2bm 2nd Base Magnitude    %g3 His/Hers/Theirs etc...    %pdg Days in jail
 %2com  ?    %gii Amount of gold in hand    %pen Prison sentence
 %2hn  ?    %god Some god (listed in TEXT.RSC)    %per Amount of Personality
 %3hn  ?    %gtp Fine    %plq Place of something in log.
 %a Cost of something.    %hea HP Modifier    %pnq Person of something in log
 %ach + Chance per    %hmd Healing rate modifier    %pqn Potential Quest Giver
 %adr + Duration per    %hnr Your title?    %pqp Potential Quest Giver's Location
 %agi Amount of Agility    %hnt Direction of location.    %ptm An enemy of the current region (?)
 %ark Considered for stat    %hol Holiday    %q1 to %q5 Effects of questions answered in bio.
 %arm Armor    %hrg  ?    %qdt Quest date in log
 %ba Book Author    %hs Holding Soul type    %qot The log comment
 %bch Base chance    %htwn  ?    %qua Condition
 %bdr Base Duration    %int Amount of Intelligence    %r1 Commoners rep
 %bt Book title    %it Item    %r2 Merchants rep
 %clc Per level (Chance)    %jok A joke    %r3 Scholars rep
 %cld Per level (Duration)    %key A location (?)    %r4 Nobilities rep
 %clm Per level (Magnitude)    %key2 Another location    %r5 Underworld rep
 %cn Current City    %kg Weight of items    %ra Player's race
 %cpn Current shop name    %kno Appears to be a guild name    %reg Region
 %cri Accused crime    %lev Rank in guild that you are in.    %rn Regent's Name
 %crn Current Region    %ln Random lastname    %rt Regent's Title
 %dae A daedra    %loc Location marked on map {    %spc Current Spell Points};
 %dam Damage modifier    %lt1 Title of %fl1    %scn Total Spell Points
 %dat Date    %ltn In the eyes of the law you are.......    %ski Skill
 %di Direction    %luc Luck    %spd Speed
 %dip  ?    %mad Resistance    %str Amount of strength
 %dng Dungeon    %map A location on the main map {    %t Regent's Title};
 %dts Daedra    %mat Material    %tcn Travel to city
 %enc Encumbrance    %mit Item    %thd Combat odds
 %end Amount of Endurance    %mn Random First(?) name (Male?)    %tim Time
 %fcn Another city    %mn2 Same as %mn (?)    %vam Vampire Name
 %fl1 Lord of %fx1    %mod Modification    %vcn Vampire's Clan
 %fl2 Lord of %fx2    %mpw Magic powers    %wdm Weapon damage
 %fn Random first(?) name (Female?)    %n A random person/Person you are talking to.    %wep Weapon
 %fn2 Same as %mn2 (?)    %nam Came up empty for me    %wil Amount of Willpower
 %fon Name of Knightly Order/Guild/Temple (?)    %nrn Noble of the current region    %wpn Poison (?)
 %fx1 A faction in news    %ol1 Old lord of %fx1    %wth Worth

Many thanks to James Dean (james@rygannon.force9.co.uk) for donating many of the string variables and descriptions.

Appendix B[edit]

Listing of Guild Quest Filenames

Below is a complete list of all types of quest file names contributed by several people. The character under the Filename heading represents the first character of a QRC or QBN file.

Filename Guild / Group   Filename Guild / Group
_ Starting quests (Tutor and Initial)   H The Benevolence of Mara
$ Vampire/Lycanthropy Cure Quests   I The Temple of Stendarr
0 School of Julianos   J The Resolution of Zenithar
1 Meridia   K Merchant Quests
2 Molag Bal   L Dark Brotherhood
3 Namira   M Fighters Guild
4 Nocturnal   N Mage Guild
5 Peryite   O Thieves Guild
6 Sheogorath   P Vampire's Quests
7 Sanguine   Q Coven Quests
8 Malacath   R Royalty Quests
9 Vaermina   S Main Quests
A Commoner's Quests ???   T Lady Azura, Crimson Gate (Daedra Lady)
B Knightly Order   U Prince Boethiah's Quest (Daedra Prince)
C Temple quests   V Clavicus Vile's Quest (Daedra Lord)
D The Akatosh Chantry   W Hermaeus Mora's quest (Daedra Lord)
E The Temple of Arkay   X Hircine's Quest (Daedra Lord)
F The House of Dibella   Y Mehrune Dagon's Quest (Daedra Lord)
G The Kynaran Order   Z Mephala's Quest (Daedra Lord)