Portrait Dialogue

Introduction

This Dragon Age: Origins mod is intended for those creating adventures with limited to no voice overs. To help facilitate this, it completely revamps the conversation UI to help bring focus to the text instead of the 3D scene.

portraitdlg.jpg

See also custom tokens for making use of custom codex and conversation tokens.

Project page

The current project is hosted on the BioWare Social Network, available [TBD]. Feel free to give feedback about it, good or bad.


PC response lines

If you want the PC response lines to be quickly available, you'll have to check "No VO in Game" for every NPC line. I know this is tedious, but perhaps there's a solution in doing it in bulk using SQL at some point.


NPC speaker name

Basics

In order for the mod to infer the NPC speaker's name and display it inline with the text, you have to check in your creature resources and export the talk table from the toolset (Tools > Export > Export Talk Table). Checking in your creature resources updates the exported creature text. Check in your placeables too if any of them are conversation owners. This process is necessary given how the mod requires a workaround to even automatically get this information at all. It probably doesn't hurt either to check in your dialogue resources as well - if you want the conversation history in the journal to work correctly, you'll have to anyway.

Limitations

There are some things to watch out for.

  • Conversations with the PC as the speaker and as the listener:
UT_Talk(GetHero(), GetHero(), R"some_conversation.dlg")

What the mod does in this situation is act as if the speaker name is not available and treat it as if it were a cutscene, so no portrait and with the text centered near the bottom of the screen. (Interestingly, this seems to leave a blank line in the journal's conversation history and the inferred speaker name is actually Jaden, which is the default player name that isn't normally exposed. So you're out of luck if you make the Jaden creature resource an NPC and make him talk - but you shouldn't be doing that in the first place. If you use GetPartyLeader() as the speaker and listener instead of GetHero() and the hero isn't the party leader, then other strange results may occur. I'll have to see what I can do about these other corner cases.)

  • Blank NPC lines, but with player responses: For now, don't do this. I'm not entirely sure if there's any reason to, but this actually requires a bit of special handling to look right. It's fine if the PC and NPC lines are both empty, or if the PC has no response choices, just a continue or end dialogue line.
  • It works if a placeable is the conversation owner. You may not want a portrait for that, but at the moment it will still expect one. The best I can suggest at the moment is to use some sort of a generic portrait or one custom suited to the situation. I can't tell from the mod if the speaker is a creature or placeable resource, but I could always add a column to the portraits 2DA so you can tell the mod and decide how to handle it.

Custom portraits

Basics

You have the option of creating your own custom portraits for use in the mod. Unfortunately they cannot be automatically generated by the game for use in this mod. Think of it as an opportunity to express your artistic talent. But if you choose to forgo them, then the mod will detect this and simply use a different mode where it centers the text near the bottom of the screen. It's up to you how big you want to make the portraits, but you may wish to make them larger unless your focus will still be on their 3D models in the scene, in which case you might find having large portraits to be a distraction.

Portrait borders

For the foreseeable future, you'll also have to create your own border for the custom portrait image if you desire one. The portraits can use DXT5 DDS files, so you can even make parts of the portrait transparent for rounded edges, a circular frame, or whatever else.

Conversations vs. cutscenes

The custom portraits will only load in an actual conversation as opposed to a cutscene. For cutscenes, centered text at the bottom of the screen is used and no NPC speaker name can be inferred. Mixing regular conversations with cutscenes can therefore be a bit confusing when having actors speaking in both.


Text handling

Inserting new lines

  • For NPC lines, you can simply type \n into the dialogue editor to get a new line now. In portrait mode, the text backing will expand to make sure all the text is covered.
  • You can also insert newlines in NPC text using custom tokens. E.g., define custom token [h] with value <desc> and define custom token [/h] with value </desc>\n\n:

[h]This would be some header description text you could define yourself using custom tokens.[/h]

Custom Colors

  • NPC lines: this is handled by using custom tokens that embed font color HTML into the text. The gold text color is by default. E.g., define custom token [q] with value <font color='#ffffff'>" and define custom token [/q] with value "</font>:

