Actions

Difference between revisions of "Sandbox"

From Sonic Retro

Line 655: Line 655:
 
rts
 
rts
 
; End of function Obj4C_MdNormal
 
; End of function Obj4C_MdNormal
 +
</asm>
 
And we're done with the Obj4C_MdNormal_Checks subroutine! Now we can get the rest of the code in without worrying about errors, provided you're following this guide correctly.
 
And we're done with the Obj4C_MdNormal_Checks subroutine! Now we can get the rest of the code in without worrying about errors, provided you're following this guide correctly.
 
====Step 4: Part 3: Obj4C_MdAir====
 
====Step 4: Part 3: Obj4C_MdAir====

Revision as of 10:23, 13 January 2013

The following guide was made by Tailsguy24, and is not yet complete. DO NOT edit/delete it for any reason.

How to Port Knuckles into Sonic 2

It surprises me that nobody else took up responsibility for making this guide, considering I, as a major fan of hacks, have seen Knuckles implemented in Sonic 2 on more than one occasion. Today, I'll be explaining how you, too, can implement Knuckles in your Sonic 2 hack.

What You'll Need

  • This guide (no duh, really)
  • The Hg disassembly of Sonic 2
  • The one known disassembly of Knuckles in Sonic 2, found on the long list of disassemblies. [1]
  • The ConTEXT text editor (because Notepad will take WAY too long to process anything)
  • Your favorite Genesis emulator (I recommend Kega Fusion but you can use any Genesis emulator you'd like)

IMPORTANT NOTE

DO NOT try to rebuild the ROM once you've started this guide or you will get build errors.

Also, there is quite a lot of code added in this tutorial and it will make the ASM file's size (and to an extent, the ROM's size) a lot bigger than they were before. You may want to consider porting Sonic 1's sound driver to Sonic 2 first, as it can take the amount of data shifting caused by extending the level index past $10 in Sonic 2 and still work properly.

Step 1: Creating the Knuckles object

First, open up s2.asm in ConTEXT and search for "dc.l ObjNull." This should come up: <asm>

               dc.l ObjNull ; Obj4C
               dc.l ObjNull ; Obj4D
               dc.l ObjNull ; Obj4E
               dc.l ObjNull ; Obj4F

</asm> Change this line: <asm>

               dc.l ObjNull ; Obj4C

</asm>

To this: <asm>

               dc.l Obj4C   ; Knuckles

</asm>

We've created our Knuckles object. Now let's get started.

Step 2: Creating the offset table

Now that you have created your Knuckles object, go to whatever folder you saved the Knuckles in Sonic 2 disassembly to, open s2k.asm in ConTEXT, and scroll down or search until you find the following code: <asm> Obj01_Index: dc.w Obj01_Init-Obj01_Index  ; 0 ; ... dc.w Obj01_Control-Obj01_Index  ; 1 dc.w Obj01_Hurt-Obj01_Index  ; 2 dc.w Obj01_Dead-Obj01_Index  ; 3 dc.w Obj01_Gone-Obj01_Index  ; 4 dc.w Obj01_Respawning-Obj01_Index ; 5 </asm> Back in s2.asm, copy and paste the following piece of code above the description of the Masher object: <asm>

----------------------------------------------------------------------------
Object 01 - Knuckles
----------------------------------------------------------------------------

Obj01: ; a0=character tst.w (Debug_placement_mode).w ; is debug mode being used? beq.s Obj01_Normal ; if not, branch jmp (DebugMode).l

---------------------------------------------------------------------------
loc_19F5C

Obj01_Normal: moveq #0,d0 move.b routine(a0),d0 move.w Obj01_Index(pc,d0.w),d1 jmp Obj01_Index(pc,d1.w)

End of function Obj01
----------------------------------------------------------------------------

</asm> Now copy the code I mentioned earlier in this step, and paste it below the code displayed above. Then, replace all of the "dc.w"'s with "offsetTableEntry.w"'s, delete the "-Obj01_Index" on the end of each line, move all of the entries down one line, add "offsetTable" to the top, and change all of the 01's in the whole section of code to 4C's. If you're following this guide correctly, your code should look like this: <asm>

----------------------------------------------------------------------------
Object 4C - Knuckles
----------------------------------------------------------------------------

Obj4C: ; a0=character tst.w (Debug_placement_mode).w ; is debug mode being used? beq.s Obj4C_Normal ; if not, branch jmp (DebugMode).l

---------------------------------------------------------------------------
loc_19F5C

Obj4C_Normal: moveq #0,d0 move.b routine(a0),d0 move.w Obj4C_Index(pc,d0.w),d1 jmp Obj4C_Index(pc,d1.w)

End of function Obj4C
----------------------------------------------------------------------------

Obj4C_Index: offsetTable

       	offsetTableEntry.w Obj4C_Init           	  ; 0

offsetTableEntry.w Obj4C_Control  ; 2 offsetTableEntry.w Obj4C_Hurt  ; 4 offsetTableEntry.w Obj4C_Dead  ; 6 offsetTableEntry.w Obj4C_Gone  ; 8 offsetTableEntry.w Obj4C_Respawning  ; $A ... </asm> Now that THAT is done and over with, let's continue to importing Knuckles' many modes (or whatever you people call them).

Step 3: Obj4C_Init

Going back to s2k.asm , you should see this piece of code right below the code I mentioned earlier in Step 2: <asm>

