Actions

User

Tailsguy24/How to Port Knuckles into Sonic 2

From Sonic Retro

< User:Tailsguy24
Revision as of 21:47, 19 January 2013 by Tailsguy24 (talk | contribs)

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.
  • 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 quite a bit bigger than they were before.

Finally, please remember that this is a work-in-progress guide that I will improve upon as more is uncovered.

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 2. 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

</asm> 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>

Just to Recap

At this point, you should have this code ported: <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

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

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)

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: dc.w Obj4C_MdNormal_Checks  ; 0 ; not airborne or rolling dc.w Obj4C_MdAir  ; 2 ; airborne dc.w Obj4C_MdRoll  ; 4 ; rolling dc.w Obj4C_MdJump  ; 6 ; jumping

=============== 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


=============== 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


=============== 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>

Step 5: Obj4C_MdRoll and Obj4C_MdJump

Paste this below the code mentioned above, changing the "Obj01"s to "Obj4C"s: <asm> Obj01_MdRoll:  ; ... tst.b $39(a0) bne.s loc_315DA6 bsr.w Knuckles_Jump

loc_315DA6:  ; ... bsr.w Knuckles_RollRepel bsr.w Knuckles_RollSpeed bsr.w Knuckles_LevelBoundaries jsr ObjectMove  ; AKA SpeedToPos in Sonic 1 bsr.w AnglePos bsr.w Knuckles_SlopeRepel rts

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

Obj01_MdJump:  ; ... bsr.w Knuckles_JumpHeight bsr.w Knuckles_ChgJumpDir bsr.w Knuckles_LevelBoundaries jsr ObjectMoveAndFall btst #6,$22(a0) beq.s loc_315DE2 sub.w #$28,$12(a0)

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

</asm> Done! Piece of cake.

Step 6: TONS of essential coding!

Well, it's time to actually get something accomplished movement-wise, don't you think? That's where this step comes in. Put the following heap of code below the code we already have: <asm>

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


Knuckles_Move:  ; ... move.w ($FFFFF760).w,d6 move.w ($FFFFF762).w,d5 move.w ($FFFFF764).w,d4 tst.b $2B(a0) bmi.w Obj01_Traction tst.w $2E(a0) bne.w Obj01_ResetScreen btst #2,($FFFFF602).w beq.s Obj01_NotLeft bsr.w Knuckles_MoveLeft

Obj01_NotLeft:  ; ... btst #3,($FFFFF602).w beq.s Obj01_NotRight bsr.w Knuckles_MoveRight

Obj01_NotRight:  ; ... move.b $26(a0),d0 add.b #$20,d0 and.b #$C0,d0 bne.w Obj01_ResetScreen tst.w $14(a0) bne.w Obj01_ResetScreen bclr #5,$22(a0) move.b #5,$1C(a0) btst #3,$22(a0) beq.w Knuckles_Balance moveq #0,d0 move.b $3D(a0),d0 lsl.w #6,d0 lea ($FFFFB000).w,a1 lea (a1,d0.w),a1 tst.b $22(a1) bmi.w Knuckles_LookUp moveq #0,d1 move.b $19(a1),d1 move.w d1,d2 add.w d2,d2 subq.w #2,d2 add.w 8(a0),d1 sub.w 8(a1),d1 cmp.w #2,d1 blt.s Knuckles_BalanceOnObjLeft cmp.w d2,d1 bge.s Knuckles_BalanceOnObjRight bra.w Knuckles_LookUp

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

Knuckles_BalanceOnObjRight:  ; ... btst #0,$22(a0) bne.s loc_315E9A move.b #6,$1C(a0) bra.w Obj01_ResetScreen

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

loc_315E9A:  ; ... bclr #0,$22(a0) move.b #0,$1E(a0) move.b #4,$1B(a0) move.w #$606,$1C(a0) bra.w Obj01_ResetScreen

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

Knuckles_BalanceOnObjLeft:  ; ... btst #0,$22(a0) beq.s loc_315EC8 move.b #6,$1C(a0) bra.w Obj01_ResetScreen

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

loc_315EC8:  ; ... bset #0,$22(a0) move.b #0,$1E(a0) move.b #4,$1B(a0) move.w #$606,$1C(a0) bra.w Obj01_ResetScreen

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

Knuckles_Balance:  ; ... jsr ChkFloorEdge cmp.w #$C,d1 blt.w Knuckles_LookUp cmp.b #3,$36(a0) bne.s Knuckles_BalanceLeft btst #0,$22(a0) bne.s loc_315F0C move.b #6,$1C(a0) bra.w Obj01_ResetScreen

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

loc_315F0C:  ; ... bclr #0,$22(a0) move.b #0,$1E(a0) move.b #4,$1B(a0) move.w #$606,$1C(a0) bra.w Obj01_ResetScreen

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

Knuckles_BalanceLeft:  ; ... cmp.b #3,$37(a0) bne.s Knuckles_LookUp btst #0,$22(a0) beq.s loc_315F42 move.b #6,$1C(a0) bra.w Obj01_ResetScreen

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

loc_315F42:  ; ... bset #0,$22(a0) move.b #0,$1E(a0) move.b #4,$1B(a0) move.w #$606,$1C(a0) bra.w Obj01_ResetScreen

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

Knuckles_LookUp:  ; ... btst #0,($FFFFF602).w beq.s Knuckles_Duck move.b #7,$1C(a0) addq.w #1,($FFFFF66C).w cmp.w #$78,($FFFFF66C).w bcs.s Obj01_ResetScreen_Part2 move.w #$78,($FFFFF66C).w cmp.w #$C8,($FFFFEED8).w beq.s Obj01_UpdateSpeedOnGround addq.w #2,($FFFFEED8).w bra.s Obj01_UpdateSpeedOnGround

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

Knuckles_Duck:  ; ... btst #1,($FFFFF602).w beq.s Obj01_ResetScreen move.b #8,$1C(a0) addq.w #1,($FFFFF66C).w cmp.w #$78,($FFFFF66C).w bcs.s Obj01_ResetScreen_Part2 move.w #$78,($FFFFF66C).w cmp.w #8,($FFFFEED8).w beq.s Obj01_UpdateSpeedOnGround subq.w #2,($FFFFEED8).w bra.s Obj01_UpdateSpeedOnGround

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

Obj01_ResetScreen:  ; ... move.w #0,($FFFFF66C).w

Obj01_ResetScreen_Part2:  ; ... cmp.w #$60,($FFFFEED8).w beq.s Obj01_UpdateSpeedOnGround bcc.s loc_315FCE addq.w #4,($FFFFEED8).w

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

Obj01_UpdateSpeedOnGround:  ; ... tst.b ($FFFFFE19).w beq.s loc_315FDC move.w #$C,d5

loc_315FDC:  ; ... move.b ($FFFFF602).w,d0 and.b #$C,d0 bne.s Obj01_Traction move.w $14(a0),d0 beq.s Obj01_Traction bmi.s Obj01_SettleLeft sub.w d5,d0 bcc.s loc_315FF6 move.w #0,d0

loc_315FF6:  ; ... move.w d0,$14(a0) bra.s Obj01_Traction

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

Obj01_SettleLeft:  ; ... add.w d5,d0 bcc.s loc_316004 move.w #0,d0

loc_316004:  ; ... move.w d0,$14(a0)

Obj01_Traction:  ; ... move.b $26(a0),d0 jsr CalcSine muls.w $14(a0),d1 asr.l #8,d1 move.w d1,$10(a0) muls.w $14(a0),d0 asr.l #8,d0 move.w d0,$12(a0)

Obj01_CheckWallsOnGround:  ; ... move.b $26(a0),d0 add.b #$40,d0 bmi.s return_3160A6 move.b #$40,d1 tst.w $14(a0) beq.s return_3160A6 bmi.s loc_31603E neg.w d1

loc_31603E:  ; ... move.b $26(a0),d0 add.b d1,d0 move.w d0,-(sp) bsr.w CalcRoomInFront  ; Also known as Sonic_WalkSpeed in Sonic 1 move.w (sp)+,d0 tst.w d1 bpl.s return_3160A6 asl.w #8,d1 add.b #$20,d0 and.b #$C0,d0 beq.s loc_3160A2 cmp.b #$40,d0 beq.s loc_316088 cmp.b #$80,d0 beq.s loc_316082 add.w d1,$10(a0) move.w #0,$14(a0) btst #0,$22(a0) bne.s return_316080 bset #5,$22(a0)

return_316080:  ; ... rts

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

loc_316082:  ; ... sub.w d1,$12(a0) rts

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

loc_316088:  ; ... sub.w d1,$10(a0) move.w #0,$14(a0) btst #0,$22(a0) beq.s return_316080 bset #5,$22(a0) rts

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

