    .ifndef WITH_FRIENDLY_RECEPTION
    .equ WITH_FRIENDLY_RECEPTION,0
    .endif
 .equ FINISH_GAP,16
 .equ AIM_CLEAR,16
 .equ AIM_IMPROVE,8
| Hard CPU chooses among existing native targets; height and physics stay native.
| +0 actual C30C hook, +4 catch opening, +8 pure target policy (D0/D1/D2).
| No persistent RAM, arbitrary RNG calls, physical or player-attribute writes.
 .text
 .globl _start
_start:
 bra.w shot_hook
 bra.w opening
 bra.w policy

shot_hook:
 jsr 0xC566                       | exact original aim, including human/special paths
 move.w %sr,-(%sp)
 movem.l %d0-%d7/%a0-%a6,-(%sp)
 bsr.w policy
 tst.w %d0
 beq.s hook_restore
 cmp.w 0xFFFFBEDC,%d1
 beq.s hook_restore
 move.w %d1,0xFFFFBEDC
 move.w %d1,2(%sp)                | native D0 aim result, preserving its upper word
hook_restore:
 movem.l (%sp)+,%d0-%d7/%a0-%a6
 move.w (%sp)+,%ccr
 move.w #5,-(%sp)                 | displaced C310; NOT a helper return address
 jmp 0xC314

opening:
 .if WITH_CATCH_OPENING
 movem.l %d1-%d7/%a0-%a6,-(%sp)
 move.w 0xFFFFBEDC,-(%sp)
 bsr.w guard                      | do not execute special-mode aim from this probe
 tst.w %d0
 .if WITH_FRIENDLY_RECEPTION
 bne.s opening_eligible
 jsr 0x225808                     | a real owned nativeB24 friendly catch may finish
 tst.w %d0
 beq.s opening_no
opening_eligible:
 .else
 beq.s opening_no
 .endif
 jsr 0xC566
 .if WITH_FRIENDLY_RECEPTION
 bsr.w policy_opening
 .else
 bsr.w policy
 .endif
 tst.w %d0
 beq.s opening_no
 cmpi.w #FINISH_GAP,%d2
 blo.s opening_no
 moveq #1,%d0
 bra.s opening_restore
opening_no:
 moveq #0,%d0
opening_restore:
 move.w (%sp)+,0xFFFFBEDC
 movem.l (%sp)+,%d1-%d7/%a0-%a6
 rts
 .else
 moveq #0,%d0
 rts
 .endif

| One genuine CPU shot may already have its native windup animation locked.
| Eligibility is separately adapted per club by the benchmark (this CMP only).
guard:
 moveq #0,%d0
 cmpi.w #1,0xFFFFF07A
 bne.w guard_done
 btst #3,0x62(%a3)
 bne.w guard_done
 btst #2,0x63(%a3)
 bne.w guard_done
 tst.w 0x34(%a3)
 ble.w guard_done
 btst #5,0x62(%a3)
 beq.s guard_context
 cmpi.w #0x7FC,0x58(%a3)
 beq.s guard_context
 cmpi.w #0x92E,0x58(%a3)
 bne.w guard_done
guard_context:
 btst #0,0xFFFFC2EA
 bne.w guard_done
 btst #4,0xFFFFC2EA
 bne.w guard_done
 btst #7,0xFFFFC2EC
 bne.w guard_done
 btst #7,0xFFFFC2EE
 bne.w guard_done
 btst #2,0xFFFFC2F2
 bne.w guard_done
 move.b 0xFFFFC2FA,%d0
 andi.w #5,%d0
 bne.s guard_no
 move.w 0xFFFFF738,%d0
 subi.w #0xA502,%d0
 cmpi.w #5,%d0
 bcs.s guard_no                    | native automatic replay can have C2EC bit7 clear
 move.w 0xFFFFB7AA,%d0
 cmpi.w #11,%d0
 bhi.s guard_no
 cmp.w 0x52(%a3),%d0
 bne.s guard_no
 moveq #1,%d0
 rts
guard_no:
 moveq #0,%d0
guard_done:
 rts

| Native BEDC input; D0 eligible, D1 selected index, D2 selected ray separation.
| D3-D7/A0-A6 preserved. 7FFF means no keeper between puck and goal line.
 .if WITH_FRIENDLY_RECEPTION