---------------------------------------------------------------------------

Obj01_Init:  ; ... addq.b #2,$24(a0) move.b #$13,$16(a0) move.b #9,$17(a0) move.l #SK_Map_Knuckles,4(a0)  ; SK_Map_Knuckles move.b #2,$18(a0) move.b #$18,$19(a0) move.b #4,1(a0) move.w #$600,($FFFFF760).w move.w #$C,($FFFFF762).w move.w #$80,($FFFFF764).w tst.b ($FFFFFE30).w bne.s Obj01_Init_Continued move.w #$780,2(a0) bsr.w Adjust2PArtPointer2_Useless move.b #$C,$3E(a0) move.b #$D,$3F(a0) move.w 8(a0),($FFFFFE32).w move.w $C(a0),($FFFFFE34).w move.w 2(a0),($FFFFFE3C).w move.w $3E(a0),($FFFFFE3E).w

Obj01_Init_Continued:  ; ... move.b #0,$2C(a0) move.b #4,$2D(a0) move.b #0,($FFFFFE19).w move.b #$1E,$28(a0) sub.w #$20,8(a0) add.w #4,$C(a0) move.w #0,($FFFFEED2).w move.w #$3F,d2

loc_3153EC:  ; ... bsr.w Knuckles_RecordPositions subq.w #4,a1 move.l #0,(a1) dbf d2,loc_3153EC add.w #$20,8(a0) sub.w #4,$C(a0) </asm> All we need to do is copy this, paste it below our already ported code, and change all of the 01's to 4C's. Now you should have this below the offset table: <asm>

---------------------------------------------------------------------------

Obj4C_Init:  ; ... addq.b #2,$24(a0) move.b #$13,$16(a0) move.b #9,$17(a0) move.l #SK_Map_Knuckles,4(a0)  ; SK_Map_Knuckles move.b #2,$18(a0) move.b #$18,$19(a0) move.b #4,1(a0) move.w #$600,($FFFFF760).w move.w #$C,($FFFFF762).w move.w #$80,($FFFFF764).w tst.b ($FFFFFE30).w bne.s Obj4C_Init_Continued move.w #$780,2(a0) bsr.w Adjust2PArtPointer2_Useless move.b #$C,$3E(a0) move.b #$D,$3F(a0) move.w 8(a0),($FFFFFE32).w move.w $C(a0),($FFFFFE34).w move.w 2(a0),($FFFFFE3C).w move.w $3E(a0),($FFFFFE3E).w

Obj4C_Init_Continued:  ; ... move.b #0,$2C(a0) move.b #4,$2D(a0) move.b #0,($FFFFFE19).w move.b #$1E,$28(a0) sub.w #$20,8(a0) add.w #4,$C(a0) move.w #0,($FFFFEED2).w move.w #$3F,d2

loc_3153EC:  ; ... bsr.w Knuckles_RecordPositions subq.w #4,a1 move.l #0,(a1) dbf d2,loc_3153EC add.w #$20,8(a0) sub.w #4,$C(a0) </asm>

Step 4: Obj4C_Control

This one is the most important. It actually makes up approximately 90% of the code for Knuckles. Therefore, we definitely need to port this.

Step 4: Part 1: Starting off

First, we have to modify the Obj01_Modes offset table from s2k.asm so we can use it for our Knuckles. Below the code mentioned above, you should see this: <asm> Obj01_Control:  ; ... tst.w ($FFFFFFDA).w beq.s loc_315422 btst #4,($FFFFF605).w beq.s loc_315422 move.w #1,($FFFFFE08).w clr.b ($FFFFF7CC).w rts

---------------------------------------------------------------------------

loc_315422:  ; ... tst.b ($FFFFF7CC).w bne.s loc_31542E move.w ($FFFFF604).w,($FFFFF602).w

loc_31542E:  ; ... btst #0,$2A(a0) beq.s loc_31543E move.b #0,$21(a0) bra.s loc_315450

---------------------------------------------------------------------------

loc_31543E:  ; ... moveq #0,d0 move.b $22(a0),d0

and.w #6,d0 move.w Obj01_Modes(pc,d0.w),d1 jsr Obj01_Modes(pc,d1.w)

loc_315450:  ; ... cmp.w #$FF00,($FFFFEECC).w bne.s loc_31545E and.w #$7FF,$C(a0)

loc_31545E:  ; ... bsr.s Knuckles_Display bsr.w Knuckles_Super bsr.w Knuckles_RecordPositions bsr.w Knuckles_Water move.b ($FFFFF768).w,$36(a0) move.b ($FFFFF76A).w,$37(a0) tst.b ($FFFFF7C7).w beq.s loc_31548A tst.b $1C(a0) bne.s loc_31548A move.b $1D(a0),$1C(a0)

loc_31548A:  ; ... bsr.w Knuckles_Animate tst.b $2A(a0) bmi.s loc_31549A jsr TouchResponse

loc_31549A:  ; ... bra.w LoadKnucklesDynPLC

---------------------------------------------------------------------------

