;############## CMonster by Patrick Davidson - ball handling Handle_Ball: push hl ; Push X coordinate pointer ld b,(hl) inc hl push hl ; Push Y coordinate pointer ld l,(hl) ld de,img_fake_ball ld a,5 call Erase_Sprite_Check_Clip_Below pop hl ; Pop Y coordinate pointer ld a,(hl) ; A = Y coordinate inc hl inc hl add a,(hl) ; A = new Y coordinate cp 248 jr c,not_ball_top ld a,(hl) ; we hit the top, so negate velocity neg ld (hl),a xor a ; set new Y coordinate to 0 not_ball_top: cp 232 jr c,not_fall_off_bottom pop hl dec hl ; HL -> b_type ld (hl),0 ; delete this ball ret not_fall_off_bottom: dec hl dec hl ld (hl),a ; save new Y coordinate cp 219 ; bouncing off paddle jr c,ball_y_done inc hl inc hl ; HL -> b_yv bit 7,(hl) ; skip bounce if already moving up jr nz,ball_y_done pop hl ; HL -> b_x push hl ld a,(p_x) neg add a,(hl) ; A = ball X - paddle X add a,2 ; A = distance past left paddle edge (and buffer) cp 24 inc hl inc hl inc hl ; HL points at YV again jr nc,ball_y_done push hl rra ; range now 0-11 (and carry shifted into bit 7) and %1110 ; range now 0-10,even #ifdef TI84CE ld bc,0 #else ld b,0 #endif ld c,a ld hl,ball_directions add hl,bc ld a,(hl) ; A = new X velocity inc hl ld b,(hl) ; B = new Y velocity pop hl bit 7,(hl) jr nz,no_set_y_velocity ld (hl),b no_set_y_velocity dec hl jr nz,no_set_x_velocity ld (hl),a no_set_x_velocity inc hl xor a ld (bounce_count),a ld hl,plimit ; decrement pause limit on bounce ld a,(hl) or a jr z,plimit_already_zero dec (hl) plimit_already_zero: ld hl,brickthrough ld a,(hl) or a jr z,brickthrough_already_zero dec (hl) brickthrough_already_zero ball_y_done: pop hl ; HL -> X coordinate ld a,(hl) inc hl inc hl add a,(hl) ; A = new X coordinate ld b,a ; B = new X coordinate cp 200 jr c,not_left ld a,(hl) neg ld (hl),a ; negate X velocity ld b,0 ; minimum X is 0 jr ball_x_calculated not_left: cp 157 jr c,ball_x_calculated ld a,(hl) neg ld (hl),a ; negate X velocity ld b,157 ; minimum X is 0 ball_x_calculated: dec hl dec hl ; HL -> X ld (hl),b push hl inc hl ld l,(hl) ; L = Y coordinate (B already is X) ld de,img_ball ld a,5 call Draw_Sprite_Check_Clip_Below_16 pop hl ; HL -> X ld (Collision_Check+1),hl push hl ld a,$c9 ; First round collision checks will flag call Collision_Checks ld a,(hit_corner) ld c,a ld b,0 ld hl,bounce_actions add hl,bc ld d,(hl) ; D = bit mask of bounce actions to take ; ld a,c ; or a ; jr z,no_ball_bounce ; add a,64 ; ld (score),a ;no_ball_bounce: pop hl ; HL -> X ld a,(brickthrough) or a jr nz,brickthrough_active inc hl inc hl ; HL -> XV ld a,(hl) rl d jr nc,no_bounce_up bit 7,a jr nz,no_bounce_up neg no_bounce_up: rl d jr nc,no_bounce_down bit 7,a jr z,no_bounce_down neg no_bounce_down: rl d jr nc,no_reverse_y neg no_reverse_y: ld (hl),a inc hl ld a,(hl) rl d jr nc,no_bounce_left bit 7,a jr nz,no_bounce_left neg no_bounce_left: rl d jr nc,no_bounce_right bit 7,a jr z,no_bounce_right neg no_bounce_right: rl d jr nc,no_reverse_x neg no_reverse_x: ld (hl),a bounce_done: xor a ; Second round collision checks will erase jr Collision_Checks brickthrough_active: xor a ld (bounce_count),a jr Collision_Checks ; Bounce actions table ; Indexed into table as follows ; Bit 0 - set if top left corner hit ; Bit 1 - set if top right corner hit ; Bit 2 - set if bottom left corner hit ; Bit 3 - set if bottom right corner hit ; Action byte defined as follows ; Bit 7 - set to force direction to left ; Bit 6 - set to force direction to right ; Bit 5 - set to reverse X direction ; Bit 4 - set to force direction to up ; Bit 3 - set to force direction to down ; Bit 2 - set to reverse direction bounce_actions: .db %00000000 ; Nothing hit, keep going .db %01001000 ; A Hit on top left only, so go down right .db %10001000 ; B Hit on top right only, so go down left .db %00001000 ; C Hit on all of top, so go down only .db %01010000 ; D Hit on bottom left only, so go up right .db %01000000 ; E Hit on all of left, so go right only .db %00100100 ; F Hit on bottom left, top right, so reverse .db %01001000 ; G Hit all but bottom right, so go down right .db %10010000 ; H Hit on bottom right only, so go up left .db %00100100 ; I Hit on bottom right and top left, so reverse .db %10000000 ; J Hit on all of right, so go left only .db %10001000 ; K Hit on all but bottom left, so go down left .db %00010000 ; L Hit on all of bottom, so go up only .db %01010000 ; M Hit on all but top right, so go up right .db %10010000 ; N Hit on all but top left, so go up left .db %00100100 ; O Hit on all, should be impossible, but reverse ;############## Test for collision with bricks, H = X, L = Y Collision_Checks: ld (smc_mode),a xor a ld (hit_corner),a ld bc,0 call Collision_Check jr z,notopleft ld hl,hit_corner set 0,(hl) notopleft: ld bc,$200 call Collision_Check jr z,notopright ld hl,hit_corner set 1,(hl) notopright: ld bc,4 call Collision_Check jr z,nobottomleft ld hl,hit_corner set 2,(hl) nobottomleft: ld bc,$204 call Collision_Check ret z ld hl,hit_corner set 3,(hl) ret Collision_Check: ld hl,0 ld a,(hl) ; D = pixel X coordinate /2 add a,b rra rra rra and 31 ld d,a inc hl ld a,(hl) add a,c rra rra rra and 31 bit 4,a jr nz,out_of_brick_area ld e,a push de call Find_Brick_DE and (hl) pop bc ret z ; bit not set - no brick here smc_mode: ret xor (hl) ld (hl),a ; rewrite with this bit gone ld a,c call Draw_Brick ; clear mode, erase the brick ld de,(Collision_Check+1) call Check_Drop_Bonus ld hl,bounce_count ld a,(hl) cp 10 jr z,max_bounce inc a ld (hl),a max_bounce: ld b,a add_score_loop: push bc call add_score pop bc djnz add_score_loop ret add_score: ld hl,score+6 ; and increment the score ld de,score_increment+5 ld a,(score_inc) ld (de),a inc de Add_6_Digits_BCD: ld b,6 loop_add_nocarry: xor a loop_add: dec hl dec de ld a,(de) adc a,(hl) sub '0' ; '0' was added twice because both ASCII cp '0'+10 jr c,loop_add_nocarry_end sub 10 ccf ld (hl),a djnz loop_add ret loop_add_nocarry_end: ld (hl),a djnz loop_add_nocarry ret out_of_brick_area: xor a ret score_increment: .db "000001"