Categories
Eldritch Eldritch 2 Slayer Shock

Turtles (All the Way Down)

My procedural level generator has come a long way since Eldritch, and outside of the occasional forum post or summary tweet, I haven’t documented it in any meaningful way since 2015. I’ve made a lot of changes for game jams and abandoned projects between 2017 and 2023, and I’ve recently made even more changes as Eldritch 2 takes a clear shape in my mind. I’m sure there will be more changes along the way, but this is the current state of it.

Prologue: Goals

I’ve used versions of this procedural level generation system in two commercial titles (Eldritch and Slayer Shock) and three recent game jams (NEON STRUCT: Desperation Column, Li’l Taffer, and Schloss der Wölfe). These games each have different goals and different reasons to use proceduralism. Eldritch was a roguelike (or roguelite), and it used procedural levels in the conventional roguelike way, generating new dungeons after each player death. Slayer Shock was a longer campaign game where total failure was a rarer occurrence, so it used procedural levels to create the dozens of missions a player might attempt throughout that campaign. I only expect my game jams to be played once, but they used a mix of bespoke and procedural level design to offload some of the burden of making levels under limited development time constraints.

I have made just as many games and game jams that did not use procedural levels at all. I believe procgen is a tool to use when it supports a game’s design and production needs, and its development should be guided by those needs. When I was invited to speak at GDC about the level generation in Eldritch, I called my talk “Procedural Level Design” rather than “Procedural Level Generation” because every decision I made on that algorithm was a level design decision.

Chapter 1: Eldritch

I spoke about Eldritch‘s procedural levels in length at GDC, and you can watch me be uncomfortable at public speaking or you can make us both happier and just read the slides. Also, Eldritch‘s levels were heavily inspired by Spelunky‘s levels (just extruded into 3D), and I highly recommend reading Darius Kazemi’s excellent interactive guide to Spelunky‘s generator. But a quick summary:

Eldritch‘s generation began by generating a maze on a small 4x4x3 grid, where each grid cell represented a 12x12x8m block of space. After that maze was created, it would randomly open some additional paths to create loops in the maze. Then it would turn that into a real space by populating each cell in that grid with a “room”: an authored 12x12x8m chunk of level design, consisting of voxels and entity spawners. Each room was built to fit a certain configuration of maze directions (north, south, east, west, up, and down), and during generation, a room would be selected at random from any of the authored rooms that could fit a maze cell.

In order to minimize the amount of rooms I had to create and to maximize the apparent variation, each room could be used in any of 8 transformations: its default, or rotated by 90, 180, or 270 degrees, and a mirror image version of any of those. These were extremely simple to do because the rooms were made of voxels, so any rotation or mirroring was an axis swap or negation on the voxel grid indexing.

There was one additional step: “feature rooms” were emplaced at random locations as seeds for maze generation, and to ensure that essential features like an entrance and exit—or random features like shops and bank vaults—would appear in the maze exactly as often as the game required. These were guided by rules that would, for example, place the entrance room on the top floor and the exit on the bottom, or make a shop have a random chance of being open, closed, or entirely absent.

Every room filled exactly one cell on the maze grid. For larger features like the ziggurat at the bottom of World 1 or the outdoor snow field at the start of the Mountains of Madness expansion, I had to build big spaces out of smaller chunks, and emplace them as multiple feature rooms with fixed locations and fixed transforms. It was pretty gross.

My main goal in Eldritch was to create interesting gameplay space; it didn’t matter much if rooms fit together neatly. The Lovecraftian theme supported bizarre, unknowable geometry, so if two rooms didn’t quite align spatially or thematically, that was fine. It worked for the game! And it turned out to be an essential part of the randomness of the game, as I would find out on subsequent projects where I added more constraints.

Chapter 2: Vamp

With Slayer Shock, the modern real-world setting and procedural mission objectives demanded some changes:

  • I wanted spatially coherent procedural levels; no more random crashed-together Lovecraftian spaces
  • I wanted levels to be any size, not limited to a small 3D grid
  • I wanted rooms to be placed according to a critical mission path, not expanded randomly in a maze
  • I wanted rooms to be any size, not limited to one cell in the 3D grid
  • I wanted rooms to be composed of static geo meshes and navmesh, not voxels

The sum of these needs represented a huge delta from Eldritch‘s generator, and I rewrote nearly the entire thing. The maze generator went away entirely, replaced by a portal-based algorithm of placing rooms one by one, wherever they could fit to connect to open portals from existing rooms. Rooms now defined their available connections by portal tags—for example, a cave portal could connect to another cave portal, but not to a forest portal; and caves and forests could be joined by special junction rooms with a cave portal on one side and a forest portal on the other.

