Interactive dialogue – part 1

Today it’s time to talk about interactive dialogue.

Here’s a thing: point and click adventure games actually don’t offer that much in the area of gameplay, at least: when you look at the number of things the player can control.

For example, in other games like e.g. an RPG, a player can fight enemies using dozens of different strategies, choosing from hundreds of spells and abilities, buy or trade items, talk to people, etc; in Mario you can control jumping and running in the minutest detail and in most sports games the available controls try to mimic the real thing as closely as possible.

However, in a ‘typical’ point and click adventure game, the gist of things you can do are: walk around, pick up stuff, use stuff with stuff and talk with NPCs.

Of these things, walking around and talking to NPCs take up about 3/4 of the gameplay while working with objects (in your inventory) maybe only 1/4. More importantly, in general the player can only click on things to trigger a possible action, meaning that it is very well possible that certain clicks result in nothing happening. Also by emphasizing the word trigger, I mean that if successful the player can lean back and watch a result, without needing to be alert for any quick reaction.

What I am trying to say here is that since adventure games do not offer a great number of (“real-time”) controls to players, they need to excel in story and atmosphere. Those two things make why we love adventure games and why they seem to appeal a bit in the same way as a good book. Interactive dialogue discussed in this post, plays a big role in bringing the story, setting the atmosphere and giving the player part of the controls.

In this post, and following posts, I’d like to go into what interactive dialogue entails: what requirements we defined for it and how I went about implementing the underlying dialogue engine.

Before I begin I’d like to say I got (stole) the current idea after reading Ron Gilbert’s post on the Thimbleweed Park blog.

So what was the initial idea, and why was it changed? Before getting into that and the machinery of the current dialogue engine, lets’s consider what makes up an interactive dialogue:

  1. After using the ‘Talk to’ action on a NPC either the hero or the NPC starts talking
  2. If the NPC asks a question to the hero, **SPOILER** he has either a direct response (to the NPC) or several responses to choose from
  3. After a choosing an option, triggering a question or remark back to the NPC, it is possible the NPC responds again and point #2 is repeated
  4. A dialogue ends either by the NPC quitting the dialogue, e.g. via a specific cutscene, or the hero choosing an exit response, such as “That’s all very interesting, but I think I must verify if I’m not needed somewhere like 50 parsecs from here”
  5. A dialogue possibly interacts with the game state (more on that later)

So the interactiveness for the player here is the opportunity to choose different things to say (back) to a NPC.

Alright, now let’s go into the rationale of the design by categorizing a bunch of key requirements we had in mind.

Editing/adding  dialogue

For me the most important part of the dialogue engine is the possibility to quickly and conveniently add/edit dialogues. Knowing that most adventure games require dozens of dialogues to be written, this needs to be as simple as possible by considering:

  • It shouldn’t be necessary to implement custom editing software, ideally a simple text editor anybody can use should be sufficient
  • While editing dialogue, it should be easy to keep track of the flow of the dialogue, meaning: which part (of dialogue) precedes/follows each line of dialogue
  • While editing dialogue the actual written dialogue should be easily legible, so the fewer the markup the better

Parsing dialogue

Having to decide on a file format for storing the dialogue, the following considerations are key:

  • The file format should be easy to parse by software, so using regular expressions or building custom parsers should be avoided
  • Again: no regular expressions! I really don’t like it, I just can’t remember that [^az-AZ*].[eat*] crap. It’s powerful, but it’s shitty too

Dialogue features/logic

Ok a suave input format and silky smooth parsing is nice, but we actually need to define what kind of dialogue features we want supported:

  • Ephemeral dialogue: these pieces of dialogue are only uttered one time and cannot be revisited. Pretty useful for e.g. writing dialogue that’s fun or adds atmosphere, but not required to advance in the game
  • Option groups: to add variety to what the hero can answer/ask, it must be possible to define different lines of dialogue for a single topic (I’ll get to this in a later post)
  • Preconditions: every piece of dialogue can be associated with a precondition, meaning it will become available only after certain conditions are met (in respect to the game state)
  • Update game state: it must be possible to update the game state whenever certain lines of dialogue have been uttered by the hero or a NPC
  • Cutscene injection: it must be possible to spice up dialogue with cutscenes. In future posts we’ll go into how we define and execute cutscenes in our engine

Disclaimer: Because we have no artist in our team (yet), all art is either programmer-art (all static backgrounds and sprites) or animated sprites we temporarily “borrowed” in fair use.

Example of an option group being used to support a series of awkward compliments
Example of an option group being used to support a series of awkward compliments

