How to add Slow Ducking into Sonic 2

Discussion in 'Tutorials' started by TheFieldWarrior, Mar 18, 2019.

  1. TheFieldWarrior

    TheFieldWarrior Warrior of the Fields Member

    Joined:
    Oct 9, 2015
    Messages:
    95
    Location:
    United Kingdom
    Hi Everyone, this is a guide on adding Sonic 3 & Knuckles' Slow Ducking mechanic into Sonic 2. This guide will be using the GitHub disassembly but if you're using the 2007 Xenowhirl disassembly then changes shouldn't be too difficult as long as you're aware of the label names.

    This is my first guide and I am still a stranger to ASM so if my explanations come off wrong please point out the mistakes. I want to give a shoutout to Fred; the creator of an upcoming S3K hack called Sonic 3 Unlocked, on his Sonic 3 Unlocked blog he highlighted an issue with Knuckles being unable to Slow Duck in Sonic 2 and explained the differences between S2 and S3K's ducking mechanics on his blog.


    What is Slow Ducking?

    Slow Ducking is the name given to the ducking mechanic in Sonic & Knuckles as well as Sonic 3 & Knuckles (Not Sonic 3 Alone), this gives players more leniency when ducking allowing them to Spin Dash without needing to come to a dead stop, one side effect this has on Knuckles is that he can duck as soon as he lands from gliding both from when he lands on the ground and when he slides across the floor.


    What we need to do to get Slow Ducking

    We need to alter the rolling code to match Sonic 3 and Knuckles' rolling code, this involves changing a few instructions, rearranging certain parts of the code and adding two new subroutines. Let's hop to it!


    Step 1: Setting up the controls for ducking/rolling

    First you'll need to head to Sonic_Roll and change this piece of code:

    Code:
    Sonic_Roll:
    
        if status_sec_isSliding = 7
        tst.b    status_secondary(a0)
       
        bmi.s    Obj01_NoRoll
        else
        btst    #status_sec_isSliding,status_secondary(a0)
        bne.s    Obj01_NoRoll
        endif
        mvabs.w    inertia(a0),d0
        cmpi.w    #$80,d0        ; is Sonic moving at $80 speed or faster?
        blo.s    Obj01_NoRoll    ; if not, branch
        move.b    (Ctrl_1_Held_Logical).w,d0
        andi.b    #button_left_mask|button_right_mask,d0 ; is left/right being pressed?
        bne.s    Obj01_NoRoll    ; if yes, branch
        btst    #button_down,(Ctrl_1_Held_Logical).w ; is down being pressed?
        bne.s    Obj01_ChkRoll            ; if yes, branch
    

    To this:

    Code:
    Sonic_Roll:
        tst.b     status_secondary(a0)
        bmi.s     Obj01_NoRoll
        move.b     (Ctrl_1_Held_Logical).w,d0
        andi.b     #button_left_mask|button_right_mask,d0 ; is left/right being pressed?
        bne.s     Obj01_NoRoll    ; if yes, branch
        btst     #button_down,(Ctrl_1_Held_Logical).w ; is down being pressed?
        beq.s    Obj01_ChkWalk
        move.w   inertia(a0),d0
        bpl.s    Obj01_ChkStatus
        neg.w    d0

    As you can see we've moved the control checks close to the beginning of the code, changed some instructions and removed some lines of code that we don't need for this section, because of this Sonic's speed is only checked when the player presses down without pressing left or right. We've pointed towards two subroutines called Obj01_ChkWalk and Obj01_ChkStatus. These are new subroutines that we need to make.


    Step 2: Creating the new subroutines

    Below Sonic_Roll add this:


    Code:
    Obj01_ChkStatus:
         cmpi.w    #$100,d0        ; is Sonic moving at $100 speed or faster?
         bhs.s    Obj01_ChkRoll    ; if not, branch
         move.b #AniIDSonAni_Duck,anim(a0) ; use ducking animation

    Now below Obj01_NoRoll add this:


    Code:
    Obj01_ChkWalk:
         cmpi.b #AniIDSonAni_Duck,anim(a0)
         bne.s Obj01_NoRoll
         move.b #AniIDSonAni_Walk,anim(a0)
         rts

    The first new subroutine checks to see if Sonic's speed is equal or greater than 1.0 pixels per frame and if so it will branch to Obj01_ChkRoll. The second new subroutine is responsible for getting that sliding duck, if you aren't ducking then it will play Sonic's walking animation.

    And that will be it as the the last few parts of the rolling code don't need any alterations so you can go ahead and build the ROM, Sonic will now do a sliding duck if his speed is below 1.0 pixels. There is one difference between our new code and the S3K rolling code, we can Slow Duck on objects (such as the EHZ bridges) which 3&K has a check for, this check forces Sonic to come to a dead stop to duck if he's standing on an object, but we don't need that (plus I prefer it like this anyway).


    We aren't done yet as we need to apply this new code to Tails, Knuckles (assuming you've already ported him) and any other character you've added to your hack


    Step 3: Allowing others to Slow Duck

    With Tails, Knuckles and whoever you've added to your hack you'll need to head to their rolling codes which are Tails_Roll, Knuckles_Roll and NewCharacter_Roll. NewCharacter is for the name of whoever you added to the hack, for example if you have Shadow it would be Shadow_Roll. Then with our new code you'll need to make the following alterations:

    1. All of the subroutine names that have Obj01 as part of their name need to have the "01" ID number changed to the Object ID number of your alternate characters. In Tails' case it's "02" (e.g. Obj02ChkStatus)

    2. The animation labels for Tails in our new code need to be #AniIDTailsAni_Walk,anim(a0) and #AniIDTailsAni_Duck,anim(a0). Alternatively you can just simply write #8,$1C(a0) for ducking and #0,$1C(a0) for walking which I would recommend doing for Knuckles and your new character(s)

    3. For Tails and your alternate character if they are a sidekick make sure (Ctrl_1_Held_Logical) is changed to (Ctrl_2_Held_Logical). This will prevent your sidekick from rolling/ducking simultaneously with the leader


    Once you've applied the new code and changes to all of the characters build the ROM and now everyone can Slow Duck. Have fun with your new ducking mechanic, be sure to credit me if you use this guide. That's all for now.
     
    Last edited: Mar 20, 2019
  2. ADudeCalledLeo

    ADudeCalledLeo I'll make a ROM hack one of these days... Member

    Joined:
    Oct 21, 2017
    Messages:
    13
    Location:
    Null Space
    This can actually be done in a much more simple way. Change this:
    Code:
       mvabs.w    inertia(a0),d0
       cmpi.w    #$80,d0        ; is Sonic moving at $80 speed or faster?
       blo.s    Obj01_NoRoll    ; if not, branch
       move.b    (Ctrl_1_Held_Logical).w,d0
       andi.b    #button_left_mask|button_right_mask,d0 ; is left/right being pressed?
       bne.s    Obj01_NoRoll    ; if yes, branch
       btst    #button_down,(Ctrl_1_Held_Logical).w ; is down being pressed?
       bne.s    Obj01_ChkRoll            ; if yes, branch
    To this:
    Code:
       btst   #button_down,(Ctrl_1_Held_Logical).w   ; is down being pressed?
       beq.s   Obj01_NoRoll               ; if not, branch
       move.b   (Ctrl_1_Held_Logical).w,d0
       andi.b   #button_left_mask|button_right_mask,d0   ; is left/right being pressed?
       bne.s   Obj01_NoRoll               ; if yes, branch
       mvabs.w   inertia(a0),d0
       cmpi.w   #$100,d0               ; is Sonic moving at $100 speed or faster?
       bhi.s   Obj01_ChkRoll               ; if yes, branch
       move.b   #AniIDSonAni_Duck,anim(a0)       ; use "ducking" animation
    Repeat for other characters.
     
  3. Kilo

    Kilo Foxy Fren Exiled

    Joined:
    Oct 9, 2017
    Messages:
    391
    Location:
    A warm and lovely place~
    Here's one for the Hivebrain ASM68K Sonic 1 disassembly, based on @ADudeCalledLeo 's version of the slow duck
    Replace all of loc_13392 with this:
    Code:
            btst    #1,($FFFFF602).w    ; is down being pressed?
            beq.s    Obj01_NoRoll    ; if not, branch
            move.b    ($FFFFF602).w,d0
            andi.b    #$C,d0    ; is left/right being pressed?
            bne.s    Obj01_NoRoll    ; if yes, branch
            move.w    $14(a0),d0
            bpl.s    @cont ; If ground speed is positive, continue
            neg.w    d0 ; If not, negate it to get the absolute value
    
    @cont
            cmpi.w    #$100,d0    ; is Sonic moving at $100 speed or faster?
            bhi.s    Obj01_ChkRoll    ; if yes, branch
            move.b    #8,$1C(a0)    ; use "ducking" animation
    The mvabs (Move absolute value) macro doesn't exist in Sonic 1, so I essentially recreated it in the routine.
     
    Last edited: Jan 26, 2020
    EddyTF and ProjectFM like this.
  4. tilk

    tilk Active Member Member

    Joined:
    Feb 2, 2012
    Messages:
    30
    SVN/GIT users of the Sonic 1 disassembly: you want to go to _incObj\SonicRoll
    And replace SonicRoll with the following:
    Code:
    Sonic_Roll:
            btst    #bitDn,(v_jpadhold2).w    ; is down being pressed?
            beq.s    .noroll            ; if not, branch
            move.b    (v_jpadhold2).w,d0
            andi.b    #btnL+btnR,d0    ; is left/right being pressed?
            bne.s    .noroll        ; if yes, branch
            move.w    obInertia(a0),d0
            bpl.s    .ispositive
            neg.w    d0
    .ispositive:
            cmpi.w    #$100,d0        ; is Sonic moving at $100 speed or faster?
            bhi.s    Sonic_ChkRoll        ; if yes, branch
            move.b    #id_Duck,anim(a0)    ; use "ducking" animation
    (if you're using asm68k, replace " . " with "@" )
     
    EddyTF likes this.