Feature rooms were no longer seeded randomly within a maze grid, but placed in sequence along a non-branching critical path which was laid out before any subsequent room expansion. This was mainly used to place entrances, exits, and junctions between indoor and outdoor areas like caves and forests.

Every region in Slayer Shock had very different requirements, and my codebase got very messy with special case hacks for each. The introduction of so many content-driven rulesets also meant that the algorithm now had the possibility to fail (which was literally impossible in Eldritch as long as there was a complete set of room configurations). And it did fail often, making level generation much slower as it continually restarted with new random seeds until a successful world was found. Worse than that, it meant that viable levels tended to be very similar. I successfully “fixed” the chaos of Eldritch and ended up with something very predictable and bland.

Chapter 3: Loam and Zeta

In 2019, I began developing a side project fantasy dungeon crawler codenamed “Loam”. That project is currently abandoned, though I’m holding onto it because it feels like it could be my magnum opus. But also it being my potential magnum opus is why it’s currently abandoned, because it was extremely overscoped as a thing to work on in my free time.

My primary goal with proceduralism in Loam was to build levels that looked like D&D maps and played like immersive sim levels. I tore out the critical path stuff from Slayer Shock and focused on how rooms were connected within a smaller space. One of the problems that kept coming up was “the door problem”: when two rooms join, where and how do I spawn a door between them? The door spawner has to belong to one room or the other; how do I ensure that there is a door and that there is only one door (i.e., both rooms aren’t trying to spawn at door at their shared boundary)? I eventually decided to use portal tags to enforce placement of small spacer tiles between rooms, and put the doors in those spacers.

I also wanted to minimize failure cases in the level generator. Most failures were due to unclosed room portals: meaning a room was placed with an open exit, but no rooms could fit beyond that exit. I solved that by allowing the generator to conclude its main expansion phase with some portals left unclosed, and then connect those portals via a series of small connective tissue tiles. These tiles are guided by a graph search between unclosed portals, and guarantee closure and connectivity as long as there is a path. The enforced space between rooms provided by the spacer tiles usually affords such a path; and as an extra step to ensure this worked well, I implemented a limited “rewind” of the generator so that spacer tiles which could not be closed would be removed and replaced with connective tiles.

My first game jam to use this algorithm was NEON STRUCT: Desperation Column, but it used an extremely constrained room set so the connective algorithm never kicked in.

Chapter 4: Fray, Lily, and Wolf

Since Eldritch, my level generator had been fundamentally an indoor generator. I faked outdoor space in Slayer Shock (at the cost of huge performance problems), but it was fundamentally designed to connect small convex rooms to other small convex rooms. I wanted to do something bigger.

In 2022, I was working on a side project codenamed “Fray” which could be summarized as “indie Far Cry Star Wars immersive sim”. Yeah, that one was overscoped too. But one of my goals was Far Cry-style outposts: small indoor complexes within a broader outdoor space, that the player can approach from any direction and scope out before attacking. It would require a radical rethinking of not only my level generator but my sector/portal-based renderer as well.

My solution was to use generators within generators. At the outdoor scale, I would generate very large “rooms” on a coarse grid; and then within those rooms, I could generate indoor sublevels comprised of smaller tiles. The most significant constraint—due to the way sublevel and superlevel portals were connected for the renderer—was that a sublevel had to be contained entirely within a superlevel room’s space; I could not use a small sublevel to connect two superlevels. But that worked fine for my Far Cry-esque goals, and I got it working in about a week.

Shortly after that, I got the idea to use room and sector “colorization” to guide room placement, so that I could build levels with sequenced gating: for example, a player must collect the red key and unlock the red door before they can access the red part of the map. I didn’t have a specific goal in mind for this, it just seemed useful and I realized it wouldn’t be too difficult to implement.

I first shipped this version of my level generator in Li’l Taffer. It had no actual outdoor generation, instead using a fixed outdoor space with a single interior generator; but the colorization feature ended up being used to demarcate the public and private space within the mansion the player is tasked to rob.

The broader feature set finally got a shipping use case in Schloss der Wölfe, which is a largely linear experience but used nested generators and region colorization to make indoor/outdoor portaling work for the renderer, to guide placement of entities, and to provide some small variations on replays.

Chapter 5: Rasa and Tofu

Shortly after I released Schloss der Wölfe, I started another game jam—something akin to The Unfinished Swan or Scanner Sombre where the player starts effectively blind and uses a tool to identify the space around them. I ended up bailing on that to focus on Eldritch 2 instead, but in the short time I was working on it, I added “furnish rooms” to my generator.

Furnish rooms function almost identically to sublevel generators (i.e., the indoor parts of an outdoor room), but they do not create new sectors and portals for the renderer. Instead, they just add all their geo to their containing room. This gave me a way to build most of a room by hand but then let the whitespace be filled in randomly.

