I would like to acknowledge the work that has already been done by Johnny on reverse engineering these sections of the game when he wrote his password generator currently live on our website as this has saved me a lot of time tracking everything down. His legacy lives on and hopefully will help inspire the others along the way!
What is Dynamic Difficulty exactly?
When starting a new game, the player is faced with a choice of three tunnels that correspond to difficulty level. The one directly above that has a couple of spiky shells blocking it will set game to Hard, the one next to it that goes diagonally up and to the right will choose Easy and finally going straight to the right will start a Normal game. In this mode the game will be tracking your progress and automatically switch between Easy and Difficult depending on how well you are progressing through the levels.
Current difficulty level can be immediately seen by the size of Ecco's life and air meters: as soon as you see that they've become somewhat squashed, the game is now in Hard mode! How does this work?
And now finally we are starting to get deep into the code!
Everything that is required for this the game keeps at a memory location of 0xA7BC::D. It's two bytes that they are using the individual nibbles of as follows:
Code: Select all
0x0000
^^^^
│││└--- Current difficulty (1: easy, 0: hard)
││└---- Force Easy Mode (0: disabled, 8: enabled)
│└----- Deaths counter when easy/hard is forced (0::F), points when Normal (0::1F -- MSB carry)
└------ Force Hard Mode (0: disabled, 8: enabled)Things are fairly straightforward here. Starting the game on the selection screen preloads this memory location with 0x1001. Forcing Easy mode sets it to 0x0081 after which it stays that way and does not change throughout the rest of the game. Similarly, forcing Hard mode will fix it at 0x8000 -- note how Easy Mode flag mentioned above has been set to 0.
In both cases above the third (from the right) nibble is then used to keep track of player's deaths (0::F).
- Dying once on Forced Easy will read 0x0181, twice 0x0281, etc until 0x0F81.
- Dying once on Forced Hard will read 0x8100, twice 0x8200, etc until 0x8F00.
Normal difficulty
So far, so standard, but what we are really interested in is what happens when Normal difficulty is selected and this is where things start to get really exciting as essentially the same data set is now used in a completely different way!
- As game begins, the location is preloaded with 0x0C01: easy mode flag is set and we are allocated 0xC or 12 in decimal points that are now stored in the location previously used to track player's deaths.
- Winning a regular stage decrements that counter by a few points. How many depends on the initial value.
- Losing at a regular stage increments that counter by a few points.
- Losing at a 3D stage increments that counter by exactly one point. That makes them more forgiving.
Code: Select all
0x0C Home Bay
0x09 Crystal Springs
0x07 Fault Zone
0x06 Two Tides
0x05 Trellia's Bay
0x04 Skyway
0x03 Sky Tides - Hard Mode startsCode: Select all
0x0B Sky Tides - Back to Easy Mode
0x09 Tube of Medusa
0x07 Skylands
0x06 Fin to Feather
0x05 Eagle's Bay
0x04 Asterite's Cave
0x03 The Lost Orcas - Hard Mode returnsThere are two main functions that are responsible for calculating the difficulty points. The one that decrements them every time you win is located at ROM offset 0x865D8 and its section that we are interested in will look like this when greatly simplified:
Code: Select all
uint16_t winNormalStage(uint16_t points) {
uint16_t modifier = points >> 2;
modifier = points - modifier;
points |= modifier;
return points;
}Its sibling responsible for penalizing the player and living at ROM offset 0x868CC is a little more complicated as they now have to be careful not to clobber the flags adjacent to it:
Code: Select all
uint16_t loseNormalStage(uint16_t points) {
uint16_t modifier = points;
if(modifier < 20) modifier++;
if(modifier >= 4) {
if((modifier < 10) modifier = 10;
}
points |= modifier;
return points;
}3D Stage Points System
You will have most likely noted how password generator on our website has that checkbox and setting it causes additional ticks to appear on the difficulty bar. This has to do with the fact mentioned above, where 3D stages will always penalize the player by one point only when dying. In normal mode the password generator assumes that every 3D stage has been passed flawlessly, but real life could be different and multiple losses on those could affect the player's progression towards harder difficulty levels. This could be considered a cosmetic addon, aimed at making generated passwords more like as if they were generated by the game that does not really affect anything else.
Conclusion
Tides of time was a very unique game for its time on Mega Drive and one of the many aspects that made it such was its dynamic difficulty. I hope that this short article has helped demystify the features of this system and overall made you better appreciate the elegant code that Novotrade have come up with for this!