ThomasSpeedrunner icon

Knuckles Code

ThomasSpeedrunner | PRO | 04/22/13 01:27:31 AM UTC | 0 ⭐ | 337 👁️ | Never ⏰ | []
text |

76.86 KB

|

None

|

0 👍

/

0 👎

; ---------------------------------------------------------------------------
; Object 4C - Knuckles
; ---------------------------------------------------------------------------
 Obj4C_InitChk:
	; a0=character
	tst.w	(Debug_placement_mode).w	; is debug mode being used?
	beq.s	Obj4C_Normal		; if not, branch
	jmp	(DebugMode).l
; ---------------------------------------------------------------------------
 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
        	offsetTableEntry.w Obj4C_Drowned                  ; $C
; ---------------------------------------------------------------------------
 Obj4C_Init:
	addq.b	#2,routine(a0)
	move.b	#$13,y_radius(a0)
	move.b	#9,x_radius(a0)
	move.l	#SK_Map_Knuckles,mappings(a0)	  ; SK_Map_Knuckles
	move.w	#$100,priority(a0)
	move.b	#$18,width_pixels(a0)
	move.b	#4,render_flags(a0)
	move.w	#$600,(Sonic_top_speed).w
	move.w	#$C,(Sonic_acceleration).w
	move.w	#$80,(Sonic_deceleration).w
	tst.b	(Last_star_pole_hit).w
	bne.s	Obj4C_Init_Continued
	; only happens when not starting at a checkpoint:
	move.w	#make_art_tile(ArtTile_ArtUnc_Knuckles,0,0),art_tile(a0)
	jsr	Adjust2PArtPointer2
	move.b	#$C,layer(a0)
	move.b	#$D,layer_plus(a0)
	move.w	x_pos(a0),(Saved_x_pos).w
	move.w	y_pos(a0),(Saved_y_pos).w
	move.w	art_tile(a0),(Saved_art_tile).w
	move.w	layer(a0),(Saved_layer).w
 Obj4C_Init_Continued:
	move.b	#0,flips_remaining(a0)
	move.b	#4,flip_speed(a0)
	move.b	#0,(Super_Sonic_flag).w
	move.b	#$1E,air_left(a0)
	sub.w	#$20,x_pos(a0)
	add.w	#4,y_pos(a0)
	move.w	#0,(Sonic_Pos_Record_Index).w
 	move.w	#$3F,d2
-	bsr.w	Knuckles_RecordPos
	subq.w	#4,a1
	move.l	#0,(a1)
	dbf	d2,-
 	add.w	#$20,x_pos(a0)
	sub.w	#4,y_pos(a0)
 Obj4C_Control:
	tst.w	(Debug_mode_flag).w		; is debug cheat enabled?
	beq.s	+				; if not, branch
	btst	#button_B,(Ctrl_1_Press).w	; is button B pressed?
	beq.s	+				; if not, branch
	move.w	#1,(Debug_placement_mode).w	; change Sonic into a ring/item
	clr.b	(Control_Locked).w		; unlock control
	rts
; ---------------------------------------------------------------------------
+
	tst.b	($FFFFF7CC).w
	bne.s	+
	move.w	($FFFFF604).w,($FFFFF602).w
+
	btst	#0,obj_control(a0)
	beq.s	+
	move.b	#0,$42(a0)
	bra.s	++
; ---------------------------------------------------------------------------
+
	moveq	#0,d0
	move.b	status(a0),d0
	and.w	#6,d0
	move.w	Obj4C_Modes(pc,d0.w),d1
	jsr	Obj4C_Modes(pc,d1.w)
+
	cmpi.w	#-$100,(Camera_Min_Y_pos).w	; is vertical wrapping enabled?
	bne.s	+				; if not, branch
	andi.w	#$7FF,y_pos(a0) 		; perform wrapping of Knuckles' y position
+
	bsr.s	Knuckles_Display
	bsr.w	Knuckles_Super
	bsr.w	Knuckles_RecordPos
	bsr.w	Knuckles_Water
	move.b	($FFFFF768).w,next_tilt(a0)
	move.b	($FFFFF76A).w,tilt(a0)
	tst.b	($FFFFF7C7).w
	beq.s	+
	tst.b	anim(a0)
	bne.s	+
	move.b	next_anim(a0),anim(a0)
+
	bsr.w	Knuckles_Animate
	tst.b	obj_control(a0)
	bmi.s	+
	jsr	TouchResponse
+
	bra.w	LoadKnucklesDynPLC
; ---------------------------------------------------------------------------
Obj4C_Modes:	offsetTable
                offsetTableEntry.w Obj4C_MdNormal             	  ; 0
        	offsetTableEntry.w Obj4C_MdAir            	  ; 1
        	offsetTableEntry.w Obj4C_MdRoll         	  ; 2
        	offsetTableEntry.w Obj4C_MdJump          	  ; 3
 ; =============== S U B	R O U T	I N E =======================================
  Knuckles_Display:
	move.b	invulnerable_time(a0),d0
	beq.s	Obj4C_Display
	subq.b	#1,invulnerable_time(a0)
	lsr.w	#3,d0
	bcc.s	Obj4C_ChkInvin
 Obj4C_Display:
	jsr	(DisplaySprite).l
 Obj4C_ChkInvin:
	btst	#1,status_secondary(a0)
	beq.s	Obj4C_ChkShoes
	tst.b	invincibility_time(a0)
	beq.s	Obj4C_ChkShoes
	move.b	($FFFFFE05).w,d0
	andi.b	#7,d0
	bne.s	Obj4C_ChkShoes
	subq.b	#1,invincibility_time(a0)
	bne.s	Obj4C_ChkShoes
	tst.b	(Current_Boss_ID).w
	bne.s	Obj4C_RmvInvin
	cmp.b	#$C,air_left(a0)
	bcs.s	Obj4C_RmvInvin
	move.w	(Level_Music).w,d0
	jsr	PlayMusic
 Obj4C_RmvInvin:
	bclr	#1,status_secondary(a0)
 Obj4C_ChkShoes:
	btst	#2,status_secondary(a0)
	beq.s	Obj4C_ChkHiJmp
	tst.b	speedshoes_time(a0)
	beq.s	Obj4C_ChkHiJmp
	move.b	($FFFFFE05).w,d0
	andi.b	#7,d0
	bne.s	Obj4C_ChkHiJmp
	subq.b	#1,speedshoes_time(a0)
	bne.s	Obj4C_ChkHiJmp
	move.w	#$600,(Sonic_top_speed).w
	move.w	#$C,(Sonic_acceleration).w
	move.w	#$80,(Sonic_deceleration).w
	tst.b	(Super_Sonic_flag).w
	beq.s	Obj4C_RmvSpeed
	move.w	#$A00,(Sonic_top_speed).w
	move.w	#$30,(Sonic_acceleration).w
	move.w	#$100,(Sonic_deceleration).w
 Obj4C_RmvSpeed:
	bclr	#2,status_secondary(a0)
	move.w	#$FC,d0
	jmp	(PlayMusic).l
 Obj4C_ChkHiJmp:
	btst    #3,status_secondary(a0)
	beq.s   Obj4C_ExitChk
	tst.b   hijump_time(a0)
	beq.s   Obj4C_ExitChk
	move.b	($FFFFFE05).w,d0
	andi.b	#7,d0
	bne.s	Obj4C_ExitChk
	subq.b  #1,hijump_time(a0)
	bne.s   Obj4C_ExitChk
	move.w  #$600,d2                ; set stats
	tst.b   (Super_Sonic_flag).w    ; is Knuckles in his Super form?
	beq.s   Obj4C_RmvHiJmp          ; if not, branch
	move.w  #$780,d2
 Obj4C_RmvHiJmp:
	bclr    #3,status_secondary(a0)
; ---------------------------------------------------------------------------
 Obj4C_ExitChk:
	rts
; End of function Knuckles_Display
  ; =============== S U B	R O U T	I N E =======================================
  Knuckles_RecordPos:
	move.w	($FFFFEED2).w,d0
	lea	($FFFFE500).w,a1
	lea	(a1,d0.w),a1
	move.w	x_pos(a0),(a1)+
	move.w	y_pos(a0),(a1)+
	addq.b	#4,($FFFFEED3).w
	lea	($FFFFE400).w,a1
	lea	(a1,d0.w),a1
	move.w	($FFFFF602).w,(a1)+
	move.w	status(a0),(a1)+
	rts
; End of function Knuckles_RecordPos
  ; =============== S U B	R O U T	I N E =======================================
  Knuckles_Water:
	tst.b	(Water_flag).w  ; does level have water?
	bne.s	Obj4C_InWater   ; if so, branch
 return_31556C:
	rts
; ---------------------------------------------------------------------------
 Obj4C_InWater:
	move.w	(Water_Level_1).w,d0
	cmp.w	y_pos(a0),d0
	bge.s	Obj4C_OutWater
  	tst.w	y_vel(a0)	; check if player is moving upward (i.e. from jumping)
	bmi.s	return_31556C	; if yes, skip routine
 	bset	#6,status(a0)	; set underwater flag
	bne.s	return_31556C	; if already underwater, branch
 	move.l	a0,a1
	jsr	ResumeMusic
	move.b	#$A,($FFFFD080).w
	move.b	#$81,($FFFFD0A8).w
	move.l	a0,($FFFFD0BC).w
	move.w	#$300,(Sonic_top_speed).w
	move.w	#6,(Sonic_acceleration).w
	move.w	#$40,(Sonic_deceleration).w
	tst.b	(Super_Sonic_flag).w
	beq.s	+
	move.w	#$500,(Sonic_top_speed).w
	move.w	#$18,(Sonic_acceleration).w
	move.w	#$80,(Sonic_deceleration).w
+
	asr	x_vel(a0)
	asr	y_vel(a0)
	asr	y_vel(a0)
	beq.s	return_31556C
	move.w	#$100,($FFFFD11C).w
	move.w	#$AA,d0
	jmp	PlaySound
; ---------------------------------------------------------------------------
 Obj4C_OutWater:
	bclr	#6,status(a0)
	beq.s	return_31556C
	move.l	a0,a1
	jsr	ResumeMusic
	move.w	#$600,(Sonic_top_speed).w
	move.w	#$C,(Sonic_acceleration).w
	move.w	#$80,(Sonic_deceleration).w
	tst.b	(Super_Sonic_flag).w
	beq.s	+
	move.w	#$A00,(Sonic_top_speed).w
	move.w	#$18,(Sonic_acceleration).w
	move.w	#$100,(Sonic_deceleration).w
+
;	cmpi.b	#4,routine(a0)
;	beq.s	+
	asl	y_vel(a0)
;+
	tst.w	y_vel(a0)
	beq.w	return_31556C
	move.w	#$100,($FFFFD11C).w
	move.l	a0,a1
	jsr	ResumeMusic
	cmp.w	#$F000,y_vel(a0)
	bgt.s	+
	move.w	#$F000,y_vel(a0)
+
	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_CheckSpindash
	bsr.w	Knuckles_Jump
	bsr.w	Knuckles_SlopeResist
	bsr.w	Knuckles_Move
	bsr.w	Knuckles_Roll
	bsr.w	Knuckles_LevelBound
	jsr	ObjectMove	  ; AKA	SpeedToPos in Sonic 1
	jsr	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	$42(a0)
	bne.s	Obj4C_MdAir_Gliding
	bsr.w	Knuckles_JumpHeight
	bsr.w	Knuckles_ChgJumpDir
	bsr.w	Knuckles_LevelBound
	jsr	ObjectMoveAndFall
	btst	#6,status(a0)
	beq.s	loc_31569C
	sub.w	#$28,y_vel(a0)
 loc_31569C:
	bsr.w	Knuckles_JumpAngle
	bsr.w	Knuckles_DoLevelCollision
	rts
