.ORIG x3000 JUMP MAIN CHECK_POINT_TR STR R7, R6, #0 INC R6, #-1 TRAP x43 INC R6, #1 LDR R7, R6, #0 JUMPR R7 ; ------------------------------------------------------ ; Main Function ; Register Assignments: ; R5 - Return Value ; R6 - Stack Pointer ; R7 - Return Address MAIN ; Initialize stack LD R6, TOS ; Initialize Timer Interval ; LD R0, INIT_TIMER_INTERVAL ; STI R0, TIMER_INTERVAL ; Initialize globals LD R0, BALL_START_ROW ST R0, BALL_ROW_POS LD R0, BALL_START_COL ST R0, BALL_COL_POS LD R0, BALL_START_VEL_ROW ST R0, BALL_ROW_VEL LD R0, BALL_START_VEL_COL ST R0, BALL_COL_VEL LD R0, PADDLE_START_COL ST R0, PADDLE_COL_POS ; Initialize video memory JSR INIT_VIDEO_MEMORY MAINLOOP TRAP x44 ; GET_EVENT BRn R5, GAME_OVER BRp R5, EVENT_MOVE ; Timer Event JSR MOVE_BALL BRn R5, GAME_OVER JUMP MAINLOOP EVENT_MOVE CONST R0, #-1 ADD R0, R0, R5 JSR MOVE_PADDLE JUMP MAINLOOP GAME_OVER HALT ; ------------------------------------------------------ ; Data Section for Top Level ; Top of Stack TOS .FILL xBFFF ; Timer Interval TIMER_INTERVAL .FILL xFE0A INIT_TIMER_INTERVAL .FILL x0040 ; Paddle Stats PADDLE_ROW_POS .FILL #116 PADDLE_START_COL .FILL #58 PADDLE_HEIGHT .FILL #2 PADDLE_WIDTH .FILL #12 PADDLE_VEL .FILL #2 ; Ball Stats BALL_START_ROW .FILL #114 BALL_START_COL .FILL #63 BALL_SIZE .FILL #2 BALL_START_VEL_ROW .FILL #-1 BALL_START_VEL_COL .FILL #1 ; Field Stats FIELD_ROW .FILL #3 FIELD_COL .FILL #8 FIELD_HEIGHT .FILL #116 FIELD_WIDTH .FILL #112 ; ------------------------------------------------------ ; Init Video Memory Subroutine - initializes video memory INIT_VIDEO_MEMORY ; Arguments: None ; Return: void ; Register Saving STR R0, R6, #0 STR R1, R6, #-1 STR R2, R6, #-2 STR R3, R6, #-3 STR R4, R6, #-4 STR R5, R6, #-5 STR R7, R6, #-6 INC R6, #-7 ; Clear previous dead paddles LD R0, PADDLE_ROW_POS LD R1, FIELD_COL CONST R2, #4 ; height = 4 (two for paddle, two for ball) LD R3, FIELD_WIDTH CONST R4, #0 ; color = black TRAP x42 ; DRAW_RECTANGLE ; Draw walls LD R4, COLOR_WALL ; Left wall LD R0, FIELD_ROW LD R1, FIELD_COL LD R2, FIELD_HEIGHT CONST R3, #1 ; width = 1 TRAP x42 ; DRAW_RECTANGLE ; Right wall LD R5, FIELD_WIDTH ADD R1, R1, R5 ; col = field_col + field_width TRAP x42 ; DRAW_RECTANGLE ; Top wall LD R1, FIELD_COL AND R2, R3, R3 ; height = 1 LD R3, FIELD_WIDTH TRAP x42 ; DRAW_RECTANGLE ; Floor LD R4, COLOR_FLOOR LD R5, FIELD_HEIGHT ADD R0, R0, R5 ; row = field_row + field_height TRAP x42 ; DRAW_RECTANGLE ; Draw paddle LD R4, COLOR_PADDLE LD R0, PADDLE_ROW_POS LD R1, PADDLE_START_COL LD R2, PADDLE_HEIGHT LD R3, PADDLE_WIDTH TRAP x42 ; DRAW_RECTANGLE ; Draw Ball LD R0, BALL_START_ROW LD R1, BALL_START_COL LD R2, COLOR_BALL TRAP x41 ; DRAW_BALL ; Register Restoring INC R6, #7 LDR R0, R6, #0 LDR R1, R6, #-1 LDR R2, R6, #-2 LDR R3, R6, #-3 LDR R4, R6, #-4 LDR R5, R6, #-5 LDR R7, R6, #-6 JUMPR R7 ; ------------------------------------------------------ ; Move Paddle subroutine - moves the paddle one frame ; local variables MP_POS_DELTA .FILL x0000 ; Subroutine MOVE_PADDLE ; Arguments: R0 - left (0), right (1) ; Return: void ; Register Saving STR R0, R6, #0 STR R1, R6, #-1 STR R2, R6, #-2 STR R3, R6, #-3 STR R4, R6, #-4 STR R5, R6, #-5 STR R7, R6, #-6 INC R6, #-7 CONST R1, #0 ; col checkpoint = 0 CONST R3, #2 MUL R0, R0, R3 INC R0, #-1 ; sets R0 to -1 for left, 1 for right BRn R0, MP_SKIP_ADD LD R1, PADDLE_WIDTH ; col checkpoint = paddle width - 1 INC R1, #-1 MP_SKIP_ADD LD R2, PADDLE_COL_POS ADD R1, R1, R2 ; col checkpoint += paddle col pos LD R4, PADDLE_VEL BRp R0, MP_SKIP_MUL MUL R0, R0, R4 ADD R1, R1, R0 ; col checkpoint += direction * paddle vel JUMP MP_END_SKIP_MUL MP_SKIP_MUL ADD R1, R1, R0 ; col checkpoint += direction * paddle vel MUL R0, R0, R4 MP_END_SKIP_MUL ST R0, MP_POS_DELTA LD R0, PADDLE_ROW_POS TRAP x43 ; CHECK_POINT BRnp R5, MP_END INC R1, #1 TRAP x43 ; CHECK_POINT BRnp R5, MP_END ; clear for movement, first erase the paddle LD R0, PADDLE_ROW_POS LD R1, PADDLE_COL_POS LD R2, PADDLE_HEIGHT LD R3, PADDLE_WIDTH CONST R4, #0 TRAP x42 ; DRAW_RECTANGLE ; now move it and redraw it LD R4, MP_POS_DELTA ADD R1, R1, R4 ST R1, PADDLE_COL_POS LD R4, COLOR_PADDLE TRAP x42 ; DRAW_RECTANGLE MP_END ; Register Restoring INC R6, #7 LDR R0, R6, #0 LDR R1, R6, #-1 LDR R2, R6, #-2 LDR R3, R6, #-3 LDR R4, R6, #-4 LDR R5, R6, #-5 LDR R7, R6, #-6 JUMPR R7 ; ------------------------------------------------------ ; Move Ball subroutine - moves the ball one frame based on velocity MOVE_BALL ; Arguments: None ; Return: R5 - game over (-1), no game over (0) ; Register Saving STR R0, R6, #0 STR R1, R6, #-1 STR R2, R6, #-2 STR R3, R6, #-3 STR R4, R6, #-4 STR R7, R6, #-5 INC R6, #-6 ; check for and handle collision JSR HANDLE_COLLISION BRn R5, MB_END ; move ball ; erase old ball LD R0, BALL_ROW_POS LD R1, BALL_COL_POS CONST R2, #0 ; color = black TRAP x41 ; DRAW_BALL ; update row position LD R4, BALL_ROW_VEL ADD R0, R0, R4 ST R0, BALL_ROW_POS ; update col position LD R4, BALL_COL_VEL ADD R1, R1, R4 ST R1, BALL_COL_POS ; draw new ball LD R2, COLOR_BALL TRAP x41 ; DRAW_BALL MB_END ; Register Restoring INC R6, #6 LDR R0, R6, #0 LDR R1, R6, #-1 LDR R2, R6, #-2 LDR R3, R6, #-3 LDR R4, R6, #-4 LDR R7, R6, #-5 JUMPR R7 ; ------------------------------------------------------ ; global variables BALL_ROW_POS .FILL x0000 BALL_COL_POS .FILL x0000 BALL_ROW_VEL .FILL x0000 BALL_COL_VEL .FILL x0000 PADDLE_COL_POS .FILL x0000 ; Colors COLOR_BALL .FILL xFFFF ; White COLOR_BRICK .FILL x43FF ; Light Cyan COLOR_PADDLE .FILL xFFFE ; Almost White COLOR_WALL .FILL x4210 ; Gray COLOR_FLOOR .FILL x0001 ; Almost Black ; ------------------------------------------------------ ; Handle Collision subroutine - checks for and handles a ball collision ; local variables HC_CACHE_ROW .FILL x0000 HC_CACHE_COL .FILL x0000 ; Subroutine HANDLE_COLLISION ; Arguments: None ; Return: R5 - game over (-1), no game over (0) ; Register Saving STR R0, R6, #0 STR R1, R6, #-1 STR R2, R6, #-2 STR R3, R6, #-3 STR R4, R6, #-4 STR R7, R6, #-5 INC R6, #-6 CONST R3, #0 ; row checkpoint = 0 LD R5, BALL_ROW_VEL BRnz R5, HC_SKIP_ADD_ROW LD R3, BALL_SIZE ; if (ball_row_vel > 0) row checkpoint = ball_size - 1 INC R3, #-1 HC_SKIP_ADD_ROW LD R0, BALL_ROW_POS ADD R3, R3, R0 ; row checkpoint += ball_row_pos ST R3, HC_CACHE_ROW ; cache the checkpoint before it's changed by velocity ADD R3, R3, R5 ; row checkpoint += ball_row_vel CONST R4, #0 ; col checkpoint = 0 LD R5, BALL_COL_VEL BRnz R5, HC_SKIP_ADD_COL LD R4, BALL_SIZE ; if (ball_col_vel > 0) col checkpoint = ball_size - 1 INC R4, #-1 HC_SKIP_ADD_COL LD R1, BALL_COL_POS ADD R4, R4, R1 ; col checkpoint += ball_col_pos ST R4, HC_CACHE_COL ; cache the checkpoint before it's changed by velocity ADD R4, R4, R5 ; col checkpoint += ball_col_vel CONST R2, #0 ; flag = 0 ; first approximation: check the x and y movements independently AND R0, R3, R3 LD R1, HC_CACHE_COL JSR GET_PIXEL_TYPE ; Check_Collision(row_checkpoint, col) ; check for game over BRzp R5, HC_END_TRAMPOLINE1 JUMP HC_END HC_END_TRAMPOLINE1 BRz R5, HC_SKIP_REV_ROW ; check for brick clearing CONST R0, #-3 ADD R0, R5, R0 BRnp R0, HC_SKIP_CLEAR_ROW AND R0, R3, R3 JSR CLEAR_BRICK HC_SKIP_CLEAR_ROW ; row collision detected, reverse row velocity LD R0, BALL_ROW_VEL NOT R0, R0 INC R0, #1 ST R0, BALL_ROW_VEL INC R5, #-2 BRnp R5, HC_SKIP_REV_PADDLE LD R0, HC_CACHE_COL JSR HANDLE_PADDLE_COLL HC_SKIP_REV_PADDLE INC R2, #1 ; flag = positive (collision detected) HC_SKIP_REV_ROW LD R0, HC_CACHE_ROW AND R1, R4, R4 JSR GET_PIXEL_TYPE ; Check_Collision(row, col_checkpoint) ; check for game over BRn R5, HC_END BRz R5, HC_SKIP_REV_COL ; check for brick clearing CONST R0, #-3 ADD R0, R5, R0 BRnp R0, HC_SKIP_CLEAR_COL LD R0, HC_CACHE_ROW JSR CLEAR_BRICK HC_SKIP_CLEAR_COL ; col collision detected, reverse col velocity LD R0, BALL_COL_VEL NOT R0, R0 INC R0, #1 ST R0, BALL_COL_VEL INC R2, #1 ; flag = positive (collision detected) HC_SKIP_REV_COL BRp R2, HC_NO_GAME_OVER ; second approximation: check both checkpoints at once (diagonal) ; This is only done if first approximation doesn't detect anything. AND R0, R3, R3 JSR GET_PIXEL_TYPE ; Check_Collision(row_checkpt, col_checkpt) ; check for game over BRn R5, HC_END BRz R5, HC_NO_GAME_OVER ; check for brick clearing CONST R0, #-3 ADD R0, R5, R0 BRnp R0, HC_SKIP_CLEAR AND R0, R3, R3 JSR CLEAR_BRICK HC_SKIP_CLEAR ; reverse both velocities LD R0, BALL_ROW_VEL NOT R0, R0 INC R0, #1 ST R0, BALL_ROW_VEL LD R0, BALL_COL_VEL NOT R0, R0 INC R0, #1 ST R0, BALL_COL_VEL HC_NO_GAME_OVER CONST R5, #0 HC_END ; Register Restoring INC R6, #6 LDR R0, R6, #0 LDR R1, R6, #-1 LDR R2, R6, #-2 LDR R3, R6, #-3 LDR R4, R6, #-4 LDR R7, R6, #-5 JUMPR R7 ; ------------------------------------------------------ ; Get Pixel Type subroutine - returns the object type at a given pixel GET_PIXEL_TYPE ; Arguments: R0 - row, R1 - col ; Return: R5 - game over (-1), no collision (0), wall collision (1), paddle collision (2), brick collision (3) ; Register Saving STR R0, R6, #0 STR R1, R6, #-1 STR R2, R6, #-2 STR R3, R6, #-3 STR R7, R6, #-4 INC R6, #-5 JSR CHECK_POINT_TR AND R3, R5, R5 ; R3 = color CONST R5, #0 ; R5 = return value BRz R3, CCP_END ; if (color == black) return 0 LD R2, COLOR_FLOOR SUB R2, R3, R2 BRz R2, CCP_GAME_OVER ; else if (color == floor_color) return -1 LD R2, COLOR_WALL SUB R2, R3, R2 BRz R2, CCP_COLL ; else if (color == wall_color) return 1 LD R2, COLOR_PADDLE SUB R2, R3, R2 BRz R2, CCP_PADDLE ; else if (color == paddle_color) return 2 ; Must be brick now JUMP CCP_BRICK ; else return 3 CCP_GAME_OVER INC R5, #-1 JUMP CCP_END CCP_COLL INC R5, #1 JUMP CCP_END CCP_PADDLE INC R5, #2 JUMP CCP_END CCP_BRICK INC R5, #3 JUMP CCP_END CCP_END ; Register Restoring INC R6, #5 LDR R0, R6, #0 LDR R1, R6, #-1 LDR R2, R6, #-2 LDR R3, R6, #-3 LDR R7, R6, #-4 JUMPR R7 ; ------------------------------------------------------ ; Handle Paddle Collision subroutine - changes ball's col velocity based on where it hits the paddle HANDLE_PADDLE_COLL ; Arguments: R0 - col ; Return: None ; Register Saving STR R0, R6, #0 STR R1, R6, #-1 STR R2, R6, #-2 STR R7, R6, #-3 INC R6, #-4 LD R1, PADDLE_COL_POS SUB R1, R0, R1 ; R1 = collision col pos - paddle col pos INC R1, #-6 BRn R1, HPC_LEFT JUMP HPC_RIGHT HPC_LEFT ; ball col vel = -abs(ball col vel) LD R2, BALL_COL_VEL BRnz R2, HPC_END NOT R2, R2 INC R2, #1 ST R2, BALL_COL_VEL JUMP HPC_END HPC_RIGHT ; ball col vel = abs(ball col vel) LD R2, BALL_COL_VEL BRzp R2, HPC_END NOT R2, R2 INC R2, #1 ST R2, BALL_COL_VEL HPC_END ; Register Restoring INC R6, #4 LDR R0, R6, #0 LDR R1, R6, #-1 LDR R2, R6, #-2 LDR R7, R6, #-3 JUMPR R7 ; ------------------------------------------------------ ; Clear Brick At Point subroutine - clears a brick at a given point CLEAR_BRICK ; Arguments: R0 - row, R1 - col ; Return: None ; Register Saving STR R0, R6, #0 STR R1, R6, #-1 STR R2, R6, #-2 STR R5, R6, #-3 STR R7, R6, #-4 INC R6, #-5 JSR GET_PIXEL_TYPE CONST R2, #-3 ADD R2, R5, R2 BRnp R2, CBAP_END ; sanity check, make sure we're clearing a brick! JSR CHECK_POINT_TR AND R2, R5, R5 JSR CLEAR_BRICK_RECURSE CBAP_END ; Register Restoring INC R6, #5 LDR R0, R6, #0 LDR R1, R6, #-1 LDR R2, R6, #-2 LDR R5, R6, #-3 LDR R7, R6, #-4 JUMPR R7 ; ------------------------------------------------------ ; Clear Brick subroutine - recursively clears a brick CLEAR_BRICK_RECURSE ; Arguments: R0 - row, R1 - col, R2 - color ; Return: None ; Register Saving STR R0, R6, #0 STR R1, R6, #-1 STR R2, R6, #-2 STR R3, R6, #-3 STR R4, R6, #-4 STR R5, R6, #-5 STR R7, R6, #-6 INC R6, #-7 JSR CHECK_POINT_TR SUB R5, R2, R5 BRnp R5, CB_END ; Cache Color AND R3, R2, R2 ; Erase Point CONST R2, #0 TRAP x40 ; DRAW_POINT ; Restore Color AND R2, R3, R3 ; Test up INC R0, #-1 JSR CLEAR_BRICK_RECURSE ; Test down INC R0, #2 JSR CLEAR_BRICK_RECURSE ; Test left INC R0, #-1 INC R1, #-1 JSR CLEAR_BRICK_RECURSE ; Test Right INC R1, #2 JSR CLEAR_BRICK_RECURSE CB_END ; Register Restoring INC R6, #7 LDR R0, R6, #0 LDR R1, R6, #-1 LDR R2, R6, #-2 LDR R3, R6, #-3 LDR R4, R6, #-4 LDR R5, R6, #-5 LDR R7, R6, #-6 JUMPR R7