← 997A Clear the back buffer Map 9AF3 → Drag every caught ball up with the bat
9988: Move the player's bat
Moves the player's bat up and down once per frame, from the sampled controls.
The chosen control style, direct or inertia, decides the step. Whatever is attached comes with it, both the bat extension and any ball caught on the bat.
Three gates can suppress the move, and the double bat tail runs even then.
Both control styles test the same three travel bounds before they move the bat.
Bound Bat Y Applies
Top 38 always
Bottom 154 with the bat on its own
Bottom 138 while the bat extension is attached
move_bat 9988 LD IX,object_table Only the bat's Y moves here. The side the player chose fixes its column.
998C LD A,(bat_sting_freeze) Gate 1: the sting freeze. The bee sets it on its overlap with the bat itself, never on a sweep hit. While it is set, jump straight to the double bat tail. That skips all bat movement, so the player cannot steer the bat. Cleared when the last ball is lost (lose_ball_last) or by the level setup (clear_state_buffers).
998F OR A
9990 JP NZ,track_double_bat
9993 LD A,(bat_freeze) Gate 2: the bat freeze. If clear, go on to the third gate. If set, run the release timer below and hold position.
9996 OR A
9997 JR Z,pick_bat_control
9999 LD HL,bat_freeze_timer Frozen: count the freeze timer up by one this frame.
999C INC (HL)
999D LD A,(HL)
999E CP $0F Release the bat freeze once the hold runs out; either way jump to the double bat tail, and leave the bat where it is.
99A0 JP NZ,track_double_bat
99A3 XOR A
99A4 LD (HL),A
99A5 LD (bat_freeze),A
99A8 JP track_double_bat
pick_bat_control 99AB LD A,(death_pause_timer) Gate 3: the death-pause timer is set – skip all movement, but still run the double bat tail.
99AE OR A
99AF JP NZ,track_double_bat
99B2 LD A,(bat_control_type) Pick the control style: inertia runs inertia control, and either dual-speed style runs direct control below.
99B5 OR A
99B6 JR NZ,apply_direct_control
99B8 CALL apply_inertia_control
99BB JP track_double_bat
The direct control style. The step follows the control bits of the current frame, with nothing carried over from the frames before it.
The step is the slow speed, or the fast speed while fire is also held. The options screen sets both, on the rows it prints as DUAL SPEED SLOW and DUAL SPEED FAST. Up decreases the bat Y, down increases it. The edge test uses the position before the step, so a large step can carry the bat past the limit.
apply_direct_control 99BE LD HL,controls Read the live control bits into HL.
99C1 BIT 3,(HL) Up held?
99C3 JR Z,direct_down
99C5 LD A,(bat_speed_slow) Take the slow speed as the step.
99C8 LD B,A
99C9 LD A,(IX+$01) Current bat Y
99CC CP $26 Blocked at the top edge – the bat cannot move further up.
99CE JP C,track_double_bat
99D1 SUB B Move the bat up by the slow speed.
99D2 LD (IX+$01),A
99D5 CALL drag_attached_up Drag the bat extension up with it.
99D8 LD A,(bat_speed_slow)
99DB CALL drag_caught_up Drag any caught ball up with it.
99DE BIT 4,(HL) Fire also held? Apply the fast-speed bonus.
99E0 JP Z,track_double_bat
99E3 LD A,(bat_speed_slow) Take the difference between the fast and slow speeds as the extra step.
99E6 LD C,A
99E7 LD A,(bat_speed_fast)
99EA SUB C
99EB LD B,A
99EC LD A,(IX+$01)
99EF SUB B Move up by the extra amount, for a total step of the fast speed this frame.
99F0 LD (IX+$01),A
99F3 CALL drag_attached_up
99F6 LD A,B
99F7 CALL drag_caught_up
99FA JR track_double_bat
direct_down 99FC BIT 2,(HL) Down held?
99FE JR Z,track_double_bat
9A00 LD A,(expand_active) An attached extension raises the bottom travel limit.
9A03 OR A
9A04 JR Z,direct_down_clamp
9A06 LD A,(IX+$01)
9A09 CP $8A Extension attached: the raised bottom limit applies.
9A0B JR NC,track_double_bat
9A0D JR direct_down_apply
direct_down_clamp 9A0F LD A,(IX+$01) No extension: take the bat's Y on its own.
9A12 CP $9A Otherwise the plain bottom limit applies.
9A14 JR NC,track_double_bat
direct_down_apply 9A16 LD A,(bat_speed_slow) Move the bat down by the slow speed and drag the extension and caught ball with it.
9A19 LD B,A
9A1A LD A,(IX+$01)
9A1D ADD A,B
9A1E LD (IX+$01),A
9A21 CALL drag_attached_down
9A24 LD A,(bat_speed_slow)
9A27 CALL drag_caught_down
9A2A BIT 4,(HL) Fire also held? Apply the fast-speed bonus downward too.
9A2C JR Z,track_double_bat
9A2E LD A,(bat_speed_slow)
9A31 LD B,A
9A32 LD A,(bat_speed_fast)
9A35 SUB B
9A36 LD B,A
9A37 LD A,(IX+$01)
9A3A ADD A,B Move down by the extra amount, for a total step of the fast speed.
9A3B LD (IX+$01),A
9A3E CALL drag_attached_down
9A41 LD A,B
9A42 CALL drag_caught_down
Double bat tail, run every frame. It acts only while the double bat flag is set, with no missile shot in flight and no retract or bomb effect armed. It then parks the secondary object at the bat's current Y on the bat's side and activates it. Drawn with the bat sprite, it is the second bat, which follows the bat's Y.
track_double_bat 9A45 LD A,(double_bat_active) Skip unless the double bat flag is set.
9A48 OR A
9A49 JR Z,launch_missile
9A4B LD A,(missile_shot) Skip while the missile shot is in flight, or while the retract or bomb effect is armed.
9A4E OR A
9A4F JR NZ,launch_missile
9A51 LD A,(fx_retract_arm)
9A54 OR A
9A55 JR NZ,launch_missile
9A57 LD A,(fx_bomb_arm)
9A5A OR A
9A5B JR NZ,launch_missile
9A5D LD B,(IX+$01) Take the bat's current Y.
9A60 PUSH IX
9A62 LD IX,obj2_object Target the secondary object and pick its X column from the bat side: the right bat parks it at x 188.
9A66 LD A,(bat_side)
9A69 OR A
9A6A JR NZ,track_double_bat_left
9A6C LD (IX+$00),$BC
9A70 JR track_double_bat_set
track_double_bat_left 9A72 LD (IX+$00),$34 The left bat parks it at the mirrored column.
track_double_bat_set 9A76 LD (IX+$01),B Set the second bat's Y to the bat's, point it at the bat sprite, and set its active flag.
9A79 LD DE,slot_bat_normal
9A7C LD (IX+$06),E
9A7F LD (IX+$07),D
9A82 SET 0,(IX+$08)
9A86 POP IX
Launch the missile shot on fire. When the missile bat is armed and fire is held in the controls, it spawns the secondary object at the bat's Y. It also seeds ball B's motion state. The shot moves outward from the bat's side. Returns immediately when nothing is armed or fire is not held.
launch_missile 9A88 LD A,(missile_active) No missile bat armed? Return.
9A8B OR A
9A8C RET Z
9A8D BIT 4,(HL) Fire not held? Return. HL points at the control bitfield only under direct control, or under inertia while the bat stands still. On every other path, this tests a byte that is not the controls – see Defects.
9A8F RET Z
9A90 XOR A Disarm the missile bat and clear ball B's combo. Cancel the swap to the missile-bat sprite and arm the swap back to the normal bat.
9A91 LD (missile_active),A
9A94 LD (combo_b),A
9A97 LD (fx_bat_missile_arm),A
9A9A INC A
9A9B LD (fx_bat_normal_arm),A
9A9E LD B,(IX+$01) Spawn the secondary object at the bat's Y. The side the bat plays from picks the X column (x 204 right / x 36 left) and the launch heading for that side.
9AA1 LD IX,obj2_object
9AA5 LD A,(bat_side)
9AA8 OR A
9AA9 JR NZ,launch_missile_left
9AAB LD (IX+$00),$CC
9AAF LD C,$63
9AB1 JR launch_missile_set
launch_missile_left 9AB3 LD (IX+$00),$24 The left bat mirrors the column and takes the opposite heading code.
9AB7 LD C,$87
launch_missile_set 9AB9 LD (IX+$01),B Store the position, point at the missile-shot sprite and activate the object. Seed ball B's motion with the launch heading, its speed and counters, and set the two-ball and missile-shot flags. The shot then travels as the secondary object and clears every brick it passes through, the golden one included. A missile run thus cuts a lane the ball cannot.
9ABC LD DE,slot_missile_shot
9ABF LD (IX+$06),E
9AC2 LD (IX+$07),D
9AC5 SET 0,(IX+$08)
9AC9 LD A,C
9ACA LD (ball_b_heading),A
9ACD LD A,$05
9ACF LD (ball_b_speed),A
9AD2 LD (ball_b_x_threshold),A
9AD5 XOR A
9AD6 LD (ball_b_on_bat),A
9AD9 LD (ball_b_y_threshold),A
9ADC LD (ball_b_y_dir),A
9ADF LD (ball_b_x_accum),A
9AE2 LD (ball_b_y_accum),A
9AE5 INC A
9AE6 LD (ball_b_in_play),A
9AE9 LD (missile_shot),A
9AEC LD A,(bat_side)
9AEF LD (ball_b_x_dir),A
9AF2 RET
← 997A Clear the back buffer Map 9AF3 → Drag every caught ball up with the bat
Fork me on GitHub