Official development blog

Map Prefabs, in Depth

An increasingly common approach to roguelike map development today is to have content partially determined by so-called “prefabs,” with layouts which are hand-made rather than fully procedurally generated. Doing so gives a designer more control over the experience, or portions of it at least, without completely supplanting the advantages of roguelike unpredictability.

Prefabs are a great way to add more meaning to a map, which when otherwise generated purely procedurally and visited again and again by a determined YASD survivor is often going to end up feeling like “more of the same” without a little manual help to shake things up. Yes, even procedural maps get boring once players start to see through their patterns! Not to mention the general lack of anything that really stands out…

Background Reading

I’ve written and demonstrated a good bit about map generation before, including the basics of how I create prefabs for Cogmind, starting with essentially drawing them in REXPaint. This method is light years ahead of the old “draw ASCII in text files” method I was using with X@COM (now that I have REXPaint, I’m definitely going to have to go back and convert that system, that’s for sure!).

xcomrl_map_blueprints

Sample X@COM map prefab excerpt, typed! In text! The horror! (At least it used a little bit of syntax highlighting to help pick out important features…)

And once prefabs are created, one of the major challenges is how to actually get them into a procedural map. After all, they need to seem like they belong! Previously I demonstrated some methods for handling that part of the process in cave-style maps, namely geometric centering (sample) and wall embedding (sample). Read the full post regarding that style over at Generating and Populating Caves.

But most maps in Cogmind are not caves, instead falling under the room-and-corridor style. Naturally these other maps will require different methods for embedding prefabs, and below I’ll be sharing these methods in addition to a more detailed look at what Cogmind’s prefab definition files have evolved into over the years.

“Seeding” with Prefabs

One way to place prefabs is before map creation even begins, in fact shaping the initial generation itself. This approach is for prefabs that will help define the core feeling or difficulty of the map as a whole, thus it’s more suited to larger prefabs, or key points such as entrances and exits. It’s easier to control the absolute distance between these important locations by placing them first. So high-priority prefabs come first… that makes sense :).

As entrances and exits are essential features while also having a large impact on how a given map plays out, thus my maps are designed to place most of them first. Not all of them are handled as prefabs and are therefore beyond the scope of this article, but some special exits that require more flair, fluff, events, or other types of content use this “initial prefab” system. The first such example is found very early in the game in the form of the entrances from Materials floors into the Mines (admittedly one of the less interesting applications, but I don’t want to leak spoilers for later content).

Step 1 in the map generator is to go down a list of potential prefabs and configurations and put them on the map!

cogmind_materials_mapgen_static_features

Complete feature list for Materials-type maps.

cogmind_materials_mapgen_variant_3_phase_1

Sample step 1 (feature variant 3) as seen in the map generator for Materials.

In this case, as per the feature list the generator chose to go with variant #3, which calls for two BLOCKED barriers to prevent pathways from linking areas on either side of them, in addition to two top-side MAT_00_S_1_MIN prefabs, one to the west and one to the east. Looking at the relevant feature data (those last two lines), these prefab areas block all entity spawning within their area, and have ever so slightly variable coordinate offsets (some prefabs elsewhere make much greater use of this ability to shift around).

The MAT_00_MIN file stores the data that allows the engine to decipher what objects are referenced within the prefab:

cogmind_materials_mapgen_mines_entrance_prefab_data

Data references shared by all Mine entrances.

And “MAT_00_S_1_MIN” refers to the file storing the layout itself:

cogmind_materials_mapgen_mines_entrance_prefab

Mines entrance MAT_00_S_1_MIN prefab layout, as seen in REXPaint. (This is a multilayered image, so here you can’t see the complete machine hidden under the ‘A’s.)

The southern edge calls for a tunneler (width = 3, the yellow number) to start digging its way south to link up with the rest of the map (when its generation proper begins), while both the left and right sides are tunnellable earth in case later pathways are dug out from elsewhere on the map that would like to link up here. Those are simply other possibilities, though--the only guaranteed access will be from the southern side.

cogmind_materials_mapgen_variant_3_final

Final map after all steps concluded, incorporating Mine entrances placed first.

Other common candidates for initial prefabs are huge semi-static areas, sometimes as large as 25×25 or even 100×100, which play an important role on that map either for plot or mechanics purposes.

cogmind_mapgen_large_prefabs

A portion of map generated with two large prefabs (highlighted) that were placed first.

The next method is a bit more complicated…

Embedding Prefabs

Most of the prefabs in Cogmind are not applied until after the initial phases of map generation are complete. Therefore all the rooms and corridors are already there and I had to determine the most flexible approaches for adding this type of content to a map without screwing up either the prefabs or map itself.

Before going any further, though, we have to decide which prefabs to add in the first place, a decision naturally affected by the theme, depth, and other various factors associated with the map in question. That process is handled via the “encounter system” I initially described in this blog post (half-way down), but I never got into the technical side of how those encounters are selected, or how those with prefabs are actually merged with the map, which is relevant here. (*Clarification: An “encounter” refers hand-made content which may be loot, enemies, friends, or basically anything, sometimes combined with procedural elements, and sometimes but not always associated with one or more prefabs.)

In general, while there are a few types of encounters that appear across multiple maps, like rooms full of debris, each type of map has its own pool of potential unique encounters. And then there are multiple base criteria that may or may not be applicable in determining whether a given encounter is chosen:

  • Depth limits: An encounter may only be allowed within a certain depth range. (I’ve actually never used this limitation because maps containing encounters generally only appear at one or two different depths anyway.)
  • Count limits: An encounter may be allowed to appear any number of times, or up to a maximum number of times in a single map, or up to a maximum number number of times in the entire world (only once in the case of true unique encounters such as with a named or otherwise NPC with very specific behavior).
  • Mutual exclusivity limits: Some encounters may not be allowed to appear in the same map as others. These will be marked as belonging to a certain group, and exclude all others once one is chosen.
  • Access limits: Encounters can require that they only be placed in a room connected to a certain number of doors/corridors. It is common to restrict this to 1 for better prefab layout control (i.e. knowing which direction from which the player will enter makes it easier to design certain prefabs).

Encounters are also not given equal weight--some are common while others are quite rare. I use words/strings to assign encounter weights in the data, because they are easier than numbers to read and compare, and can be more quickly tweaked across the board if necessary (by changing their underlying values).

