I found a few spare minutes tonight to work on fixing the AI; managed to find the graphical glitch (took about 20s) and another 4 sections of code that had bugs. Much to my dismay, the guards still run in the wrong direction on the first demo level.
For those interested, the debugging process atm consists of opening both the Apple II and Coco 3 versions in the MESS emulator side-by-side, and running them (manually) in lock-step, comparing key results throughout the AI routines. Painful but a no-brainer! And it's actually fortunate in this instance that the very first guard starts off in the wrong direction - it should mean that the first pass through the AI logic will reveal most of the bugs! I mean, I've found 4 bugs already and I've only stepped through about a quarter of the AI logic!
It might seem to some that there are an awful lots of bugs in the AI code (I'm looking at you James) but you need to remember that I've added over 700 lines of 6809 without much visible feedback along the way. When porting the mechanics of movement, I was able to code small chunks of routines and - usually - immediately see whether or not it actually worked. And then fix the bugs before blogging about them!
I've also been thinking a bit about the colour version. I'm pretty sure that with clever use of the palette I'll be able to render both colour and monochrome versions of the Apple II display in the Coco3's 4-colour mode using the same graphics data. This of course means there's no reason to retain the 2-colour version of the game... though being the pack-rat that I am, it'll probably remain in the source only .ifdef'd out.
And that also goes for the Neo Geo version, of course. On that note, I've decided to tackle an automated static translation of the original 6502 code - it should be an interesting exercise in itself! I guess once I've got a 68K source base, I could also look at porting to other platforms such as Amiga, Atari ST and some other more obscure platforms.
But for now, back to debugging...
This blog chronicles my progress porting various retro games to other retro platforms. The goal in each project - at least when targeting a new CPU - is to effectively replicate the original graphics and the original code line-by-line, to produce a 100% accurate port of the original game.
Saturday, 31 May 2014
Friday, 30 May 2014
Mostly Playable
Tonight I finished porting the guard AI. I also did a quick audit of the ported code and discovered a few minor routines that I hadn't done and also a few lines here-and-there related to, amongst other things, the speed of the guards that I've subsequently completed.
However, there are clearly one or more bugs in the AI code (one of which causes a graphical glitch - they're generally easier to find) but nothing too major. The guards do wander around and occasionally act intelligently but more often than not get stuck or stand still. Regardless, it's a major milestone and within a session or two I'm hoping to have the demo screens running correctly and a 100% accurate and fully playable game!
It's also very good to note that without the delay loop (hack) in the main game loop it still runs too fast! Once I've ironed out the above-mentioned bugs in the AI code I'll port the original game speed throttling code, and then release a demo for beta testing whilst I attend to the rest of the missing features I detailed in my last post.
Lode Runner is approaching 4,200 lines of 6809 and it's interesting to note that my Neo Geo port of Donkey Kong is roughly the same size (68K code of course) but is only 50% complete!
I've been thinking a bit about a Neo Geo port of Lode Runner; hardware platform issues aside, it probably wouldn't be too difficult to write a 6502-68000 translator, especially given my now-intimate knowledge of the code base - even if it was in part Lode Runner-specific. That plus the fact that the rendering routines would be replaced with much, much simpler sprites, it may not be a lot of work to get something running! Food for thought...
However, there are clearly one or more bugs in the AI code (one of which causes a graphical glitch - they're generally easier to find) but nothing too major. The guards do wander around and occasionally act intelligently but more often than not get stuck or stand still. Regardless, it's a major milestone and within a session or two I'm hoping to have the demo screens running correctly and a 100% accurate and fully playable game!
It's also very good to note that without the delay loop (hack) in the main game loop it still runs too fast! Once I've ironed out the above-mentioned bugs in the AI code I'll port the original game speed throttling code, and then release a demo for beta testing whilst I attend to the rest of the missing features I detailed in my last post.
Lode Runner is approaching 4,200 lines of 6809 and it's interesting to note that my Neo Geo port of Donkey Kong is roughly the same size (68K code of course) but is only 50% complete!
I've been thinking a bit about a Neo Geo port of Lode Runner; hardware platform issues aside, it probably wouldn't be too difficult to write a 6502-68000 translator, especially given my now-intimate knowledge of the code base - even if it was in part Lode Runner-specific. That plus the fact that the rendering routines would be replaced with much, much simpler sprites, it may not be a lot of work to get something running! Food for thought...
Wednesday, 28 May 2014
More on the AI and overall progress
Last night I finished commenting the guard AI code. FTR there's approximately 700 lines of 6502 assembler to produce almost exactly 1KB of object code for the AI. It's straight-forward enough to decipher on a line-by-line basis; it's when I try to wrap my head around the algorithm as a whole that it takes a few more brain cells. I'm most of the way there I think.
It also doesn't help that one of the first sections of the algorithm that I tackled has a bug. I'm yet to confirm this, but I believe that this bug is (at least partly) responsible for the instances where the guards actually run away from the player. You may be tempted to suggest that it's a feature rather than a bug, but the very nature of it suggests to me that it is indeed a bug, even if the behaviour was an unintended side-effect that Doug Smith decided to retain.
Roughly speaking, as far as I've deduced the guards attempt to get themselves - first and foremost - onto the same level (row) as the player, and the search algorithm for a path is quite exhaustive, which means a lot of code gets executed. When scanning down to see if the guard can get to the same level, it (also) checks each side of that column to see if there is a route to the left or right. Checking the route to the left is OK, but when checking to the right, under some circumstances the aforementioned bug causes it to check the wrong row. So it sometimes sees an obstruction when there isn't one, and will run away when in fact the guard is only a few (empty) tiles away from the player. Other times the guard will get stuck trying to follow a non-existent route (e.g. when you see them looping on ladders).
Anyway, I'm yet to port the code and when I've done so, I'll experiment more to document the exact behaviour caused by the bug. I can also 'fix' it and see if the game is any harder.
I also did a quick 'audit' of the original code and I'm satisfied that I've identified most of the code and that those sections that I haven't commented can be attributed to the level editor or other sections that I know about but haven't ported yet. On this note, a list of what is yet to be ported includes:
Aside from the above, there's only the matter of saving/loading high scores (if I opt to implement that) and of course the level editor, which I have no plans to port at this stage.
And for the case of the Coco3, it'll be tight but I still believe it will be possible to have a 4-colour mode version of the game. The cartridge version is looking a little less likely at this stage, at least without some fancy bank-switching hardware on the cartridge itself.
I've also come across a few small sections of dead code. This includes a look-up table that determines the time that a guard will remain in a hole before attempting to escape, whose index is determined not only by the number of guards on the level, but also by an unknown variable whose value never appears to be set to anything other than zero - unless there is a problem loading/displaying the level!?! Weird...
Right now I need to finish porting the AI and then ensure that the demo levels run correctly. Once I'm satisfied that the game-play is intact and 100% faithful to the original, I'll release a playable demo of the first 5 (or so) levels whilst I finish off the bells and whistles.
It also doesn't help that one of the first sections of the algorithm that I tackled has a bug. I'm yet to confirm this, but I believe that this bug is (at least partly) responsible for the instances where the guards actually run away from the player. You may be tempted to suggest that it's a feature rather than a bug, but the very nature of it suggests to me that it is indeed a bug, even if the behaviour was an unintended side-effect that Doug Smith decided to retain.
Roughly speaking, as far as I've deduced the guards attempt to get themselves - first and foremost - onto the same level (row) as the player, and the search algorithm for a path is quite exhaustive, which means a lot of code gets executed. When scanning down to see if the guard can get to the same level, it (also) checks each side of that column to see if there is a route to the left or right. Checking the route to the left is OK, but when checking to the right, under some circumstances the aforementioned bug causes it to check the wrong row. So it sometimes sees an obstruction when there isn't one, and will run away when in fact the guard is only a few (empty) tiles away from the player. Other times the guard will get stuck trying to follow a non-existent route (e.g. when you see them looping on ladders).
Anyway, I'm yet to port the code and when I've done so, I'll experiment more to document the exact behaviour caused by the bug. I can also 'fix' it and see if the game is any harder.
I also did a quick 'audit' of the original code and I'm satisfied that I've identified most of the code and that those sections that I haven't commented can be attributed to the level editor or other sections that I know about but haven't ported yet. On this note, a list of what is yet to be ported includes:
Accurate game speed throttling- Circular wipe at the start and end of each level/life
Spinning 'GAME OVER' text animationRestoration of game screen after High Score screen displayed mid-gameHigh score table (itself)High score determination andname entry- Storage and loading of the entire 150 levels
- And last but certainly not least - sound!
Aside from the above, there's only the matter of saving/loading high scores (if I opt to implement that) and of course the level editor, which I have no plans to port at this stage.
And for the case of the Coco3, it'll be tight but I still believe it will be possible to have a 4-colour mode version of the game. The cartridge version is looking a little less likely at this stage, at least without some fancy bank-switching hardware on the cartridge itself.
I've also come across a few small sections of dead code. This includes a look-up table that determines the time that a guard will remain in a hole before attempting to escape, whose index is determined not only by the number of guards on the level, but also by an unknown variable whose value never appears to be set to anything other than zero - unless there is a problem loading/displaying the level!?! Weird...
Right now I need to finish porting the AI and then ensure that the demo levels run correctly. Once I'm satisfied that the game-play is intact and 100% faithful to the original, I'll release a playable demo of the first 5 (or so) levels whilst I finish off the bells and whistles.
Monday, 26 May 2014
The guards are getting smarter!
As I mentioned, the AI for when the guard is on the same row as the player is quite simple; if there's a direct path to the player, then move towards the player! Pretty intuitive stuff.
So this much I've implemented, and I can confirm that it's enough to get the guards escaping from the holes if the player remains on the same level. Yah! I did discover another minor glitch though - when the guard interrupts the digging it isn't cleaned up properly. I'll get to that in due course...
This morning I hit memory problems again (the code is about 3,500 lines and assembles to about 8KB now), so it was time to move the title screen data out of the source code and load it into high memory. Here's the breakdown of the Coco's 64KB memory space so far:
Each colour tile will require twice the data, but since I'll only need two (2) sets instead of four, it should occupy the same space. Likewise since the title screen data is stored in RLE format, I'm not expecting it to require too much more memory either.
Anyway, onwards with the AI for now...
So this much I've implemented, and I can confirm that it's enough to get the guards escaping from the holes if the player remains on the same level. Yah! I did discover another minor glitch though - when the guard interrupts the digging it isn't cleaned up properly. I'll get to that in due course...
This morning I hit memory problems again (the code is about 3,500 lines and assembles to about 8KB now), so it was time to move the title screen data out of the source code and load it into high memory. Here's the breakdown of the Coco's 64KB memory space so far:
- monochrome screen #1 $0000-$1DFF (8KB)
- monochrome screen #2 $2000-$3DFF (8KB)
- 6502 zero-page memory variables $3F00-$3FFF
- program code & data $4000-$6DFF (assembler output)
- monochrome tile data (4 sets) $8000-$A3C0 (pre-loaded from a disk file)
- monochrome title data $A800-$B993 (pre-loaded from a disk file)
Each colour tile will require twice the data, but since I'll only need two (2) sets instead of four, it should occupy the same space. Likewise since the title screen data is stored in RLE format, I'm not expecting it to require too much more memory either.
Anyway, onwards with the AI for now...
Saturday, 24 May 2014
Monkey See, Monkey Do
I've finished - but not completely debugged - the mechanics of the guard movement.
There's no AI to speak of yet; I've implemented some test code whereby the guards simply mirror the player or, more correctly, the keys held down by the player. Here's a short video to show the guards all moving, falling into holes and re-spawning.
You'll notice they'll actually start to climb - and then subsequently fall - whenever the player tries to move up, regardless of whether there's a ladder there or not. I started to debug this behaviour and then discovered that there was nothing at all in the guard movement code preventing this from happening! Turns out that the code relies on the AI routines to not even attempt to move up without a ladder.
To this end I've started to comment the guard AI. I was pleasantly surprised to find that the logic for when the guard is on the same row as the player is quite straight-forward. That got my hopes up that the rest of the AI would be just as simple - alas that's not the case at all. It gets significantly more involved when the guards are on a different row...
I'm still not sure whether the guards escaping from the holes is driven by the movement mechanics or the AI - they don't yet do that correctly as you'll notice in the video. From here-on in it's a matter of reverse-engineering the AI, adding it in sections, and continuing to test the movement until I've ported every line and the demo plays correctly. On that note, the re-spawn points are deterministic, and I suspect there's no random element at all to the AI either - I can't see how the demo would work if there was.
Getting down to the business end of the port now!
EDIT: After implementing a small part of the AI, it seems that the guards' escaping from holes is actually driven by the AI, not the movement mechanics. It's possible then that the mechanics are complete and working. Onwards with the AI now...
There's no AI to speak of yet; I've implemented some test code whereby the guards simply mirror the player or, more correctly, the keys held down by the player. Here's a short video to show the guards all moving, falling into holes and re-spawning.
You'll notice they'll actually start to climb - and then subsequently fall - whenever the player tries to move up, regardless of whether there's a ladder there or not. I started to debug this behaviour and then discovered that there was nothing at all in the guard movement code preventing this from happening! Turns out that the code relies on the AI routines to not even attempt to move up without a ladder.
To this end I've started to comment the guard AI. I was pleasantly surprised to find that the logic for when the guard is on the same row as the player is quite straight-forward. That got my hopes up that the rest of the AI would be just as simple - alas that's not the case at all. It gets significantly more involved when the guards are on a different row...
I'm still not sure whether the guards escaping from the holes is driven by the movement mechanics or the AI - they don't yet do that correctly as you'll notice in the video. From here-on in it's a matter of reverse-engineering the AI, adding it in sections, and continuing to test the movement until I've ported every line and the demo plays correctly. On that note, the re-spawn points are deterministic, and I suspect there's no random element at all to the AI either - I can't see how the demo would work if there was.
Getting down to the business end of the port now!
EDIT: After implementing a small part of the AI, it seems that the guards' escaping from holes is actually driven by the AI, not the movement mechanics. It's possible then that the mechanics are complete and working. Onwards with the AI now...
Friday, 23 May 2014
Left, right and up!
Fixed a few more glitches - including the 1st frame glitch - and added right and up to the guard's repertoire. As for movement, only down to go, although there are still a few more minor issues with the guard movement as a whole. The guards also die and re-spawn.
I'll press on with adding down and then look at solving the remaining issues.
Aside from the AI, I really am starting to round out the code. I'm missing the high score entry routine, and the circular wipe, but there's not a lot else aside from the editor, which I'm not planning on porting. I'll need to write my own level data access routines, which will likely be bank-switched into memory to negate the need for any DOS (and also facilitate a cartridge version).
But, I'm getting ahead of myself here. The immediate task is to complete guard movement.
I'll press on with adding down and then look at solving the remaining issues.
Aside from the AI, I really am starting to round out the code. I'm missing the high score entry routine, and the circular wipe, but there's not a lot else aside from the editor, which I'm not planning on porting. I'll need to write my own level data access routines, which will likely be bank-switched into memory to negate the need for any DOS (and also facilitate a cartridge version).
But, I'm getting ahead of myself here. The immediate task is to complete guard movement.
Thursday, 22 May 2014
Still cranking and squashing
Squashed another handful of bugs in the guard code, but still not done!
Discovered in the process that the player movement code also had a bug; the rendering looked fine on the screen but it didn't update one of the 'logical playfields' correctly - effectively leaving a clone of the player on top of every ladder they've climbed. Made it somewhat easier for the guards to kill the player!
I've deduced that the unknown guard state variable is, in a nutshell, the state of the guard. I'm yet to work out the meaning of all the different values, but 7-12 mean that the guard is wriggling to get out of a hole and - I think - negative means he's carrying gold!?! There's a bit more to it, too.
The guard state is also influenced by other variables, including an initialiser in the main game loop that takes into account the total number of guards on the level, amongst other things. A look-up table is then used to calculate the actual initial value. This is unexpectedly complicating matters somewhat, as the 'wrong' initialiser value causes guards to behave improperly.
Anyway, the guards all run left (and fall) properly now (except for a graphics glitch after the very first frame of gameplay), but are yet to be killed by the holes filling in. That I'll be implementing next session, and will hopefully shed further light on the guard status byte.
Still plenty to do, I'm afraid.
Discovered in the process that the player movement code also had a bug; the rendering looked fine on the screen but it didn't update one of the 'logical playfields' correctly - effectively leaving a clone of the player on top of every ladder they've climbed. Made it somewhat easier for the guards to kill the player!
I've deduced that the unknown guard state variable is, in a nutshell, the state of the guard. I'm yet to work out the meaning of all the different values, but 7-12 mean that the guard is wriggling to get out of a hole and - I think - negative means he's carrying gold!?! There's a bit more to it, too.
The guard state is also influenced by other variables, including an initialiser in the main game loop that takes into account the total number of guards on the level, amongst other things. A look-up table is then used to calculate the actual initial value. This is unexpectedly complicating matters somewhat, as the 'wrong' initialiser value causes guards to behave improperly.
Anyway, the guards all run left (and fall) properly now (except for a graphics glitch after the very first frame of gameplay), but are yet to be killed by the holes filling in. That I'll be implementing next session, and will hopefully shed further light on the guard status byte.
Still plenty to do, I'm afraid.
Subscribe to:
Posts (Atom)