Wednesday, April 23, 2014

3DS OutRun

M2's version of OutRun for the Nintendo 3DS is out in Japan. M2 have done a fantastic job with the previous SEGA ports, so it's exciting that OutRun has finally made it. Playing these titles in 3D for the first time is an awesome experience. This is also the first new port of the original OutRun for around ten years.



Whilst I haven't tried the 3DS version yet, I've checked out the videos and information online. There's a good interview with M2 here in Japanese.



There are plenty of solid features: 3D graphics, 60 FPS gameplay, widescreen mode, optional car colours, car handling settings and the usual difficulty and time DIP switch options from the arcade machine.

In terms of bugs, interestingly, M2 opted to fix the timing issues that we discussed in a previous post. However, the arcade mode uses the original timing. It's a confusing way of doing things I think as it creates two separate OutRun timing systems. The sprite scaling bug is fixed and the level object issue with the broken Gateway arches also appear fixed.

So, you're probably thinking - is this the best best version of OutRun ever? Unfortunately, there are a few drawbacks if you're looking for a truly faithful experience. The biggest gripe is the Ferrari substitution, an inevitability due to licensing issues.



Whilst the car is purely cosmetic, it's also THE memorable graphic from the original game. It would be disappointing to replace Sonic the Hedgehog with a blue badger for example, even if the gameplay was identical.

Other graphics that have been changed include the Porsche graphic, which has had the spoiler removed.


The Marlboro lookalike sign on the start banner has been altered further to differentiate it from the cigarette brand. I spotted a sign that had been edited to contain an M2 logo also. 

There appears to be a sprite clipping bug on Stage 2 with the large stone graphics. It's possible this is an optimization to help the game run faster on the 3DS, but the large stones are disabled as they get closer to the camera. It's also possible M2 forgot to update a hard-coded value in the drawing routine for this object for widescreen displays. 


The shadows also seem to be too dark, so I'm not sure what's happened there. Maybe a palette optimization with the translucency for speed purposes on the 3DS? The Saturn conversion got this right, so I'm guessing it's not an oversight.  



Regarding the extras to change the car handling, I have mixed views on their merits and will wait to see how they play. Maybe being able to bump into traffic with no ill effects, drive off-road at full speed, grip corners more tightly and drive at a higher speed will be awesome and add a new dimension to the game. Maybe these are just cheap and easy features for M2 to implement! ;) Either way, they are pretty easy additions to CannonBall if they prove to be popular and there is a genuine demand for them.

In terms of a commercial OutRun release, this is probably as good as it's ever going to get so please buy a copy when it's released in your territory and show M2 and SEGA some support.

I'll keep this post updated as I find out more information!

Monday, April 21, 2014

Time Keeping

I've been chatting to Ade recently about the timing bugs present in OutRun. We initially discussed a timing bug that another blog reader, James Pearce submitted a fix for previously. Ade writes:

I believe the lap timing code in Out Run to be incorrect and would like your opinion on it. The timers are incremented every vertical blank so that should mean that seconds should increase by 1 every 60 vertical blanks.  I've looked at the original 68000 code and also your Cannonball source and it would appear that there's a bug in the code that handles the overflow from hundredths of seconds into full seconds.

I don't need to tell you that the 68000 code that increments the timers is at 0x007f4c in main cpu address space.  Specifically the bit of code that handles the overflow of hundredths to seconds is :-

007f58: cmpi.b   #$40, ($2,A1)       ; compare hundreds with 64 (should this be 60??)
007f5e: blt   $7f90                  ; branch if less than else reset hundredths and increment full seconds

Surely if the increment timers routine is called every vertical blank then it should be checking if hundredths are less than 60 and NOT less than 64?

I confirmed that this is indeed a bug in the Sega code. Ade looked into this further: 

I've been looking more and more into the timing issues and have come to the conclusion that Out Run timing is in quite a bad way and littered with bugs!

After doing the $40 to $3c alteration at $7f5b the timer still wasn't right, if I started a game with the dips set to normal (i.e. start time of 75 seconds on stage 1) the lap timer showed 1:18:50 when time ran out.  This was in comparison with 1:13:62 without the $40/$3c fix.

So I looked deeper into it and found another bug, this time in decrement_timers (0xb736).  The 68k here is :

subq.w #1, $60864.l            ; subtract 1 from the frame_counter
bge       $b760                ; branch if greater than or equal to zero

The Cannonball source is :-