cogmind_encounter_weights

Encounter weight value ranges (source).

 

cogmind_encounter_weights_data_matrix_excerpt

Encounter weight values (data excerpt), where each column is a different map, and each row is a different encounter.

So you’ve got some prefabs chosen and a map that looks like this:

cogmind_mapgen_storage

Completed room-and-corridor map generation, sample 1.

Or this:

cogmind_mapgen

Completed room-and-corridor map generation, sample 2.

Or something else with rooms and corridors. How do we match encounters with rooms and actually embed prefabs in there?

Unlike “seeding prefabs” described earlier, these “room-based prefabs” actually come in a few different varieties, but all share the characteristic that they are placed in what are initially rooms, as defined by the map generator. Of course the map generator must know where it placed all the rooms and their doors in the first place, info which has all kinds of useful applications even beyond just prefabs. Can’t very well place prefabs without some likely target areas to check!

The most common prefab variety is the “enclosed room” category. A random available room is selected, then compared against the size of each possible prefab for the current encounter. (A single encounter may have multiple alternative prefabs of different dimensions, and as long as one or more will fit the current room then oversized options are simply ignored.) In order for a rectangular prefab to fit the target room it may also be rotated, which doubles as a way to provide additional variety in the results. And yet another way to expand the possibility space here is to randomly flip the prefab horizontally. (Flipping vertically is the same thing as rotating 180 degrees, so kinda pointless :P)

cogmind_room_prefab_embedded_process

Steps to place an enclosed room prefab.

  1. Find a room that’s large enough to hold the desired encounter/prefab.
  2. Find a target rectangle which borders the doorway. (The horizontal axis is randomized to anywhere that will allow the door to be along the prefab’s bottom edge. Prefabs are always drawn to face “south” by default, to establish a common baseline from which to shift, rotate, and flip them. And those with a single-door restriction are always rotated so that their bottom edge faces the door, whichever side of the room its on. This makes designing the experience much easier since you always know which direction from which the player will enter this type of prefab.)
  3. Prefab dimensions will generally not precisely match those of the room in which they’re placed, therefore the surplus room area is usually filled in with earth and the walls are rebuilt along the new inner edge (though the room resizing is optional--it can be left as extra open space).
  4. Place the prefab and its objects, done! (rotated example shown on the right)

There are some further customization options as well. Doors can be expanded to multi-cell doors, like for special rooms that want to be noticeable as such from the outside (as a suggestive indicator to the player). Or the door(s) can be removed to simply leave an open entryway.

cogmind_room_prefab_embedded_process_modifications

Variations on the above room prefab via post-placement modifications.

The third form shown below takes the modifications a step further by removing the door and entire front wall to completely open the room to the corridor outside, creating a sort of “cubby” with the prefab contents.

cogmind_room_prefab_embedded_process_cubby

Front wall removed for cubby variant.

Storage depots found in Cogmind’s earliest floors use the “cubby room” design. The reason there is it makes them easy to spot and differentiate from afar, which helps since the point is to enable players to expand their inventory if necessary for their strategy.

cogmind_materials_storage_depot

Storage depot prefab as seen embedded in a Cogmind map.

Another “accessible room” variety is essentially like an enclosed room, but the prefab is designed to allow for maximum flexibility and access rather than expecting the room to be shrunk down to its size and new walls created. These prefabs usually don’t have internal walls and instead just become decoration/contents for an existing room without changing its structure. While it may end up in a room larger than itself and therefore have extra open space, including these types of prefabs is necessary to fill parts of the map containing rooms with multiple entry points where rooms with obstructions and walls wouldn’t do because they could illogically block off some of those paths. For the same reason, accessible room prefabs must leave all of their edges open for movement (though may contain objects that do not block movement).

cogmind_room_prefab_embedded_process_rotated

Steps to place an accessible room prefab.

  1. Find a room that’s large enough to hold the desired encounter/prefab (any number of access points is valid).
  2. Position the target rectangle anywhere in the room (random).
  3. Place the prefab and its objects, done!

The primary drawback of using the encounter system to place encounters in randomly selected rooms is that there is no control over relative positioning of different encounters. While it’s possible to add further restrictions or tweaks to guide placement on a macro scale, it seems to work out okay as is. The existing system does, however, also sometimes result in suboptimal placement of encounters, i.e. a smarter system could fit more into a given area, or better rearrange those that it did place to maximize available play space. But these effects are only apparent on the design side--the player won’t notice any of this.

An alternative would be to use a room-first approach, choosing a room and then finding an encounter that fits, but in my case I wanted to prioritize encounters themselves, which are the more important factor when it comes to game balance.

cogmind_tunnel_map_encounters

Post-mapgen prefabs placed in a map, highlighted by category for debugging.

So overall my prefab solution is a combination of external text files and binary image files, processed by about 3,000 lines of code.

Inside a Prefab

So far we’ve seen how prefabs fit into the bigger picture, but another equally important aspect is what goes into a prefab itself. Each prefab must have an associated definition file (sometimes shared by multiple prefabs if they have similar contents), which is a simple text file that describes the objects found in the prefab.

My first ever prefab article (linked earlier), written two and half years ago (!), appeared before even any prefabs had been used in Cogmind. As you can guess, things have evolved since then, getting a lot more versatile and powerful as new features were added to meet new needs throughout alpha development. Here I’ll give a general rundown of those features, to give a better idea of how they work.

At the most basic level, a definition file is simply a list explaining what object each ASCII character in the prefab represents. After placing the initial prefab terrain--walls/doors/etc, the generator consults the corresponding definition file and creates those objects at the specified positions. Reference characters are written to the prefab image’s fourth layer as part of the design process (they can be any color, but I always use green for consistency).

cogmind_garrison_prefab_sample

Sample prefab layout image (draw in REXPaint and stored as a compressed .xp file). Green letters and numbers all exist on the highest layer (layer 4) and refer to objects. This particular prefab represents one quarter of a garrison interior, which are built entirely from a large selection of prefabs.

In a definition file, each line corresponds to a reference, of which there are five types:

cogmind_prefab_definition_object_types

Prefab definition object types.

