Friday, 30 April 2021

The 80:20 rule of Scramble; you can only get 20% of the way through the game with 80% of the code written.

I've completed the game lifecycle mechanics and fixed a few bugs in the process. Somewhat interestingly, in two completely different routines I had omitted the instructions that reset the column scroll values in the C code. Strange coincidence.

But you can now coin up and play 1P or 2P games through to completion and back to attract mode.


2P game in action

There are a few odd bits of code in there, such as specifically copying two one-byte data values from memory (a level value and a flag) over the storage for a pointer; they're never read back and that same copy is done in two places. However it's benign because the pointer is re-initialised before it is used again. I'm scratching my head wondering how that could have gone unnoticed in the assembler source.

I've only got two reasonbly trivial routines that I can't test to go besides all the the routines related to player bullets & bombs and their collisions and explosions. Those routines simply check if an extra life should be awarded (based on score) and also display the 'mission complete' flags.

Looking at the source code after yet another cleanup I'd estimate it to be around 80% complete. There's nothing new in those routines that hasn't been transcoded already, and a lot of it will be cut and paste. Whilst the code is nicely structured and lends itself very readily to a C transcode, there is a reasonable amount of very similar and in some cases outright duplicate code.

From here there's a couple of days of work in the bullets and bombs and then it'll be play testing.

I'm yet to transcode any audio-related routines. The audio control simply involves writing sound ordinal values to the sound CPU (another Z80) which controls a pair of AY8910 sound chips. I'm not intending on porting any audio at this point, but will probably add stubs for the audio routines so that sound may be added at some point in the future, even if not by me.


Thursday, 29 April 2021

2P or not 2P, that is the question.

 Today was mostly working through all the game lifecycle mechanics and adding some support for scoring during the game.

In previous transcodes I've just used (long) binary values for scores etc. In Scramble however, at some point early on I chose to preserve the use of BCD, and although I can't recall the exact reason I do remember thinking it was the right choice at the time. I'm regretting it a bit now, because the code for adding to your score is a bit messy in C, and the high score table code was just tedious.

You can now play through a game and get back to attract mode and start another - if you have sufficient credits of course.

1P gameplay mechanics seems to be complete

With no firing/bombing implemented it's difficult to get too far through the game, even with infinite fuel. On the 1st stage it's fairly easy to dodge the rockets, but the UFOs on the 2nd stage are another matter. A simple algorithm but effective.

High score table update is coded but not tested. Interestingly, the way I read it is if your score equals that of any previous entry in the high score table, the game will not insert your new score. That's a bit weird and it's going to be tough to confirm on MAME because playing the game you get 10 pts every second or so just for staying alive.

Although it's boring I'll probably work through the 2P mechanics just to get it ticked off. Given the architecture of the code though, that'll be an effort not considerably less than the 1P mechanics.

I'm wishing now that I had preserved all the ASM code in the completed C functions. It's kind of cool seeing the original code and makes it easier to debug; just blows out the file size considerably.

Given the relative ease of this transcode, and the fact that Galaxian uses the same hardware, I'm pretty keen to start on that as soon as Scramble is finished and ported to at least one if not a few other platforms. I'm a little concerned that older C compilers may not like my anonymous structures and unions, but I'll cross that bridge when I come to it. With Galaxian though, I'll preserve the original ASM code in the C source and see how that works out for me.

Wednesday, 28 April 2021

Running on the smell of an oily rag

Working through the game start up and it's a bit of a grind to be honest. A fair bit of code had to be transcribed before anything interesting happened. But I now have the game starting and the player ship moving around. If you don't die from being hit or colliding with something, you'll run out of fuel.

Coin up, start a game and move around.

No shooting or bombing, but you can play through the 3 lives and it displays "GAME OVER" although I suspect the scroll offsets of the display area haven't been reset as they should be as it appears at a random offset from centre, and in the wrong colour. A quick search didn't reveal where that was but I'll find it.

As I work through the code I mark each routine as being one of UNIMPLEMENTED, WIP, LOOKS_OK, UNTESTED or COMPLETE via a printf that can be selectively enabled or disabled by category. Today added a whole swag of UNTESTED routines.

Unlike my earlier efforts, in this transcode I've started with the original disassembly, with every line denoted a C comment. Makes it much easier to keep functions in the same order as the ASM code, and keep track of addresses etc. Until a few days ago I was writing the new C function under the corresponding ASM function, but more recently I've moved the commented ASM inside the functions with the C code following each block of ASM code.

