Ascent of Hintermark

Tame the Wilderness

Tuesday, 15 March 2016

Progress February (and a bit of March) 2016

The development of Ascent of Hintermark continued in February and the first two weeks of March.   Whilst development in January was dominated by tool development, the latest weeks have focused mostly on upgrading the dungeon generation code.  One of the goals of Hintermark is to provide a deeper tactical depth of how dungeons [1] are explored, so this part needs a lot of TLC.  February's work is just the start.

Generating Dungeons

Whilst generating beautiful dungeons is a popular endeavour in the roguelike community, this has not been the focus in February.  The focus has been more on reorganising the backend to handle a tactical underlying structure, and to ensure that dungeons are always traversable.  As some dungeons will be persistent it will break the game if one was unable to traverse through the dungeon during a quest.

The first quest (aka the ambush quest) is the "red thread" which development follows, and the first dungeon visited is a natural cavern.  To generate this cavern an erosion algorithm is used for each room, and then the rooms (and clusters of rooms) are connected by tunnels.

A challenge with the erosion algorithm was that the generated rooms could look quite odd due to the random nature of the erosion.  The general parameters into the generator gave quite varied results, but at room level there were frequently layouts that felt wrong. As a first step in trying to make this better, a set of algorithms were executed to "post-process" the rooms in order to make them fit an overall style of the cavern (e.g a rounded earth cave system needs to look different than a limestone cavern).  As different post-processing produced different results, the obvious step was to allow specification of which post-processing algorithms are used (and in what order) in the etage rules (json-files).

As the dungeon generation got more complex and post-processing became easier to tweak, it was obvious that the Etage Visualiser needed to be extended to inspect each generation step and post-processing for individual rooms.  A rewrite of the generation algorithms to track the steps was done, and the Etage Visualiser was extended with support for viewing each step in detail.  It was easy to then add support for generating each step as an image which could be combined into an animated GIF.

Tactical Structure

While the dungeon generation was making progress, steps were needed to add and maintain a tactical structure in a random environment.  Support for "Areas" was added last year, where an "area" is a prefab(ricated) area that can be added either by design or randomly picked by the generator.  Some examples are e.g the interior of the mayor's house or the town market:




Whilst "areas" have a limited amount of randomised elements, they hardcode specific floors, decor, etc and are too specific for a general dungeon generator.  Therefore, a method was needed to describe only the structure in more abstract terms, and where each etage/dungeon would fill in the specifics.

The easiest starting point was to look at the room structure itself and how it influences the tactical environment.  Imagine an end-room with a single hallway in and a small gang of defenders in the room.  They would most likely set up fortification in the hallway and possibly traps on the way in.  This behaviour would be the same regardless if it was in a fantasy-style dungeon, a castle or even in a dense forest.  Enemies capable of thinking tactically would shape their environment and set up defenses.  The generator needs rules to set up creatures, their tactical environment and most importantly a fun environment that the player can exploit.  After a few attempts and refactoring the mechanism got the inventive name "Structures", and can be combined with "Areas" for an even more powerful tool.

Area elements represent concrete floor types, decor, creatures, ..  Examples are e.g "right-side-wall-desert-style-terrain", "upper-right-corner-riverbank", "red-vase-yellow-flowers", .. Structure elements represent more abstract descriptions , e.g basic ones "permanent wall", "open floor", "optional floor", "stair upwards", .. It is a generator's job to fit in these mechanisms with the normal generation if it decides to (or is forced to) use a "structure".  Structures, like areas, are layered and can have overlapping rules for floors, decor, creatures, items, ..


This is still very much a work in progress, and will be the topic of a more extensive write-up later as I think it is a useful strategy for other TRPGs and roguelikes as well.

Other Dungeon Generation Fixes


Generally the entire backend of the dungeon generation has undergone a major upgrade, where almost no part has been left untouched.  This is not limited to structures and connecting graphs/rooms, but is also a key point in allowing the generators to be a lot more configurable from etage rules.  How to place stairs, the player, exits, room rules, .. are all now part of a very configurable format.

Simplification of the generator code and how we work on dungeons, nudged the underlying code to rely more on higher order lazy iterators to transform dungeons.  The downside of this is more garbage created compared to for-loops, but the readability and conciseness have been greatly increased.  As this is mainly used during the generation step, the extra garbage can be collected before the gameplay of the level.

Continuous Integration

As Hintermark has become bigger and more complex, with a growing test set, it was about time to set up a continuous integration server.  This would help run tests on a different machine than the development laptop (to avoid machine-specific files and behaviour) and ensure that things are working.  Thanks to KolibriFX I was allowed to borrow an older stationary Linux box that now runs Jenkins and happily builds things all day long.  Michael let me borrow a usb wifi-dongle to put it on the home network. When new code is pushed to the source repository, the server will build and test that everythng is (still) ok. Via Slack the server will also notify me on my mobile whenever things are built.

Naturally this took some work, but the hope is that it will save energy in the long run. An extra bonus is that things run great on Linux as well, and not just OSX.

An issue that popped up was that the RNG behaved slightly different on Linux, so the standard RNG was replaced with a modified XorShift+ algorithm where I can store the entire state of the RNG and restart it at any point.  This works regardless of platform now, so tests can rely on RNG behaviour on Linux, OSX, ...  This will also be useful for later save games where RNG state will be stored.