For consistency and to aid readability of prefabs when creating/editing them, I always use upper case letters for props and traps (the latter actually being a subset of the former), lower case letters for entities (robots/mobs), numbers for items, and punctuation for debris (of which only one reference is actually necessary, because the actual appearance is determined by the engine).

Note that a “tag” is the internal name for an object, which may not always match the name the player sees, to enable objects that appear the same but are actually different for whatever reason.

The above basic info, a character plus the object’s [TYPE] and [TAG], are the only required data for a given object, but most objects will be followed by additional data keywords that describe the object in more detail (overriding otherwise default behaviors). The set of applicable keywords is generally different for each type of object, though any reference can specify the [SHIFT] keyword, which instructs the prefab to randomly shift that object within a certain area, (+/-x, +/-y), so that it doesn’t always appear in the same place.

cogmind_prefab_definition_keyword_samples

Sample prefab keywords used to expand on different object definitions. Custom syntax highlighting helps parse the file when editing.

Items and entities specifically have more options for their [TAG] value. Quite often it’s desirable to select one from among multiple potential types, a feature supported by additional syntax and keywords.

cogmind_prefab_definition_syntax_randomization_entities

Randomizing entities in prefabs.

The first example demonstrates how it’s possible to designate any number of entities from which to randomly select, in that case a G-34 and G-47.

The second example, on the other hand, simply specifies an entity class, and the game will select an entity appropriate for the depth at which the prefab is placed. This is useful for prefabs used across multiple depths, and has the added benefit that any changes to object names (and other values!) do not force reconsideration of existing prefabs. For the same reason, hard-scripting specific object names is avoided where possible.

The third example simply demonstrates random selection between different classes works, too.

Designating a class instead of a specific name may also call for additional keywords (optional), where [CATEGORY] suggests which category to select an entity variant from, where a single class may belong to more than one entity category, [STRONG] tells whether to select an entity that is one level stronger than the current depth, and [FALLBACK] tells the engine to fall back on the weakest variant when technically no variant of the desired class exists at or below the current depth.

cogmind_prefab_definition_syntax_randomization_items

Randomizing items in prefabs.

Items (and traps, actually) often do the same thing, and can range from extremely specific (Ex 1) to extremely vague (Ex 4). Ex 2 demonstrates just a sampling of the available categories to select from, as away of narrowing down the selection pool--important for balance and controlling the experience! And Ex 3 is a pretty situational one, randomly selecting an item that would normally be equipped by the entity in parenthesis, to allow for thematic loot (the scene of a specific battle, for example).

Where no specific tag is given, the [PROTOTYPE] keyword suggests that the item should be chosen from among prototypes (a better type of item) than common items, [NEVERFAULTY] designates that a chosen prototype should never be a faulty version, and [RATING]+X can be used to have the map generator attempt to choose an “out of depth” item instead (where X is the number of levels higher than the current one to choose from).

The theme of non-static prefab data is an important one, as it’s a relatively cheap way to make even handcrafted content stay fresh despite repeated exposure. To take this theme even further, individual keywords can be modified by various prefixes with different effects:

cogmind_prefab_definition_syntax_randomization_keywords

Prefab keyword randomization modifiers. These can be applied to any data keyword for any object.

For larger scale randomization we also have two available columns at the beginning of each line (excluded from all of the above samples):

cogmind_prefab_definition_syntax_randomization

Prefab generic randomization capabilities and syntax.

Despite the appeal of randomization, it is often desired that multiple entities or items placed near each other in a prefab should be of the same type, even when randomly selected. Thus by default whenever the object for a reference character was chosen randomly, any cardinally adjacent matching characters will automatically use the same object type (extending as far as necessary in a chain). Where there is a need to allow adjacent objects (even those with matching characters) to be different from one another, the [UNIQUE] keyword can be used to explicitly force that.

Some Statistics

As of today Cogmind contains…

  • 148 base types of encounters, 115 of which use prefabs
  • 372 prefabs in all (much higher than the number of encounters because some have multiple prefabs, and as explained before not all prefabs are associated specifically with encounters)
  • The largest prefab is 100×90
  • The smallest is 3×2 :P (mostly a mechanical thing)
  • The average is 7×7
  • The single encounter with the greatest variety of unique prefabs has 12 to choose from

In total, 25% of encounters are categorized as “fluff,” 15% as “risk vs. reward,” 14% as “danger,” and 46% as “rewards.”

Posted in Design, Dev Series: Procedural Maps | Tagged , , , , , | Leave a comment

Year 3 of the Cogmind

Unbelievable… I’ve been working on Cogmind for three and a half years now. Yet another year has gone by, and this time the end is very much in sight!

To start off, as I did for 2014 and 2015 here’s a collage of development images from the past year:

cogmind_development_year_3_small

Images from the past year of Cogmind development as appeared on this blog and Twitter (full mega size here).

GIFs outnumbered PNGs about three-to-one, but an animated collage wouldn’t be able to include enough images to do the year justice :). I don’t have anywhere specific I collect only GIFs, though I did use a number of them on the page I put together this year dedicated to summarizing some of the innovations Cogmind is bringing to the genre.

Development Time

As usual I’ve been keeping close tabs on where every hour is spent, altogether 6,383 hours so far:

timeline - cogmind_monthly_development_hours_201307-201611

Cogmind Monthly Development Hours, 2013.7-2016.11 (click for crisper full-size version). (The color coding is for different aspects of development tackled each month, the subject of a future in-depth article to come when Cogmind is complete.)

That’s 1,982 hours this year compared to 2,321 last year, when I was doing a lot of promotional prep for the launch (trailer, website, etc.), and didn’t take any vacations like I did this year. (The year before, 2014, totaled 1,528 hours.) Comparing purely work on the game itself, this year added 1,151 hours compared to 1,273 in 2015 (and 1,078 the year before that), so in that respect progress has remained relatively steady. There’s lots more interesting data in there, but I’ll get into that another time.

At the end of 2015, my only worry was that I’d be forced to do a full launch earlier by cutting or postponing newly-planned features, but through a careful balance of progress and minimal marketing, revenue has remained steady, and Cogmind keeps growing extra features :D

Releases!

2016 saw seven major releases.

cogmind_releases_161122

Cogmind release summary, as seen on the FAQ. For links to changelogs, full release notes, and preview images, see the Release History I maintain on the forums.

