Thursday, October 1, 2015

DMMuse.com Dungeon Generation Primer

DMMuse.com is a site where I publish random generators and tools for D&D.  Currently I've been working on a Dungeon Generator.  What makes the DMMuse.com Dungeon Generator different is its ability to accept content contributions from anyone.  This article describes how to add content to the generator.  The more people that add content, the fresher the generated dungeons will be for everyone!

Generator Syntax

Adding content to the Dungeon Generator involves adding new entries to various "tables" hosted at DMMuse.com.  When you add an entry to a table, you can optionally use DMMuse.com "generator syntax".  This is a powerful set of markup that lets you randomize and vary your entry's text each time that it's generated.  The full scope of the generator syntax is explained on this help page at DMMuse.com.

Dungeon Rooms

The Dungeon Generator works by first collecting a group of random room descriptions, and then building out a map to match those descriptions.  The room descriptions themselves come from a DMMuse.com table called Dungeon Rooms.

The entries in Dungeon Rooms follow a few conventions.  They start by the name of the room, in bold, followed by a comma, and then the room description.  To make text bold in an entry, enclose it in HTML bold tags - <b> and </b>.

Here's an example Dungeon Rooms entry:

<b>Empty Room</b>, not much to see here.

The entry can include a number of optional tags.  The first tag tells the Dungeon Generator to use a specific room shape template when generating the map for the room.  For example, to tell the Generator to always make the room square, do this:

<b>Square Room</b>, will always be square. template=square

The following is a list of shape templates that are currently available.  Check back, I will update this article as more shape templates are added:

cavern, circle, oval, shaft, small, square, warrens

The "decor" tag tells the Generator to add a piece of visual decoration to the room.  A few pieces of decor are available, more will be added in the future:

chasm, fountain, moat, water

The "inject" tag injects monsters into the dungeon room entry.  The tag should specify the name of the (D&D e5) monster, followed by a comma, followed by the number of monsters.  You can use dice notation when specifying this number.  For example, to add 1d6 orcs to a room:

<b>Orc Room</b>, they attack! inject=orc,1d6

Because of the way the Generator parses text, monster names that contain spaces can be problematic. For this reason, replace any spaces in a monster name with asterisks (*).  The Generate will replace these asterisks with spaces when it parses the text.

<b>Elemental Cavern</b>, a large natural cavern. inject=air*elemental,1d3

Dungeon Dressing

In addition to the rooms themselves, the Dungeon Generator adds pieces of dungeon dressing.  These are simple things like sounds, smells, scratches on the walls, or discarded gear, that add interest.  You can contribute dungeon dressing to DMMuse.com by adding entries to the Dungeon Dressing table.

Themes

The Dungeon Generator supports optional themes.  The user can select select one or more themes to add distinct flavor to the generated dungeon.  Themes are implemented by adding entries to two DMMuse.com tables, Dungeon Theme Flair, and Dungeon Theme Bosses, and by adding themed rooms to the Dungeon Rooms table itself.

To add a specially-themed dungeon room, use the "theme" tag at the end of the entry.  Below is a list of themes that DMMuse.com currently supports:

earth, darkness, kobold

To add a new kobold-themed rule, for example, add something like this to Dungeon Rooms:

<b>Kobold Room</b>, several of the [@PersonalityTraits] critters are here. theme=kobold inject=kobold,2d6

Dungeon Theme Flair items are special entries that can appear in dungeon rooms when the specified theme was selected.  Unlike other entries, you should preface the Dungeon Theme Flair entry with one of the following things ...

Contains: 
Trap: 
Monster: 

"Contains" entries are like pieces of dungeon dressing that correspond to the theme.  "Trap" entries are traps that are specific to the theme.  And "Monster" entries are monsters that might be used if the theme is selected.  Place the names of the monsters themselves in HTML bold tags.

Don't forget to append the appropriate "theme" tag at the end of these entries.  And note, unlike the other entries, these don't have periods at the end.  An example of each Dungeon Theme Flair is presented below:

Contains: a lone kobold egg, hatching theme=kobold

Trap: a jar of green slime breaks and shatters, triggered by [@TrapTriggers] theme=kobold

Monster: [2d6+2] <b>kobolds</b>, [1d4] of them riding <b>giant lizards</b> theme=kobold

The final piece of customization you can provide to a theme is a boss monster, represented by entries in the Dungeon Theme Bosses table.  Use HTML bold tags to enclose monster names, and explore the DMMuse.com random name generation capability to add a unique name to bosses.  Read more about random names in the Generator Syntax help page.

Here's an example kobold boss.  Note the "theme" tag at the end, don't forget this:

[RandomName;kobold] is the [king|head|ruler] of the tribe, a <b>kobold</b> "great wyrm" of some [stature|renown|intelligence] theme=kobold

