NaNoGenMo was on again in November 2015, and I made it my mission to get a finished 50,000 word novel out of it. After scrapping my initial plan to construct a narrative journey/road novel generator, I wanted to work on something I could complete in a more reasonable time-frame.
So I came up with the Gamebook of Dungeon Tropes, a sprawling, weird, 1000 section generated novel, with multiple pathways through the story.
How It Works
The gamebook generator is written in Ruby. It starts from a simple 2D map of grid cells forming a labyrinth, then uses the Calyx gem to construct a bunch of nested template grammars that decorate the map with randomly generated text.
Here’s how the map generator works:
- Start with a random walk that draws a series of connected cells on a grid. Each cell will represent a room in the labyrinth.
- Run a maze generator over the cells to randomly connect exits between neighbouring cells, oriented by the four cardinal directions (north, south, east, west).
- Pick a starting cell at the edge of the labyrinth. This will be the entrance to the dungeon.
- Traverse each cell and label them with section numbers, starting from the entrance.
At this point there’s enough structure to generate the main text of the story.
Here’s what a random walk generating 600 map squares looks like:
Rooms & Passages
The structure of the text is modelled on on the style of old-school gamebooks—think Fighting Fantasy and Pick-a-Path. Each room is generated based on a position in the map, with the choices to move forward in the story given by the list of exits, each leading to another room.
It’s possible to make these connections between rooms bi-directional—so that readers can move back in the story. It’s also possible to connect the rooms as a directed graph, so that movement is always one-way. One of the improvements and tidy-ups I’d like to make is to make this an optional parameter that can be switched on or off when running the generator.
Descriptions and contents of rooms and the events that happen there are distributed based on Gary Gygax’s famous generation table from the original Dungeons & Dragons Dungeon Master’s Guide (page 171). Translating the D20 dice numbering to weighted probabilities (0..1) gives the following starting point for the template grammar:
class DungeonRoom < Calyx::Grammar start( [:empty, 0.6], [:monster, 0.1], [:monster_treasure, 0.15], [:special, 0.05], [:trick_trap, 0.05], [:treasure, 0.05] ) rule :empty, 'Empty' rule :monster, 'Monster Only' rule :monster_treasure, 'Monster and Treasure' rule :special, 'Special' rule :trick_trap, 'Trick/Trap.' rule :treasure, 'Treasure' end
From here, most of the text in each room variation can be generated by mashing various lists (of lists, of lists) together.
Content from the lists is randomly sampled in a stateless way, meaning that bizarre combinations of surroundings are possible. To make the flow of rooms more interesting and coherent, it might be possible to decorate the map cells with meta information that describes an overall architecture or ecosystem so that there’s continuity when moving from one place to another. I haven’t done that yet.
There’s also an overall quest and a primary antagonist (boss) that gets generated which provides a frame narrative for the chaos of the labyrinth. Right now, it’s used to generate the title and intro sequence, and fills in a basic ending.
This could be improved by traversing the map and generating extra text with elements of foreshadowing or items and environmental textures related to the quest. For example, if the quest boss is a dragon, then certain rooms could be filled with traces of the dragon’s destruction like scorch marks, scratches, charred and burned detritus, etc.
Another thing I’ve been considering is to rewrite the generator so that it produces a Twine document. But I like the idea of manually turning from section to section, so for now, it’s formatted as a classical gamebook.