Dialogue Modding – pt 2 – Basics

Locating the lines

The first thing to do is to locate where in the file the lines we want to mod are located. Unfortunately, neither the search features in pyGFF nor the toolset work on this sort of file, so we’ll first need to convert the file to a format that can be easily searched. Open the dialogue or conversation in pyGFF, Save As, and change the file type to YAML, which can be opened in any text editor. (h/t to @quenched-steel-modding for much appreciated assistance divining this method)

The YAML format won’t include the sequential line IDs, which doesn’t help if you need to figure out where exactly a line is in the file or determine which lines are linked in the children list, so we need to go one step further.

For each conversation I edit, I personally like to start with a document that contains nothing but the line ID and string reference for each line in that file, which I can then use as a reference to take notes and to copy and paste from the talktable. Here’s how I get that:

Open the YAML in Notepad++, ctrl+F to Find, and then search for 30201 (for DA2) or LINE_TEXT (for DAO) using Find All in Current Document. Copy and paste the search results into a new document.

Now switch over to Replace, switch the search mode to Regular expression, and tick on “. matches newline.”

Find what: ,.+?\[

Replace with: \r\n

This will strip out everything but the string references and a little bit at the start and end of the document can be manually deleted. Then hit ctrl+A, tab, and alt+C and insert numbers counting from 0.

If you don’t know how to search the talktable, refer to the previous part of this tutorial. If you know exactly what line of dialogue you’re looking for, you can search for it in the talktable to get the string reference, then search for the string reference in this text file to get the line ID. If you need to search for anything other than the string reference – say you’re looking for all lines with specific plot flags – you can instead do this search in the YAML, scroll up to get the string reference, and repeat.

Bookkeeping

However you decide to keep track of the lines you need and the changes you’ve made to them – and I absolutely recommend you keep track of both – you will probably want to note down at the very least the line ID, the string reference and string, the children list, and any conditions.

Changing the conversation by editing conditions

Conditions are very, very powerful, and very easy to locate and change.

As a refresher: a condition consists of a plot (identified by GUID), a flag, and a boolean (true/false). The game checks to see if the condition matches the data in the save game, and if it does, the line will play. If not, it continues to check the next child line in the sequence. A line without a condition will always play (or always be a selectable PC response). There must always be at least one line in the list that has no condition, or the conversation might quit abruptly. If it’s an owner/speaker line, it must be last on the list, or it will prevent the lines below it from playing.

If you want a line to play under different circumstances

You can replace the plot GUID and flag to swap the plot flag out entirely. This is what I did for my Awakening non-circle mage fix, as well as to fix the broken plot flag in Zevran’s dialogue.

If you want a line to always play

You can remove the condition entirely and it will override any lines lower than it on the list. You must use the toolset to delete conditions. pyGFF won’t convert the empty string to a null string and the line won’t play as intended. Delete the CONVERSATION_PLOT_GUID (in pyGFF this null string displays as a question mark) and change the plot flag to -1.

(If you know what you’re doing you can fix the null string in a hex editor in a pinch. The string reference is little endian, and you’ll find a one byte pointer that will need to be overwritten with FFFFFFFF. If that didn’t make sense, don’t try it, use the toolset.)

If you want a line to never play

You can alter the condition to never return a positive. If modding DAO files, the easiest way to do this is to use a debug script that is included in the toolset for this purpose: add zz_return_false to the CONVERSATION_SCRIPT field.

This is not an option in DA2 files. You will have to remove the line from the link list or hide it under another line without a condition instead. Do not delete the line. This is trickier, because you’ll have to find every branch in the conversation that links to that line and change each one individually, or the line may still play under some circumstances.

Try not to make assumptions about what plot flags may return always false. I had to update my DAI bi Cassandra mod after learning that, in some save games (including one of mine I hadn’t used for testing), plot 00000000-0000-0000-0000-000000000000 flag 0 would return true.

You can have a much finer degree of control over the conversation by altering the child line list. Every line that can play after one finishes must be linked. Keep in mind the alternating speaker->listener structure of the conversation should be maintained. Most branching line lists are located on empty-string “continue” lines. If you’re going to be doing much re-pathing I recommend starting from the earliest relevant line and manually following the child lines in the list to make sure the relevant parts of the branch are fully accounted for.

You can add or delete links (again don’t ever delete lines ever). You can also rearrange them to alter the priority with which they play.

To delete links, just hit the delete key. To add a link go ahead and copy and paste one line on the list and then change the value to match the new line you want to link to. The only time finding and copying an existing link to that line from elsewhere in the conversation would be faster is if you’re making changes to the DA2 dialogue wheelYou must use pyGFF to rearrange links. Just select the link list (not the links themselves) and use the doohickey to shuffle them around to your heart’s content. You can also add or remove links down here if you want.

Be careful when adding new linked lines that you only add lines from that section of the conversation. Once you link to that branch you’re stuck on that branch.

Adding new player responses

Cloning and adding new lines does not normally fall under basic editing – it will be covered in more depth in a later post. Actually adding edited vo into a conversation and making sure the facefx and animations play correctly can be a complicated process even with the toolset. Without the toolset it’s a far more complex endeavor. And without access to the sound tools used to compile the DA2 wwise soundbanks, adding new voiced lines to DA2 is currently beyond us.

The simple exception to this complicated problem is adding an unvoiced player response in DAO. It’s… well, it’s pretty easy.  Just duplicate one of the player *RPLY lines in the list you want to add to (that goes to the owner response you want it to go to) and make sure it ends up all the way down at the bottom. Very last line in the file. Very important. As with deleting lines, you don’t want to do anything that will alter the sequential IDs of the individual lines as that will break the entire conversation. You can add or change the condition if you want, and then add a local string.

Local strings

You’ll be familiar with local strings if you’ve ever opened a .dlg (or a .uti or etc.) after exporting them from the toolset, as the toolset… for some reason… exports local strings which will override the string reference. Which is why dialogue and item mods show up in english in non-english localized games even if the text hasn’t been altered which I’m 100% sure is frustrating as all get out, but it’s actually useful here.

Here’s what that new line ends up looking like:

You can see pyGFF has separate fields for the string reference (don’t bother altering that) and string, while in the toolset you have to manually add a colon after the string reference and type the new string into the same field.

New line edited to satisfaction, go back up to that original link list and add in the link.

Recall that as with removing conditions, if you’re working in pyGFF you will have to switch to the the toolset to fix null strings if the duplicate line lacks a condition.

(I haven’t touched much on actions at all although you can see in pyGFF there’s one present in the copied/altered line – almost definitely an approval gain. If you want to alter actions I’m going to assume you’re already familiar with the concept, but basically edit them the same way you would conditions.)

Moving forward

If you can find your way around the dialogue you can do quite an impressive amount with simply rerouting lines and altering conditions and actions. It’s a full account of every technique I’d used in a published mod at the initial time of writing.

While these first two basic tutorials have been equally applicable to modding both DAO or DA2, further parts of the tutorial, which delve into more complicated subjects, will be more oriented toward modding DA2 and detailing its specific, more complex, file structure. The reason for this is that familiarity with the toolset dialogue editor should make the relatively-straightforward structure of DAO dialogue files pretty clear, and the ability to use the developer-provided tools to natively create and export things like cutscenes, stages, or even new soundbanks and facefx, should get you a long way.