As I mentioned in my intro post, I've been noodling around with a disasm of Sonic 2 for a few weeks, learning how all the parts to go together. While trying to think of some cool things to do with the game, I stumbled across this post by XenoSonic (from July 2005) over on Retro which explains how to edit the binary to make the timer start at 9:59 and count down, instead of starting at 0:00 and counting up. I looked around, but didn't see any ASM tutorials that did a similar thing. Seeing this as a great opportunity to practice assembly editing, I worked to convert that tutorial from a hex editing one, and I believe I've succeeded, and I'd like to share the results so that others who may want to make this change can do so. This was done using the Xenowhirl disassembly. I've mirrored the format of XenoSonic's post for those of you who want to follow along with that one. Step 1: Setting things up This is the part where we make the timer flash when time is running out, and where we set the point in time at which the "TIME OVER" occurs. First, let's take care of that timer flashing. In each of loc_40804:, loc_40820:, loc_4085A:, and loc_40876:, you'll see the following line: cmpi.b #9,(Timer_minute).w In all four cases, change that line to: cmpi.b #0,(Timer_minute).w Next, we need to change the TIME OVER, which typically occurs the instant before the clock ticks over to ten minutes. Now, we want to make it so it happens when the clock hits zero. In Hud_ChkTime:, you'll see the line: cmpi.l #$93B3B,(a1)+ ; is the time 9:59? and change it to: cmpi.l #$0,(a1)+ ; is the time 0:00? Step 2: Starting the timer at 9:59 In this step, we're going to initialize the timer to start at 9:59, instead of 0:00, and also set the timer to set correctly after restarting from death but having previously hit a starpost. In the label Level_FromCheckpoint:, we need to alter some of the middle of that code. Take these lines: move.b #1,(Update_HUD_score).w move.b #1,(Update_HUD_rings).w move.b #1,(Update_HUD_timer).w move.b #1,(Update_HUD_timer_2P).w jsr (loc_17AA4).l jsr (RingsManager).l jsr (SpecialCNZBumpers).l jsr (RunObjects).l jsr (BuildSprites).l bsr.w JmpTo_loc_3FCC4 bsr.w SetLevelEndType and make some changes so that part now looks like this: move.b #1,(Update_HUD_score).w move.b #1,(Update_HUD_rings).w move.b #1,(Update_HUD_timer).w move.b #1,(Update_HUD_timer_2P).w jmp (Reverse_Timer).l ; jump to code newly setting timer to 9:59 ; notice the loc_17AA4 label is now gone from this section loc_423A: jsr (RingsManager).l jsr (SpecialCNZBumpers).l jsr (RunObjects).l jsr (BuildSprites).l bsr.w JmpTo_loc_3FCC4 bsr.w SetLevelEndType Now we need to add the Reverse_Timer subroutine. After byte_1795E:, there is a nop command and then a few blank lines before the comments to subroutine loc_17AA4. In that blank area, place the following subroutines. Reverse_Timer: jsr (loc_17AA4).l ; loc_17AA4 subroutine call moved here cmpi.w #$0, (Timer).w bne CP_Return cmpi.w #$0, (Timer_second).w bne CP_Return move.l #$93C3C, (Timer).w ; set the timer to maximum possible time CP_Return: jmp (loc_423A).l ; jump back to continue checkpoint loading Step 3: The countdown Lastly, we need our timer to count down instead of up. The last few lines of the subroutine Hud_ChkTime: are bcs.s Hud_ChkLives move.b #0,(a1) addq.b #1,-(a1) cmpi.b #60,(a1) bcs.s loc_40E18 move.b #0,(a1) addq.b #1,-(a1) cmpi.b #9,(a1) bcs.s loc_40E18 move.b #9,(a1) loc_40E18: We're going to do two things at once here. First, we need to add code to make the seconds count go from "00" to "59" when appropriate, at the end of the minute. Second, we need to switch it so that things count down, instead of up. Here's how we do it: bcs.s Hud_ChkLives move.b #0,(a1) subq.b #1,-(a1) ; subtract instead of add 1 cmpi.b #60,(a1) bcs.s loc_40E18 move.b #0,(a1) subq.b #1,-(a1) ; subtract instead of add 1 cmpi.b #9,(a1) bcs.s Timer_CD ; new subroutine to make 00 come after 59 move.b #9,(a1) Timer_CD: cmpi.w #$0, (Timer_second).w ; if the current seconds value is 00 move.w #$3C3C, (Timer_second).w ; then the next one should be 59 jmp loc_40E18 ; continue (this jump might not be needed) loc_40E18: Step 4: Ironing out one final bug When you get a TIME OVER, the clock typically resets back to giving full time. This can prove particularly problematic if the death occurs after a starpost has been hit. To make it so that after a TIME OVER, the game returns to the time on the clock as of the last time a starpost was hit, delete this line in loc_14034: clr.l (Saved_Timer).w And that does it! Your game timer should now count down instead of up. I explain fixing the Time Bonus below, in a separate post. If you have any problems, questions, comments, etc., let me know.