Prev: C950 Up: Map Next: CC81
CB4F: Main Game Loop
Used by the routine at Stage_Next_Wave.
Wave-active game loop entry, called from Stage_Next_Wave once the entity list and playfield are ready. Initialises the player's starting screen position and frame counters, copies the sprite template via Initialise_Wave_Start_Sprites, then falls into the per-frame control poll at Main_Loop_Poll. Each frame: reads the controller via Read_Control_Input, moves and redraws the player sprite, spawns one new entity every three frames adjacent to the player, dispatches all active entity handlers via DispatchWordFromHL, updates the colour bar and protection checks, then loops back to Main_Loop_Poll.
Initialise the player's screen position and frame counters for the start of the wave.
Main_Game_Loop CB4F LD HL,$C4D4 Point HL at Player_Y_Position and set the starting screen row to 5C.
CB52 LD (HL),$5C
CB54 INC HL
CB55 LD (HL),$7D Set the starting screen column to 7D and reset the wave-start delay counter at Wave_Start_Delay to 1A.
CB57 LD A,$1A
CB59 LD ($C533),A
CB5C LD A,$0F Set the animation frame counters at Animation_Frame_Counter_One and Animation_Frame_Counter_Two to 0F and copy the sprite template via Initialise_Wave_Start_Sprites.
CB5E LD ($C534),A
CB61 LD ($C536),A
CB64 CALL Initialise_Wave_Start_Sprites
This entry point is used by the routine at Dispatch_Narrow_Entity_Approach.
Per-frame start: check whether the wave is still active before processing input.
Main_Loop_Poll CB67 LD A,($C533) If the wave-start delay counter at Wave_Start_Delay is non-zero, jump to Dispatch_Narrow_Entity_Approach (wave-end / game-over handling).
CB6A AND A
CB6B JP NZ,Dispatch_Narrow_Entity_Approach
This entry point is used by the routine at Animate_Wave_Start_Sequence.
Read the controller and map the input to player movement directions.
Main_Loop_Frame CB6E CALL Read_Control_Input Read the controller state via Read_Control_Input.
CB71 LD A,C Apply vertical input processing via Compute_Entity_Approach_Position_Short and store the result in C.
CB72 CALL Compute_Entity_Approach_Position_Short
CB75 LD C,A
CB76 LD A,B Apply horizontal input processing via Compute_Entity_Approach_Position and store the result in B.
CB77 CALL Compute_Entity_Approach_Position
CB7A LD B,A
CB7B CP $0F If the direction is neutral (0F), skip to Main_Loop_Update_Y.
CB7D JR Z,Main_Loop_Update_Y
CB7F LD ($C518),A Store the updated X direction at Player_X_Direction.
Main_Loop_Update_Y CB82 LD A,C If the vertical direction changed, store it at Player_Y_Direction.
CB83 CP $0F
CB85 JR Z,Main_Loop_Move_Player
CB87 LD ($C517),A
Move the player sprite if a direction was input. Neutral direction (0F) means no movement — skip directly to entity spawning.
Main_Loop_Move_Player CB8A LD A,B If no horizontal direction, skip to Main_Loop_Entity_Spawn.
CB8B CP $0F
CB8D JR Z,Main_Loop_Entity_Spawn
CB8F LD E,A Build the sprite frame word offset from the X direction and stash it; point HL at Intro_Closing_Sprite and erase the current player sprite via Erase_Entity_Sprite.
CB90 SLA E
CB92 LD D,$00
CB94 PUSH DE
CB95 LD HL,$C4D3
CB98 CALL Erase_Entity_Sprite Erase the current player sprite via Erase_Entity_Sprite.
CB9B POP DE Look up the movement delta for the current direction in the table at Movement_Delta_Table; add the Y delta to Player_Y_Position.
CB9C LD HL,$C6AE
CB9F ADD HL,DE
CBA0 EX DE,HL
CBA1 LD HL,$C4D4
CBA4 LD A,(DE)
CBA5 ADD A,(HL)
CBA6 CP $10
CBA8 JR C,Main_Loop_Clamp_X
CBAA CP $AD Reject the Y move if the new position is above the playfield top or below the bottom edge.
CBAC JR NC,Main_Loop_Clamp_X
CBAE LD (HL),A Write the updated Y position.
Main_Loop_Clamp_X CBAF INC HL Add the X delta to Player_X_Position.
CBB0 INC DE
CBB1 LD A,(DE)
CBB2 ADD A,(HL)
CBB3 CP $08
CBB5 JR C,Main_Loop_Update_Sprite Reject the X move if the new position is past the left edge.
CBB7 CP $F2
CBB9 JR NC,Main_Loop_Update_Sprite Reject the X move if past the right edge.
CBBB LD (HL),A Write the updated X position.
Select the sprite frame for the new direction and redraw the player.
Main_Loop_Update_Sprite CBBC LD A,($C518) Look up the sprite frame index for the current X direction in Sprite_Frame_Table; write it to Intro_Closing_Sprite.
CBBF LD E,A
CBC0 LD D,$00
CBC2 LD HL,$D620
CBC5 ADD HL,DE
CBC6 EX DE,HL
CBC7 LD A,(DE)
CBC8 LD HL,$C4D3
CBCB LD (HL),A
CBCC EXX Set the player colour to INK: WHITE, PAPER: BLACK (BRIGHT) in B' and redraw the player sprite via Draw_Entity_Sprite.
CBCD LD B,$47
CBCF EXX
CBD0 CALL Draw_Entity_Sprite
Every three frames spawn one new entity adjacent to the player.
Main_Loop_Entity_Spawn CBD3 LD HL,$C4CF Decrement the entity spawn timer at Entity_Spawn_Timer.
CBD6 DEC (HL)
CBD7 JP NZ,Main_Loop_Entity_Update If the timer has not reached zero, skip to Main_Loop_Entity_Update.
CBDA LD (HL),$03 Reset the spawn timer to 03.
CBDC LD HL,($C4D1) Load the entity list end pointer from Playfield_Entity_List_Pointer and write the movement handler address Move_And_Redraw_Entity to the entity list.
CBDF LD DE,$D5DD
CBE2 LD (HL),E Advance past the handler address word in the entity list.
CBE3 INC HL
CBE4 LD (HL),D
CBE5 INC HL
CBE6 LD ($C4DA),HL Save the entity record write pointer to Entity_Record_Pointer.
CBE9 LD A,($C517) Load the Y direction index from Player_Y_Direction.
CBEC EX DE,HL Index the entity type table at Entity_Type_By_Direction_Table by Y direction and write the entity type to the entity record.
CBED LD C,A
CBEE LD B,$00
CBF0 LD HL,$D4F1
CBF3 ADD HL,BC
CBF4 EX DE,HL
CBF5 LD A,(DE)
CBF6 LD (HL),A
CBF7 INC HL Advance to the next entity record field.
CBF8 LD A,($C517) Load the Y direction again, scale it to a byte offset (×8), and look up the sprite pixel offsets in Narrow_Entity_Sprite_Data.
CBFB LD C,A
CBFC SLA C
CBFE SLA C
CC00 SLA C
CC02 LD B,$00 Clear the high byte of the offset and index into Narrow_Entity_Sprite_Data.
CC04 EX DE,HL
CC05 LD HL,$C7CF
CC08 ADD HL,BC Add the direction offset to the sprite data base address.
CC09 LD A,($C4D4) Compute the entity's initial Y position from Player_Y_Position plus the sprite Y offset; write both bytes to the entity record.
CC0C ADD A,(HL)
CC0D LD (DE),A
CC0E INC HL
CC0F INC DE
CC10 LD A,($C4D5)
CC13 ADD A,(HL) Write the X position bytes derived from Player_X_Position.
CC14 LD (DE),A
CC15 INC HL
CC16 INC DE
CC17 LD A,($C4D4) Add the sprite Y check offset to the player Y position and reject the spawn if the result is above the playfield top edge.
CC1A ADD A,(HL)
CC1B CP $10
CC1D JR C,Main_Loop_Abort_Spawn Reject the spawn if the Y position is below the playfield bottom edge (B8).
CC1F CP $B8
CC21 JR NC,Main_Loop_Abort_Spawn Reject if below the bottom edge.
CC23 LD (DE),A Write the validated Y position field to the entity record.
CC24 INC HL
CC25 INC DE
CC26 LD A,($C4D5) Check the X position is within the playfield horizontal bounds (08–F7).
CC29 ADD A,(HL)
CC2A CP $08
CC2C JR C,Main_Loop_Abort_Spawn Reject the spawn if the X position is past the left edge.
CC2E CP $F8
CC30 JR NC,Main_Loop_Abort_Spawn Reject if past the right edge.
CC32 LD (DE),A Write the validated X position field to the entity record.
CC33 INC HL
CC34 INC DE
CC35 LD BC,$0004 Copy the remaining four entity record bytes via LDIR.
CC38 LDIR
CC3A EX DE,HL Mark the end of the entity record and update the entity list end pointer at Playfield_Entity_List_Pointer.
CC3B LD (HL),$FF
CC3D INC HL
CC3E LD ($C4D1),HL
CC41 LD E,$01 Initialise the entity via Initialise_Entity_State.
CC43 CALL Initialise_Entity_State
CC46 LD HL,($C4DA) Reload the entity record pointer from Entity_Record_Pointer and set the entity colour to INK: WHITE, PAPER: BLACK (BRIGHT) in B'.
CC49 EXX
CC4A LD B,$47
CC4C EXX
CC4D CALL Draw_Narrow_Entity_Sprite Draw the spawned entity sprite via Draw_Narrow_Entity_Sprite.
CC50 LD HL,($C4D1) Reload the entity list end pointer from Playfield_Entity_List_Pointer.
Main_Loop_Write_Terminator CC53 LD DE,$CE62 Write the playfield entity handler CE62 and the FF sentinel as the entity list terminator.
CC56 LD (HL),E
CC57 INC HL
CC58 LD (HL),D
CC59 INC HL
CC5A LD (HL),$FF
Dispatch all active entity handlers, update animation and colour bar.
Main_Loop_Entity_Update CC5C LD HL,$6100 Set HL to the start of the entity list at Entity_List_Base.
CC5F CALL DispatchWordFromHL Dispatch all entity handlers in the list via DispatchWordFromHL.
CC62 LD HL,($C51B) Decrement the animation counter at Animation_Frame_Pair if it is non-zero.
CC65 LD A,H
CC66 OR L
CC67 JR Z,Main_Loop_Colour_Bar_Update
CC69 DEC HL
CC6A LD ($C51B),HL
Main_Loop_Colour_Bar_Update CC6D CALL UpdateAttributeBar Update the colour bar via UpdateAttributeBar, run the protection check via CheckScoreAwardLife, and call the game state update via Dispatch_Entity_State_Handler.
CC70 CALL CheckScoreAwardLife
CC73 CALL Dispatch_Entity_State_Handler
CC76 CALL CheckScoreAwardLife_SessionGate Run the copy protection gate via CheckScoreAwardLife_SessionGate and loop back to Main_Loop_Poll.
CC79 JP Main_Loop_Poll
Out-of-bounds abort: the new entity would fall outside the playfield. Skip the spawn but still write the entity list terminator.
Main_Loop_Abort_Spawn CC7C LD HL,($C4D1) Reload the entity list end pointer from Playfield_Entity_List_Pointer and jump to Main_Loop_Write_Terminator.
CC7F JR Main_Loop_Write_Terminator
Prev: C950 Up: Map Next: CC81