Sonic '06-Like Character and Level Selector

Discussion in 'Discussion and Q&A Archive' started by ProjectFM, Dec 9, 2014.

Thread Status:
Not open for further replies.
  1. ProjectFM

    ProjectFM Optimistic and self-dependent Member

    Joined:
    Oct 4, 2014
    Messages:
    912
    Location:
    Orono, Maine
    I'm doing a hack of  Sonic 1 using the Hivebrain disassembly. My goal in this hack is to make a demake of Sonic '06 for the Genesis/Megadrive. This code was made to select the story to be played when a A, B, or C is pressed at the title screen. Then it would load a certain level order depending on the story and select from a list of 11 characters (Normal Sonic, Silver, Shadow, Tails, Knuckles, Blaze, Amy, Rouge, E-123 Omega, Sonic at Mach Speed, and Sonic carrying Elise). Instead of that, the game just picks Sonic's story despite another story being picked, use his level order, and and use him despite other characters needing to be there.
    I've worked several hours on this and I hope someone can help me out. Here is the code:


    Title_LoadText:
    move.w (a5)+,(a6)
    dbf d1,Title_LoadText ; load uncompressed text patterns
    move.b #0,($FFFFFE30).w ; clear lamppost counter
    move.w #0,($FFFFFE08).w ; disable debug item placement mode
    move.w #0,($FFFFFFF0).w ; disable debug mode
    move.w #0,($FFFFFFEA).w
    tst.w ($FFFFF70E).w
    bne.w Title_Silver
    move.w #0,($FFFFFE10).w ; set level to GHZ (00)
    move.b #0,($FFFFF70E).w ; set character to Sonic
    bra.w Title_Return
    Title_Silver:
    cmpi.w #1,($FFFFF70E).w
    bne.w Title_Shadow
    move.w #$400,($FFFFFE10).w ; set level to SYZ (04)
    move.b #1,($FFFFF70E).w ; set character to Silver
    bra.w Title_Return
    Title_Shadow:
    move.w #$300,($FFFFFE10).w ; set level to SLZ (03)
    move.b #2,($FFFFF70E).w ; set character to Shadow
    Title_Return:

    This code is to load each character's first level. As you can see F70E is the ram address used for stories and characters. The words are used for the stories and the bytes are used for characters. I originally had these as two separate ram addresses but I decided to combine them to decrease ram usage.


    loc_3230:
    tst.w ($FFFFF614).w
    beq.w Demo

    Title_CheckForA:
    cmpi.b #$40,($FFFFF605).w ; is button A pressed?
    bne.s Title_CheckForB ; if not, branch
    move.w #0,($FFFFF70E).w ; set the multiple character flag to $01 (indicating Metal Sonic)
    move.b #$B5,d0 ; put value of ring sound into d0
    jsr PlaySound_Special ; jump to the subroutine that plays the sound currently in d0 ($B5, at the moment)
    bra.w StartCheck

    Title_CheckForB:
    cmpi.b #$10,($FFFFF605).w ; is button B pressed?
    bne.s Title_CheckForC ; if not, branch
    move.w #1,($FFFFF70E).w ; set the multiple character flag to $01 (indicating Metal Sonic)
    move.b #$B5,d0 ; put value of ring sound into d0
    jsr PlaySound_Special ; jump to the subroutine that plays the sound currently in d0 ($B5, at the moment)
    bra.w StartCheck

    Title_CheckForC:
    cmpi.b #$20,($FFFFF605).w ; is button C pressed?
    bne.s StartCheck ; if not, branch
    move.w #2,($FFFFF70E).w ; set the multiple character flag to $01 (indicating Metal Sonic)
    move.b #$B5,d0 ; put value of ring sound into d0
    jsr PlaySound_Special ; jump to the subroutine that plays the sound currently in d0 ($B5, at the moment)
    bra.w StartCheck

    StartCheck:
    andi.b #$80,($FFFFF605).w ; check if Start is pressed
    beq.w loc_317C ; if not, branch

    This is the code used for checking if A, B, or C buttons are pressed at the title screen. This is based on the SCHG how-to on extra characters.


    Obj3A_NextLevel: ; XREF: Obj3A_Index
    move.b ($FFFFFE10).w,d0
    andi.w #7,d0
    lsl.w #3,d0
    move.b ($FFFFFE11).w,d1
    andi.w #3,d1
    add.w d1,d1
    add.w d1,d0
    tst.w ($FFFFF70E).w ; is story 0 (Sonic)?
    bne.s Silver_Story ; if not, branch
    move.w SonLevelOrder(pc,d0.w),d0 ; load level from level order array
    lea (SonicOrder).l,a2 ; load character number
    bra.s Obj3A_Continue ; continue code

    Silver_Story:
    cmpi.w #$01,($FFFFF70E).w ; is story 1 (Silver)?
    bne.s Shadow_Story ; if not, branch
    move.w SilLevelOrder(pc,d0.w),d0 ; load level from level order array
    lea (SilverOrder).l,a2 ; load character number

    Obj3A_Continue:
    move.w d0,($FFFFFE10).w ; set level number
    tst.w d0
    bne.s Obj3A_ChkSS
    move.b #$a2,($FFFFF70E).w ; set character number
    move.b #0,($FFFFF600).w ; set game mode to level (00)
    bra.s Obj3A_Display2

    This is the code used for loading the next level and character depending on the story. This uses six files: SonLevelOrder, SilLevelOrder, and ShwLevelOrder are each story's level orders and SonicOrder, SilverOrder, and ShadowOrder are each level's character and use the use the same order as their respective levelorders. Shadow_Story is located elsewhere but is similar to Silver_Story.


    LoadSonicDynPLC: ; XREF: Obj01_Control; et al
    moveq #0,d0
    move.b $1A(a0),d0 ; load frame number
    cmp.b ($FFFFF766).w,d0
    beq.s Jump_Equal
    move.b d0,($FFFFF766).w
    lea (SonicDynPLC).l,a2
    add.w d0,d0
    adda.w (a2,d0.w),a2
    moveq #0,d5
    move.b (a2)+,d5
    subq.w #1,d5
    bmi.s locret_13C96
    move.w #$F000,d4
    tst.b ($FFFFF70E).w ; is character 0 (Sonic)?
    bne.s Silver_Character ; if not, branch
    move.l #Art_Sonic,d6 ; load Sonic's art
    bra.s SPLC_ReadEntry ; continue code

    Jump_Equal:
    jmp locret_13C96

    Silver_Character:
    cmpi.b #1,($FFFFF70E).w ; is character 1 (Silver)?
    bne.s Shadow_Character ; if not, branch
    move.l #Art_Silver,d6 ; load Silver's art
    bra.s SPLC_ReadEntry ; continue code

    Shadow_Character:
    cmpi.b #2,($FFFFF70E).w ; is character 2 (Shadow)?
    bne.s Other_Character ; if not, branch
    move.l #Art_Shadow,d6 ; load Silver's art
    bra.s SPLC_ReadEntry ; continue code

    Other_Character:
    move.l #Art_Sonic,d6 ; load Sonic's art

    SPLC_ReadEntry:

    This is the code for loading each character's art. So far, the code is only for Sonic, Silver, and Shadow's art. Any other characters would just use Sonic's sprites but have none of Sonic's extra moves. I haven't made the characters load custom mappings, palettes, or DPLCs yet either.

    Thanks!
     
  2. ThomasThePencil

    ThomasThePencil resident psycho Member

    Joined:
    Jan 29, 2013
    Messages:
    910
    Location:
    the united states. where else?
    This could be improved. It's terribly inefficient.

    This heap of code:


    LoadSonicDynPLC: ; XREF: Obj01_Control; et al
    moveq #0,d0
    move.b $1A(a0),d0 ; load frame number
    cmp.b ($FFFFF766).w,d0
    beq.s Jump_Equal
    move.b d0,($FFFFF766).w
    lea (SonicDynPLC).l,a2
    add.w d0,d0
    adda.w (a2,d0.w),a2
    moveq #0,d5
    move.b (a2)+,d5
    subq.w #1,d5
    bmi.s locret_13C96
    move.w #$F000,d4
    tst.b ($FFFFF70E).w ; is character 0 (Sonic)?
    bne.s Silver_Character ; if not, branch
    move.l #Art_Sonic,d6 ; load Sonic's art
    bra.s SPLC_ReadEntry ; continue code

    Jump_Equal:
    jmp locret_13C96

    Silver_Character:
    cmpi.b #1,($FFFFF70E).w ; is character 1 (Silver)?
    bne.s Shadow_Character ; if not, branch
    move.l #Art_Silver,d6 ; load Silver's art
    bra.s SPLC_ReadEntry ; continue code

    Shadow_Character:
    cmpi.b #2,($FFFFF70E).w ; is character 2 (Shadow)?
    bne.s Other_Character ; if not, branch
    move.l #Art_Shadow,d6 ; load Silver's art
    bra.s SPLC_ReadEntry ; continue code

    Other_Character:
    move.l #Art_Sonic,d6 ; load Sonic's art

    SPLC_ReadEntry:

    Could be changed to simply this:


    LoadSonicDynPLC: ; XREF: Obj01_Control; et al
    moveq #0,d0
    move.b $1A(a0),d0 ; load frame number
    cmp.b ($FFFFF766).w,d0
    beq.w locret_13C96
    move.b d0,($FFFFF766).w
    lea (SonicDynPLC).l,a2
    add.w d0,d0
    adda.w (a2,d0.w),a2
    moveq #0,d5
    move.b (a2)+,d5
    subq.w #1,d5
    bmi.w locret_13C96
    move.w #$F000,d4
    move.b ($FFFFF70E).w,d3
    move.l Char_ArtTable(pc,d3.w),d6

    SPLC_ReadEntry:
    moveq #0,d3

    [...other DPLC code...]

    Char_ArtTable:
    dc.l Art_Sonic
    dc.l Art_Shadow
    dc.l Art_Silver
    ; Expand as necessary.

    See? Much smaller and easier to expand. The clearing of d3 is necessary; if my memory serves me right, d3 is used further down in the loading-character-DPLCs routine. I'm not sure, though.
     
    Last edited by a moderator: Dec 9, 2014
  3. ProjectFM

    ProjectFM Optimistic and self-dependent Member

    Joined:
    Oct 4, 2014
    Messages:
    912
    Location:
    Orono, Maine
    As much as I'd love to have this in my hack, it turns Sonic into a garbled-up mess.

    Edit: It only does it in GHZ Act 1.

    Edit2: Nevermind. Other acts start out fine but then become more and more messed up.
     
    Last edited by a moderator: Dec 9, 2014
  4. ThomasThePencil

    ThomasThePencil resident psycho Member

    Joined:
    Jan 29, 2013
    Messages:
    910
    Location:
    the united states. where else?
    That's...odd...try clearing d3 before loading $FFFFF70E to d3. This command does that:


    moveq #0,d3

    If that doesn't work, give me a screenshot of what happens and I might be able to pinpoint the source.
     
    Last edited by a moderator: Dec 9, 2014
  5. JoenickROS

    JoenickROS ROS (bug fixing in progress) Member

    Joined:
    Feb 5, 2012
    Messages:
    929
    See the problem here? Ill give you a hint, look at the bits. I lined it up to make it easier. There are some other things but I can't explain them well enough.


    Edit: My answer was crap.
     
    Last edited by a moderator: Dec 10, 2014
  6. ProjectFM

    ProjectFM Optimistic and self-dependent Member

    Joined:
    Oct 4, 2014
    Messages:
    912
    Location:
    Orono, Maine
    That's...odd...try clearing d3 before loading $FFFFF70E to d3. This command does that:


    moveq #0,d3

    If that doesn't work, give me a screenshot of what happens and I might be able to pinpoint the source.



    This worked. Thanks!
     
Thread Status:
Not open for further replies.