| This entry is used ONLY by the catch-opening probe. The general shot target
| policy retains its original busy exclusions. A real owned friendly B24 catch
| may use exactly the same native rays and minimum opening as an ordinary catch.
policy_opening:
 link.w %a6,#-24
 movem.l %d3-%d7/%a0-%a5,-(%sp)
 moveq #0,%d1
 move.w 0xFFFFBEDC,%d1
 move.w #0x7FFF,%d2
 cmpi.w #8,%d1
 bhi.w policy_no
 bsr.w guard
 tst.w %d0
 bne.s policy_geometry
 jsr 0x225808
 tst.w %d0
 beq.w policy_no
 bra.s policy_geometry
 .endif
policy:
 link.w %a6,#-24
 movem.l %d3-%d7/%a0-%a5,-(%sp)
 moveq #0,%d1
 move.w 0xFFFFBEDC,%d1
 move.w #0x7FFF,%d2
 cmpi.w #8,%d1
 bhi.w policy_no
 bsr.w guard
 tst.w %d0
 beq.w policy_no
policy_geometry:
 move.w 0xFFFFB74A,-2(%a6)
 move.w 0xFFFFB75E,%d3
 btst #7,0x62(%a3)
 bne.s puck_depth
 neg.w %d3
puck_depth:
 move.w %d3,-4(%a6)
 cmpi.w #264,%d3
 bge.w behind_goal
 cmpi.w #88,%d3
 blt.w policy_yes                 | retain native clears outside attacking policy
 move.w #264,%d4
 sub.w %d3,%d4
 move.w %d4,-6(%a6)
 move.w %d1,%d3
 lsl.w #2,%d3
 lea 0xC542,%a0
 move.w 2(%a0,%d3.w),-16(%a6)      | keep the actual native chosen shot height
 lea 0xFFFFB04A,%a0
 cmpi.w #6,0x52(%a3)
 bcc.s keeper_base
 adda.w #768,%a0
keeper_base:
 moveq #5,%d7
keeper_scan:
 tst.w 0x34(%a0)
 bne.s keeper_next
 btst #2,0x63(%a0)
 bne.s keeper_next
 moveq #0,%d3
 move.b 0x28(%a0),%d3
 ext.w %d3
 asr.w #1,%d3
 add.w (%a0),%d3
 move.w %d3,-8(%a6)
 moveq #0,%d4
 move.b 0x2A(%a0),%d4
 ext.w %d4
 asr.w #1,%d4
 add.w 0x14(%a0),%d4
 btst #7,0x62(%a3)
 bne.s keeper_depth
 neg.w %d4
keeper_depth:
 sub.w -4(%a6),%d4
 ble.w policy_yes
 cmp.w -6(%a6),%d4
 bhi.w policy_yes
 move.w %d4,-10(%a6)
 bra.s evaluate
keeper_next:
 adda.w #128,%a0
 dbra %d7,keeper_scan
 bra.w policy_yes
evaluate:
 move.w %d1,%d3
 lsl.w #2,%d3
 lea 0xC542,%a0
 move.w (%a0,%d3.w),%d3
 bsr.w ray_gap
 move.w %d3,%d2                  | actual native target's current opening
 move.w %d2,%d6                  | best target, retaining native on ties
 move.w %d1,%d7
 moveq #-16,%d5
 moveq #1,%d4
post:
 move.w %d5,%d3
 bsr.w ray_gap
 cmpi.w #AIM_CLEAR,%d3
 blt.s post_next
 cmp.w %d6,%d3
 ble.s post_next
 move.w %d3,%d6
 moveq #3,%d7                    | right low native target
 tst.w %d5
 bpl.s post_height
 moveq #5,%d7                    | left low native target
post_height:
 cmpi.w #6,-16(%a6)
 bne.s post_high
 moveq #2,%d7
 tst.w %d5
 bpl.s post_next
 moveq #6,%d7
 bra.s post_next
post_high:
 cmpi.w #12,-16(%a6)
 bne.s post_next
 moveq #1,%d7
 tst.w %d5
 bpl.s post_next
 moveq #7,%d7
post_next:
 neg.w %d5
 dbra %d4,post
 move.w %d2,%d3
 addi.w #AIM_IMPROVE,%d3
 cmp.w %d3,%d6
 blt.s policy_yes
 move.w %d7,%d1
 move.w %d6,%d2
policy_yes:
 moveq #1,%d0
 bra.s policy_return
behind_goal:
 moveq #0,%d2
 bra.s policy_yes
policy_no:
 moveq #0,%d0
policy_return:
 movem.l (%sp)+,%d3-%d7/%a0-%a5
 unlk %a6
 rts

ray_gap:
 sub.w -2(%a6),%d3
 muls.w -10(%a6),%d3
 divs.w -6(%a6),%d3
 add.w -2(%a6),%d3
 sub.w -8(%a6),%d3
 bpl.s gap_return
 neg.w %d3
gap_return:
 rts
