Solo RPG Dev Journal Part VI — Dungeon Generation

…and we’re back.

After a bit of a break while I worked on some other things, I’m continuing my strange journey to develop a traditional fantasy solo-RPG as basically a stream of consciousness. (Until I playtest it, and then revise.) With a baseline of mechanics in place, including character creation, the skeletons of combat and magic systems, and a set of game structures, it’s time to start figuring out how to generate content to use it all with.

While it might be cool to make prewritten adventures and settings for this game, I don’t want any such content to be necessary to play it. Since “exploration” is a game structure, the player needs to be able to, uh, explore. Discover new people, places, and things.

This means that I need to design a way to generate content through gameplay.

I’m going to start at the most abstract level. My design goal is a system that is based to a significant degree on the specific player character you create and offers varying levels of complexity, depending on how much the player wants to engage with it.

Since I want the system to be grounded in character decision, I’ll start with the question, “What is the player looking for? What are they hoping to find?”

Based on the game structures discussed in the very first article in this series, there are a few options that need support:

  • The first should almost certainly be dungeons, since dungeoncrawling is a major game structure. We’ll start here.
  • Urban exploration comes next. Cities and other settled areas are where the “NPC interaction” game structure is most likely to take place, so this needs to be just as robust as the dungeon generation. Some things players might be looking for include:
    • A specific NPC or type of NPC (ie blacksmith, courier, trainer, etc)
    • A shop (armory, apothecary, general store, etc)
    • Quest-related NPCs (quest-givers, other NPCs involved in quests)
  • Following from the above, we’ll need some way to generate quests. This may be distinct from the “exploration” aspect, but to avoid design bloat and needless complexity we’ll probably want them to use some common framework/mechanics. If we could find a way to make this also character-dependent (ie, you have mechanics for creating your own objectives and quests), then we’d really be cooking.
  • Finally, some form of wilderness exploration that ties everything together. What kinds of things do you stumble across while you’re exploring? What experiences might be offered by different terrains?

Let’s sketch some ideas out, starting with…

Dungeons

While a lot of games have systems for rolling a bunch of dice onto graph paper and then using the dice placement and rolls to create dungeon walls and rooms, I feel this system should be more abstract and structured than that. Those systems work well for GMs trying to generate content, but in a solo game where you’re also the player, you want the experience of “discovering” a dungeon as you go. So that’s what this system needs to accomplish.

I think to begin with it’s best to start with some categories. I’ll probably get the most bang for my mental buck by thinking in terms of “size” and “type.” More than two dimensions and things will start to feel unwieldy.

Dungeon sizes:

  • Tiny — these are basically anything you could make into a one-page dungeon. No more than a few rooms, and almost always just one level.
  • Small — possibly the most common kind of randomly-generated dungeon? These will be between 1 and 3 levels (though 3 would be rare) and with no more than a few encounters.
  • Medium — 2-5 levels. Plenty of encounters, but still something that could theoretically be cleared in a single session.
  • Large — 3-7 levels. Not intended to be cleared in a single session.
  • Mega — ginormous behemoth dungeons. These might need some special mechanics devoted to just them — we’ll figure that out later.

…and after just typing that out, I already feel overwhelmed.

While having lots of procedures for generating dungeons might be fun for some people (even me if I’m in the right mood), the point of this game isn’t to generate dungeons. It’s work the player will have to do in order to dungeoncrawl.

So while in some ways it would be nice to have tons of variety, for fast-and-dirty gameplay, I need to curb my impulse to add more, more, more. For now, I’m going to limit my sizes to 3.

Dungeoncrawling is generally based on moving from room to room, so the number of rooms will define the size of the dungeon.

And therein lies a problem–if you roll up the number of rooms right at the beginning, there’s no surprise. You’ll always know how much of the dungeon is left to explore, and exactly when you’ll reach the end.

So we’ll need to proceduralize/gameify it a bit.

First roll–size of the dungeon. You’ll roll 1d6:

  • 1-2: Small dungeon.
  • 3-5: Medium dungeon.
  • 6: Large dungeon.