As you can see, progress consisted of maps upon maps upon maps… Cogmind began 2016 with 14 map types, and is ending it with 26, each of which also added unique mechanics, components, and in some cases major plot events. The world got so big that it was finally time to add a world map.

cogmind_world_map

Sample Cogmind world map in action.

And with that Cogmind’s story is almost complete, which is my primary criterion for judging Cogmind to be 1.0. So we’re close!

As far as sharing progress, note that the nature of this dev blog has changed--while I used to share smaller specific development updates here, this year you’ll notice I’ve instead shifted to publishing mostly longer articles of (hopefully) greater value about some relevant gamedev topic, with occasional aggregate Cogmind updates where they align with that goal.

Regarding individual features and content, I technically share even more updates than I used to, but that progress is posted to the announcements board, subreddit, and Twitter (also some other forum threads).

I like this division of focus, and will continue the pattern into 2017, with planned articles on topics like pricing, game difficulty, code testing, roguelikedev tips, and more.

Milestones

So what other big milestones did 2016 see…

Well, the biggest would have to be that Cogmind passed both the 2,000- and 3,000-player thresholds this year! (The latter just this month.) This was the first full calendar year that Cogmind was available for purchase. Yep, in addition to the 2015 initial launch, the public alpha (Early Access, if you must!) has continued for 19 months now. Sales have been acceptable, enough to avoid forcing me to cut features! Actually, enough to convince me that I have leeway to add more, and as a result 2016 brought tons of new mechanics and QoL features that wouldn’t have otherwise been possible. So thanks from myself and on behalf of future players :D. On that note, back in May I did a recap of the first 12 months of Alpha Access, wherein I shared revenue breakdowns, among other reflections.

Cogmind’s community has grown in absolute terms, though as we’re still in alpha most new supporters play for a bit then stop to wait for 1.0. I decided against holding another tournament like the Alpha Challenge 2015, at least this year, because while it was great fun, it also took too much time away from development last year :/. The leaderboards, however, have been very active, and there has been lots of helpful related discussion (both development-wise and player-to-player) on the forums.

cogmind_high_scores_161218

A recent snapshot of the top of the Cogmind leaderboards. The leaderboard system has advanced somewhat as well, now separately listing further areas reached by player, and providing access to the score sheets for each run.

Forum discussion has slowed somewhat in the second half of the year, though, as many long-time players have switched to hanging out on the chat server (Discord) for the past 4-5 months.

On the project side, out of curiosity I compared Cogmind’s lines of code to a year ago--this year it passed the 100k LoC mark:

cogmind_loc_1512v1612

Cogmind lines of code, from 2015 to 2016.

In the past year there’s been a net +16,396 lines of code, or a 17.2% increase. Not a lot! That’s because as described earlier much of the progress this year was in content--new maps and their corresponding robots, components, events, etc. All of that stuff is implemented via external scripts, map prefabs, and other data files rather than code. Essentially this shows the core game was already solid in 2015, all it needed was more content to realize The Vision.

But hey, we passed 100k :P

Recognition

Each year Cogmind attracts more attention, and this year in addition to the smaller sites that published related news/articles, Cogmind appeared among the Top games on Rock, Paper, Shotgun, on Destructoid’s Top 33 list, and Nerd Much’s Top 50 list.

More recently RPS did a sudden quick article on Cogmind following one of this year’s larger releases. That title was quite a shock, and something I totally wasn’t ready for. Very busy those few days xD. In any case, it did spur another big chunk of sales which will help propel development to 1.0! Very grateful for that coverage.

Then just this month Cogmind was once again voted into the Top 100 indies of the year on IndieDB.

It’s good there’s just enough attention going around to keep bringing in new players, because I’m still not doing any active marketing outreach. I get legit review key requests, but they go on a list for later and I’d rather focus on development and the existing community for now. That said, I have been doing a lot in the wider roguelike community, including making my way over to the US to take part in the awesome Roguelike Celebration! I felt like a nervous wreck, but gave a talk people seemed to enjoy anyway :P.

I don’t really look forward to it, but by necessity 2017 is going to be a very different kind of year because I’ll have to mostly shift away from creating content and on to business and marketing -_-. That’s where hobby development really shows its superiority over doing this to make a meager living!

2017

This is it. 2017 will be a crucial year for Cogmind, because it’s the year we reach 1.0, and the year we’ll finally see what cogmind can do once it reaches a wider audience--will it flop, or will it be able to pay for more roguelike goodness in the future? :)

I never imagined back in 2013 when starting out (and most certainly not when putting out the initial free version in 2012!) that I’d still be working on Cogmind now, but I’m glad I am because it’s the result of good things! There haven’t been any serious development hiccups, and progress has continued at the expected pace, I just repeatedly pushed back the long-term schedule to fit in more stuff. It’s true that many of these things could have simply waited until after a “1.0″ launch, which is what I’m sure most sane (or financially desperate) developers would do, but even Alpha 1 was a pretty solid game, and there’s been ongoing player support ever since it was released, so I never really saw a need to rush it.

That said, development is naturally coming to a 1.0 milestone. I mean, look where I’ve set the current progress meter:

cogmind_progress_161122

Cogmind development progress as of November 22nd, 2016.

Almost everything’s at 95%, which is basically me-speak for “you could call it done but I could always do more, and I am.”

There’s still the ambient audio to work on, a portion intentionally left for last so it could more efficiently be handled all at once, and there are already so many sound effects that they essentially create an “ambiance without any ambient sound,” so it wasn’t required for alpha to have additional background effects anyway (though there are a few placeholders out there). I’ll be getting on that soon.

For fun I put together a time-lapse gif showing how the public progress meter (always shared via the FAQ) has evolved to reach this point:

cogmind_progress_140810-161122

Cogmind development progress graphs, from August 2014 to November 2016 (early on in pre-alpha there were still enough incomplete subsystems to warrant displaying them individually, but eventually for much of alpha it boiled down to just maps and story).

Looking to the future, well, I’ve also continued to share the major bits over in the FAQ:

cogmind_roadmap_161122

Cogmind dev roadmap snapshot, November 2016.

