Sponsored By

Changeable Minds

Separating event tracking from character knowledge.

Jon Ingold

January 17, 2024

7 Min Read
The core cast of Overboard!

At inkle, we write narrative games with high player agency, which means allowing the player to mess about both with the consequences of things, but also with the causes of them. The player isn’t only reacting to events, but also strategising and executing plans to drive the narrative in the way they want.

For example, in our 2021 game Overboard!, we cast the player as a murderess trying to get away with a murder they most definitely commited: either by providing themselves with an alibi, or better yet, pinning enough evidence on another character that they take the fall.

An idea like this could be implemented as a branching narrative tree, populated with hard fails and a golden path. But branching narratives don’t lend themselves to strategic play because the choices of one moment can’t be guaranteed to appear again. Didn’t leave the bloodied knife in the uncle’s cabin at 10 o’clock? Too late, you missed your chance, you can’t go back.

For Overboard! we instead took a light simulation approach inspired by text adventure games of Infocom: we create a boat full of murder suspects on schedules who went about an eight-hour day filled with misdirections, leads, clues and overheard snippets of conversation. The player could then intersect with these schedules, scurrying around and setting up little traps for these characters to fall into.

To make that work, we needed a bunch of systems, at the core of which was a source of truth for “what’s happening?” For that we use an event chains concept which is basically an upgrade on basic Boolean flags —where a flag might say “has this happened?”, an event chain can say “how far through this happening are we right now?”

For example, imagine the player is going to find and open Pandora’s box. Instead of three flags for “seen Pandora’s box”, “unlocked Pandora’s box”, “opened Pandora’s box”, we have a single chain — a slider, effectively—which tells the game how far through opening Pandora’s box you are. This allows us to quickly test where on that scale a player is, in ranges: have they unleashed the world’s evils? Have they seen the box, but don’t know what it contains? And it means we quickly “catch up” if the player takes a short-cut: if they hit Pandora’s box with Thor’s hammer, we can skip right to “opened Pandora’s box”, and it’s implicit that the player has “unlocked” the box too.

Note that some events might have only one event in their chain and be Booleans after all; some chains can permanently branch; and complex events might require multiple parallel chains to fully describe their state. States can be set from anywhere in the story — so unlike a branching narrative, which is totally reliant on “where it is” for its state, here the state information sits outside of the story, queries on demand. And most importantly, once set, a state is never unset. What has happened cannot be undone — after all, if we add a final state, “shut Pandora’s box”, it has still been open and that’s, y’know, relevant. (We might also need a normal on/off Boolean for if the box is actually open or closed right now, of course, but that’s something else again.)

The event chain model has served us well across many games, but one challenge that came up throughout Overboard!’s whiplash development was the secondary problem of modelling, not what’s happened, but what other character’s believe has happened, which ought to have as much narrative impact as the events themselves. After all, if you tell a character they were seen with the victim at the time of the murder, they’re going to try to secure an alibi, even if you’re lying through your teeth.

A naivë computational approach might be to duplicate the whole world event state on a per character basis, and then make sure that characters only update what they know about the world when they’re present. But this gets extremely complex very fast — if you don’t see me open Pandora’s box you won’t know about it, but if you walk through the room where it’s open, do you notice then? But if you’re not there when I tell the butler he’s fired, that’s nothing something you can pick up passively. Unless the butler himself tells you.

What’s more, this kind of modelling is completely opaque to the player — it’s too complex to surface, so how do we help the player feel agency instead of overwhelm?

In Overboard! we didn’t attempt to solve any of this. We just modelled every “person thinks X” event as another event chain, that might start with “X told Y about Z” and end in “Y is sure about Z”, or might end with “Y realises X was lying about Z”. These chains were messy and overlapped a lot, and they were hard to query. The game came out okay, but it proved in the making that event chains are a bad model for this purpose — because what a character believes breaks that fundamental assumption of “once set, a state is never unset”. A character might believe that the butler is dead because you said he was, only for him to bump into the butler later on. A character might not realise a murder has occurred, then think you did it, then think the butler did it, then go back to thinking you did it, then decide it was suicide after all. People’s viewpoints are not geological, constrained by the accumulative effect of irreversible time. People change their minds about things all the time. (Except fascists. They broken.)

So: to 2024, and we’re thinking about character modelling and event chains for new prototypes. We’re trying out a new “calculation-based” abstraction for modelling character beliefs. This is more like the classic AI flow inside a chess computer: a game-state is passed in, analysed, and a best-guess result is generated. In this case, we pass in the world event chains to each individual character’s analysis function, and come back with “what does the character now believe?”

From a scripting point of view, this gives each character a tidy black box for decision making that has no interest in flow state, or where in the game the player happens to be. Conversation beats are still events (“You told the butler about Jim holding the box…”), and passive moments are still events (“The butler saw Pandora’s box was now open…”) But the consequence of these events is now a single if-statement — if the butler heard about Jim, and saw the box open, the butler will believe that Jim opened the box. But should Jim protest his innocence — adding another event to the world state — then the butler can quickly change his mind.

Each character only needs to think about the things that matter to them. We don’t need to model or compute everything for everyone —and we certainly don’t need every character to have an opinion on every event. Spot-fixing and adding detail is easy: if we find a case where a character ought to change his mind about something and didn’t, we simply add that case explictly into the character’s personal computation. We don’t need to track down how the state happened or try to understand why they character got into the state they did. The only input is the state.

So now we have three coupled systems running in parallel:

  1. The world — the player and characters move around, opening and closing boxes and doors, moving things around, and saying things to each other. We model where people and things are, and what states they’re in.

  2. The event chains — uni-directional tracking of events, always moving upwards and forwards as thing occur, and never being undone, including the accumulation of information, truthful and otherwise, by characters from characters.

  3. The belief state — computed from the event chains when required for each character so see what they currently think of the things in the game that matter to them.

From a writer’s point of view, the world pushes events as and when they occur; events are queried by beliefs via a separate analysis process; and then beliefs and events are queried by the world when they’re needed to decide what can and should happen next. The writer doesn’t need to know or keep track of, from moment to moment, what caused an event to happen or what caused a character to believe what they currently believe.

It’s too early to call if this approach is truly sustainable at scale, but it’s already jumped forward what we can achieve in the multi-character space without our brains exploding. You should see the conclusions we’ve got these lil’ guys jumping to. No idea why.

This blog was originally posted on Medium and has been republished with the author's permission. It has been slightly adapted to our formatting standards.

Read more about:

Featured Blogs

About the Author(s)

Daily news, dev blogs, and stories from Game Developer straight to your inbox

You May Also Like