Sunday, April 08, 2012

Traffic Code Ported

Porting Update:
The traffic code is now ported and the end result is 600 lines of C++ and what appears to be the correct behaviour.

One aspect that the 80s home conversions missed, is that OutRun's traffic is relatively smart. If you drive up slowly behind it, it will accelerate to stay out of your way. It will also attempt to change lanes where possible to avoid the player and other AI traffic. Each traffic object has a series of flags to denote its proximity to other road objects.


The traffic logic works by grabbing the traffic objects from the ordered sprite display list. This has the advantage of meaning that the traffic is already z ordered correctly as an optimisation for proximity checks. The display list references the original objects and the logic code then goes to work on these. 

Next I'll be working on the ferrari crash routines. You may remember that I posted about them here a couple of years ago. Yes, it's been that long!

More bugs?
I know this attention to detail is becoming increasingly pedantic but today's random bug in the original game relates to the positioning of the passengers in the car. Come to a complete stop. Gently accelerate and you'll notice both man and woman shift to the right by a pixel. Slow down and they will shift left again. 

I've found the line in the original code that's causing this, but I'm not sure if this is a bug or intentional behaviour? I'm pretty sure the programmers got a check for the horizontal flipping of the Ferrari inverted when setting the passenger offsets. What do you think?

Scoring
It's been a while since I've written something non-technical. So let's explain OutRun's scoring logic:
  • You will score when both Ferrari wheels are on road. The amount you score depends on your speed. This value will be incremented 30 times a second.

    The table of values is as follows. The player's speed is used as an index into this table:
    0, 10, 20, 30, 40, 50, 60, 80, 110, 150, 200, 260, 330, 410, 500, 600, 710, 830, 960

    To score the highest value (960) you must be travelling at 287 kph.
  • Overtaking a car: 20,000 points
  • 100,000 points per 0.1 second of bonus time on game completion

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). 

Update:
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);
    return;
}

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. 


Tuesday, January 31, 2012

Gateway's Broken Arches

Have you noticed that Gateway's arches are randomly broken in the original OutRun? At times arches don't join, sometimes they float in the air and occasionally complete pillars are missing. 

It's not very noticeable at high speed, and the precise nature of the breakage isn't consistent. Overall though, it spoils the illusion of what would otherwise be a cool level. 


For my rewrite, there's a simple solution to this problem; but not for the original game sadly. OutRun's software engine can display 76 scenery sprites at any one time, which are initialized dynamically as the level progresses. Further sprites are reserved for traffic and other essential objects. 

Each Gateway arch comprises 4 sprites (two pillars and two joining sections). So we can display 19 complete arches at any one time. Therefore, on complex stretches of road where no free slots can be allocated, some of the pillar components are simply skipped.

Thankfully, we don't have memory or speed restrictions on a modern PC and can allocate additional slots to dynamically spawn sprites. In fact, it's as easy as changing a single number. And here's a screenshot to (somewhat) prove it. 


The illusion when moving through the level is greatly improved, and when I eventually increase the frame rate beyond the original 30fps, this level will be awesome! 

Sunday, January 29, 2012

OutRun C++ Engine Tech Demo

Finally, after years of hard labour, here's a technical demo of the OutRun C++ port. The demo showcases recent work porting the core level rendering engine. The benefit of rewriting the engine, is that it will facilitate modifications and enhancements to the original game that Yu Suzuki only dreamed of.

Now, let's get arty and check out some stills from the demo. I've implemented the ability to change the horizon y coordinate, so we can experience viewpoints never seen in the original game. How about a bird's eye view of the start line?


We can also straddle left and right, so it's possible to find further interesting camera angles. Although this one reveals that our surf-boarding friend isn't actually in the water! Messing with the original engine can highlight its limitations of course. This demo allows you to scroll further left and right than the original engine, which can cause glitches. 


It's fun to be able to browse the scenery in detail: 


Here's a beach-side postcard scene for you:


And finally a view down the final straight of Coconut Beach before the road fork. Alas, the road fork code hasn't been ported yet, so this is the road to nowhere at the moment. 


The keys for the demo are:
  • Space: Toggle automatic movement through level
  • Cursor Up: Advance slowly
  • Cursor Left/Right: Move camera left/right
  • A/Z: Adjust horizon
  • Escape: Quit
Requirements:
Other Notes:
  • Having control over the rendering engine surfaces glitches and limitations present in the original code. Using unpatched roms, the sprite zoom bug mentioned in this post is evident. You can use patched roms to eliminate this. 
  • There is a bug where a random shadow pops into view dependent on the camera x coordinate. This is present in MAME as well, but is hard to reproduce when you're actually racing through the level. I need to get this verified on hardware to help track down a solution and determine whether it's a video emulation issue or a bug in the original codebase. 
Download here: outrun_tech_demo1.zip

Let me know what you think by leaving a comment below.

Monday, January 16, 2012

OutRun Sprite Zoom Bug

OutRun uses a lookup table to set the horizontal and vertical zoom values of sprites based on their z co-ordinate.

Unfortunately, one of the vertical zoom entries in this table is incorrect. If you drive as slowly as possibly by gently tapping the accelerator, there is a single position where sprites snap to an erroneous vertical zoom value. This causes the sprite to clip incorrectly and jolt to a different offset.

You can see an example of this behaviour in the animation below. Note the third palm tree from the left suddenly snaps and zooms to an incorrect position.


Unbelievably, this applies to all sprites in the game. Although it's only noticeable when driving at low speeds. However, once spotted it's hard to ignore.

I've updated OutRun: Enhanced Edition with a patch for the bug.

In other news, expect an early tech demo of my C++ port very shortly. It was in coding the port that I spotted this bug.

Update: The Sega Saturn port does not suffer from this issue. Looking through the Saturn binary, I can't find the lookup table used by the arcade version, so this area was probably rewritten for hardware purposes.

The Xbox port (part of OutRun 2) does have the bug.