loc_3160A2:  ; ... add.w d1,$12(a0)

return_3160A6:  ; ... rts

End of function Knuckles_Move


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


Knuckles_MoveLeft:  ; ... move.w $14(a0),d0 beq.s loc_3160B0 bpl.s Knuckles_TurnLeft

loc_3160B0:  ; ... bset #0,$22(a0) bne.s loc_3160C4 bclr #5,$22(a0) move.b #1,$1D(a0)

loc_3160C4:  ; ... sub.w d5,d0 move.w d6,d1 neg.w d1 cmp.w d1,d0 bgt.s loc_3160D6 add.w d5,d0 cmp.w d1,d0 ble.s loc_3160D6 move.w d1,d0

loc_3160D6:  ; ... move.w d0,$14(a0) move.b #0,$1C(a0) rts

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

Knuckles_TurnLeft:  ; ... sub.w d4,d0 bcc.s loc_3160EA move.w #-$80,d0

loc_3160EA:  ; ... move.w d0,$14(a0) move.b $26(a0),d1 add.b #$20,d1 and.b #$C0,d1 bne.s return_31612C cmp.w #$400,d0 blt.s return_31612C move.b #$D,$1C(a0) bclr #0,$22(a0) move.w #$A4,d0 jsr PlaySound cmp.b #$C,$28(a0) bcs.s return_31612C move.b #6,($FFFFD124).w move.b #$15,($FFFFD11A).w

return_31612C:  ; ... rts

End of function Knuckles_MoveLeft


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


Knuckles_MoveRight:  ; ... move.w $14(a0),d0 bmi.s Knuckles_TurnRight bclr #0,$22(a0) beq.s loc_316148 bclr #5,$22(a0) move.b #1,$1D(a0)

loc_316148:  ; ... add.w d5,d0 cmp.w d6,d0 blt.s loc_316156 sub.w d5,d0 cmp.w d6,d0 bge.s loc_316156 move.w d6,d0

loc_316156:  ; ... move.w d0,$14(a0) move.b #0,$1C(a0) rts

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

Knuckles_TurnRight:  ; ... add.w d4,d0 bcc.s loc_31616A move.w #$80,d0

loc_31616A:  ; ... move.w d0,$14(a0) move.b $26(a0),d1 add.b #$20,d1 and.b #$C0,d1 bne.s return_3161AC cmp.w #$FC00,d0 bgt.s return_3161AC move.b #$D,$1C(a0) bset #0,$22(a0) move.w #$A4,d0 jsr PlaySound cmp.b #$C,$28(a0) bcs.s return_3161AC move.b #6,($FFFFD124).w move.b #$15,($FFFFD11A).w

return_3161AC:  ; ... rts

End of function Knuckles_MoveRight


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


Knuckles_RollSpeed:  ; ... move.w ($FFFFF760).w,d6 asl.w #1,d6 move.w ($FFFFF762).w,d5 asr.w #1,d5 move.w #$20,d4 tst.b $2B(a0) bmi.w Obj01_Roll_ResetScreen tst.w $2E(a0) bne.s Knuckles_Apply_RollSpeed btst #2,($FFFFF602).w beq.s loc_3161D8 bsr.w Knuckles_RollLeft

loc_3161D8:  ; ... btst #3,($FFFFF602).w beq.s Knuckles_Apply_RollSpeed bsr.w Knuckles_RollRight

Knuckles_Apply_RollSpeed:  ; ... move.w $14(a0),d0 beq.s Knuckles_CheckRollStop bmi.s Knuckles_ApplyRollSpeedLeft sub.w d5,d0 bcc.s loc_3161F4 move.w #0,d0

loc_3161F4:  ; ... move.w d0,$14(a0) bra.s Knuckles_CheckRollStop

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

Knuckles_ApplyRollSpeedLeft:  ; ... add.w d5,d0 bcc.s loc_316202 move.w #0,d0

loc_316202:  ; ... move.w d0,$14(a0)

Knuckles_CheckRollStop:  ; ... tst.w $14(a0) bne.s Obj01_Roll_ResetScreen tst.b $39(a0) bne.s Knuckles_KeepRolling bclr #2,$22(a0) move.b #$13,$16(a0) move.b #9,$17(a0) move.b #5,$1C(a0) subq.w #5,$C(a0) bra.s Obj01_Roll_ResetScreen

---------------------------------------------------------------------------
magically gives Knuckles an extra push if he's going to stop rolling where it's not allowed
(such as in an S-curve in HTZ or a stopper chamber in CNZ)


Knuckles_KeepRolling:  ; ... move.w #$400,$14(a0) btst #0,$22(a0) beq.s Obj01_Roll_ResetScreen neg.w $14(a0)

Obj01_Roll_ResetScreen:  ; ... cmp.w #$60,($FFFFEED8).w beq.s Knuckles_SetRollSpeeds bcc.s loc_316250 addq.w #4,($FFFFEED8).w

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

Knuckles_SetRollSpeeds:  ; ... move.b $26(a0),d0 jsr CalcSine muls.w $14(a0),d0 asr.l #8,d0 move.w d0,$12(a0) muls.w $14(a0),d1 asr.l #8,d1 cmp.w #$1000,d1 ble.s loc_316278 move.w #$1000,d1

loc_316278:  ; ... cmp.w #-$1000,d1 bge.s loc_316282 move.w #-$1000,d1

loc_316282:  ; ... move.w d1,$10(a0) bra.w Obj01_CheckWallsOnGround

End of function Knuckles_RollSpeed


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


Knuckles_RollLeft:  ; ... move.w $14(a0),d0 beq.s loc_316292 bpl.s Knuckles_BrakeRollingRight

loc_316292:  ; ... bset #0,$22(a0) move.b #2,$1C(a0) rts

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

Knuckles_BrakeRollingRight:  ; ... sub.w d4,d0 bcc.s loc_3162A8 move.w #-$80,d0

loc_3162A8:  ; ... move.w d0,$14(a0) rts

End of function Knuckles_RollLeft


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


Knuckles_RollRight:  ; ... move.w $14(a0),d0 bmi.s Knuckles_BrakeRollingLeft bclr #0,$22(a0) move.b #2,$1C(a0) rts

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

Knuckles_BrakeRollingLeft:  ; ... add.w d4,d0 bcc.s loc_3162CA move.w #$80,d0

loc_3162CA:  ; ... move.w d0,$14(a0) rts

End of function Knuckles_RollRight
---------------------------------------------------------------------------
Subroutine for moving Knuckles left or right when he's in the air
---------------------------------------------------------------------------
=============== S U B R O U T I N E =======================================


Knuckles_ChgJumpDir:  ; ... move.w ($FFFFF760).w,d6 move.w ($FFFFF762).w,d5 asl.w #1,d5 btst #4,$22(a0) bne.s Obj01_Jump_ResetScreen move.w $10(a0),d0 btst #2,($FFFFF602).w beq.s loc_31630E bset #0,$22(a0) sub.w d5,d0 move.w d6,d1 neg.w d1 cmp.w d1,d0 bgt.s loc_31630E tst.w ($FFFFFFD0).w bne.w loc_31630C add.w d5,d0 cmp.w d1,d0 ble.s loc_31630E

loc_31630C:  ; ... move.w d1,d0

loc_31630E:  ; ... btst #3,($FFFFF602).w beq.s loc_316332 bclr #0,$22(a0) add.w d5,d0 cmp.w d6,d0 blt.s loc_316332 tst.w ($FFFFFFD0).w bne.w loc_316330 sub.w d5,d0 cmp.w d6,d0 bge.s loc_316332

loc_316330:  ; ... move.w d6,d0

loc_316332:  ; ... move.w d0,$10(a0)

Obj01_Jump_ResetScreen:  ; ... cmp.w #$60,($FFFFEED8).w beq.s Knuckles_JumpPeakDecelerate bcc.s loc_316344 addq.w #4,($FFFFEED8).w

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

Knuckles_JumpPeakDecelerate:  ; ... cmp.w #-$400,$12(a0) bcs.s return_316376 move.w $10(a0),d0 move.w d0,d1 asr.w #5,d1 beq.s return_316376 bmi.s Knuckles_JumpPeakDecelerateLeft sub.w d1,d0 bcc.s loc_316364 move.w #0,d0

loc_316364:  ; ... move.w d0,$10(a0) rts

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

Knuckles_JumpPeakDecelerateLeft:  ; ... sub.w d1,d0 bcs.s loc_316372 move.w #0,d0

loc_316372:  ; ... move.w d0,$10(a0)

return_316376:  ; ... rts

End of function Knuckles_ChgJumpDir


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


