The following blog post, unless otherwise noted, was written by a member of Gamasutras community.

The thoughts and opinions expressed are those of the writer and not Gamasutra or its parent company.

In this blogpost, our programmer Isak talks about some of the considerations we made in making a mod-friendly dialogue system for our game in production Ludus

One of the absolute key parts of Ludus is the ability to interact with NPCs and participate in the Roman society from the perspective of a Lanista. To achieve this we needed a competent dialogue system. I think anyone who has worked with dialogue trees will know what type of features to expect from this kind of tool, but with our emphasis on modability I think some of our decisions in the actual implementation might be different from some other games.

While we have developed quite ambitous plans for the ways you can interact with the NPCs in Ludus in addition to simple scripted dialogues which rely on what will hopefully be a pretty sophisticated AI - we still maintain that it is important to be able to create more tailor-made content which we can mix with the more spontaneous systems we're attempting to develop.

Even though simulating almost everything fully is super awesome - if you sprinkle in some more set-in-stone-ish events, we can hopefully put the player in awe of what outcomes arise during the course of the game. It should hopefully also be hard to tell what was scripted and what was simulated, just that we would like to guarantee or at least make it more likely that interesting things happen no matter what.

One way we can do this is to make dialogues that will push the simulation quite hard in a certain direction with the side effects that occur on certain dialogue nodes.

So that's the justification for still having hardcoded dialogues in the game, but how do you actually go about authoring the dialogues?

Initially when we started we were using a tool called ChatMapper which is a fairly decent choice. But we soon realized that in order to actually export dialogues that the conversation middleware could use, every modder would have to buy a license. Since we care a lot about modders we decided that this was not acceptable so we got rid of both ChatMapper and the middleware. After researching alternatives, we set out to create our own way of authoring dialogues and our own dialogue system.

We wanted a plain text format that could easily be edited by hand and read with eyes (instead of toes!). A common choice for hierarchical data would be XML or JSON, but we're not huge fans of those. As an Emacs user I soon had the epiphany that the Emacs Org Mode format would be quite nice for modeling a dialogue tree. It has nice properties such as not having to worry about closing tags or parenthesis for the tree nodes. Emacs comes with nice ways to edit and view it, which certainly helps, and we could add extensions to make it even nicer to edit. However if we have the time we might even put an editor for dialogues in the game itself.

Either way if you are not familiar with org-mode, you might want an explanation on how the format is structured! The way you write an org document is that you create a headline which you do by putting a number of asterisks (*) and a space, and then the name of the headline. After that you put a newline and anything you put below that will belong to the headline. Examples of things you'd put in the headlines are things such as paragraphs and source blocks and various attributes and such. The nesting level of the headline is determined by the number of asterisks before the name of the headline. Here's a very simple example of a document:

* My headline

This is a pragraph that belongs to "My headline"

** My child headline

This paragraph is in a headline which is a child to "My headline"

Here's another pragraph, they are separated by two newlines.

*** My grandchild headline

This paragraph belongs to headline which is a child to "My child headline"!

** My second child headline

This is the second child to "My headline"

* My other headline

This headline is not a child of "My headline" it is a sibling.

** My other child headline

And so on!

It might be hard to read at first but again just pay attention to the asterisks before the headline title and you should be able to visualize the nesting. Emacs makes it much easier to visualize the nesting since you can turn on "org-indent-mode" which is very helpful. You usually indent the text under a headline in emacs but I stopped doing that when I noticed that it broke org-indent-mode which looks much nicer anyway. Even so, even without any indentation to make it more clear I find this format to be less noisy than something like XML or JSON. I think this format could be pleasant for other things than just dialogues, for example I think it could fit quite well as a plain-text representation of a scene-graph.

I mentioned that other than paragraphs you could put things such as source blocks and attributes under a paragraph. Let's discuss the syntax of these a little bit. For source blocks we use the exact same syntax as Emacs org-mode, which looks like this

#+BEGIN_SRC boo

import UnityEngine

Debug.Log("Gonna set some values now in my boo script")

ludus.dialogue_state.likes_turtles = true

ludus.dialogue_state.hates_bacon = false

Debug.Log("Done setting values! :)")

#+END_SRC

If you have a keen eye you'll notice that we explicitly say that the language for the source is "boo", you'll be able to use any language here that there exists a driver for, and even add your own language driver if your favorite is missing (assuming everything goes right). But that's for another post about the scripting system!

Attributes have a similar syntax and can be put on their own or attached to another element in the headline's section, such as a source block or paragraph. For example, we support an attribute called WHEN which you attach to a source block to specify when that script should run, a particularly useful stage to run a script is "condition" which can help filter out certain dialogue nodes if the script condition script returns false. An example could look something like this

* You were mean to the NPC

#+ACTOR: npc

#+CONVERSANT: player

I can't believe you said I'm lame. Dang you man.

#+WHEN: condition

#+BEGIN_SRC boo

script_return ludus.dialogue_state.were_mean

#+END_SRC

This example also shows the attributes ACTOR and CONVERSANT which, unlike the WHEN attribute, is not directly attached to an element of the headline - instead it is an element itself. What distinguishes an attribute element from an attribute for an element is the two newlines separating the elements, just like with paragraphs. The main thing that distinguishes an attribute element from a regular element is that you can't attach attributes to attributes.

That is really almost all of the syntax, the last thing that you might be yearning for is text substitution. Well for that you can use a macro language which again is just any programming language that has a driver for the scripting system. In order to set the property for what macro language to use you use what is called a "property drawer". Which looks like this:

:PROPERTIES:

:MACRO-LANGUAGE: boo

:END:

Once you've done this you can use boo in order to evaluate any code that will in the end return a string for what should be substituted. Like this:

And that's the way {{{ script_return "it is!" }}}!

Finally in org-mode, headlines can have keywords prepended to them, such as TODO. We decided to adopt this for creating link headlines by adding the keyword LINK to designate that the headline is a link. The way you write a link is as follows:

** LINK my link headline

[[The title of the headline I am linking to]]

As you can see this means that it is good practice to name your headline something unique.

That covers basically most of it, there are other useful features as well such as running a script when entering and exiting a dialogue (and even individual dialogue nodes) for setup and cleanup etc. But this article isn't really intended to fully document every feature of our dialogue format, but rather to introduce you to the basic ideas and principles on how we (and hopefully modders!) will write dialogues for the game. We suspect that the format will evolve over time so documenting everything right now would probably be time down the drain.

If you want to you can take a look here in order to read an example of a dialogue that I've been using for testing which showcases everything I mentioned in this post. It kind of lives in its own space for now in that it doesn't have any real side effects in the real game, but it illustrates how you can arrange a dialogue - quite sloppily though because it was quickly thrown together for testing purposes, the result of running that dialogue (with a work-in-progress UI) can be seen below (click to maximize)! Thanks for reading!