I bailed on that game jam and returned to Eldritch 2. The last big thing I needed to address to make all of these years of changes work for this game was a problem that had been lingering since Slayer Shock. Ever since I moved from voxels to mesh-based rooms, I’d needed to make sure that navmesh edges fit together precisely so I could stitch them up after rooms were placed. This prohibited me from doing the sort of chaotic crashed-together spaces of Eldritch, because every edge of every room needed to conform to a consistent navmesh signature. I waffled on this for a while, but ultimately decided that the accidental chaos of Eldritch‘s worlds was something I needed to now intentionally repeat. I rewrote some big chunks of my navmesh stitching and pathfinding code, and now my generator will stitch together any overlaps in coincident navmesh edges, to ensure that AIs can navigate between rooms as long as there is any actual space to do so.

I also finally reintroduced two Eldritch-era parts of the generator: mirrored rooms (a whole separate blog post in and of itself because of all the new requirements of mirroring meshes and navmesh, through multiple stacked transforms) and feature rooms, which are now emplaced at two stages: first as seed rooms before the map is “colorized” for gating; and then in a second pass, for feature rooms which may depend on that region colorization.

All of this leads to the current state of Eldritch 2‘s level generation. Levels are formed by a series of nested generators (outdoor overworlds with indoor dungeons, both with rooms optionally populated by random furnish rooms); with optional sequence gating, either within the overworld or within any dungeon; and each nested level seeded parametrically to guide placement of special features like shops and bank vaults. Room placement can still fail at any step depending on the authored room content; but as long as I populate all the common cases and keep the constraints reasonable, it rarely does. And the generator produces interesting levels in under 200ms, keeping load times to a minimum.

Categories
Eldritch Eldritch 2 NEON STRUCT Slayer Shock

Rosa

I’ve been developing games professionally for 17 years, and I’ve been developing my personal engine Rosa for about as long. This isn’t going to be a post about whether or not you should make your own engine. I generally wouldn’t advise it, but you should make your own decision. I made my decision a long time ago. I love making games, but I love programming too; and engine development provides some of the most satisfying programming challenges. This is a brief history of Rosa and my current ideas for its future.

The origins of Rosa came from my student work at SMU Guildhall (2005-2007). As part of the curriculum, every programming student had to build their own 3D game engine, with OpenGL and Direct3D rendering, audio, input, collision and physics, etc. The more game-specific parts of an engine were left to each individual to focus on, and I chose to pursue AI with studies on behavior systems, awareness models, and pathfinding. This was my first time writing a 3D engine from scratch, and I got it done but it was messy.

When I graduated in 2007 and became a full-time professional game developer, I also began building a new personal engine, taking the good parts of what I had learned and cleaning up the messier, poorly-architected bits. Incidentally, I jettisoned OpenGL at this point, believing Direct3D to be the way (and Windows to be the only OS). I did this work mostly for fun, but I also hoped to eventually make a game of my own. Between 2007 and 2012, I built a lot of engine parts without ever getting close to actually shipping a game.

Brass City Couriers (unfinished, circa 2009-2012).

I leaned on Blender heavily at this time, even using it as my level editor because that seemed easier than building a level editor. The lighting model was baked and static, encoded into level geo as vertex colors and applied to dynamic meshes through a coarse volumetric directional ambience grid. Game objects were inheritance-based. Development was slow.

Codename “Agency” (extremely unfinished, circa 2012).

In the summer of 2011, I was frustrated with the inheritance model of game objects and decided to experiment with this fancy new “Entity Component System” concept I’d been hearing about. I was also eager to explore procedural generation, for reasons I don’t quite recall but probably had something to do with Minecraft. I built a simple textmode graphics framework and began building an infinite procedurally-generated world populated with composition-based objects. It was fast, it was fun, and in retrospect, it may have been the most important step I could have taken in my career.

Second Order (unfinished, circa 2012).

In early 2013, I left the relative security of my Big Commercial Games job and went into business for myself. (A few months later, my brother did the same and we formed Minor Key Games.) I had a very limited budget and needed to ship a game in around 8 months. The obvious choice might have been to lean on all the tech I had built over the prior 6 years, but instead, I ripped it all up and streamlined everything. I used the simplest possible art and rendering: all albedo, no normal maps, no specular lighting. I rewrote my collision code for AABBs exclusively, because it’s fast and simple and I was using voxels so everything was axis-aligned anyway. And I incorporated some ECS concepts to make game object composition and reusability a breeze.

Eldritch (2013), Minor Key Games.

My engine didn’t have a name at this time, but I’ll call this Rosa v1. Eldritch was a modest success and I followed it with my Thief-meets-Deus Ex cyberpunk stealth love letter NEON STRUCT. I didn’t make many engine changes for Neon; I improved my tools and optimized the voxel lighting grid to support turning lights on and off at runtime, but it is fundamentally still Rosa v1: all albedo, with voxel worlds.

