Saturday, March 31, 2012

Mame graphics bug? Update: Solved!

Now is the following a bug in the original game, or MAME's video emulation?

In the below screenshot you can see a large shadow bottom left. What is it? Where has it come from? Who knows! 

Correct behaviour (car x position 0x1E3)

Shadow error bottom left (car x position 0x1E2)

  • You can reproduce this by manually setting the car x position to 0x1E2 in the mame debugger (offset 0x260050 in memory). 
  • Drive forward from the start line, and you'll see this shadow flicker on and off.
  • Setting the car position to 0x1E1 or 0x1E3 sees the shadow disappear as below.
Can someone try reproducing this on hardware? You probably want to give it a go on MAME first to get the hang of where to drive without using the debugger!

I suspect this is an issue with MAME's video emulation code, which I've used as a basis for my port, but would be nice to get verification.

Incidentally, I can't reproduce this issue on the Sega Saturn port. (Interestingly, the Saturn port also fixes some of the other bugs I found that can be reproduced on hardware). 

Thanks to Magic Knight for reproducing this on hardware. Surprisingly, it's a bug in the original game code. It only took 5 minutes to find and fix in my C++ translation. Here's the offending code:

// Hide Sprite if off screen
if (sprite_y2 < 256 || sprite_y > 479 ||
    sprite_x + width < 192 || sprite_x > 512)
    hide_hwsprite(input, output);

The fix is to change the highlighted > symbol to >=. Easy! I'm going to wait before patching the original game, just in case this has caused any side effects. 

The bug is caused by the shadow on the right hand side, wrapping to the left as it goes off-screen. 

Wednesday, March 21, 2012

Vroom Vroom

Some good news - the main Ferrari is implemented. Controls are also complete, which means you can drive through all the levels of the game, albeit without collisions or crash sequences yet. The handling feels right though. Here are some screenshots:


The code, as usual, is rather comical. The original assembler manages to combine sound effect triggering logic, score updates and logic to trigger tyre smoke when turning into sharp bends into one almighty routine. I guess coding practices have come on somewhat since 1986. It's kind of funny to be the first person to delve into this code in over 25 years. 

I continue to find bugs in the original codebase, which I'm optionally fixing in my conversion. There will probably be a menu option to toggle my fixes. The latest can be reproduced as follows:
  • Drive into the level a bit.
  • Come to a standstill.
  • Turn the wheel leftmost, then let it centre itself
  • Accelerate and notice the car veers off to the left, even though the wheel is now centered
I can patch this bug on the anniversary edition the next time I do a release, if there's demand. I suspect no-one ever noticed it though. Can it be reproduced easily on hardware?

Update: Yes, it's been reproduced on hardware. Interestingly, it can't be reproduced on the Sega Saturn port.

Saturday, March 10, 2012

Splitting Roads

At last, the core level engine that handles rendering of levels can be deemed complete:
  • Every stage renders correctly and the corresponding level object routines are complete.
  • The code to handle the road split is complete.
  • The code to transition tilemaps between levels is complete.
  • The code to fade the road and sky palettes is complete.
  • You can move through each level and seamlessly load the next one.
Being OutRun, there was an unbelievably large amount of code to handle the level transitions. For example, the road split works via a giant 15-way switch statement that looks at your position and sends commands to the sub CPU to alter the road. 

So now it's onto gameplay. I've been coding the routines to render and control the Ferrari. This higher level code is far easier to work with than the core level engine code. Debugging an error in this area of code now thankfully  involves a few minutes investigation, as opposed to the days some of the core rendering bugs took.  

The code is atrociously messy in places. For example, the logic to handle smoke under the Ferrari's tyres seems to have been inserted pretty much everywhere: in the road splitting code, gear changing code, level object rendering code etc. There is nothing modular about this game! 

To compensate for this, I allow my ported C++ classes to all access each other. They still have private members of course, but there's a global public reference to the class itself. The code could potentially be refactored at a later stage, but for now the focus is getting it ported and working.