RPG Conversation systems.

A major component of RPG games is talking to people, uncovering motives, accepting quests, learning secrets and talking your way out of tricky situations. But natural language is a hard problem. When making a game we need conversation to manageable and therefore we need some type of abstraction.

It's instructive to look how existing games have tackled conversation design problems.

Conversations are difficult things, they can affect the entire world, for instance you might convince someone to press a button that triggers a game-ending nuclear detonation. Conversations can also affect themselves; offend a character and the entire conversation might change! Managing this type of complexity is a challenge. A real-world conversation can roam over many topics but in the game world we need strategies to create a manageable, authorable structure.

In this article we examine how Never Winter Nights deals with conversation. Never Winter Nights (aka NWN) is an RPG game and toolset released by Bioware in 2002. It's game mechanics are based on the Dungeons and Dragons tabletop roleplaying game.

The games look like this.

This is what never winter nights looked like.

The Never Winter Nights games feature the standard complex conversation system as seen in games like the early Fallouts or Baulder's Gate. Conversations are text based. An NPC says some text and then beneath, the player may chose from several replies.

For this type of game the screen layout is usually similar to the one below. The player can still see the game world but about half the screen is taken up with UI for the dialog system.

This is what never winter nights looked like.

Conversation Features

Here are some of the high-level features of the NWN dialog system.

  • Conversation is a separate game state.
  • Conversation pauses the game world.
  • The NPC's speech is rendered as text.
  • The player is presented with a choice of replies.
  • Some replies may be hidden depending on certain conditions.
  • Choosing a reply may alter the game's state.
  • Conversations can contain loops.
  • To exit the conversation the player must choose a special reply that may not always be available.

A reply being available may depend on several factors; the class of the player, the previous choices in a conversation, player intelligence or charisma, how far the player has proceeded in a certain quest and so on.

How does Never Winter Night do Dialog?

Never Winter Nights uses a graph to represent conversations.

A conversation graph is made up of nodes. Each nodes indicates some snippet of speech from the NPC or player. Nodes are evaluated in order to determine if they can be displayed. If a node has no condition restricting it's display, it's assumed the node can be shown. Every conversation starts at the root node which checks all it's children until it finds one that can be displayed.

A diagram showing the structure of Never Winter Nights dialog tree.

There are two types of node; dialog nodes and response nodes. Response nodes may only be children of dialog nodes. A dialog node however may be a child of another dialog node.

When a dialog node is evaluated and can be shown, its text is displayed in the NPC dialog panel. Its children are then evaluated in order and added to the reply panel. Sometimes there is only one child and it's another dialog node. In this case a "Press Space to Continue" prompt is added to the reply panel. Once the player has read what the NPC has to say they can hit the Spacebar and advance to the next dialog node.

Otherwise the player is then free to choose one of the displayed responses.

On choosing a response the conversation graph advances to the next eligible dialog child node. Nodes may contain an exit tag that causes the conversation to end when chosen.

Let's try a simple conversation where we represent the nodes with Lua tables.

In this RPG we assume you can become a knight but start as a peasant. The NPC addresses you differently depending on your status.

{
    type = "root",
    condition = nil,
    children =
    {
        {
            type = "dialog",
            condition = function() return player.IsKnight() end,
            text = "Anything I can help you with sire?",
            children =
            {
                {
                    type = "response",
                    text = "Any news?",
                    children =
                    {
                        {
                            type = "dialog",
                            text = "No, sire.",
                            exit = true -- ends conversation
                        }
                    }
                },
                {
                    type = "response",
                    text = "No, thank you.",
                    exit = true, -- ends conversation
                }
            }
        },
        {
            type = "dialog",
            text = "Hello. You ok?",
            children =
            {
                {
                    type = "response",
                    text = "Any news?",
                    children =
                    {
                        {
                            type = "dialog",
                            text = "Heard one of royals has been sneaking"
                                .. " out at night.",
                            children =
                            {
                                {
                                    type = "response",
                                    text = "Interesting. Thanks.",
                                    exit = true
                                }
                            }
                        }
                    }
                },
                {
                    type = "response",
                    text = "Fine thanks, just a bit busy now.",
                    exit = true
                }

            }
        }
    }
}

The above conversation graph presents the player with a conversation like this, if you're a knight:

NPC: Anything I can help you with sire?
1. Any news?
2. No, thanks [END]

And if you're not a knight you'll get a conversation like this:

NPC: Hello, you ok?
1. Any news?
2. Fine thanks, just a bit busy now. [END]

Nodes may contain an optional condition function to determine if they are shown. We can also extend the node definition to add functions that fire when a reply is chosen or loop backs the let the player return to a previous node.

Drawbacks

The Never Winter Nights conversation system let's us have complicated conversations, with many branches and that are still manageable for a game designer or writer to author, but there are some drawbacks.

There's limited error checking. Designing a conversation is basically raw programming and it's very easy to introduce game breaking bugs, especially for designers unfamiliar with programming. This means a lot of testing time is required and possibly post-release patches.

Even with good tooling it's possible to create broken dialogs. For example: all dialogs have conditions and it's possible none ever fire. Therefore the conversation breaks at that point. Or with loop-backs we could create an endless loop between two nodes with no way to end the conversation.

Conversations are static and very text based. NPCs stand still and spit out statements. They don't change facial expression or move around.

They're hard to create and hard to reason about once created.

They're not resilient in the face of change. If there's one constant in game development; it's change. Dialog will be revised, quests will change and bugs and mistakes are certain to creep in. The person making the edits will no longer remember (or even know) exactly how the original conversation was supposed to work and how it was supposed to modify the global state.

I'd consider these open problems for most conversation systems in RPG games. If you think you can solve them that's information worth sharing!

Implementation

It's one thing to talk in the abstract about a conversation system but to really understand what's going on, nothing beats an implementation. The next article uses the How to Make an RPG codebase to create a version of this type of conversation system.