Ambush Quest

As mentioned above the first quest is what forces the development, and in February the focus was on the first cave system in the quest and the encounters there.  This is not finished, but is moving ahead with new dialogues and extending the quest.  The needs of the quest also plays into how we set up the tactical environment (e.g "structures" as explained earlier), but it also moved us more into the gameplay territory.

Component System

A trendy thing in game development these days are Entity Component Systems (ECS). Discussion persists on best practice and how to implement behaviour.  Hintermark had a preliminary component system for creatures (player, people and monsters), but as the tactical environment expanded the player also needed to interact with the environment.  After a refactoring the code, most entities (creatures, items, terrain, decor, ...) in the game can now be composed by arranging components.  The entities' attributes and behaviour is defined by the components it consist of, where the existence (or not) of the right components decide whether it can be attacked, destroyed, ..  This is a work in progress, and some parts of the code rely on types (Person, Monster, Player, ..) but this is gradually being phased out.

Generally ECS separates the code (system) and the data (entities consisting of components), but a more OO approach has behaviour in the components as well.  For now Hintermark uses components with behaviour to keep related concepts together.  As an example the Drop Component has the behaviour to drop items if the host entity (which can be a person, monster, decor, item, ..) is killed or destroyed.


This is still a work in process, but as of 12th of March the player can now target e.g wall-mounted torches.  The player can then shoot them down with an arrow with the same attack/health/drop components as would be used as when attacking a bandit.  This is going to be the focus for more of the March development, along with more work on structures.

Notes:

  1. In this blog post I will use the word "dungeon" to refer to a generated etage/level, regardless of whether it is an actual fantasy-style dungeon, natural cave system, dense forest or even a town.

Monday, 1 February 2016

Progress January 2016

Despite being low on energy in January I have managed to put some hours into Hintermark.  While the actual hours put into it aren't plentiful, they're usually efficient when they happen.  I thought I should share some of the progress with you, on this brand new blog.

Etage Visualizer

Last you heard of any progress on Hintermark,  I had spent a day or two to make a quick and dirty Etage Visualizer  [1] in Gtk# to optimize the workflow when working with dungeon generation.  That was a huge success and allowed a lot faster iteration.  The Etage Visualizer was soon expanded with support for checking player placement, different dungeon generators, seed control and stair placement.  The newest feature is the ability to load players in different states, e.g to see what maps look like depending on the player's quests and progress. It has over the month turned into a very useful tool, but looks hideous.


Conversation Simulator

Inspired by the Etage Visualizer, I realized that tweaking conversations and conversation-like interactions was a bit cumbersome to go into Unity to test.  So I added a small Gtk# app that allows me to run conversations and conversation-like interactions quickly, and allows me to choose players and conversation-"owners" quickly to check behaviour. This seems to work fine, and over time I think it'll be as beneficial as the Etage Visualizer.


Ambush Quest

The first (tutorial) quest (aka the Ambush Quest) is the current red thread in the development as I am developing general features to support it.  This allows me to use those features for other quests, both handcrafted and generated quests.  One of the more important features that will be in Hintermark is extended interaction with the environment. In the Ambush Quest this is central to the quest several times to ensure players know that environment interaction can get them far.



As part of this quest the player will approach the ambush site and needs to inspect it for clues on how to proceed. Triggering environment actions and inspecting the general environment is now 80% implemented, and it feels right so far.  The work here also caused a full overhaul of all floor tiles, decor, items and creatures to ensure they all had proper names and descriptions. The presentation has taken a backseat to functionality so far.



A bit later in the Ambush Quest the player will find a natural cave, and work has started on the generator.  The general dungeon generator uses rectangular-like rooms, which makes it fairly easy to  insert various tactical elements.  We need fun tactical elements in natural caverns, as well.  Natural caverns don't have a rigorous structure like a man-made dungeon, but are more fluid in nature.  This is the main challenge for February; to allow a more general way to describe areas for insertion of tactical elements, so that we can use most of the code for the dungeon generator in the cavern generator, too.


Technical Progress

Among other things, a smarter way to deal with coordinate flags has been implemented.  This is separate from the field-of-view (FOV) code and takes into account special behaviour of certain floors and "decor" on each coordinate in a better way.  This was a fairly big rewrite, but already allows more fine-grained behaviour for how to deal with coordinates for the FOV-code, the AI and for player choices.

I am using Tiled to edit some of the environments in the game, and especially for areas that the generators can insert.  Tiled is a multi-layered tile editor where I can insert abstract and object information into these areas.  Besides normal drawing of areas and placing items and environments, I use it for adding quest information, meta information and even coordinate triggers and events.  Tiled exports .tmx files which I then convert to Hintermark's internal system.


What's Next

In February the plan is to delve into more of the dungeon generation and combining it with tactical elements, in particular for more fluid environments like a natural cavern (as opposed to the more rigidly structured dungeons).  Extending and working more on environment interaction is also the plan. 

To allow you all to see what happens, I expect to make a short video to demo some new features and  revamp the website a little bit.

Notes:

  1. Etage is the word I use for a generated floor or level.  As both floor and level are kind of ambiguous words I chose the word etage.