A bunch of the pending stuff will be scratched off with the next release--just two more releases and the last remaining bits of Cogmind’s world will be complete, to be followed by whatever features I feel shouldn’t really wait until post-1.0 development. I.e., they need to be in there before Cogmind gets more attention from the less die-hard fans. I haven’t finalized exactly what those pieces are yet, as there are quite a lot of optional features and content still left on the chopping block. I’ll take stock of those later, and after implementing them it’s time to do a 1.0 release. And then, you know, keep releasing more after that :P

In short, Cogmind 1.0 is coming in 2017. Getting nervous, but also can’t wait!

And once again, Happy New Year :D

cogmind_30missile_fun

Playing with a fake weapon that fires 30 missiles. Because hell yeah 30 missiles.

Posted in Gamedev | Tagged , , , | Leave a comment

Improving the Hacking Experience

The terrible curse of gamedev is that it’s really hard to finish a game when there’s always something that could be better. The great thing about gamedev is that there’s always something that could be better, meaning room for more new features and content to make players happy :D

The previous round of major UI enhancements (in the form of extra optional features) was centered around inventory management, which lies at the very core of Cogmind’s gameplay. And now more recently the less central but still oft-used manual hacking system has undergone a similar treatment, getting its own set of UI add-ons that players appreciate.

In Cogmind hacking is most easily performed directly, via the available list of valid machine commands marked by letters and with percentages reflecting their chance of success, but sometimes players want to carry out more difficult “indirect hacks” of unlisted targets by keying them in manually.

cogmind_manual_hacking_terminal

Manually hacking a terminal, including use of unlisted targets.

Forcing the player to remember the information required to take advantage of this strategy, and type it repeatedly, may seem like unnecessary requirements. We have computers to do that sort of thing for us, while we apply our brain’s processing power instead to problem solving--what exactly to do when. That’s the more enjoyable part of games for most players. (Note that it is, however, quite in theme to be typing hacking commands without any form of assistance, and at least one player specifically requested that none of these features be available, so it is possible to turn them off.)

Repetition was initially addressed in part by the “hacking buffer,” allowing players to automatically cycle back through previous hacks (including those during previous runs), or even modify the buffer directly as an external text file.

cogmind_manual_hacking_buffer

Cycling through the manual hacking buffer to repeat previous commands.

But the buffer is more suited to recent hacks, since it’s cumbersome to cycle back through dozens of entries to find a particular one, in which time you may as well have just typed the command out again :P. There are buffer features like automatic removal of duplicates and non-existent commands, but they only go so far.

Thus we have several more features to aid the hack-minded Cogmind…

Unique Codes

Any part of the game that causes extra non-fun work for the player is a candidate for streamlining, and when the story portion of the game exploded in Alphas 8 and 9, unique codes for manual hacking became just that.

Obtained by talking to NPCs or accessing certain terminal records, these codes could then be entered while hacking other machines or robots elsewhere in the world for some kind of effect. The problem: using them meant having to know them, which meant having to write them down, or even worse, scrolling way back through the message log to find where they were last referenced. I made the codes short (only four letters) to facilitate this, and at first there were only a couple anyway so it wasn’t much of an issue, but with more plot comes more codes, and neither of the old approaches were satisfactory--scroll searching was a slow process, and writing them down would often be wasteful since they might never be used. (Note that these codes are randomly generated, so they change every run.)

The UI does all this automatically now. Mouse players can simply click on the code they want to input, while keyboard players first type the normal code hack prefix (“\\”) to switch focus to the code list where they only need to press the corresponding letter key. The list even conveniently includes who gave it to you and where.

cogmind_manual_hacking_codes_machines

Interacting with the terminal code assist feature.

And the same feature is available for manual hacks targeting robots, not just machines:

cogmind_manual_hacking_codes_robots

Code assist feature activation while manually datajacking a Sentry.

No more writing down codes :D

Autocompletion

Us coders have autocomplete for our source hacking, so why not give it to players, too? :)

There are currently 82 machine commands in Cogmind, and while I’ve attempted to use relatively systematic naming conventions, it’s still a lot to remember, especially those which aren’t used so often. And even when players do remember exactly how to hack their target, the occasional typo is also annoying.

The solution is to take whatever the player has typed, even as little as one letter, and start narrowing down the possibilities, compiling a list of all matching commands and displaying the first as grayed out text, possibly followed by a number indicator if there is more than one match available. All the player has to do is press spacebar or tab to accept the gray text rather than typing it out in full, or keep typing to narrow down the possibilities, or press up/down to cycle through the other matches!

cogmind_manual_hacking_autocomplete

Manual hacking gets autocomplete!

From the outset all common commands are considered for the autocompletion list, while unauthorized hacks learned while playing are considered only after discovering them, information that is carried from game to game. This is to avoid spoiling secrets that are intended to be learned through regular play (NPCs and terminal records provide this info), though players who for some reason don’t have their user data from previous games (or those who look up spoilers) can type the commands out manually and they’ll be permanently considered “learned” as well.

The automated recording of secrets learned via lore is itself helpful for hack discovery, in case a player didn’t notice or forgot what some NPC told them (and doesn’t want to search through their lore collection UI for it :P), since simply typing “Trojan” at the command prompt (or really even just “tro”!) will list all known Trojans for that machine. (“t” and “tr” work, too, but there will also be non-Trojan matches due to trap-related commands.)

Indirect Queries

Querying terminal records often returns results that themselves contain further topics to query, forming a web of potential lore. Mouse users can simply click on these other topics to attempt to hack them indirectly, but keyboard users have always had to type out the Query(Topic) command manually.

Until now.

When keyboard mode is active, reference numbers appear next to each available topic and simply pressing the corresponding number key will attempt to hack it.

cogmind_manual_hacking_keyboard_quick_query

Hacking a chain of lore-related terminal records purely via keyboard, using reference numbers.

The system only supports the ten most recent topic references (because number keys), but that’s plenty enough to have full access to several consecutive hacking results. After the tenth topic, the numbers will wrap back around to 1 again.

To reiterate, mouse users will not see the numbers, and I don’t think keyboard users will be impacted too much in terms of readability, since the numbers are grayed out and one can learn to ignore/read past them until they’re needed. The affect on readability was, however, one of the main reasons I repeatedly postponed implementing this feature. In the end I’ve decided that convenient functionality is more important, and actually kinda think they make the entry text look cool, anyway :)

