Wednesday, December 7, 2011

Part Eight - Everything comes to him who waits

After having put the Prince of Persia project on hiatus, I went on to do other things. One of them was a GameBase64 browser for Mac OS X (for my own personal use) and the other was a conversion of the Flash/iOS game Canabalt for the C64 (not to be confused with C64anabalt, the other Canabalt version for the C64 by Paul Koller).

A port of Canabalt, the popular one-button jump'n'run, was an interesting diversion

But Prince of Persia was still at the back of my mind, mostly because it's such a great project and I got so far already. I still intended to finish it some day, but I didn't have the energy and most of all, I couldn't see the light at the end of the tunnel. I had no plan how to continue.

I wanted to release Canabalt in March of 2011, but as it turned out, I had to wait a long time for somebody to do the music for the game. In April I still hadn't received it, so I kinda became bored with waiting and my thoughts wandered off.

Before long I found myself thinking about Prince of Persia again. I had the idea to look into C64 cartridge technology to decide if that would be a feasible route to go. I only had a very minimal idea of how some of the advanced cartridges with bank-switching logic (the ones used by Ocean and System 3) worked in detail. I started investigating and in my head I began to rearrange the memory layout of my existing code base.

Which things can I move into the cartridge ROM? Which things have to stay in RAM? Where's the best place to put graphics data? How much work would it be to rewrite my existing REU-based code to get this up and running?
I was quite aware that those cartridges offered a unique possibility. Not only would I be able to move all the big animation data into ROM, but I could also have code there and run it from ROM. This meant it would be possible to free up even more RAM, which is something I needed to fit in all the parts that I hadn't touched yet. Guards and fighting logic, among other things.

But most of all I was hoping that it would allow me to fit two full frame buffers into memory, to get rid of all the ugly redrawing glitches.
So off I went, tearing my old code apart and rearranging it. I initially planned to use an Ocean cartridge but quickly found some inconsistencies in VICE's emulation of that type of cartridge, which meant that my code worked in VICE but didn't work on real hardware. I decided to continue working within VICE and got it up and running in a few days, after which I made a little video capture to show off the double-buffered drawing code.



Now I was finally able to add new features. I added Steve's player sprites and did the status display on the bottom. Things started to become easy again.

Getting annoyed by Ocean cartridge limitations I decided to switch to EasyFlash. It was a clean, well documented standard, with excellent support in VICE. I was amazed by enthusi's conversions of Maniac Mansion and Zak McKracken and I liked the fact that the cartridge could be flashed using just a C64, eliminating the need for dodgy Windows software. Also the prize was affordable, so I ordered a pre-built cartridge and it arrived at the beginning of May. I was very excited that I could finally play the cartridge-based build on real hardware so I made a little movie.


I still had a good chunk of work ahead of me. The most pressing issue now was to get the guards in, and to do a serious amount of performance optimizations.
To help with the first I was lucky that Steve had already released his conversions of those animation frames. So I now had to figure out which part of the code was dealing with the second character.

The basic idea of the game engine is that most of it can deal with either the Prince or a guard. The routines use the CharData structures, so the same animation code is used to animate them both. That gave me a hint that I should have almost all of the code already in place.
I had to do a bit of cleaning up and structure it more like the original. The low-level functions for executing the sequence and looking up frame definitions were shared. The code calling those was split up into two parts: updateKidAnimation and updateShadAnimation.

The first of the two loads KidData into CharData and ShadData into OppData using loadKidAndShad. It then runs the input control code (updateControlAndCheckForDeath), parses the sequence table (animChar), applies acceleration and velocity to the character, then updates the position. Afterwards it does collision detection and resolution.

The other function, updateShadAnimation uses loadShadAndKid to load ShadData into CharData and KidData into OppData, but otherwise does many of the same things. It obviously doesn't run the input code but instead it checks the type of opponent and then runs updateOpponent which handles hard-wired behaviors of mouse, skeleton and shadow man and generic sword fighting movement for guards (updateNormalGuardImpl). It then goes through much of the same code as updateKidAnimation to animate the character and update its position.

Since the guards only have a small subset of animation frames compared to the Prince, they also only have a smaller frame def list. To deal with this, readFrameDef calls a routine which I called overrideFrameDefListForCharacter. It checks CharID and then reads from the alternative frame def list via indexIntoGuardFrameDefList.

After updateCharacters is done with dealing with the Kid and the Shad separately it handles common code needed for fighting (checkIfStabbingOrBlocking, checkIfCharacterIsHit, checkIfStabbingOpponent) before updating the strength of both characters. Now all the state variables of the characters are final and the game is ready to update the screen.

Having made many mistakes in reverse engineering all of this code at first, I was quite happy to finally see a second animated character on the screen. Initially the fighting code didn't quite work, but that also came together after a few days. I had reached the point now where I had to move some of the code to ROM, and the guard AI logic was the prime candidate for that. So I still had room to grow the game.

The skeleton is just a normal guard that can't be killed
By now I had already became a bit bored of the first level in the game. So I added the blueprint data for all 14 levels, also because I wanted to see the skeleton in level 3. It turned out really nicely.

Within a month of rebooting the project, I had made a lot of progress and was confident that I could finish this game. But because I was unsure about the remaining parts I still expected it to take another year. The requirements for cutscenes and title screen scared me a bit. I had no idea how much work that would be. Also I had no music or sound effects, no final background graphics and performance was still abysmal. The latter now became a real problem. I had to tackle that one first. But I was just about to leave for vacation to Barcelona. Would that be a problem or a blessing? Find out in the next part.

12 comments:

  1. Hah, it seems the solution to memory problems on the C64 is also "get an SSD"! (-:

    ReplyDelete
  2. Rebooting an old project is an impressive feat.

    ReplyDelete
  3. Very impressive! Cool that you made progress so fast after switching to cartridge. I find it more and more difficult to keep believing that this game could work on a plain C64 without cartridge. (Maybe if someone says the magic word "Impossible", Crossbow is going to make it happen - in SMON.) ;-)

    ReplyDelete
  4. @S.E.S.: I found that the switch to cartridge was particularly easy because it simplified the code so much. Previously I had REU transfers littered through the code, and suddenly all I had to do is set $de00 to switch cartridge bank and could access data and code as if it were in RAM. So this was one of the reasons why I progressed so quickly after deciding to go with a cartridge.

    ReplyDelete
  5. Thanks for writing this blog - I really like reading it!

    ReplyDelete
  6. Hey,
    Thanks for your last set of tips. The character animations look way smoother now.

    Just a quick question regarding CharSword and CharLife.... What are the different bits being used for? I see the 6th and 7th bit of CharSword and 7th bit of CharLife has some kind of significance but I haven't figured out what.

    ReplyDelete
  7. you got a 94% score in the latest Retro Gamer mag, and a fine review as well - topped with a "sizzler" badge/reward. :)

    ReplyDelete
  8. This comment has been removed by the author.

    ReplyDelete
  9. Thanks a lot for your work!
    However, what do you mean by "Ocean cartridge limitations"? Does it refer to the fact these are not well documented, as indicated in your post?
    Thanks

    ReplyDelete
  10. Still reading and enjoying. Thanks for keeping the updates coming

    ReplyDelete
  11. I hope the series continues next year :-)

    ReplyDelete
  12. Hi Mr Sid,

    I couldn`t find any other opportunity to contact you. I want to ask you if it`s already if I used footage of your port for a review on Youtube:
    http://www.youtube.com/watch?v=FykuXgQjESk

    Just drop me a comment in case you don`t like if your games are reviewed on Youtube and I`m going to delete it.


    Regards

    ReplyDelete