← D00C Capsule behavior handler Map D186 → H-rotor behavior handler
D05B: Orb (ball-capturer) behavior handler
Behavior handler for the orb, which captures ball A and spits it back out. On top of the shared spawn and death reactions it runs its own hunt, chew, spit and give-up.
Input
IX the orb's sprite record
IY the orb's logic record
C the orb's pool-slot index
A capture of the ball scores 500 points. An orb that catches nothing within 250 frames turns into a capsule.
The orb homes on ball A and captures it. In its default state it chases ball A. When it overlaps ball A, it chews the ball for 110 frames, then spits it back toward the bat.
Hunt, the default: it forces the hunt sprite into the sprite record each frame, then steers. While the bat holds ball A, for a serve or a glue catch, the orb wanders on a random heading. In free flight it homes on the ball.
It avoids walls, advances, and leaves play at the far edge. A counter in its record counts to 250 frames, and at 250 the orb gives up. It then tests for the catch. An overlap enters the chew. Otherwise the sweep destroys it.
Chew: on the first frame it deactivates the ball. It clears ball A's active flag so nothing draws the ball. It runs the chew animation, and loops frames 21–28.
For its first 10 frames, timed by a counter in its record, the orb still homes on the ball and moves. The ball stays where it was caught. After that, a second counter is a hold timer that ticks to 100 frames. The ball's Y is pinned to the orb's Y while it ticks. At animation frame 20 it arms the chew sound. When the hold timer reaches 100 it switches to the spit.
Spit: it plays the continuation of the orb animation, and at animation frame 6 it arms the orb-spit sound. From animation frame 8 on it points ball A's sprite at the spat-out ball. It also re-arms the capture slide, which makes the ball active again and walks it back to the bat side.
QUIRK: the spit code carries a death transition on animation frame 14. It sits on the branch for frames below 8, where the frame can never be 14. The orb therefore never dies here. From frame 8 onward it merely re-arms the ball every frame. The spit has no self-exit.
The slot is reclaimed externally, via the ball-loss path. Each frame it re-arms the capture slide. The slide walks the caught ball to the bat's losing edge at 5 px/frame and, on arrival, loses the ball. With ball B in play, ball B takes over as ball A and the re-armed slide carries it off too. When the last ball goes, the last-ball branch zeroes the type field of every inhabitant record. The dispatcher therefore skips the now-empty orb slot on the next pass.
Give up: it zeroes the anim frame, state and both counters. It then rewrites the type field. The slot becomes a capsule on the next frame.
update_orb D05B CALL inhabitant_react_state Run the shared reaction machine; while a spawn or death animation plays it returns carry and the orb skips its own update this frame.
D05E RET C
D05F LD A,(IY+$0C) Branch on the reaction state: the chew runs here; the spit, give-up and hunt below.
D062 CP $03
D064 JR NZ,update_orb_5
D066 LD A,(IY+$0B) On the first chew frame only, deactivate the captured ball.
D069 OR A
D06A JR NZ,update_orb_0
D06C PUSH IX Clear ball A's active flag so nothing draws the ball.
D06E LD IX,ball_a_object
D072 RES 0,(IX+$08)
D076 POP IX
update_orb_0 D078 CP $14 Partway through the chew animation, arm the 49-step chew sound.
D07A JR NZ,update_orb_1
D07C LD A,$01
D07E LD (chew_counter),A
update_orb_1 D081 LD HL,anim_orb Advance the chew animation by one frame.
D084 CALL advance_anim
D087 LD A,(IY+$0B) Loop the chew tail: wrap the animation frame back to 21 at the tail's end, so frames 21–28 cycle.
D08A CP $1D
D08C JR C,update_orb_2
D08E LD (IY+$0B),$15
update_orb_2 D092 LD A,(IY+$09) Early in the chew, close on the ball. Once the chew count reaches its limit, hold the ball in place.
D095 CP $0A
D097 JR NZ,update_orb_4
D099 INC (IY+$0A) Hold timer: once it runs out, switch to the spit.
D09C LD A,(IY+$0A)
D09F CP $64
D0A1 JR NZ,update_orb_3
D0A3 LD (IY+$0C),$04 Begin the spit and reset the animation frame.
D0A7 LD (IY+$0B),$00
update_orb_3 D0AB LD A,(IX+$01) Pin the ball's Y to the orb's so it tracks the orb while held.
D0AE PUSH IX
D0B0 LD IX,ball_a_object
D0B4 LD (IX+$01),A
D0B7 POP IX
D0B9 RET
update_orb_4 D0BA INC (IY+$09) Under 10 frames in: step toward the ball and advance.
D0BD LD B,$01
D0BF CALL head_toward_target
D0C2 CALL move_object
D0C5 RET
update_orb_5 D0C6 CP $04 Spit the chewed ball back out.
D0C8 JR NZ,update_orb_8
D0CA LD A,(IY+$0B) Partway through the spit animation, arm the orb-spit sound.
D0CD CP $06
D0CF JR NZ,update_orb_6
D0D1 LD A,$05
D0D3 LD (orb_spit_timer),A
update_orb_6 D0D6 LD HL,anim_orb+$3A Advance the spit animation (the continuation of the orb animation).
D0D9 CALL advance_anim
D0DC LD A,(IY+$0B) Past the first frames of the spit, release the ball.
D0DF CP $08
D0E1 JR C,update_orb_7
D0E3 LD A,$01 Re-arm the capture slide that walks the ball back to the bat side.
D0E5 LD (capture_slide),A
D0E8 PUSH IX Point ball A's sprite at the spat-out ball.
D0EA LD IX,ball_a_object
D0EE LD HL,slot_orb_ball
D0F1 LD (IX+$06),L
D0F4 LD (IX+$07),H
D0F7 POP IX
D0F9 RET
update_orb_7 D0FA CP $0E QUIRK dead code: the branch above enters only while the spit animation is in its early frames. This later frame therefore never matches, and the death it would set never fires.
D0FC RET NZ
D0FD LD (IY+$0C),$02
D101 LD (IY+$0B),$00
D105 RET
update_orb_8 D106 CP $05 Give up the hunt.
D108 JR NZ,update_orb_9
D10A XOR A Reset the animation frame, state and both counters.
D10B LD (IY+$0B),A
D10E LD (IY+$0C),A
D111 LD (IY+$09),A
D114 LD (IY+$0A),A
D117 LD (IY+$08),$08 Morph into a capsule: rewrite the type field so the capsule handler runs this slot next frame.
D11B RET
update_orb_9 D11C INC (IY+$09) Hunt timer: once it runs out with no catch, give up.
D11F LD A,(IY+$09)
D122 CP $FA
D124 JR NZ,update_orb_10
D126 LD (IY+$0C),$05 Arm the give-up reset.
update_orb_10 D12A LD HL,slot_orb_hunt Force the orb's hunt sprite into the sprite record each frame.
D12D LD (IX+$06),L
D130 LD (IX+$07),H
D133 LD A,(ball_a_on_bat) While the bat holds ball A, for a serve or a glue catch, wander. In free flight, home on it.
D136 OR A
D137 JR Z,update_orb_11
D139 XOR A Ball on the bat: wander on a random heading.
D13A CALL pick_wander_heading
D13D JR update_orb_12
update_orb_11 D13F LD B,$01 Free flight: steer toward the ball.
D141 CALL head_toward_target
update_orb_12 D144 CALL object_avoid_walls Avoid walls, advance, and despawn off the far edge.
D147 CALL move_object
D14A CALL inhabitant_offscreen
D14D RET C
D14E LD A,C Test the orb against ball A for a catch through the first and second overlap operands.
D14F LD (overlap_slot_1),A
D152 LD A,$01
D154 LD (overlap_slot_2),A
D157 CALL overlap_pair
D15A OR A
D15B JR NZ,update_orb_13
D15D CALL overlap_sweep No catch: the sweep destroys the orb.
D160 OR A
D161 RET Z
D162 LD (IY+$0B),$00 Die: restart the animation and enter the death reaction.
D166 LD (IY+$0C),$02
D16A RET
update_orb_13 D16B XOR A Catch: zero the anim frame and both counters and enter the chew.
D16C LD (IY+$0B),A
D16F LD (IY+$09),A
D172 LD (IY+$0A),A
D175 LD (IY+$0C),$03
D179 INC A Flag the capture: set the ball-captured flag and request the glue release.
D17A LD (capture_active),A
D17D LD (glue_release_req),A
D180 LD A,$32 Award 500 points for the catch, banked as this frame's pending points.
D182 LD (pending_score),A
D185 RET
← D00C Capsule behavior handler Map D186 → H-rotor behavior handler
Fork me on GitHub