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