Ashley Sheridan​.co.uk

Building a Dungeons and Dragons Game

Posted on

Tags:

I'm a big fan of Dungeons & Dragons, and have been for years, first playing the book adaptions of the game, before moving on to the group tabletop version and the computer games based on the tabletop rules. The recent success of Baldurs Gate 3 has seen a surge in the popularity of the genre. I wanted to take this passion and turn it into something creative using my skills as a developer.

Contents

The Initial Project Aim

At first, my initial aim was a new take on an older project I'd taken on some time ago, building out a Dungeons & Dragons character sheet generator. However, this time I wanted to set my aim a little higher, and go beyond that to build out a collection of tools, and eventually a game based on the rules. Of course, my graphics skills are nowhere near on a par with even the basic 90's style of some of the early D&D games, so that will probably be the most challenging aspect when I eventually get to that point of this project.

The API

The first stage of this was building out an API layer that would be the basis for the project. This has all been built with Laravel, as it made the obvious choice for an API. Eloquent is tremendously powerful for building out complex models easily, and it really shines when updating existing models or adding new models, which a lot of the endpoints will need to do. Also, the JSON API resources make it trivial to output JSON responses. The majority of the endpoints so far are based around characters (as the initial approach has been with the character sheet generator in mind) to cover things like:

  • Creating characters
  • Listing characters and specific details of individual ones
  • Updating specific parts of information on characters via PATCH requests
  • Getting infromation on classes, races, languages, and spells available for a character

Using pivot tables with Laravel is a lot simpler than writing out the queries by hand as SQL, boiling down to a one line function to retrieve related models, and another single line to update the pivot table with new relationships.

Key Parts of the API

Some of the more interesting aspects of the API are the dice roll, name and item generators. These both generate random responses, but operate in very different ways. The name generator creates names based on different source types. A Markov chain then uses these various different source lists to generate new names, which can be used as suggestions when creating a character. This allows for a huge variety of new names to be easily generated, and can easily be adapted in the future to generate names of anything if I add further different sources, like places or future races/species.

The dice roll endpoint can generate rolls for any number of dice of the standard tabletop roleplay sides: d4, d6, d8, d10, d12, and d20. In the character creation process I use this to generate the ability roles for a character, based on the standard rules of 4d6 (4 × 4-sided dice), with the lowerst of the 4 discarded. The rolls are stored in the database, along with a generated UUID, and then when saving the characters stats, the UUID is passed in rather than the dice roll values. The aim here is to avoid cheating, as could be more easily done if it was all based on roll values.

There is a random encounter endpoint that returns an encounter based on the number of characters in a party and their levels, required difficulty, and the environment. This then uses the standard D&D rules to generate an encounter of 1 or more creatures that match the party challenge level (within a range of about 20%) for the requested difficulty. Currently, when it generates encounters of more than one creature, it repeats the same creature multiple times. Eventually I'll adapt this to create more complex encounters involving multiple types of creatures that might occur together, like gnolls and hyenas, or goblins and worgs.

Lastly, the item generator has a couple of different parts to it. First, there is a book generator, that creates random book title and description combinations. These are generated by picking random elements from a collection of book types, adjectives, themes, and description parts, that combine to form a variety of different general book types. The endpoint also has a random chance to return a scroll of a random spell type. While the book endpoint is a GET it does have a side-effect of saving a generated book/spell scroll to the database if it didn't already exist.

The last part of the item generator is for weapons and armor. This will return a random common item from the database, with a small chance of creating an rarer item type. It does this by picking a common item as a base, cloning it, then adding random attributes appropriate to that type (either armor or weapon). Like with the books, the item is saved to the database if it did not already exist.

Expanding the API

The plan is to expand the API to encompass all that a game needs, from generating more complex encounters, maps (both indoor and outdoor), handling combat turns, and eventualy creating whole campaigns and dialog.

The User Interface

I built the UI layer using Angular, as I've always found that to be very capable at building out complex interfaces. Using Angular 19 has been interesting, as a lot of things have changed since I last used the framework, such as InputSignals being used for inputs and other things, and the revamped templating syntax (I have to say, I honestly preferred the older syntax).

One thing I am doing here is to rely on AI for generating graphics, as that's something that I'm especially weak at. For things like portrait generation for the character races, it did a brilliant job:

Character race editing screen showing races, and associated subraces, with character portraits and race details

One thing I've been doing more on this project is to inline the SVG images as child components, using an InputSignal to determine which SVG to show from a series of related ones. While this does add slightly to the overall weight of each template once rendered, the perceived performance should be better, as there will be no flashes of content as external images load in. Also, it's far easier to colour an SVG using CSS if it's inline with the rest of the template HTML, like I have for the spells list section:

Character spell selection screen showing spells applicable for a character by their race, class, and level

At some point I'll need to create icons for individual spells, but with 361 spells in the database, that will certainly take some time, and I don't know if AI generated icons would really work given how niche the types of images I could need are. AI is great for things it has been trained on, but it's less useful for things like very specific D&D creatures and spells!

The Code

I've made the code for both the game API and the game UI parts available on Github. Each one is a seperate project which I've been running locally under their respective development servers where they happily work together. As I develop it further and get a proper security layer in (I've been focusing on features right now) I'll eventually host it and make it available for testing. But feel free to check out the code if you want, and let me know if you have any thoughts on it.

Comments

Leave a comment