← A341 Active ball's tile-map probe origin (two bytes, little-endian) Map A4E6 → Unused bytes
A343: Move the active ball and detect bounces
Probes the cell ahead of the active ball on each axis with the collision probe. A wall or brick hit reflects its heading.
move_ball A343 LD A,$FF Clear the two axis bounce codes and the axis count before this move.
A345 LD (bounce_x_code),A
A348 LD (bounce_y_code),A
A34B XOR A
A34C LD (bounce_axis_count),A
A34F LD A,(active_ball)
A352 OR A
A353 JR NZ,move_ball_use_b
A355 LD IY,ball_a_x_accum This arm takes ball A's state record.
A359 JR move_ball_probe_x
move_ball_use_b A35B LD IY,ball_b_x_accum Otherwise it is ball B's.
move_ball_probe_x A35F LD A,(active_ball) Find the active ball's probe origin and keep it.
A362 LD B,A
A363 INC B
A364 CALL ball_tile_cell
A367 LD (ball_cell_ptr),HL
A36A LD A,(IY+$04) Probe one tile ahead in the ball's X direction for a wall or brick. A leftward sign probes the tile to the left and flags the leftward bounce code.
A36D OR A
A36E JR NZ,move_ball_probe_x_pos
A370 LD B,$20
A372 CALL collision_probe
A375 OR A
A376 JR Z,move_ball_check_y
A378 LD A,$02
A37A LD (bounce_x_code),A
A37D LD HL,bounce_axis_count
A380 INC (HL)
A381 JR move_ball_check_y
move_ball_probe_x_pos A383 LD B,$22 A rightward sign probes that side and flags the rightward code.
A385 CALL collision_probe
A388 OR A
A389 JR Z,move_ball_check_y
A38B XOR A
A38C LD (bounce_x_code),A
A38F LD HL,bounce_axis_count
A392 INC (HL)
move_ball_check_y A393 LD A,(active_ball) With the X axis settled, the missile shot returns here, with no Y probe and no reflection.
A396 OR A
A397 JR Z,move_ball_probe_y
A399 LD A,(missile_shot)
A39C OR A
A39D RET NZ
move_ball_probe_y A39E LD A,(IY+$05) Probe one tile ahead in Y and flag a Y bounce. An upward sign probes the tile above.
A3A1 OR A
A3A2 JR NZ,move_ball_probe_y_pos
A3A4 LD B,$01
A3A6 CALL collision_probe
A3A9 OR A
A3AA JR Z,move_ball_resolve
A3AC LD A,$01
A3AE LD (bounce_y_code),A
A3B1 LD HL,bounce_axis_count
A3B4 INC (HL)
A3B5 JR move_ball_resolve
move_ball_probe_y_pos A3B7 LD B,$41 A downward sign probes the tile below and flags the downward bounce code.
A3B9 CALL collision_probe
A3BC OR A
A3BD JR Z,move_ball_resolve
A3BF LD A,$03
A3C1 LD (bounce_y_code),A
A3C4 LD HL,bounce_axis_count
A3C7 INC (HL)
move_ball_resolve A3C8 LD A,(bounce_axis_count) Nothing hit – return. Otherwise turn the bounce flags into a reflected heading.
A3CB OR A
A3CC RET Z
A3CD CP $02
A3CF JR Z,move_ball_corner
A3D1 LD A,(bounce_x_code)
A3D4 OR A
A3D5 JP P,move_ball_reflect
A3D8 LD A,(bounce_y_code)
A3DB JP move_ball_reflect
move_ball_corner A3DE LD B,$04 Both axes hit (a corner): look up the diagonal bounce code.
A3E0 LD HL,corner_bounce_codes
move_ball_corner_loop A3E3 LD A,(bounce_x_code) Each record holds the two axis codes and the diagonal bounce code they yield; compare this one's X code, then its Y code.
A3E6 CP (HL)
A3E7 JR NZ,move_ball_corner_skip
A3E9 INC HL
A3EA LD A,(bounce_y_code)
A3ED CP (HL)
A3EE JR NZ,move_ball_corner_next
A3F0 INC HL
A3F1 LD A,(HL)
A3F2 JP move_ball_reflect
move_ball_corner_skip A3F5 INC HL The X code did not match, so this record's Y byte is skipped as well.
move_ball_corner_next A3F6 INC HL Step over the rest of the record and try the next one.
A3F7 INC HL
A3F8 DJNZ move_ball_corner_loop
move_ball_reflect A3FA EX AF,AF' Mirror the heading about the axis it struck. B takes the ball's current heading, and the reflection table indexed by the bounce code gives the axis. The reflected heading lies as far past the axis as the current one lies short of it.
A3FB LD HL,ball_a_heading
A3FE LD A,(active_ball)
A401 LD E,A
A402 LD D,$00
A404 ADD HL,DE
A405 LD B,(HL)
A406 PUSH HL
A407 EX AF,AF'
A408 LD HL,bounce_axis_dirs
A40B LD E,A
A40C LD D,$00
A40E ADD HL,DE
A40F LD A,(HL)
A410 SUB B
A411 LD B,(HL)
A412 ADD A,B
move_ball_adj_quadrant A413 ADD A,$24 Bias by a half-turn. A result below the heading space wraps up a full turn.
A415 CP $48
A417 JR NC,move_ball_0
A419 ADD A,$48
A41B JR move_ball_1
move_ball_0 A41D CP $90 One above it wraps down a full turn.
A41F JR C,move_ball_1
A421 SUB $48
move_ball_1 A423 POP HL Recover the pointer to the heading byte.
move_ball_q48 A424 LD C,A C now holds the reflected heading and B the reference heading of the axis it struck, which names the way it came in. The cases below fold C into the arc that axis allows it to leave on. Came in due right: leave between 90° and 264°.
A425 LD A,B
A426 CP $48
A428 JR NZ,move_ball_q5a
A42A LD A,C
A42B CP $5A
A42D JR C,move_ball_2
A42F CP $7E
A431 JP C,move_ball_store
move_ball_2 A434 SUB $24 Outside that arc: take off a half-turn, and wrap up a full turn if that drops below the space.
A436 CP $48
A438 JP NC,move_ball_store
A43B ADD A,$48
A43D JP move_ball_store
move_ball_q5a A440 CP $5A Came in straight up: leave between 180° and 356°.
A442 JR NZ,move_ball_q6c
A444 LD A,C
A445 CP $6C
A447 JP NC,move_ball_store
A44A SUB $24
A44C CP $48
A44E JP NC,move_ball_store
A451 ADD A,$48
A453 JP move_ball_store
move_ball_q6c A456 CP $6C Came in due left: leave between 270° and 84°.
A458 JR NZ,move_ball_q7e
A45A LD A,C
A45B CP $5A
A45D JR C,move_ball_store
A45F CP $7E
A461 JR NC,move_ball_store
A463 SUB $24
A465 CP $48
A467 JR NC,move_ball_store
A469 ADD A,$48
A46B JR move_ball_store
move_ball_q7e A46D CP $7E Came in straight down: leave between 0° and 176°.
A46F JR NZ,move_ball_q51
A471 LD A,C
A472 CP $6C
A474 JR C,move_ball_store
A476 SUB $24
A478 CP $48
A47A JR NC,move_ball_store
A47C ADD A,$48
A47E JR move_ball_store
move_ball_q51 A480 CP $51 Came in on the up-right diagonal: leave between 139° and 315°.
A482 JR NZ,move_ball_q63
A484 LD A,C
A485 CP $63
A487 JR C,move_ball_q51_wrap
A489 CP $87
A48B JR C,move_ball_store
move_ball_q51_wrap A48D SUB $24 Outside that arc: take off a half-turn, and wrap up a full turn if that drops below the range.
A48F CP $48
A491 JR NC,move_ball_store
A493 ADD A,$48
A495 JR move_ball_store
move_ball_q63 A497 CP $63 Came in on the up-left diagonal: leave between 221° and 35°.
A499 JR NZ,move_ball_q75
A49B LD A,C
A49C CP $75
A49E JR NC,move_ball_store
A4A0 CP $51
A4A2 JR C,move_ball_store
A4A4 SUB $24
A4A6 CP $48
A4A8 JR NC,move_ball_store
A4AA ADD A,$48
A4AC JR move_ball_store
move_ball_q75 A4AE CP $75 Came in on the down-left diagonal: leave between 319° and 135°.
A4B0 JR NZ,move_ball_q87
A4B2 LD A,C
A4B3 CP $63
A4B5 JR C,move_ball_store
A4B7 CP $87
A4B9 JR NC,move_ball_store
A4BB SUB $24
A4BD CP $48
A4BF JR NC,move_ball_store
A4C1 ADD A,$48
A4C3 JR move_ball_store
move_ball_q87 A4C5 CP $87 A reference heading that matches none of the eight leaves the reflected heading alone.
A4C7 JR Z,move_ball_q87b
A4C9 LD A,C
A4CA JR move_ball_store
move_ball_q87b A4CC LD A,C Came in on the down-right diagonal: leave between 41° and 215°.
A4CD CP $75
A4CF JR NC,move_ball_clamp_final
A4D1 CP $51
A4D3 JR NC,move_ball_store
move_ball_clamp_final A4D5 SUB $24 Outside that arc: take off a half-turn, and wrap up a full turn if that drops below the range.
A4D7 CP $48
A4D9 JR NC,move_ball_store
A4DB ADD A,$48
move_ball_store A4DD LD (HL),A Store the new heading, arm the move gate that debounces a re-hit, and re-derive the ball's velocity.
A4DE LD (IY+$08),$01
A4E2 CALL set_ball_velocity
A4E5 RET
← A341 Active ball's tile-map probe origin (two bytes, little-endian) Map A4E6 → Unused bytes
Fork me on GitHub