There you have it!  Hopefully some of you will start adding your own entries, keeping the Dungeon Generator's results always fresh and surprising!

Wednesday, September 23, 2015

Rendering Dungeons

Been working on rendering the randomly generated dungeons in a more game-friendly format.  The 24-pixel tiling is looking pretty good.  I've got basic doors placed and rendered.  A next step will be adding some variety to the doors, to get secret doors, locked doors, iron-bound doors, bricked-up doorways, etc.  I want to also start keying these to a "difficulty level" input parameter.  The difficulty will also eventually drive things like trap placement and monsters.

Monday, September 21, 2015

Procedural Dungeons

Taking a small break from wilderness generation, on to the dungeons that will eventually be populating that wilderness.  Here's a sample 20 room dungeon layout based on a new algorithm that I just completed.

The dungeon generation library features a modular architecture based on room and passage "carvers".  The "carvers" create room and passage shapes in a variety of styles.  Since the system is modular, it will be easy to create specific environments, like caverns, mines, etc.

The next task here is to scan for door placement and render this in a format that's more usable for gaming.  Ultimately I see this as the basis for a DMMuse themed dungeon generator.

Saturday, September 19, 2015

A Slicker Presentation

With the bulk of the terrain generation under my belt, I spent some time working on the visual presentation of the hex map.  I feel that the maps were looking too clunky and cluttered, with too many terrain icons.  Since I had a fully detailed elevation map at my disposal, why not use that to create nice looking gradient terrain hexes, rather than relying on terrain icons to represent everything?  I kept terrain icons for areas of high mountains and heavy forests, but the nice gradient of hex colors now presents a pleasing aesthetic to the map.

Oh, I also cleaned up river generation a bit more.  My prior algo was producing some truly crazy and maze like rivers.  While they looked interesting, they were decidedly not natural looking.  This algo uses the previous one to determine an ultimate destination for the river, but then lets the river move naturally toward that destination, while introducing some subtle, meandering variations.

I'm starting to collect my thoughts on the next steps, which will involve placing cultures and their artifacts (settlements, dungeons, ruins, etc) on the map!

Friday, September 18, 2015

Better Rivers

I cranked up the World Generator after a long hiatus, and promptly improved the river generation.  I had to first re-factor the generator to understand that it was creating a hex map instead of a 2D grid.  I then changed the river generation to render rivers along the center of hexes, rather than along hex-sides.

The rivers start at a high-elevation point on the map, then use a very simple algorithm to determine their flow.  I just pick the next hex of the river to be the neighbor hex with the lowest elevation, excluding any hexes already used for the particular river being generated.  The result are rivers that meander nicely, mimicking the winding rivers we find in nature.

Monday, January 12, 2015

Hex Terrain Mapping Complete

Wetlands Added

The terrain mapping for my fractal world generation is now complete, with the addition of swamps and an occasional fungal forest.  I decided to take the simple approach to swamps, and set a terrain hex to swamp if its moisture level was close to the high end, and the ground was level.  Fungal forests can appear in these same conditions, but can quickly grow to cover over much of the surrounding terrain, so they add somewhat of a wildcard to the mix.

Sample World

Here's the randomly seeded world #1482326029 (yes, you can regenerate the same world by supplying the seed value) in snapshot.  I went with 40% land and a size of 768x300 hexes.  This world happened to have a good range of terrains, from ultra-lush jungles and swamps to arid deserts.  I'll highlight a couple area of note.


Fertile Delta

Here a river flows between two mountain ranges, creating a fertile area of lush forests and jungles amidst a generally arid desert environment.


Fungal Forest

There happened to be only one fungal forest generated on this world, in the red box below.  This bizarre terrain could form the basis of quests to retrieve rare spell components.


Campaign Start?

I've often used islands as a starting point for campaigns.  Their limited geographic area established handy constraints for low level parties.  Once the potential adventures on the island are resolved, its time to board a ship and head for new shores.  The generator produces worlds with many realistic islands and archipelagos to pick from.


What's Next

Next steps will be laying the groundwork for introducing cultures/races into the world, the birth of settlements, conflicts, expansion, etc.

Thursday, January 8, 2015

River Generation

Recap

With the terrain hexes of my fractal world generator mapped out, I have the basis of a campaign world in the form of a hex map.  The next important feature to add is rivers.

Rivers

Rivers should begin from the higher points on the map, and snake their way down until they hit a water hex.  I first randomly determine how many rivers to place on the map, and then build a list of candidate origin spaces which are the highest points in the elevation map.  I then take random candidates from the list, and ensure that they are not too close to the origins of previously formed rivers.

With the origin set, I look at the origin point's neighbor hexes, and move the river down into the one with the lowest elevation.  I repeat the process, winding the river down, until it's deposited into a water hex.