Another query-related bonus feature for both mouse and keyboard users is that these topic references themselves now also include a ‘!’ prefix to indicate that a particular record has not been read/discovered before, to facilitate lore collection.

cogmind_manual_hacking_mark_undiscovered_lore

‘!’ marking lore records that haven’t been hacked yet.

This is the same indicator that appears in the machine target list for direct queries.

Addendum

None of the features mentioned in this post are necessary, but they sure are convenient! Why weren’t they just implemented to begin with?

The most obvious answer is time. A lot of work goes into the base features and UI itself, and by the time each is complete and able to get the job done, all the test have been run, the kinks worked out, the bugs fixed… it’s really draining and often feels about time to move on to the next thing :P. Besides, there are always other pressing features that need attention, too! Thus many ways to further improve an experience often end up filed under “Maybe later?” This is fine because it feeds into the second reason:

Sometimes rushing to add “improvements” turns out to be a bad idea. With a working foundation in place, time permitting it’s always better to watch how players use a given feature, listen to how players talk about it, and use it yourself. With more use case data, over time even better solutions might become apparent. Development that moves too fast in one direction without waiting for intermediate results is more likely to waste time, as efforts might clash (either code-wise or UX-wise) with another feature which isn’t as mature.

So in my case I keep a list of features like these and revisit them occasionally to look at them from a new perspective, maybe add some more notes, and when a particular feature hits critical mass (sometimes pushed over the edge by player requests or what I hear players talking about :D), it becomes the next implementation target and will find its way into a near-term update.

Posted in GUI | Tagged , , | Leave a comment

Weaving Narratives into Procedural Worlds, Part 3: Methods

With Part 1 (Value) and Part 2 (Characteristics) of this series as a background, it’s time to examine the variety of methods Cogmind uses to achieve those goals, which are important considerations every step of the way. This is also what is meant by “weaving,” because there are quite a few individual components working together to reinforce the narrative, and reflect it.

Structure

When creating a roguelike in which a story can thrive, I believe the most fundamentally important decisions involve the world layout and how the player traverses it. For a non-linear story experience, it makes sense to have multiple available destinations at once, be it presented as some kind of open world, or maps connected in some sort of network. Cogmind uses the latter, dividing the world into areas which belong to either the central complex, or branches linked from there but which eventually lead back to the complex. (I talked about this and several related topics in the World of Robots post last year.)

cogmind_world_composition_compact

A simplified breakdown of Cogmind’s world.

An important distinction between the two types of areas is that the story is confined to the branches, meaning the player can spend the majority of their time on the direct route to the surface/end and never even come in contact with story. There are no NPCs or dialogue along that route, and before long anyone who wants story will know where to find it.

Branches are structured such that the more story-oriented ones are generally deeper, and there is a quicker way to loop back into the main complex before seeing much, if again the player is not interested (or too weak, since story areas are more challenging!). Overall this structure is key to the “optional” characteristic discussed last time--players aren’t required to engage with the story,

Most players do at some point start to develop an interest in the story, but it happens gradually, which is beneficial as it keeps the world simpler for new players, while opening up new options for more experienced players. In fact, for better players who may still be unaware of the story, the additional strategic options that stem from integrating story elements with gameplay are one of the primary hooks driving them to explore. For example there are the “manual hacking codes” which often link otherwise unrelated areas by having a code obtained in one area provide some kind of benefits in another.

cogmind_manual_hacking_codes_machines

Using the manual hacking code assist feature added in Alpha 10, listing where and who originally provided each code. (Also works for robot hacking.)

That the player cannot backtrack to earlier areas is crucial here. Taking one route naturally closes off one or more others. Cogmind would be quite a different experience if it were open world, or even just possible to return to previous maps!

cogmind_world_map_concept_final_full.png

Sample in-game world map tracing the player’s path from deep underground towards the surface.

There is a huge amount of design freedom enabled by forcing the player forward, allowing for greater developer control which in turns makes it easier to maintain a more focused and fun experience. Good balance is important in a roguelike, but so is overall flow (not so much in sandbox roguelikes, where players are responsible for their own flow).

Note that all branches are accessible in every world, though the impossibility of visiting them all in a single run presents the player with interesting choices, choices that continue to expand as they learn more about its structure and get closer to the end.

Lore & Dialogue

There is quite a lot of lore in Cogmind, appearing in various forms to provide multiple different channels for the player to explore the story.

Games will naturally embed their lore, essentially the backbone of the story, wherever appropriate for the theme and setting. e.g. books, tombstones, travelogues, etc. At the extreme there are cRPGs which allow you to read inscriptions and text from just about any object, though traditional roguelike environments are only so rich and a systematic/streamlined approach is more appropriate, suggesting that we limit lore to a handful of easily recognizable sources.

One of Cogmind’s primary gateways to lore are terminal records (definitely not an uncommon practice in sci-fi games :P). Terminals can be hacked for background information on various topics, organized so that the closer to the surface/end, the further into the story those topics are sourced. Most of the records are written from one of the factions’ point of view, while records on terminals found in outlying areas might provide other points of view.

All pieces of lore are not created equal, either. Some are more mundane and generally available, while others are designed to be found in special areas, so uncovering the full set of lore and figuring out the story is somewhat of a puzzle that takes time--many runs (and a good enough player to piece together). The content of records may also link to other records, which can in turn be hacked directly from there, giving the lore a web-like form that always entices the player with yet more topics to explore :)

cogmind_terminal_record_lore

Terminal record lore hacking, both via direct links and manually.

If players don’t want to hack the terminal records for whatever reason (and it’s easy not to because terminals have so many other useful functions), then the story doesn’t even come into play there.

Lore is also embedded in “robot analysis” records, which provide a real benefit to players who hack them (accuracy and dodge modifiers against that type of foe), but also describe their components and maybe a bit of story-relevant fluff about each robot’s purpose or history.

Probably the lore feature most unexpectedly absent from Cogmind is item descriptions. Even many games without an emphasis on story (or any story at all) might have flavor text for item descriptions, using that to set the tone. In Cogmind this would be a massive amount of work--so many items!--and more importantly I don’t think having that kind of fluff immediately available for items fits the theme. It wouldn’t be able to do the best job an item description could do without muddying the idea that the player is a robot, and not actually playing a robot. There’s also not enough room to display that kind of info without putting it in a separate window :P. (Note, however, that dozens of items do have lore in the form of terminal records, so it’s not non-existent, just not ubiquitous.)