NEON STRUCT (2015), Minor Key Games.

By the time I finished Neon, I was growing tired of Minecraft comparisons. I liked the ease of working with voxel worlds, but I couldn’t escape the shadow of the king of voxels. I was also starting to feel constrained by how much I had cut my engine to the bone; in particular, I was constantly working around the lack of dynamic lights and eager to rebuild my rendering skills. I undertook a substantial overhaul of my engine during development of the next game, removing voxels in favor of mesh-based geo and replacing the simple forward renderer with a deferred renderer using a principled physically-based lighting model.

Slayer Shock (2016), Minor Key Games.

My engine still didn’t have a name, but I’ll call this Rosa v2. Slayer Shock missed the mark, but that’s a story for another time. I ran out of money around the end of 2016, got a job, and largely put my engine and my games aside for a while. From 2017 to 2020, I dabbled in a couple of projects but ultimately got nowhere. But while copying code back and forth between a couple of projects and renaming classes to match the project, I realized that it would be easier if I had a unifying name for game-level classes in my codebase. So instead of renaming top-level classes like EldritchFramework to NeonFramework to VampFramework, all my games could use one common codename. I picked “Rosa” because it was like tattooing “MOM” on my arm, and that became the de facto name of my engine.

In 2020, stuck inside while a pandemic raged on, I started doing game jams to scratch the indie dev itch. I finished four game jams that year, and have done at least one every year since. These game jams culminated in what I consider a trilogy of minimalist first-person games: NEON STRUCT: Desperation Column, Li’l Taffer, and Schloss der Wölfe. Each of these improved upon my engine’s pipeline and workflow, largely by leaning on procedural generation. I developed tools to quickly generate procedural meshes and materials for world geo, and I reinvented my procedural level generation algorithm to create indoor spaces nested inside larger outdoor spaces. These three games also share a common visual style which I’ve been calling my signature “toy aesthetic”.

Schloss der Wölfe (2023).

I consider this current generation of the engine to be Rosa v3, and it is the engine I am now using to develop Eldritch 2. It combines the fast iteration and relatively simple art pipeline of Rosa v1 with the physically-based dynamic lighting and materials of Rosa v2. It’s a joy to work in, and work on. My current work is revising my procedural level generation (again) to bridge the gap between the more spatially plausible worlds of my recent game jams and the intentionally bizarro crashed-together spaces of Eldritch.

Looking to the future, there’s at least one unavoidable tech task that I need to deal with. Rosa is still using Direct3D 9 and OpenGL 2, absolutely ancient graphics APIs that have increasingly fragile vendor support. I don’t feel the need to upgrade for any particular modern features—I’m actually rather happy working with 20-year old tech—but OpenGL is no longer supported on Mac and getting a modern Windows PC set up to build a Direct3D 9 app requires jumping through a lot of hoops that they would clearly developers not do anymore. I’ll have to port to Vulkan eventually, and probably Metal if I ever want to target Mac again.

That’s a lot of words, and I’ve barely scratched the surface of my engine. I’ve got some tech that has been largely stable since as far back as Eldritch: AI behavior trees, event + reaction gameplay scripting, collision detection and sweeps/traces. I’ve got a custom cook process that is fast as heck. I’ve shipped 13 games or game jams on this engine, and it has grown a lot along the way. And I’m excited to keep using it!

Categories
Eldritch

Eldritch: Permalife in Indie Games

About ten months ago, I released Eldritch. I followed it quickly with Mac and Linux ports in November and a free expansion in December. I documented the process on this blog, and stated that “the story of Eldritch isn’t over yet.” I was correct, but not in the way I thought.

Sometime during Eldritch’s development, I had looked up H.P. Lovecraft’s birthday. I can’t remember exactly why. I was probably hoping to launch on that date as a tribute to the author who inspired the game’s world and creatures. But his birthday fell on August 20, and I was nowhere near being able to ship on that date in 2013. So I put that idea in my pocket. Maybe I could do a sale on that date next year, I thought.

In early 2014, around the time I wrote the post-mortem article, I was in preliminary talks to bring Eldritch to an unspecified console. Over the following months, I made decent progress on that port, despite my inexperience on the hardware. But with a limited budget and my own uncertainty about sales on the particular platform, I eventually chose to walk away from that and focus on my next project, NEON STRUCT. I began telling people I was done with Eldritch, that I had made the game I wanted to make and I was ready to move on to something new. I released the source code in April, ostensibly an act of some finality. I dove into production on NEON STRUCT, and Eldritch became my past.

