11 March 2016 - Forum Rules

Main Menu

Super Hang-On (Genesis) Game Timer - inaccurate?

Started by TheArbiter, April 26, 2019, 07:52:55 PM

Previous topic - Next topic


Hi! Hoping someone can help me out here.

I've been speedrunning Super Hang-On (Genesis) and one of my recent runs finished with a lower time than a fellow runner, but the checkpoints time was also lower which made no sense. Researching into this I think I found a problem in how the game calculates in-game times for sectors, but I need to be sure since this could have implications for our community.

At $0558 in RAM time counts up in hex, and when you reach a checkpoint it temporarily zeroes, the time is shown for that sector and kept track of for overall time. Then the weird bit is that ones and tens seem to carried over.

For example: the value gets to 3466, zeroes, a time of 34"70 is shown. Then rather than counting up from 0000, it starts from 0073.

That would appear to indicate that subseconds are carried over between sectors, which would be subject to manipulation. I am not quite sure however since freezing $0558 did nothing to change the sector time: it was only when I froze $0556 that this was achieved.

Can anyone help clarify this?


"and when you reach a checkpoint it temporarily zeroes"
Are you sure it is the game timer and not just the timer used for display purposes*? Especially if "I am not quite sure however since freezing $0558 did nothing to change the sector time" is the case and changing another nearby location did more.

*I have not played with the most timer code down to levels like this. However we see such things often enough with anti cheat/cheat prevention type methods.

As far as the holdovers of the sub second parts. Timers then were mostly a bit of fun. As such it could be an oversight, or it could be an optimisation (it might shave a few cycles off which could have been necessary).

I am not entirely sure what you can do with all this for the purposes of speed running, at least under the various rule sets I have seen over the years. Probably be easier to switch an external timer at this point, or maybe borrow a TAS emulator and have their Lua scripts take care of things.


I am confident that it is the game timer yeah - the checkpoint times sum to the total on the score screen at the end. To be sure, I compared a sector split from two runs. The runs showed 'the same time' but when I adjusted for subseconds and played them back in sync, one was faster than the other as indicated. Similar things happened when I used subsecond adjustment on a pair of splits where one player was supposed to be faster but after adjustment and sync video I found the reverse. $0556 only ever oscillates from 1E00 through 1E1D and back around again.

My thought (saying this without having heard from our mod yet, so take with a pinch of salt) was that a patch could be made to eliminate the erroneous behaviour and be sure the timer was properly reset at the end of each sector, which would avoid a player having to use a calc to work out their time. The other option that seemed obvious would be to manually remove the subseconds that were not meant to be there but as mentioned that isn't as transparent as simply repairing the timer - I know someone on the forum has hacked SHO graphically before.

EDIT: as each sector is completed, the time is written to $040C onwards for each sector, and these are summed at the end of the race and shown in $04EC and $04EE, all of that in hex. Poking those values changes the time shown at the end.


Hey TheArbiter, good to see a speedrunner on here, I'm sure they exist but I don't think in all my years dipping in and out of the forums that I've ever saw a post by one.

Can I just check, what rom is it your working on? My copy is 'Super Hang-On (JUE) (REV 01) [!].bin' so if I do find anything it'll be for that.


Hi Ryan, yeah I'm one of those people who wants to know the gubbins inside but cannot understand code, so thank fuck for emulators and ram watches or my speedruns would be so basic  :laugh: I found the issue with both Rev 01 and Rev 00 - the only differences between them are things like frame rate and bike handling. I've also got visual evidence that the fault is present on SHO Arcade MAME. I found a simple way to prove it, I started a race in Asia and on the first frame score had ticked to 400 I paused, and set the following values fixed in memory:
-I froze the bytes handling AI collision, $065A and $C7C0, so no collision would affect position or speed
-I set $055A at "500" and $064A at "250" which set speed to 290km.
-I set $0614 to freeze at 0 guaranteeing middle track position throughout to ensure the sectors were the same length.

In S1, I finished with a time of 35"80, and did not change speed for S2. The time for S2 was therefore performed with a constant speed of 290km/h, and was timed at 34"80.

I reset the game, and set 267km/h for S1 - 267km/h. Before the checkpoint for S2 I changed speed back to 290km/h for S2. The time for S1 was 38"56, S2 showed up as 34"53.

As a speedrunner I don't know what level of work would go into making a hack patch of the game. What would be required, is either
-a patch that ensures the timer counts from 00"00 with each new sector, or
-a patch that edits the sector times stored in area $040C onwards to their correct times so that the final IGT shown is correct. To my understanding both of those would result in the same correction. If it is a lot of work however we can use a pencil and paper to do manual adjustments, indeed it didn't take me long to do that for our current leaderboards.


Well, personally it is my belief that as a speedrunner you should be playing the game in the state it is presented, defects and all. If there is an issue with the timer then it is your prerogative to investigate that issue and figure out how to manipulate it in game to your advantage, not to change the code to adjust it to work how you think it should / wish it did.  ;)

That said of course, I'm not going to dictate how you run your game and I'm much more interested in looking at the code than I am debating the semantics of what speed running is all about!

With that in mind, I looked into the timers and I'm afraid I'm getting very different results than you.

For me, offset $040C doesn't contain the timer, it just contains 00s. I see the timers as being stored as follows (each is 4 bytes long):

SPLIT_TIMER             EQU $00FFC82E
TOTAL_TIMER             EQU $00FFC832
RIVAL_TIMER             EQU $00FFC860

These are stored exactly as seen in game, so a value of 00 00 05 86 would display as 0'05"86, here is a screenshot example:

I've disassembled the game and uploaded the source code here: so that it is easier to work out how it all hangs together.

Out of interest, which emulator are you currently using?


Ahh crap I'm sorry! It completely slipped my mind to be clear. There is an Arcade Mode and an Original Mode in the game. We use Arcade Mode for speedrunning, no wonder you are getting such different results because what you mention and the screenshots you have are from Original. I'm using Bizhawk when I do my research. I hope the omission hasn't rendered the obviously sizeable work you've just done invalid! Let me clarify the results I have based on Arcade Mode.

$0554 "TIME", the timer that counts down top-middle of the screen as the time limit to reach next checkpoint
$0556 seems to be tied to Genesis clock speed
$0558 Sector times - after each checkpoint, jumps from 0000 back to where subseconds had left off
$055A Speed
$064A Speed
$C70C Turbo Speed
$0614 X-position relative to track
$065A and $0C70, handle collision detection/behaviour with AI bikes
$040C onwards, stores sector times and totals them for IGT at end of races
These values are also stored in $0484 onwards which at a guess might be the 'best laptime' data
$04EC Minutes of final IGT
$04EE Seconds and subseconds of final IGT


Quote from: TheArbiter on May 01, 2019, 06:57:45 PM
...the obviously sizeable work you've just done...
Not as sizable as the work I'm going to have to put in to get decent enough to reach the first split point on Arcade before the timer runs out haha, I'm terrible at this game!

Nothing invalidated, will focus on Arcade mode when I next look into it. Keep sharing the values you find and if you want to search the source code for them add 00FF in front (so 00FF0554 for the timer) or sometimes FFFF (so FFFF0554) and you should be able to find most of the code that has an impact on them (assuming it does so directly and not through a pointer) :thumbsup:

EDIT - Been in for another look and can confirm that the addresses you have shared are indeed correct and I can see them changing when in Arcade mode. :thumbsup: I'll look further into it and see if I can figure out what's happening to the counters to cause the issue you are seeing.