Knuckles_LevelBoundaries:  ; ... move.l 8(a0),d1 move.w $10(a0),d0 ext.l d0 asl.l #8,d0 add.l d0,d1 swap d1 move.w ($FFFFEEC8).w,d0 add.w #$10,d0 cmp.w d1,d0 bhi.s Knuckles_Boundary_Sides move.w ($FFFFEECA).w,d0 add.w #$128,d0 tst.b ($FFFFF7AA).w bne.s loc_3163A6 add.w #$40,d0

loc_3163A6:  ; ... cmp.w d1,d0 bls.s Knuckles_Boundary_Sides

Knuckles_Boundary_CheckBottom:  ; ... move.w ($FFFFEECE).w,d0 add.w #$E0,d0 cmp.w $C(a0),d0 blt.s Knuckles_Boundary_Bottom rts

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

Knuckles_Boundary_Bottom:  ; ... jmp KillCharacter

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

Knuckles_Boundary_Sides:  ; ... move.w d0,8(a0) move.w #0,$A(a0) move.w #0,$10(a0) move.w #0,$14(a0) bra.s Knuckles_Boundary_CheckBottom

End of function Knuckles_LevelBoundaries


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


Knuckles_Roll:  ; ... tst.b $2B(a0) bmi.s Obj01_NoRoll move.w $14(a0),d0 bpl.s loc_3163E6 neg.w d0

loc_3163E6:  ; ... cmp.w #$80,d0 bcs.s Obj01_NoRoll move.b ($FFFFF602).w,d0 and.b #$C,d0 bne.s Obj01_NoRoll btst #1,($FFFFF602).w bne.s Obj01_ChkRoll

Obj01_NoRoll:  ; ... rts

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

Obj01_ChkRoll:  ; ... btst #2,$22(a0) beq.s Obj01_DoRoll rts

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

Obj01_DoRoll:  ; ... bset #2,$22(a0) move.b #$E,$16(a0) move.b #7,$17(a0) move.b #2,$1C(a0) addq.w #5,$C(a0) move.w #$BE,d0 jsr PlaySound tst.w $14(a0) bne.s return_31643C move.w #$200,$14(a0)

return_31643C:  ; ... rts

End of function Knuckles_Roll


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


Knuckles_Jump:  ; ... move.b ($FFFFF603).w,d0 and.b #$70,d0 beq.w return_3164EC moveq #0,d0 move.b $26(a0),d0 add.b #$80,d0 bsr.w CalcRoomOverHead cmp.w #6,d1 blt.w return_3164EC move.w #$600,d2 btst #6,$22(a0) beq.s loc_316470 move.w #$300,d2

loc_316470:  ; ... tst.w ($FFFFFFD0).w  ; Check for demo mode (note: in normal Sonic 2, this is the level select flag!) beq.s loc_31647A add.w #$80,d2  ; Set the jump height to Sonic's height in Demo mode because Sonic Team were too lazy to record new demos for S2&K.

loc_31647A:  ; ... moveq #0,d0 move.b $26(a0),d0 sub.b #$40,d0 jsr CalcSine muls.w d2,d1 asr.l #8,d1 add.w d1,$10(a0) muls.w d2,d0 asr.l #8,d0 add.w d0,$12(a0) bset #1,$22(a0) bclr #5,$22(a0) addq.l #4,sp move.b #1,$3C(a0) clr.b $38(a0)

loc_3164B2: move.w #$A0,d0 jsr PlaySound move.b #$13,$16(a0) move.b #9,$17(a0) btst #2,$22(a0) bne.s Knuckles_RollJump move.b #$E,$16(a0) move.b #7,$17(a0) move.b #2,$1C(a0) bset #2,$22(a0) addq.w #5,$C(a0)

return_3164EC:  ; ... rts

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

Knuckles_RollJump:  ; ... bset #4,$22(a0) rts

End of function Knuckles_Jump


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


Knuckles_JumpHeight:  ; ... tst.b $3C(a0) beq.s Knuckles_UpwardsVelocityCap move.w #-$400,d1 btst #6,$22(a0) beq.s loc_31650C move.w #-$200,d1

loc_31650C:  ; ... cmp.w $12(a0),d1 ble.w Knuckles_CheckGlide  ; Check if Knuckles should begin a glide move.b ($FFFFF602).w,d0 and.b #$70,d0 bne.s return_316522 move.w d1,$12(a0)

return_316522:  ; ... rts

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

Knuckles_UpwardsVelocityCap:  ; ... tst.b $39(a0) bne.s return_316538 cmp.w #-$FC0,$12(a0) bge.s return_316538 move.w #-$FC0,$12(a0)

return_316538:  ; ... rts

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

Knuckles_CheckGlide:  ; ... tst.w ($FFFFFFD0).w  ; Don't glide on demos bne.w return_3165D2 tst.b $21(a0) bne.w return_3165D2 move.b ($FFFFF603).w,d0 and.b #$70,d0 beq.w return_3165D2 tst.b ($FFFFFE19).w bne.s Knuckles_BeginGlide cmp.b #7,($FFFFFFB1).w bcs.s Knuckles_BeginGlide cmp.w #50,($FFFFFE20).w bcs.s Knuckles_BeginGlide tst.b ($FFFFFE1E).w bne.s Knuckles_TurnSuper

Knuckles_BeginGlide:  ; ... bclr #2,$22(a0) move.b #$A,$16(a0) move.b #$A,$17(a0) bclr #4,$22(a0) move.b #1,$21(a0) add.w #$200,$12(a0) bpl.s loc_31659E move.w #0,$12(a0)

loc_31659E:  ; ... moveq #0,d1 move.w #$400,d0 move.w d0,$14(a0) btst #0,$22(a0) beq.s loc_3165B4 neg.w d0 moveq #-$80,d1

loc_3165B4:  ; ... move.w d0,$10(a0) move.b d1,$1F(a0) move.w #0,$26(a0) move.b #0,($FFFFF7AC).w bset #1,($FFFFF7AC).w bsr.w sub_315C7C

return_3165D2:  ; ... rts

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

Knuckles_TurnSuper:  ; ... move.b #1,($FFFFF65F).w move.b #$F,($FFFFF65E).w move.b #1,($FFFFFE19).w move.w #60,($FFFFF670).w move.b #$81,$2A(a0) move.b #$1F,$1C(a0) move.b #$7E,($FFFFD040).w move.w #$800,($FFFFF760).w move.w #$18,($FFFFF762).w move.w #$C0,($FFFFF764).w move.w #0,$32(a0) bset #1,$2B(a0) move.w #$DF,d0 jsr PlaySound move.w #$96,d0 jmp PlayMusic

End of function Knuckles_JumpHeight
---------------------------------------------------------------------------

rts

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


Knuckles_Super:  ; ... tst.b ($FFFFFE19).w beq.w return_3166C8 tst.b ($FFFFFE1E).w beq.s loc_31667E subq.w #1,($FFFFF670).w bpl.w return_3166C8 move.w #60,($FFFFF670).w tst.w ($FFFFFE20).w beq.s loc_31667E or.b #1,($FFFFFE1D).w cmp.w #1,($FFFFFE20).w beq.s loc_316672 cmp.w #10,($FFFFFE20).w beq.s loc_316672 cmp.w #100,($FFFFFE20).w bne.s loc_316678

loc_316672:  ; ... or.b #%10000000,($FFFFFE1D).w

loc_316678:  ; ... subq.w #1,($FFFFFE20).w bne.s return_3166C8

loc_31667E:  ; ... move.b #2,($FFFFF65F).w move.w #40,($FFFFF65C).w move.b #0,($FFFFFE19).w move.b #1,$1D(a0) move.w #1,$32(a0) move.w #$600,($FFFFF760).w move.w #$C,($FFFFF762).w move.w #$80,($FFFFF764).w btst #6,$22(a0) beq.s return_3166C8 move.w #$300,($FFFFF760).w move.w #6,($FFFFF762).w move.w #$40,($FFFFF764).w

return_3166C8:  ; ... rts

End of function Knuckles_Super


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


Knuckles_Spindash:  ; ... tst.b $39(a0) bne.s Knuckles_UpdateSpindash cmp.b #8,$1C(a0) bne.s return_316718 move.b ($FFFFF603).w,d0 and.b #$70,d0 beq.w return_316718 move.b #9,$1C(a0) move.w #$E0,d0 jsr PlaySound addq.l #4,sp move.b #1,$39(a0) move.w #0,$3A(a0) cmp.b #$C,$28(a0) bcs.s loc_316710 move.b #2,($FFFFD11C).w

loc_316710:  ; ... bsr.w Knuckles_LevelBoundaries bsr.w AnglePos

return_316718:  ; ... rts

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