With August 20 approaching this year, I reached out to Humble and Valve to set up a 24-hour sale for Eldritch. My representative at Valve offered to make Eldritch the Steam daily deal for that date, but asked if I would have an update to coincide with the sale. I didn’t have anything prepared; Eldritch was my past, right? But landing a highly visible spot on the front page of Steam was a bigger deal than I had expected. So I took a brief hiatus from NEON STRUCT and began preparing a Steam-centric update for Eldritch.

The community had requested trading cards and achievements since launch—as they do with every game—but I had chosen not to add those things for mostly personal reasons. I didn’t understand the appeal of trading cards, and I felt that achievements were antithetical to the “play it your way” mentality of the game’s design. A year later, my feelings on those have shifted. Achievements exist for players who like to get achievements; people like myself who value the “play it your way” design don’t necessarily care about achievements, or are perhaps the most willing to play a game multiple times to get all the achievements. Either way, the presence of achievements should not detract from a player’s experience. As for trading cards, I still think they’re a bit silly; but I have spent funds from my Steam Wallet to complete my Spelunky card set, so who am I to deny someone their trading cards? I’m happy to finally bring Steam achievements and cards to Eldritch.

Adding cards and achievements was a good start, but it wasn’t a substantial update on its own. I wanted to add new content for people who weren’t also interested in those features; and secondary to that, I wanted to experiment with more Steamworks features like leaderboards. After pitching a handful of ideas around, I lighted on the concept of a small challenge mode that would fundamentally change the objective of Eldritch. Where the original levels were always about going from point A to point B (albeit in creative, player-directed ways), this expansion would be about mining the world for resources. Thorough exploration, not speedrunning, would be the dominant play style.

The result is a new dungeon, the Asylum of Azathoth. In this world, the player is charged with collecting and freeing trapped souls; but she has only three minutes in each level to do so before the chaotic deity Azathoth arrives to gobble her up. The difficulty and the pace of the Asylum are unlike anything previously seen in Eldritch, and I am eager to see what strategies players discover to maximize their soul count in the Asylum.

So, is this the end for Eldritch? I can’t say anymore. I have no further plans for it now, but it is a game that lends itself well to expansion. And every time I return to it, I recall how much fun Eldritch is to develop and to play. Maybe I’ll revisit it again in the future. For now, I hope you enjoy this update! Cthulhu fhtagn!

Categories
Eldritch

Eldritch: Mountains of Post-Mortem-ness

Last April, I began working on a game. In October, I released it. This is the story of Eldritch.

(Note: Sales info including pretty graphs is provided near the bottom of this post.)

Background

I’ve written before about the good times at 2K Marin; and if that were the whole story, it would seem ridiculous that I would ever leave that place. Sadly, it didn’t remain that way for long. The story of The Bureau: XCOM Declassified is a complicated thing, and perhaps someday, I’ll be up to the task of telling my version of it. It was a frustrating and depressing project that seemed to never end, and I watched many good friends and colleagues depart for greener pastures over the years. I contemplated finding a new job. I spoke with a few great developers about new opportunities. And I entertained the fantastic notion of “going indie” and making the games I had been longing to make for years.

In March, my wife Kim received a sizable bonus payment for her work on the Skylanders games. It was enough to pay off her student loans as well as mine, which she graciously offered to do. I suggested that I could instead take that amount and use it to fund a few months of independent development. We discussed it for a week, and the following Friday, I gave notice at 2K. Between Kim’s investment, my savings, my 401k, and a very significant number of unused vacation days, I estimated I had enough funding to survive until just about the end of 2013. It was time to get to work.

Making a Video Game

The development of Eldritch was a blur. I planned it carefully to fit my strengths as a programmer and designer, to minimize technical risks, and to be finished with enough time and money left to test, promote, and sell it. The core systems came together rapidly. I shared a playable build with a few close friends after less than two months, and continued to solicit feedback from trusted friends and colleagues on a monthly basis until its release.

The shape of the game hardened around the end of August. My original schedule had Eldritch shipping in December, but a combination of being well ahead of schedule and running a bit short on money urged me to move that up. I chose late October for the release date, avoiding (as much as possible) the hype haloes surrounding the Grand Theft Auto V and PlayStation 4 launch windows. That left me with just under two months to promote Eldritch before its release.

Marketing and Greenlight

With Eldritch mostly finished, I turned my attention to marketing. I created a website, captured footage and screenshots, cut a trailer, set up a Steam Greenlight page, wrote a press release, and prayed anyone would take my game seriously. Making the initial announcement was perhaps the single most nerve-wracking part of the entire development process. The response over the next 24 hours would determine whether I had made a huge mistake by going indie or making Eldritch.