Obj01_Modes: dc.w Obj01_MdNormal-Obj01_Modes  ; 0 ; ... dc.w Obj01_MdAir-Obj01_Modes  ; 1 dc.w Obj01_MdRoll-Obj01_Modes  ; 2 dc.w Obj01_MdJump-Obj01_Modes  ; 3 </asm> Do the same thing that was done with the code in Step 1. It should now look like this: <asm> Obj4C_Control:  ; ... tst.w ($FFFFFFDA).w beq.s loc_315422 btst #4,($FFFFF605).w beq.s loc_315422 move.w #1,($FFFFFE08).w clr.b ($FFFFF7CC).w rts

---------------------------------------------------------------------------

loc_315422:  ; ... tst.b ($FFFFF7CC).w bne.s loc_31542E move.w ($FFFFF604).w,($FFFFF602).w

loc_31542E:  ; ... btst #0,$2A(a0) beq.s loc_31543E move.b #0,$21(a0) bra.s loc_315450

---------------------------------------------------------------------------

loc_31543E:  ; ... moveq #0,d0 move.b $22(a0),d0 and.w #6,d0 move.w Obj4C_Modes(pc,d0.w),d1 jsr Obj4C_Modes(pc,d1.w)

loc_315450:  ; ... cmp.w #$FF00,($FFFFEECC).w bne.s loc_31545E and.w #$7FF,$C(a0)

loc_31545E:  ; ... bsr.s Knuckles_Display bsr.w Knuckles_Super bsr.w Knuckles_RecordPositions bsr.w Knuckles_Water move.b ($FFFFF768).w,$36(a0) move.b ($FFFFF76A).w,$37(a0) tst.b ($FFFFF7C7).w beq.s loc_31548A tst.b $1C(a0) bne.s loc_31548A move.b $1D(a0),$1C(a0)

loc_31548A:  ; ... bsr.w Knuckles_Animate tst.b $2A(a0) bmi.s loc_31549A jsr TouchResponse

loc_31549A:  ; ... bra.w LoadKnucklesDynPLC

---------------------------------------------------------------------------

Obj4C_Modes: offsetTable

               offsetTableEntry.w Obj4C_MdNormal_Checks  ; 0 ; not airborne or rolling

offsetTableEntry.w Obj4C_MdAir  ; 2 ; airborne offsetTableEntry.w Obj4C_MdRoll  ; 4 ; rolling offsetTableEntry.w Obj4C_MdJump  ; 6 ; jumping </asm>

Step 4: Part 2: Obj4C_MdNormal

Back to s2k.asm! The next bit of code you'll want to find is this: <asm>

=============== S U B R O U T I N E =======================================


Knuckles_Display:  ; ... move.w $30(a0),d0 beq.s Obj01_Display subq.w #1,$30(a0) lsr.w #3,d0 bcc.s Obj01_CheckInvincibility

Obj01_Display:  ; ... jsr DisplaySprite

Obj01_CheckInvincibility:  ; ... btst #1,$2B(a0) beq.s Obj01_CheckSpeedShoes tst.w $32(a0) beq.s Obj01_CheckSpeedShoes subq.w #1,$32(a0) bne.s Obj01_CheckSpeedShoes tst.b ($FFFFF7AA).w bne.s Obj01_RemoveInvincibility cmp.b #$C,$28(a0) bcs.s Obj01_RemoveInvincibility move.w ($FFFFFF90).w,d0 jsr PlayMusic

Obj01_RemoveInvincibility:  ; ... bclr #1,$2B(a0)

Obj01_CheckSpeedShoes:  ; ... btst #2,$2B(a0) beq.s Obj01_ExitCheck tst.w $34(a0) beq.s Obj01_ExitCheck subq.w #1,$34(a0) bne.s Obj01_ExitCheck move.w #$600,($FFFFF760).w move.w #$C,($FFFFF762).w move.w #$80,($FFFFF764).w tst.b ($FFFFFE19).w beq.s Obj01_RemoveSpeedShoes move.w #$800,($FFFFF760).w move.w #$18,($FFFFF762).w move.w #$C0,($FFFFF764).w

Obj01_RemoveSpeedShoes:  ; ... bclr #2,$2B(a0) move.w #$FC,d0 jmp PlayMusic

---------------------------------------------------------------------------

Obj01_ExitCheck:  ; ... rts

End of function Knuckles_Display


=============== S U B R O U T I N E =======================================


Knuckles_RecordPositions:  ; ... move.w ($FFFFEED2).w,d0 lea ($FFFFE500).w,a1 lea (a1,d0.w),a1 move.w 8(a0),(a1)+ move.w $C(a0),(a1)+ addq.b #4,($FFFFEED3).w lea ($FFFFE400).w,a1 lea (a1,d0.w),a1 move.w ($FFFFF602).w,(a1)+ move.w $22(a0),(a1)+ rts

End of function Knuckles_RecordPositions


=============== S U B R O U T I N E =======================================


Knuckles_Water:  ; ... tst.b ($FFFFF730).w bne.s Obj01_InWater

return_31556C:  ; ... rts

---------------------------------------------------------------------------

Obj01_InWater:  ; ... move.w ($FFFFF646).w,d0 cmp.w $C(a0),d0 bge.s Obj01_OutWater bset #6,$22(a0) bne.s return_31556C move.l a0,a1 bsr.w ResumeMusic move.b #$A,($FFFFD080).w move.b #$81,($FFFFD0A8).w move.l a0,($FFFFD0BC).w move.w #$300,($FFFFF760).w move.w #6,($FFFFF762).w move.w #$40,($FFFFF764).w tst.b ($FFFFFE19).w beq.s loc_3155C0 move.w #$400,($FFFFF760).w move.w #$C,($FFFFF762).w move.w #$60,($FFFFF764).w