Knuckles_UpdateSpindash:  ; ... move.b ($FFFFF602).w,d0 btst #1,d0 bne.w Knuckles_ChargingSpindash move.b #$E,$16(a0) move.b #7,$17(a0) move.b #2,$1C(a0) addq.w #5,$C(a0) move.b #0,$39(a0) moveq #0,d0 move.b $3A(a0),d0 add.w d0,d0 move.w Spindash_Speeds(pc,d0.w),$14(a0) tst.b ($FFFFFE19).w beq.s loc_31675C move.w Super_Spindash_Speeds(pc,d0.w),$14(a0)

loc_31675C:  ; ... move.w $14(a0),d0 sub.w #$800,d0 add.w d0,d0 and.w #$1F00,d0 neg.w d0 add.w #$2000,d0 move.w d0,($FFFFEED0).w  ; Lock camera for a certain number of frames btst #0,$22(a0) beq.s loc_316780 neg.w $14(a0)

loc_316780:  ; ... bset #2,$22(a0) move.b #0,($FFFFD11C).w move.w #$BC,d0 jsr PlaySound bra.s Obj01_Spindash_ResetScreen

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

Spindash_Speeds:  ; ... dc.w $800, $880, $900, $980, $A00, $A80, $B00, $B80, $C00; 0 Super_Spindash_Speeds:  ; ... dc.w $B00, $B80, $C00, $C80, $D00, $D80, $E00, $E80, $F00; 0

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

Knuckles_ChargingSpindash:  ; ... tst.w $3A(a0) beq.s loc_3167D4 move.w $3A(a0),d0 lsr.w #5,d0 sub.w d0,$3A(a0) bcc.s loc_3167D4 move.w #0,$3A(a0)

loc_3167D4:  ; ... move.b ($FFFFF603).w,d0 and.b #$70,d0 beq.w Obj01_Spindash_ResetScreen move.w #$900,$1C(a0) move.w #$E0,d0 jsr PlaySound add.w #$200,$3A(a0) cmp.w #$800,$3A(a0) bcs.s Obj01_Spindash_ResetScreen move.w #$800,$3A(a0)

Obj01_Spindash_ResetScreen:  ; ... addq.l #4,sp cmp.w #$60,($FFFFEED8).w beq.s loc_316818 bcc.s loc_316814 addq.w #4,($FFFFEED8).w

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

loc_316818:  ; ... bsr.w Knuckles_LevelBoundaries bsr.w AnglePos rts

End of function Knuckles_Spindash


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


Knuckles_SlopeResist:  ; ... move.b $26(a0),d0 add.b #$60,d0 cmp.b #$C0,d0 bcc.s return_316856 move.b $26(a0),d0 jsr CalcSine muls.w #$20,d0 asr.l #8,d0 tst.w $14(a0) beq.s return_316856 bmi.s loc_316852 tst.w d0 beq.s return_316850 add.w d0,$14(a0)

return_316850:  ; ... rts

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

loc_316852:  ; ... add.w d0,$14(a0)

return_316856:  ; ... rts

End of function Knuckles_SlopeResist


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


Knuckles_RollRepel:  ; ... move.b $26(a0),d0 add.b #$60,d0 cmp.b #$C0,d0 bcc.s return_316892 move.b $26(a0),d0 jsr CalcSine muls.w #$50,d0 asr.l #8,d0 tst.w $14(a0) bmi.s loc_316888 tst.w d0 bpl.s loc_316882 asr.l #2,d0

loc_316882:  ; ... add.w d0,$14(a0) rts

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

loc_316888:  ; ... tst.w d0 bmi.s loc_31688E asr.l #2,d0

loc_31688E:  ; ... add.w d0,$14(a0)

return_316892:  ; ... rts

End of function Knuckles_RollRepel


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


Knuckles_SlopeRepel:  ; ... nop tst.b $38(a0) bne.s return_3168CE tst.w $2E(a0) bne.s loc_3168D0 move.b $26(a0),d0 add.b #$20,d0 and.b #$C0,d0 beq.s return_3168CE move.w $14(a0),d0 bpl.s loc_3168B8 neg.w d0

loc_3168B8:  ; ... cmp.w #$280,d0 bcc.s return_3168CE clr.w $14(a0) bset #1,$22(a0) move.w #$1E,$2E(a0)

return_3168CE:  ; ... rts

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

loc_3168D0:  ; ... subq.w #1,$2E(a0) rts

End of function Knuckles_SlopeRepel


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


Knuckles_JumpAngle:  ; ... move.b $26(a0),d0 beq.s Knuckles_JumpFlip bpl.s loc_3168E6 addq.b #2,d0 bcc.s BraTo_Knuckles_JumpAngleSet moveq #0,d0

BraTo_Knuckles_JumpAngleSet:  ; ... bra.s Knuckles_JumpAngleSet

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

loc_3168E6:  ; ... subq.b #2,d0 bcc.s Knuckles_JumpAngleSet moveq #0,d0

Knuckles_JumpAngleSet:  ; ... move.b d0,$26(a0)

Knuckles_JumpFlip:  ; ... move.b $27(a0),d0 beq.s return_316934 tst.w $14(a0) bmi.s Knuckles_JumpLeftFlip

Knuckles_JumpRightFlip:  ; ... move.b $2D(a0),d1 add.b d1,d0 bcc.s BraTo_Knuckles_JumpFlipSet subq.b #1,$2C(a0) bcc.s BraTo_Knuckles_JumpFlipSet move.b #0,$2C(a0) moveq #0,d0

BraTo_Knuckles_JumpFlipSet:  ; ... bra.s Knuckles_JumpFlipSet

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

Knuckles_JumpLeftFlip:  ; ... tst.b $29(a0) bne.s Knuckles_JumpRightFlip move.b $2D(a0),d1 sub.b d1,d0 bcc.s Knuckles_JumpFlipSet subq.b #1,$2C(a0) bcc.s Knuckles_JumpFlipSet move.b #0,$2C(a0) moveq #0,d0

Knuckles_JumpFlipSet:  ; ... move.b d0,$27(a0)

return_316934:  ; ... rts

End of function Knuckles_JumpAngle


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


Knuckles_DoLevelCollision2:  ; ... move.l #$FFFFD600,($FFFFF796).w cmp.b #$C,$3E(a0) beq.s loc_31694E move.l #$FFFFD900,($FFFFF796).w

loc_31694E:  ; ... move.b $3F(a0),d5 move.w $10(a0),d1 move.w $12(a0),d2 jsr CalcAngle sub.b #$20,d0 and.b #$C0,d0 cmp.b #$40,d0 beq.w Knuckles_HitLeftWall2 cmp.b #$80,d0 beq.w Knuckles_HitCeilingAndWalls2 cmp.b #$C0,d0 beq.w Knuckles_HitRightWall2 bsr.w CheckLeftWallDist tst.w d1 bpl.s loc_316998 sub.w d1,8(a0) move.w #0,$10(a0) bset #5,($FFFFF7AC).w

loc_316998:  ; ... bsr.w CheckRightWallDist tst.w d1 bpl.s loc_3169B0 add.w d1,8(a0) move.w #0,$10(a0) bset #5,($FFFFF7AC).w

loc_3169B0:  ; ... bsr.w Player_CheckFloor tst.w d1 bpl.s return_3169CC add.w d1,$C(a0) move.b d3,$26(a0) move.w #0,$12(a0) bclr #1,($FFFFF7AC).w

return_3169CC:  ; ... rts

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

Knuckles_HitLeftWall2:  ; ... bsr.w CheckLeftWallDist tst.w d1 bpl.s Knuckles_HitCeilingAlt sub.w d1,8(a0) move.w #0,$10(a0) bset #5,($FFFFF7AC).w

Knuckles_HitCeilingAlt:  ; ... bsr.w CheckCeilingDist tst.w d1 bpl.s Knuckles_HitFloor neg.w d1 cmp.w #$14,d1 bcc.s loc_316A08 add.w d1,$C(a0) tst.w $12(a0) bpl.s return_316A06 move.w #0,$12(a0)

return_316A06:  ; ... rts

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

loc_316A08:  ; ... bsr.w CheckRightWallDist tst.w d1 bpl.s return_316A20 add.w d1,8(a0) move.w #0,$10(a0) bset #5,($FFFFF7AC).w

return_316A20:  ; ... rts

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

Knuckles_HitFloor:  ; ... tst.w $12(a0) bmi.s return_316A44 bsr.w Player_CheckFloor tst.w d1 bpl.s return_316A44 add.w d1,$C(a0) move.b d3,$26(a0) move.w #0,$12(a0) bclr #1,($FFFFF7AC).w

return_316A44:  ; ... rts

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