if (--ostats.frame_counter >= 0)
    return false;

This is basically saying that the routine should still return false even if the frame_counter has reached zero, this is incorrect.  This means that the next time this routine is called the frame_counter (which is already at zero) will have another 1 subtracted from it, leaving a value of $ffff at $60864.w and it will have taken 31 iterations of this routine to reduce the time_counter by 1 whereby it should be 30 iterations.  The bge instruction should be a bgt instruction.  The Cannonball source should be '> 0' NOT '>= 0'.  By fixing this ($6c to $6e @ $b73c) I was getting closer to perfection!  Now when I started a game with 75 seconds on the timer the lap timer showed exactly 1:16:00 when time ran out.  The timing was now exactly 1 second out from where it should be.

The next bug I found was also in decrement_timers.  This time at the very end of the routine.  The Cannonball source is :-

return (ostats.time_counter < 0);

This should be <= 0 as, in its current guise, it will still count a whole second beyond the expiration of the timer before it returns a false value.  The 68k code uses the bcs (branch if carry set) instruction to test if the sbcd instruction has caused a carry by subtracting 1 from a value of 0.  To fix it in 68k requires a little more work but can be achieved by the fact that the sbcd instruction clears the Z flag if the result of the subtract operation is non-zero, otherwise it leaves it unchanged.  If the Z flag is set immediately before the sbcd instruction then it can be tested afterwards and if it's still set then we know that the result of the subtract was zero and can return a true value to indicate this.

I came up with this fix :-

00B74A: moveq #1, D1           ; replace moveq #0, D1 and addq.w #1, D1 with this single instruction
00B74C: move.w $60860.l, D0    ; move 16-bits from $60860 into D0 (make double sure that the sbcd instruction works correctly)
00B752: moveq #0, D5           ; trash D5 to set the Z flag in the CCR (D5 is unused so this is OK)
00B754: sbcd D1, D0            ; subtract D1 from D0 and set Z flag accordingly
00B756: beq $b764              ; branch if Z flag is still set after the sbcd instruction (counter has reached zero)

The instruction at $b74c (move.w $60860.l, D0) probably isn't needed and I could probably have got away with using the original instruction (move.b $60861.l, D0) as the sbcd instruction is byte-sized, not word-sized, but I erred on the side of caution, just to be double sure.

The above works well and I finally have a situation whereby I start a game with 75 seconds on the timer and the lap timer says 1:15:00 when time runs out!

There is a slight drawback though....  When the timer expires the game engine state changes from $c (GS_INGAME) to $f (GS_INIT_GAMEOVER).  This has the side effect of not updating the countdown timer at the top left of the screen (via the HUD display routine which checks the game engine state) and so it stays on 1 instead of being updated to 0.  So I need to alter the exit condition of the decrement_timers routine to set $60860.w to be 0 and then call draw_timer1 ($8216) before the game engine state is changed to $f, to force the game engine to update the HUD timer at the top left of the screen to zero.  I haven't done this yet, that's the next task!

I know that all your resource is currently tied up in Cannonboard but I was wondering whether you'd ever consider including fixes to the timing code in a future update to the enhanced roms.  I'm obviously intending on fixing up my own roms so that the total of all 5 laps exactly equals the overall game time when I cross the finish line, which will also agree to my stopwatch!

But I'm wondering how many other people out there are as bothered about it as I am?  It's a tough one to call as, like you say, the timing is so fundamental to Out Run and it's been wrong ever since day one so why bother to fix it now when people have got used to how it is.  It's a shame there's no more unused dip switches available where you could give people the option to toggle it fixed or original.

Now, we could fix these bugs in CannonBall. However, my original thinking was that having two timing systems would be confusing. I assumed players would want to compare times with the original machine and for a time to be consistent (even if it does not reflect the actual time you took to race the course!)

The only bug I have fixed relating to timing was a display bug with the EXTEND TIME overlay. What do you all think? 

Wednesday, April 16, 2014

CannonBoard Motion Control Part 2

The CannonBoard interface is progressing really nicely. Colin sent me this video earlier of the full moving cabinet working in conjunction with CannonBall.

You can see the motor calibration code is ported which moves the cabinet left and right at startup before finally centering. The in-game motor code, which I'd originally ported for force-feedback PC based steering wheels, can now be used as originally intended - to drive the cabinet's motor!