Dialogue

Lore can also be obtained by listening to NPCs, usually by bumping into them, but sometimes by simply coming into visual range. The content is often just fluff and tidbits from different viewpoints to reinforce the lore, as well as the occasional general tip or strategic or tactical suggestion. For those I try to write them in a way that feels like a logical thing the NPC might say (to a stranger or in whatever the given situation/location is), as opposed to an overt “I am NPC #23 and I exist solely to tell you this out-of-context piece of information.”

cogmind_dialogue_msg_sample.png

Sample dialogue text in the message log.

As mentioned earlier all of these NPCs are off the beaten path to the end, but even there they and their dialogue are very unintrusive, simply appearing as text in the message log, and for a short duration at the bottom of the map view.

cogmind_map_dialogue.gif

An NPC talking as the player moves around.

Similarly, there are a few examples (it’s an underused system…) whereby a short description of some scene may also pop up at the edge like that.

Slightly more intrusive are the modal dialogue boxes used for major NPCs and encounters in some special areas, though the frequency of those is kept to a minimum. It’s quick and easy for the player to simply hit Escape or close the window for those they’re already familiar with (or not initiate them in the first place).

See this earlier post for more talk about the dialogue UI.

Lore Collection

Now that most of the lore is completed and in game, not too long ago a new and valuable feature was added: the lore collection interface. This is a central repository for all the lore the player has encountered throughout all of their runs, where “lore” includes most NPC conversations and terminal records. The contents are categorized by location and ordered alphabetically, where players can skip to a section by simply pressing the first letter of the entry they’re looking for, or scroll around the list to autoload text.

cogmind_lore_UI

Interacting with the lore collection UI (here filled with junk because spoilers :P).

To facilitate lore collection, terminal records the player has never read before are marked with a ‘!’ directly in the terminals from where they are available. And beyond the reference value of having all this info conveniently in one place, the percent bar there at the bottom reveals some of the system’s other benefits.

Players can know just how much of the information about the world they have or haven’t discovered, which tends to encourage them to learn more about the world, a strong incentive to explore when combined with the (correct) assumption that these unexplored areas likely also contain lots of interesting gameplay possibilities!

Players are now comparing each others’ “percentage of lore collected” (a bit of competition), and more importantly can watch their own meta progress in the new scorehistory.txt which also records the cumulative lore value at the end of each new run. It’s nice to have progress meters aside from score alone.

Encounters

Another aspect of Cogmind that fills out the world with story-related content, albeit in a piecemeal fashion rather than any kind of linear narrative experience, is the encounter system. These “mini-experiences” created with scripts and handcrafted map pieces, sometimes with heavy randomization, again reinforce the lore at various points.

cogmind_encounter_sample_TES_firing_range

An example prefab encounter as seen in REXPaint, the program I use to “draw” most of Cogmind’s encounters. One faction is testing the effectiveness of their prototype robot and new weaponry, and what better target than a couple of their sworn enemies? (disabled, of course) There are a variety of things that can happen with this single scenario. A quick-thinking (and moving!) player could blast through the southeastern wall, which is likely along a corridor, and rewire the allies through the new entrance to immediately fight back. Or if the player is spotted and reported not far from this room, regardless of the state of the tests, said prototype robot will likely be dispatched in defense. Or the player may want to attack first and later rescue the allies, or do it to loot the room of its experimental weapons. Or ignore the room completely and stay out of trouble :P

Of course some of these experiences are pure fluff, though many have other implications as well. And while handcrafted, when placed near one another, or when players encounter them in various unique situations, emergent results make them somewhat unique each time. That’s the beauty of mixing handcrafted content into procedural generation algorithms--it’s possible to get the best of both worlds :D

I’ve written more about encounters before in articles on Map Composition and Generating and Populating Caves, though I haven’t shown a distribution sample for any corridor-based maps before, so here’s a new image:

cogmind_tunnel_map_encounters

Procedurally distributed encounters, colored by type.

Localized environmental storytelling is easy to do like this. For example some scrap and broken down robots from two opposing factions strewn across a cave, or an abandoned partially-destroyed base that might still contain a terminal with bits of info as to what happened. This isn’t commonly done in many roguelikes due to the traditional de-emphasis of terrain and props.

Yet More Elements

There are still other features that work to increase the appeal of story in roguelikes, though these don’t constitute entire systems on their own so I’ll cover them together here at the end.

  • Once a game includes NPCs, it’s helpful to include a town of sorts, lore permitting. Cogmind has something like this located in an out-of-the-way area, and it’s a great dumping ground for a lot of those tidbits of lore and knowledge mentioned earlier. Even better, the available dialogue for each run is selected from a larger pool, increasing replayability for a time. I’ve also seen a number of players appreciate the change of pace that such a location brings. Suddenly there’s no fighting, no fleeing, just walking around enjoying the scenery and talking.
  • Secrets! Some topic mentioned in passing in one area might have some implication for another area. Or talking to one NPC might trigger some event elsewhere (or a chain of events!). Secrets drive exploration, and lore is a great place to sneak them in rather than in a purely environmental sense (e.g. “what’s behind that door?” or “what if I attack this non-hostile actor…”).
  • Multiple endings. Cogmind will have more than one ending, some of which reflect the extra difficulty of different approaches to the story elements, while others are simply different due to choices made. Unique endings reward the player for exploring alternative challenges, and are also an opportunity to tell a little more of the story, too. (Note: Cogmind does not yet include multiple endings--we’re coming up on that soon, though currently a win is already rewarded with a somewhat different ending screen.)

Conclusion

This whole approach to telling a story with a roguelike boils down to the game being “story-backed” rather than necessarily “story-driven.” Revealing the story piecemeal through many different means, where the most interesting parts are the hardest to reach, is a good design to follow since it provides incremental incentives and is more rewarding in the long run. It’s actually easier to win a run of Cogmind than it is to discover the full story, making the latter a potentially even more rewarding experience for some players!

Either way, don’t simply dump the story on the player--that’s the boring method which gets repetitive fast. There are plenty of other options :)