Knuckles_HitCeilingAndWalls2:  ; ... bsr.w CheckLeftWallDist tst.w d1 bpl.s loc_316A5E sub.w d1,8(a0) move.w #0,$10(a0) bset #5,($FFFFF7AC).w

loc_316A5E:  ; ... bsr.w CheckRightWallDist tst.w d1 bpl.s loc_316A76 add.w d1,8(a0) move.w #0,$10(a0) bset #5,($FFFFF7AC).w

loc_316A76:  ; ... bsr.w CheckCeilingDist tst.w d1 bpl.s return_316A88 sub.w d1,$C(a0) move.w #0,$12(a0)

return_316A88:  ; ... rts

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

Knuckles_HitRightWall2:  ; ... bsr.w CheckRightWallDist tst.w d1 bpl.s loc_316AA2 add.w d1,8(a0) move.w #0,$10(a0) bset #5,($FFFFF7AC).w

loc_316AA2:  ; ... bsr.w CheckCeilingDist tst.w d1 bpl.s loc_316ABC sub.w d1,$C(a0) tst.w $12(a0) bpl.s return_316ABA move.w #0,$12(a0)

return_316ABA:  ; ... rts

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

loc_316ABC:  ; ... tst.w $12(a0) bmi.s return_316ADE bsr.w Player_CheckFloor tst.w d1 bpl.s return_316ADE add.w d1,$C(a0) move.b d3,$26(a0) move.w #0,$12(a0) bclr #1,($FFFFF7AC).w

return_316ADE:  ; ... rts

End of function Knuckles_DoLevelCollision2


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


Knuckles_DoLevelCollision:  ; ... move.l #$FFFFD600,($FFFFF796).w cmp.b #$C,$3E(a0) beq.s loc_316AF8 move.l #$FFFFD900,($FFFFF796).w

loc_316AF8:  ; ... move.b $3F(a0),d5 move.w $10(a0),d1 move.w $12(a0),d2 jsr CalcAngle sub.b #$20,d0 and.b #$C0,d0 cmp.b #$40,d0 beq.w Knuckles_HitLeftWall cmp.b #$80,d0 beq.w Knuckles_HitCeilingAndWalls cmp.b #$C0,d0 beq.w Knuckles_HitRightWall bsr.w CheckLeftWallDist tst.w d1 bpl.s loc_316B3C sub.w d1,8(a0) move.w #0,$10(a0)

loc_316B3C:  ; ... bsr.w CheckRightWallDist tst.w d1 bpl.s loc_316B4E add.w d1,8(a0) move.w #0,$10(a0)

loc_316B4E:  ; ... bsr.w Player_CheckFloor tst.w d1 bpl.s return_316BC0 move.b $12(a0),d2 addq.b #8,d2 neg.b d2 cmp.b d2,d1 bge.s loc_316B66 cmp.b d2,d0 blt.s return_316BC0

loc_316B66:  ; ... add.w d1,$C(a0) move.b d3,$26(a0) bsr.w Knuckles_ResetOnFloor move.b d3,d0 add.b #$20,d0 and.b #$40,d0 bne.s loc_316B9E move.b d3,d0 add.b #$10,d0 and.b #$20,d0 beq.s loc_316B90 asr $12(a0) bra.s loc_316BB2

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

loc_316B90:  ; ... move.w #0,$12(a0) move.w $10(a0),$14(a0) rts

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

loc_316B9E:  ; ... move.w #0,$10(a0) cmp.w #$FC0,$12(a0) ble.s loc_316BB2 move.w #$FC0,$12(a0)

loc_316BB2:  ; ... move.w $12(a0),$14(a0) tst.b d3 bpl.s return_316BC0 neg.w $14(a0)

return_316BC0:  ; ... rts

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

Knuckles_HitLeftWall:  ; ... bsr.w CheckLeftWallDist tst.w d1 bpl.s Knuckles_HitCeiling sub.w d1,8(a0) move.w #0,$10(a0) move.w $12(a0),$14(a0) rts

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

Knuckles_HitCeiling:  ; ... bsr.w CheckCeilingDist tst.w d1 bpl.s Knuckles_HitFloor_0 sub.w d1,$C(a0) tst.w $12(a0) bpl.s return_316BF4 move.w #0,$12(a0)

return_316BF4:  ; ... rts

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

Knuckles_HitFloor_0:  ; ... tst.w $12(a0) bmi.s return_316C1C bsr.w Player_CheckFloor tst.w d1 bpl.s return_316C1C add.w d1,$C(a0) move.b d3,$26(a0) bsr.w Knuckles_ResetOnFloor move.w #0,$12(a0) move.w $10(a0),$14(a0)

return_316C1C:  ; ... rts

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

Knuckles_HitCeilingAndWalls:  ; ... bsr.w CheckLeftWallDist tst.w d1 bpl.s loc_316C30 sub.w d1,8(a0) move.w #0,$10(a0)

loc_316C30:  ; ... bsr.w CheckRightWallDist tst.w d1 bpl.s loc_316C42 add.w d1,8(a0) move.w #0,$10(a0)

loc_316C42:  ; ... bsr.w CheckCeilingDist tst.w d1 bpl.s return_316C78 sub.w d1,$C(a0) move.b d3,d0 add.b #$20,d0 and.b #$40,d0 bne.s loc_316C62 move.w #0,$12(a0) rts

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

loc_316C62:  ; ... move.b d3,$26(a0) bsr.w Knuckles_ResetOnFloor move.w $12(a0),$14(a0) tst.b d3 bpl.s return_316C78 neg.w $14(a0)

return_316C78:  ; ... rts

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

Knuckles_HitRightWall:  ; ... bsr.w CheckRightWallDist tst.w d1 bpl.s Knuckles_HitCeiling2 add.w d1,8(a0) move.w #0,$10(a0) move.w $12(a0),$14(a0) rts

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

Knuckles_HitCeiling2:  ; ... bsr.w CheckCeilingDist tst.w d1 bpl.s Knuckles_HitFloor2 sub.w d1,$C(a0) tst.w $12(a0) bpl.s return_316CAC move.w #0,$12(a0)

return_316CAC:  ; ... rts

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

Knuckles_HitFloor2:  ; ... tst.w $12(a0) bmi.s return_316CD4 bsr.w Player_CheckFloor tst.w d1 bpl.s return_316CD4 add.w d1,$C(a0) move.b d3,$26(a0) bsr.w Knuckles_ResetOnFloor move.w #0,$12(a0) move.w $10(a0),$14(a0)

return_316CD4:  ; ... rts

End of function Knuckles_DoLevelCollision


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


Knuckles_ResetOnFloor:  ; ... tst.b $39(a0) bne.s Knuckles_ResetOnFloor_Part3 move.b #0,$1C(a0)

End of function Knuckles_ResetOnFloor


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


Knuckles_ResetOnFloor_Part2:  ; ... move.b $16(a0),d0 move.b #$13,$16(a0) move.b #9,$17(a0) btst #2,$22(a0) beq.s Knuckles_ResetOnFloor_Part3 bclr #2,$22(a0) move.b #0,$1C(a0) sub.b #$13,d0 ext.w d0 add.w d0,$C(a0)

Knuckles_ResetOnFloor_Part3:  ; ... bclr #1,$22(a0) bclr #5,$22(a0) bclr #4,$22(a0) move.b #0,$3C(a0) move.w #0,($FFFFF7D0).w move.b #0,$27(a0) move.b #0,$29(a0) move.b #0,$2C(a0) move.w #0,($FFFFF66C).w move.b #0,$21(a0) cmp.b #$20,$1C(a0) bcc.s loc_316D5C cmp.b #$14,$1C(a0) bne.s return_316D62

loc_316D5C:  ; ... move.b #0,$1C(a0)

return_316D62:  ; ... rts

End of function Knuckles_ResetOnFloor_Part2


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


Obj01_Hurt:  ; ...

FUNCTION CHUNK AT 00316E14 SIZE 0000001C BYTES

tst.w ($FFFFFFDA).w beq.s Obj01_Hurt_Normal btst #4,($FFFFF605).w beq.s Obj01_Hurt_Normal move.w #1,($FFFFFE08).w clr.b ($FFFFF7CC).w rts

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

Obj01_Hurt_Normal:  ; ... tst.b $25(a0) bmi.w Knuckles_HurtInstantRecover jsr ObjectMove  ; AKA SpeedToPos in Sonic 1 add.w #$30,$12(a0) btst #6,$22(a0) beq.s loc_316DA0 sub.w #$20,$12(a0)

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

loc_316DAE:  ; ... bsr.w Knuckles_HurtStop bsr.w Knuckles_LevelBoundaries bsr.w Knuckles_RecordPositions bsr.w Knuckles_Animate bsr.w LoadKnucklesDynPLC jmp DisplaySprite

