Sonic 2 (Simon Wai Prototype) Level Select in Sonic 1
From Sonic Retro
(Original guide by Kram1024) (aka Kramlat)
(Guide updated by JGMR)
You probably wonder why Sonic 2 Beta has that level select that looks almost like the Sonic 1 level select, and how Sonic 2 Nick Arcade prototype has one that is the Sonic 1 level select. Well, that is what we are going to make the one in Sonic 1 behave like.
Contents
Overview
First, let's look at an overview of what our level select code looks like normally in Sonic 1 (this is from the Hivebrain disassembly):
; ---------------------------------------------------------------------------
; Level Select
; ---------------------------------------------------------------------------
LevelSelect:
move.b #4,($FFFFF62A).w
bsr.w DelayProgram
bsr.w LevSelControls
bsr.w RunPLC_RAM
tst.l ($FFFFF680).w
bne.s LevelSelect
andi.b #$F0,($FFFFF605).w ; is A, B, C, or Start pressed?
beq.s LevelSelect ; if not, branch
move.w ($FFFFFF82).w,d0
cmpi.w #$14,d0 ; have you selected item $14 (sound test)?
bne.s LevSel_Level_SS ; if not, go to Level/SS subroutine
move.w ($FFFFFF84).w,d0
addi.w #$80,d0
tst.b ($FFFFFFE3).w ; is Japanese Credits cheat on?
beq.s LevSel_NoCheat ; if not, branch
cmpi.w #$9F,d0 ; is sound $9F being played?
beq.s LevSel_Ending ; if yes, branch
cmpi.w #$9E,d0 ; is sound $9E being played?
beq.s LevSel_Credits ; if yes, branch
LevSel_NoCheat:
cmpi.w #$94,d0 ; is sound $80-$94 being played?
bcs.s LevSel_PlaySnd ; if yes, branch
cmpi.w #$A0,d0 ; is sound $95-$A0 being played?
bcs.s LevelSelect ; if yes, branch
LevSel_PlaySnd:
bsr.w PlaySound_Special
bra.s LevelSelect
; ===========================================================================
LevSel_Ending: ; XREF: LevelSelect
move.b #$18,($FFFFF600).w ; set screen mode to $18 (Ending)
move.w #$600,($FFFFFE10).w ; set level to 0600 (Ending)
rts
; ===========================================================================
LevSel_Credits: ; XREF: LevelSelect
move.b #$1C,($FFFFF600).w ; set screen mode to $1C (Credits)
move.b #$91,d0
bsr.w PlaySound_Special ; play credits music
move.w #0,($FFFFFFF4).w
rts
; ===========================================================================
LevSel_Level_SS: ; XREF: LevelSelect
add.w d0,d0
move.w LSelectPointers(pc,d0.w),d0 ; load level number
bmi.w LevelSelect
cmpi.w #$700,d0 ; check if level is 0700 (Special Stage)
bne.s LevSel_Level ; if not, branch
move.b #$10,($FFFFF600).w ; set screen mode to $10 (Special Stage)
clr.w ($FFFFFE10).w ; clear level
move.b #3,($FFFFFE12).w ; set lives to 3
moveq #0,d0
move.w d0,($FFFFFE20).w ; clear rings
move.l d0,($FFFFFE22).w ; clear time
move.l d0,($FFFFFE26).w ; clear score
rts
; ===========================================================================
LevSel_Level: ; XREF: LevSel_Level_SS
andi.w #$3FFF,d0
move.w d0,($FFFFFE10).w ; set level number
PlayLevel: ; XREF: ROM:00003246�j ...
move.b #$C,($FFFFF600).w ; set screen mode to $0C (level)
move.b #3,($FFFFFE12).w ; set lives to 3
moveq #0,d0
move.w d0,($FFFFFE20).w ; clear rings
move.l d0,($FFFFFE22).w ; clear time
move.l d0,($FFFFFE26).w ; clear score
move.b d0,($FFFFFE16).w ; clear special stage number
move.b d0,($FFFFFE57).w ; clear emeralds
move.l d0,($FFFFFE58).w ; clear emeralds
move.l d0,($FFFFFE5C).w ; clear emeralds
move.b d0,($FFFFFE18).w ; clear continues
move.b #$E0,d0
bsr.w PlaySound_Special ; fade out music
rts
; ===========================================================================
; ---------------------------------------------------------------------------
; Level select - level pointers
; ---------------------------------------------------------------------------
LSelectPointers:
binclude misc\ls_point.bin
align 2
; ---------------------------------------------------------------------------
; Level select codes
; ---------------------------------------------------------------------------
LevelSelectCode_J:
binclude misc\ls_jcode.bin
align 2
LevelSelectCode_US:
binclude misc\ls_ucode.bin
align 2
; ===========================================================================
Notice anything here?
Button Fix, Part 1
A lot of stuff here we really do not need, as well as the fact that all buttons that are not the D-Pad seem to be used to play a sound or select a level. Let's fix that.
LevelSelect:
move.b #4,($FFFFF62A).w
bsr.w DelayProgram
bsr.w LevSelControls
bsr.w RunPLC_RAM
tst.l ($FFFFF680).w
bne.s LevelSelect
andi.b #$F0,($FFFFF605).w ; is A, B, C, or Start pressed?
beq.s LevelSelect ; if not, branch
move.w ($FFFFFF82).w,d0
cmpi.w #$14,d0 ; have you selected item $14 (sound test)?
bne.s LevSel_Level_SS ; if not, go to Level/SS subroutine
move.w ($FFFFFF84).w,d0
addi.w #$80,d0
tst.b ($FFFFFFE3).w ; is Japanese Credits cheat on?
beq.s LevSel_NoCheat ; if not, branch
cmpi.w #$9F,d0 ; is sound $9F being played?
beq.s LevSel_Ending ; if yes, branch
cmpi.w #$9E,d0 ; is sound $9E being played?
beq.s LevSel_Credits ; if yes, branch
LevSel_NoCheat:
cmpi.w #$94,d0 ; is sound $80-$94 being played?
bcs.s LevSel_PlaySnd ; if yes, branch
cmpi.w #$A0,d0 ; is sound $95-$A0 being played?
bcs.s LevelSelect ; if yes, branch
LevSel_PlaySnd:
bsr.w PlaySound_Special
bra.s LevelSelect
We do not need the Japanese credits code, removed that junk. As for the levels, we want to start them with but not exclusively just , so an andi would be used there. Also, we want to exit back to the Sega screen, and why not some nice music? Only or should play something on the sound test.
The results should look like this:
LevelSelect:
move.b #4,($FFFFF62A).w
bsr.w DelayProgram
bsr.w LevSelControls
bsr.w RunPLC_RAM
tst.l ($FFFFF680).w
bne.s LevelSelect
move.w ($FFFFFF82).w,d0
cmpi.w #$14,d0 ; have you selected item $14 (sound test)?
bne.s LevSelLevCheckStart; if not, go to Level/SS subroutine
cmpi.b #$80,($FFFFF605).w ; is Start pressed?
beq.s LevSelStartPress ; if true, branch
cmpi.b #$20,($FFFFF605).w ; is B pressed?
beq.s LevSelBCPress ; if not, branch
cmpi.b #$10,($FFFFF605).w ; is C pressed?
beq.s LevSelBCPress ; if not, branch
bra.s LevelSelect
; ===========================================================================
LevSelLevCheckStart: ; XREF: LevelSelect
andi.b #$80,($FFFFF605).w ; is Start pressed?
beq.s LevelSelect ; if not, branch
bra.s LevSel_Level_SS
LevSelBCPress: ; XREF: LevelSelect
move.w ($FFFFFF84).w,d0
addi.w #$80,d0
cmpi.w #$94,d0 ; is sound $80-$94 being played?
bcs.s LevSel_PlaySnd ; if yes, branch
cmpi.w #$A0,d0 ; is sound $95-$A0 being played?
bcs.s LevelSelect ; if yes, branch
LevSel_PlaySnd:
bsr.w PlaySound_Special
bra.s LevelSelect
LevSelStartPress: ; XREF: LevelSelect
move.b #$00,$FFFFF600
jmp MainGameLoop ;go to sega screen
Level Select Music Fix
That fixes the level select so that it runs levels in a Sonic 2 manner, but it doesn't fix the music. Let's do that now.
Find:
Title_ClrVram:
move.l d0,(a6)
dbf d1,Title_ClrVram ; fill VRAM with 0
bsr.w LevSelTextLoad
and add under dbf d1,Title_ClrVram ; fill VRAM with 0, these lines:
move.b #$81,d0
jsr PlaySound
replace #$81 with your choice of song.
the result should look like:
Title_ClrVram:
move.l d0,(a6)
dbf d1,Title_ClrVram ; fill VRAM with 0
move.b #$81,d0
jsr PlaySound
bsr.w LevSelTextLoad
Green Hill Zone music at the level select, how lovely. On the other hand, if you plan on using my Sonic 2 Sound Driver port, try using music number $91 and PlayMusic as opposed to PlaySound.
Button Fix, Part 2
As you already know, is not yet fixed, time to fix that button:
First, we will have to edit the "LevSel_SndTest" routine. $C (left and right) will not work for detecting . We will need $4C (A/Left/Right) instead, so look in our function for:
LevSel_SndTest: ; XREF: LevSelControls
cmpi.w #$14,($FFFFFF82).w ; is item $14 selected?
bne.s LevSel_NoMove ; if not, branch
move.b ($FFFFF605).w,d1
andi.b #$C,d1 ; is left/right pressed?
and change it to read out:
LevSel_SndTest: ; XREF: LevSelControls
cmpi.w #$14,($FFFFFF82).w ; is item $14 selected?
bne.s LevSel_NoMove ; if not, branch
move.b ($FFFFF605).w,d1
andi.b #$4C,d1 ; is left/right/A pressed?
instead.
Now we can start working on adding the routine to handle and increase the 16's ($10) part of the sound test:
locate:
beq.s LevSel_NoMove ; if not, branch
move.w ($FFFFFF84).w,d0
and add below:
btst #6,d1 ; is A pressed?
bne.s LevSel_A ; if not, branch
Now locate:
bcc.s LevSel_Right
moveq #$4F,d0 ; if sound test moves below 0, set to $4F
and add this routine under it to add support to the level select:
LevSel_A:
btst #6,d1 ; is A button pressed?
beq.s LevSel_Right ; if not, branch
add.w #16,d0 ; add $10 to sound test
Optional fix
To make the counter reset after the current ID slot in the sound test, add this underneath the code for 'LevSel_A:':
cmpi.w #$50,d0
bcs.s LevSel_Refresh2
moveq #0,d0 ; if sound test moves above $4F, set to 0
So the code looks like this:
LevSel_A:
btst #6,d1 ; is A button pressed?
beq.s LevSel_Right ; if not, branch
add.w #16,d0 ; add $10 to sound test
cmpi.w #$50,d0
bcs.s LevSel_Refresh2
moveq #0,d0 ; if sound test moves above $4F, set to 0
This would help prevent the game from accessing inaccessible ID slots in the sound test, which would have caused the game to crash if said sound IDs to be were played.
Expanding the sound test index
If you're adding more music slots to the sound test, you may have to adjust the sound test index in the level select. Refer to these guides here for more information.
Conclusion
Now the Sonic 1 level select will behave exactly like that of the one in Sonic 2 (Simon Wai prototype, except for night mode and split screen, those can be added manually if you get such a system working). Enjoy your alternative level select :)
|Sonic 2 (Simon Wai Prototype) Level Select in Sonic 1]]