On September 9, I flipped the switch: eldritchgame.com and the Greenlight page went live, a few dozen press release emails were sent, tweets were tweeted, and I held my breath. Within minutes, PC Gamer had posted a preview. Presale purchases began rolling in. Greenlight “Yes” votes trended above 50%. I exhaled.

Beta

I had done extensive playtesting with friends and family, but that group could only provide a narrow cross section of hardware for compatibility testing. Eldritch wasn’t the first game I would ship using my homegrown engine, but it was the first one I was asking money for, and I dreaded seeing a forum full of disappointed users who bought the game and then couldn’t play it.

My solution was to do a soft launch of the finished game, call it a beta, and try to fix all the major issues before the announced release date. For the purpose of compatibility testing, this worked well. I got a lot of useful bug reports, fixed at least one major rendering error, and even had time to incorporate a few small gameplay changes suggested by the early adopters. What I could have done better is to effectively communicate that the game was content complete. In this age of early access games and perennial updates, calling Eldritch a “beta” while presenting a Minecraft-inspired aesthetic invited players to misunderstand the state of the game and my intentions for it. (To this day, some users still mistake Eldritch on Steam for an early access game!)

An unexpected consequence of this phase of testing was discovering how many players felt betrayed by the relative ease of Eldritch compared to most other roguelike games. That was something I had never heard from my family and friends playtest sessions; and for my part, I still feel that Eldritch’s difficulty sits right where I wanted it: challenging for the majority of new players, but giving way to a feeling of mastery within a few hours instead of dozens or hundreds of hours. But happily, the beta phase provided the opportunity for me to make the eleventh hour addition of a more punishing New Game+ mode, which seems to have mostly satisfied the more hardcore players.

Greenlight

Shortly after launching the beta, Eldritch was greenlit for Steam. It took me by surprise; the Greenlight numbers had been strong, but there were still a significant number of games ranked higher than it when it was selected. I can only guess that the impending release date may have been a factor. I have mixed feelings about Greenlight (and the greater Steam developer experience), but my experience with it was obviously very positive compared to many other developers.

For better or worse, being on Steam is not an automatic windfall anymore. In fact, it looks like being on Steam may be the barest necessity for financial success for many developers. It’s a complicated topic which perhaps warrants a separate article.

Let’s Play

Eldritch has received a good amount of press coverage, from its initial announcement to reviews through the recent release of the Mountains of Madness expansion. I’m grateful for all of it, but nothing has made as big an impact on traffic and sales as being featured on high profile Twitch and YouTube channels. During the month when Eldritch was on Greenlight, I observed large boosts in “Yes” votes after each new feature video.

As YouTube and some major publishers continue to make it harder for these creators to monetize their videos, I encourage independent developers to make it easier. Get in contact with YouTubers, and make it easy for them to get in contact with you. Make preview builds readily available. Publish a written statement authorizing monetization of footage of your game. Game developers and YouTubers can have a very healthy symbiotic relationship, and if that’s something that the industry heavyweights aren’t interested in, indies will eat their lunch.

Mac and Linux

I was very interested in doing cross-platform PC development with Eldritch, but I had no prior Mac or Linux experience. I didn’t want to jeopardize the Windows release, so I decided to ship first on Windows and then consider porting to other operating systems. This would also allow me to evaluate the early sales numbers and do a simple cost-benefit analysis to ensure that I would be likely to recoup the time and money spent porting.

Then I got bored waiting for the Windows launch and just started doing it. It took less time than I expected, and I released the first Mac and Linux candidates just three weeks after the Windows launch.

I rewrote the entire Direct3D renderer to remove dependencies on the D3DX helper library. In particular, I had been using D3DX to load .fx shader files and manage render states, and porting to OpenGL would require the engine to manage render states itself. I quietly patched the new Direct3D renderer into the Steam version of Eldritch, and incredibly, it caused zero new bugs and performed slightly better. With the new renderer in place, I was able to implement a parallel OpenGL version. I targeted OpenGL 2.1 because it seemed mostly equivalent to the Direct3D 9 feature set that Eldritch uses.

I also wrote parallel implementations for the windowing, input, and clock systems, replacing Windows API calls with cross-platform SDL calls. (In Windows, I can compile the game either using the Windows API or SDL; the released version still uses the Windows API because switching to SDL seemed unnecessary.)

Finally, I installed Ubuntu and began learning how to actually build an Eldritch executable for Linux. This (and the equivalent work on Mac OS X which followed) was the most tedious part of the port: lots of mucking about with unfamiliar IDEs, searching for obscure compiler flags, and rewriting MSVC-safe code to make gcc happier. It was boring to do, it’s boring to write about, and it’s probably boring to read about. Moving on, then.

Localization

Besides the Mac and Linux versions, localization was the biggest feature I wanted to add to Eldritch after release. I had designed the textual parts of my engine to be localization-ready many years ago, but had never actually had an opportunity to use it. I also knew that my system only supported the Latin alphabet and would need to be revised for Cyrillic-based languages.