End of function Obj01_Hurt


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


Knuckles_HurtStop:  ; ... move.w ($FFFFEECE).w,d0 add.w #$E0,d0 cmp.w $C(a0),d0 blt.w JmpTo_KillCharacter bsr.w Knuckles_DoLevelCollision btst #1,$22(a0) bne.s return_316E0C moveq #0,d0 move.w d0,$12(a0) move.w d0,$10(a0) move.w d0,$14(a0) move.b d0,$2A(a0) move.b #0,$1C(a0) subq.b #2,$24(a0) move.w #$78,$30(a0) move.b #0,$39(a0)

return_316E0C:  ; ... rts

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

JmpTo_KillCharacter:  ; ... jmp KillCharacter

End of function Knuckles_HurtStop
---------------------------------------------------------------------------
START OF FUNCTION CHUNK FOR Obj01_Hurt

Knuckles_HurtInstantRecover:  ; ... subq.b #2,$24(a0) move.b #0,$25(a0) bsr.w Knuckles_RecordPositions bsr.w Knuckles_Animate bsr.w LoadKnucklesDynPLC jmp DisplaySprite

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


Obj01_Dead:  ; ... tst.w ($FFFFFFDA).w beq.s loc_316E4A btst #4,($FFFFF605).w beq.s loc_316E4A move.w #1,($FFFFFE08).w clr.b ($FFFFF7CC).w rts

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

loc_316E4A:  ; ... bsr.w CheckGameOver jsr ObjectMoveAndFall bsr.w Knuckles_RecordPositions bsr.w Knuckles_Animate bsr.w LoadKnucklesDynPLC jmp DisplaySprite

End of function Obj01_Dead


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


CheckGameOver:  ; ... move.b #1,($FFFFEEBE).w move.b #0,$39(a0) move.w ($FFFFEECE).w,d0 add.w #$100,d0 cmp.w $C(a0),d0 bge.w return_316F64 move.b #8,$24(a0) move.w #$3C,$3A(a0) addq.b #1,($FFFFFE1C).w subq.b #1,($FFFFFE12).w bne.s Obj01_ResetLevel move.w #0,$3A(a0) move.b #$39,($FFFFB080).w move.b #$39,($FFFFB0C0).w move.b #1,($FFFFB0DA).w move.w a0,($FFFFB0BE).w clr.b ($FFFFFE1A).w

Obj01_Finished:  ; ... clr.b ($FFFFFE1E).w clr.b ($FFFFFECA).w move.b #8,$24(a0) move.w #$9B,d0 jsr PlayMusic moveq #3,d0 jmp LoadPLC

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

Obj01_ResetLevel:  ; ... tst.b ($FFFFFE1A).w beq.s Obj01_ResetLevel_Part2 move.w #0,$3A(a0) move.b #$39,($FFFFB080).w move.b #$39,($FFFFB0C0).w move.b #2,($FFFFB09A).w move.b #3,($FFFFB0DA).w move.w a0,($FFFFB0BE).w bra.s Obj01_Finished

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

Obj01_ResetLevel_Part2:  ; ... tst.w ($FFFFFFDC).w beq.s return_316F64 move.b #0,($FFFFEEBE).w move.b #$A,$24(a0) move.w ($FFFFFE32).w,8(a0) move.w ($FFFFFE34).w,$C(a0) move.w ($FFFFFE3C).w,2(a0) move.w ($FFFFFE3E).w,$3E(a0) clr.w ($FFFFFE20).w clr.b ($FFFFFE1B).w move.b #0,$2A(a0) move.b #5,$1C(a0) move.w #0,$10(a0) move.w #0,$12(a0) move.w #0,$14(a0) move.b #2,$22(a0) move.w #0,$2E(a0) move.w #0,$3A(a0)

return_316F64:  ; ... rts

End of function CheckGameOver


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


Obj01_Gone:  ; ... tst.w $3A(a0) beq.s return_316F78 subq.w #1,$3A(a0) bne.s return_316F78 move.w #1,($FFFFFE02).w

return_316F78:  ; ... rts

End of function Obj01_Gone
---------------------------------------------------------------------------

Obj01_Respawning:  ; ... tst.w ($FFFFEEB0).w bne.s loc_316F8C tst.w ($FFFFEEB2).w bne.s loc_316F8C move.b #2,$24(a0)

loc_316F8C:  ; ... bsr.w Knuckles_Animate bsr.w LoadKnucklesDynPLC jmp DisplaySprite

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


Knuckles_Animate:  ; ... lea (KnucklesAniData).l,a1 moveq #0,d0 move.b $1C(a0),d0 cmp.b $1D(a0),d0 beq.s KAnim_Do move.b d0,$1D(a0) move.b #0,$1B(a0) move.b #0,$1E(a0) bclr #5,$22(a0)

KAnim_Do:  ; ... add.w d0,d0 add.w (a1,d0.w),a1 move.b (a1),d0 bmi.s KAnim_WalkRun move.b $22(a0),d1 and.b #1,d1 and.b #$FC,1(a0) or.b d1,1(a0) subq.b #1,$1E(a0) bpl.s KAnim_Delay move.b d0,$1E(a0)

KAnim_Do2:  ; ... moveq #0,d1 move.b $1B(a0),d1 move.b 1(a1,d1.w),d0 cmp.b #$FC,d0 bcc.s KAnim_End_FF

KAnim_Next:  ; ... move.b d0,$1A(a0) addq.b #1,$1B(a0)

KAnim_Delay:  ; ... rts

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

KAnim_End_FF:  ; ... addq.b #1,d0 bne.s KAnim_End_FE move.b #0,$1B(a0) move.b 1(a1),d0 bra.s KAnim_Next

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

KAnim_End_FE:  ; ... addq.b #1,d0 bne.s KAnim_End_FD move.b 2(a1,d1.w),d0 sub.b d0,$1B(a0) sub.b d0,d1 move.b 1(a1,d1.w),d0 bra.s KAnim_Next

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

KAnim_End_FD:  ; ... addq.b #1,d0 bne.s KAnim_End move.b 2(a1,d1.w),$1C(a0)

KAnim_End:  ; ... rts

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

KAnim_WalkRun:  ; ... addq.b #1,d0 bne.w KAnim_Roll moveq #0,d0 move.b $27(a0),d0 bne.w KAnim_Tumble moveq #0,d1 move.b $26(a0),d0 bmi.s loc_31704E beq.s loc_31704E subq.b #1,d0

loc_31704E:  ; ... move.b $22(a0),d2 and.b #1,d2 bne.s loc_31705A not.b d0

loc_31705A:  ; ... add.b #$10,d0 bpl.s loc_317062 moveq #3,d1

loc_317062:  ; ... and.b #$FC,1(a0) eor.b d1,d2 or.b d2,1(a0) btst #5,$22(a0) bne.w KAnim_Push lsr.b #4,d0 and.b #6,d0 move.w $14(a0),d2 bpl.s loc_317086 neg.w d2

loc_317086:  ; ... tst.b $2B(a0) bpl.w loc_317090 add.w d2,d2

loc_317090:  ; ... lea (KnucklesAni_Run).l,a1 cmp.w #$600,d2 bcc.s loc_3170A4 lea (KnucklesAni_Walk).l,a1 add.b d0,d0

loc_3170A4:  ; ... add.b d0,d0 move.b d0,d3 moveq #0,d1 move.b $1B(a0),d1 move.b 1(a1,d1.w),d0 cmp.b #$FF,d0 bne.s loc_3170C2 move.b #0,$1B(a0) move.b 1(a1),d0

loc_3170C2:  ; ... move.b d0,$1A(a0) add.b d3,$1A(a0) subq.b #1,$1E(a0) bpl.s return_3170E4 neg.w d2 add.w #$800,d2 bpl.s loc_3170DA moveq #0,d2

loc_3170DA:  ; ... lsr.w #8,d2 move.b d2,$1E(a0) addq.b #1,$1B(a0)

return_3170E4:  ; ... rts

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

KAnim_Tumble:  ; ... move.b $27(a0),d0 moveq #0,d1 move.b $22(a0),d2 and.b #1,d2 bne.s KAnim_Tumble_Left and.b #$FC,1(a0) add.b #$B,d0 divu.w #$16,d0 add.b #$31,d0 move.b d0,$1A(a0) move.b #0,$1E(a0) rts

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

KAnim_Tumble_Left:  ; ... and.b #$FC,1(a0) tst.b $29(a0) beq.s loc_31712C or.b #1,1(a0) add.b #$B,d0 bra.s loc_317138

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

loc_31712C:  ; ... or.b #3,1(a0) neg.b d0 add.b #-$71,d0