loc_3155C0:  ; ... asr $10(a0) asr $12(a0) asr $12(a0) beq.s return_31556C move.w #$100,($FFFFD11C).w move.w #$AA,d0 jmp PlaySound

---------------------------------------------------------------------------

Obj01_OutWater:  ; ... bclr #6,$22(a0) beq.s return_31556C move.l a0,a1 bsr.w ResumeMusic move.w #$600,($FFFFF760).w move.w #$C,($FFFFF762).w move.w #$80,($FFFFF764).w tst.b ($FFFFFE19).w beq.s loc_315616 move.w #$800,($FFFFF760).w move.w #$18,($FFFFF762).w move.w #$C0,($FFFFF764).w

loc_315616:  ; ... cmp.b #4,$24(a0) beq.s loc_315622 asl $12(a0)

loc_315622:  ; ... tst.w $12(a0) beq.w return_31556C move.w #$100,($FFFFD11C).w move.l a0,a1 bsr.w ResumeMusic cmp.w #$F000,$12(a0) bgt.s loc_315644 move.w #$F000,$12(a0)

loc_315644:  ; ... move.w #$AA,d0 jmp PlaySound

End of function Knuckles_Water


=============== S U B R O U T I N E =======================================


Obj01_MdNormal:  ; ... bsr.w Knuckles_Spindash bsr.w Knuckles_Jump bsr.w Knuckles_SlopeResist bsr.w Knuckles_Move bsr.w Knuckles_Roll bsr.w Knuckles_LevelBoundaries jsr ObjectMove  ; AKA SpeedToPos in Sonic 1 bsr.w AnglePos bsr.w Knuckles_SlopeRepel rts

End of function Obj01_MdNormal

Put that below the code we've already ported, then go through it and replace each and every "Obj01" with "Obj4C." You should get this: <asm>

=============== S U B R O U T I N E =======================================


Knuckles_Display:  ; ... move.w $30(a0),d0 beq.s Obj4C_Display subq.w #1,$30(a0) lsr.w #3,d0 bcc.s Obj4C_CheckInvincibility

Obj4C_Display:  ; ... jsr DisplaySprite

Obj4C_CheckInvincibility:  ; ... btst #1,$2B(a0) beq.s Obj4C_CheckSpeedShoes tst.w $32(a0) beq.s Obj4C_CheckSpeedShoes subq.w #1,$32(a0) bne.s Obj4C_CheckSpeedShoes tst.b ($FFFFF7AA).w bne.s Obj4C_RemoveInvincibility cmp.b #$C,$28(a0) bcs.s Obj4C_RemoveInvincibility move.w ($FFFFFF90).w,d0 jsr PlayMusic

Obj4C_RemoveInvincibility:  ; ... bclr #1,$2B(a0)

Obj4C_CheckSpeedShoes:  ; ... btst #2,$2B(a0) beq.s Obj4C_ExitCheck tst.w $34(a0) beq.s Obj4C_ExitCheck subq.w #1,$34(a0) bne.s Obj4C_ExitCheck move.w #$600,($FFFFF760).w move.w #$C,($FFFFF762).w move.w #$80,($FFFFF764).w tst.b ($FFFFFE19).w beq.s Obj4C_RemoveSpeedShoes move.w #$800,($FFFFF760).w move.w #$18,($FFFFF762).w move.w #$C0,($FFFFF764).w

Obj4C_RemoveSpeedShoes:  ; ... bclr #2,$2B(a0) move.w #$FC,d0 jmp PlayMusic

---------------------------------------------------------------------------

Obj4C_ExitCheck:  ; ... rts

End of function Knuckles_Display


=============== S U B R O U T I N E =======================================


Knuckles_RecordPositions:  ; ... move.w ($FFFFEED2).w,d0 lea ($FFFFE500).w,a1 lea (a1,d0.w),a1 move.w 8(a0),(a1)+ move.w $C(a0),(a1)+ addq.b #4,($FFFFEED3).w lea ($FFFFE400).w,a1 lea (a1,d0.w),a1 move.w ($FFFFF602).w,(a1)+ move.w $22(a0),(a1)+ rts

End of function Knuckles_RecordPositions


=============== S U B R O U T I N E =======================================


Knuckles_Water:  ; ... tst.b ($FFFFF730).w bne.s Obj4C_InWater

return_31556C:  ; ... rts

---------------------------------------------------------------------------

Obj4C_InWater:  ; ... move.w ($FFFFF646).w,d0 cmp.w $C(a0),d0 bge.s Obj4C_OutWater bset #6,$22(a0) bne.s return_31556C move.l a0,a1 bsr.w ResumeMusic move.b #$A,($FFFFD080).w move.b #$81,($FFFFD0A8).w move.l a0,($FFFFD0BC).w move.w #$300,($FFFFF760).w move.w #6,($FFFFF762).w move.w #$40,($FFFFF764).w tst.b ($FFFFFE19).w beq.s loc_3155C0 move.w #$400,($FFFFF760).w move.w #$C,($FFFFF762).w move.w #$60,($FFFFF764).w

