D File Format
NB. Description taken from Weidu readme, with permission. Check weidu.org for latest information, as this information is subject to rapid change.
The D file format is a way of describing Infinity Engine dialogues and modifications to Infinity Engine Dialogues in a portable, easy-to-understand format. It supports foreign language translations and allows you to describe extensions to existing game dialogues without forcing you to describe their content. This allows you to write mods that work with mods written by others.
The D file format is presented here in an extended context-free grammar notation. If you are unfamiliar with CFGs, take a look http://www.wikipedia.com/wiki/Context-free_grammar or http://www.cs.rochester.edu/users/faculty/nelson/courses/csc_173/grammars/cfg.html. You don't really need to understand a CFG formally, though.
To get a real idea of how they work, use WeiDU to create JAHEIRA.D for yourself and look at it in a text editor. You can also browse the examples and test directories that come with WeiDU.
All of the syntax keywords are given in a UPPERCASE COURIER. All other keywords are symbolic. Notes:
- bar list means "0 or more copies of bar".
- [ foo ] means "an optional foo" or "0 or 1 copies of foo".
- foo bar ... means "you may repeat foo bar as often as you like here".
|D File||A D file is a text file that contains a number of D Actions. D Files tell WeiDU how to create and modify Infinity Engine DLG files.|
|is||D Action list||A D File is a list of D Actions. Typically the first and only one is BEGIN, which defines the content of a new dialogue. Other D Actions can be used to modify existing dialogues.|
|D Action||A D Action tells WeiDU how to create or modify Infinity Engine DLG files.|
|is||BEGIN filename [ nonPausing ] state list||BEGIN tells WeiDU that you are creating a new DLG file from scratch. Any existing DLG file with the same name will be overwriten. The new DLG file contains exactly the states in the list. If you set nonPausing to a non-zero integer, the game will not ``stop time'' while the conversation takes place. By default time stops during conversations.|
|or||APPEND filename state list END||This tells WeiDU to place the given states at the end of the already-existing dialogue filename.DLG.|
|or||CHAIN [ IF [ WEIGHT #weight ] stateTriggerString [ THEN ] ] entryFilename entryLabel chainText list chainEpilogue||This instructs WeiDU to make a long conversation in which the PC can say nothing. This is useful when you want the NPCs to talk among themselves for a long time. It and its friends, INTERJECT and INTERJECT_COPY_TRANS can incredible time-savers when you're writing non-trivial dialogue. See the examples for ideas. CHAIN will only append to existing dialogues. You cannot use CHAIN to create a new DLG.|
|or||INTERJECT entryFilename entryLabel globalVariable chainText list exitFilename exitLabel||Behaves like CHAIN except that all of the chainText is additionally guarded by the transition predicate Global("globalVariable","GLOBAL",0) and accompanied by the action SetGlobal("globalVariable","GLOBAL",1). If you pick globalVariable to be unique, this will ensure that the chainText is only ever seen once per game. This is useful for making interjections.|
|or||INTERJECT_COPY_TRANS entryFilename entryLabel globalVariable chainText list||This behaves just like INTERJECT except that the exitFilename and exitLabel are not present. Instead, whenever the dialogue would pass out of the chainText it follows a copy of the transitions that were at the state with stateLabel originally. This is convenient for making quick interjections from NPCs that do not actually change the true flow of the conversation. See the transition COPY_TRANS for more information about this idea.|
|or||EXTEND_TOP filename stateLabel list [ #positionNumber ] transition list END||This instructs WeiDU to add the transitions in list to the top of
the transition list for the specified states in filename.DLG
(which must already exist).
If a positionNumber is given, WeiDU to insert the transitions just between already-existing transitions #positionNumber and #positionNumber+1 in the given states for the given file. The first transition is number 1.
|or||EXTEND_BOTTOM filename stateNumber list [ #positionNumber ] transition list END||Behaves just like EXTEND_TOP but adds the transitions to the bottom of the list instead.|
|or||ADD_STATE_TRIGGER filename stateNumber stateTriggerString [ stateNumber list ]||This instructs WeiDU to add the stateTriggerString to all of the states with the given stateNumbers in the file filename.DLG (which must already exist). This is handy for adding extra conditions to an existing dialogue state.|
|or||ADD_TRANS_TRIGGER filename stateNumber transTriggerString [ stateNumber list ]||This instructs WeiDU to add the transTriggerString to all of the transitions in all of the states with the given stateNumbers in the file filename.DLG (which must already exist). This is often used in conjunction with EXTEND_BOTTOM to make a new branch in an existing state. Use ADD_TRANS_TRIGGER to add the negation of some predicate to all of the existing transitions, then use EXTEND_BOTTOM to add a transition with that predicate to that state.|
|or||REPLACE filename state list END||This instructs WeiDU to load filename.DLG and replace some of its states with the new ones described in the state list. All of the states should have numeric stateLabels (e.g., "5" or "67"). A new state with label X will replace the old state number X.|
|or||SET_WEIGHT filename stateLabel #stateWeight||This instructcs WeiDU to destructively change the WEIGHT of the given state in filename.DLG (which must exist). This should only be used to patch or workaround existing dialogues. Never use SET_WEIGHT if you can help it.|
|or||REPLACE_SAY filename stateLabel sayString||This instructs WeiDU to destructively change the sayString of the given state in filename.DLG (which must exist). This should only be used to patch or workaround existing dialogues. Never use REPLACE_SAY if you can help it.|
|or||REPLACE_STATE_TRIGGER filename stateNumber stateTriggerString [ stateNumber list ]||This instructs WeiDU to destructively set the stateTriggerString of all of the states with the given stateNumbers in the file filename.DLG (which must already exist). It should be used with caution.|
|or||REPLACE_TRIGGER_TEXT filename oldText newText||This instructs WeiDU to destructively replace every occurrence of oldText (which may be a regexp) in the stateTriggerStrings and transTriggerStrings of filename.DLG (which must exist). This should only be used to patch or workaround existing dialogues. Never use this if you can help it.|
|or||REPLACE_ACTION_TEXT filename oldText newText||This instructs WeiDU to destruveily replace every occurrence of oldText (which may be a regexp) in the stateActionStrings of filename.DLG (which must exist). This should only be used to patch or workaround existing dialogues. Never use this if you can help it.|
|or||REPLACE_ACTION_TEXT_PROCESS filename oldText newText||This instructs WeiDU to destruveily replace every occurrence of oldText
(which may be a regexp) in the stateActionStrings
of filename.DLG (which must exist) with newText. However,
newText is first compiled as a BAF action list. In particular,
this means that replacing with commands like:
~DisplayString(Myself,@123)~... will do what you expect. This should only be used to patch or workaround existing dialogues. Never use this if you can help it.
|chainEpilogue||Determines where the dialogue should flow at the end of the CHAIN.|
|is||END filename stateNumber||Transfer to the given state in the given dialogue file.|
|or||EXTERN filename stateNumber||Transfer to the given state in the given dialogue file.|
|or||COPY_TRANS filename stateNumber||At the end of the CHAIN text, copy all transitions from the given state in the given file. This is useful for interjections (see INTERJECT).|
|or||EXIT||At the end of the CHAIN text, exit the dialogue.|
|or||END transition list||Execute the given transitions after the final state in the CHAIN.|
|state||In Infinity Engine games, this is the fundamental unit of dialogue.|
|is||IF [ WEIGHT #weightNumber ] stateTriggerString [ THEN ] [ BEGIN ] stateLabel SAY sayText [ = SayText ... ] transition list END||When you start conversing with a creature that uses a DLG file, the
Infinity Engine searches through all of the states in that file
in order of increasing WEIGHT and selects the first one it finds
for which the stateTriggerString is both true and not empty.
The creature then says all of the associated sayText. Finally,
the transitions are evaluted in bottom-up (i.e., reverse) order.
If a transition is found with a transTriggerString that
evaluates to True and no replyText, that transition is
immediately executed. Otherwise, all of the transitions are
presented as options to the PC.
If a stateLabel is an integer it is called a stateNumber. All of the states in the DLG files that come with the original game use stateNumbers. Only D files use symbolic strings for stateLabels.
Including more than one bit of sayText here is often called Multisay.
Finally, once you are familiar with the syntax you may omit the THEN and BEGIN keywords if you like.
|or||APPENDI filename state list END||This is legacy syntax that behaves just like the D Action APPEND but is considered a state. Avoid it.|
|or||CHAIN2 entryFilename entryLabel chain2Text list exitFilename exitLabel||This is legacy syntax that behaves somewhat like the D Action CHAIN but is considered a state. In addition, chain2Text is slightly different from chainText. Avoid this construction.|
|transition||Transitions determine how dialogue flows from one state to another.|
|is||IF transTriggerString [ THEN ] transFeature list transNext||If the transTriggerString evaluates to true or is empty, this transition is viable. If it contains no replyText within its transFeature list, it is immediately taken. Otherwise, the replyText is presented as an option to the user. If the transition is taken, any actions in the transFeature list are performed and the dialogue flows to the point indicated by the transNext. transitions are evaluated in "reverse order". That is, the "bottom" or "last" response for a state is checked first. If its transTriggerString evaluates to true and it has no REPLY text, that transition is immediately taken. See SAREV25A state 1 for an example of a state with all kinds of transitions.|
|or||+ [ transTriggerString ] + replyText transFeature list transNext||This abbreviated syntax for transitions that would contain REPLY (which is by far the most common case) allows you to save yourself some time and typing. It behaves like the full form above.|
|or||COPY_TRANS filename stateLabel||This instructs WeiDU to copy all of the transitions from the
state with the given stateLabel in filename.DLG. This
copying takes place before all other D Actions. For example,
this is a valid transition list:
IF ~Before()~ THEN GOTO my_state COPY_TRANS PLAYER1 33 IF ~After()~ THEN EXTERN SOLA 55
|transFeature||These are features or actions associated with taking a transition.|
|is||REPLY replyText||If this transition is taken, the PC says the replyText.|
|or||DO stateActionString||If this transition is taken, the stateActionString is executed.|
|or||JOURNAL text||If this transition is taken, the text is added to the PC's journal.|
|or||SOLVED_JOURNAL text||If this transition is taken, the text is added to the ``solved'' section of the PC's journal.|
|or||UNSOLVED_JOURNAL text||If this transition is taken, the text is added to the ``unsolved'' section of the PC's journal.|
|or||FLAGS integer||This allows you to set the features associated with a transition directly using the binary format of DLG files. Do not use this!|
|transNext||This determines where dialogue flows after a transition has been taken.|
|is||GOTO stateLabel||The dialogue continues at the state with label stateLabel in the same DLG file as the current state.|
|or||EXTERN filename stateLabel||The dialogue continues at the state with label stateLabel in the file filename.DLG.|
|or||EXIT||The conversation ends.|
|or||+ stateLabel||This is a synonym for GOTO.|
|chainText||This is a rapid shorthand for chaining together many little bits of dialogue when the PC is not saying anything.|
|is||[ IF transTriggerString THEN ] sayText = sayText ...|
|followed by||[ == fileName [ IF transTriggerString THEN ] sayText = sayText ... ]||The == (that's two consecutive equal signs) marks the beginning of a new speaker (indicated by fileName). If the transTriggerString is true or if it is not present, this new speaker says all of its sayText in order.|
|text||This represents strings that are shown to the player, rather than strings that the game uses internally for predicates and actions.|
|is||string [ [WAVEFILE] ]||The given string is used for both male and female players. The optional [WAVEFILE] is the associated sound.|
|or||string [ [WAVEFILE] ] string [ [WAVEFILE] ]||The first string and soudn file are used if the PC is male, the second string and sound file are used if the PC is female. This is useful mainly for international versions of Infinity Engine games.|
|or||#integer||The string with reference number #integer from DIALOG.TLK should be used unchanged.|
|or||@integer||The last definition of the translation string @integer given in any TRA file should be used.|