But these numbers don’t inherently tell you how many rooms there are. From there, you’ll roll something that for now I’ll call the Dungeon Seed. It’ll be a number that you refer to while dungeoncrawling to determine “if there are more rooms to this dungeon,” and possibly other things.

  • Small dungeon: 2d6, take lower.
  • Medium dungeon: 2d6, take higher.
  • Large dungeon: 2d6, add results.

When you generate a dungeon, you’ll have to record these things. So it’ll look something like:

[Dungeon Name] Size: Small Seed: 2

(You will occasionally end up with situations where, for example, a Small dungeon has a Seed of 6 while a Large dungeon has a Seed of 2. So the Seed cannot, by itself, determine how many rooms are in the dungeon.)

Now, the “loop” of a dungeoncrawl boils down to of 1.) enter room; 2a.) overcome obstacle or encounter (combat, trap, puzzle, etc); 2b.) explore the room to see if there are any secrets; 3.) decide to go to the next room, or retreat; 4.) repeat. Thus, the player will need to generate each room as they go.

I’m imagining players “mapping” these dungeons out as they go. Not necessarily a geographic map (although players who like that may want to), but rather something like an abstract node map, noting each room, what is or was in it, and what connections it has to other rooms. So you’d be basically keying as you go.

We’ll figure out how to roll encounters/traps/treasures/etc later, but for now I want to focus on how rooms are generated. All dungeons will have at least one room, so at first the player simply enters the dungeon. (Maybe later I’ll devise a way to generate alternative or hidden entrances, or entrances that are locked/trapped, etc., but for now let’s keep things simple.) They solve whatever encounter may or may not be in the first room, and then they see how many pathways there are to future rooms.

Keeping it simple–there are always a number of pathways from the main entrance equal to the Dungeon Seed. So a Seed of 1 means that there will be a minimum of 1 additional room, aside from the entrance. The maximum possible will be 12 (!!!) which might be overwhelming, but this will be a rare situation.

So the player chooses a connection and moves into Room #2. Here’s where things get sticky.

We need a way to roll how many connections Room #2 (and other subsequent rooms) have so that the chance of further rooms diminishes the longer you go on. We don’t want endless dungeons, here.

My gut instinct is that the Dungeon Seed acts as a starting point when you choose a pathway, which then diminishes as the dungeon is explored. At a certain point, a pathway runs out and the player has to take another pathway, until all are exhausted.

(The Dungeon Seed itself doesn’t diminish, since I may want to use it for other purposes. It just gives you a starting number when you embark down a certain path.)

The Seed alone isn’t enough, however, because then the choice between Small/Medium/Large doesn’t affect anything after rolling it. So we’ll need some kind of procedure or table for comparing some combination of dice rolls, the Dungeon Seed, and the dungeon’s Size.

I’m going to run a procedure as I go to see how it feels. Starting with a Small dungeon for simplicity, I roll 2d6 and take the lowest for a Dungeon Seed of 2. I write a circle node for the Entrance, and draw two lines to represent two connections. Here’s what I’ve got so far:

(Obviously, none of these rooms have any content yet. That’s later.)

Okay, so I clear the Entrance and take Path 1A into Room #2. In addition to the paper where I’m mapping the dungeon nodes, I have a separate area of scratch paper for keeping track of the number based on the Dungeon Seed. (I feel like I should have a term of art for this number…for now I’ll call them “threads” but I may revisit that)

The Seed is 2, so in my scratch-area I write 2, under Connection 1A. I enter Room #2, and now I roll to see how many connections it has to further rooms…what should I roll?

My thinking is to simply roll 1d6, and if I roll equal to or under the number of the Seed, add that many connections and reduce the number by 1. The problem, as stated above, is that that doesn’t take into account whether the dungeon is supposed to be Small, Medium, or Large. (The Seed will tend to make dungeons larger or smaller based on this, but not always.)

Another option would be to continue using the same rolling method used to generate the Seed–small dungeons roll 2d6-take-lowest, Medium 2d6-take-highest, and Large dungeons 2d6. This is nice and intuitive, however it means that Large dungeons will frequently have multiple rooms with 7, 8, or 9 connections each. That would make basically any Large dungeon overwhelming.

Here’s another idea: since the player will have 3d6 available to them, they roll 1d6 for Small dungeons, 2d6 for Medium, and 3d6 for Large. The room will have 1 connection/exit/doorway/whatever for each d6 that’s under the pathway threshold.

