Amaranth, an Open Source Roguelike in C#
↩ ↪June 11, 2010
Update 2021/10/08: I moved the code to GitHub and updated the links below. I also ported it all to Dart: Piecemeal (was Bramble), Malison, and Hauberk (was Amaranth). The game is still nowhere near being done.
Tonight I get to do something I’ve wanted to do for a really long time: I’m open-sourcing the roguelike I’ve been working on for several years. Amaranth is an old-school terminal-based roguelike written in C#. It looks like this:
Because I’m crazy about decoupling, it’s actually split into three separate projects:
Bramble is a very small low-level library containing utility classes. It doesn’t rely on anything beyond core .NET collections and provides more useful 2D vector and rectangle classes, along with some other handy stuff. Even if you aren’t working on a game, there may be something in here you can use, which is why it’s separated into its own project.
Malison is the terminal library Amaranth uses for its user interface. Like many roguelikes, Amaranth doesn’t have graphics. Instead, it draws the game world in ASCII like an old computer terminal. Malison is a generic library for drawing to a virtual terminal. Even if you don’t care about Amaranth, Malison should be exactly what you need if you’re going to write your own roguelike or other terminal-style app in C#.
One nice feature it has is that it decouples a logical terminal from a specific renderer. It provides a renderer using WinForms, but it should be simple to implement other renderers on top of XNA, WPF, or Silverlight. Code that writes to a terminal only knows about the abstract terminal API, which means you could have a single game engine that supports rendering to a bunch of different terminal implementations. I wrote about the design of the terminal API in this post.
Amaranth is the actual game, or the beginnings of one. I have lots of work left to do here, but a lot is also done. I’ll be writing more about interesting bits of the engine, I hope. In the meantime you’ll have to dig around in the code if you’re curious. Some fun stuff it supports:
The game engine is completely decoupled from UI. It was designed so that if I later write a graphical front-end for it, zero engine code would need to change.
The game loop handles different entity speeds, decoupling from UI, makes no distinction between player-controlled and AI entities, and makes clever use of coroutines.
Game content is data-driven and loaded from friendly human-readable text files.
Expected roguelike features are in there: random dungeons, line-of-sight, field-of-view, inventory, stores, spells, etc.
The game loop was designed to support emergent behavior and interactions between entities. For example, hitting a monster could cause it to explode in a fireball which will in turn light a nearby torch, blinding an adjacent zombie. (There isn’t content for this stuff yet, though, just engine support.)
No global state. Singletons are for amateurs.
It’s all up on GitHub: Bramble, Malison, Amaranth. Feel free to try it out, fork it, or whatever. In the meantime, I’ll try to find time to start writing some documentation on more interesting parts of what’s in there.