Big feature this time, dungeon generation.
There’s a new tab on the right hand side, you’ll recognize it by the Treasure Map icon. This tray is full screen no matter what your screen size is. I made this decision because of the complexity of the controls (just click the icon again to close the tray).
Once you have generated your map, click on any of the tiles to switch their state from open to closed (black to white and vice versa), so you can tweak any maps you generate to fit exactly what you’re looking for.
I have set the defaults to be Roll20 friendly making my maps match up with the Roll20 defaults as closely as possible so that dropping a map into place should only take a minute or two. The goal of this project is to create a bunch of tools to help me DM entirely by the seat of my pants, so hopeful it should be easy enough to do while dropping exposition on my players.
This one is a little more complex, so I’m going to go into more detail on how I went about doing this below. All of the images used to illustrate the text are generated by the DM Tools.
Dungeon generation is something I’ve been trying to do (with only some success) for several years for my other project, Goblin Puncher, but as that was the project I used to teach myself JavaScript and programming in general, I had a lot of failures and misunderstood successes with that.
But, something clicked the other night. I came across this post, disagreed strongly with significant portions of the implementation, but it had a nugget of knowledge I hadn’t come across yet, and it clicked with me.
I think a big piece of it is that when developing most business applications or even websites, you don’t really have to stretch the math or spacial reasoning muscles. Most business applications are about storing, finding, editing, and deleting data. So I’ve not had an excuse to spend much time brushing up on things I’ve always been interested in like pathfinding algorithms.
In this case, the tutorial introduced me to one of the oldest map generation algorithms: The Random Walk (aka The Drunken Walk). The algorithm itself is so simple that I’m a little dumbfounded I didn’t stumble onto it myself (mostly because I was over-complicating the issue). The gist is that you have four cardinal directions. You choose a random starting position and at any decision point, you randomly choose a direction that is not the way you came or the way you’re currently going. By staggering segment lengths you can end up with a very winding pattern, something like this.
Add another pass or two and you get slightly more complex patterns.
This is a passable dungeon on its own, but there isn’t a lot of variety. What few chambers are made are all irregular. The fix to this was rather simple. I had the script choose a constrained random height and width for a rectangle and then choose one of the points we’ve already drawn on as the origin (upper left-hand corner) of our rectangle.
It’s my understanding that this is the reverse of how a lot of dungeon generators work, as they build the chambers and then the paths between them, but this is the result it creates.
This gives a better feeling of a spiderweb of passages between rooms.
Once the actual generation of the dungeon was working, the rest was easy. The preview is a set of <div> elements with a percentage width and the same percentage top (this is a CSS trick for making responsive perfect squares with nothing in them). I just tied a click even to the <div> elements and toggled the state of the corresponding bool in the 2d array that is the map data.
Exporting to PNG was just as easy, just create a canvas and draw the squares at the scale specified by the user, export that to a dataURL and set it as the source of an <img> element. I could trigger a file download, and may in the future, but something just feels wrong about triggering a file download with JavaScript, even if it is at the response of a user. Gives me flashbacks to my hack of a file manager I wrote to extend CKEditor.