Originally posted to GameDeveloper.com in August 2022:
How the home-rolled scripting language Exoscript helped us design a flexible open world narrative of nearly 600K words.
My favorite narratives are ones where the reader – or player – is a participant, taking the author’s text and telling their own stories with it. For our narrative RPG I Was a Teenage Exocolonist, I wanted this: organic worldbuilding, characters with their own lives, replayability, and major events as signposts in a larger narrative space the player can explore. Not a linear visual novel, but a loose and vast narrative intertwined with deckbuilding and stats raising, dynamic yet deterministic.
I’m Sarah Northway, co-founder of Northway Games and creator of I Was a Teenage Exocolonist, as well as the narrative city-building series Rebuild and other games. I grew up an avid reader and writer before games became my life. I even considered writing a young-adult sci-fi novel instead of this game, but I know my strengths lie in programming and game design, and it would be a waste not to combine them with the story I wanted to tell.
With Rebuild 3, the similarly large 200K word narrative was delivered as an assortment of procedurally generated events involving a post-apocalyptic settlement. But for I Was a Teenage Exocolonist, I had a new challenge: to tell a coherent narrative along a 10-year timeline, involving characters who grow up, change dramatically, and may (or may not) even die mid-game.
I worked with co-writer and narrative designer Lindsay Ishihiro to produce Exocolonist’s huge and complicated narrative, with approximately 6 novels’ worth of text and 800 triggered events.
The Octopus
With our focus on replayability, I wanted players to only see a small amount of the narrative during each life, but without forcing them into one track at a time. For a dynamic open world, we’d need events to occur with or without you there to witness them, and you could pop in on a plotline in the middle of some crisis which might be too late to solve.
I wanted you to see the world from different points of view as you grow up in the game: as a child or an adult, as a farmer or a soldier, as a romantic or a rebel.
A branching narrative wasn’t going to cut it, or at least not just one. We needed many different plotlines overlapping and affecting one another, and hundreds of one-off triggered events to build a narrative world you could explore at will. And we couldn’t always control what order events would fire in, or what state the world would be in when they did.
Our narrative wasn’t a branching tree, but a juggling octopus. Flexible and interconnected, with a core narrative and many wriggling limbs.
Event Categories
Our 800 narrative events break down into these types and trigger methods:
1) Main plot
These occur in every playthrough, and tie the game together with the consistency of changing seasons. Every year there is an event for your birthday, then the Vertumnalia harvest festival in midyear, then an event during glow season as the planet begins to reject the colonists’ presence. Unique challenges happen during specific years, always on the same date in every life, but the outcomes can be changed by your decisions and skills.
The predictability of main plot events provides an anchor as the months tick by, and reinforce the current mood of the game as it grows darker over time.
2) Sequential threads
Spend time in geoponics, and you’ll discover a friend’s secret pet, which over ten events grows up to be a huge problem. Work in the command wing, and you’ll get embroiled with a secret club with plans to free the colony from tyranny. There’s a series of world-building events as you improve in each of the twenty-five school, hobby or career paths, which often give the player a choice between two or three cards to build their deck, representing how the player is growing as they increase particular skills.
Sequential events always happen in order, but might be skipped if you’re too old. They’re triggered with the main plot events after you do an activity for the month. If two or more happen at once, I try to pick the highest priority one and delay the others.
3) Friendship events
Characters have love meters which trigger sequential events as you get to know them. These tend to be less connected to larger colony plotlines, and they’re optional, requiring you to walk up and talk to the character when they have a speech bubble over their heads.
4) Exploration
These appear as signposts, creatures or floating question marks out in the wild, and feel like miniature RPG encounters. Many involve a card battle or a skill challenge, and they’re scattered around semi-randomly depending on the region, season, and year.
5) Barks
In addition to our 800 triggered events, there are 1800 barks: short single paragraphs with no choices that play when there’s nothing else to say. They’re highly conditional, based on anything from the weather or your combat skill to obscure choices you made as a kid.
Enter Exoscript
I considered various commercial scripting systems, including Inkle’s ink and the Unity asset store Dialog System, but none were quite right. I was planning to hire a co-writer, so I wanted something that would be easy for a non-programmer to learn and use. I wanted script that would look like plain English and feel simple and natural to write in, lightweight with a limited set of powerful features that we could use in complex ways. I wanted to be free to easily extend it, integrate it into the Unity project, and change events while running the game.
Ink came closest, and I would recommend it to someone in the same situation. But I was bitten by the desire for full control, and writing my own parser sounded like fun!
In the end creating Exoscript was indeed fun, and didn’t take as long as I’d expected. About a week to get the base features in, then another few weeks of optimization and upgrades gradually as we needed them. Co-writer / narrative designer Lindsay (who turned out to have a background in code) quickly got the hang of complex conditionals and started asking for more.
In this example, choosing “Try to distract it” sets an event-level variable (“~set var_distract”), then returns to the previous list of choices while removing itself (“>>>”). This will reveal a new choice to “Attack the monster!” now that you’ve distracted it (“~if var_distract”), which triggers a card battle (“~call battle(combat_10)”). But it has an additional bravery requirement (“~ifd skill_bravery >= 10”) which must also be met. If you win the battle, a new illustration will show (“~set bg = nearby_close”) and a permanent variable will be set (“~set mem_savedTonin = true”) to remember this for future events.
Calls and Conditionals
Call statements like “~call battle()” use reflection to jump into a C# library of about a hundred methods that gradually grew through development. If they have parameters, those are automatically validated when the scripts are parsed, along with parameters used in any “~set” or “~if” commands. I wanted to be sure we’d catch typos in the IDs of skills, backgrounds, characters, or cards as early as possible.
The validation step also checks that referenced variables have been set at some point, and for unlikely cases like jumps causing infinite loops. This made my job as an editor much easier, and will be handy if players mod the game to add their own events.
Closely connecting Exoscript with the Unity project made it easy to trigger visual effects, for example “~set left = marz” slides the character Marz in to the left side of the scene, and changes the color of text in double-quotes to her color, blue.
Our in-line conditionals (eg “[if skill_bravery >= 50] How brave you are! [else] Scaredy cat! [end]”) work like “~if” to determine which block of text to show. We use them all over the place, but prefer to put them around full paragraphs. This is both easier to read, and if we ever decide to localize one day it will make translators’ jobs easier.
Groundhog Day and Our Process
A key narrative feature in I Was a Teenage Exocolonist is a mysterious wormhole that lets you remember bits of past lives. On your second playthrough onward, new choices appear in events you’ve previously encountered. These can be used to shortcut difficult challenges, like curing a disease without spending years researching it, so you could eventually combine many lives of knowledge into one “perfect” life.
In honor of the classic Bill Murray movie Groundhog Day, these are called “groundhogs” or just “hogs” in the code.
The simplicity of Exoscript was a relief given how much we had to keep track of. Generally our system was: I blocked events out, Lindsay wrote them, then I edited and tested them in the game. Lindsay pulled in the direction of romance and longer prose, and I pulled towards blunt gameplay-oriented choices, and together we found a great balance. We hashed out the trickiest parts of the narrative together on Discord.
We had notes and spreadsheets of facts and jargon, and Exoscript was easy to skim for references, but writing Exocolonist really only worked because both of us were able to hold the entirety of the narrative in our heads for a few years.
The Future of Exoscript
I mentioned modding above, which I hear Exocolonist fans are already doing before the game is even out! They’re adding their own events, and have even ported the syntax highlighting to other text editors. I tried to make modding easier by storing the story files in the filesystem in plain text, and if there’s enough demand I might implement Steam workshop support after launch.
Localization is something else we’ve wanted to do but have been unable to so far due to the enormous nature of Exocolonist’s narrative. But fan translations may also be possible some day via a modding system. And I’ll be using Exoscript again for my next (unannounced) game.
I’m looking forward to seeing what players think of the game, what stories they tell inside it, and how it inspires them creatively in their own writing and art.
I Was a Teenage Exocolonist launches on Switch, PS4, PS5, and PC/Mac/Linux on August 25th.