Moisture

For each of the hexes that contains a river, I bump up the moisture level.  The intention here is to potentially yield something like the Nile river, which cuts through a desert, but is flanked by lush vegetation.

Example


Here's a river originating in a colder region of the world, beginning in the mountain range to the west.  It snakes to the right, then up, and again to the right, to finally run off into the ocean.  Cutting through an area of cold desert, the moisture from the river causes evergreen forests and shrubland to grow along its banks.

Wednesday, January 7, 2015

Mapping Terrain Hexes

Recap

After completing the elevation map, temperature map, and moisture map, I'm ready to try and put these pieces together and determine terrain types for each hex on my dynamically generated fractal world.

Blur

Before tackling the terrain mapping, one aspect of the generated maps was bothering me.  They were too noisy.  Too many tiny island and lakes, more so than in natural world terrain.  I decided to apply two passes of a simple blur filter to the elevation map before the subsequent processing steps.  The results are more pleasing, but it's possible I might increase the number of blurs even more if the worlds still look too noisy.

Elevation Map with 2 Blur Passes
Terrain Mapping

I used the diagram below as a reference for mapping a point on the elevation map to a terrain.  First, I determine by the elevation if the hex is a flatland, hills, or mountain.  Then, I cross reference the temperature by the moisture to determine the appropriate terrain type.  For example, if it's a mountain hex, possible terrain types might be mountain, evergreen mountain, forested mountain, or jungle mountain.  I then made the tallest mountains on the maps into snow peaks, and threw in a minute chance of one or more volcanos popping up.


Terrain Mapping Results

Here's the example world above mapped to hexes.  The world is 768x300 hexes, or 230,400 total hexes.  I had to shrink the image quite a bit in order for blogger to accept it.  I like the shapes of the land masses, and the look of the mountain ranges.  If there's one thing I would tune, it would probably be to decrease the overall moisture level so more plains and shrub lands manifest.  But I think that the moisture control will be a tweakable dial in the final product, so you can create lush jungle worlds or barren desert worlds, as desired.


Since it's difficult to make out the individual hexes in this image, here's a section zoomed in.


What's Next?

I'm starting to consider how to populate the world with various fantasy races.  I'm leaning toward trying to model a simulated history.  Start by putting some primitive tribes on the map, let them advance and expand, and eventually come into contact and either ally or conflict, depending on their alignments.  As civilizations grow, settlements will spring into existence organically, and grow from villages to towns to cities, or might get razed by war and wind up as ruins.

But that's not immediately next in the development queue.  Next I'm going to integrate the other terrain types that haven't made an appearance yet, namely swamps and fungal forests.  Oh, and I almost forgot ... rivers.  And I might just start building those terrain hooks I talked about earlier, and throw some elemental portals into the mix to see how they mess up the climate and the resulting terrains.

Tuesday, January 6, 2015

Fast Moisture Simulation

Recap

In the previous post I described my attempt to model average precipitation (moisture) in my fractal world generator.  While the end result was acceptable, the amount of processing time needed to complete hundreds of cycles of simulated air circulation was too much.  I needed a faster approach.

Approximating

Rather than slavishly attempt to model every pixel of air movement, I decided to try a randomized approximation that would hopefully yield similar results.  My new moisture simulation performs 10 cycles of the following steps:

  1. Adds a small amount of moisture to each point on the map.
  2. Determine a random offset to the left/right and up/down.  Rather than 1 pixel shifts like in my previous model, the maximum offset is 20% of the map size, and the minimum 5%.
  3. Take an image of the elevation map, shift it by the offset amount, and use the elevation values to modify the moisture map.  Low elevations will add to the moisture map, and higher elevations will subtract from it.
Results

Approximated Moisture Map








Here are the results applied to the same fractal world as the previous example.  On the plus side, this method resulted in more amorphous moisture blobs, which I think will work better once this data is used to map to terrain hexes.  We still have low moisture areas (blue) which will translate to deserts, but they aren't as precisely defined as the previous method.  Bottom line, I think this approach will yield a result just as usable as the more intensive method, at about one hundredth of the processing time required, so it's a win!

Monday, January 5, 2015

Moisture Simulation

Recap

I'm developing a random RPG campaign map generator, and have the following pieces in place:


Precipitation

The next piece of the puzzle is generating a moisture map that represents the average precipitation at each point on the world.  A combination of the temperature, moisture, and elevation will ultimately determine which hex terrain is chosen for a particular point.

Algorithm