loc_317138:  ; ... divu.w #$16,d0 add.b #$31,d0 move.b d0,$1A(a0) move.b #0,$1E(a0) rts

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

KAnim_Roll:  ; ... subq.b #1,$1E(a0) bpl.w KAnim_Delay addq.b #1,d0 bne.s KAnim_Push move.w $14(a0),d2 bpl.s loc_317160 neg.w d2

loc_317160:  ; ... lea (KnucklesAni_Roll2).l,a1 cmp.w #$600,d2 bcc.s loc_317172 lea (KnucklesAni_Roll).l,a1

loc_317172:  ; ... neg.w d2 add.w #$400,d2 bpl.s loc_31717C moveq #0,d2

loc_31717C:  ; ... lsr.w #8,d2 move.b d2,$1E(a0) move.b $22(a0),d1 and.b #1,d1 and.b #$FC,1(a0) or.b d1,1(a0) bra.w KAnim_Do2

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

KAnim_Push:  ; ... subq.b #1,$1E(a0) bpl.w KAnim_Delay move.w $14(a0),d2 bmi.s loc_3171A8 neg.w d2

loc_3171A8:  ; ... add.w #$800,d2 bpl.s loc_3171B0 moveq #0,d2

loc_3171B0:  ; ... lsr.w #8,d2 move.b d2,$1E(a0) lea (KnucklesAni_Push).l,a1 move.b $22(a0),d1 and.b #1,d1 and.b #$FC,1(a0) or.b d1,1(a0) bra.w KAnim_Do2

End of function Knuckles_Animate
---------------------------------------------------------------------------

KnucklesAniData:dc.w KnucklesAni_Walk-KnucklesAniData; 0 ; ... dc.w KnucklesAni_Run-KnucklesAniData; 1 dc.w KnucklesAni_Roll-KnucklesAniData; 2 dc.w KnucklesAni_Roll2-KnucklesAniData; 3 dc.w KnucklesAni_Push-KnucklesAniData; 4 dc.w KnucklesAni_Wait-KnucklesAniData; 5 dc.w KnucklesAni_Balance-KnucklesAniData; 6 dc.w KnucklesAni_LookUp-KnucklesAniData; 7 dc.w KnucklesAni_Duck-KnucklesAniData; 8 dc.w KnucklesAni_Spindash-KnucklesAniData; 9 dc.w KnucklesAni_Unused-KnucklesAniData; 10 dc.w KnucklesAni_Pull-KnucklesAniData; 11 dc.w KnucklesAni_Balance2-KnucklesAniData; 12 dc.w KnucklesAni_Stop-KnucklesAniData; 13 dc.w KnucklesAni_Float-KnucklesAniData; 14 dc.w KnucklesAni_Float2-KnucklesAniData; 15 dc.w KnucklesAni_Spring-KnucklesAniData; 16 dc.w KnucklesAni_Hang-KnucklesAniData; 17 dc.w KnucklesAni_Unused_0-KnucklesAniData; 18 dc.w KnucklesAni_S3EndingPose-KnucklesAniData; 19 dc.w KnucklesAni_WFZHang-KnucklesAniData; 20 dc.w KnucklesAni_Bubble-KnucklesAniData; 21 dc.w KnucklesAni_DeathBW-KnucklesAniData; 22 dc.w KnucklesAni_Drown-KnucklesAniData; 23 dc.w KnucklesAni_Death-KnucklesAniData; 24 dc.w KnucklesAni_OilSlide-KnucklesAniData; 25 dc.w KnucklesAni_Hurt-KnucklesAniData; 26 dc.w KnucklesAni_OilSlide_0-KnucklesAniData; 27 dc.w KnucklesAni_Blank-KnucklesAniData; 28 dc.w KnucklesAni_Unused_1-KnucklesAniData; 29 dc.w KnucklesAni_Unused_2-KnucklesAniData; 30 dc.w KnucklesAni_Transform-KnucklesAniData; 31 dc.w KnucklesAni_Gliding-KnucklesAniData; 32 dc.w KnucklesAni_FallFromGlide-KnucklesAniData; 33 dc.w KnucklesAni_GetUp-KnucklesAniData; 34 dc.w KnucklesAni_HardFall-KnucklesAniData; 35 dc.w KnucklesAni_Badass-KnucklesAniData; 36 KnucklesAni_Walk:dc.b $FF, 7, 8, 1, 2, 3, 4, 5, 6,$FF; 0 ; ... KnucklesAni_Run:dc.b $FF,$21,$22,$23,$24,$FF,$FF,$FF,$FF,$FF; 0 ; ... KnucklesAni_Roll:dc.b $FE,$9A,$96,$9A,$97,$9A,$98,$9A,$99,$FF; 0 ; ... KnucklesAni_Roll2:dc.b $FE,$9A,$96,$9A,$97,$9A,$98,$9A,$99,$FF; 0 ; ... KnucklesAni_Push:dc.b $FD,$CE,$CF,$D0,$D1,$FF,$FF,$FF,$FF,$FF; 0 ; ... KnucklesAni_Wait:dc.b 5,$56,$56,$56,$56,$56,$56,$56,$56,$56,$56,$56,$56; 0 ; ... dc.b $56,$56,$56,$56,$56,$56,$56,$56,$56,$56,$56,$56,$56; 13 dc.b $56,$56,$56,$56,$56,$56,$56,$56,$56,$56,$56,$56,$56; 26 dc.b $56,$56,$56,$56,$56,$56,$56,$56,$56,$56,$56,$56,$D2; 39 dc.b $D2,$D2,$D3,$D3,$D3,$D2,$D2,$D2,$D3,$D3,$D3,$D2,$D2; 52 dc.b $D2,$D3,$D3,$D3,$D2,$D2,$D2,$D3,$D3,$D3,$D2,$D2,$D2; 65 dc.b $D3,$D3,$D3,$D2,$D2,$D2,$D3,$D3,$D3,$D2,$D2,$D2,$D3; 78 dc.b $D3,$D3,$D2,$D2,$D2,$D3,$D3,$D3,$D2,$D2,$D2,$D3,$D3; 91 dc.b $D3,$D4,$D4,$D4,$D4,$D4,$D7,$D8,$D9,$DA,$DB,$D8,$D9; 104 dc.b $DA,$DB,$D8,$D9,$DA,$DB,$D8,$D9,$DA,$DB,$D8,$D9,$DA; 117 dc.b $DB,$D8,$D9,$DA,$DB,$D8,$D9,$DA,$DB,$D8,$D9,$DA,$DB; 130 dc.b $DC,$DD,$DC,$DD,$DE,$DE,$D8,$D7,$FF; 143 KnucklesAni_Balance:dc.b 3,$9F,$9F,$A0,$A0,$A1,$A1,$A2,$A2,$A3,$A3,$A4,$A4; 0 ; ... dc.b $A5,$A5,$A5,$A5,$A5,$A5,$A5,$A5,$A5,$A5,$A5,$A5,$A5; 13 dc.b $A5,$A5,$A6,$A6,$A6,$A7,$A7,$A7,$A8,$A8,$A9,$A9,$AA; 26 dc.b $AA,$FE, 6  ; 39 KnucklesAni_LookUp:dc.b 5,$D5,$D6,$FE, 1  ; 0 ; ... KnucklesAni_Duck:dc.b 5,$9B,$9C,$FE, 1  ; 0 ; ... KnucklesAni_Spindash:dc.b 0,$86,$87,$86,$88,$86,$89,$86,$8A,$86,$8B,$FF; 0 ; ... KnucklesAni_Unused:dc.b 9,$BA,$C5,$C6,$C6,$C6,$C6,$C6,$C6,$C7,$C7,$C7,$C7; 0 ; ... dc.b $C7,$C7,$C7,$C7,$C7,$C7,$C7,$C7,$FD, 0; 13 KnucklesAni_Pull:dc.b $F,$8F,$FF  ; 0 ; ... KnucklesAni_Balance2:dc.b 3,$A1,$A1,$A2,$A2,$A3,$A3,$A4,$A4,$A5,$A5,$A5,$A5; 0 ; ... dc.b $A5,$A5,$A5,$A5,$A5,$A5,$A5,$A5,$A5,$A5,$A5,$A6,$A6; 13 dc.b $A6,$A7,$A7,$A7,$A8,$A8,$A9,$A9,$AA,$AA,$FE; 26 dc.b 6 KnucklesAni_Stop:dc.b 3,$9D,$9E,$9F,$A0,$FD, 0  ; 0 ; ... KnucklesAni_Float:dc.b 7,$C0,$FF  ; 0 ; ... KnucklesAni_Float2:dc.b 5,$C0,$C1,$C2,$C3,$C4,$C5,$C6,$C7,$C8,$C9,$FF; 0 ; ... KnucklesAni_Spring:dc.b $2F,$8E,$FD, 0  ; 0 ; ... KnucklesAni_Hang:dc.b 1,$AE,$AF,$FF  ; 0 ; ... KnucklesAni_Unused_0:dc.b $F,$43,$43,$43,$FE, 1  ; 0 ; ... KnucklesAni_S3EndingPose:dc.b 5,$B1,$B2,$B2,$B2,$B3,$B4,$FE, 1, 7,$B1,$B3,$B3; 0 ; ... dc.b $B3,$B3,$B3,$B3,$B2,$B3,$B4,$B3,$FE, 4; 13 KnucklesAni_WFZHang:dc.b $13,$91,$FF  ; 0 ; ... KnucklesAni_Bubble:dc.b $B,$B0,$B0, 3, 4,$FD, 0  ; 0 ; ... KnucklesAni_DeathBW:dc.b $20,$AC,$FF  ; 0 ; ... KnucklesAni_Drown:dc.b $20,$AD,$FF  ; 0 ; ... KnucklesAni_Death:dc.b $20,$AB,$FF  ; 0 ; ... KnucklesAni_OilSlide:dc.b 9,$8C,$FF  ; 0 ; ... KnucklesAni_Hurt:dc.b $40,$8D,$FF  ; 0 ; ... KnucklesAni_OilSlide_0:dc.b 9,$8C,$FF  ; 0 ; ... KnucklesAni_Blank:dc.b $77, 0,$FF  ; 0 ; ... KnucklesAni_Unused_1:dc.b $13,$D0,$D1,$FF  ; 0 ; ... KnucklesAni_Unused_2:dc.b 3,$CF,$C8,$C9,$CA,$CB,$FE  ; 0 ; ... dc.b 4 KnucklesAni_Gliding:dc.b $1F,$C0,$FF  ; 0 ; ... KnucklesAni_FallFromGlide:dc.b 7,$CA,$CB,$FE, 1  ; 0 ; ... KnucklesAni_GetUp:dc.b $F,$CD,$FD, 0  ; 0 ; ... KnucklesAni_HardFall:dc.b $F,$9C,$FD, 0  ; 0 ; ... KnucklesAni_Badass:dc.b 5,$D8,$D9,$DA,$DB,$D8,$D9,$DA,$DB,$D8,$D9,$DA,$DB; 0 ; ... dc.b $D8,$D9,$DA,$DB,$D8,$D9,$DA,$DB,$D8,$D9,$DA,$DB,$D8; 13 dc.b $D9,$DA,$DB,$D8,$D9,$DA,$DB,$DC,$DD,$DC,$DD,$DE,$DE; 26 dc.b $FF  ; 39 KnucklesAni_Transform:dc.b 2,$EB,$EB,$EC,$ED,$EC,$ED,$EC,$ED,$EC,$ED,$EC,$ED; 0 ; ... dc.b $FD, 0, 0  ; 13

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


