When Dead Mage created Children of Morta, a narrative-driven 2D dungeon crawler, they ran into some challenges balancing the roguelike elements with the story progression. We talked to Reza Hooshangi, Lead Programmer at Dead Mage, about how they combined the huge possibilities of procedural generation associated with roguelike games with a sense of meaning and progress needed in narrative-driven games.
Making a procedural system requires that you define many rules and constraints that define the borders of what is possible in your game. In this blog post, we will look at defining a level structure, the challenges that arise when you introduce narrative elements, and the custom tool that Dead Mage built in Unity to balance the fresh feeling of random events with the narrative progression needed to support the story in their game.
In Children of Morta, every level is made up of a number of rooms connected to each other by doorways. There are many kinds of rooms with various types of content; some might contain a breathtaking fight with hordes of enemies, a mysterious game of chance, an NPC waiting desperately for the player’s help, or just regular pathways filled with regular enemies.
Hooshangi explains that in Children of Morta, they defined a group of parameters for each level, mapping out all of the rooms and how they should be connected to each other. He provided us with the following diagrams, which give you a sense of the great number of possibilities in the basic structure of one given level alone.
First, you take the basic structure
The first diagram shows an example of a simplified version of a level structure.
Each level has a main path which consists of every room from the start room leading to the end room (rooms 0,1,2,3,4). It also can contain a number of branches (dead ends) connected to the main path (the side path with rooms 6 and 7).
Then, you add rules for how to connect them at this particular level
Level structure parameters define the rooms and put a list of constraints on how they can be connected together. For instance, in this level, item room (the room with a reward item) is supposed to be connected to a room in the main branch but not to the first half of the path. The side path also has its own constraints, but for the sake of simplicity, let’s assume them to always be connected to room 1. So this specific level could also look something like what is shown in the diagrams below:
But what about orientation?
So far, the structure doesn’t reveal anything about the orientation of the rooms. So in the end, it could look like any of the diagrams below:
Each room has a number of possible shapes and forms, so there’s a lot of different possibilities for making a level with these parameters, as you can see in the following diagrams.
So far, we’ve looked at how complex just the basic structure of a simple level can be, but it’s not over yet!
Procedural generation meets narrative design
Sometimes, a procedural narrative encounter occurs that modifies the level temporarily. For example, in the diagram below, you can see a procedural event requiring the addition of two extra rooms.
The R1 room contains an NPC that asks the player to find and bring something to him in exchange for a reward. Further on the main path, the player finds another room (R2) with the requested object in it. He has to fight his way to the object, pick it up, return it to the NPC and get his reward.
This is a simple example of a procedural event that resolves itself in one level, but there are other types of procedural events you might encounter, which have more complex objectives.
Sometimes it takes a couple of playthroughs until the player catches up with the rest of a side storyline. In the meantime, he will find traces of other procedural events. However, because they are ordered randomly, different players might encounter them in completely different situations.
Once the rooms are in their places, it’s time to fill them with procedural content. Children of Morta has a number of subsystems for generating and managing different types of content. You might not be surprised that Hooshangi, a big fan of the Matrix films, gave these subsystems in Children of Morta the following names:
- Key Maker: Handles all the doors and connections between rooms
- Oracle and Persephone: Put environmental assets, narrative objects, cutscenes and many other things in a given level
- Tank: Generates and manages pathfinding graphs (character in The Matrix who operated the hovercraft)
- Smith: Spawns enemies (obviously!)
- Merovingian: Spreads the loot in the level (Even though he didn’t exactly spread his money around the world in the Matrix films)
Each one of these subsystems has its own set of parameters defining the precise behavior for a specific level. So each level has a structural parameter about its form and layout, plus a set of parameters for each one of its content-generation subsystems.
How Dead Mage balanced random events with narrative progression
The collection of all the parameters mentioned above includes everything the procedural algorithms need to generate a level and everything inside it. Each level of the game has a predesigned set of these parameters with its own features and characteristics. But Children of Morta has a linear story between all runs, which by nature, works in opposition to a predesigned set of constraints.
On the one hand, a small number of constraints would cause totally different (random) levels with no sense of progress or meaning. On the other hand, if the levels were predesigned, each playthrough would be exactly the same with no narrative progression whatsoever!
A custom tool to create meaningful chains of events
In order to reach a level of coherency and meaningful relations between gameplay elements and thus give players a meaningful experience, Hooshangi and his team built a custom tool in Unity, which they call Train Man.
This system is notified about everything that happens in the game and is able to change the parameters of how what will occur. Each time the procedural system is going to generate a new level, it gathers all the default parameters and sends them to the Train Man. The parameters are then modified in a way that reflects the current state of the story.
In one of the first runs of the game, the tool manipulates the generation parameters of the level and adds a special room to it containing a wolf cub fighting over her mother’s corpse. Saving the cub will start a new quest that affects the procedural generation through time. For example, later in the game, you might find a room in a corner of a level with medicine for the cub in it.
The narrative line of the wolf cub, however, is just one of many procedural events. Dead Mage’s custom tool stores and manages a number of active procedural events in the player profile. As the diagrams below illustrate, everything that happens in the lifetime of each procedural event is tracked and when the time comes, the procedural parameters are modified based on the progress.
Micro, macro meaning
This enabled Dead Mage to work independently on each procedural event matching the generated level to the current state of all active procedural events. This resulted in many possibilities for varied levels, which convey a sense of randomness, and freshness, to the player every time they’re active in a given level. At the same time, though, it enabled specific and temporary modifications that give the player a sense of something meaningful going on in the big picture of the underlying story.
Dead Mage’s custom Train Man tool keeps track of the player’s level progress managing side quests and narratives in order to maintain the feeling of progress in the story. They also use it, however for a number of other applications, which help ensure a positive player experience:
- Dynamic difficulty: For a procedural event, it can keep track of the player’s actions and change the number of spawned enemies, hazards, dropped health potions, loots, and so on, over time to balance it with the player’s skills.
- Unlocking content: They can hide some of the random content from the player and add it later when he has spent a certain amount of time with the default content. This helps decrease initial frustration and increase the replay value over time.
- Analytics: They can measure and analyze the player’s actions in order to understand how they like to play the game.
As part of their procedural generation in Children of Morta, Dead Mage created rules and constraints, which are virtually endless in terms of the possibilities in each level. This solved the problem of giving the player a fresh experience each time they played a given level in the roguelike dungeon game. They then extended Unity with their custom Train Man tool to enable temporary modifications within those constraints, which preserves the narrative-driven framework of the game by giving the player a sense of something meaningful going on in the Children of Morta world. To learn more about how Dead Mage used Unity, read the Children of Morta case story.