don't click here

Some changes and fixes for Sonic 2

Discussion in 'Engineering & Reverse Engineering' started by Esrael, Jun 7, 2012.

  1. redhotsonic

    redhotsonic

    Also known as RHS Tech Member
    1,587
    10
    18
    United Kingdom
    YouTuber
    Too many sprites, that's the issue.


    Anyway, to make all the little Eggman's pop when Dr Eggman himself start's flying away, go to "loc_32C66:" and just under the label, insert this:

    Code (ASM):
    1.     tst.b   ($FFFFF7A7).w   ; Is boss defeated?
    2.     bne.s   +       ; If so, branch

    So you have this:

    Code (ASM):
    1. loc_32C66:
    2.     tst.b   ($FFFFF7A7).w   ; Is boss defeated?
    3.     bne.s   +       ; If so, branch
    4.     cmpi.b  #4,(MainCharacter+routine).w
    5.     beq.s   loc_32C76
    6.     cmpi.b  #4,(Sidekick+routine).w
    7.     bne.s   loc_32C82

    Then, go to "loc_32C82:" and between "cmpi.b #-2,collision_property(a0)" and "bgt.s return_32C96", insert a new label +, so you have this:

    Code (ASM):
    1. loc_32C82:
    2.     cmpi.b  #-2,collision_property(a0)
    3.     bgt.s   return_32C96
    4. +
    5.     move.b  #$14,mapping_frame(a0)
    6.     move.b  #6,anim(a0)

    Now, when you defeat the MTZ boss, as soon as Dr Eggman stops exploding then starts flying away, all remaining little Eggmans will automatically pop.
     
  2. Works great, thanks! I knew the balloons glitching was because of the Genesis sprite limit, but was referring to them coming after you after the boss is defeated. :P I've started applying fixes to the Xenowhirl disassembly since it seems most fixes on the wiki are geared towards it more than the SVN disassembly (most do work on both though). The only "issue" I've noticed is the Super Sonic transformation, one of the sprites (head region) becomes a garbled reddish mess while transforming. I'm not sure if it's a side effect of one of the fixes or because of the Genesis sprite limit.

    EDIT: What's the proper fix for the SVN disassembly? Thinking I might apply fixes to both.
     
  3. redhotsonic

    redhotsonic

    Also known as RHS Tech Member
    1,587
    10
    18
    United Kingdom
    YouTuber
    Seems like Sonic's art is not aligned properly. Find Sonic's art (ArtUnc_Sonic:) and then above it, you should see something like "align $200". Increase it. $10000 should do fine. This will increase the ROM size quite a bit, but it fixes it. If it still appears glitched, then it might be a different bug.
     
  4. Appears to have fixed it, thanks! :)
     
  5. redhotsonic

    redhotsonic

    Also known as RHS Tech Member
    1,587
    10
    18
    United Kingdom
    YouTuber
    Okay, I haven't posted any fixes for a long time, but I just came across a bug in my hack. This isn't a bug in Sonic 2, but in Sonic 2 and Knuckles, but this wasn't worth making it's own topic. See, in my hack, all characters celebrate at the end of the act, but if I made Knuckles glide and slide on the floor, as soon as he went into the celebration stage, he was stuck in the floor like so:

    [​IMG]


    Looking at Knuckles sliding in slow motion, he slides fine on floor, but for 1 frame only, he is in the ground by a couple of pixels:

    [​IMG]


    But by the very next frame, he's on the floor fine. So I had to look into a fix, which I did. But I got curious. I ported Knuckles from "Sonic 2 and Knuckles", so I wondered if the bug is in there... and it is:

    [​IMG]


    But if you look in the original "Sonic 3 and Knuckles", this bug is already fixed and Knuckles has no ground issues:

    [​IMG]



    So, let's apply this fix. Assuming you've ported Knuckles from S2K, and haven't changed any of the official labels, go to "loc_315926:" and you should see these four commands under the label:

    Code (ASM):
    1.         move.b  $16(a0),d0
    2.         sub.b   #$13,d0
    3.         ext.w   d0
    4.         add.w   d0,$C(a0)

    You may comment these out (or delete them). Instead, you can put this in:

    Code (ASM):
    1.         subi.w  #9,$C(a0)           ; This fixes Knuckles getting stuck in the ground

    So, you end up with this:

    Code (ASM):
    1. loc_315926:                   ; ...
    2.         move.w  #0,$14(a0)
    3.         move.w  #0,$10(a0)
    4.         move.w  #0,$12(a0)
    5. ;       move.b  $16(a0),d0
    6. ;       sub.b   #$13,d0
    7. ;       ext.w   d0
    8. ;       add.w   d0,$C(a0
    9.         subi.w  #9,$C(a0)           ; This fixes Knuckles getting stuck in the ground
    10.         bsr.w   Knuckles_ResetOnFloor_Part2
    11.         move.w  #$F,$2E(a0)
    12.         move.b  #$22,$1C(a0)
    13.         rts

    So now, for this one single frame, it will move Knuckles up 9 pixels, so he appears on the floor correctly. As the rest of the frames were fine in the first place, no need to make any other changes.



    EDIT: If anyone wants to put this on the wiki, feel free.
     
  6. redhotsonic

    redhotsonic

    Also known as RHS Tech Member
    1,587
    10
    18
    United Kingdom
    YouTuber
    In case anyone misses my main topic when they come to fixing bugs in Sonic 2, a lot of speed bugs have got fixed by me. Main topic is here with comments, or you can just see the fix in the spoiler below:


    Hello, I've been meaning to make this guide for ages but because of life reasons, I just didn't have the time. But recently, I have found more time and decided to get on with this.


    In Sonic 2, there are multiple speed issue bugs with Sonic and Tails, but for now, let's look at it with Sonic's point of view. It's uncommon, but not exactly rare, and when Super Sonic is enabled, it becomes more apparent. But sometimes, Sonic's top speed, acceleration and deceleration can be set wrong. The most common place for the bugs to occur is around this area of ARZ1 due to where the speed shoes are placed.

    [​IMG]


    Like said, it can be uncommon, but with people's hacks putting speedshoes underwater and other places, the bugs can happen more often.



    There are several speed issues:

    • If Super Sonic and you hit speedshoes, his top speed goes a little bit higher which is fine, but his acceleration and deceleration decreases. Technically, it's applying normal Sonic's speedshoes speed.
    • If Normal Sonic and you get speedshoes, if you go underwater, speedshoes's speed are lost. Even if you get out of the water, Sonic's speed is normal.
    • If Super Sonic and you get speedshoes, if you go underwater, speedshoes's speed are lost. Even if you get out of the water, Super Sonic's speed is normal.
    • If underwater and you get speedshoes, Sonic's "out-of-water" speedshoes speed apply, making you go way too fast underwater. Getting out of water or even back in and the speedshoes speeds are lost, even with speedshoes applied.
    • If Super and underwater and you get speedshoes, Normal Sonic's "out-of-water" speedshoes speed apply, making you go way too fast underwater. Getting out of water or even back in and the speedshoes speeds are lost, even with speedshoes applied, but applies Super Sonic's speed settings.
    • If underwater and you get speedshoes, bug above applies but if you never leave the water, once speedshoes wear off, Sonic's normal speed applies, even though you're still underwater, making you still too fast.
    • If Super and underwater and you get speedshoes, bug above the above applies but if you never leave the water, once speedshoes wear off, Super Sonic's speed applies, even though you're still underwater, making you still too fast.
    • If underwater and then you transform into Super Sonic, Super Sonic's "out-of-water" speed applies, making you way too fast.
    • If you have speedshoes and then you transform into Super Sonic, Super Sonic's speed applies, making you lose speedshoes speed, making you that bit slower than you should be.
    • If underwater when you have speedshoes and then you transform into Super Sonic, Super Sonic's "out-of-water" speed applies, and you lose your speedshoes speed.
    • If underwater when you have speedshoes and you're Super Sonic and you transform back to normal Sonic, normal Sonic's "underwater" speed applies, making you lose your speedshoes.


    A lot, eh? The main issue is that the game never checks to see if you have the speedshoes applied or not. Or when becoming Super and etc, it's not checking if underwater, etc, etc. It would have to do a few checks itself to get it right and I suspect Sonic Team didn't have time to do it as it wasn't particularly important. But we're going to fix these ourselves, and it's easier than you think.

    Please note: I am using Xenowhirls disassembly, although this shouldn't be hard to follow if you're using the HG disassembly.




    Step 1 - Back-up your disassembly

    Like all guides you're about to follow, make a back-up before making any changes! I am also not held responsible for any troubles this may bring to your hack.




    Step 2 - Creating new speeds

    First of all, we need to make some new speed settings. Here are some of Sonic's speeds settings listed in Sonic 2 currently:

    Code (ASM):
    1. ; NORMAL
    2.     move.w  #$600,(Sonic_top_speed).w
    3.     move.w  #$C,(Sonic_acceleration).w
    4.     move.w  #$80,(Sonic_deceleration).w
    5.  
    6. ; NORMAL SPEED SHOES
    7.     move.w  #$C00,(Sonic_top_speed).w
    8.     move.w  #$18,(Sonic_acceleration).w
    9.     move.w  #$80,(Sonic_deceleration).w
    10.    
    11. ; SUPER SONIC
    12.     move.w  #$A00,(Sonic_top_speed).w
    13.     move.w  #$30,(Sonic_acceleration).w
    14.     move.w  #$100,(Sonic_deceleration).w
    15.    
    16. ; NORMAL UNDERWATER
    17.     move.w  #$300,(Sonic_top_speed).w
    18.     move.w  #6,(Sonic_acceleration).w
    19.     move.w  #$40,(Sonic_deceleration).w
    20.  
    21. ; SUPER SONIC UNDERWATER
    22.     move.w  #$500,(Sonic_top_speed).w
    23.     move.w  #$18,(Sonic_acceleration).w
    24.     move.w  #$80,(Sonic_deceleration).w

    As you can see, the game doesn't have speed settings for "Normal underwater with speedshoes", "Super Sonic with speedshoes" or "Super Sonic underwater with speedshoes". No wonder why all these bugs exist. Now, we have to come up with these speeds, which I have already done with some maths involved. To get "Normal underwater with speedshoes", I thought, how does normal Sonic get speedshoes speed? Well, everything is doubled except his deceleration, which stays the same. So I did the same and got this new speed setting.

    Code (ASM):
    1. ; NORMAL UNDERWATER SPEED SHOES
    2.     move.w  #$600,(Sonic_top_speed).w
    3.     move.w  #$C,(Sonic_acceleration).w
    4.     move.w  #$40,(Sonic_deceleration).w

    It's almost identical to Sonic's normal speed, except his deceleration is slower. To get "Super Sonic with speedshoes", I left the top speed setting it already does alone, but made it not decrease Super Sonic's acceleration and deceleration, making him that tiny bit faster:

    Code (ASM):
    1. ; SUPER SONIC SPEED SHOES
    2.     move.w  #$C00,(Sonic_top_speed).w
    3.     move.w  #$30,(Sonic_acceleration).w
    4.     move.w  #$100,(Sonic_deceleration).w

    To get "Super Sonic underwater with speedshoes", I followed the same method on how "Normal" does it, and got this:

    Code (ASM):
    1. ; SUPER SONIC UNDERWATER SPEED SHOES
    2.     move.w  #$A00,(Sonic_top_speed).w
    3.     move.w  #$30,(Sonic_acceleration).w
    4.     move.w  #$80,(Sonic_deceleration).w

    You do not need to add any of the ASM above into your hack as yet.




    Step 3 - Creating a new table

    Now we've got all our speeds, we need to convert it into a table. Which I have already done on your behalf:

    Code (ASM):
    1. ; ===========================================================================
    2. ; ----------------------------------------------------------------------------
    3. ; Speed Settings Array
    4.  
    5. ; This array defines what speeds the character should be set to
    6. ; ----------------------------------------------------------------------------
    7. ;       blank   top_speed   acceleration    deceleration    ; # ; Comment
    8. Speedsettings:
    9.     dc.w    $0, $600,       $C,     $80     ; $00   ; Normal
    10.     dc.w    $0, $C00,       $18,        $80     ; $08   ; Normal Speedshoes
    11.     dc.w    $0, $300,       $6,     $40     ; $16   ; Normal Underwater
    12.     dc.w    $0, $600,       $C,     $40     ; $24   ; Normal Underwater Speedshoes
    13.     dc.w    $0, $A00,       $30,        $100        ; $32   ; Super
    14.     dc.w    $0, $C00,       $30,        $100        ; $40   ; Super Speedshoes
    15.     dc.w    $0, $500,       $18,        $80     ; $48   ; Super Underwater
    16.     dc.w    $0, $A00,       $30,        $80     ; $56   ; Super Underwater Speedshoes
    17. ; ===========================================================================

    This will be our new table. We'll insert this into the ASM file shortly. First, let's go onto the next step.




    Step 4 - Creating a new subroutine to apply speeds

    So, we need to create a new subroutine to grab the right speed under Sonic's conditions. Here is what I come up with:

    Code (ASM):
    1. ; ===========================================================================
    2. ; ---------------------------------------------------------------------------
    3. ; Subroutine to collect the right speed setting for a character
    4. ; a0 must be character
    5. ; a1 will be the result and have the correct speed settings
    6. ; a2 is characters' speed
    7. ; ---------------------------------------------------------------------------
    8.  
    9. ; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
    10.  
    11. ApplySpeedSettings:
    12.     moveq   #0,d0               ; Quickly clear d0
    13.     tst.w   speedshoes_time(a0)     ; Does character have speedshoes?
    14.     beq.s   +               ; If not, branch
    15.     addq.b  #1,d0               ; Quickly add 1 to d0
    16. +
    17.     btst    #6,status(a0)           ; Is the character underwater?
    18.     beq.s   +               ; If not, branch
    19.     addq.b  #2,d0               ; Quickly add 2 to d0
    20. +
    21.     cmpa.w  #MainCharacter,a0       ; Is it Tails currently following this code?
    22.     bne.s   +               ; If so, branch and ignore next question
    23.     tst.b   (Super_Sonic_flag).w        ; Is the character Super?
    24.     beq.s   +               ; If not, branch
    25.     addq.b  #4,d0               ; Quickly add 4 to d0
    26. +
    27.     add.b   d0,d0               ; Multiply itself
    28.     add.b   d0,d0               ; And again
    29.     add.b   d0,d0               ; And again
    30.     lea Speedsettings(pc,d0.w),a1   ; Load correct speed settings into a1
    31.     addq.l  #2,a1               ; Increment a1 by 2 quickly
    32.     move.l  (a1)+,(a2)+         ; Set character's new top speed and acceleration
    33.     move.w  (a1),(a2)           ; Set character's deceleration
    34.     rts                 ; Finish subroutine
    35. ; ===========================================================================

    What this will do is ask questions like if you're underwater, have speedshoes or are Super and depending on the answers, it will add bytes to d0. Once finished with the questions, whatever d0 is, it will multiply itself 3 times. With the new result in d0 after that multiplication, it will then grab data from the table with its starting position being whatever d0 is. For example, say you're normal Sonic and underwater. After the questions, d0 should be 2. Multiply itself 3 times, d0 becomes 16. If you then look for 16 on the table, you'll see that it does indeed equal "Normal Underwater". So it got the right speed setting.


    So, here is our new code and table so far:

    Code (ASM):
    1. ; ===========================================================================
    2. ; ---------------------------------------------------------------------------
    3. ; Subroutine to collect the right speed setting for a character
    4. ; a0 must be character
    5. ; a1 will be the result and have the correct speed settings
    6. ; a2 is characters' speed
    7. ; ---------------------------------------------------------------------------
    8.  
    9. ; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
    10.  
    11. ApplySpeedSettings:
    12.     moveq   #0,d0               ; Quickly clear d0
    13.     tst.w   speedshoes_time(a0)     ; Does character have speedshoes?
    14.     beq.s   +               ; If not, branch
    15.     addq.b  #1,d0               ; Quickly add 1 to d0
    16. +
    17.     btst    #6,status(a0)           ; Is the character underwater?
    18.     beq.s   +               ; If not, branch
    19.     addq.b  #2,d0               ; Quickly add 2 to d0
    20. +
    21.     cmpa.w  #MainCharacter,a0       ; Is it Tails currently following this code?
    22.     bne.s   +               ; If so, branch and ignore next question
    23.     tst.b   (Super_Sonic_flag).w        ; Is the character Super?
    24.     beq.s   +               ; If not, branch
    25.     addq.b  #4,d0               ; Quickly add 4 to d0
    26. +
    27.     add.b   d0,d0               ; Multiply itself
    28.     add.b   d0,d0               ; And again
    29.     add.b   d0,d0               ; And again
    30.     lea Speedsettings(pc,d0.w),a1   ; Load correct speed settings into a1
    31.     addq.l  #2,a1               ; Increment a1 by 2 quickly
    32.     move.l  (a1)+,(a2)+         ; Set character's new top speed and acceleration
    33.     move.w  (a1),(a2)           ; Set character's deceleration
    34.     rts                 ; Finish subroutine
    35. ; ===========================================================================
    36.  
    37. ; ----------------------------------------------------------------------------
    38. ; Speed Settings Array
    39.  
    40. ; This array defines what speeds the character should be set to
    41. ; ----------------------------------------------------------------------------
    42. ;       blank   top_speed   acceleration    deceleration    ; # ; Comment
    43. Speedsettings:
    44.     dc.w    $0, $600,       $C,     $80     ; $00   ; Normal
    45.     dc.w    $0, $C00,       $18,        $80     ; $08   ; Normal Speedshoes
    46.     dc.w    $0, $300,       $6,     $40     ; $16   ; Normal Underwater
    47.     dc.w    $0, $600,       $C,     $40     ; $24   ; Normal Underwater Speedshoes
    48.     dc.w    $0, $A00,       $30,        $100        ; $32   ; Super
    49.     dc.w    $0, $C00,       $30,        $100        ; $40   ; Super Speedshoes
    50.     dc.w    $0, $500,       $18,        $80     ; $48   ; Super Underwater
    51.     dc.w    $0, $A00,       $30,        $80     ; $56   ; Super Underwater Speedshoes
    52. ; ===========================================================================



    Step 5 - Placing your new code in your ASM file

    Thanks to step 4, we've got the majority of the code sorted. You now want to place that new code in your ASM file. My suggestion is to put it between Sonic and Tails object, seeming as they're both the ones that are going to use it more often. So, search for "obj02:" and place it just above.

    Now, if you've put the code in between Sonic and Tails like I said above, the rest of my guide should be fine, although if you do decide to insert the code elsewhere, you may get some “branch out of range” errors, which you must fix yourself. Depending on how heavy you've edited Sonic and/or Tails code, you might get these errors anyway, but they're so simple to fix.




    Step 6 - Replacing some old code in certain places

    Now we have our new code, we need to make some jumps to it. So, let's go.


    First, go to "Obj01_Init:". You only need to do this bit if you have checkpoints starting underwater, otherwise, you can skip this bit of the step. You MUST follow the rest of this step from when you see "************" onwards. Anyway, under the label "Obj01_Init:", find and delete these lines:

    Code (ASM):
    1.     move.w  #$600,(Sonic_top_speed).w   ; set Sonic's top speed
    2.     move.w  #$C,(Sonic_acceleration).w  ; set Sonic's acceleration
    3.     move.w  #$80,(Sonic_deceleration).w ; set Sonic's deceleration
    and replace with this

    Code (ASM):
    1.     lea (Sonic_top_speed).w,a2  ; Load Sonic_top_speed into a2
    2.     bsr.w   ApplySpeedSettings  ; Fetch Speed settings

    "************"


    Under "Obj01_ChkShoes:" find and delete these lines:

    Code (ASM):
    1.     move.w  #$600,(Sonic_top_speed).w
    2.     move.w  #$C,(Sonic_acceleration).w
    3.     move.w  #$80,(Sonic_deceleration).w
    4.     tst.b   (Super_Sonic_flag).w
    5.     beq.s   Obj01_RmvSpeed
    6.     move.w  #$A00,(Sonic_top_speed).w
    7.     move.w  #$30,(Sonic_acceleration).w
    8.     move.w  #$100,(Sonic_deceleration).w

    and replace with this

    Code (ASM):
    1.     lea (Sonic_top_speed).w,a2  ; Load Sonic_top_speed into a2
    2.     bsr.w   ApplySpeedSettings  ; Fetch Speed settings

    Next, under "Obj01_InWater:" find these lines and delete:

    Code (ASM):
    1.     move.w  #$300,(Sonic_top_speed).w
    2.     move.w  #6,(Sonic_acceleration).w
    3.     move.w  #$40,(Sonic_deceleration).w
    4.     tst.b   (Super_Sonic_flag).w
    5.     beq.s   +
    6.     move.w  #$500,(Sonic_top_speed).w
    7.     move.w  #$18,(Sonic_acceleration).w
    8.     move.w  #$80,(Sonic_deceleration).w
    9. +

    and replace with:

    Code (ASM):
    1.     lea (Sonic_top_speed).w,a2  ; Load Sonic_top_speed into a2
    2.     bsr.w   ApplySpeedSettings  ; Fetch Speed settings

    Next, under "Obj01_OutWater:" find these lines and delete:

    Code (ASM):
    1.     move.w  #$600,(Sonic_top_speed).w
    2.     move.w  #$C,(Sonic_acceleration).w
    3.     move.w  #$80,(Sonic_deceleration).w
    4.     tst.b   (Super_Sonic_flag).w
    5.     beq.s   +
    6.     move.w  #$A00,(Sonic_top_speed).w
    7.     move.w  #$30,(Sonic_acceleration).w
    8.     move.w  #$100,(Sonic_deceleration).w
    9. +

    and replace with:

    Code (ASM):
    1.     lea (Sonic_top_speed).w,a2  ; Load Sonic_top_speed into a2
    2.     bsr.w   ApplySpeedSettings  ; Fetch Speed settings

    Next, go to "Sonic_CheckGoSuper:" and find and delete these lines:

    Code (ASM):
    1.     move.w  #$A00,(Sonic_top_speed).w
    2.     move.w  #$30,(Sonic_acceleration).w
    3.     move.w  #$100,(Sonic_deceleration).w

    and replace with:

    Code (ASM):
    1.     lea (Sonic_top_speed).w,a2      ; Load Sonic_top_speed into a2
    2.     bsr.w   ApplySpeedSettings      ; Fetch Speed settings

    Next, go to "Sonic_RevertToNormal:" and find and delete these lines:

    Code (ASM):
    1.     move.w  #$600,(Sonic_top_speed).w
    2.     move.w  #$C,(Sonic_acceleration).w
    3.     move.w  #$80,(Sonic_deceleration).w
    4.     btst    #6,status(a0)   ; Check if underwater, return if not
    5.     beq.s   return_1AC3C
    6.     move.w  #$300,(Sonic_top_speed).w
    7.     move.w  #6,(Sonic_acceleration).w
    8.     move.w  #$40,(Sonic_deceleration).w

    and replace with this slightly different code:

    Code (ASM):
    1.     lea (Sonic_top_speed).w,a2      ; Load Sonic_top_speed into a2
    2.     bra.w   ApplySpeedSettings      ; Fetch Speed settings and return


    Now onto Tails. Seeming as Tails uses the exact same speeds, we can use the exact same table. So, go to "Obj02_Init:". You only need to do this bit if you have checkpoints starting underwater, otherwise, you can skip this bit of the step. You MUST follow the rest of this step from when you see "~~~~~~~~~~~~" onwards. Anyway, under the label "Obj02_Init:", find and delete these lines:

    Code (ASM):
    1.     move.w  #$600,(Tails_top_speed).w   ; set Tails' top speed
    2.     move.w  #$C,(Tails_acceleration).w  ; set Tails' acceleration
    3.     move.w  #$80,(Tails_deceleration).w ; set Tails' deceleration

    and replace with this slightly different code:

    Code (ASM):
    1.     lea (Tails_top_speed).w,a2  ; Load Tails_top_speed into a2
    2.     bsr.w   ApplySpeedSettings  ; Fetch Speed settings

    "~~~~~~~~~~~~"


    Next, go to "Obj02_ChkShoes:" and find and delete these lines:

    Code (ASM):
    1.     move.w  #$600,(Tails_top_speed).w
    2.     move.w  #$C,(Tails_acceleration).w
    3.     move.w  #$80,(Tails_deceleration).w

    and replace with:

    Code (ASM):
    1.     lea (Tails_top_speed).w,a2  ; Load Tails_top_speed into a2
    2.     bsr.w   ApplySpeedSettings  ; Fetch Speed settings

    Next, find "Obj02_InWater:" and find and delete these lines:

    Code (ASM):
    1.     move.w  #$300,(Tails_top_speed).w
    2.     move.w  #6,(Tails_acceleration).w
    3.     move.w  #$40,(Tails_deceleration).w

    and replace with:

    Code (ASM):
    1.     lea (Tails_top_speed).w,a2  ; Load Tails_top_speed into a2
    2.     bsr.w   ApplySpeedSettings  ; Fetch Speed settings

    Next, under "Obj02_OutWater:", find and delete:

    Code (ASM):
    1.     move.w  #$600,(Tails_top_speed).w
    2.     move.w  #$C,(Tails_acceleration).w
    3.     move.w  #$80,(Tails_deceleration).w

    and replace with:

    Code (ASM):
    1.     lea (Tails_top_speed).w,a2  ; Load Tails_top_speed into a2
    2.     bsr.w   ApplySpeedSettings  ; Fetch Speed settings


    That's Tails. Let's edit the speed shoes object code. Locate label "super_shoes:" and find and delete these lines:

    Code (ASM):
    1.     move.w  #$C00,(Sonic_top_speed).w
    2.     move.w  #$18,(Sonic_acceleration).w
    3.     move.w  #$80,(Sonic_deceleration).w

    and replace with this new code:

    Code (ASM):
    1.     movem.l a0-a2,-(sp)     ; Move a0, a1 and a2 onto stack
    2.     lea (MainCharacter).w,a0    ; Load Sonic to a0
    3.     lea (Sonic_top_speed).w,a2  ; Load Sonic_top_speed into a2
    4.     jsr ApplySpeedSettings  ; Fetch Speed settings
    5.     movem.l (sp)+,a0-a2     ; Move a0, a1 and a2 from stack

    Then finally, go to "loc_12A10" and delete these lines:

    Code (ASM):
    1.     move.w  #$C00,(Tails_top_speed).w
    2.     move.w  #$18,(Tails_acceleration).w
    3.     move.w  #$80,(Tails_deceleration).w

    and replace with this slightly different new code:

    Code (ASM):
    1.     movem.l a0-a2,-(sp)     ; Move a0, a1 and a2 onto stack
    2.     lea (MainCharacter).w,a0    ; Load Tails to a0
    3.     lea (Tails_top_speed).w,a2  ; Load Tails_top_speed into a2
    4.     jsr ApplySpeedSettings  ; Fetch Speed settings
    5.     movem.l (sp)+,a0-a2     ; Move a0, a1 and a2 from stack

    All done. Please note, do not edit under the label "loc_3AA22:". This is the only speed settings that can be left alone. This is when Sonic jumps onto the Tornado at the end of WFZ. This code applies to Super Sonic too (so Super Sonic goes slower) but this is to stop Super Sonic over-shooting the Tornado and falling to his death. The speed only applies when Sonic is about to jump onto the plane.


    Be warned! If you have put in other places where you've made the characters change their speed, you'll want to edit them too!




    Step 7 - Fixing another bug

    With the above fixes applied, a new bug has been introduced. The bug? If you're Super Sonic and you die whilst Super, the "Super_Sonic_flag" will still remain set. This means, once the level restarts, the speed settings will fetch speeds with Super Sonic in mind, because of the flag. So if you go underwater or get sppedshoes, it will still think you're Super and take that into account. And if you followed the two steps for when Sonic and Tails get created, then the Super speeds will apply then too.


    Also whilst Super Sonic, if you pause the game and press A to quit, the flag will remain set. You could select Tails in options and Tails will have Super speeds. Anyway, let's fix this.


    Find "Level_ClrRam:" and directly underneath it before the ClearRAM macros, put this:

    Code (ASM):
    1.     clr.b   (Super_Sonic_flag).w

    There we go, all bugs should be fixed.



    Now, when you enter/exit water, enter/exit speedshoes and/or enter/exit Super, the speeds should all be set correctly!


    As per usual, here is a ROM with the bugs fixed.



    Cheers,
    redhotsonic
     
  7. MoDule

    MoDule

    Tech Member
    327
    24
    18
    Procrastinating from writing bug-fix guides
    People are still hacking Sonic 2, right? Thought so. Anyway, down to business. Over the last few days I've been fixing a number of object-collision-related bugs. I think the first one has already been fixed, but I'll post my version anyway, since the subsequent fixes loosely rely on it.

    So, lets start with the first one:

    Fix ducking not properly reducing character's height during object collisions

    In Sonic 2 and onwards there is a bug in the character-to-object collision checking code. Usually, when the player ducks or spin-dashes, one would expect their character's height to be reduced, but this actually only works for Sonic while he is ducking. Tails's height is never reduced, and spin-dashing doesn't do anything, either. Here, we are going to fix that.

    Preparation

    Before doing anything else, we'll define a macro that will come in handy later on:
    Code (ASM):
    1. ; ---------------------------------------------------------------------------
    2. ; Macro to load a character's hitbox data to be used in one of the Touch routines.
    3. ;
    4. ; The formula to calculate a character's new Y radius when the top edge is moved, but the bottom
    5. ; edge should stay in the same place (e.I. when ducking) is as follows:
    6. ;   R = (D - O)/2
    7. ; where R is the new Y radius, D is the character's original diameter - 3 (32 for Sonic, 24 for
    8. ; Tails), and O is the difference between the new and old top edges. O should be an even number.
    9. ; ---------------------------------------------------------------------------
    10. Touch_SetupSize macro
    11.     move.w  x_pos(a0),d2        ; load position into d2,d3
    12.     move.w  y_pos(a0),d3
    13.     subi.w  #8,d2           ; assume X radius to be 8
    14.     moveq   #0,d5
    15.     move.b  y_radius(a0),d5
    16.     subq.b  #3,d5           ; reduce Y radius by 3
    17.     sub.w   d5,d3           ; set top of hitbox = Y pos - (Y radius - 3)
    18.  
    19. ; Touch_ChkDuck:
    20.     move.b  anim(a0),d0
    21.  
    22. ; Touch_ChkDuckSonic:
    23.     cmpi.b  #ObjID_Sonic,id(a0) ; is character Sonic?
    24.     bne.s   Touch_ChkDuckTails  ; if not, branch
    25.     subq.b  #8,d0           ; is Sonic ducking?
    26.     beq.s   Touch_SonicDuck     ; if yes, reduce height
    27.     subq.b  #1,d0           ; is Sonic spindashing?
    28.     bne.s   Touch_NoDuck        ; if not, branch
    29.  
    30. ; Touch_SonicSpindash:
    31.     addi.w  #12,d3          ; move Sonic's top edge down 12 pixels...
    32.     moveq   #(32 - 12)/2,d5     ; ... and set his Y radius to 10
    33.     bra.s   Touch_NoDuck
    34. ; ---------------------------------------------------------------------------
    35.  
    36. Touch_SonicDuck:
    37.     addq.w  #6,d3           ; move Sonic's top edge down 6 pixels...
    38.     moveq   #(32 - 6)/2,d5      ; ... and set his Y radius to 13
    39.     cmpi.b  #$4D,mapping_frame(a0)  ; is sonic fully crouched?
    40.     bne.s   Touch_NoDuck        ; if not, branch
    41.     addq.w  #6,d3           ; move Sonic's top edge down a total of 12 pixels...
    42.     moveq   #(32 - 12)/2,d5     ; ... and set his Y radius to 10
    43.     bra.s   Touch_NoDuck
    44. ; ---------------------------------------------------------------------------
    45.  
    46. Touch_ChkDuckTails:
    47.     subq.b  #8,d0           ; is Tails ducking?
    48.     beq.s   Touch_TailsDuck     ; if yes, reduce height
    49.     subq.b  #1,d0           ; is Tails spindashing?
    50.     bne.s   Touch_NoDuck        ; if not, branch
    51.  
    52. ; Touch_TailsSpindash:
    53.     addq.w  #6,d3           ; move Tails's top edge down 6 pixels...
    54.     moveq   #(24 - 6)/2,d5      ; ... and set his Y radius to 9
    55.     bra.s   Touch_NoDuck
    56. ; ---------------------------------------------------------------------------
    57.  
    58. Touch_TailsDuck:
    59.     addi.w  #12,d3          ; move Tails's top edge down 12 pixels...
    60.     moveq   #(24 - 12)/2,d5     ; ... and set his Y radius to 6
    61.    
    62. Touch_NoDuck:
    63.     move.w  #8*2,d4         ; set X diameter
    64.     add.w   d5,d5           ; set Y diameter
    65.     endm
    The best place to put this macro is in s2.macros.asm. As for what this macro does, it's basically the first part of TouchResponse with a few modifications to fix the character height bug. This adds checks for ducking, and spin-dashing, as well as for Sonic's first ducking frame. What this code does in the original is set up a number of registers with coordinate, and radius values. The registers we're interested in are d3, and d5, which hold the character's bounding box's upper edge, and y-radius, respectively. The interesting part starts at Touch_ChkDuck. Since we'll be potentially checking for a number of animations, we load the current character's anim into d0. Then we check the character's id. For each of the characters, we check for the relevant animation numbers, and reduce their height if a specific animation is playing.

    Extending the macro

    Some users might want to do a little more with this code, like add extra animation checks, or make it work with more characters. Here I'll provide a few explanations on how to do most of the changes necessary.

    To extend this code for even more characters, such as Knuckles, we will add a few lines to Touch_ChkDuckTails. Note how we make a check for Sonic's object-id at the beginning of Touch_ChkDuckSonic? We can do the same right after the label Touch_ChkDuckTails: check for the next character's id, and branch to that character's setup code if necessary. When doing this, place the extra character's code before Touch_NoDuck, as the code following it is expected to be at the end. This can be repeated for any number of characters. Note that after every extension, an unconditional branch (bra) to Touch_NoDuck needs to be added at the end of the previous character's code. For example, if we added Knuckles as a third character, we'd add a check for his id at the beginning of Touch_ChkDuckTails, add code for handling his animations before Touch_NoDuck, and then we'd need to add a branch to Touch_NoDuck at the end of the code after Touch_TailsDuck and before Touch_NoDuck.

    To add additional animation checks, go to the beginning of the character-specific code. For Sonic, this would be at Touch_ChkDuckSonic. This is where we check for specific animations. Note how I used a series of subqs. That's only because it's slightly faster than using cmpi, and happens to work in this instance. Unless you understand how this works, I'd suggest you stick to using cmpi, and place your own checks in front of mine, to make sure everything still works afterwards. The animation handlers (Touch_SonicSpindash, Touch_SonicDuck, etc.) all basically work the same way: add something to d3, and overwrite d5. This is also where to do mappings-frame-specific checks, like in Touch_SonicDuck. The value to add to d3 is how many pixels the character's hitbox should be moved down; the value to write to d5 is calculated with the formula provided in the macro's documentation. Note that D is based on what the character's height would normally be, and that this isn't always the character's standing height, like while jumping.

    Note

    The macro can be changed into a subroutine, if that is more desirable. Note that using a macro, and calling a subroutine work differently.

    Fixing the bug

    Now that the macro is ready, we can get on with fixing the bug. First, go to TouchResponse(loc_3F554). Note that a portion of the code here looks a lot like our macro, as mentioned earlier. Now replace the following code:
    Code (ASM):
    1.     move.w  x_pos(a0),d2 ; load Sonic's position into d2,d3
    2.     move.w  y_pos(a0),d3
    3.     subi.w  #8,d2
    4.     moveq   #0,d5
    5.     move.b  y_radius(a0),d5
    6.     subq.b  #3,d5
    7.     sub.w   d5,d3
    8.     cmpi.b  #$4D,mapping_frame(a0)  ; is Sonic ducking?
    9.     bne.s   Touch_NoDuck        ; if not, branch
    10.     addi.w  #$C,d3
    11.     moveq   #$A,d5
    12. ; loc_3F592:
    13. Touch_NoDuck:
    14.     move.w  #$10,d4
    15.     add.w   d5,d5
    with the macro Touch_SetupSize. To use a macro, all we have to do is write its name, and indent it like we would with any opcode. Like this:
    Code (ASM):
    1. Label:      ; labels are not indented
    2.     Touch_SetupSize ; macros are indented, like other code
    3.  
    4.     ; other code
    5.  
    Now all we have to do is repeat this step for Touch_Boss, Check_CNZ_bumpers, and Touch_Rings. Note that Touch_Rings has two lines inserted before the end of the code we are replacing:
    Code (ASM):
    1.     move.w  #6,d1   ; set ring radius
    2.     move.w  #12,d6  ; set ring diameter
    These two lines should not be removed. Also note that Check_CNZ_bumpers is slightly different in that it assumes a slightly larger x radius. It subtracts 9 from d2 instead of 8, and subsequently sets d4 to 18 instead of 16. The macro can't do this on its own (without a slight rewrite), so for now, add this after the macro in Check_CNZ_bumpers:
    Code (ASM):
    1.     subq.w  #1,d2       ; X radius is larger by 1 in this routine
    2.     moveq   #18,d4      ; ... which means the diameter is larger by 2
    This adjusts d2 and d4 to use the correct values again.

    And with that, we are done.

    The bug explained

    The problem is quite simple. The original collision checking routine was only written with Sonic 1 in mind. In that game, Sonic only had a single ducking frame, so checking only for that frame is the natural solution. Sonic 2 however introduced a second character, Tails, Sonic has a second ducking frame, and both characters can perform the spin-dash. Unfortunately, it looks like the old collision checking code was never updated to account for this, thus making Tails unable to duck under things, Sonic only getting a height reduction during his final ducking frame, and both characters getting hit while spin-dashing by objects that would appear to go over them.

    Afterthoughts

    The new code can quickly bloat up into monstrous proportions when adding new characters, or animations. Ignoring size, the execution time can also increase. While speed isn't much of an issue here, it can become one when we start using this macro too often, like we will be doing in a later guide. My (as of yet unimplemented) solution to this is to have the character objects calculate their hitbox coordinates and radii inside their own code, and save these values somewhere in RAM. That way, the calculation only needs to be done once per character, as opposed to once per hitbox check. Building on this, we could eliminate the calculation altogether by using a table that maps every mappings frame to a pair of bounding box offsets and radii, but this would be difficult to do without a dedicated editor.

    End of guide

    As an aside, I recently made an addendum to a guide in my own topic, here. I had to switch two lines around, because there'd be a specific case when it doesn't behave correctly, otherwise. Speaking of my topic, should it just be merged with this one? It was originally meant to become what this topic here is, but forgot to make the suggestion, so now it just looks like a self-glorifying ego trip.

    Anyway, there's a few more guides coming, so watch this space.
     
  8. Dracula

    Dracula

    Oldbie
    605
    0
    16
    I'm watching you!
    Converting NES Mappers to MMC5
    While I was playing Sonic 2 a long time ago, on Wing Fortress Zone at the end, Sonic tries to jump on the tornado and for some reason, he keep on jumping to his death. Not sure if this a bug or not.
     
  9. redhotsonic

    redhotsonic

    Also known as RHS Tech Member
    1,587
    10
    18
    United Kingdom
    YouTuber

    Don't forget the CNZ bumpers at loc_174DE. Although, it might not be necessary. I think using a subroutine would be better rather than a macro. Using a subroutine may be ever-so slightly longer, it will save a ton of space. Personal preference I suppose. Nice work either way, it's a bit cleaner than the earlier fix in this topic.




    When super or normal? Either way, I haven't seen this bug.
     
  10. Dracula

    Dracula

    Oldbie
    605
    0
    16
    I'm watching you!
    Converting NES Mappers to MMC5
    Both!
     
  11. MoDule

    MoDule

    Tech Member
    327
    24
    18
    Procrastinating from writing bug-fix guides
    Oops, for some reason, I thought those worked differently. Turns out, I was wrong. I'll fix it right away. This is why it's good to share these things.
     
  12. MoDule

    MoDule

    Tech Member
    327
    24
    18
    Procrastinating from writing bug-fix guides
    A new day, a new guide.
    ... Actually, this one probably could have been a part of yesterday's guide, but oh well.

    Today we will be performing an arguably more useful fix than yesterday: we'll make it so that characters can duck under solid objects. I actually already made a fix for this a long time ago, but it was messy, and I never made it public.

    Fix incorrect solid object collisions while ducking

    In all of the main series 16-bit Sonic games, there's a bug where ducking has no effect on solid object collisions. When checking the lower boundary of a solid object, characters will always behave as if they were standing, unless they are rolling. Here, we are going to fix that.

    Fixing the bug

    First, locate the label SolidObject_cont(loc_199E8). This is the part of the solid object code that performs the hitbox checks. The relevant code looks like this:
    Code (ASM):
    1. loc_199F0:
    2.     ; We now perform the x portion of a bounding box check.  To do this, we assume a
    3.     ; coordinate system where the x origin is at the object's left edge.
    4.     move.w  x_pos(a1),d0        ; load Sonic's x position...
    5.     sub.w   x_pos(a0),d0        ; ... and calculate his x position relative to the object
    6.     add.w   d1,d0           ; assume object's left edge is at (0,0).  This is also Sonic's distance to the object's left edge.
    7.     bmi.w   loc_19AC4       ; branch, if Sonic is outside the object's left edge
    8.     move.w  d1,d3
    9.     add.w   d3,d3           ; calculate object's width
    10.     cmp.w   d3,d0
    11.     bhi.w   loc_19AC4       ; branch, if Sonic is outside the object's right edge
    12.     ; We now perform the y portion of a bounding box check.  To do this, we assume a
    13.     ; coordinate system where the y origin is at the highest y position relative to the object
    14.     ; at which Sonic would still collide with it.  This point is
    15.     ;   y_pos(object) - width(object)/2 - y_radius(Sonic) - 4,
    16.     ; where object is stored in (a0), Sonic in (a1), and height(object)/2 in d2.  This way
    17.     ; of doing it causes the object's hitbox to be vertically off-center by -4 pixels.
    18.     move.b  y_radius(a1),d3     ; load Sonic's y radius
    19.     ext.w   d3
    20.     add.w   d3,d2           ; calculate maximum distance for a top collision
    21.     move.w  y_pos(a1),d3        ; load Sonic's y position...
    22.     sub.w   y_pos(a0),d3        ; ... and calculate his y position relative to the object
    23.     addq.w  #4,d3           ; assume a slightly lower position for Sonic
    24.     add.w   d2,d3           ; assume the highest position where Sonic would still be colliding with the object to be (0,0)
    25.     bmi.w   loc_19AC4       ; branch, if Sonic is above this point
    26.     andi.w  #$7FF,d3
    27.     move.w  d2,d4
    28.     add.w   d4,d4           ; calculate minimum distance for a bottom collision
    29.     cmp.w   d4,d3
    30.     bhs.w   loc_19AC4       ; branch, if Sonic is below this point
    Right after the third line from the bottom which calculates the minimum distance for a bottom collision, add the following code:
    Code (ASM):
    1. ; Solid_ChkDuck:
    2.     move.b  anim(a1),d5
    3.  
    4. ; Solid_ChkDuckSonic:
    5.     cmpi.b  #ObjID_Sonic,id(a1) ; is character Sonic?
    6.     bne.s   Solid_ChkDuckTails  ; if not, branch
    7.     subq.b  #8,d5           ; is Sonic ducking?
    8.     beq.s   Solid_SonicDuck     ; if yes, branch
    9.     subq.b  #1,d5           ; is Sonic spindashing?
    10.     bne.s   Solid_NoDuck        ; if not, branch
    11.  
    12. ; Solid_SonicSpindash:
    13.     subi.w  #12,d4          ; reduce object's downward radius by 12
    14.     bra.s   Solid_NoDuck
    15. ; ---------------------------------------------------------------------------
    16.  
    17. Solid_SonicDuck:
    18.     subq.w  #6,d4           ; reduce object's downward radius by 6
    19.     cmpi.b  #$4D,mapping_frame(a1)  ; is sonic fully crouched?
    20.     bne.s   Solid_NoDuck        ; if not, branch
    21.     subq.w  #6,d4           ; reduce object's downward radius by a total of 12
    22.     bra.s   Solid_NoDuck
    23. ; ---------------------------------------------------------------------------
    24.  
    25. Solid_ChkDuckTails:
    26.     subq.b  #8,d5           ; is Tails ducking?
    27.     beq.s   Solid_TailsDuck     ; if yes, branch
    28.     subq.b  #1,d5           ; is Tails spindashing?
    29.     bne.s   Solid_NoDuck        ; if not, branch
    30.  
    31. ; Solid_TailsSpindash:
    32.     subq.w  #6,d4           ; reduce object's downward radius by 6
    33.     bra.s   Solid_NoDuck
    34. ; ---------------------------------------------------------------------------
    35.    
    36. Solid_TailsDuck:
    37.     subi.w  #12,d4          ; reduce object's downward radius by 12
    38.  
    39. Solid_NoDuck:
    With this, the bug is fixed.

    Extending functionality

    There might be cases when the user wants to add additional animation checks, or characters. Doing this works much like extending the Touch_SetupSize macro, as described here. The only difference is that what you would add to d3 in the other guide, you'd subtract from d4 here. So if for example you wanted to reduce Tails's height while ducking by 12, here you subtract 12 from d4, as seen in Solid_TailsDuck. You also do not need to set d5 to anything, since it's not used here.

    Afterthoughts

    The extra overhead produced by the additional checks is multiplied by the number of solid objects on screen. This can lead to the game incurring slowdown earlier than it would normally. My proposed solution, as seen in the other guide here, is to calculate character hitbox information inside the character's code, and save it in RAM, thus eliminating the need to calculate it for every solid object's collision check.

    End of guide

    I know there's a few other solid object routines that I didn't touch. If someone knows what these specific routines are used for, and if they need to be fixed, too, please let me know.
     
  13. flamewing

    flamewing

    Emerald Hunter Tech Member
    1,161
    65
    28
    France
    Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
    This is the same bug that causes the ARZ boss to shoot out when you land the last hit on a specific frame. The fix for both is similar, too, so here they go:

    Fixing the Silver Sonic glitch
    Go to loc_3984A; there, you will find the following code:
    Code (Text):
    1. loc_3984A:
    2.     bsr.w   loc_39CAE
    3.     bsr.w   loc_39D1C
    4.     subq.b  #1,objoff_2A(a0)
    5.     beq.s   loc_39886
    and change it to this:
    Code (Text):
    1. loc_3984A:
    2.     bsr.w   loc_39CAE
    3.     bsr.w   loc_39D1C
    4.     cmpi.b  #$C,routine(a0)
    5.     beq.w   JmpTo45_DisplaySprite
    6.     subq.b  #1,objoff_2A(a0)
    7.     beq.s   loc_39886
    and it will be fixed.

    Fixing the ARZ boss bug
    Go to loc_306B8, where you will find the following code:
    Code (Text):
    1. loc_306B8:
    2.     bsr.w   Boss_MoveObject
    3.     bsr.w   loc_3075C
    4.     bsr.w   loc_30824
    5.     cmpi.b  #-$40,mapping_frame(a0)
    6.     bne.s   loc_306F8
    7.     lea (Boss_AnimationArray).w,a1
    and change it to this:
    Code (Text):
    1. loc_306B8:
    2.     bsr.w   Boss_MoveObject
    3.     bsr.w   loc_3075C
    4.     bsr.w   loc_30824
    5.     cmpi.b  #$C0,mapping_frame(a0)
    6.     bne.s   loc_306F8
    7.     cmpi.b  #8,angle(a0)
    8.     beq.s    loc_306F8
    9.     lea (Boss_AnimationArray).w,a1
    and it will be fixed.

    So what exactly is going on?
    For the ARZ code, 'angle(a0)' is the equivalent of 'routine(a0)' for most other objects: it selects which branch of the code to execute. In both cases, the functions called before the added code check to see if the boss was defeated and sets routine/angle to the right value for this case. Then, the normal flow of code does other stuff that adds 2 to routine/angle (as the case may be). For the ARZ boss, this puts him in the flying away mode; for Silver Sonic, this turns him into the rockets he uses when coming down. The new branches skip over the code that would cause these errors.
     
  14. redhotsonic

    redhotsonic

    Also known as RHS Tech Member
    1,587
    10
    18
    United Kingdom
    YouTuber
    Is that it? It's that simple? Thanks very much for the ARZ fix; I'll be applying it now. Shame the bug is still in my release for the SHC, but hey ho! Thanks again :)


    EDIT: This hasn't fixed the ARZ bug for me. He can still leave early.
     
  15. flamewing

    flamewing

    Emerald Hunter Tech Member
    1,161
    65
    28
    France
    Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
    The only changes I have in this boss other than the one above are: fix for laughing when players are hit; destruction fix from up thread; changes for S3&K priority and my hybrid object manager; Hg synch. None of these affect anything related, and I can't perform the blast-off in my hack despite getting the final hit in all possible frames (I am a TASer, so...).

    Maybe some change you made to the boss is conflicting with the fix?
     
  16. redhotsonic

    redhotsonic

    Also known as RHS Tech Member
    1,587
    10
    18
    United Kingdom
    YouTuber
    Knowing my luck, yes. The boss has been edited for the way he shoots more arrows. I tried fiddling with it, but no avail'. But if you're sure this fix definitely works, then it's a problem on my end and will look into it. Cheers, either way!
     
  17. redhotsonic

    redhotsonic

    Also known as RHS Tech Member
    1,587
    10
    18
    United Kingdom
    YouTuber
    Okay, flamewing. Your fix for the ARZ glitch definitely does NOT work. I even performed the glitch in your hack:

    [​IMG]

    [​IMG]

    [​IMG]


    flamewing, I will send you a savestate which will perform this glitch via PM. I even tried your fix in the original S2 ROM. Still happens.



    Anyway, your fix was along the right lines, but not in the right place. Reason why? Well, I tried doing this instead temporarily:

    Code (ASM):
    1.     cmpi.b  #$C0,mapping_frame(a0)
    2.     bne.s   loc_306F8
    3.     cmpi.b  #2,angle(a0)
    4.     bge.s   loc_306F8
    With this code, Eggman will NEVER use the hammer because the angle (routine) is always 2 or more. He will just stay in one spot forever and ever. Yet, I was still able to perform this glitch. So, your fix does not work.




    The real fix

    Now, I noticed that it usually happens just a moment before he stops moving left/right. So, using your fix as a guide, I tried this instead:



    Code (ASM):
    1. loc_3069E:
    2.     cmpi.b  #8,angle(a0)
    3.     beq.s   loc_306AA
    4.     addq.b  #2,angle(a0)
    5.     move.w  #0,($FFFFF758).w
    6.  
    7. loc_306AA:
    This code adds 2 to the angle (routine) just a split second before Eggman stops moving from side to side. Now I cannot get this glitch to happen. I had a savestate in my S2R game where this glitch would happened, applied this fix, and even using the savestate, the glitch will now NOT happen.

    Hope this helps you and many others.
     
  18. flamewing

    flamewing

    Emerald Hunter Tech Member
    1,161
    65
    28
    France
    Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
    Actually -- and you should have seen this coming -- I manged to reproduce the glitch with your fix applied [​IMG]

    So:

    The Really real fix for the ARZ boss
    Use both fixes at the same time. Why? Well, there are two cases that cause the boss to blast-off: one when he is stopping moving left or right and one when he is just about to start swinging his hammer. RedHotSonic's fix applies to the first case, mine applies to the second case.

    Now it is time to find out how many similar cases there are for Silver Sonic...
     
  19. redhotsonic

    redhotsonic

    Also known as RHS Tech Member
    1,587
    10
    18
    United Kingdom
    YouTuber
    Ah, this boss is sneakier than we thought. Well, at least we can safely say it's now fixed =P

    lol!

    EDIT: Got tags wrong on quote.
     
  20. flamewing

    flamewing

    Emerald Hunter Tech Member
    1,161
    65
    28
    France
    Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
    How to prevent level wraps in S1, S2 and S3&K
    Every classic Sonic game has them: gather enough speed (or use zipping mechanisms, or debug mode), go through the left edge of the screen and bam -- you are now at the end of the level. This is how you can completely eliminate level wraps from your hack.

    In all cases, I am assuming the Hg disassembly; it should be easy to port it over to your favorite outdated disassembly.

    Sonic 1
    Find the routine "Sonic_LevelBound" (it is in file "_incObj/Sonic LevelBound.asm"); it starts like this:
    [68k]Sonic_LevelBound: ; XREF: Obj01_MdNormal; et al
    move.l obX(a0),d1
    move.w obVelX(a0),d0
    ext.l d0
    asl.l #8,d0
    add.l d0,d1
    swap d1
    move.w (v_limitleft2).w,d0
    addi.w #$10,d0
    cmp.w d1,d0 ; has Sonic touched the side boundary?
    bhi.s @sides ; if yes, branch[/68k]
    Change this routine so it looks like this:
    [68k]Sonic_LevelBound: ; XREF: Obj01_MdNormal; et al
    moveq #0,d2
    move.l obX(a0),d1
    smi.b d2 ; Set d2 if player on position > 32767
    add.w d2,d2 ; Move bit up
    move.w obVelX(a0),d0
    spl.b d2 ; Set if speed is positive
    add.w d2,d2 ; Move bit up
    ext.l d0
    asl.l #8,d0
    add.l d0,d1
    spl.b d2 ; Set if position+speed is < 32768
    move.w (v_limitleft2).w,d0
    addi.w #$10,d0
    tst.w d2 ; If d2 is zero, we had an underflow of position
    beq.s @sides
    swap d1
    cmp.w d1,d0 ; has Sonic touched the side boundary?
    bhi.s @sides ; if yes, branch[/68k]
    You are done.

    Sonic 2
    Find the routine "Sonic_LevelBound"; it starts like this:
    [68k]; loc_1A974:
    Sonic_LevelBound:
    move.l x_pos(a0),d1
    move.w x_vel(a0),d0
    ext.l d0
    asl.l #8,d0
    add.l d0,d1
    swap d1
    move.w (Camera_Min_X_pos).w,d0
    addi.w #$10,d0
    cmp.w d1,d0 ; has Sonic touched the left boundary?
    bhi.s Sonic_Boundary_Sides ; if yes, branch[/68k]
    Change this routine so it looks like this:
    [68k]; loc_1A974:
    Sonic_LevelBound:
    moveq #0,d2
    move.l x_pos(a0),d1
    smi.b d2 ; Set d2 if player on position > 32767
    add.w d2,d2 ; Move bit up
    move.w x_vel(a0),d0
    spl.b d2 ; Set if speed is positive
    add.w d2,d2 ; Move bit up
    ext.l d0
    asl.l #8,d0
    add.l d0,d1
    spl.b d2 ; Set if position+speed is < 32768
    move.w (Camera_Min_X_pos).w,d0
    addi.w #$10,d0
    tst.w d2 ; If d2 is zero, we had an underflow of position
    beq.s Sonic_Boundary_Sides
    swap d1
    cmp.w d1,d0 ; has player touched the left boundary?
    bhi.s Sonic_Boundary_Sides ; if yes, branch[/68k]
    Now find the routine "Tails_LevelBound" and do the same. From now on, no matter how much speed you gain, you can never go past the left boundary of the screen and do a level wrap.

    Sonic 3 & Knuckles
    Find the function "Player_Check_Screen_Boundaries"; it looks like this:
    [68k]Player_Check_Screen_Boundaries:

    move.l $10(a0),d1
    move.w $18(a0),d0
    ext.l d0
    asl.l #8,d0
    add.l d0,d1
    swap d1
    move.w (Camera_min_X_pos).w,d0
    addi.w #$10,d0
    cmp.w d1,d0
    bhi.s loc_11732[/68k]
    Now change it to look like this:
    [68k]Player_Check_Screen_Boundaries:

    moveq #0,d2
    move.l $10(a0),d1
    smi.b d2 ; Set d2 if player on position > 32767
    add.w d2,d2 ; Move bit up
    move.w $18(a0),d0
    spl.b d2 ; Set if speed is positive
    add.w d2,d2 ; Move bit up
    ext.l d0
    asl.l #8,d0
    add.l d0,d1
    spl.b d2 ; Set if position+speed is < 32768
    move.w (Camera_min_X_pos).w,d0
    addi.w #$10,d0
    tst.w d2 ; If d2 is zero, we had an underflow of position
    beq.s loc_11732
    swap d1
    cmp.w d1,d0
    bhi.s loc_11732[/68k]
    Now find the routine "Tails_Check_Screen_Boundaries" and do the same. You are done.

    So, what is going on?
    When computing the position to compare against the left boundary, if the speed is negative (I.e., to the left) and it is larger, in magnitude, than the current X position, applying the speed to the position causes the result to become negative, effectively becoming a large positive number. When compared to the minimum camera X + 10, it is considered a valid value. The additional code checks for this underflow in the position, and prevents it from happening.