[q]This would be some white text with quotation marks that you could define yourself using custom tokens.[/q] But this text would be the default gold color.

  • PC response lines: Currently it's not possible to change the response line color with the mod. That might be available later, but will involve more work.

Other HTML

  • You could use custom tokens to try to insert other HTML tags into the NPC lines. If it works, it works, but Flash has a more limited subset of HTML available. You might start here as a reference. It's probably best not to do anything too crazy, though. E.g., if you want italics without parentheses that the <desc> tags gives you, then perhaps create a custom token to insert <i> and </i>.

Pseudo-cutscene effects

These will work in regular conversations, so you don't need to convert them into cutscenes in order to work. Currently there's support for a fade in effect, a quick fade in, and simulating a brief custscene insomuch as there's no text and it's automatically skipped after a moment.

  • Automatically skipped NPC-line: if the NPC line consists solely of the text {forcecontinue} then it hides any portrait, the NPC line, and any PC response text — including 1. (Continue) — followed by simulating the user pressing the escape key after 1.5 seconds. I've been using this to establish a scene and the actor locations before moving on into a purely portrait dialogue mode. I should make the scene length more flexible, but this is how it is for the moment.
  • Fade in effects: A word of warning - this isn't pretty to set up at first, but is very easy to use in conversations afterwards, so I think it's worth the initial hassle. Now that that's out of the way, lets get down to business. As odd as this sounds, you'll need to use the fade map or at least a submap. Yes, the map for that beloved realm of spirits, demons, and annoying blur effects. Why? Because I can read its map pins from the UI and if you create more pins, then they won't show up in the UI, unlike the other types of maps. It's that or nothing for now. The fade map is due its own section, but for now you can reference my forum post here about some of the fade map's specifics. If your standalone mod isn't using the fade map, that's OK - just create one anyway but you'll have to see that forum post about the resource name requirements. It expects to have at least two pins, with the pin tag openui_portraitdialogue_cmd and openui_portraitdialogue_cmd_sig. In the script example below, you'll see how they're used in plot scripts for the pseudo-cutscene effects. I'm truly sorry it's this ugly - I wish I knew a better workaround for the UI.

You'll also need to create a regular plot with a main flag for pseudo-cutscene commands. It doesn't matter what it's called or what the plot flags are. What matters is what the plot script does. In the associated plot script for EVENT_TYPE_SET_PLOT, do the following for a fade-in effect:

////////////////////////////////////////////////////////////
//
// Added to a "Custom plot events.txt" script template
//
////////////////////////////////////////////////////////////
 
// Whatever plot you made for it. It doesn't matter as mentioned - only what this script does exactly.
#include "plt_your_dlg_plot"
 
#include "wrappers_h"
 
// Chosen as something that won't be the initial pin state.
// The mod also expects this value or else it ignores the token update.
const int CMD_SIGNAL_RAISE = 6;
 
// Necessary, unfortunately, if you want the same command repeated on the next dialogue line.
// We don't get token updates otherwise.
const int CMD_SIGNAL_CLEAR = 255;
 
// Supported pseudo-cutscene command constants for now.
const int CMD_FADEIN = 1;
const int CMD_FASTFADEIN = 6;
 
int StartingConditional()
{
   .
   .
   .
   if(nType == EVENT_TYPE_SET_PLOT) // actions -> normal flags only
   {
      object oCmdPin = GetObjectByTag("openui_portraitdialogue_cmd"); // hardcoded tag name - the mod expects it to be a fade map pin (or fade submap pin)
      object oCmdSignalPin = GetObjectByTag("openui_portraitdialogue_cmd_sig");  // hardcoded tag name - the mod expects it to be a fade map pin (or fade submap pin)
      switch(nFlag)
      {
         case YOUR_PLOT_DLG_FADEIN: // A plot flag you defined. It doesn't matter what it is, only what's done in this script.
            WR_SetWorldMapLocationStatus(oCmdPin, CMD_FADEIN, TRUE);
            WR_SetWorldMapLocationStatus(oCmdSignalPin, CMD_SIGNAL_CLEAR, TRUE);
            WR_SetWorldMapLocationStatus(oCmdSignalPin, CMD_SIGNAL_RAISE, TRUE);
            break;
         case YOUR_PLOT_DLG_FASTFADEIN:  // A plot flag you defined. It doesn't matter what it is, only what's done in this script.
            WR_SetWorldMapLocationStatus(oCmdPin, CMD_FASTFADEIN , TRUE);
            WR_SetWorldMapLocationStatus(oCmdSignalPin, CMD_SIGNAL_CLEAR, TRUE);
            WR_SetWorldMapLocationStatus(oCmdSignalPin, CMD_SIGNAL_RAISE, TRUE);    
            break;
      }
   }
   .
   .
   .
}

