In the mouth of a broad tunnel, they paused to look one more time upon the fair land of Midnight.

Here is something that I have been working on in the background – Tunnels in The Lords of Midnight. It’s not something that is going to be used in the main game, but I am hoping to have a new scenario released later this year, early next at the latest.

For those of you who have read Drew’s novelisation, then the need for tunnels will make sense. For those of you who haven’t, well something for your list…

Normal Tunnels

Now, you’d think that adding tunnels to LoM would be pretty straight forward. It is as you may know from following my posts, the same codebase as Doomdark’s Revenge, having been unified a few years back. However, there are some issues.

Firstly, even though they are the same engine, and use the same data structures etc, the games are built conditionally as separate projects. This means certain part of the engine is not compiled depending on the games. For example, tunnels, mist, AI lords, special objects, are not part of LoM. Regiments, Ice Fear, and Waypoints, are not part of DDR. There are other little things like critters and battles working differently, and small UI changes.

The engine is written in c++ and most of these features are turned on or off using preprocessor macros like this..

            if ( !IsDead() ) {
#if defined(_DDR_)
                flags.Reset ( cf_inbattle|cf_wonbattle|cf_preparesbattle);
#endif
#if defined(_LOM_)
                flags.Reset ( cf_inbattle|cf_wonbattle );
#endif

Some of it is handled with c++ object inheritance.

Some of it is not handled very well. The code base, like many projects has morphed and evolved over the years. I as a 30+ year veteran software developer, understand the vast gulf of academic based code structure, and real world getting it done with deadlines. And it’s no surprise that the engine has many of these pitfalls.

The following piece of code makes sure that two characters tunnel status is the same. ie: These two characters can only see each other if they are both either in, or both out of the tunnel.

#if defined(_DDR_)
            // they both need to be in or out of a tunnel
            if ( c->IsInTunnel() != IsInTunnel() )
                return false;
#endif

The thing you will notice is that the preprocessor check that will include this code is _DDR_ which means, it only gets compiled when I build Doomdark’s Revenge. Ideally this code should either be governed with a _TUNNELS_ feature preprocessor macro or better still, a feature check based on the capabilities of the scenario. So, that was the first thing I had to do and it took a few iterations to get it right.

The landscaping view for DDR is different as it has a header, therefore the tunnel view needed to be modified.

New graphics were used to distinguish the two.

Text had to change. The DDR strings database has ways of describing that a character is in a tunnel, or can see and entrance. LoM did not.

I found a bug on the think page that is in DDR in that it will show you information about a character in a location that does not have the same tunnel status. There were a couple of other UI issues specific to LoM for showing characters or armies in a tunnel. These just come out of different code paths.

Narrow tunnels

You will notice in the above image, a slightly different tunnel view. This is for narrow tunnels. The novel explicitly has Farflame not entering the tunnels when Morkin does even though they are together, and this is because he is too large. This is a story specific plot device, but that makes no sense when we consider the tunnels in DDR. So the change I made to accommodate this was to have normal and narrow tunnels. In this instance Farflame can enter the tunnels, but there are some important areas that he cannot go because they are too narrow, and the game indicates this with the slightly different layout. Narrow tunnels will also be extended to armies, and too many characters in one location.

Something else I have done with the tunnels is to tweak the concept of entrance and exit. In DDR these are always one of four terrain types – Palace, Pit, Gate, and Temple. However using the mapping software you can now override this and mark any location as an exit, an entrance, or both.

Tunnel view in mapping tools

And finally, while I was make changes for the mapping I extended two other features. Firstly impassable mountains. This was added as a rule recently to help make games optionally harder or just different and it was locked to just mountains. However, I have now added a feature to allow any location on the map to be marked as impassable. In this instance it will be used for all the mountains around Ushgarak. This means that the only way to enter the plains of despair is to take Kor and Grarg. The slight pass at Vorgath as been closed off but I am having to think this through a little more because of the consequences to a western attack.

And finally, respawning of things. In DDR critters and things (claws, thorns, springs, etc) regenerate randomly. I am planning on adding this to LoM as a rule, but for the next scenario I am also adding it as a mapping feature so that certain locations can respawn. In this instance I am using it for critters in the tunnels.

Tunnel Exit

There will be more information about the Novel Campaign later as I work my way through it.

Should we prepare to do battle against the wind and snow?

I was looking at a battle issue reported recently that battle reports were not always being displayed. I’ve had reports before that the AI Lords don’t appear to engage in battle the same as the original, but I have tested this many times and not been able to find an issue other than the AI being unpredictable and a little shaky.

I had recently done some testing while adding the new game rules in place and had my lords attacked, and indeed failed an approach of lord and been attacked, and attacked a lord and battle had commenced, so on the whole it seemed to be working.

I poured over the code again to check the AI conditions of battle and noticed something interesting. The rule is that if the lord can’t walk forward and it is dawn and they are not blocked, then there is a 50% chance of them staying in the current location and ending their turn.

Analysing that a little; blocked means exactly that, they cannot move in the direction they want to under any circumstances. This is usually because of Icy Wastes or there are too many people in the location. Can’t walk forward is usually a transitory check, something in the location they are in or entering could potentially stop them entering, but nothing that would break the game. The Dawn check is just helping to differentiate moving into a location during the turn from moving out of a location at the start of the turn.

The code that makes those decisions is separate from the code that is handling the AI Turns logic. So I went to look at that to check under what condition the lord could not walk forward, and the thing that caught my eyes was – if there is an enemy in the current location. Combine that with the checks in the AI Turns logic and what you have is, there is a 50% chance that a lord will leave a battle at the start of his turn, but if they enter a location with an enemy they will always stop to fight.

The problem was that this flag was being reset by another piece of logic which was actually more to do with the player and not the AI, and also some shared LoM logic. The net effect was, if you attack an enemy lord, or have a failed approach, then the enemy will pretty much always move on and not engage. Now, this seems counter to what my testing has shown, so I can only posit that there was something else happening in these situations that was keeping the enemy at the same location.

Once I realised this it was a quick fix to isolate the piece of code that was overwriting the can’t walk forward flag. However, this then highlighted another bigger issue, and that was that the lord was not considering the enemy as their enemy, and thus the trigger was not occuring.

Again, I checked out the area of the code that handles this, and clearly it was based on LoM, in that Luxor is the friend, and Doomdark/Shareth is the foe. But this does not take in to account the multi-race nature of DDR. So what in effect was happening is that the AI was not really considering the players lords as enemy, or indeed not always correctly considering the enemy AI lords as enemy, which means they would often over look them. Obviously there were fighting, but again I think other issues were causing them to stay in the location of another lord. And as long as multiple lords are in the same location, the battle algorithm would get the friend/enemy check correct and they would fight.

Now, this looks like it has always been wrong, ie: nearly 10 years since I released the games. But I suspect the problem is actually due to the merging of the code bases and likely crept in in the later stages of v1 and then rolled over in to v2.

Stray boulders made a mountain range of the forest floor

I shall be releasing an update to both The Lords of Midnight and Doomdark’s Revenge toward the end of June. This is the “Summer Solstice” update.

There are currently three fixes.

  • Problem with Android rotation.
  • Cowardly lords can still enter a battle.
  • Characters are no longer correctly tinted by the time of day on the landscape.

Along with these fixes there will be a couple of new features. These features will be driven by the new gameplay rule system. The idea being that you can additionally enable certain features that will have an affect on how the game plays.

Menu showing gameplay options

I have been planning this for a while and intended to introduce it with the c# rebuild that I am working on (slowly), but after requesting features for possible inclusion in regular updates I have decided to bring it forward. It gives an easy way to extend gameplay options.

Neil Swanson contacted me with a few ideas for new features and they have been rolled in to the gameplay rules.

I’ve also always intended to have a game difficulty mode: easy, medium, hard. So the intention is to use this in conjunction with the gameplay rules to leverage different types of play.

The following rules have been slated for development and have issues created for them on my GitHub repos. There are likely a few things to consider for them, so details may change.

  • DDR – Original terrain travel times
  • DDR – Armies attack when near an enemy
  • DDR – Armies will continue a battle without just randomly leaving
  • LOM – Cup of Dreams can replenish overnight
  • LOM – Varied initial start positions
  • LOM – Utarg of Utarg can become disloyal
  • LOM – Doomdark will go after Morkin heavily if the Ice Crown is picked up
  • LOM – Doomdark will guard the Ice Crown more heavily
  • LOM – Change quest completion rules to align with Mike’s original intention
  • LOM – Fey are not recruitable
  • DDR – Fast Tunnels
  • LOM/DDR – Impassable mountains
  • LOM/DDR – AI Impassable mountains

The plan is to have the last 4 in the Solstice update, and the work on Impassable Mountains already almost complete.

It’s interesting that when you think of a simple one line description of a feature, how complex it can become when you start to develop it. For example, impassable mountains are just that. LoM and DDR already have a concept of impassable terrain with the Frozen and Icy Wastes, so dropping in Mountains seems simple enough until….

What happens if the friend/enemy is in a mountain? You need to disable approach and battle. Out of that comes the concept of AI Impassable mountains to stop the AI characters from freely moving around the map. But that has its own issues.

What happens when a lord loses a fight and runs away. Well in LoM they only leave on location and there is already a check that it’s not Frozen Wastes, so that becomes straight forward. But in DDR they move up to 3 locations away. It checks that the target location is not Icy Wastes but not if the locations to get there are. Which is why you can currently be bounced in to the Plains of Anvoril if you enter battle up against the Icy Wastes surrounding it.

In DDR special objects are randomly placed on the map. So they can’t be placed on a mountain, but technically they can’t be placed anywhere that can’t be accessed. There are a handful of locations that would be problematic. So either the map needs to be edited to make those locations accessible, or they need to be marked as un-accessible, or we need to allow particular lords or races to not be affected by Impassable Mountains – like say Giants and Dwarves. The later make sense as there are a few Dwarven fortresses that are locked away in the mountains.