My first pass at modeling precipitation can be summed up as:
  1. Create several randomized wind bands.  Winds will blow left to right across the map, but these randomized zones will provide some cross-currents.
  2. Complete a number of cycles of simulated air circulation.  The number of cycles is set to the width of the map.  With the maps I am currently working with, this means 768 cycles of simulated air circulation.  For each cycle:
    1. For every water point on the map, add a small amount of moisture to that point.
    2. Use the wind bands to "blow" the air map one space.
    3. Subtract a small amount of moisture from each point, based on the elevation at that point.  This step is intended to simulate the deserts that can form next to mountain ranges.
Results

The example below shows a simulated moisture map after 768 cycles of simulated air circulation.  I'm generally pleased with the result.  The mountains in the upper left continent are producing a large desert region, there are numerous areas of moderate moisture which will map to plains, and much of the map has high moisture, which will lead to forests and jungles, depending on the temperate in the area.

The only problem with the approach is the processing time involved.  It takes about 15 seconds of processing to complete the 768 cycles of simulated air circulation.  I think I can create a simpler approach that will be orders of magnitude faster, and still produce acceptable results.

Elevation Map
Moisture Map after 768 cycles

Sunday, January 4, 2015

Temperature Zones

Recap

Work on my fractal world and dynamic campaign map generator continues.  With an elevation map in place, and basic hex mapping accomplished, this next step will move us toward ultimately more realistic terrain.

Research

My crash course in biome generation led me to Community and Ecosystem Dynamics, which I think has most of what I need to get an adequate model developed.  After digesting most of this, I concluded that the first step would be dividing the world into temperature zones.

Algorithm

I implemented a simple algorithm to produce a temperature map of the world, based on a minimum and a maximum temperature as parameters.  The default minimum temperature is -15˚ C., and the default maximum is 30˚ C.  You'll be able to supply different parameters to generate colder or warmer worlds as desired.

The exact temperature at each point on the map is calculated by the longitude (assuming an equator at the center), and the elevation, with a slight randomization applied.

Example

In the example below, note how areas of higher elevation have an overall cooling effect on the region.

Fractal World Elevation Map
Corresponding Temperature Map
Future Hooks

As the project progresses, I will need to add hooks into the fractal world generator to account for localized anomalies in temperature.  For example, in my home D&D campaign, there are numerous portals into various elemental planes that make their surrounding regions much colder or hotter.  Also, certain large monsters could have an affect on the surrounding climate.  It will be exciting, for example, to produce a large localized region of cold from an elemental portal and see the resulting terrain get generated as tundra and ice fields.

Saturday, January 3, 2015

Fractal World Mapped to Hexes

Mapping to Hexes

In day two of my dynamic campaign world generator development I built a rough translation of the elevation maps from yesterday into a hex grid.  I did a very basic mapping of elevation values to three "terrains", green for plains, yellow for hills, brown for mountains.  This mapping is purely temporary.  As the project advances I plan to build a climate and biome generator which will ultimately produce more varied and interesting terrain.

Different Worlds

The fractal world generator can produce worlds in a variety of styles.  For the two examples below, I decided to crank up the generator to 768x200 pixels.  Since each pixel of the fractal world will map to a hex, this gives us a campaign world of 153,600 hexes.  I plan to use a scale of 5 miles per hex myself, so this will give me a campaign map of 3,840 x 1,000 miles.  Of course, the size parameters will be adjustable in the final product.

The first example shows a world with three distinct continents, separated by oceans, with a few smaller land masses.









In contrast, this world is more amorphous, with numerous chains of islands connecting the larger continents.









Let's take a look at the amorphous world with the basic hex mapping applied.  Quite a bit of terrain there to populate and explore!  The next step will be working on the climate and biome generator to start producing some forests, swamps, deserts, and more.


Friday, January 2, 2015

Fractal Worlds

A World at the Press of a Button

The idea of generating a complete campaign world at the press of a virtual button is very intriguing to me.  My appreciation of randomness in RPGs began when I was surprised by how playable the random dungeons generated in the Warhammer Quest tabletop game were.  With a well-seeded set of random tables, an interesting story will unfold.

The Concept

There is already some great groundwork for dynamic campaign world generation out there, and new projects like Worldspinner look very promising.  But I'm going to take on the challenge of creating a campaign world generator as well.  My twist: the project will be powered by my DMMuse.com database of random tables and generators.

DMMuse is a curated, open repository of RPG generators.  The idea is for community members to help populate the tables, resulting in an ever-growing store of value.  With the DMMuse framework well established, I have an engine that can generate the random settlements, adventure locations, and lairs that will eventually populate the procedurally generated campaign world.

First Step - Elevation Map

The first step in creating the world is getting a basic world map.  I implemented a fractal world builder that spits out an elevation map of a randomly generated world.  An example is shown above.  This particular map is 150x100 pixels in size.  When converted to a hex map, that gives us a campaign map of 15,000 hexes.

Taking this elevation map and converting it into a basic hex map will be the next step in the process.