This does mean that no rooms (aside from the entrance) will have more than 3 exits unless I add some specific mechanics for that, but I’m okay with that for now. Since I’ll have a separate system for secret passages, that might allow for more.

Okay, going with that for now.

So in Room 2, since this is a Small dungeon, I roll 1d6, and get…

3! So Room #2 is a dead end. (I needed to roll equal to or under the Dungeon Seed of 2 for there to be another connection.)

Backtracking, I take passage 1B into Room #3. I roll again, and get…

2! So Room #3 has another connection. I note this, and reduce the thread number in my scratch paper by 1. Now my node map of the dungeon looks like this:

Taking passage 3A, I enter Room #4 and roll again. This time, I have to roll a 1 to avoid a dead end. I roll…

3 again! Room #4 is a dead end.

…or is it?

Now I need a way to generate secret rooms/connections. This system may need iteration in the future, but for now I’ll base it on a Dungeoneering check.

I could have a DC table for passing the check based on…something, but instead I’ll keep it simpler by saying that the DC for finding secret passages in the dungeon is 7 (the DC for an average check) + the Dungeon Seed.

This means smaller dungeons will have easier-to-spot secrets, which is fine with me right now. A bigger issue is that it should be possible to fail this check without determining whether a room has a dungeon or not–your check tells you if your character can determine if there’s a secret in that room; it doesn’t determine if the secret exists. Make sense?

Originally I wanted to have this system mirror the one for determining rooms/passages, but that leads to a bit of weirdness where there can never be more secret passages than the Dungeon Seed, and encourages the player to metagame (if the Dungeon Seed is 3 and they’ve already found 3 secrets, they’ll know not to look for any more).

So a better system that keeps the randomness is that, if you pass your Dungeoneering check, there is a 1-in-6 chance you find a secret of some sort. From there, you’ll roll on a table (based on dungeon type) to determine if the secret is a passage, treasure, or something else. Perhaps some effects can increase the chance of secrets existing.

This means that there is a potentially unlimited amount of secrets in any given dungeon. (Well, at least as many secrets as there are rooms.) In actual play that will not happen, but it keeps the player from metagaming.

If I fail the Dungeoneering check, I’ll note that node with a “?” symbol. This means I can potentially find a secret here later…we’ll have to figure out how to determine what “later” means.

Using the character I created in the Character Creation article, Reynard Puck, I go back through the rooms to search for secrets. Reynard has no points in Dungeoneering and an Intelligence of 3, so I’ll roll 2d6 + 3 and, if I get 9 or above (7 + the Dungeon Seed of 2) I determine if the room has a secret or not.

I roll 4 times, once for each room, and pass the first 2 checks while failing the second 2. (Funnily, I rolled snake-eyes twice in a row.) Anyways, on both of the passed checks I rolled 1d6 to determine if there was a secret in the rooms, which there was not. So I leave those alone, and put question marks next to rooms 3 and 4 because Reynard isn’t quite certain there are no secrets in them. Now my node map looks like this:

It occurs to me now that using 1d6 to generate rooms for Small dungeons, 2d6 for Medium, and 3d6 for Large creates weirdness where Small dungeon rooms can never have more than 1 passage. I don’t like that.

Revising, we’ll say instead that the number of connections rolled this way is equal to the lowest roll that is equal to or less than the thread number.

So suppose you’re exploring a Large dungeon with a Seed of 10, and you’re 3 passages deep (so the thread number is 7). You enter a room and roll 3d6, getting 3-3-2. These are all under the thread number of 7, and the lowest roll is 2, so there are 2 passages in this room. The thread is reduced to 6.

Two more things I think I need before the skeleton of this system is complete: there needs to be a way to make different nodes/passages connect to each other so that this system can generate Jaquaysed dungeons, and I need a way to determine if the dungeon has multiple levels.

For the first problem, a very simple, but cumbersome, system would be something like “for each passage/connection, there is an x-in-6 chance that it connects to an already-existing room.” I say this would be cumbersome because it’s a whole other dice roll you’d need to perform for every single connection; that might get annoying quickly.

On the other hand, for two nodes to connect, they each need to have a connection that has not yet been discovered. So you wouldn’t necessarily be doing it for every connection.