I couldn’t afford to pay a localization team (my old friend, the cost-benefit analysis, didn’t see a lot of money in translating Eldritch), but after receiving a couple of unsolicited offers to translate Eldritch for free, I decided to test the waters and ask for volunteers. The response was amazing, and I am incredibly grateful to the folks who generously donated their time to translate Eldritch to nine more languages.

In order to support the Russian and Ukrainian translations, I needed to finally make my engine Unicode-aware. This process was surprisingly painless, because UTF-8 encoding meant I only needed to change code where I loaded strings or displayed them. When storing, searching, or modifying strings, I could still just treat them as null-terminated char arrays. The biggest roadblock to Cyrillic support almost ended up being the fonts I had chosen; only one of the three fonts has Cyrillic characters, so the entire game uses a single typeface when playing in Russian or Ukrainian.

Madness

The early response to Eldritch was almost universally positive, but even the positive reviews often cited a scarcity of content as a weakness. This response, coupled with the earlier frequent misunderstanding that the game was an early access title or would receive perennial updates, steered a lot of conversation about Eldritch in the direction of “what will the developers add next?”

My initial plan was to add nothing next. In my mind, Eldritch is a complete game, a short but endlessly revisitable adventure that respects the player’s time instead of dragging on. But it is also the sort of game that lends itself well to expansions. It is pure, unburdened by narrative, and straightforward to pin new levels, enemies, and weapons to the existing structure of the game.

When I was reading a lot of Lovecraft and mentally filing ideas away for inclusion in Eldritch, At the Mountains of Madness was a story I felt deserved more room than I could have given it in the original game. I borrowed its shoggoths but left the rest for another day, and the idea of an adventure set in the semi-abandoned cities of Antarctica was the only choice I ever considered for the expansion.

The decision to release the expansion for free was a risky one, which sadly didn’t pay off exactly as I’d hoped. While a few players had expressed a willingness to pay for more content, many more had commented on the brevity of the original release with a more disappointed tone. My plan was to release Eldritch: Mountains of Madness for free as a gesture of appreciation for satisfied players and of good will to those who felt slighted by the length of the original game. It would not generate any revenue directly, but a free expansion would provide another opportunity to promote the game and a good hook for more press coverage. Unfortunately, I didn’t consider that so much of the press would be shut down on holiday just around the time of the expansion’s release. I appreciate the coverage it has received, but it was not the well-timed tidal wave of promotion I had hoped for.

Costs

The primary cost of developing Eldritch was the burn rate of my own living expenses: rent, utilities, food, etc. I effectively took a 45% pay cut compared to my former salary, and I did my best to forego unnecessary purchases until Eldritch began generating income. Other significant costs included middleware licensing and contractor payments. All told, it cost somewhere in the vicinity of $22,000 to make Eldritch, $4,000 to port to Mac and Linux, and $5,000 to make Mountains of Madness. My first sales target was simply to recoup those costs (plus taxes) so that I wouldn’t have lost money making this game.

Sales

The time from Eldritch’s initial announcement (September 9) to its proper release date (October 21) was exceptionally short by industry standards, and I don’t know exactly what the effect of that may have been. Perhaps the prompt release helped capitalize on initial excitement surrounding the announcement. Or perhaps Eldritch would have been more successful with six months or a year of slowly teased information to build hype.

Inspired by Hitbox Team’s transparent Dustforce sales report, I’m going to share Eldritch’s sales over the past three months. Please be aware that the dollar figures shown below are the gross revenue, before Steam and Humble take their cut, and before taxes are paid. After fees, shares, and taxes, Minor Key Games makes roughly 43% of that amount.

By any measure, Eldritch is a success, but not a mind-blowing one. I would characterize it as a good start for the company, with plenty of room to grow. Its sales have been more than sufficient to hit my modest goals, and enough that I will get to keep making games independently for at least another year.

presale

Eldritch became available for presale via Humble on September 9, the day it was announced. The announcement was echoed around various websites for most of that week, leading to a fairly wide initial spike before dropping to a steady rate of sales. There was a small spike on September 26, when the beta became available, but that event was not heavily promoted and the sales leveled out again.

launch

Then the official launch happened, and the second wave of press coverage hit, and Eldritch was featured on the front page of Steam for a while. The day 1 sales immediately dwarfed the entire presale period. Launch sales were bolstered a little bit by inclusion in the Steam Halloween Sale (at the launch discount of 20% off), and then the daily sales leveled out once again after a couple of weeks. By this time, Eldritch had recouped its initial development cost.

autumn

