Actions

SCHG How-to

Difference between revisions of "Add the Air Roll/Flying Spin Attack"

From Sonic Retro

(Created page with "'''NOTE: This guide isn't just copy-paste. This is intended to teach more than just how to port the Air Roll.''' '''EDIT (SSRG, 12/6/19): Removed a mention of how putting the...")
 
m
Line 3: Line 3:
 
'''EDIT (SSRG, 12/6/19): Removed a mention of how putting the bsr just anywhere in Obj01_MdJump/Obj01_MdJump2 would screw up the jump, and moved the placememnt of the bsr, based off of Iso Kilo's observations.'''
 
'''EDIT (SSRG, 12/6/19): Removed a mention of how putting the bsr just anywhere in Obj01_MdJump/Obj01_MdJump2 would screw up the jump, and moved the placememnt of the bsr, based off of Iso Kilo's observations.'''
  
As you likely know, whenever you jump on a spring in a Sonic game, you enter a vulnerable state. However, in Sonic Triple Trouble, you could press a jump button while in the spring animation to curl up into a ball:
+
As you likely know, whenever you jump on a spring in a Sonic game, you enter a vulnerable state. However, in ''[[Sonic Triple Trouble]]'', you could press a jump button while in the spring animation to curl up into a ball:
  
 
[[File:Flying_Spin_Attack.png]]
 
[[File:Flying_Spin_Attack.png]]
Line 103: Line 103:
 
Now, we don't want Sonic to be able to Air Roll if he '''isn't in the air''', correct?  
 
Now, we don't want Sonic to be able to Air Roll if he '''isn't in the air''', correct?  
 