So I’ll tentatively go with that–when you go down a passage for the first time, and there are any nodes with unexplored passages, there is a 1-in-6 chance that the passage connects to the existing node. If multiple such nodes exist, you roll 1d6 and select the node with the number closest to whatever you rolled. (You can use 2d6 or 3d6 if there are somehow more than 6 nodes with available unexplored connections.)

This is a bit of an annoying system, but the alternative is dungeons that don’t connect to each other at all. Unless a better idea hits me, I’ll have to be very careful about how I explain/present this rule.

Next, multiple levels. This should be based on the dungeon’s size and/or Seed, so we’ll create another thread for it on our scratch paper. My tentative idea is that some action or event will trigger a check for a level connection, and to discover if there’s another level, you must roll under the thread (which, again, equals the Dungeon Seed) using the same number of d6s you used to roll the Seed. If you discover another level, you reduce the thread by 1.

The trigger for additional levels will be based on content/type, so I’m not going to be worried about that right now. This will allow things like catacombs to be more likely to have more levels than caves, for example.

Additional levels are more of an advanced thing, but basically they’ll work as a whole separate node map with connections to other levels noted. I’ll fuck with that in the next article, which will be about stocking the dungeon.

So, to break down the procedure as simply as I can:

  1. Roll 1d6 to determine Size of dungeon.
  2. Roll the Dungeon Seed based on its size. (2d6-take-lowest for Small, 2d6-take-highest for Medium, 2d6 for Large.)
  3. Create Entrance node, including a number of passages equal to the Seed.
  4. Pick a passage, and create a “thread” for that passage based on the Seed.
  5. In the next room, and for each subsequent room, roll xd6, where x is based on the Size of the dungeon. If any rolls are equal to or below the thread number, then the room has a number of passages equal to the lowest of these rolls. Reduce the thread number by 1.
  6. Repeat step 5 until you reach a room with no more connections.
    • 6a. If you explore a passage, and there are other unexplored passages in other nodes, roll 1d6. On a 1, then this passage connects to a previously-explored room. Roll 1d6, 2d6, or 3d6, whichever is most appropriate, and connect to the node number closest to your roll.
  7. Backtrack and repeat steps 4-6a for all unexplored connections.

Again, somewhere in there will be checks for connections to deeper levels of the dungeon, but I’m not worried about that right now. Now I’m going to run the procedure one more time, with a Large map, and see what happens. Here’s what I came up with:

  • I rolled 2d6 and got a 7 for the Seed.
  • Labeled all connections.
  • Went down 1A to Room 2, and rolled 3d6. The lowest roll was 3, so Room 2 has 3 connections. Labeled them and reduced Thread A by 1.
  • Continued on this trajectory, rolling 1s in Room 3 and Room 4. With each passage, I rolled 1d6 to determine connections to previous levels, but didn’t get any.
  • Room 5 was a dead end (by this point, the thread was 4, and I rolled 6-5-5). So I backtracked all the way to Room 2 and went down passage 2B to Room 6.
  • Lowest roll in Room 6 was a 2. The thread is now 3.
  • In 6A I rolled a 1, meaning Room 7 has 1 connection. Thread is now 2.
  • Room 8 is a dead-end. Backtracked to Room 6 and took 6B. I rolled 6-4-4, so no more connections in Room 9. Backtracked to Room 2 and took 2C to Room 10, where I rolled a 2. Thread is now 1.
  • 11 was a dead-end, but I rolled a 1 on Room 12 for another connection. However, the thread is now 0, so if Room 12 leads to a new room, I won’t even be rolling for further connections.
  • Taking 12A, I finally roll a 1 for a connection to a previous node! The only node with unexplored connections is Room 1, the entrance. There are 6 connections (1B through 1G), so I roll 1d6 and get 3. Thus, Room 12 connects to Room 1 through 1D.
  • Backtracking to Room 1. I cross off Thread D since it connects to the thread I just made. I take passage 1B to the newly-christened Room 13, which has 3 connections. The thread is now 6.
  • 13A leads to Room 14, where I roll a 1 for 1 connection. The thread is now 5.
  • 14A leads to Room 15, where I roll 3 connections. The thread is 4…
  • (this continues for some time)

