Recently I released the first version of samovar, a roguelike dungeon crawler game. It took around six months to make, and is one of the few successful projects of this scale that I've been able to pull off. In this post I'll share some of what I learned from developing the game, as well as thoughts about future projects.
Samovar is a roguelike game, which means that it resembles an old game called Rogue: the entire interface is made of unicode characters, game content is randomly generated, and a mechanic called permadeath means that the player doesn't respawn after death. Roguelikes are a well-established genre, and have influenced more popular games like Minecraft and Dwarf Fortress. What inspired me to make one was a wonderful dungeon crawler called Brogue, which I've played for several years now. A great thing about roguelike games (Brogue included) is that they're not too difficult to program, at least compared to other games, but the "playability" can be incredibly high; with procedurally generated content, you can design deeply complex worlds that almost have a life of their own.
The special idea behind samovar was that you can brew different types of tea, and use it as a sort of potion -- hence the name samovar. For some reason, that idea alone provided a great deal of motivation, especially during the initial period of writing boilerplate. Ironically enough, the brewing system ended up relatively crude, because the game was too short and simple for anything more than that. Another idea that I latched onto was to use different species of semi-sentient mushrooms as the main type of monster, along with some other fictional cave creatures like "spaghetti worms." Admittedly, the worldbuilding was rushed and overly simple, but at least it wasn't completely incoherent. One of my main goals was to avoid nethackism, the practice of stuffing a fictional universe's lore with geeky in-jokes; in other words, I wanted to try and keep things original.
Overall, it took roughly six months to make the alpha version of samovar, from the beginning of May 2022 through October. I rarely ever finish hobby projects to the point of being "releasable," so it was very fortunate that I managed to work on samovar for such a long time. Even more fortunate was the fact that development ended when it did: the college semester was becoming more and more stressful, and only a few days later, an unexpected event threw a wrench into my personal life. Anyway, here are some interesting aspects of samovar's development:
I decided, for whatever reason, to write samovar in Common Lisp. Development was very smooth since lisp is a REPL-based language, so I was able to use emacs' slime-mode to interactively develop the game, rather than compiling and re-compiling after every small change. Lisp doesn't have a fancy type system, but this wasn't a huge issue, perhaps due to the type of software I was making, or because of my own ignorance (I'm sure there are many bugs that I haven't found yet). Another great feature of lisp is its lists, which I exploited to make all sorts of ad-hoc data structures.
Terrain generation was my favorite aspect of the game to work on. It was surprisingly easy to experiment with different procedural generation algorithms, and the process of building a level, adjusting a few parameters, and then re-building was addictive. It didn't take too much to create impressive levels, reminiscent of big-name roguelikes such as Angband or Nethack. Aside from the visual aspect, though, there were subtle things like "rhythm" (the pace of exploring a level) that proved extremely difficult to design.
One of the things I love about Brogue is how vibrant its colors and lighting are, and I wanted to have a similar aesthetic in samovar. Lighting was pretty fun to design and experiment with, although I never quite got it to the same level as Brogue.
One of the first things I did was implement a few fundamental algorithms, like recursive shadowcasting and A*, so that I could start working on almost any other aspect of the game afterwards. This proved to be an excellent strategy, and probably sped up the development process quite a bit.
I only started working on monster AI near the end of development, and consequently wasn't able to put as much energy into it, because at that point there were so many other loose ends that I had to spend time tying up. The monsters act pretty dumb as a result, and aren't able to coordinate with each other. Still, I managed to write a few interesting features. One of the many things I love about Brogue is that, when you get to the deeper and more difficult weapons, there are monsters that shoot sparks, lightning bolts, dragon fire, curses, etc. at you, which does a lot to punch up the drama of the game. I added some simple mechanics like that to samovar, including a deadly type of thing called a "c-beam," which has a scary-looking animation. Monsters capable of using beam weapons are able to choose a good time (in theory) to launch the beam, which slots into the crude AI system pretty well. There are also a few simple monster behaviors like replication and vampirism.
Even more difficult than AI was designing the progression system, which involves how level structure changes over time, what sort of weapons are introduced, how the player levels up, how difficulty changes, and so on. Progression ended up being very rudimentary, as I found it hard to design an appropriate system given how short samovar is (<15 small levels, with not too much content).
Recently I installed OpenBSD on a whim, and realized that samovar can't really run on my new system. The exectuable that sbcl produces requires more memory than OpenBSD allows; and while I could always tweak the system-wide configuration to change this, that's still a big compatibility issue. Second, the game uses a library called BearLibTerminal for its user interface. Unfortunately, there isn't an official release of BLT made for *BSD systems, and although I tried to compile it from source, the resulting library was riddled with bugs. With all this in mind, it's clear why many roguelikes use a very simple "tech stack," like C and ncurses, in order to maximize cross-platform compatibility.
There are no plans for another release of samovar, simply because it's not the sort of software that I'm willing to maintain and continually work on. It would be nice if I made some game (or other program) that deserved that amount of long-term dedication, but in order to reach that point, I need to experiment and try new ideas right now.
Along those lines, I've decided to try making another roguelike as my next project. When it comes to hobbyist software development, games seem to be a decent niche: the constraints of practicality are less demanding than, say, if you were writing a text editor; and the amount of creativity and deep thinking you can put into a game is basically arbitrary. With samovar I was able to get a decent understanding of the fundamental mechanics behind roguelike games, which should make it easier to get the next project up and running quickly. Then, I can improve upon the finer aspects of game design. My goals for this future project are:
- Juice: there should be more visual and narrative feedback.
- Lighting: graphics should approach Brogue in terms of sophistication.
- Compatibility: see earlier in this post.
- Rhythm: the game should have a better system for progression, and individual levels should be paced out in a more satisfying way.
- Worldbuilding: it should avoid nethackism, and there should be lots of deep content that all fits together.
- AI: monsters should interact with each other more, and should have more complex goals than just attacking the player.
Anyway, that's the roguelike postmortem. Developing this game was a rewarding experience, and by finishing it, I proved to myself that not all projects of this scope will end in failure or disillusionment. Especially if you're interested in making or playing roguelikes, I hope you found this blog post insightful in some way or another.