I've been removing the ASM code from the file whenever I deem a function to be COMPLETE (tested, debugged) but now I'm thinking that in my next transcode, I should actually keep the ASM code in there. It'll blow out the source file size of course, but does that really matter?

An example of what I mean...

// $10BA
void game_init (void)
{
  DEBUG_OPT_UNTESTED;
  
  //10BA: 21 09 40    ld   hl,$4009              ; load HL with address of TEMP_COUNTER_4009  
  //10BD: 35          dec  (hl)
  //10BE: C0          ret  nz                    ; wait until counter reaches zero
  //10BF: 36 0A       ld   (hl),$0A              ; set TEMP_COUNTER_4009 to 10

  if (--wram.temp_counter_4009 != 0)
    return;
  wram.temp_counter_4009 = 10;

  //10C1: 2C          inc  l                     ; bump HL to point to SCRIPT_STAGE
  //10C2: 34          inc  (hl)                  ; advance to next stage of script (PLAY_GAME @ $22F4)
  
  wram.script_stage++;
  
  //10C3: 3E 01       ld   a,$01
  //10C5: 32 19 40    ld   ($4019),a             ; set DRAW_LANDSCAPE_FLAG
  
  wram.draw_landscape_flag = 1;
  
  //10C8: 21 01 00    ld   hl,$0001
  //10CB: 22 80 43    ld   ($4380),hl            ; set PLAYERS[0].IsActive and reset PLAYERS[0].IsExploding flags
  //10CE: 22 A0 43    ld   ($43A0),hl            ; set PLAYERS[1].IsActive and reset PLAYERS[1].IsExploding flags
  
  wram.players[0].is_active = 1;
  wram.players[0].is_exploding = 0;
  wram.players[1].is_active = 1;
  wram.players[1].is_exploding = 0;
  
  //10D1: AF          xor  a
  //10D2: 32 82 43    ld   ($4382),a             ; reset PLAYERS[0].StageOfLife (see PLAYER_INIT @ $16FE)
  
  wram.players[0].stage_of_life = 0;
  
  //; player starting level, update lives remaining 
  //10D5: 21 08 41    ld   hl,$4108              ; load HL with address of CURRENT_PLAYER_LIVES
  //10D8: 35          dec  (hl)                  ; reduce number of lives
  //10D9: 11 03 07    ld   de,$0703              ; Command ID: 7 = HEAD_UP_DISPLAY_COMMAND, Param:3 = DISPLAY_CURRENT_PLAYER_LIVES
  //10DC: FF          rst  $38                   ; call QUEUE_COMMAND
  
  wram.current_player_lives--;
  rst38_queue_command (7, 3);           // HEAD_UP_DISPLAY_COMMAND, CURRENT_PLAYER_LIVES


There is one bug that I haven't even looked for that revealed itself after I got the full demo lifecycle coded; when the player is killed and the next life starts, random strips of the landscape are missing. Given the nature of the bug and the data structures in the game, I suspect it's an area of memory being corrupted... hopefully it won't elude me for too long when I finally go looking for it.

There's probably another day or two (at least) working through the game lifecycle mechanics before I get onto the shooting and bombing.

Tuesday, 27 April 2021

Oh flip!!!

 Some good progress today even though there's not a lot to show for it.

I fixed a couple of bugs (including the stubborn explosion sprite one) that weren't directly related to transcoding the actual Z80 instructions to C. And speaking of the sprite bug; I stared at it a while longer before it struck me that the sprite codes for half the ship explosion were out of range! What that meant was that they had flip X/Y bits set - which I hadn't yet implemented!

The other bug was the 'graphical glitch' on the text way back from Day 1. Today I noticed that it only seemed to occur on the attract screens, and then I noticed it was only on the 'space' character, and always the same glitch. Didn't take long to realise that my text strings were using the wrong character code for space! All fixed now.

I worked through the collision routines for the ship and different objects, such as rockets, ufos, fireballs, and ground-based objects, and finally the landscape. I had to patch the code temporarily to trigger different collisions in demo mode, but everything I can test in the demo seems to work now. I also did a big clean-up of all the C code, removing the ASM code (comments) from routines that are considered complete.

So on to starting a game; implementing coin-up, reading from hardware (dipswitches, coin mechanisms and buttons), more scripts and initialisation code to transcode. I also had to hack a fix for a race condition between my two threads - since I don't actually have a proper, pre-emptive vertical blank interrupt (NMI) routine - but works better now.

Current state of progress is that you can coin up and start a game, but you don't get to see any evidence of the latter as of yet.

Coining up

Next I'll continue on with getting a game to start, and either moving the ship or finishing off the higher level mechanics of the 1 and 2 player game lifecycle. That'll leave bullets, bombs and their interactions.

Sunday, 25 April 2021

And then I went and spoiled it all by doing something stupid like explode you...

 I've added the player, player explosion and rocket explosion. And in the process I've encountered my first stubbon bug since I began the transcode.

The player explosion is obviously wrong

You can see that the player explosion is using the same sprite for both halves of the ship. Trouble is, I've checked and double-checked the code, printed debug messages, and I still can't explain it. It's driving me nuts. Here's hoping a new day will shed some light.

That aside, there is a *LOT* of code for the collision detection and explosions. The top level collision routine calls no less than 13 subroutines, each checking collisions between a player/bullet/bomb and object/landscape. And there'll be a lot of cut-and-paste in those routines. I'd even estimate that once I've completed both, I'll be 75-80% through the transcode. The remainder will be for coining up, player controls and mechanics of one and two player games and scoring.

Stay tuned.

Saturday, 24 April 2021

All your base are belong to us!

 I now have all the objects that aren't related to the player rendering and animating - including the end of game 'base' which is an otherwise unremarkable so-called ground object.


UFO stage

There's a fair bit of near-identical code in the object handlers, so today was more cut and paste and creating tables rather than implementing new behaviours.

Fireball stage

I've added a few build options to the C code, such as the ability to jump straight to the demo in attract mode and also select the starting stage in the demo. No doubt I'll also add options such as infinite fuel, player invincibility and/or infinite lives to facilitate play testing.

The base at the end the final stage

This really has been a staightforward transcode and now, roughly 50% through the code, I don't see any surprises to come. The code structure accomodates a C translation very nicely indeed.

In fact I took another quick look at Scott's Galaxian disassembly today and Scramble is undoubtedly derived from the Galaxian code base, despite the fact that Galaxian was released in 1979 by Namco and Scramble in 1981 by Konami. Galaxian would also be another straightforward transcode, and I'm tempted to work on it sooner rather than later whilst the project is fresh in my mind.

Next up is animating the player and fuel gauge, scores, mission flags etc. Since the player is inevitably destroyed by a rocket early in the demo, I'll have to also implement at least some of the explosion routines sooner rather than later.

I'm starting to consider which platform(s) I'll target for this transcode. I think Neo Geo will (still) be my preferred target, even if in rotated (vertical) mode initially. I'm trying to work out how difficult it will be to convert to horizontal - likely a lot easier than Space Invaders has proved to be - but I probably won't really know until I try.


Friday, 23 April 2021

Rocket to me, baby!

Some eye candy today. I've now got the rockets launching and following their pre-described path. Every 64 interrupts the code scans the ground-based objects to see if there are any rockets likely to hit the player (within a hard-coded window towards the left side of the screen) and if so, launches the first one it finds.

There are a maximum of 4 in-flight objects at any one time, and that includes rockets, ufos and even fireballs. Yes, hard to believe that there are only ever 4 fireballs on the screen in stage 3, and that they cause so much trouble!

Rockets launching

Each so-called 'in-flight' object has a table that describes their flight path, which is used to apply a delta to its position every interrupt. Not surprisingly, the path table for the rocket consists of a single entry that moves it up the screen.

Rendering the ceiling and the floor

It's interesting that you don't notice the imperfections in the game until you're debugging a transcode. The rocket sprites actually overwrite the progress bar before disappearing - confirmed on MAME.

You tend not to notice the gaudy palette when you're playing...

Next up is to add the routines to handle ufos and fireballs, and also to render the base (a ground-based object). Aside from the fuel gauge, which is currently not updated, that'll be about all I can do before adding the player ship and handling collision detection & explosion to round out the demo.

All that will leave handling of player controls, bullets and bombs, things exploding and game mechanics suchs as coin-up, scoring, high score updating etc. If I had to take a guess, I think I'm approaching the halfway point in the transcode. It's hard to estimate at this stage because the ASM-to-C code line ratio varies considerably with the code itself.