; --------------------------------------------------------------------------- ; Level ; ZONE/SPECIAL STAGE LOOP (MLS values $08, $0C, and $10; bit 7 set indicates ; that the load routine is running) ; --------------------------------------------------------------------------- ; loc_3EC4: Level: move.b (Game_Mode).w,(Game_Mode_Copy).w bset #7,(Game_Mode).w ; add $80 to screen mode (for pre level sequence) tst.w (Demo_mode_flag).w bmi.s + move.b #$79+$80,d0 bsr.w PlaySound_Special ; fade out music + bsr.w ClearPLC bsr.w Pal_FadeFrom tst.w (Demo_mode_flag).w bmi.w Level_ClrRam move #$2700,sr bsr.w ClearScreen jsr (LoadTitleCard).l ; load title card patterns move #$2300,sr moveq #0,d0 move.w d0,(Timer_frames).w move.b (Current_Zone).w,d0 cmpi.b #$10,(Game_Mode_Copy).w bne.w + moveq #0,d0 move.b (Current_Special_Stage+1).w,d0 + ; multiply d0 by 12, the size of a level art load block add.w d0,d0 add.w d0,d0 move.w d0,d1 add.w d0,d0 add.w d1,d0 cmpi.b #$10,(Game_Mode_Copy).w ; HOLD UP! Are we in a special stage? bne.w + ; If we are not, branch. Otherwise... lea (SpecialStageArtPointers).l,a2 ; ...load the special stage art pointers to a2 instead. bra.w ++ + lea (LevelArtPointers).l,a2 ; Load the level art pointers to a2. + lea (a2,d0.w),a2 moveq #0,d0 move.b (a2),d0 beq.s + bsr.w LoadPLC + moveq #1,d0 bsr.w LoadPLC bsr.w sub_4450 moveq #6,d0 tst.w (Two_player_mode).w bne.s + cmpi.w #2,(Player_mode).w bne.s Level_ClrRam addq.w #1,d0 + tst.b (Graphics_Flags).w bpl.s + addq.w #2,d0 + bsr.w LoadPLC ; loc_3F48: Level_ClrRam: clr.b (Super_Sonic_flag).w clr.w (Closest_Object_X_Dist).w clr.w (Closest_Object_Y_Dist).w clr.w (Closest_Object_Hypotenuse_Dist).w clr.b (Homing_Attack_Chain_Counter).w clr.b (Next_Flight_Anim).w clr.b (Reverse_Gravity_Flag).w clr.b (Current_Shield).w clearRAM Sprite_Table_Input,$400 clearRAM Object_RAM,$2400 ; clear object RAM clearRAM $FFFFF628,$58 clearRAM Misc_Variables,$100 clearRAM $FFFFFE60,$50 clearRAM $FFFFE700,$100 move.b #0,(Camera_System_Selection).w lea (VDP_control_port).l,a6 move.w #$8B03,(a6) move.w #$8230,(a6) move.w #$8407,(a6) move.w #$857C,(a6) move.w #$9001,(a6) move.w #$8004,(a6) move.w #$8720,(a6) move.w #$8C81,(a6) tst.b (Debug_cheat_flag).w beq.s loc_4012 btst #5,(Ctrl_1_Held).w beq.s + move.w #$8C89,(a6) + btst #6,(Ctrl_1_Held).w beq.s loc_4012 move.b #1,(Debug_mode_flag).w loc_4012: move.w #$8ADF,(Hint_counter_reserve).w ; H-INT every 223rd scanline tst.w (Two_player_mode).w beq.s loc_402C move.w #$8A6B,(Hint_counter_reserve).w ; H-INT every 108th scanline move.w #$8014,(a6) move.w #$8C87,(a6) loc_402C: move.w (Hint_counter_reserve).w,(a6) clr.w (VDP_Command_Buffer).w move.w #VDP_Command_Buffer,(VDP_Command_Buffer_Slot).w jsr CheckLevelForWater ; loc_407C: Level_LoadPal: moveq #3,d0 ; load Sonic's palette index cmpi.w #2,(Player_mode).w ; are you playing as Tails? bne.s + ; if not, branch moveq #$2C,d0 ; load Tails' palette index + cmpi.w #3,(Player_mode).w ; are you playing as Knuckles? bne.s + ; if not, branch moveq #$28,d0 ; load Knuckles' palette index + cmpi.w #9,(Player_mode).w ; are you playing as Derpy? bne.s + ; if not, branch moveq #$33,d0 ; load Derpy's palette index + bsr.w PalLoad2 ; load the palette line tst.b (Last_star_pole_hit).w ; is it the start of the level? beq.s Level_GetBgm ; if yes, branch move.b (Saved_Water_move).w,(Water_move).w ; loc_40AE: Level_GetBgm: tst.w (Demo_mode_flag).w bmi.w loc_4114 moveq #0,d0 move.b (Current_Zone).w,d0 lea MusicList1(pc),a1 cmpi.b #0,(Current_Act).w beq.s Level_BgmChkSS lea MusicList2(pc),a1 cmpi.b #1,(Current_Act).w beq.s Level_BgmChkSS lea MusicList3(pc),a1 cmpi.b #2,(Current_Act).w beq.s Level_BgmChkSS lea MusicList4(pc),a1 Level_BgmChkSS: cmpi.b #$10,(Game_Mode_Copy).w bne.w Level_PlayBgm moveq #0,d0 move.b (Current_Special_Stage+1).w,d0 lea MusicListSS(pc),a1 ; loc_40C8: Level_PlayBgm: move.b (a1,d0.w),d0 ; load from music playlist move.w d0,(Level_Music).w ; store level music bsr.w PlayMusic ; play level music move.b #$34,(Object_RAM+$80).w ; load Obj34 (level title card) at $FFFFB080 ; loc_40DA: Level_TtlCard: move.b #$C,(Delay_Time).w bsr.w DelayProgram jsr (RunObjects).l jsr (BuildSprites).l bsr.w RunPLC_RAM move.w (Object_RAM+$80+x_pos).w,d0 cmp.w (Object_RAM+$80+$30).w,d0 ; has title card sequence finished? bne.s Level_TtlCard ; if not, branch tst.l (Plc_Buffer).w ; are there any items in the pattern load cue? bne.s Level_TtlCard ; if yes, branch move.b #$C,(Delay_Time).w bsr.w DelayProgram jsr (Hud_Base).l loc_4114: moveq #3,d0 bsr.w PalLoad1 ; load Sonic's palette line bsr.w LevelSizeLoad bsr.w JmpTo_DeformBgLayer clr.w (Vscroll_Factor).w move.w #-$E0,($FFFFF61E).w clearRAM Horiz_Scroll_Buf,$400 bsr.w sub_4E98 bsr.w JmpTo_loadZoneBlockMaps jsr (loc_402D4).l bsr.w JmpTo_loc_E300 jsr (FloorLog_Unk).l bsr.w LoadCollisionIndexes bsr.w WaterEffects bsr.w InitPlayers move.w #0,(Ctrl_1_Logical).w move.w #0,(Ctrl_2_Logical).w move.w #0,(Ctrl_1).w move.w #0,(Ctrl_2).w move.b #1,(Control_Locked).w move.b #1,($FFFFF7CF).w move.b #0,(Level_started_flag).w ; Level_ChkWater: tst.b (Water_flag).w ; does level have water? beq.s Level_ClrHUD ; if not, branch move.b #4,(Object_RAM+$380).w ; load Obj04 (water surface) at $FFFFB380 move.w #$60,(Object_RAM+$380+x_pos).w ; set horizontal offset move.b #4,(Object_RAM+$3C0).w ; load Obj04 (water surface) at $FFFFB3C0 move.w #$120,(Object_RAM+$3C0+x_pos).w ; set different horizontal offset ; Level_LoadObj: misnomer now Level_ClrHUD: moveq #0,d0 tst.b (Last_star_pole_hit).w ; are you starting from a lamppost? bne.s Level_FromCheckpoint ; if yes, branch move.w d0,(Ring_count).w ; clear rings move.l d0,(Timer).w ; clear time move.b d0,(Extra_life_flags).w ; clear extra lives counter move.w d0,(Ring_count_2P).w ; ditto for player 2 move.l d0,(Timer_2P).w move.b d0,(Extra_life_flags_2P).w ; loc_41E4: Level_FromCheckpoint: move.b d0,(Time_Over_flag).w move.b d0,(Time_Over_flag_2P).w move.b d0,($FFFFFF4E).w move.w d0,($FFFFFF4C).w move.w d0,(Debug_placement_mode).w move.w d0,(Level_Inactive_flag).w move.b d0,($FFFFF622).w move.b d0,($FFFFF623).w move.w d0,($FFFFFEF0).w move.w d0,($FFFFFEF2).w move.w d0,($FFFFFEF4).w move.w d0,($FFFFFEF6).w move.w d0,(Loser_Time_Left).w bsr.w OscillateNumInit move.b #1,(Update_HUD_score).w move.b #1,(Update_HUD_rings).w move.b #1,(Update_HUD_timer).w move.b #1,(Update_HUD_timer_2P).w jsr (ObjectsManager).l jsr (RingsManager).l jsr (SpecialCNZBumpers).l jsr (RunObjects).l jsr (BuildSprites).l bsr.w JmpTo_loc_3FCC4 bsr.w SetLevelEndType move.w #0,(Demo_button_index).w move.w #0,(Demo_button_index_2P).w lea (DemoScriptPointers).l,a1 moveq #0,d0 move.b (Current_Zone).w,d0 ; load zone value lsl.w #2,d0 movea.l (a1,d0.w),a1 tst.w (Demo_mode_flag).w bpl.s loc_4290 lea (dword_498C).l,a1 move.w ($FFFFFFF4).w,d0 subq.w #1,d0 lsl.w #2,d0 movea.l (a1,d0.w),a1 loc_4290: move.b 1(a1),(Demo_press_counter).w tst.b (Current_Zone).w bne.s loc_42A8 lea (Demo_EHZ_Tails).l,a1 move.b 1(a1),(Demo_press_counter_2P).w loc_42A8: move.w #$668,(Demo_Time_left).w tst.w (Demo_mode_flag).w bpl.s loc_42C8 move.w #$21C,(Demo_Time_left).w cmpi.w #4,($FFFFFFF4).w bne.s loc_42C8 move.w #$1FE,(Demo_Time_left).w loc_42C8: tst.b (Water_flag).w beq.s loc_42E8 moveq #$15,d0 cmpi.b #8,(Current_Zone).w beq.s loc_42E4 moveq #$16,d0 cmpi.b #$D,(Current_Zone).w beq.s loc_42E4 moveq #$17,d0 cmpi.b #$F,(Current_Zone).w beq.s loc_42E4 moveq #$30,d0 loc_42E4: bsr.w PalLoad4_Water loc_42E8: move.w #-1,(Object_RAM+$80+$3E).w move.b #$E,(Object_RAM+$1C0+routine).w move.w #$A,(Object_RAM+$1C0+$34).w loc_42EA: move.b #$C,(Delay_Time).w bsr.w DelayProgram jsr (RunObjects).l jsr (BuildSprites).l bsr.w RunPLC_RAM tst.b (Object_RAM+$140).w bne.s loc_42EA ; loop while the object at $FFFFB140 is still loaded lea (Object_RAM+$80).w,a1 move.b #$16,routine(a1) move.w #$2D,anim_frame_duration(a1) move.b #$16,next_object+routine(a1) move.w #$2D,next_object+anim_frame_duration(a1) tst.b $80(a1) beq.s + ; branch if an object has not been loaded at $FFFFB100 move.b #$16,$80+routine(a1) move.w #$2D,$80+anim_frame_duration(a1) + move.b #0,(Control_Locked).w move.b #0,($FFFFF7CF).w move.b #1,(Level_started_flag).w ; Level_StartGame: loc_435A: bclr #7,(Game_Mode).w ; clear $80 from the game mode ; --------------------------------------------------------------------------- ; Main level loop (when all title card and loading sequences are finished) ; --------------------------------------------------------------------------- ; loc_4360: Level_MainLoop: bsr.w PauseGame move.b #8,(Delay_Time).w bsr.w DelayProgram addq.w #1,(Timer_frames).w ; add 1 to level timer bsr.w MoveSonicInDemo bsr.w WaterEffects jsr (RunObjects).l tst.w (Level_Inactive_flag).w bne.w Level bsr.w JmpTo_DeformBgLayer bsr.w UpdateWaterSurface jsr (RingsManager).l cmpi.b #$C,(Current_Zone).w ; is it CNZ? bne.s + ; if not, branch past jsr jsr (SpecialCNZBumpers).l + bsr.w JmpTo_loc_3FCC4 bsr.w PalCycle_Load bsr.w RunPLC_RAM bsr.w OscillateNumDo bsr.w ChangeRingFrame bsr.w CheckLoadSignpostArt jsr (BuildSprites).l jsr (ObjectsManager).l cmpi.b #8,(Game_Mode).w ; check if in demo mode beq.s loc_43DC cmpi.b #$C,(Game_Mode).w ; check if in normal play mode beq.w Level_MainLoop cmpi.b #$10,(Game_Mode).w ; check if in special stage play mode beq.w Level_MainLoop rts ; Return to whatever code was running before this routine was run. ; --------------------------------------------------------------------------- loc_43DC: tst.w (Level_Inactive_flag).w bne.w loc_43FA tst.w (Demo_Time_left).w beq.w loc_43FA cmpi.b #8,(Game_Mode).w beq.w Level_MainLoop move.b #0,(Game_Mode).w ; => SegaScreen rts ; Return to whatever code was running before this routine was run. ; --------------------------------------------------------------------------- CheckLevelForWater: cmpi.b #$0F,(Current_Zone).w ; Are we in Ancient Lake Zone? beq.w Level_InitWater ; If so, branch. cmpi.w #$0002,(Current_ZoneAndAct).w ; Are we in Frosty Dusk Zone Act 3? beq.w Level_InitWater ; If so, branch. cmpi.w #$0004,(Current_Special_Stage).w ; Are we in the 5th special stage? beq.w Level_InitWater ; If so, branch. Level_NoWater: move.w #$1000,d0 move.w d0,(Water_Level_1).w ; set water heights move.w d0,(Water_Level_2).w move.w d0,(Water_Level_3).w move.b #0,(Water_flag).w rts Level_InitWater: move.b #1,(Water_flag).w move.w #0,(Two_player_mode).w tst.b (Water_flag).w ; does level have water? beq.w Level_LoadPal ; if not, branch move.w #$8014,(a6) moveq #0,d0 move.w (Current_ZoneAndAct).w,d0 lsl.b #6,d0 lsr.w #5,d0 andi.w #$FFFE,d0 lea (WaterHeight).l,a1 ; load water height array move.w (a1,d0.w),d0 move.w d0,(Water_Level_1).w ; set water heights move.w d0,(Water_Level_2).w move.w d0,(Water_Level_3).w clr.b (Water_routine).w ; clear water routine counter clr.b (Water_move).w ; clear water movement move.b #1,(Water_on).w ; enable water Level_LoadWaterPal: tst.b (Water_flag).w ; does level have water? beq.w Level_NoWater ; if not, branch moveq #$15,d0 ; palette number $15 cmpi.b #8,(Current_Zone).w bne.s Level_PalNotHPZ ; branch if level is not HPZ cmpi.w #2,(Player_mode).w ; are you playing as Tails? bne.s + ; if not, branch moveq #$2F,d0 ; load Tails' palette index + cmpi.w #3,(Player_mode).w ; are you playing as Knuckles? bne.s Level_WaterPal ; if not, branch moveq #$2B,d0 bra.s Level_WaterPal ; branch Level_PalNotHPZ: moveq #$16,d0 ; palette number $16 cmpi.b #$D,(Current_Zone).w bne.s Level_PalNotCFZ ; branch if level is not CFZ cmpi.w #2,(Player_mode).w ; are you playing as Tails? bne.s + ; if not, branch moveq #$2D,d0 ; load Tails' palette index + cmpi.w #3,(Player_mode).w ; are you playing as Knuckles? bne.s Level_WaterPal ; if not, branch moveq #$29,d0 bra.s Level_WaterPal ; branch Level_PalNotCFZ: moveq #$17,d0 ; palette number $17 cmpi.b #$F,(Current_Zone).w bne.s Level_PalNotALZ ; branch if level is not ALZ cmpi.w #2,(Player_mode).w ; are you playing as Tails? bne.s + ; if not, branch moveq #$2E,d0 ; load Tails' palette index + cmpi.w #3,(Player_mode).w ; are you playing as Knuckles? bne.s Level_WaterPal ; if not, branch moveq #$2A,d0 Level_PalNotALZ: moveq #$30,d0 ; palette number $30 cmpi.w #2,(Player_mode).w ; are you playing as Tails? bne.s + ; if not, branch moveq #$31,d0 ; load Tails' palette index + cmpi.w #3,(Player_mode).w ; are you playing as Knuckles? bne.s Level_WaterPal ; if not, branch moveq #$32,d0 ; loc_409E: Level_WaterPal: bra.w PalLoad3_Water ; load underwater palette (with d0) ; ---------------------------------------------------------------------------