2DA files involved

Template 2DAs can be downloaded from the project page listed at the top. In the portrait dialogue 2DA, you'll find an OUIPortraits_ worksheet; create a copy to work on with your own unique suffix. This explains the columns in it:

ID Label FileName Width Height Comments
int string string int int comment
  • The ID column should be the strref/string ID for your exported creature or placeable text. You can treat this worksheet as a proper M2DA, gaps in the ID range and all. I wish I could have just used an object tag, but this was the only way to get this whole thing to work. You can find these strrefs more easily by creating a filter in the toolet's string editor to filter the type of string you're looking for. Also, don't forget to check in your creatures or placeables at least once back into the toolset so the toolset will generate these strrefs for you automatically. In the future, it might be possible to create an app to facilitate making this easier. Also, it seems that the exported text will always use a unique number even if the string is actually the same - that makes enough sense, but at least the toolset doesn't seem to try to optimize strrefs if the text is the same. So this way creatures or placeables can have the same localized name, but they should have different strrefs, so you can refer to their individual IDs. You can also share the same portrait DDS texture file in the FileName column - this might be useful if you have different creature resources which ultimately represent the same NPC (even though they have the same name, the toolset should assign a different string ID.)
  • The FileName is just the name of your portrait file. E.g., abc100cr_some_npc.dds.
  • The Width is the width of the portrait texture file. It will also scale with the screen resolution, so unless you plan on it being small, it wouldn't hurt to make it a reasonable size. The width in this page's screen shot is 200 pixels.
  • The Height is the height of the portrait texture file. It will also scale with the screen resolution, so unless you plan on it being small, it wouldn't hurt to make it a reasonable size. The height in this page's screen shot is 252 pixels.
  • The Comments are just there for you to put in whatever text you want.

Using conversation stages in the DA:O toolset

The portrait dialogue is probably best using some neutral background - such as a vista of some sort. The static models in the game can actually look fairly decent as a backdrop. If you create a conversation stage and set the camera to not use depth of field, you can get some pretty interesting vista shots to use. The area's fog might be another concern, but if needs be it should be possible to work around that by temporarily setting the atmosphere values in DAScript and setting them back again after in the root conversation node's script or plot entry. I'll expand this section with more examples later, but it's ultimately up to you how you want to make things look nice. Note above the there are pseudo-cutscene functions that might help you make the transition to a vista backdrop a little easier.

You'll also probably want to set the stage camera for every NPC line to use whatever backdrop, which can again be somewhat tedious and error prone. And again, a future solution might be in doing it in bulk with an SQL statement, or at least finding which lines still have (Default) selected for a camera.


Packaging it into your own mod

Put the mod's .swf files, your .dds portrait textures, and processed .gda files into your module's addins/[uid]/module/override directory before creating a .dazip file. These files shouldn't have to go into the core override to work. Note however that if you have my other mod installed, FtG UI Mod, then the conversation and journal .swf UIs in that mod will supersede this one's .swf files. Now that I have a better understanding of how the resources are working, I'll have to release another version that's less intrusive, but you could either disable that mod or just put these .swf files (not your .dds, and definitely not your .gdas) in your core override with the understanding that they shouldn't have to be there and that situation should change soon. (In general, some UI files need to go into the core override, but not all and not these ones.)


Miscellaneous

  • This mod doesn't affect the slide show currently, as that's a completely separate UI resource.