The Mac and Linux ports were released without much promotion in early November—an intentional (albeit questionable) choice to give them a gentler landing at the cost of some coverage. The next spike occurred during the Steam Autumn Sale, when Eldritch was offered at a 50% discount. Shortly after this, I wrote that Eldritch had sold 12,000 units at an average price of $12, and I thought that was the end of the story.

holiday

Then this happened. During Steam’s Holiday Sale, Eldritch was offered at an 80% discount ($3) in an overnight Steam flash sale (2 a.m. – 10 a.m. PST). I knew it was coming, but I had virtually no expectations for it. It looked like a poor timeslot, and I didn’t realize just how important front page visibility is during a Steam sale. When I woke up that morning, I quickly tweeted about the sale and then logged in to check the overnight numbers. I thought I was looking at the wrong numbers at first; Eldritch had literally doubled its units sold overnight! Even at such a low price, the revenue from the flash sale exceeded the total revenue of the Autumn Sale and the rest of the Holiday Sale combined. It was also during this sale that the Mac and Linux ports finally recouped their development cost, with an unexpected 11% of purchases during those eight hours coming from Linux users.

sum

In its first three months on sale, Eldritch grossed over $215,000. After subtracting fees, taxes, and Steam and Humble’s shares, it has generated almost $100,000 for our company, or approximately a threefold return on investment.

What Now?

2013 was an amazing year for my career, and the story of Eldritch isn’t over yet. The total number of units sold (about 32,000) is still low enough that there seems to be value in my continuing to promote the game and build awareness. Further sales will surely continue to draw more players, and later, I would be interested in including Eldritch in Humble-style game bundles.

The big question is whether it is worthwhile to continue to develop Eldritch or move on to the next (possibly Eldritch-related) project. Features like mod support and Steam achievements continue to be highly requested, but the cost-benefit analysis for those doesn’t look great. Mod support would be difficult to do right (beyond simple features like texture packs) and would require a larger active user base to flourish. Perhaps mod support could help grow the user base, but we’re living in a post-Minecraft world, and I question how much excitement the addition of mod support to a game like Eldritch could realistically generate.

Thank you all for your support of Eldritch so far, and I hope you enjoy whatever we do in 2014!

Categories
Eldritch

Shoes and Ships and Sealing Wax

As independent game developers, Kyle and I want to be more open and transparent about development than we could be in our AAA past lives. Kyle explained the reasons for this in some detail in his indie announcement, but my interpretation is: silence is a form of dishonesty. The ubiquitous “no comment” deflection serves mainly to obscure unattractive truths about a product. I would rather be frank (“Sadly, Eldritch won’t have cooperative multiplayer.”) than to lead a customer on (“We can’t talk about our plans for multiplayer yet.”).

So in September, I announced Eldritch for Windows only, and the inevitable question of other platforms was asked. I explained, in cautiously noncommittal terms, that I was certainly interested in doing Mac and Linux versions, but they would not be available at launch. In retrospect, I wonder if I should have been more open about the reasons (Eldritch was written on a custom engine that only targeted Direct3D, I had only purchased an FMOD license for one platform, etc.), but this answer seemed to satisfy people.

Of course, I would have liked to ship on Windows, Mac, and Linux simultaneously; but I had no prior experience with Mac or Linux development, no idea how long it would take to port my engine, and a very constrained schedule due to my budget. So I planned to ship on Windows first, then do a cost-benefit analysis to determine if and when it would be beneficial to release on the other platforms. For the cost, I estimated 4-8 weeks of my salary (inasmuch as I have a salary), plus the FMOD licensing fees for the additional platforms. That’s a relatively small sum, but my other debts take precedence. Benefits are harder to determine. Common knowledge puts the combined Mac and Linux gaming market share at around 10% of Windows. Being cross-platform also opens other doors, such as the potential for inclusion in Humble Bundle sales, but I could not rationally depend on that in my analysis. I finally determined that if Eldritch sold on the order of 15,000 copies (at full price on Steam), then it would become beneficial to move forward on the port.

Then something unexpected happened. I ran out of bugs to fix during the Eldritch beta. I added a New Game+ mode because I had the time to do it. I started to get bored. So I decided to investigate what it would take to make my engine cross-platform. Investigation turned into implementation, and after a couple of weeks, I was sitting on a relatively portable codebase. The estimated 4-8 weeks from my cost analysis vanished, rolled into the time I had allotted for finaling the Windows build.

At the moment, I have Mac and Linux alpha builds ready for testing, and I intend to send those to interested friends next week. A wide release is still pending the aforementioned FMOD license fee, although I am reconsidering its priority relative to my other debts in light of the new timing.

All of which is a very long-winded way to finally confirm that Eldritch is coming to Mac and Linux. I’ll follow up (probably on Twitter, in somewhat fewer words) when I figure out the release date, but rest assured that it won’t be long.