loc_3155C0:  ; ... asr $10(a0) asr $12(a0) asr $12(a0) beq.s return_31556C move.w #$100,($FFFFD11C).w move.w #$AA,d0 jmp PlaySound

---------------------------------------------------------------------------

Obj4C_OutWater:  ; ... bclr #6,$22(a0) beq.s return_31556C move.l a0,a1 bsr.w ResumeMusic move.w #$600,($FFFFF760).w move.w #$C,($FFFFF762).w move.w #$80,($FFFFF764).w tst.b ($FFFFFE19).w beq.s loc_315616 move.w #$800,($FFFFF760).w move.w #$18,($FFFFF762).w move.w #$C0,($FFFFF764).w

loc_315616:  ; ... cmp.b #4,$24(a0) beq.s loc_315622 asl $12(a0)

loc_315622:  ; ... tst.w $12(a0) beq.w return_31556C

               move.w	#$100,($FFFFD11C).w

move.l a0,a1 bsr.w ResumeMusic cmp.w #$F000,$12(a0) bgt.s loc_315644 move.w #$F000,$12(a0)

loc_315644:  ; ... move.w #$AA,d0 jmp PlaySound

End of function Knuckles_Water


=============== S U B R O U T I N E =======================================


Obj4C_MdNormal:  ; ... bsr.w Knuckles_Spindash bsr.w Knuckles_Jump bsr.w Knuckles_SlopeResist bsr.w Knuckles_Move bsr.w Knuckles_Roll bsr.w Knuckles_LevelBoundaries jsr ObjectMove  ; AKA SpeedToPos in Sonic 1 bsr.w AnglePos bsr.w Knuckles_SlopeRepel rts

End of function Obj4C_MdNormal

</asm> And we're done with the Obj4C_MdNormal_Checks subroutine! Now we can get the rest of the code in without worrying about errors, provided you're following this guide correctly.

Step 4: Part 3: Obj4C_MdAir

Not very complicated, just find this, place it below the ported code and replace each "Obj01" with a "Obj4C." <asm>


=============== S U B R O U T I N E =======================================


Obj01_MdAir:  ; ... tst.b $21(a0) bne.s Obj01_MdAir_Gliding bsr.w Knuckles_JumpHeight bsr.w Knuckles_ChgJumpDir bsr.w Knuckles_LevelBoundaries jsr ObjectMoveAndFall btst #6,$22(a0) beq.s loc_31569C sub.w #$28,$12(a0)

loc_31569C:  ; ... bsr.w Knuckles_JumpAngle bsr.w Knuckles_DoLevelCollision rts

---------------------------------------------------------------------------

Obj01_MdAir_Gliding:  ; ... bsr.w Knuckles_GlideSpeedControl bsr.w Knuckles_LevelBoundaries jsr ObjectMove  ; AKA SpeedToPos in Sonic 1 bsr.w Knuckles_GlideControl

return_3156B8:  ; ... rts

End of function Obj01_MdAir

</asm> You should end up with this: <asm>


=============== S U B R O U T I N E =======================================


Obj4C_MdAir:  ; ... tst.b $21(a0) bne.s Obj4C_MdAir_Gliding bsr.w Knuckles_JumpHeight bsr.w Knuckles_ChgJumpDir bsr.w Knuckles_LevelBoundaries jsr ObjectMoveAndFall btst #6,$22(a0) beq.s loc_31569C sub.w #$28,$12(a0)

loc_31569C:  ; ... bsr.w Knuckles_JumpAngle bsr.w Knuckles_DoLevelCollision rts

---------------------------------------------------------------------------

Obj4C_MdAir_Gliding:  ; ... bsr.w Knuckles_GlideSpeedControl bsr.w Knuckles_LevelBoundaries jsr ObjectMove  ; AKA SpeedToPos in Sonic 1 bsr.w Knuckles_GlideControl

return_3156B8:  ; ... rts

End of function Obj4C_MdAir

</asm> I told you it wasn't complicated.

Step 4: Part 4: Everything having to do with Knuckles' gliding

And we don't even need to change anything. WOOHOO! <asm>

=============== S U B R O U T I N E =======================================


Knuckles_GlideControl:  ; ...

FUNCTION CHUNK AT 00315C40 SIZE 0000003C BYTES

move.b $21(a0),d0 beq.s return_3156B8 cmp.b #2,d0 beq.w Knuckles_FallingFromGlide cmp.b #3,d0 beq.w Knuckles_Sliding cmp.b #4,d0 beq.w Knuckles_Climbing_Wall cmp.b #5,d0 beq.w Knuckles_Climbing_Up

Knuckles_NormalGlide: move.b #$A,$16(a0) move.b #$A,$17(a0) bsr.w Knuckles_DoLevelCollision2 btst #5,($FFFFF7AC).w bne.w Knuckles_BeginClimb move.b #$13,$16(a0) move.b #9,$17(a0) btst #1,($FFFFF7AC).w beq.s Knuckles_BeginSlide move.b ($FFFFF602).w,d0 and.b #$70,d0 bne.s loc_31574C move.b #2,$21(a0) move.b #$21,$1C(a0) bclr #0,$22(a0) tst.w $10(a0) bpl.s loc_315736 bset #0,$22(a0)

loc_315736:  ; ... asr $10(a0) asr $10(a0) move.b #$13,$16(a0) move.b #9,$17(a0) rts

---------------------------------------------------------------------------