Posted in Dev Series: Story in Roguelikes | Tagged , , , , , , , , , | 6 Responses

Weaving Narratives into Procedural Worlds, Part 2: Characteristics

In Part 1 I shared several areas where I believe roguelikes can benefit from the inclusion of story elements. Then comes the hard part: actually doing it :)

Because there are certainly a number of ways story can worsen a roguelike experience, the next step is to identify the characteristics of a good roguelike narrative, to show that permadeath and a procedurally generated world don’t have to be completely incompatible with a rich story.

The Story

Of course, at the foundation here is the need to have a compelling story in the first place! That’s kind of the whole point--if it’s going to be a boring, generic story, then the game may as well get by on the merits of roguelike gameplay alone. Having that strong focus is good, but it would be really nice to tap into some of that value mentioned before. What type of story can achieve those goals?

As in all things game design, consistency is key. A story that makes sense due to its consistent internal logic reinforces the whole world building aspect (Part 1). With only partial familiarity, an observant player begins to intuit things, like where to find some object or actor, what impact a particular course of action may have, etc. by filling gaps in their knowledge with what seems reasonable. They may not always be right, but at least that path is available, and it’s an enjoyable process for some. Plus being wrong is fun, too. Because surprises :)

So the most useful story in this regard will be one which makes heavy use of cross-references between the game’s different forms of content and NPC dialogue, attitudes, behavior, everything… to strengthen player intuition and general understanding. Just like solid mechanics anchor the gameplay, so can a solid story anchor the content.

Cross-referencing also makes it easier to avoid one of the bigger pitfalls that can detract from the value of story: linearity. Unless it’s somehow part of an intentional underlying theme for the game, a linear story is almost certainly bad for a roguelike. It works against the freshness of each playthrough intended by the use of procedural generation (not to mention the annoyance of having to repeatedly face the exact same story content on each death!). Instead, make sure the story is easily split up into smaller chunks that can just as well be experienced independently of one another and still be interesting and meaningful (more on that below).

A complex plot with multiple interconnected threads will also naturally be a lot more replayable.

cogmind_major_NPC_encounter_visualization

Abstract visualization of Cogmind’s potential plot-related encounters with major NPCs, colored by faction. The beginning of the game is at the left, and it progresses to completion at the far side. Many of these encounters have implications for later encounters, for the player, or for the world in general.

Notice that the story plays a lesser role in the early game, which as the most commonly replayed segment could grate on the player if there were too heavy an emphasis on static elements. This especially makes sense for Cogmind because there is no initial character generation phase, though other games could even attempt to use the very beginning to introduce a wider array of story-related options.

Story-Gameplay Integration

Story encounters shouldn’t simply be meaningful in a lore sense, but have real implications for the rest of the game, basically giving the player’s actions consequences on a higher level. Most roguelikes have a relatively short feedback loop--fight a battle, rest up, maybe raise a level, then explore until the next battle. Story elements large and small can be integrated into the gameplay itself, adding a unique kind of replay value by being elements the player can choose to engage with as part of a long-term strategy. Depending on what the player decides to do, the plot might affect later events in a significant way, have no impact at all, something in between, or maybe just cause some immediate effect. As the player becomes aware of static elements within the plot, on future runs they may or may not want to trigger certain events depending on their plans, condition, and where they happen to be.

So the story is not there simply for story’s sake, serving as the basis for additional long-term feedback loops. For this reason I try to ensure many aspects of Cogmind’s story have useful (or at least interesting) consequences for the player. This extra dimension to the world creates gameplay deeper than the average pure dungeon crawler, and despite the static elements the approach has proven resilient in the face of many replays. Plus there’s always room to expand the number of options! Even a modest number of interactive elements can lead to a large variety of combinations and outcomes.

cogmind_major_NPC_encounter_visualization_longterm_impact

The same major NPC encounter visualization from earlier, showing those with a direct effect on some later encounter (arrows), as well as those with a relatively significant long-term impact on gameplay (bracketed length).

It’s Optional!

Despite everything said so far in this series, one of the most important characteristics of Cogmind’s story is that it is completely optional.

The game should be enjoyable without requiring that the player make sense of the story to progress, or pay any attention to it at all. Players new to the game can go from beginning to end on no more than the idea that “okay, I’m a robot and there are robots out to kill me… dakka dakka boom.” In fact, every single dot in the diagrams above can be avoided or ignored.

Not shoving the story in the player’s face helps decrease the tension between those static elements and the procedural world, giving the latter plenty of room to breath. Many people enjoy roguelikes purely for the gameplay, or prefer to do their own procedural storytelling, and there’s no need to take that space away. One of Cogmind’s best players played for over a year without interacting with the story, though more recently said he gained a new appreciation for the game after beginning to dig deeper.

At the same time there are other players who from the outset put the most effort into uncovering every bit of the story, lore, and secrets they could find. For the vast majority of the lore and story elements, the player has to actually be curious enough to seek them out, and keeping it optional accommodates two very different types of players.

From a content perspective, technically Cogmind’s narrative is not centered on the player, making it much easier to be optional. This is probably an important factor when developing a rogeulike with story, as it doesn’t need to be annoyingly pervasive if the player holds some lesser role.

Another important characteristic is that the player is spoken to but never says anything in return (no obvious dialogue choices, either). Conversations are short one-way affairs, outside of which the player can simply express their intent through actions and by where they travel. Design-wise this can be a rather limiting factor, but besides keeping the experience streamlined (and easily ignorable!), design restrictions tend to lead to more creative solutions, so I’ve enjoyed working with it.

To recap, in my case the ideal roguelike story presents a compelling, consistent narrative linking much of the content, one that has a meaningful impact on the gameplay, but interacting with it is still an optional way to enjoy the game. Other roguelikes with different goals could certainly take an alternative approach to story elements, or leave them out entirely, but I aim to create a deeper experience than “just another dungeon dive,” both in gameplay terms and with regard to telling interesting and meaningful stories. I believe Cogmind has succeeded at that so far, but there’s still more work to do!

Part 3 of this series is coming next week, to talk about concrete methods for integrating a non-procedural story into an otherwise procedural world (of course taking Cogmind as an example!).

Posted in Dev Series: Story in Roguelikes | Tagged , , , | 2 Responses