LoadKnucklesDynPLC:  ; ... moveq #0,d0 move.b $1A(a0),d0

End of function LoadKnucklesDynPLC
START OF FUNCTION CHUNK FOR sub_333D66

LoadKnucklesDynPLC_Part2:  ; ... cmp.b ($FFFFF766).w,d0 beq.w return_31753E move.b d0,($FFFFF766).w lea (SK_PLC_Knuckles).l,a2  ; SK_PLC_Knuckles add.w d0,d0 add.w (a2,d0.w),a2 move.w (a2)+,d5 subq.w #1,d5 bmi.w return_31753E moveq #0,d3 lea ($FFFFF100).w,a3  ; RAM address where the converted art will be stored lea ArtConvTable(pc),a4  ; Load art-conversion table

KPLC_ReadEntry:  ; ... moveq #0,d0 moveq #0,d1 move.w (a2)+,d1 move.w d1,d4 rol.w #4,d4 and.w #$F,d4 addq.w #1,d3 add.w d4,d3 and.w #$FFF,d1 lsl.l #5,d1 lea (SK_ArtUnc_Knux).l,a1  ; SK_ArtUnc_Knux add.l d1,a1

KPLC_ConvertArtFromS3K:  ; ... move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+ move.b (a1)+,d0 move.b (a4,d0.w),(a3)+  ; Repeated $20 times dbf d4,KPLC_ConvertArtFromS3K dbf d5,KPLC_ReadEntry move.l #$FFF100,d1  ; RAM address where the converted art was stored move.w #$F000,d2  ; VRAM address for Knuckles' art lsl.w #4,d3 jmp QueueDMATransfer

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

return_31753E:  ; ... rts

END OF FUNCTION CHUNK FOR sub_333D66
---------------------------------------------------------------------------
This table converts art using palette indexes set for S&K to palette indexes set for S2.
Format
The rightmost nybble of entry X in any row = the new index that replaces color X.
Similarly, the leftmost nybble of entry X in any column = the new index that replaces color X.
Specific replacements
$0 -> $0
$1 -> $6
$2 -> $5
$3 -> $3
$4 -> $2
$5 -> $4
$6 -> $C
$7 -> $D
$8 -> $E
$9 -> $F
$A -> $A
$B -> $B
$C -> $7
$D -> $8
$E -> $9
$F -> $1
---------------------------------------------------------------------------

ArtConvTable: dc.b $00,$06,$05,$03,$02,$04,$0C,$0D,$0E,$0F,$0A,$0B,$07,$08,$09,$01; 0 ; ... dc.b $60,$66,$65,$63,$62,$64,$6C,$6D,$6E,$6F,$6A,$6B,$67,$68,$69,$61; 16 dc.b $50,$56,$55,$53,$52,$54,$5C,$5D,$5E,$5F,$5A,$5B,$57,$58,$59,$51; 32 dc.b $30,$36,$35,$33,$32,$34,$3C,$3D,$3E,$3F,$3A,$3B,$37,$38,$39,$31; 48 dc.b $20,$26,$25,$23,$22,$24,$2C,$2D,$2E,$2F,$2A,$2B,$27,$28,$29,$21; 64 dc.b $40,$46,$45,$43,$42,$44,$4C,$4D,$4E,$4F,$4A,$4B,$47,$48,$49,$41; 80 dc.b $C0,$C6,$C5,$C3,$C2,$C4,$CC,$CD,$CE,$CF,$CA,$CB,$C7,$C8,$C9,$C1; 96 dc.b $D0,$D6,$D5,$D3,$D2,$D4,$DC,$DD,$DE,$DF,$DA,$DB,$D7,$D8,$D9,$D1; 112 dc.b $E0,$E6,$E5,$E3,$E2,$E4,$EC,$ED,$EE,$EF,$EA,$EB,$E7,$E8,$E9,$E1; 128 dc.b $F0,$F6,$F5,$F3,$F2,$F4,$FC,$FD,$FE,$FF,$FA,$FB,$F7,$F8,$F9,$F1; 144 dc.b $A0,$A6,$A5,$A3,$A2,$A4,$AC,$AD,$AE,$AF,$AA,$AB,$A7,$A8,$A9,$A1; 160 dc.b $B0,$B6,$B5,$B3,$B2,$B4,$BC,$BD,$BE,$BF,$BA,$BB,$B7,$B8,$B9,$B1; 176 dc.b $70,$76,$75,$73,$72,$74,$7C,$7D,$7E,$7F,$7A,$7B,$77,$78,$79,$71; 192 dc.b $80,$86,$85,$83,$82,$84,$8C,$8D,$8E,$8F,$8A,$8B,$87,$88,$89,$81; 208 dc.b $90,$96,$95,$93,$92,$94,$9C,$9D,$9E,$9F,$9A,$9B,$97,$98,$99,$91; 224 dc.b $10,$16,$15,$13,$12,$14,$1C,$1D,$1E,$1F,$1A,$1B,$17,$18,$19,$11; 240

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

</asm> Change all "Obj01"s to "Obj4C"s.

And we're done!

Finally, we can stop worrying about Knuckles' code and get on with our lives. :D

Added Step #1: Making Obj4C's Ptr

Just when you thought you were done with this, you found out that I found out this! Getting tired? Well, this step should solve your problems! Go to s2.constants.asm and find these two lines: <asm> ObjID_Buzzer = id(ObjPtr_Buzzer) ; 4B ObjID_Aquis = id(ObjPtr_Aquis) ; 50 </asm> Uh oh, it seems an observant eye may catch the fact that the index goes from 4B straight to 50. skipping the first four null object values. We're going to add one to change that number to three. Between the two aforementioned lines, add this: <asm> ObjID_Knuckles = id(ObjPtr_Knuckles)  ; 4C </asm> And there you go! That should solve most, if not all, of the errors. If I have missed anything, don't hesitate to let me know.