loc_31574C:  ; ... bra.w sub_315C7C

---------------------------------------------------------------------------

Knuckles_BeginSlide:  ; ... bclr #0,$22(a0) tst.w $10(a0) bpl.s loc_315762 bset #0,$22(a0)

loc_315762:  ; ... move.b $26(a0),d0 add.b #$20,d0 and.b #$C0,d0 beq.s loc_315780 move.w $14(a0),$10(a0) move.w #0,$12(a0) bra.w Knuckles_ResetOnFloor_Part2

---------------------------------------------------------------------------

loc_315780:  ; ... move.b #3,$21(a0) move.b #$CC,$1A(a0) move.b #$7F,$1E(a0) move.b #0,$1B(a0) cmp.b #$C,$28(a0) bcs.s return_3157AC move.b #6,($FFFFD124).w move.b #$15,($FFFFD11A).w

return_3157AC:  ; ... rts

---------------------------------------------------------------------------

Knuckles_BeginClimb:  ; ... tst.b ($FFFFF7AD).w bmi.w loc_31587A move.b $3F(a0),d5 move.b $1F(a0),d0 add.b #$40,d0 bpl.s loc_3157D8 bset #0,$22(a0) bsr.w CheckLeftCeilingDist or.w d0,d1 bne.s Knuckles_FallFromGlide addq.w #1,8(a0) bra.s loc_3157E8

---------------------------------------------------------------------------

loc_3157D8:  ; ... bclr #0,$22(a0) bsr.w CheckRightCeilingDist or.w d0,d1 bne.w loc_31586A

loc_3157E8:  ; ... move.b #$13,$16(a0) move.b #9,$17(a0) tst.b ($FFFFFE19).w beq.s loc_315804 cmp.w #$480,$14(a0) bcs.s loc_315804 nop

loc_315804:  ; ... move.w #0,$14(a0) move.w #0,$10(a0) move.w #0,$12(a0) move.b #4,$21(a0) move.b #$B7,$1A(a0) move.b #$7F,$1E(a0) move.b #0,$1B(a0) move.b #3,$1F(a0) move.w 8(a0),$A(a0) rts

---------------------------------------------------------------------------

Knuckles_FallFromGlide:  ; ... move.w 8(a0),d3 move.b $16(a0),d0 ext.w d0 sub.w d0,d3 subq.w #1,d3

loc_31584A:  ; ... move.w $C(a0),d2 sub.w #$B,d2 jsr ChkFloorEdge_Part2 tst.w d1 bmi.s loc_31587A cmp.w #$C,d1 bcc.s loc_31587A add.w d1,$C(a0) bra.w loc_3157E8

---------------------------------------------------------------------------

loc_31586A:  ; ... move.w 8(a0),d3 move.b $16(a0),d0 ext.w d0 add.w d0,d3 addq.w #1,d3 bra.s loc_31584A

---------------------------------------------------------------------------

loc_31587A:  ; ... move.b #2,$21(a0) move.b #$21,$1C(a0) move.b #$13,$16(a0) move.b #9,$17(a0) bset #1,($FFFFF7AC).w rts

---------------------------------------------------------------------------

Knuckles_FallingFromGlide:  ; ... bsr.w Knuckles_ChgJumpDir add.w #$38,$12(a0) btst #6,$22(a0) beq.s loc_3158B2 sub.w #$28,$12(a0)

loc_3158B2:  ; ... bsr.w Knuckles_DoLevelCollision2 btst #1,($FFFFF7AC).w bne.s return_315900 move.w #0,$14(a0) move.w #0,$10(a0) move.w #0,$12(a0) move.b $16(a0),d0 sub.b #$13,d0 ext.w d0 add.w d0,$C(a0) move.b $26(a0),d0 add.b #$20,d0 and.b #$C0,d0 beq.s loc_3158F0 bra.w Knuckles_ResetOnFloor_Part2

---------------------------------------------------------------------------

loc_3158F0:  ; ... bsr.w Knuckles_ResetOnFloor_Part2 move.w #$F,$2E(a0) move.b #$23,$1C(a0)

return_315900:  ; ... rts

---------------------------------------------------------------------------

Knuckles_Sliding:  ; ... move.b ($FFFFF602).w,d0 and.b #$70,d0 beq.s loc_315926 tst.w $10(a0) bpl.s loc_31591E add.w #$20,$10(a0) bmi.s loc_31591C bra.s loc_315926

---------------------------------------------------------------------------

loc_31591C:  ; ... bra.s loc_315958

---------------------------------------------------------------------------

loc_31591E:  ; ... sub.w #$20,$10(a0) bpl.s loc_315958

loc_315926:  ; ... move.w #0,$14(a0) move.w #0,$10(a0) move.w #0,$12(a0) move.b $16(a0),d0 sub.b #$13,d0 ext.w d0 add.w d0,$C(a0) bsr.w Knuckles_ResetOnFloor_Part2 move.w #$F,$2E(a0) move.b #$22,$1C(a0) rts

---------------------------------------------------------------------------

loc_315958:  ; ... move.b #$A,$16(a0) move.b #$A,$17(a0) bsr.w Knuckles_DoLevelCollision2 bsr.w Player_CheckFloor cmp.w #$E,d1 bge.s loc_315988 add.w d1,$C(a0) move.b d3,$26(a0) move.b #$13,$16(a0) move.b #9,$17(a0) rts