These features will become more clear once I’ll go through a fully fledged example of the current dialogue file format in the next post.

Current approach

With the aforementioned requirements in mind and after having implemented an approach based on a graph structure represented in JSON file format, I eventually came up with using YAML to define a similar input file format as was described on the Thimbleweed Park blog. This file does not reflect a graph, but something I call dialogue blocks in my code.

The reasons for taking TP’s approach as a basis is that I totally appreciate not needing to build special editing software, but simply being able to use a simple text editor to edit a file that is both easy to read, but also has the possibility to add the required dialogue logic in a human readable manner.

Why YAML? 

Since I really do not like writing custom parsers and since I did not appreciate the use of JSON in my previous implementation (more on that later), I decided to go for YAML, which is really light on markup and very close to something you would use to write down your grocery list with. In short: it seemed like something that would be both machine and human readable and therefore easy to parse and allowing us to copy-paste dialogue/text without having to wrap everything in countless curly braces.

As mentioned in our tech stack post, this is the YAML parser we use.

The old approach (using JSON to plot a dialogue graph)

{
nodes : [
{
actor : "patton",
id : 1,
precondition : null,
preconditonValue : null,
postAction : null,
text : ["What is it Drew?"],
children : [8, 9]
}
{
actor : "patton",
id : 2,
precondition : null,
preconditonValue : null,
postAction : "patton_told_about_stale_magazines",
text : ["Ah yes, but that was already last year's version, doesn't Fennimore ever refresh those magazines!?", "The latest update SpreadCover Mega Lavestorm has been available for two months already!"],
children : [10, 11]
}
{
actor : "patton",
id : 3,
precondition : null,
preconditonValue : null,
postAction : null,
text : ["No can't do such a thing, she's already been riding me like a mule on the Manderlay account."],
children : [11, 12]
}
{
actor : "patton",
id : 4,
precondition : null,
preconditonValue : null,
postAction : null,
text : ["Come on Drew, just leave me alone will ya, want to finish early!", "Unless...", "MAYBE I'll cave if you can give me a box of cheerios."],
children : [11, 13]
}

As you can see this format is not exactly (dialogue) writer friendly:

  • It’s hard to quickly see which part of the dialogue belong together, you have to hunt for (child) IDs and scroll
  • Every line of dialogue takes a fully filled in property list, making it very verbose
  • It’s supposed to reflect a graph structure, which is always a pain regardless of the markup format; even images of graphs can be hard to consult, let alone a text representation.

So next to the file format being different, the old approach modelled an (interactive) dialogue as a graph where each node is a line of dialogue and each edge is represents the possible lines of dialogue that can follow. As you can see in the example, each node also had an optional precondition and ‘post action’. The post action is used to refer to a piece of lua script that should be executed after the line of dialogue is uttered (in later posts we will talk about how and why we hooked up lua to our engine).

Alright it seems that for now I’ve globally described most of the rationale and requirements of what I/we perceive as a useful interactive dialogue system for a point and click adventure game.

Just before closing off here’s the (simple) YAML file, which is underlying the animated GIF in this post:

first_encounter:
  - fennimore:
    - Hey Drew!
  - :main

compliment:
  - $fennimore.compliments++
  - fennimore: [{if: fennimore.compliments==0}, You bet Drew! Told you there's no game like Parrises Squares!]
  - fennimore: [{if: fennimore.compliments==1}, Thanks again!]
  - fennimore: [{if: fennimore.compliments==2}, Thanks!]
  - fennimore: [{if: fennimore.compliments==3}, Well... gee...]
  - :main

#----------------------------HERO OPTIONS------------------------------
main:
  - 1: [{if: once},"Hey buddy, you look sharp as always!", :compliment]
  - 1: [{if: once},"Hey buddy, you're on fire!", :compliment]
  - 1: [{if: once},"Hey Fennimore, I want more!", :compliment]
  - 1: [{if: once},"Ok that's it, I'm calling the authorities! Red hot alert!", :compliment]
  - 2: ["Sorry Mr. sharp, gotta go market me some foodstuffs", :exit]

More elaborate examples of this input format + an explanation of how it is translated to the dialogue engine will follow in the second part.

Until next time *pom pom pommmmm*

2 thoughts on “Interactive dialogue – part 1

    1. Thanks! So far we really enjoy Luxe. It feels much more lean than HaxeFlixel, being still shiney and new.

      MicUurloon can tell a bit more about it, since he’s the one so far that has been on Gitter as well.

      (Part 2 of interactive dialogue I hope to finish this weekend)

Leave a Reply