This is an old version of the post about interactive stories, which I didn’t quite finish. Please have a look at the newer version.


Modern computer games increased the storytelling level lower bound significantly. Compared to Choose your adventure books, which allow readers to interact with the story (by choosing various branches), modern games often incorporate not only short-term decisions but also inventory, situation, and long-term decisions. All of these are quite easy to use by the player but can be challenging to implement while writing a story.

If your aspirations are to create such an interactive story, then you can use a specialized software for that. Noteworthy one is Artify (not free), which was used to write the Disco Elysium game. For our purposes, we shall focus on Twine, which aims to making text RPGs.

The point you should keep in mind is that whatever you write: it should be easy to work with.

Higher than simple interactive books, you may want to keep track of player’s decisions and inventory so that the story may be altered down the line. You may also give your players more freedom so that the story is non-linear. This is very well implemented in games Disco Elysium ↗ and Planescape Torment ↗.

In this post, we will have a look on how to start with interactive writing. Then, we shall see typical techniques used in contemporary games.

Getting into it

Download Twine ↗, watch tutorials ↗, practice.

Write at least a very simple story and see how the program works. Try to use the following features.

  • Reveal the story on a page gradually.
  • Branch the story depending on what was clicked
  • Join the branches of the story back together to a main story trunk.

These features are quite specific to interactive storytelling so they should be quite easy to implement. However, first-time user will have no idea and they are not trivial to create in any program. If you opened the program, tried to click around and have no idea how to progress, then open the hints with examples which are just below this paragraph.

Have look at the final file. Click the following link and explore how it works. You may also import it into twine (or look at the hints above) to see its structure.

Elementary techniques

These are needed for full interactive story experience. We include extensive examples in the expandable sections.

Notation

First, we introduce some basic notation.

  • node – Is a conversation beat, represents a volume of text the character says at a time; usually depicted with box or a circle.
  • edge – A traversal from one node to another node, represents where the conversation goes next; usually depicted with an arrow.
  • actor – A character who speaks in the conversation. Each node has its actor signified by color, name, and/or picture.
  • flow – A synonym for progression of the conversation.
  • branch – One way the flow may go.

Writing a dialogue consists of creating nodes and connecting them with edges.

When a player starts a conversation he begins in a starting node and progresses along the edges to other nodes. One node can be considered current: the last node visited by the player which is the last conversation beat which was said. The nodes which the player did before may be called past or passed nodes.

Entities and global properties

Things outside of the conversation are often called entities. This includes items (weapons, armor, tools), characters (player, NPCs, enemies), and ideas (technologies, thoughts). For us, the main uses will be to lead the conversation in different direction or give the player different conversation options when:

  • the player has some item in their inventory,
  • a NPC is in player’s proximity.

Although entities are important for the game, we shall touch on them just very lightly. As writers, we should be aware of entities but their setup should be left to programmers.

In writing, the entities shall manifest via variables (see next section).

Global properties are things you want to check against as well, but they are not physical things in the game. They usually depend on previous conversation choices or the current situation of the player. Hence you may lead the conversation in different direction or give the player different conversation options when:

  • the player knows some information (e.g., he read about the town on Wikipedia),
  • the player chose to convey some information (e.g., introduce himself under a fake name),
  • the player is at some location (e.g., indoors).

In writing, the global variables shall also manifest via variables, but (usually) do not have a concrete representation in the game world.

Variables

Imagine variables as an information-keeping tool to remember something. Such information may be used later to influence conversations or player options (see conditions section). They usually have clear names as its_raining or inventory.handkerchief.

Setting a variable means to remember something. E.g., if the player obtained a map we can set items.map variable to value true (usually by assignment as: items.map = true), indicating that fact in the system for later use. We distinguish several types of variables, usually:

  • boolean – true or false
  • integer / double – numbers
  • string – text

Also, we want to scope the variables (group them) if they have something in common. E.g., putting all player items into items scope and putting shop items into shop scope allows us to distinguish items.gun from shop.gun.

Conditions

Once a variable is set it can be checked with a condition. Most common is to check on the following.

  • equality == – used as items.gun.loaded_bullets == items.gun.bullet_capacity
  • non-equality != – used as items.gun.loaded_bullets != 0
  • bigger > (or equal >=) – used as player.money >= item.cost
  • smaller < (or equal <=) – used as player.weight <= 100

(Note the difference from assignment of a variable with = only one equal sign.)

Also, we may want to check against more conditions at once. This is usually written as:

  • all conditions at the same time hold – and or &&
  • at least one of the conditions hold – or or ||

Mainly, we may use conditions to do the following.

Split the flow

Main use is to split the flow to different branches. To accommodate this we may create an auxiliary node (with no text or actor) which serves only the function of checking the condition and diverting the flow. How to realize this functionality very much depends on what editor you use.

Hide dialog options

We may also use conditions to hide dialog options.