---------------------------------------------------------------------------

loc_315988:  ; ... move.b #2,$21(a0) move.b #$21,$1C(a0) move.b #$13,$16(a0) move.b #9,$17(a0) bset #1,($FFFFF7AC).w rts

---------------------------------------------------------------------------

Knuckles_Climbing_Wall:  ; ... tst.b ($FFFFF7AD).w bmi.w loc_315BAE move.w 8(a0),d0 cmp.w $A(a0),d0 bne.w loc_315BAE btst #3,$22(a0) bne.w loc_315BAE move.w #0,$14(a0) move.w #0,$10(a0) move.w #0,$12(a0) move.l #$FFFFD600,($FFFFF796).w cmp.b #$D,$3F(a0) beq.s loc_3159F0 move.l #$FFFFD900,($FFFFF796).w

loc_3159F0:  ; ... move.b $3F(a0),d5 move.b #$A,$16(a0) move.b #$A,$17(a0) moveq #0,d1 btst #0,($FFFFF602).w beq.w loc_315A76 move.w $C(a0),d2 sub.w #$B,d2 bsr.w sub_315C22 cmp.w #4,d1 bge.w Knuckles_ClimbUp  ; Climb onto the floor above you tst.w d1 bne.w loc_315B30 move.b $3F(a0),d5 move.w $C(a0),d2 subq.w #8,d2 move.w 8(a0),d3 bsr.w sub_3192E6  ; Doesn't exist in S2 tst.w d1 bpl.s loc_315A46 sub.w d1,$C(a0) moveq #1,d1 bra.w loc_315B04

---------------------------------------------------------------------------

loc_315A46:  ; ... subq.w #1,$C(a0) tst.b ($FFFFFE19).w beq.s loc_315A54 subq.w #1,$C(a0)

loc_315A54:  ; ... moveq #1,d1 move.w ($FFFFEECC).w,d0 cmp.w #-$100,d0 beq.w loc_315B04 add.w #$10,d0 cmp.w $C(a0),d0 ble.w loc_315B04 move.w d0,$C(a0) bra.w loc_315B04

---------------------------------------------------------------------------

loc_315A76:  ; ... btst #1,($FFFFF602).w beq.w loc_315B04 cmp.b #$BD,$1A(a0) bne.s loc_315AA2 move.b #$B7,$1A(a0) addq.w #3,$C(a0) subq.w #3,8(a0) btst #0,$22(a0) beq.s loc_315AA2 addq.w #6,8(a0)

loc_315AA2:  ; ... move.w $C(a0),d2 add.w #$B,d2 bsr.w sub_315C22 tst.w d1 bne.w loc_315BAE move.b $3E(a0),d5 move.w $C(a0),d2 add.w #9,d2 move.w 8(a0),d3 bsr.w sub_318FF6 tst.w d1 bpl.s loc_315AF4 add.w d1,$C(a0) move.b ($FFFFF768).w,$26(a0) move.w #0,$14(a0) move.w #0,$10(a0) move.w #0,$12(a0) bsr.w Knuckles_ResetOnFloor_Part2 move.b #5,$1C(a0) rts

---------------------------------------------------------------------------

loc_315AF4:  ; ... addq.w #1,$C(a0) tst.b ($FFFFFE19).w beq.s loc_315B02 addq.w #1,$C(a0)

loc_315B02:  ; ... moveq #-1,d1

loc_315B04:  ; ... tst.w d1 beq.s loc_315B30 subq.b #1,$1F(a0) bpl.s loc_315B30 move.b #3,$1F(a0) add.b $1A(a0),d1 cmp.b #$B7,d1 bcc.s loc_315B22 move.b #$BC,d1

loc_315B22:  ; ... cmp.b #$BC,d1 bls.s loc_315B2C move.b #$B7,d1

loc_315B2C:  ; ... move.b d1,$1A(a0)

loc_315B30:  ; ... move.b #$20,$1E(a0) move.b #0,$1B(a0) move.b #$13,$16(a0) move.b #9,$17(a0) move.w ($FFFFF602).w,d0 and.w #$70,d0 beq.s return_315B94 move.w #$FC80,$12(a0) move.w #$400,$10(a0) bchg #0,$22(a0) bne.s loc_315B6A neg.w $10(a0)

loc_315B6A:  ; ... bset #1,$22(a0) move.b #1,$3C(a0) move.b #$E,$16(a0) move.b #7,$17(a0) move.b #2,$1C(a0) bset #2,$22(a0) move.b #0,$21(a0)

return_315B94:  ; ... rts

---------------------------------------------------------------------------

Knuckles_ClimbUp:  ; ... move.b #5,$21(a0)  ; Climb up to the floor above you cmp.b #$BD,$1A(a0) beq.s return_315BAC move.b #0,$1F(a0) bsr.s sub_315BDA

return_315BAC:  ; ... rts

---------------------------------------------------------------------------

loc_315BAE:  ; ... move.b #2,$21(a0) move.w #$2121,$1C(a0) move.b #$CB,$1A(a0) move.b #7,$1E(a0) move.b #1,$1B(a0) move.b #$13,$16(a0) move.b #9,$17(a0) rts

End of function Knuckles_GlideControl


=============== S U B R O U T I N E =======================================