There was a point when doing this when I began to fear I’d created a monster and would have to go back to the drawing board. The connections and rooms kept exploding. I would generate a dozen rooms from 1 thread, and then look back in horror at my entrance node seeing that it still had 5 unexplored threads. At that rate, I could easily end up with hundreds of rooms!

My fears were allayed as I went, however, for a couple reasons. First–when a thread is reduced to 0, all the unexplored connections along that thread automatically end in dead-ends. Once that happens, you basically move onto the next thread.

The connections between levels worked great. They cleared 4 entire threads, because if a room connected back to the entrance, then that’s a whole passage that I now didn’t need to draw. Threads 1D through 1G ended up connecting to the three that I actually did use. So while based on the number of connections in the entrance I had a whopping 7 threads, with level connections it was reduced to 3, which still generated a total of 34 rooms. This feels about right for a “large” dungeon.

I already know one change I’m going to make, however. Imagine if I’d had a Dungeon Seed of 12–rare, but something that is fairly likely to happen in the course of a game at least once. 12 connections from the entrance would be insane, and each thread would have to go down from 12 to 0. It would be ridiculous.

And that’s not even counting additional dungeon levels.

And I didn’t even check for secrets with this one!!!

So instead of the number of connections in the entrance being equal to the Seed, you’ll roll the number of connections using 1d6 for Small, 2d6 for Medium, and 3d6 for Large, taking the highest roll. So entrances will have a maximum of 6 connections.

To wrap up, here’s a test with these revisions, using a Medium dungeon.

…and problems ensue.

I think I got very lucky with the number of connections in that Large dungeon test. My Medium test, with a Seed of only 5, generated a dungeon with 30 rooms, only 4 less than the “Large” dungeon with the Seed of 7.

I think the way I’m rolling dice is skewing the probability with the threads. See, rolling an extra dice for passages in a Large dungeon (3d6 vs. 2d6 for Medium) does mean that I’m more likely to roll under the thread, but it also means I’m more likely to roll a lower number, such as a 1 or 2. I’m no expert in probability, but I think this is having an effect here.

I also don’t like that when a thread is exhausted, the player will know that none of the unexplored rooms along that thread will have further connections. It’s metagame knowledge that I’m trying to avoid. However, when I tested again just moving to the next thread regardless of which passage I was in, it made the dungeon balloon to enormous sizes as I’d be ten rooms deep down a path, the thread would reset, and suddenly I was generating new rooms with 4, 5, or 6 further passages.

I think I can solve both problems by having the threads reset, but limiting the number of them based on the dungeon’s size. An easy way would be 1 thread for Small dungeons, 2 for Medium, 3 for Large.

So what happens if you happen to roll a Large dungeon with a Seed of 2 and only 1 entrance connection? (You’d have to roll snake-eyes for the Seed, and triple-1s for the connections. Damn, the dice gods would have to hate you for that to happen. Still, it’s a possibility I need to consider.)

In that case, you’d have 3 threads beginning at 2. You’d go into the next room and roll 3d6; at least 1 roll would have to be 2 or lower to generate a 3rd room. You’d have a significant chance of getting a “Large” dungeon consisting of only 2 rooms.

Ugh.

To add more randomization, and hopefully solve edge cases like the one above, I’m going to revisit how threads work. You’ll generate a number of threads at “runtime” based on the size of the dungeon (1, 2, or 3), but the threads will be equal to 1d6 + the Seed. So each thread will be different, but none can be smaller than 2 (3 for Large dungeons).

I think limiting the number of threads will keep dungeon levels significantly smaller. Threads in Large dungeons can theoretically be as large as 18, but with only 3 of them, the size should still be relatively constrained, and hey, when I get multiple levels worked out–this makes it possible to generate megadungeons.

That’s going to be the system for now. Generate a size, a Seed, and between 1 and 3 threads. Then, start generating rooms and connections.

Now, we’ve got a node map detailing a bunch of dungeon rooms. It’s time to put actual stuff in them.

Back to Part 1

2 responses

  1. Solo RPG Dev Journal Part V — Magic – Christian Chiakulas Avatar

    […] Next: Part VI – Dungeon Generation […]

    Like

Leave a comment