; ---------------------------------------------------------------------------
 Obj4C_MdAir_Gliding: 
	bsr.w	Knuckles_GlideSpeedControl
	bsr.w	Knuckles_LevelBound
	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	$42(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,y_radius(a0)
	move.b	#$A,x_radius(a0)
	bsr.w	Knuckles_DoLevelCollision2
	btst	#5,($FFFFF7AC).w
	bne.w	Knuckles_BeginClimb
	move.b	#$13,y_radius(a0)
	move.b	#9,x_radius(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,$42(a0)
	move.b	#$21,anim(a0)
	bclr	#0,status(a0)
	tst.w	x_vel(a0)
	bpl.s	loc_315736
	bset	#0,status(a0)
 loc_315736:
	asr	x_vel(a0)
	asr	x_vel(a0)
	move.b	#$13,y_radius(a0)
	move.b	#9,x_radius(a0)
	rts
; ---------------------------------------------------------------------------
 loc_31574C:
	bra.w	sub_315C7C
; ---------------------------------------------------------------------------
 Knuckles_BeginSlide: 
	bclr	#0,status(a0)
	tst.w	x_vel(a0)
	bpl.s	loc_315762
	bset	#0,status(a0)
 loc_315762:
	move.b	angle(a0),d0
	add.b	#$20,d0
	and.b	#$C0,d0
	beq.s	loc_315780
	move.w	inertia(a0),x_vel(a0)
	move.w	#0,y_vel(a0)
	bra.w	Knuckles_ResetOnFloor_Part2
; ---------------------------------------------------------------------------
 loc_315780:
	move.b	#3,$42(a0)
	move.b	#$CC,mapping_frame(a0)
	move.b	#$7F,anim_frame_duration(a0)
	move.b	#0,anim_frame(a0)
	cmp.b	#$C,air_left(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	layer_plus(a0),d5
	move.b	$43(a0),d0
	add.b	#$40,d0
	bpl.s	loc_3157D8
	bset	#0,status(a0)
	jsr	CheckLeftCeilingDist
	or.w	d0,d1
	bne.s	Knuckles_FallFromGlide
	addq.w	#1,x_pos(a0)
	bra.s	loc_3157E8
; ---------------------------------------------------------------------------
 loc_3157D8:
	bclr	#0,status(a0)
	jsr	CheckRightCeilingDist
	or.w	d0,d1
	bne.w	loc_31586A
 loc_3157E8:
	move.b	#$13,y_radius(a0)
	move.b	#9,x_radius(a0)
	tst.b	(Super_Sonic_flag).w
	beq.s	loc_315804
	cmp.w	#$480,inertia(a0)
	bcs.s	loc_315804
	nop
 loc_315804:
	move.w	#0,inertia(a0)
	move.w	#0,x_vel(a0)
	move.w	#0,y_vel(a0)
	move.b	#4,$42(a0)
	move.b	#$B7,mapping_frame(a0)
	move.b	#$7F,anim_frame_duration(a0)
	move.b	#0,anim_frame(a0)
	move.b	#3,$43(a0)
	move.w	x_pos(a0),x_sub(a0)
;	move.w	#SndID_WallGrab,d0
;	jmp	(PlaySound).l
	rts
; ---------------------------------------------------------------------------
 Knuckles_FallFromGlide:
	move.w	x_pos(a0),d3
	move.b	y_radius(a0),d0
	ext.w	d0
	sub.w	d0,d3
	subq.w	#1,d3
 loc_31584A:
	move.w	y_pos(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,y_pos(a0)
	bra.w	loc_3157E8
; ---------------------------------------------------------------------------
 loc_31586A:
	move.w	x_pos(a0),d3
	move.b	y_radius(a0),d0
	ext.w	d0
	add.w	d0,d3
	addq.w	#1,d3
	bra.s	loc_31584A
; ---------------------------------------------------------------------------
 loc_31587A:
	move.b	#2,$42(a0)
	move.b	#$21,anim(a0)
	move.b	#$13,y_radius(a0)
	move.b	#9,x_radius(a0)
	bset	#1,($FFFFF7AC).w
	rts
; ---------------------------------------------------------------------------
 Knuckles_FallingFromGlide:
	bsr.w	Knuckles_ChgJumpDir
	add.w	#$38,y_vel(a0)
	btst	#6,status(a0)
	beq.s	loc_3158B2
	sub.w	#$28,y_vel(a0)
 loc_3158B2:
	bsr.w	Knuckles_DoLevelCollision2
	btst	#1,($FFFFF7AC).w
	bne.s	return_315900
	move.w	#0,inertia(a0)
	move.w	#0,x_vel(a0)
	move.w	#0,y_vel(a0)
	move.b	y_radius(a0),d0
	sub.b	#$13,d0
	ext.w	d0
	add.w	d0,y_pos(a0)
	move.b	angle(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.b	#$F,move_lock(a0)
	move.b	#$23,anim(a0)
;	move.w	#SndID_Land,d0
;	jmp	(PlaySound).l
 return_315900:
	rts
; ---------------------------------------------------------------------------
 Knuckles_Sliding:
	move.b	($FFFFF602).w,d0
	and.b	#$70,d0
	beq.s	loc_315926
	tst.w	x_vel(a0)
	bpl.s	loc_31591E
	add.w	#$20,x_vel(a0)
	bmi.s	loc_31591C
	bra.s	loc_315926
; ---------------------------------------------------------------------------
 loc_31591C:
	bra.s	loc_315958
; ---------------------------------------------------------------------------
 loc_31591E:
	sub.w	#$20,x_vel(a0)
	bpl.s	loc_315958
 loc_315926:
	move.w	#0,inertia(a0)
	move.w	#0,x_vel(a0)
	move.w	#0,y_vel(a0)
	move.b	y_radius(a0),d0
	sub.b	#$13,d0
	ext.w	d0
	add.w	d0,y_pos(a0)
	bsr.w	Knuckles_ResetOnFloor_Part2
	move.b	#$F,move_lock(a0)
	move.b	#$22,anim(a0)
	rts
; ---------------------------------------------------------------------------
 loc_315958:
	move.b	#$A,y_radius(a0)
	move.b	#$A,x_radius(a0)
	bsr.w	Knuckles_DoLevelCollision2
	jsr	Sonic_CheckFloor
	cmp.w	#$E,d1
	bge.s	loc_315988
	add.w	d1,y_pos(a0)
	move.b	d3,angle(a0)
	move.b	#$13,y_radius(a0)
	move.b	#9,x_radius(a0)
;	move.b	(Timer_frames+1).w,d0
;	andi.b	#7,d0
;	bne.s	+
;	moveq	#SndID_Slide,d0
;	jmp	(PlaySound).l
;+
	rts
; ---------------------------------------------------------------------------
 loc_315988:
	move.b	#2,$42(a0)
	move.b	#$21,anim(a0)
	move.b	#$13,y_radius(a0)
	move.b	#9,x_radius(a0)
	bset	#1,($FFFFF7AC).w
	rts
; ---------------------------------------------------------------------------
 Knuckles_Climbing_Wall:
	tst.b	($FFFFF7AD).w
	bmi.w	loc_315BAE
	move.w	x_pos(a0),d0
	cmp.w	x_sub(a0),d0
	bne.w	loc_315BAE
	btst	#3,status(a0)
	bne.w	loc_315BAE
	move.w	#0,inertia(a0)
	move.w	#0,x_vel(a0)
	move.w	#0,y_vel(a0)
	move.l	#$FFFFD600,($FFFFF796).w
	cmp.b	#$D,layer_plus(a0)
	beq.s	loc_3159F0
	move.l	#$FFFFD900,($FFFFF796).w
 loc_3159F0:
	move.b	layer_plus(a0),d5
	move.b	#$A,y_radius(a0)
	move.b	#$A,x_radius(a0)
	moveq	#0,d1
	btst	#0,($FFFFF602).w
	beq.w	loc_315A76
	move.w	y_pos(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	layer_plus(a0),d5
	move.w	y_pos(a0),d2
	subq.w	#8,d2
	move.w	x_pos(a0),d3
	bsr.w	sub_3192E6	  ; Doesn't exist in S2
	tst.w	d1
	bpl.s	loc_315A46
	sub.w	d1,y_pos(a0)
	moveq	#1,d1
	bra.w	loc_315B04
; ---------------------------------------------------------------------------
 loc_315A46:
	subq.w	#1,y_pos(a0)
	tst.b	(Super_Sonic_flag).w
	beq.s	loc_315A54
	subq.w	#1,y_pos(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	y_pos(a0),d0
	ble.w	loc_315B04
	move.w	d0,y_pos(a0)
	bra.w	loc_315B04
; ---------------------------------------------------------------------------
 loc_315A76:
	btst	#1,($FFFFF602).w
	beq.w	loc_315B04
	cmp.b	#$BD,mapping_frame(a0)
	bne.s	loc_315AA2
	move.b	#$B7,mapping_frame(a0)
	addq.w	#3,y_pos(a0)
	subq.w	#3,x_pos(a0)
	btst	#0,status(a0)
	beq.s	loc_315AA2
	addq.w	#6,x_pos(a0)
 loc_315AA2:
	move.w	y_pos(a0),d2
	add.w	#$B,d2
	bsr.w	sub_315C22
	tst.w	d1
	bne.w	loc_315BAE
	move.b	layer(a0),d5
	move.w	y_pos(a0),d2
	add.w	#9,d2
	move.w	x_pos(a0),d3
	bsr.w	sub_318FF6
	tst.w	d1
	bpl.s	loc_315AF4
	add.w	d1,y_pos(a0)
	move.b	($FFFFF768).w,angle(a0)
	move.w	#0,inertia(a0)
	move.w	#0,x_vel(a0)
	move.w	#0,y_vel(a0)
	bsr.w	Knuckles_ResetOnFloor_Part2
	move.b	#5,anim(a0)
	rts
; ---------------------------------------------------------------------------
 loc_315AF4:
	addq.w	#1,y_pos(a0)
	tst.b	(Super_Sonic_flag).w
	beq.s	loc_315B02
	addq.w	#1,y_pos(a0)
 loc_315B02:
	moveq	#-1,d1
 loc_315B04:
	tst.w	d1
	beq.s	loc_315B30
	subq.b	#1,$43(a0)
	bpl.s	loc_315B30
	move.b	#3,$43(a0)
	add.b	mapping_frame(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,mapping_frame(a0)
 loc_315B30:
	move.b	#$20,anim_frame_duration(a0)
	move.b	#0,anim_frame(a0)
	move.b	#$13,y_radius(a0)
	move.b	#9,x_radius(a0)
	move.w	($FFFFF602).w,d0
	and.w	#$70,d0
	beq.s	return_315B94
	move.w	#$FC80,y_vel(a0)
	move.w	#$400,x_vel(a0)
	bchg	#0,status(a0)
	bne.s	loc_315B6A
	neg.w	x_vel(a0)
 loc_315B6A:
	bset	#1,status(a0)
	move.b	#1,jumping(a0)
	move.b	#$E,y_radius(a0)
	move.b	#7,x_radius(a0)
	move.b	#2,anim(a0)
	bset	#2,status(a0)
	move.b	#0,$42(a0)
 return_315B94:
	rts
; ---------------------------------------------------------------------------
 Knuckles_ClimbUp:
	move.b	#5,$42(a0)	  ; Climb up to	the floor above	you
	cmp.b	#$BD,mapping_frame(a0)
	beq.s	return_315BAC
	move.b	#0,$43(a0)
	bsr.s	sub_315BDA
 return_315BAC:
	rts
; ---------------------------------------------------------------------------
 loc_315BAE:
	move.b	#2,$42(a0)
	move.w	#$2121,anim(a0)
	move.b	#$CB,mapping_frame(a0)
	move.b	#7,anim_frame_duration(a0)
	move.b	#1,anim_frame(a0)
	move.b	#$13,y_radius(a0)
	move.b	#9,x_radius(a0)
	rts
; End of function Knuckles_GlideControl
  ; =============== S U B	R O U T	I N E =======================================
  sub_315BDA:
	moveq	#0,d0
	move.b	$43(a0),d0
	lea	word_315C12(pc,d0.w),a1
	move.b	(a1)+,mapping_frame(a0)
	move.b	(a1)+,d0
	ext.w	d0
	btst	#0,status(a0)
	beq.s	loc_315BF6
	neg.w	d0
 loc_315BF6:
	add.w	d0,x_pos(a0)
	move.b	(a1)+,d1
	ext.w	d1
	add.w	d1,y_pos(a0)
	move.b	(a1)+,anim_frame_duration(a0)
	addq.b	#4,$43(a0)
	move.b	#0,anim_frame(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	layer_plus(a0),d5
	btst	#0,status(a0)
	bne.s	loc_315C36
	move.w	x_pos(a0),d3
	bra.w	loc_319208
; ---------------------------------------------------------------------------
 loc_315C36:
	move.w	x_pos(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	anim_frame_duration(a0)
	bne.s	return_315C7A
	bsr.w	sub_315BDA
	cmp.b	#$10,$43(a0)
	bne.s	return_315C7A
	move.w	#0,inertia(a0)
	move.w	#0,x_vel(a0)
	move.w	#0,y_vel(a0)
	btst	#0,status(a0)
	beq.s	loc_315C70
	subq.w	#1,x_pos(a0)
 loc_315C70:
	bsr.w	Knuckles_ResetOnFloor_Part2
	move.b	#5,anim(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,anim_frame_duration(a0)
	move.b	#0,anim_frame(a0)
	move.w	#$2020,anim(a0)
	bclr	#5,status(a0)
	bclr	#0,status(a0)
	moveq	#0,d0
	move.b	$43(a0),d0
	add.b	#$10,d0
	lsr.w	#5,d0
	move.b	byte_315CC2(pc,d0.w),d1
	move.b	d1,mapping_frame(a0)
	cmp.b	#$C4,d1
	bne.s	return_315CC0
	bset	#0,status(a0)
	move.b	#$C0,mapping_frame(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,$42(a0)
	bne.w	loc_315D88
	move.w	inertia(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	$43(a0),d1
	and.b	#$7F,d1
	bne.s	loc_315CFC
	addq.w	#4,d0
	tst.b	(Super_Sonic_flag).w
	beq.s	loc_315CFC
	addq.w	#8,d0
 loc_315CFC:
	move.w	d0,inertia(a0)
	move.b	$43(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,$43(a0)
	move.b	$43(a0),d0
	jsr	CalcSine
	muls.w	inertia(a0),d1
	asr.l	#8,d1
	move.w	d1,x_vel(a0)
	cmp.w	#$80,y_vel(a0)
	blt.s	loc_315D62
	sub.w	#$20,y_vel(a0)
	bra.s	loc_315D68
; ---------------------------------------------------------------------------
 loc_315D62:
	add.w	#$20,y_vel(a0)
 loc_315D68:
	move.w	($FFFFEECC).w,d0
	cmp.w	#$FF00,d0
	beq.w	loc_315D88
	add.w	#$10,d0
	cmp.w	y_pos(a0),d0
	ble.w	loc_315D88
	asr	x_vel(a0)
	asr	inertia(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
 ; ---------------------------------------------------------------------------
 Obj4C_MdRoll:
	tst.b	spindash_flag(a0)
	bne.s	loc_315DA6
	bsr.w	Knuckles_Jump
 loc_315DA6:
	bsr.w	Knuckles_RollRepel
	bsr.w	Knuckles_RollSpeed
	bsr.w	Knuckles_LevelBound
	jsr	ObjectMove	  ; AKA	SpeedToPos in Sonic 1
	jsr	AnglePos
	bsr.w	Knuckles_SlopeRepel
	rts
; ---------------------------------------------------------------------------
 Obj4C_MdJump:
	bsr.w	Knuckles_JumpHeight
	bsr.w	Knuckles_ChgJumpDir
	bsr.w	Knuckles_LevelBound
	jsr	ObjectMoveAndFall
	btst	#6,status(a0)
	beq.s	loc_315DE2
	sub.w	#$28,y_vel(a0)
 loc_315DE2:
	bsr.w	Knuckles_JumpAngle
	bsr.w	Knuckles_DoLevelCollision
	rts
 ; =============== S U B	R O U T	I N E =======================================
  Knuckles_Move:
	move.w	(Sonic_top_speed).w,d6
	move.w	(Sonic_acceleration).w,d5
	move.w	(Sonic_deceleration).w,d4
	tst.b	status_secondary(a0)
	bmi.w	Obj4C_Traction
	tst.b	move_lock(a0)
	bne.w	Obj4C_ResetScreen
	btst	#2,($FFFFF602).w
	beq.s	Obj4C_NotLeft
	bsr.w	Knuckles_MoveLeft
 Obj4C_NotLeft:
	btst	#3,($FFFFF602).w
	beq.s	Obj4C_NotRight
	bsr.w	Knuckles_MoveRight
 Obj4C_NotRight:
	move.b	angle(a0),d0
	add.b	#$20,d0
	and.b	#$C0,d0	; is Knuckles on a slope?
	bne.w	Obj4C_ResetScreen	; if yes, branch
	tst.w	inertia(a0)	; is Knuckles moving?
	bne.w	Obj4C_ResetScreen	; if yes, branch
	bclr	#5,status(a0)
	move.b	#5,anim(a0)
	btst	#3,status(a0)
	beq.w	Knuckles_Balance
	moveq	#0,d0
	move.b	interact(a0),d0
	lsl.w	#6,d0
	lea	(Object_RAM).w,a1 ; a1=character
	lea	(a1,d0.w),a1 ; a1=object
	tst.b	status(a1)
	bmi.w	Knuckles_LookUp
	moveq	#0,d1
	move.b	width_pixels(a1),d1
	move.w	d1,d2
	add.w	d2,d2
	subq.w	#2,d2
	add.w	x_pos(a0),d1
	sub.w	y_pos(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,status(a0)
	bne.s	loc_315E9A
	move.b	#6,anim(a0)
	bra.w	Obj4C_ResetScreen
; ---------------------------------------------------------------------------
 loc_315E9A:
	bclr	#0,status(a0)
	move.b	#0,anim_frame_duration(a0)
	move.b	#4,anim_frame(a0)
	move.w	#$606,anim(a0)
	bra.w	Obj4C_ResetScreen
; ---------------------------------------------------------------------------
 Knuckles_BalanceOnObjLeft:
	btst	#0,status(a0)
	beq.s	loc_315EC8
	move.b	#6,anim(a0)
	bra.w	Obj4C_ResetScreen
; ---------------------------------------------------------------------------
 loc_315EC8:
	bset	#0,status(a0)
	move.b	#0,anim_frame_duration(a0)
	move.b	#4,anim_frame(a0)
	move.w	#$606,anim(a0)
	bra.w	Obj4C_ResetScreen
; ---------------------------------------------------------------------------
 Knuckles_Balance:
	jsr	(ChkFloorEdge).l
	cmp.w	#$C,d1
	blt.w	Knuckles_LookUp
	cmp.b	#3,next_tilt(a0)
	bne.s	Knuckles_BalanceLeft
	btst	#0,status(a0)
	bne.s	loc_315F0C
	move.b	#6,anim(a0)
	bra.w	Obj4C_ResetScreen
; ---------------------------------------------------------------------------
 loc_315F0C:
	bclr	#0,status(a0)
	move.b	#0,anim_frame_duration(a0)
	move.b	#4,anim_frame(a0)
	move.w	#$606,anim(a0)
	bra.w	Obj4C_ResetScreen
; ---------------------------------------------------------------------------
 Knuckles_BalanceLeft:
	cmp.b	#3,tilt(a0)
	bne.s	Knuckles_LookUp
	btst	#0,status(a0)
	beq.s	loc_315F42
	move.b	#6,anim(a0)
	bra.w	Obj4C_ResetScreen
; ---------------------------------------------------------------------------
 loc_315F42:
	bset	#0,status(a0)
	move.b	#0,anim_frame_duration(a0)
	move.b	#4,anim_frame(a0)
	move.w	#$606,anim(a0)
	bra.w	Obj4C_ResetScreen
; ---------------------------------------------------------------------------
 Knuckles_LookUp:
	btst	#0,($FFFFF602).w
	beq.s	Knuckles_Duck
	move.b	#7,anim(a0)
	addq.w	#1,(Sonic_Look_delay_counter).w
	cmpi.w	#$78,(Sonic_Look_delay_counter).w
	blo.s	Obj4C_ResetScreen_Part2
	move.w	#$78,(Sonic_Look_delay_counter).w
	cmpi.w	#$C8,(Camera_Y_pos_bias).w
	beq.s	Obj4C_UpdateSpeedOnGround
	addq.w	#2,(Camera_Y_pos_bias).w
	bra.s	Obj4C_UpdateSpeedOnGround
; ---------------------------------------------------------------------------
 Knuckles_Duck:
	btst	#1,($FFFFF602).w
	beq.s	Obj4C_ResetScreen
	move.b	#8,anim(a0)
	addq.w	#1,($FFFFF66C).w
	cmp.w	#$78,($FFFFF66C).w
	bcs.s	Obj4C_ResetScreen_Part2
	move.w	#$78,($FFFFF66C).w
	cmp.w	#8,($FFFFEED8).w
	beq.s	Obj4C_UpdateSpeedOnGround
	subq.w	#2,($FFFFEED8).w
	bra.s	Obj4C_UpdateSpeedOnGround
; ---------------------------------------------------------------------------
 Obj4C_ResetScreen:
	move.w	#0,($FFFFF66C).w
 Obj4C_ResetScreen_Part2:
	cmp.w	#$60,($FFFFEED8).w
	beq.s	Obj4C_UpdateSpeedOnGround
	bcc.s	loc_315FCE
	addq.w	#4,($FFFFEED8).w
 loc_315FCE:
	subq.w	#2,($FFFFEED8).w
 ; ---------------------------------------------------------------------------
 Obj4C_UpdateSpeedOnGround:
	tst.b	(Super_Sonic_flag).w
	beq.s	loc_315FDC
	move.w	#$C,d5
 loc_315FDC:
	move.b	($FFFFF602).w,d0
	and.b	#$C,d0
	bne.s	Obj4C_Traction
	move.w	inertia(a0),d0
	beq.s	Obj4C_Traction
	bmi.s	Obj4C_SettleLeft
	sub.w	d5,d0
	bcc.s	loc_315FF6
	move.w	#0,d0
 loc_315FF6:
	move.w	d0,inertia(a0)
	bra.s	Obj4C_Traction
; ---------------------------------------------------------------------------
 Obj4C_SettleLeft:
	add.w	d5,d0
	bcc.s	loc_316004
	move.w	#0,d0
 loc_316004:
	move.w	d0,inertia(a0)
 Obj4C_Traction:
	move.b	angle(a0),d0
	jsr	CalcSine
	muls.w	inertia(a0),d1
	asr.l	#8,d1
	move.w	d1,x_vel(a0)
	muls.w	inertia(a0),d0
	asr.l	#8,d0
	move.w	d0,y_vel(a0)
 Obj4C_CheckWallsOnGround:
	move.b	angle(a0),d0
	add.b	#$40,d0
	bmi.s	return_3160A6
	move.b	#$40,d1
	tst.w	inertia(a0)
	beq.s	return_3160A6
	bmi.s	loc_31603E
	neg.w	d1
 loc_31603E:
	move.b	angle(a0),d0
	add.b	d1,d0
	move.w	d0,-(sp)
	jsr	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,x_vel(a0)
	move.w	#0,inertia(a0)
	btst	#0,status(a0)
	bne.s	return_316080
	bset	#5,status(a0)
 return_316080:
	rts
; ---------------------------------------------------------------------------
 loc_316082:
	sub.w	d1,y_vel(a0)
	rts
; ---------------------------------------------------------------------------
 loc_316088:
	sub.w	d1,x_vel(a0)
	move.w	#0,inertia(a0)
	btst	#0,status(a0)
	beq.s	return_316080
	bset	#5,status(a0)
	rts
; ---------------------------------------------------------------------------
 loc_3160A2:
	add.w	d1,y_vel(a0)
 return_3160A6:
	rts
; End of function Knuckles_Move
  ; =============== S U B	R O U T	I N E =======================================
  Knuckles_MoveLeft: 
	move.w	inertia(a0),d0
	beq.s	loc_3160B0
	bpl.s	Knuckles_TurnLeft
 loc_3160B0:
	bset	#0,status(a0)
	bne.s	loc_3160C4
	bclr	#5,status(a0)
	move.b	#1,next_anim(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,inertia(a0)
	move.b	#0,anim(a0)
	rts
; ---------------------------------------------------------------------------
 Knuckles_TurnLeft: 
	sub.w	d4,d0
	bcc.s	loc_3160EA
	move.w	#-$80,d0
 loc_3160EA:
	move.w	d0,inertia(a0)
	move.b	angle(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,anim(a0)
	bclr	#0,status(a0)
	move.w	#$A4,d0
	jsr	PlaySound
	cmp.b	#$C,air_left(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	inertia(a0),d0
	bmi.s	Knuckles_TurnRight
	bclr	#0,status(a0)
	beq.s	loc_316148
	bclr	#5,status(a0)
	move.b	#1,next_anim(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,inertia(a0)
	move.b	#0,anim(a0)
	rts
; ---------------------------------------------------------------------------
 Knuckles_TurnRight: 
	add.w	d4,d0
	bcc.s	loc_31616A
	move.w	#$80,d0
 loc_31616A:
	move.w	d0,inertia(a0)
	move.b	angle(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,anim(a0)
	bset	#0,status(a0)
	move.w	#$A4,d0
	jsr	PlaySound
	cmp.b	#$C,air_left(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	(Sonic_top_speed).w,d6
	asl.w	#1,d6
	moveq	#6,d5
	move.w	#$20,d4
	tst.b	status_secondary(a0)
	bmi.w	Obj4C_Roll_ResetScreen
	tst.b	move_lock(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	inertia(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,inertia(a0)
	bra.s	Knuckles_CheckRollStop
; ---------------------------------------------------------------------------
 Knuckles_ApplyRollSpeedLeft: 
	add.w	d5,d0
	bcc.s	loc_316202
	move.w	#0,d0
 loc_316202:
	move.w	d0,inertia(a0)
 Knuckles_CheckRollStop: 
	tst.w	inertia(a0)
	bne.s	Obj4C_Roll_ResetScreen
	tst.b	spindash_flag(a0)
	bne.s	Knuckles_KeepRolling
	bclr	#2,status(a0)
	move.b	#$13,y_radius(a0)
	move.b	#9,x_radius(a0)
	move.b	#5,anim(a0)
	subq.w	#5,y_pos(a0)
	bra.s	Obj4C_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,inertia(a0)
	btst	#0,status(a0)
	beq.s	Obj4C_Roll_ResetScreen
	neg.w	inertia(a0)
 Obj4C_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	angle(a0),d0
	jsr	CalcSine
	muls.w	inertia(a0),d0
	asr.l	#8,d0
	move.w	d0,y_vel(a0)
	muls.w	inertia(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,x_vel(a0)
	bra.w	Obj4C_CheckWallsOnGround
; End of function Knuckles_RollSpeed
  ; =============== S U B	R O U T	I N E =======================================
  Knuckles_RollLeft: 
	move.w	inertia(a0),d0
	beq.s	loc_316292
	bpl.s	Knuckles_BrakeRollingRight
 loc_316292:
	bset	#0,status(a0)
	move.b	#2,anim(a0)
	rts
; ---------------------------------------------------------------------------
 Knuckles_BrakeRollingRight: 
	sub.w	d4,d0
	bcc.s	loc_3162A8
	move.w	#-$80,d0
 loc_3162A8:
	move.w	d0,inertia(a0)
	rts
; End of function Knuckles_RollLeft
  ; =============== S U B	R O U T	I N E =======================================
  Knuckles_RollRight: 
	move.w	inertia(a0),d0
	bmi.s	Knuckles_BrakeRollingLeft
	bclr	#0,status(a0)
	move.b	#2,anim(a0)
	rts
; ---------------------------------------------------------------------------
 Knuckles_BrakeRollingLeft: 
	add.w	d4,d0
	bcc.s	loc_3162CA
	move.w	#$80,d0
 loc_3162CA:
	move.w	d0,inertia(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	(Sonic_top_speed).w,d6
	move.w	(Sonic_acceleration).w,d5
	asl.w	#1,d5
	btst	#4,status(a0)
	bne.s	Obj4C_Jump_ResetScreen
	move.w	x_vel(a0),d0
	btst	#2,($FFFFF602).w
	beq.s	++
	bset	#0,status(a0)
	sub.w	d5,d0
	move.w	d6,d1
	neg.w	d1
	cmp.w	d1,d0	; compare new speed with top speed
	bgt.s	++	; if new speed is less than the maximum, branch
	add.w	d5,d0	; remove this frame's acceleration change
	cmp.w	d1,d0	; compare speed with top speed
	ble.s	++	; if speed was already greater than the maximum, branch
	tst.w	($FFFFFFD0).w
	bne.s	+
	add.w	d5,d0
	cmp.w	d1,d0
	ble.s	++
+
	move.w	d1,d0
+
	btst	#3,($FFFFF602).w
	beq.s	++
	bclr	#0,status(a0)
	add.w	d5,d0
	cmp.w	d6,d0
	blt.s	++
	sub.w	d5,d0	; remove this frame's acceleration change
	cmp.w	d1,d0	; compare speed with top speed
	bge.s	++	; if speed was already greater than the maximum, branch
	tst.w	($FFFFFFD0).w
	bne.s	+
	sub.w	d5,d0
	cmp.w	d6,d0
	bge.s	++
+
	move.w	d6,d0
+
	move.w	d0,x_vel(a0)
 Obj4C_Jump_ResetScreen:
	cmp.w	#$60,($FFFFEED8).w
	beq.s	Knuckles_JumpPeakDecelerate
	bcc.s	+
	addq.w	#4,($FFFFEED8).w
+
	subq.w	#2,($FFFFEED8).w
 Knuckles_JumpPeakDecelerate:
	cmp.w	#-$400,y_vel(a0)
	bcs.s	return_316376
	move.w	x_vel(a0),d0
	move.w	d0,d1
	asr.w	#5,d1
	beq.s	return_316376
	bmi.s	Knuckles_JumpPeakDecelerateLeft
	sub.w	d1,d0
	bcc.s	+
	move.w	#0,d0
+
	move.w	d0,x_vel(a0)
	rts
; ---------------------------------------------------------------------------
 Knuckles_JumpPeakDecelerateLeft:
	sub.w	d1,d0
	bcs.s	+
	move.w	#0,d0
+
	move.w	d0,x_vel(a0)
 return_316376:
	rts
; End of function Knuckles_ChgJumpDir
  ; =============== S U B	R O U T	I N E =======================================
  Knuckles_LevelBound:
	move.l	x_pos(a0),d1
	move.w	x_vel(a0),d0
	ext.l	d0
	asl.l	#8,d0
	add.l	d0,d1
	swap	d1
	move.w	($FFFFEEC8).w,d0
	add.w	#$10,d0
	cmp.w	d1,d0
	bhi.s	Knuckles_Boundary_Sides
	move.w	(Camera_Max_X_pos).w,d0
	addi.w	#$128,d0
	tst.b	(Current_Boss_ID).w
	bne.s	+
	addi.w	#$40,d0
+
	cmp.w	d1,d0			; has Knuckles touched the right boundary?
	bls.s	Knuckles_Boundary_Sides	; if yes, branch
 Knuckles_Boundary_CheckBottom:
	move.w	(Camera_Max_Y_pos_now).w,d0
	addi.w	#$E0,d0
	cmp.w	y_pos(a0),d0
	blt.s	Knuckles_Boundary_Bottom
	rts
; ---------------------------------------------------------------------------
 Knuckles_Boundary_Bottom:
        addq.l  #4,sp
	jmp	(KillCharacter).l
; ---------------------------------------------------------------------------
 Knuckles_Boundary_Sides:
	move.w	d0,x_pos(a0)
	move.w	#0,x_sub(a0)
	move.w	#0,x_vel(a0)
	move.w	#0,inertia(a0)
	bra.s	Knuckles_Boundary_CheckBottom
; End of function Knuckles_LevelBound
  ; =============== S U B	R O U T	I N E =======================================
  Knuckles_Roll:
	tst.b	status_secondary(a0)
	bmi.s	Obj4C_NoRoll
	move.w	inertia(a0),d0
	bpl.s	loc_3163E6
	neg.w	d0
 loc_3163E6:
	cmp.w	#$80,d0
	bcs.s	Obj4C_NoRoll
	move.b	($FFFFF602).w,d0
	and.b	#$C,d0
	bne.s	Obj4C_NoRoll
	btst	#1,($FFFFF602).w
	bne.s	Obj4C_ChkRoll
 Obj4C_NoRoll:
	rts
; ---------------------------------------------------------------------------
 Obj4C_ChkRoll:
	btst	#2,status(a0)
	beq.s	Obj4C_DoRoll
	rts
; ---------------------------------------------------------------------------
 Obj4C_DoRoll:
	bset	#2,status(a0)
	move.b	#$E,y_radius(a0)
	move.b	#7,x_radius(a0)
	move.b	#2,anim(a0)
	addq.w	#5,y_pos(a0)
	move.w	#$BE,d0
	jsr	PlaySound
	tst.w	inertia(a0)
	bne.s	return_31643C
	move.w	#$200,inertia(a0)
 return_31643C:
	rts
; End of function Knuckles_Roll
  ; ---------------------------------------------------------------------------
; Subroutine allowing Knuckles to jump
; ---------------------------------------------------------------------------
 ; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
  Knuckles_Jump:
	move.b	(Ctrl_1_Press_Logical).w,d0
	and.b	#button_B_mask|button_C_mask,d0
	beq.w	return_3164EC
	moveq	#0,d0
	move.b	angle(a0),d0
	add.b	#$80,d0
	jsr	CalcRoomOverHead
	cmp.w	#6,d1
	blt.w	return_3164EC
	move.w	#$600,d2
	tst.b	(Super_Sonic_flag).w	; Test if super
	beq.s	+       		; if not, branch
	move.w	#$780,d2        	; set higher jump speed if super
+
	btst	#6,status(a0)   	; Test if underwater
	beq.s	+                       ; if not, branch
	move.w	#$380,d2        	; set lower jump speed if underwater
+
	btst    #3,status_secondary(a0) ; Test if high jump powerup is active
	beq.s   +                       ; if it isn't, branch
	move.w  #$700,d2                ; So it is? Set Knuckles' jump height
	tst.b   (Super_Sonic_flag).w    ; Test to see if we're in our Super form
	beq.s   +                       ; if we aren't, branch
	move.w  #$800,d2                ; So we are? Set Knuckles' jump height
+
	tst.w	(Demo_mode_flag).w	; Check for demo mode
	beq.s	+
	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.
+
	moveq	#0,d0
	move.b	angle(a0),d0
	sub.b	#$40,d0
	jsr	CalcSine
	muls.w	d2,d1
	asr.l	#8,d1
	add.w	d1,x_vel(a0)     	; make Knuckles jump (in X... this adds nothing on level ground)
	muls.w	d2,d0
	asr.l	#8,d0
	add.w	d0,y_vel(a0)    	; make Knuckles jump (in Y)
	bset	#1,status(a0)
	bclr	#5,status(a0)
	addq.l	#4,sp
	move.b	#1,jumping(a0)
	clr.b	stick_to_convex(a0)
	move.w	#$A0,d0
	jsr	(PlaySound).l           ; play jumping sound
;	move.b	#$13,y_radius(a0)
;	move.b	#9,x_radius(a0)
	btst	#2,status(a0)
	bne.s	Knuckles_RollJump
	move.b	#$E,y_radius(a0)
	move.b	#7,x_radius(a0)
	move.b	#2,anim(a0)	; use "jumping" animation
	bset	#2,status(a0)
	addq.w	#5,y_pos(a0)
 return_3164EC:
	rts
; ---------------------------------------------------------------------------
 Knuckles_RollJump: 
	bset	#4,status(a0)
	rts
; End of function Knuckles_Jump
  ; =============== S U B	R O U T	I N E =======================================
  Knuckles_JumpHeight: 
	tst.b	jumping(a0)
	beq.s	Knuckles_UpwardsVelocityCap
	move.w	#-$400,d1
	btst	#6,status(a0)
	beq.s	loc_31650C
	move.w	#-$200,d1
 loc_31650C:
	cmp.w	y_vel(a0),d1
	ble.w	Knuckles_CheckGlide		; Check if Knuckles should begin a glide
	move.b	(Ctrl_1_Held_Logical).w,d0
	andi.b	#button_B_mask|button_C_mask,d0	; is a jump button pressed?
	bne.s	return_316522			; if not, return
	move.w	d1,y_vel(a0)
+
	tst.b	(Control_Locked).w	; Are Controls locked?
	bne.s	return_316522	; If so, branch, and do not bother with Super code
	move.b	(Ctrl_1_Press_Logical).w,d0
	andi.b	#button_A_mask,d0	; is the A button pressed?
	bne.w	Knuckles_CheckGoSuper	; if yes, test for turning into Super Knuckles
	rts
 return_316522:
	rts
; ---------------------------------------------------------------------------
 Knuckles_UpwardsVelocityCap:
	tst.b	spindash_flag(a0)
	bne.s	return_316538
	cmp.w	#-$FC0,y_vel(a0)
	bge.s	return_316538
	move.w	#-$FC0,y_vel(a0)
 return_316538:
	rts
; ---------------------------------------------------------------------------
 Knuckles_CheckGlide:
	tst.w	(Demo_mode_flag).w	  ; Don't glide on demos
	bne.w	return_3165D2
	tst.b	$42(a0)
	bne.w	return_3165D2
	move.b	($FFFFF603).w,d0
	and.b	#$70,d0
	beq.w	return_3165D2
	tst.b	(Super_Sonic_flag).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_CheckGoSuper
 Knuckles_BeginGlide:
	bclr	#2,status(a0)
	move.b	#$A,y_radius(a0)
	move.b	#$A,x_radius(a0)
	bclr	#4,status(a0)
	move.b	#1,$42(a0)
	add.w	#$200,y_vel(a0)
	bpl.s	loc_31659E
	move.w	#0,y_vel(a0)
 loc_31659E:
	moveq	#0,d1
	move.w	#$400,d0
	move.w	d0,inertia(a0)
	btst	#0,status(a0)
	beq.s	loc_3165B4
	neg.w	d0
	moveq	#-$80,d1
 loc_3165B4:
	move.w	d0,x_vel(a0)
	move.b	d1,$43(a0)
	move.w	#0,angle(a0)
	move.b	#0,($FFFFF7AC).w
	bset	#1,($FFFFF7AC).w
	bsr.w	sub_315C7C
 return_3165D2:
	rts
; ---------------------------------------------------------------------------
 Knuckles_CheckGoSuper:
	tst.b	(Update_HUD_timer).w	; has Knuckles reached the end of the act?
	beq.w	return_316671		; if yes, branch
         tst.b	(Super_Sonic_flag).w	; is Knuckles already Super?
	bne.w	Knuckles_RevertToNormal	; if yes, branch (This allows for reverting manually)
	cmpi.b	#7,(Emerald_count).w	; does Knuckles have exactly 7 emeralds?
	bne.s	return_316671		; if not, branch
	cmpi.w	#50,(Ring_count).w	; does Knuckles have at least 50 rings?
	blo.s	return_316671		; if not, branch
 	move.b	#1,($FFFFF65F).w
	move.b	#$F,($FFFFF65E).w
	move.b	#1,(Super_Sonic_flag).w
	move.w	#60,($FFFFF670).w
	move.b	#$81,obj_control(a0)
	move.b	#$1F,anim(a0)
	move.b	#$7E,($FFFFD040).w
	move.w	#$A00,(Sonic_top_speed).w
	move.w	#$30,(Sonic_acceleration).w
	move.w	#$100,(Sonic_deceleration).w
	btst	#6,status(a0)	; Check if underwater, return if not
	beq.s	+
	move.w	#$500,(Sonic_top_speed).w
	move.w	#$18,(Sonic_acceleration).w
	move.w	#$80,(Sonic_deceleration).w
+
	move.b	#0,invincibility_time(a0)
	bset	#1,status_secondary(a0)
	move.w	#$DF,d0
	jsr	(PlaySound).l
	move.w	#$97,d0
	jmp	(PlayMusic).l
; End of function Knuckles_JumpHeight
 ; ---------------------------------------------------------------------------
return_316671:
	rts
 ; =============== S U B	R O U T	I N E =======================================
  Knuckles_Super:
	tst.b	(Super_Sonic_flag).w
	beq.w	return_3166C8
	tst.b	(Update_HUD_timer).w
	beq.s	Knuckles_RevertToNormal	; ?
	subq.w	#1,($FFFFF670).w
	bpl.w	return_3166C8
	move.w	#60,($FFFFF670).w
	tst.w	($FFFFFE20).w
	beq.s	Knuckles_RevertToNormal
	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,(Update_HUD_rings).w
 loc_316678:
	subq.w	#1,(Ring_count).w
	bne.s	return_3166C8
 ; originally loc_31667E
Knuckles_RevertToNormal:
	move.b	#2,(Super_Sonic_palette).w
	move.w	#40,(Palette_frame).w
	move.b	#0,(Super_Sonic_flag).w
	move.b	#1,next_anim(a0)
	move.b	#1,invincibility_time(a0)
	move.w	#$600,(Sonic_top_speed).w
	move.w	#$C,(Sonic_acceleration).w
	move.w	#$80,(Sonic_deceleration).w
	btst	#6,status(a0)
	beq.s	return_3166C8
	move.w	#$300,(Sonic_top_speed).w
	move.w	#6,(Sonic_acceleration).w
	move.w	#$40,(Sonic_deceleration).w
 return_3166C8:
	rts
; End of function Knuckles_Super
  ; =============== S U B	R O U T	I N E =======================================
  Knuckles_CheckSpindash:
	tst.b	spindash_flag(a0)
	bne.s	Knuckles_UpdateSpindash
	cmp.b	#8,anim(a0)
	bne.s	return_316718
	move.b	(Ctrl_1_Press_Logical).w,d0
	andi.b	#button_B_mask|button_C_mask|button_A_mask,d0
	beq.w	return_316718
	move.b	#9,anim(a0)
	move.w	#$E0,d0
	jsr	(PlaySound).l
	addq.l	#4,sp
	move.b	#1,spindash_flag(a0)
	move.b	#0,spindash_counter(a0)
	cmpi.b	#$C,air_left(a0)
	bcs.s	+
	move.b	#2,($FFFFD11C).w
+
	bsr.w	Knuckles_LevelBound
	jsr	(AnglePos).l
 return_316718:
	rts
; ---------------------------------------------------------------------------
 Knuckles_UpdateSpindash:
	move.b	(Ctrl_1_Held_Logical).w,d0
	btst	#button_down,d0
	bne.w	Knuckles_ChargingSpindash
 	; unleash the charged spindash and start rolling quickly:
	move.b	#$E,y_radius(a0)
	move.b	#7,x_radius(a0)
	move.b	#2,anim(a0)
	addq.w	#5,y_pos(a0)
	move.b	#0,spindash_flag(a0)
	moveq	#0,d0
	move.b	spindash_counter(a0),d0
	add.w	d0,d0
	move.w	Knuckles_SpindashSpeeds(pc,d0.w),inertia(a0)
	tst.b	(Super_Sonic_flag).w
	beq.s	loc_31675C
	move.w	Knuckles_SpindashSpeedsSuper(pc,d0.w),inertia(a0)
 loc_31675C:
	move.w	inertia(a0),d0
	sub.w	#$800,d0
	add.b	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,status(a0)
	beq.s	loc_316780
	neg.w	inertia(a0)
 loc_316780:
	bset	#2,status(a0)
	move.b	#0,($FFFFD11C).w
	move.w	#$BC,d0
	jsr	(PlaySound).l
	move.b	angle(a0),d0
	jsr	(CalcSine).l
	muls.w	inertia(a0),d1
	asr.l	#8,d1
	move.w	d1,x_vel(a0)
	muls.w	inertia(a0),d0
	asr.l	#8,d0
	move.w	d0,y_vel(a0)
 	bra.s	Obj4C_Spindash_ResetScr
; ---------------------------------------------------------------------------
Knuckles_SpindashSpeeds:
	dc.w  $800	; 0
	dc.w  $880	; 1
	dc.w  $900	; 2
	dc.w  $980	; 3
	dc.w  $A00	; 4
	dc.w  $A80	; 5
	dc.w  $B00	; 6
	dc.w  $B80	; 7
	dc.w  $C00	; 8
 Knuckles_SpindashSpeedsSuper:
	dc.w  $B00	; 0
	dc.w  $B80	; 1
	dc.w  $C00	; 2
	dc.w  $C80	; 3
	dc.w  $D00	; 4
	dc.w  $D80	; 5
	dc.w  $E00	; 6
	dc.w  $E80	; 7
	dc.w  $F00	; 8
; ---------------------------------------------------------------------------
 Knuckles_ChargingSpindash:		  ; If still charging the dash...
	tst.b	spindash_counter(a0)
	beq.s	+
	move.b	spindash_counter(a0),d0
	lsr.b	#5,d0
	sub.b	d0,spindash_counter(a0)
	bcc.s	+
	move.b	#0,spindash_counter(a0)
+
	move.b	(Ctrl_1_Press_Logical).w,d0
	andi.b	#button_B_mask|button_C_mask|button_A_mask,d0
	beq.w	Obj4C_Spindash_ResetScr
	move.w	#$900,anim(a0)
	move.w	#$E0,d0
	jsr	(PlaySound).l
	addi.b	#$1,spindash_counter(a0)
	cmpi.b	#8,spindash_counter(a0)
	bcs.s	Obj4C_Spindash_ResetScr
	move.b	#8,spindash_counter(a0)
	bra.s	Obj4C_Spindash_ResetScr
	move.b	#8,spindash_counter(a0)
 Obj4C_Spindash_ResetScr:
	addq.l	#4,sp
	cmpi.w	#$60,(Camera_Y_pos_bias).w
	beq.s	loc_316818
	bhs.s	+
	addq.w	#4,(Camera_Y_pos_bias).w
+	subq.w	#2,(Camera_Y_pos_bias).w
 loc_316818:
	bsr.w	Knuckles_LevelBound
	jsr	(AnglePos).l
	rts
; End of function Knuckles_Spindash
  ; =============== S U B	R O U T	I N E =======================================
  Knuckles_SlopeResist:
	move.b	angle(a0),d0
	add.b	#$60,d0
	cmp.b	#$C0,d0
	bcc.s	return_316856
	move.b	angle(a0),d0
	jsr	CalcSine
	muls.w	#$20,d0
	asr.l	#8,d0
	tst.w	inertia(a0)
	beq.s	return_316856
	bmi.s	loc_316852
	tst.w	d0
	beq.s	return_316850
	add.w	d0,inertia(a0)
 return_316850:
	rts
; ---------------------------------------------------------------------------
 loc_316852:
	add.w	d0,inertia(a0)
 return_316856:
	rts
; End of function Knuckles_SlopeResist
  ; =============== S U B	R O U T	I N E =======================================
  Knuckles_RollRepel:
	move.b	angle(a0),d0
	add.b	#$60,d0
	cmp.b	#$C0,d0
	bcc.s	return_316892
	move.b	angle(a0),d0
	jsr	CalcSine
	muls.w	#$50,d0
	asr.l	#8,d0
	tst.w	inertia(a0)
	bmi.s	loc_316888
	tst.w	d0
	bpl.s	loc_316882
	asr.l	#2,d0
 loc_316882:
	add.w	d0,inertia(a0)
	rts
; ---------------------------------------------------------------------------
 loc_316888:
	tst.w	d0
	bmi.s	loc_31688E
	asr.l	#2,d0
 loc_31688E:
	add.w	d0,inertia(a0)
 return_316892:
	rts
; End of function Knuckles_RollRepel
  ; =============== S U B	R O U T	I N E =======================================
  Knuckles_SlopeRepel:
	nop
	tst.b	stick_to_convex(a0)
	bne.s	return_3168CE
	tst.b	move_lock(a0)
	bne.s	loc_3168D0
	move.b	angle(a0),d0
	add.b	#$20,d0
	and.b	#$C0,d0
	beq.s	return_3168CE
	move.w	inertia(a0),d0
	bpl.s	loc_3168B8
	neg.w	d0
 loc_3168B8:
	cmp.w	#$280,d0
	bcc.s	return_3168CE
	clr.w	inertia(a0)
	bset	#1,status(a0)
	move.b	#$1E,move_lock(a0)
 return_3168CE:
	rts
; ---------------------------------------------------------------------------
 loc_3168D0:
	subq.b	#1,move_lock(a0)
	rts
; End of function Knuckles_SlopeRepel
  ; =============== S U B	R O U T	I N E =======================================
  Knuckles_JumpAngle: 
	move.b	angle(a0),d0
	beq.s	Knuckles_JumpFlip
	bpl.s	loc_3168E6
	addq.b	#2,d0
	bcc.s	Knuckles_JumpAngleSet
	moveq	#0,d0
	bra.s	Knuckles_JumpAngleSet
; ---------------------------------------------------------------------------
 loc_3168E6:
	subq.b	#2,d0
	bcc.s	Knuckles_JumpAngleSet
	moveq	#0,d0
 Knuckles_JumpAngleSet: 
	move.b	d0,angle(a0)
 Knuckles_JumpFlip: 
	move.b	flip_angle(a0),d0
	beq.s	return_316934
	tst.w	inertia(a0)
	bmi.s	Knuckles_JumpLeftFlip
 Knuckles_JumpRightFlip: 
	move.b	flip_speed(a0),d1
	add.b	d1,d0
	bcc.s	Knuckles_JumpFlipSet
	subq.b	#1,flips_remaining(a0)
	bcc.s	Knuckles_JumpFlipSet
	move.b	#0,flips_remaining(a0)
	moveq	#0,d0
	bra.s	Knuckles_JumpFlipSet
; ---------------------------------------------------------------------------
 Knuckles_JumpLeftFlip: 
	tst.b	flip_turned(a0)
	bne.s	Knuckles_JumpRightFlip
	move.b	flip_speed(a0),d1
	sub.b	d1,d0
	bcc.s	Knuckles_JumpFlipSet
	subq.b	#1,flips_remaining(a0)
	bcc.s	Knuckles_JumpFlipSet
	move.b	#0,flips_remaining(a0)
	moveq	#0,d0
 Knuckles_JumpFlipSet: 
	move.b	d0,flip_angle(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,layer(a0)
	beq.s	loc_31694E
	move.l	#$FFFFD900,($FFFFF796).w
 loc_31694E:
	move.b	layer_plus(a0),d5
	move.w	x_vel(a0),d1
	move.w	y_vel(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
	jsr	CheckLeftWallDist
	tst.w	d1
	bpl.s	loc_316998
	sub.w	d1,x_pos(a0)
	move.w	#0,x_vel(a0)
	bset	#5,($FFFFF7AC).w
 loc_316998:
	jsr	CheckRightWallDist
	tst.w	d1
	bpl.s	loc_3169B0
	add.w	d1,x_pos(a0)
	move.w	#0,x_vel(a0)
	bset	#5,($FFFFF7AC).w
 loc_3169B0:
	jsr	Sonic_CheckFloor
	tst.w	d1
	bpl.s	return_3169CC
	add.w	d1,y_pos(a0)
	move.b	d3,angle(a0)
	move.w	#0,y_vel(a0)
	bclr	#1,($FFFFF7AC).w
 return_3169CC:
	rts
; ---------------------------------------------------------------------------
 Knuckles_HitLeftWall2: 
	jsr	CheckLeftWallDist
	tst.w	d1
	bpl.s	Knuckles_HitCeilingAlt
	sub.w	d1,x_pos(a0)
	move.w	#0,x_vel(a0)
	bset	#5,($FFFFF7AC).w
 Knuckles_HitCeilingAlt: 
	jsr	CheckCeilingDist
	tst.w	d1
	bpl.s	Knuckles_HitFloor
	neg.w	d1
	cmp.w	#$14,d1
	bcc.s	loc_316A08
	add.w	d1,y_pos(a0)
	tst.w	y_vel(a0)
	bpl.s	return_316A06
	move.w	#0,y_vel(a0)
 return_316A06:
	rts
; ---------------------------------------------------------------------------
 loc_316A08:
	jsr	CheckRightWallDist
	tst.w	d1
	bpl.s	return_316A20
	add.w	d1,x_pos(a0)
	move.w	#0,x_vel(a0)
	bset	#5,($FFFFF7AC).w
 return_316A20:
	rts
; ---------------------------------------------------------------------------
 Knuckles_HitFloor: 
	tst.w	y_vel(a0)
	bmi.s	return_316A44
	jsr	Sonic_CheckFloor
	tst.w	d1
	bpl.s	return_316A44
	add.w	d1,y_pos(a0)
	move.b	d3,angle(a0)
	move.w	#0,y_vel(a0)
	bclr	#1,($FFFFF7AC).w
 return_316A44:
	rts
; ---------------------------------------------------------------------------
 Knuckles_HitCeilingAndWalls2: 
	jsr	CheckLeftWallDist
	tst.w	d1
	bpl.s	loc_316A5E
	sub.w	d1,x_pos(a0)
	move.w	#0,x_vel(a0)
	bset	#5,($FFFFF7AC).w
 loc_316A5E:
	jsr	CheckRightWallDist
	tst.w	d1
	bpl.s	loc_316A76
	add.w	d1,x_pos(a0)
	move.w	#0,x_vel(a0)
	bset	#5,($FFFFF7AC).w
 loc_316A76:
	jsr	CheckCeilingDist
	tst.w	d1
	bpl.s	return_316A88
	sub.w	d1,y_pos(a0)
	move.w	#0,y_vel(a0)
 return_316A88:
	rts
; ---------------------------------------------------------------------------
 Knuckles_HitRightWall2: 
	jsr	CheckRightWallDist
	tst.w	d1
	bpl.s	loc_316AA2
	add.w	d1,x_pos(a0)
	move.w	#0,x_vel(a0)
	bset	#5,($FFFFF7AC).w
 loc_316AA2:
	jsr	CheckCeilingDist
	tst.w	d1
	bpl.s	loc_316ABC
	sub.w	d1,y_pos(a0)
	tst.w	y_vel(a0)
	bpl.s	return_316ABA
	move.w	#0,y_vel(a0)
 return_316ABA:
	rts
; ---------------------------------------------------------------------------
 loc_316ABC:
	tst.w	y_vel(a0)
	bmi.s	return_316ADE
	jsr	Sonic_CheckFloor
	tst.w	d1
	bpl.s	return_316ADE
	add.w	d1,y_pos(a0)
	move.b	d3,angle(a0)
	move.w	#0,y_vel(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,layer(a0)
	beq.s	loc_316AF8
	move.l	#$FFFFD900,($FFFFF796).w
 loc_316AF8:
	move.b	layer_plus(a0),d5
	move.w	x_vel(a0),d1
	move.w	y_vel(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
	jsr	CheckLeftWallDist
	tst.w	d1
	bpl.s	loc_316B3C
	sub.w	d1,x_pos(a0)
	move.w	#0,x_vel(a0)
 loc_316B3C:
	jsr	CheckRightWallDist
	tst.w	d1
	bpl.s	loc_316B4E
	add.w	d1,x_pos(a0)
	move.w	#0,x_vel(a0)
 loc_316B4E:
	jsr	Sonic_CheckFloor
	tst.w	d1
	bpl.s	return_316BC0
	move.b	y_vel(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,y_pos(a0)
	move.b	d3,angle(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	y_vel(a0)
	bra.s	loc_316BB2
; ---------------------------------------------------------------------------
 loc_316B90:
	move.w	#0,y_vel(a0)
	move.w	x_vel(a0),inertia(a0)
	rts
; ---------------------------------------------------------------------------
 loc_316B9E:
	move.w	#0,x_vel(a0)
	cmp.w	#$FC0,y_vel(a0)
	ble.s	loc_316BB2
	move.w	#$FC0,y_vel(a0)
 loc_316BB2:
	move.w	y_vel(a0),inertia(a0)
	tst.b	d3
	bpl.s	return_316BC0
	neg.w	inertia(a0)
 return_316BC0:
	rts
; ---------------------------------------------------------------------------
 Knuckles_HitLeftWall: 
	jsr	CheckLeftWallDist
	tst.w	d1
	bpl.s	Knuckles_HitCeiling
	sub.w	d1,x_pos(a0)
	move.w	#0,x_vel(a0)
	move.w	y_vel(a0),inertia(a0)
	rts
; ---------------------------------------------------------------------------
 Knuckles_HitCeiling: 
	jsr	CheckCeilingDist
	tst.w	d1
	bpl.s	Knuckles_HitFloor_0
	sub.w	d1,y_pos(a0)
	tst.w	y_vel(a0)
	bpl.s	return_316BF4
	move.w	#0,y_vel(a0)
 return_316BF4:
	rts
; ---------------------------------------------------------------------------
 Knuckles_HitFloor_0: 
	tst.w	y_vel(a0)
	bmi.s	return_316C1C
	jsr	Sonic_CheckFloor
	tst.w	d1
	bpl.s	return_316C1C
	add.w	d1,y_pos(a0)
	move.b	d3,angle(a0)
	bsr.w	Knuckles_ResetOnFloor
	move.w	#0,y_vel(a0)
	move.w	x_vel(a0),inertia(a0)
 return_316C1C:
	rts
; ---------------------------------------------------------------------------
 Knuckles_HitCeilingAndWalls: 
	jsr	CheckLeftWallDist
	tst.w	d1
	bpl.s	loc_316C30
	sub.w	d1,x_pos(a0)
	move.w	#0,x_vel(a0)
 loc_316C30:
	jsr	CheckRightWallDist
	tst.w	d1
	bpl.s	loc_316C42
	add.w	d1,x_pos(a0)
	move.w	#0,x_vel(a0)
 loc_316C42:
	jsr	CheckCeilingDist
	tst.w	d1
	bpl.s	return_316C78
	sub.w	d1,y_pos(a0)
	move.b	d3,d0
	add.b	#$20,d0
	and.b	#$40,d0
	bne.s	loc_316C62
	move.w	#0,y_vel(a0)
	rts
; ---------------------------------------------------------------------------
 loc_316C62:
	move.b	d3,angle(a0)
	bsr.w	Knuckles_ResetOnFloor
	move.w	y_vel(a0),inertia(a0)
	tst.b	d3
	bpl.s	return_316C78
	neg.w	inertia(a0)
 return_316C78:
	rts
; ---------------------------------------------------------------------------
 Knuckles_HitRightWall:
	jsr	CheckRightWallDist
	tst.w	d1
	bpl.s	Knuckles_HitCeiling2
	add.w	d1,x_pos(a0)
	move.w	#0,x_vel(a0)
	move.w	y_vel(a0),inertia(a0)
	rts
; ---------------------------------------------------------------------------
 Knuckles_HitCeiling2:
	jsr	CheckCeilingDist
	tst.w	d1
	bpl.s	Knuckles_HitFloor2
	sub.w	d1,y_pos(a0)
	tst.w	y_vel(a0)
	bpl.s	return_316CAC
	move.w	#0,y_vel(a0)
 return_316CAC:
	rts
; ---------------------------------------------------------------------------
 Knuckles_HitFloor2:
	tst.w	y_vel(a0)
	bmi.s	return_316CD4
	jsr	Sonic_CheckFloor
	tst.w	d1
	bpl.s	return_316CD4
	add.w	d1,y_pos(a0)
	move.b	d3,angle(a0)
	bsr.w	Knuckles_ResetOnFloor
	move.w	#0,y_vel(a0)
	move.w	x_vel(a0),inertia(a0)
 return_316CD4:
	rts
; End of function Knuckles_DoLevelCollision
  ; =============== S U B	R O U T	I N E =======================================
  Knuckles_ResetOnFloor:
	tst.b	spindash_flag(a0)
	bne.s	Knuckles_ResetOnFloor_Part3
	move.b	#0,anim(a0)
; End of function Knuckles_ResetOnFloor
  ; =============== S U B	R O U T	I N E =======================================
  Knuckles_ResetOnFloor_Part2:
	move.b	y_radius(a0),d0
	move.b	#$13,y_radius(a0)
	move.b	#9,x_radius(a0)
	btst	#2,status(a0)
	beq.s	Knuckles_ResetOnFloor_Part3
	bclr	#2,status(a0)
	move.b	#0,anim(a0)
	sub.b	#$13,d0
	ext.w	d0
	add.w	d0,y_pos(a0)
 Knuckles_ResetOnFloor_Part3:
	bclr	#1,status(a0)
	bclr	#5,status(a0)
	bclr	#4,status(a0)
	move.b	#0,jumping(a0)
	move.w	#0,(Chain_Bonus_counter).w
	move.b	#0,flip_angle(a0)
	move.b	#0,flip_turned(a0)
	move.b	#0,flips_remaining(a0)
	move.w	#0,(Sonic_Look_delay_counter).w
	move.b	#0,$42(a0)
	cmp.b	#$20,anim(a0)
	bcc.s	loc_316D5C
	cmp.b	#$14,anim(a0)
	bne.s	return_316D62
 loc_316D5C:
	move.b	#0,anim(a0)
 return_316D62:
	rts
; End of function Knuckles_ResetOnFloor_Part2
  ; =============== S U B	R O U T	I N E =======================================
  Obj4C_Hurt:
 ; FUNCTION CHUNK AT 00316E14 SIZE 0000001C BYTES
 	tst.w	($FFFFFFDA).w
	beq.s	Obj4C_Hurt_Normal
	btst	#4,($FFFFF605).w
	beq.s	Obj4C_Hurt_Normal
	move.w	#1,($FFFFFE08).w
	clr.b	($FFFFF7CC).w
	rts
; ---------------------------------------------------------------------------
 Obj4C_Hurt_Normal:
	tst.b	routine_secondary(a0)
	bmi.w	Knuckles_HurtInstantRecover
	jsr	(ObjectMove).l
	addi.w	#$30,y_vel(a0)
	btst	#6,status(a0)
	beq.s	+
	subi.w	#$20,y_vel(a0)
+
	cmpi.w	#-$100,(Camera_Min_Y_pos).w
	bne.s	+
	andi.w	#$7FF,y_pos(a0)
+
	bsr.w	Knuckles_HurtStop
	bsr.w	Knuckles_LevelBound
	bsr.w	Knuckles_RecordPos
	bsr.w	Knuckles_Water
	bsr.w	Knuckles_Animate
	bsr.w	LoadKnucklesDynPLC
	jmp	(DisplaySprite).l
; End of function Obj4C_Hurt
  ; =============== S U B	R O U T	I N E =======================================
  Knuckles_HurtStop:
	move.w	($FFFFEECE).w,d0
	add.w	#$E0,d0
	cmp.w	y_pos(a0),d0
	blt.w	JmpTo3_KillCharacter
	bsr.w	Knuckles_DoLevelCollision
	btst	#1,status(a0)
	bne.s	return_316E0C
	moveq	#0,d0
	move.w	d0,y_vel(a0)
	move.w	d0,x_vel(a0)
	move.w	d0,inertia(a0)
	move.b	d0,obj_control(a0)
	move.b	#0,anim(a0)
	subq.b	#2,routine(a0)
	move.b	#$78,invulnerable_time(a0)
	move.b	#0,spindash_flag(a0)
 return_316E0C:
	rts
; ---------------------------------------------------------------------------
 JmpTo3_KillCharacter:
	jmp	(KillCharacter).l
; End of function Knuckles_HurtStop
 ; ---------------------------------------------------------------------------
; START	OF FUNCTION CHUNK FOR Obj4C_Hurt
 Knuckles_HurtInstantRecover:
	subq.b	#2,routine(a0)
	move.b	#0,routine_secondary(a0)
	bsr.w	Knuckles_RecordPos
	bsr.w	Knuckles_Animate
	bsr.w	LoadKnucklesDynPLC
	jmp	DisplaySprite
; END OF FUNCTION CHUNK	FOR Obj4C_Hurt
 ; =============== S U B	R O U T	I N E =======================================
  Obj4C_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	CheckGameOverKnux
	jsr	(ObjectMoveAndFall).l
	bsr.w	Knuckles_RecordPos
	bsr.w	Knuckles_Animate
	bsr.w	LoadKnucklesDynPLC
	jmp	(DisplaySprite).l
; End of function Obj4C_Dead
  ; =============== S U B	R O U T	I N E =======================================
  CheckGameOverKnux:
	move.b	#1,($FFFFEEBE).w
	move.b	#0,spindash_flag(a0)
	move.w	($FFFFEECE).w,d0
	add.w	#$100,d0
	cmp.w	y_pos(a0),d0
	bge.w	return_316F64
	move.b	#8,routine(a0)
	move.b	#$3C,spindash_counter(a0)
	addq.b	#1,($FFFFFE1C).w
	subq.b	#1,($FFFFFE12).w
	bne.s	Obj4C_ResetLevel
	move.b	#0,spindash_counter(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
 Obj4C_Finished:
	clr.b	($FFFFFE1E).w
	clr.b	($FFFFFECA).w
	move.b	#8,routine(a0)
	move.w	#$9B,d0
	jsr	(PlayMusic).l
	moveq	#3,d0
	jmp	LoadPLC
; ---------------------------------------------------------------------------
 Obj4C_ResetLevel: 
	tst.b	(Time_Over_flag).w
	beq.s	Obj4C_ResetLevel_Part2
	move.b	#0,spindash_counter(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	Obj4C_Finished
; ---------------------------------------------------------------------------
 Obj4C_ResetLevel_Part2:
	tst.w	(Two_player_mode).w
	beq.s	return_316F64
	move.b	#0,(Scroll_lock).w
	move.b	#$A,routine(a0)	; => Obj4C_Respawning
	move.w	(Saved_x_pos).w,x_pos(a0)
	move.w	(Saved_y_pos).w,y_pos(a0)
	move.w	(Saved_art_tile).w,art_tile(a0)
	move.w	(Saved_layer).w,layer(a0)
	clr.w	(Ring_count).w
	clr.b	(Extra_life_flags).w
	move.b	#0,obj_control(a0)
	move.b	#5,anim(a0)
	move.w	#0,x_vel(a0)
	move.w	#0,y_vel(a0)
	move.w	#0,inertia(a0)
	move.b	#2,status(a0)
	move.b	#0,move_lock(a0)
	move.b	#0,spindash_counter(a0)
 return_316F64:
	rts
; End of function Obj4C_CheckGameOver
  ; =============== S U B	R O U T	I N E =======================================
  Obj4C_Gone:
	tst.b	spindash_counter(a0)
	beq.s	return_316F78
	subq.b	#1,spindash_counter(a0)
	bne.s	return_316F78
	move.w	#1,($FFFFFE02).w
 return_316F78:
	rts
; End of function Obj4C_Gone
 ; ---------------------------------------------------------------------------
 Obj4C_Respawning: 
	tst.w	($FFFFEEB0).w
	bne.s	loc_316F8C
 	tst.w	($FFFFEEB2).w
	bne.s	loc_316F8C
	move.b	#2,routine(a0)
 loc_316F8C:
	bsr.w	Knuckles_Animate
	bsr.w	LoadKnucklesDynPLC
	jmp	DisplaySprite
 ; ---------------------------------------------------------------------------
; Knuckles when he's drowning
; ---------------------------------------------------------------------------
Obj4C_Drowned:
        jsr     (ObjectMove).l			; Make Knuckles able to move
        addi.w  #$10,y_vel(a0)			; Apply gravity
        bsr.w   Knuckles_RecordPos		; Record position
        bsr.w   Knuckles_Animate		; Animate Knuckles
        bsr.w   LoadKnucklesDynPLC		; Load Knuckles' DPLCs
        jmp     (DisplaySprite).l		; And finally, display Knuckles
; ===========================================================================
 ; ---------------------------------------------------------------------------
; Subroutine to animate Knuckles' sprites
; See also: AnimateSprite
; ---------------------------------------------------------------------------
 ; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 Knuckles_Animate:
	lea	(KnucklesAniData).l,a1
	moveq	#0,d0
	move.b	anim(a0),d0
	cmp.b	next_anim(a0),d0
	beq.s	KAnim_Do
	move.b	d0,next_anim(a0)
	move.b	#0,anim_frame(a0)
	move.b	#0,anim_frame_duration(a0)
	bclr	#5,status(a0)
 KAnim_Do:
	add.w	d0,d0
	add.w	(a1,d0.w),a1
	move.b	(a1),d0
	bmi.s	KAnim_WalkRun
	move.b	status(a0),d1
	and.b	#1,d1
	and.b	#$FC,render_flags(a0)
	or.b	d1,render_flags(a0)
	subq.b	#1,anim_frame_duration(a0)
	bpl.s	KAnim_Delay
	move.b	d0,anim_frame_duration(a0)
 KAnim_Do2:
	moveq	#0,d1
	move.b	anim_frame(a0),d1
	move.b	1(a1,d1.w),d0
	cmp.b	#$FC,d0
	bcc.s	KAnim_End_FF
 KAnim_Next:
	move.b	d0,mapping_frame(a0)
	addq.b	#1,anim_frame(a0)
 KAnim_Delay:
	rts
; ---------------------------------------------------------------------------
 KAnim_End_FF:
	addq.b	#1,d0
	bne.s	KAnim_End_FE
	move.b	#0,anim_frame(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,anim_frame(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),anim(a0)
 KAnim_End:
	rts
; ---------------------------------------------------------------------------
 KAnim_WalkRun:
	addq.b	#1,d0
	bne.w	KAnim_Roll
	moveq	#0,d0
	move.b	flip_angle(a0),d0
	bne.w	KAnim_Tumble
	moveq	#0,d1
	move.b	angle(a0),d0
	bmi.s	loc_31704E
	beq.s	loc_31704E
	subq.b	#1,d0
 loc_31704E:
	move.b	status(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,render_flags(a0)
	eor.b	d1,d2
	or.b	d2,render_flags(a0)
	btst	#5,status(a0)
	bne.w	KAnim_Push
	lsr.b	#4,d0
	and.b	#6,d0
	move.w	inertia(a0),d2
	bpl.s	loc_317086
	neg.w	d2
 loc_317086:
	tst.b	status_secondary(a0)
	bpl.w	loc_317090
	add.w	d2,d2
 loc_317090:
	lea	(KnuxAni_Run).l,a1
	cmp.w	#$600,d2
	bcc.s	loc_3170A4
	lea	(KnuxAni_Walk).l,a1
	add.b	d0,d0
 loc_3170A4:
	add.b	d0,d0
	move.b	d0,d3
	moveq	#0,d1
	move.b	anim_frame(a0),d1
	move.b	1(a1,d1.w),d0
	cmp.b	#$FF,d0
	bne.s	loc_3170C2
	move.b	#0,anim_frame(a0)
	move.b	1(a1),d0
 loc_3170C2:
	move.b	d0,mapping_frame(a0)
	add.b	d3,mapping_frame(a0)
	subq.b	#1,anim_frame_duration(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,anim_frame_duration(a0)
	addq.b	#1,anim_frame(a0)
 return_3170E4:
	rts
; ---------------------------------------------------------------------------
 KAnim_Tumble:
	move.b	flip_angle(a0),d0
	moveq	#0,d1
	move.b	status(a0),d2
	and.b	#1,d2
	bne.s	KAnim_Tumble_Left
	and.b	#$FC,render_flags(a0)
	add.b	#$B,d0
	divu.w	#$16,d0
	add.b	#$31,d0
	move.b	d0,mapping_frame(a0)
	move.b	#0,anim_frame_duration(a0)
	rts
; ---------------------------------------------------------------------------
 KAnim_Tumble_Left: 
	and.b	#$FC,render_flags(a0)
	tst.b	flip_turned(a0)
	beq.s	loc_31712C
	or.b	#1,render_flags(a0)
	add.b	#$B,d0
	bra.s	loc_317138
; ---------------------------------------------------------------------------
 loc_31712C:
	or.b	#3,render_flags(a0)
	neg.b	d0
	add.b	#-$71,d0
 loc_317138:
	divu.w	#$16,d0
	add.b	#$31,d0
	move.b	d0,mapping_frame(a0)
	move.b	#0,anim_frame_duration(a0)
	rts
; ---------------------------------------------------------------------------
 KAnim_Roll:
	subq.b	#1,anim_frame_duration(a0)
	bpl.w	KAnim_Delay
	addq.b	#1,d0
	bne.s	KAnim_Push
	move.w	inertia(a0),d2
	bpl.s	loc_317160
	neg.w	d2
 loc_317160:
	lea	(KnuxAni_Roll2).l,a1
	cmp.w	#$600,d2
	bcc.s	loc_317172
	lea	(KnuxAni_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,anim_frame_duration(a0)
	move.b	status(a0),d1
	and.b	#1,d1
	and.b	#$FC,render_flags(a0)
	or.b	d1,render_flags(a0)
	bra.w	KAnim_Do2
; ---------------------------------------------------------------------------
 KAnim_Push:
	subq.b	#1,anim_frame_duration(a0)
	bpl.w	KAnim_Delay
	move.w	inertia(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,anim_frame_duration(a0)
	lea	(KnuxAni_Push).l,a1
	move.b	status(a0),d1
	and.b	#1,d1
	and.b	#$FC,render_flags(a0)
	or.b	d1,render_flags(a0)
	bra.w	KAnim_Do2
; End of function Knuckles_Animate
 ; ---------------------------------------------------------------------------
KnucklesAniData:		offsetTable
KnuxAni_Walk_ptr:		offsetTableEntry.w KnuxAni_Walk			; 0   ; 0
KnuxAni_Run_ptr:		offsetTableEntry.w KnuxAni_Run			; 1   ; 1
KnuxAni_Roll_ptr:		offsetTableEntry.w KnuxAni_Roll			; 2   ; 2
				offsetTableEntry.w KnuxAni_Roll2		; 3   ; 3
				offsetTableEntry.w KnuxAni_Push			; 4   ; 4
				offsetTableEntry.w KnuxAni_Wait			; 5   ; 5
				offsetTableEntry.w KnuxAni_Balance		; 6   ; 6
				offsetTableEntry.w KnuxAni_LookUp		; 7   ; 7
				offsetTableEntry.w KnuxAni_Duck			; 8   ; 8
				offsetTableEntry.w KnuxAni_Spindash		; 9   ; 9
				offsetTableEntry.w KnuxAni_Unused		; 10  ; $A
				offsetTableEntry.w KnuxAni_Pull			; 11  ; $B
				offsetTableEntry.w KnuxAni_Balance2		; 12  ; $C
				offsetTableEntry.w KnuxAni_Stop			; 13  ; $D
				offsetTableEntry.w KnuxAni_Float		; 14  ; $E
				offsetTableEntry.w KnuxAni_Float2		; 15  ; $F
				offsetTableEntry.w KnuxAni_Spring		; 16  ; $10
				offsetTableEntry.w KnuxAni_Hang			; 17
				offsetTableEntry.w KnuxAni_Unused_0		; 18
				offsetTableEntry.w KnuxAni_S3EndingPose		; 19
				offsetTableEntry.w KnuxAni_WFZHang		; 20
				offsetTableEntry.w KnuxAni_Bubble		; 21
				offsetTableEntry.w KnuxAni_DeathBW		; 22
				offsetTableEntry.w KnuxAni_Drown		; 23
				offsetTableEntry.w KnuxAni_Death		; 24
				offsetTableEntry.w KnuxAni_OilSlide		; 25
				offsetTableEntry.w KnuxAni_Hurt			; 26
				offsetTableEntry.w KnuxAni_OilSlide_0		; 27
				offsetTableEntry.w KnuxAni_Blank		; 28
				offsetTableEntry.w KnuxAni_Unused_1		; 29
				offsetTableEntry.w KnuxAni_Unused_2		; 30
				offsetTableEntry.w KnuxAni_Transform		; 31
				offsetTableEntry.w KnuxAni_Gliding		; 32
				offsetTableEntry.w KnuxAni_FallFromGlide	; 33
				offsetTableEntry.w KnuxAni_GetUp		; 34
				offsetTableEntry.w KnuxAni_HardFall		; 35
				offsetTableEntry.w KnuxAni_Badass		; 36
KnuxAni_Walk:	dc.b $FF,  7,  8,  1,  2,  3,  4,  5,  6,$FF; 0 ; ...
KnuxAni_Run:	dc.b $FF,$21,$22,$23,$24,$FF,$FF,$FF,$FF,$FF; 0	; ...
KnuxAni_Roll:	dc.b $FE,$9A,$96,$9A,$97,$9A,$98,$9A,$99,$FF; 0 ; ...
KnuxAni_Roll2:	dc.b $FE,$9A,$96,$9A,$97,$9A,$98,$9A,$99,$FF; 0 ; ...
KnuxAni_Push:	dc.b $FD,$CE,$CF,$D0,$D1,$FF,$FF,$FF,$FF,$FF; 0 ; ...
KnuxAni_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
KnuxAni_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
KnuxAni_LookUp:	dc.b	  5,$D5,$D6,$FE,  1	     ; 0 ; ...
KnuxAni_Duck:	dc.b	5,$9B,$9C,$FE,	1	   ; 0 ; ...
KnuxAni_Spindash:	dc.b   0,$86,$87,$86,$88,$86,$89,$86,$8A,$86,$8B,$FF; 0 ; ...
KnuxAni_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
KnuxAni_Pull:	dc.b  $F,$8F,$FF	   ; 0 ; ...
KnuxAni_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
KnuxAni_Stop:	dc.b	3,$9D,$9E,$9F,$A0,$FD,	0  ; 0 ; ...
KnuxAni_Float:	dc.b	 7,$C0,$FF	    ; 0	; ...
KnuxAni_Float2:	dc.b	  5,$C0,$C1,$C2,$C3,$C4,$C5,$C6,$C7,$C8,$C9,$FF; 0 ; ...
KnuxAni_Spring:	dc.b	$2F,$8E,$FD,  0	     ; 0 ; ...
KnuxAni_Hang:	dc.b	1,$AE,$AF,$FF	   ; 0 ; ...
KnuxAni_Unused_0:	dc.b  $F,$43,$43,$43,$FE,	1      ; 0 ; ...
KnuxAni_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
KnuxAni_WFZHang:	dc.b $13,$91,$FF	      ;	0 ; ...
KnuxAni_Bubble:	dc.b	 $B,$B0,$B0,  3,  4,$FD,  0  ; 0 ; ...
KnuxAni_DeathBW:	dc.b $20,$AC,$FF	      ;	0 ; ...
KnuxAni_Drown:	dc.b $20,$AD,$FF	    ; 0	; ...
KnuxAni_Death:	dc.b $20,$AB,$FF	    ; 0	; ...
KnuxAni_OilSlide:	dc.b   9,$8C,$FF	       ; 0 ; ...
KnuxAni_Hurt:	dc.b $40,$8D,$FF	   ; 0 ; ...
KnuxAni_OilSlide_0:	dc.b   9,$8C,$FF		 ; 0 ; ...
KnuxAni_Blank:	dc.b $77,  0,$FF	    ; 0	; ...
KnuxAni_Unused_1:	dc.b $13,$D0,$D1,$FF	       ; 0 ; ...
KnuxAni_Unused_2:	dc.b   3,$CF,$C8,$C9,$CA,$CB,$FE  ; 0 ; ...
			dc.b   4
KnuxAni_Gliding:	dc.b $1F,$C0,$FF	      ;	0 ; ...
KnuxAni_FallFromGlide:	dc.b	 7,$CA,$CB,$FE,	 1	    ; 0	; ...
KnuxAni_GetUp:	dc.b	$F,$CD,$FD,  0	    ; 0	; ...
KnuxAni_HardFall:	dc.b  $F,$9C,$FD,	0	       ; 0 ; ...
KnuxAni_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
KnuxAni_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	mapping_frame(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
	move.w	#tiles_to_bytes(ArtTile_ArtUnc_Knuckles),d4
; loc_1B86E:
KPLC_ReadEntry:
	moveq	#0,d1
	move.w	(a2)+,d1
	move.w	d1,d3
	lsr.w	#8,d3
	andi.w	#$F0,d3
	addi.w	#$10,d3
	andi.w	#$FFF,d1
	lsl.l	#5,d1
	addi.l	#SK_ArtUnc_Knux,d1
	move.w	d4,d2
	add.w	d3,d4
	add.w	d3,d4
	jsr	(QueueDMATransfer).l
	dbf	d5,KPLC_ReadEntry	; repeat for number of entries
 return_31753E:
	rts
; END OF FUNCTION CHUNK	FOR sub_333D66
 ; =============== S U B	R O U T	I N E =======================================
 ; Doesn't exist in S2
 sub_3192E6:
	move.b	x_radius(a0),d0
	ext.w	d0
	sub.w	d0,d2
	eor.w	#$F,d2
	lea	($FFFFF768).w,a4
	move.w	#-$10,a3
	move.w	#$800,d6
	jsr	FindFloor
	move.b	#$80,d2
 loc_319306:
	bra.w	loc_318FE8
; End of function sub_3192E6
 ; START	OF FUNCTION CHUNK FOR CheckRightWallDist
 loc_318FE8:
	move.b	($FFFFF768).w,d3
	btst	#0,d3
	beq.s	return_318FF4
	move.b	d2,d3
 return_318FF4:
	rts
; END OF FUNCTION CHUNK	FOR CheckRightWallDist
 ; =============== S U B	R O U T	I N E =======================================
  sub_318FF6:
	move.b	x_radius(a0),d0
	ext.w	d0
	add.w	d0,d2
	lea	($FFFFF768).w,a4
	move.w	#$10,a3
	move.w	#0,d6
	jsr	FindFloor
	move.b	#0,d2
	bra.s	loc_318FE8
; End of function sub_318FF6
 ; ---------------------------------------------------------------------------
; This doesn't exist in S2...
; START	OF FUNCTION CHUNK FOR sub_315C22
 loc_319208:
	move.b	x_radius(a0),d0
	ext.w	d0
	add.w	d0,d3
	lea	($FFFFF768).w,a4
	move.w	#$10,a3
	move.w	#0,d6
	jsr	FindWall
	move.b	#$C0,d2
	bra.w	loc_318FE8
; END OF FUNCTION CHUNK	FOR sub_315C22
 ; ---------------------------------------------------------------------------
; START	OF FUNCTION CHUNK FOR sub_315C22
 loc_3193D2:
	move.b	x_radius(a0),d0
	ext.w	d0
	sub.w	d0,d3
	eor.w	#$F,d3
	lea	($FFFFF768).w,a4
	move.w	#$FFF0,a3
	move.w	#$400,d6
	jsr	FindWall
	move.b	#$40,d2
	bra.w	loc_318FE8
; END OF FUNCTION CHUNK	FOR sub_315C22

Comments