sub_315BDA:  ; ... moveq #0,d0 move.b $1F(a0),d0 lea word_315C12(pc,d0.w),a1 move.b (a1)+,$1A(a0) move.b (a1)+,d0 ext.w d0 btst #0,$22(a0) beq.s loc_315BF6 neg.w d0

loc_315BF6:  ; ... add.w d0,8(a0) move.b (a1)+,d1 ext.w d1 add.w d1,$C(a0) move.b (a1)+,$1E(a0) addq.b #4,$1F(a0) move.b #0,$1B(a0) rts

End of function sub_315BDA
---------------------------------------------------------------------------

word_315C12: dc.w $BD03,$FD06,$BE08,$F606,$BFF8,$F406,$D208,$FB06; 0 ; ...

=============== S U B R O U T I N E =======================================


sub_315C22:  ; ...

FUNCTION CHUNK AT 00319208 SIZE 00000020 BYTES
FUNCTION CHUNK AT 003193D2 SIZE 00000024 BYTES

move.b $3F(a0),d5 btst #0,$22(a0) bne.s loc_315C36 move.w 8(a0),d3 bra.w loc_319208

---------------------------------------------------------------------------

loc_315C36:  ; ... move.w 8(a0),d3 subq.w #1,d3 bra.w loc_3193D2

End of function sub_315C22
---------------------------------------------------------------------------
START OF FUNCTION CHUNK FOR Knuckles_GlideControl

Knuckles_Climbing_Up:  ; ... tst.b $1E(a0) bne.s return_315C7A bsr.w sub_315BDA cmp.b #$10,$1F(a0) bne.s return_315C7A move.w #0,$14(a0) move.w #0,$10(a0) move.w #0,$12(a0) btst #0,$22(a0) beq.s loc_315C70 subq.w #1,8(a0)

loc_315C70:  ; ... bsr.w Knuckles_ResetOnFloor_Part2 move.b #5,$1C(a0)

return_315C7A:  ; ... rts

END OF FUNCTION CHUNK FOR Knuckles_GlideControl
=============== S U B R O U T I N E =======================================


sub_315C7C:  ; ... move.b #$20,$1E(a0) move.b #0,$1B(a0) move.w #$2020,$1C(a0) bclr #5,$22(a0) bclr #0,$22(a0) moveq #0,d0 move.b $1F(a0),d0 add.b #$10,d0 lsr.w #5,d0 move.b byte_315CC2(pc,d0.w),d1 move.b d1,$1A(a0) cmp.b #$C4,d1 bne.s return_315CC0 bset #0,$22(a0) move.b #$C0,$1A(a0)

return_315CC0:  ; ... rts

End of function sub_315C7C
---------------------------------------------------------------------------

byte_315CC2: dc.b $C0,$C1,$C2,$C3,$C4,$C3,$C2,$C1; 0 ; ...

=============== S U B R O U T I N E =======================================


Knuckles_GlideSpeedControl:  ; ... cmp.b #1,$21(a0) bne.w loc_315D88 move.w $14(a0),d0 cmp.w #$400,d0 bcc.s loc_315CE2 addq.w #8,d0 bra.s loc_315CFC

---------------------------------------------------------------------------

loc_315CE2:  ; ... cmp.w #$1800,d0 bcc.s loc_315CFC move.b $1F(a0),d1 and.b #$7F,d1 bne.s loc_315CFC addq.w #4,d0 tst.b ($FFFFFE19).w beq.s loc_315CFC addq.w #8,d0

loc_315CFC:  ; ... move.w d0,$14(a0) move.b $1F(a0),d0 btst #2,($FFFFF602).w beq.s loc_315D1C cmp.b #$80,d0 beq.s loc_315D1C tst.b d0 bpl.s loc_315D18 neg.b d0

loc_315D18:  ; ... addq.b #2,d0 bra.s loc_315D3A

---------------------------------------------------------------------------

loc_315D1C:  ; ... btst #3,($FFFFF602).w beq.s loc_315D30 tst.b d0 beq.s loc_315D30 bmi.s loc_315D2C neg.b d0

loc_315D2C:  ; ... addq.b #2,d0 bra.s loc_315D3A

---------------------------------------------------------------------------

loc_315D30:  ; ... move.b d0,d1 and.b #$7F,d1 beq.s loc_315D3A addq.b #2,d0

loc_315D3A:  ; ... move.b d0,$1F(a0) move.b $1F(a0),d0 jsr CalcSine muls.w $14(a0),d1 asr.l #8,d1 move.w d1,$10(a0) cmp.w #$80,$12(a0) blt.s loc_315D62 sub.w #$20,$12(a0) bra.s loc_315D68

---------------------------------------------------------------------------

loc_315D62:  ; ... add.w #$20,$12(a0)

loc_315D68:  ; ... move.w ($FFFFEECC).w,d0 cmp.w #$FF00,d0 beq.w loc_315D88 add.w #$10,d0 cmp.w $C(a0),d0 ble.w loc_315D88 asr $10(a0) asr $14(a0)

loc_315D88:  ; ... cmp.w #$60,($FFFFEED8).w beq.s return_315D9A bcc.s loc_315D96 addq.w #4,($FFFFEED8).w

loc_315D96:  ; ... subq.w #2,($FFFFEED8).w

return_315D9A:  ; ... rts

End of function Knuckles_GlideSpeedControl
---------------------------------------------------------------------------

</asm>