Luckily, there's a bitfield in the SSTs often known as ''status''. If bit one, in this case, is enabled, that means Sonic's in the air. Now, you may just think, "I can do what I just did with $1C!" That isn't the case. Since $22/status is a bitfield, we have to use a command known as btst ('''B'''i'''t'''e'''st''').
 
Luckily, there's a bitfield in the SSTs often known as ''status''. If bit one, in this case, is enabled, that means Sonic's in the air. Now, you may just think, "I can do what I just did with $1C!" That isn't the case. Since $22/status is a bitfield, we have to use a command known as btst ('''B'''i'''t'''e'''st''').
 +
[[Category:SCHG How-tos (Sonic the Hedgehog (16-bit))]]

Revision as of 13:20, 6 December 2019

NOTE: This guide isn't just copy-paste. This is intended to teach more than just how to port the Air Roll.

EDIT (SSRG, 12/6/19): Removed a mention of how putting the bsr just anywhere in Obj01_MdJump/Obj01_MdJump2 would screw up the jump, and moved the placememnt of the bsr, based off of Iso Kilo's observations.

As you likely know, whenever you jump on a spring in a Sonic game, you enter a vulnerable state. However, in Sonic Triple Trouble, you could press a jump button while in the spring animation to curl up into a ball:

Flying Spin Attack.png

Now, this isn't in Sonic 1, 2, or 3 & Knuckles. However, this guide can show you how to add this move to Sonic 1's Hivebrain disasm, so that you can do this in Sonic 1.

NOTE: For those not using the S1 Hivebrain disasm or S1 at all, porting should be easy. Make sure to look for the equivalent addresses and routines.

Now, we want the code to be gone through whenever Sonic is setting his jumping data. As such, putting it in Obj01_MdNormal wouldn't work for our purposes. Instead, we should put it in Obj01_MdJump and Obj01_MdJump2.

This is Obj01_MdJump:

Obj01_MdJump:                ; XREF: Obj01_Modes
        bsr.w    Sonic_JumpHeight
        bsr.w    Sonic_ChgJumpDir
        bsr.w    Sonic_LevelBound
        jsr    ObjectFall
        btst    #6,$22(a0)
        beq.s    loc_12E5C
        subi.w    #$28,$12(a0)

loc_12E5C:
        bsr.w    Sonic_JumpAngle
        bsr.w    Sonic_Floor
        rts

And this is Obj01_MdJump2:

Obj01_MdJump2:                ; XREF: Obj01_Modes
        bsr.w    Sonic_JumpHeight
        bsr.w    Sonic_ChgJumpDir
        bsr.w    Sonic_LevelBound
        jsr    ObjectFall
        btst    #6,$22(a0)
        beq.s    loc_12EA6
        subi.w    #$28,$12(a0)

loc_12EA6:
        bsr.w    Sonic_JumpAngle
        bsr.w    Sonic_Floor
        rts

While there are multiple places within this subroutine to place our branch, it makes the most sense to put it below the label itself. So, place this:

        bsr.w   Sonic_AirRoll

Right under the labels for Obj01_MdJump and Obj01_MdJump2.

Now, bsr and jsr are a special kind of branch. After the code it branches to is finished, it'll automatically return to the point where we branched from and continue from right below it. This will be important for the format of our Air Roll code.

So, we've created a branch to a new subroutine. The problem is, it doesn't exist! If you try to build right now, you'll get an error. Now, we have to create the subroutine itself.

Put the proper label within Sonic's code, I've personally put it below Sonic_JumpHeight's function.

Now, we have to actually code the action. We want the code to only execute if A/B/C is pressed, right?

Now, this tutorial should show you how to utilize button presses, so check it out real quick, because I'd rather not copy what Selbi had to say.

Now that you are back, you should have created something like this:

Sonic_AirRoll:
        move.b    ($FFFFF603).w,d0 ; Move $FFFFF603 to d0
        andi.b    #$70,d0 ; Has A/B/C been pressed?
        bne.w    AirRoll_Checks ; If so, branch.

Now, we don't want this code being all there is, and we don't want it moving on to whatever is below it, especially if that's what is being branched to by the button press, correct? This is where rts (Return To Subroutine) comes in handy. The name should hint at it's function. Now, rts returns to the point where the current routine/subroutine was branched from, and continues code execution from there, much like what bsr and jsr automatically do. So, in order to keep the game from executing code it shouldn't, we should add a rts to the bottom of Sonic_AirRoll:

Sonic_AirRoll:
        move.b    ($FFFFF603).w,d0 ; Move $FFFFF603 to d0
        andi.b    #$70,d0 ; Has A/B/C been pressed?
        bne.w    AirRoll_Checks ; If so, branch.
        rts ; Return.

Now, there's another new subroutine being branched to! So, create that label, AirRoll_Checks, right below the rts. This is how the Sonic_AirRoll function should look:

Sonic_AirRoll:
        move.b    ($FFFFF603).w,d0 ; Move $FFFFF603 to d0
        andi.b    #$70,d0 ; Has A/B/C been pressed?
        bne.w    AirRoll_Checks ; If so, branch.
        rts ; Return.
 
AirRoll_Checks:

Now, we don't want the code to execute if Sonic's already in a ball, right? Luckily, in RAM, there's a SST which stores the current object's animation, which just so happens to be Sonic! Sonic's animation ID for rolling in Sonic 1 is #$2. The SST in question is $1C. IF you know what's about to happen, good job, you already know of the cmp (Compare) instruction. This instruction compares one thing to another thing. Using this, we can perform a branch using beq (Branch if Equal) and bne (Branch if Not Equal). This is what the end result should look like:

AirRoll_Checks:
        cmpi.b    #2,$1C(a0) ; Is animation 2 active?
        bne.s   AirRoll_Set ; If not, branch.

If you want the move to, just like in Triple Trouble, only be able to occur if Sonic's in his spring animation, change the animation ID to the spring animation (#$10, IIRC) and invert the branch (beq -> bne, bne -> beq).

Now, we don't want Sonic to be able to Air Roll if he isn't in the air, correct? Luckily, there's a bitfield in the SSTs often known as status. If bit one, in this case, is enabled, that means Sonic's in the air. Now, you may just think, "I can do what I just did with $1C!" That isn't the case. Since $22/status is a bitfield, we have to use a command known as btst (Bitest).