The dream is slowly becoming a reality and it's great to see the level of care and attention Colin has been pouring in to get the hardware just right. He is continuing to work on the audio interface next. 

Wednesday, April 09, 2014

CannonBoard Motion Control

In between changing nappies, I've had a small amount of time to work on the software side of CannonBoard. We're starting to get full motion control working with the sitdown cabinet.

The below video shows Colin demonstrating his OutRun cabinet connected to the Cannonboard interface. Currently the Arduino is running a ported version of the motor calibration code. This shows the interface is working and we'll be able to control the motor hardware from a PC running CannonBall.


In addition to this, we've verified that the previous work on the controls works via the original cabinet. It's a bit tricky to demonstrate though as the monitor output is to the PC currently.


My next steps are to finish the in-game motion control code and ensure the cabinet is moving correctly with the interface. Then controls and movement will be proven.

Colin is working on a version of the interface that removes the Arduino entirely. He is also working on the cabinet audio hardware interface. 

Saturday, March 15, 2014

CannonBoard First Steps

As a reminder CannonBoard is a project to enable OutRun machines to be cleanly swapped to a PC running CannonBall. A modern PC connects to an Arduino which in turn is connected to the CannonBoard hardware. The OutRun controls then plug directly into the CannonBoard hardware.

Colin posted me a prototype CannonBoard PCB last week. Click the images for a larger version.


Here's a shot from the back so you can see how it connects to the Arduino.


Here it is connected up to my chaotic test harness with the original OutRun connectors:


To make testing simpler, I'm using my hacked together OutRun controls. I normally attach these to an original OutRun PCB, but they're perfect for testing this setup.


Some LOL wiring here. It all works though. Note the stylish shoebox. 

CannonBall is currently working with the controls, which means there's no reason this shouldn't work with the original controls in a proper cabinet now. I've sent a test version back to Colin to play around with. In the meantime, I'm just pleased to have my name on a PCB.


I have another project in the pipeline - Project Baby. It's due to start any day now and will likely consume a fair chunk of time ;) Aside from that, I'll be working on the CannonBoard interface mostly during my moments of spare time. I'm looking forward to getting the motor outputs hooked up among other things.

Monday, January 27, 2014

CannonBall 0.22a - Continuous Mode

This release features a number of new features, important fixes and other changes.

Features:
  • Continuous Mode
    Play all 15 stages sequentially. This mode features its own high-score table.
  • Ability to toggle the fixed audio rom in the settings menu. It should be named opr-10188.71f and be placed in the roms directory. The fixed rom can be generated using bspatch and the relevant patch file from the enhanced edition pack
  • Fixed split axis support. XBox 360 pads should now work.
    The FAQ has some basic configuration advice. Thanks to baritonomarchetto for donating the pad. Rumble will also be supported in the future, but it means I'll have to upgrade the project to SDL 2. So it's a little more work than might be expected.

Core Engine Fixes:

  • Fixed a vehicle sprite bug that affected the angle of certain traffic sprites. Info here
  • Fixed two audio bugs that caused traffic noise to stutter under some circumstances, or not play correctly.
  • Corrected the pitch of PCM samples, they were played too quickly before. 

Other Minor Enhancements:
  • Ability to use controllers on other ports. This is configured in config.xml.
  • Support for arcade cabinets with a separate switch for high and low gear. This can be enabled in the gear options. 
  • The High Score table can display longer times to support Continuous Mode.
  • Added two handy game modes to toggle between 'original arcade' and 'enhanced' presets.

Quite a lot of code ended up changing to support Continuous Mode, so let me know if I broke anything in the process. Feel free to discuss the release on the forum

Download it here.

Update: Fixed the reported crash in continuous mode. This was a nasty bug that only materialized on a single level, when the code was compiled in release mode. 

Tuesday, January 14, 2014

CannonBoard Hardware Update

Colin Davies has been making solid progress on the CannonBoard project. This is the plug and play hardware interface that allows you to cleanly swap a modern PC into an original OutRun cabinet and run CannonBall.

"The audio is now hooked up to the original connectors. There is also a power supply input and dummy experimental load resistors to keep the Outrun PSU happy as it requires a minimum load (about 1 amp / 5 watts). This is important to balance the 5v for reliability and for the rest of the electronics on board to function. It will be optional whether the board runs from the Outrun 5v or the Arduino 5v."

The analog inputs still need to be hooked up; you can see the I/O layout below.



Soon we'll be at a point where we can start running some tests with CannonBall.