| Hard attack: puck-relative forward support, select a free improved receiver,
| and defer bad-angle shots when such a receiver exists. Native pass/shot physics.
    .ifndef WITH_AI_PLAYBOOK
    .equ WITH_AI_PLAYBOOK,1
    .endif
    .text
    .globl _start
_start:
    bra.w support
    bra.w passpick
    bra.w shotgate

| Common live CPU skater guard. Returns D0=1 eligible, 0 otherwise.
| No persistent RAM; inputs/registers besides D0 preserved.
guard:
    moveq #0,%d0
    cmpi.w #1,0xFFFFF07A
    bne.s guard_done
    btst #3,0x62(%a3)
    bne.s guard_done
    btst #5,0x62(%a3)
    bne.s guard_done
    btst #2,0x63(%a3)
    bne.s guard_done
    btst #0,0xFFFFC2EA
    bne.s guard_done
    btst #7,0xFFFFC2EC
    bne.s guard_done
    btst #2,0xFFFFC2F2
    bne.s guard_done
    btst #0,0xFFFFC2FA
    bne.s guard_done
    btst #7,0xFFFFC2EE            | native offside signal
    bne.s guard_done
    tst.w 0x34(%a3)
    ble.s guard_done
    moveq #1,%d0
guard_done:
    rts

support:
    lea 0xE594,%a0               | displaced EvadePC callback
    movem.l %d0/%d2-%d7/%a1-%a2,-(%sp)
    bsr.w guard
    tst.w %d0
    beq.w support_native
    .if WITH_PASS_CONTINUITY
    bsr.w flight_owner
    .else
    move.w 0xFFFFB7AA,%d2
    .endif
    cmpi.w #11,%d2
    bhi.w support_native
    cmp.w 0x52(%a3),%d2
    beq.w support_native
    move.w 0x52(%a3),%d3
    subi.w #6,%d2
    subi.w #6,%d3
    eor.w %d3,%d2
    bmi.w support_native
    cmpi.w #3,0x34(%a3)
    blt.w support_native
    cmpi.w #5,0x34(%a3)
    bgt.w support_native
    move.w 0xFFFFB75E,%d3
    btst #7,0x62(%a3)
    bne.s support_depth
    neg.w %d3
support_depth:
    cmpi.w #112,%d3
    blt.w support_native
    cmpi.w #292,%d3
    bgt.w support_native
    move.w 0xFFFFB74A,%d4
    cmpi.w #4,0x34(%a3)
    beq.s center
    moveq #1,%d5                 | wing side in world X, from native target
    move.l (%sp),%d2
    tst.w %d2
    bpl.s wing_side
    moveq #-1,%d5
wing_side:
    move.w %d4,%d2
    muls.w %d5,%d2
    cmpi.w #32,%d2
    bgt.s strong_wing
    moveq #44,%d6                | far-side finisher
    addi.w #24,%d3
    move.w #184,%d2
    move.w #236,%d7
    bra.s wing_xy
strong_wing:
    moveq #90,%d6                | same-side return outlet, behind the carrier
    subi.w #40,%d3
    move.w #128,%d2
    move.w #198,%d7
wing_xy:
    muls.w %d5,%d6
    bra.s clamp_depth
center:
    moveq #16,%d6
    tst.w %d4
    bmi.s center_depth
    neg.w %d6
center_depth:
    subi.w #12,%d3
    move.w #172,%d2
    move.w #218,%d7
clamp_depth:
    cmp.w %d2,%d3
    bge.s max_depth
    move.w %d2,%d3
max_depth:
    cmp.w %d7,%d3
    ble.s occupancy
    move.w %d7,%d3
occupancy:
    lea 0xFFFFB04A,%a1
    cmpi.w #6,0x52(%a3)
    bcc.s opp_ready
    adda.w #768,%a1
opp_ready:
    .if WITH_REAL_ACTORS
    moveq #5,%d7
    .else
    moveq #4,%d7
    .endif
occupant:
    tst.w 0x34(%a1)
    ble.s next_occupant
    btst #2,0x63(%a1)
    bne.s next_occupant
    move.w (%a1),%d2
    sub.w %d6,%d2
    cmpi.w #-28,%d2
    blt.s next_occupant
    cmpi.w #28,%d2
    bgt.s next_occupant
    move.w 0x14(%a1),%d2
    btst #7,0x62(%a3)
    bne.s occupant_depth
    neg.w %d2
occupant_depth:
    sub.w %d3,%d2
    cmpi.w #-28,%d2
    blt.s next_occupant
    cmpi.w #28,%d2
    bgt.s next_occupant
    subi.w #28,%d3                | drop into a return lane rather than stand marked
    cmpi.w #4,0x34(%a3)
    beq.s support_apply
    moveq #24,%d2
    muls.w %d5,%d2
    add.w %d2,%d6
    bra.s support_apply
next_occupant:
    adda.w #128,%a1
    dbra %d7,occupant
support_apply:
    move.w %d6,%d0
    move.w %d3,%d1
    btst #7,0x62(%a3)
    bne.s support_store
    neg.w %d1
support_store:
    move.l %d0,(%sp)              | return adjusted D0 through saved slot
support_native:
    movem.l (%sp)+,%d0/%d2-%d7/%a1-%a2
    jmp 0x103C8

| Returns relative teammate slot in D0 or -1. Other registers preserved.
| Local stack contains geometry, score and best index; scan only five skaters.
findreceiver:
    link.w %a6,#-32
    movem.l %d1-%d7/%a0-%a5,-(%sp)
    move.w #-1,-8(%a6)
    bsr.w guard
    tst.w %d0
    beq.w find_done
    btst #1,0x64(%a3)              | keep native breakaway decisions
    bne.w find_done
    move.w 0x52(%a3),%d0
    cmp.w 0xFFFFB7AA,%d0
    bne.w find_done
    move.w 0xFFFFB75E,%d1
    btst #7,0x62(%a3)
    bne.s find_depth
    neg.w %d1
find_depth:
    .if WITH_AI_PLAYBOOK
    cmpi.w #88,%d1
    .else
    cmpi.w #112,%d1
    .endif
    blt.w find_done
    cmpi.w #292,%d1
    bgt.w find_done
    move.w %d1,-2(%a6)
    move.w 0xFFFFB74A,%d2
    bpl.s carrier_abs
    neg.w %d2
carrier_abs:
    add.w %d2,%d2
    subi.w #224,%d1
    bpl.s carrier_cost
    neg.w %d1
carrier_cost:
    add.w %d1,%d2
    move.w %d2,-4(%a6)
    move.w #0x7FFF,-6(%a6)
    lea 0xFFFFB04A,%a4
    lea 0xFFFFB34A,%a5
    cmpi.w #6,0x52(%a3)
    bcs.s own_ready
    exg %a4,%a5
own_ready:
    movea.l %a4,%a0
    .if WITH_REAL_ACTORS
    moveq #5,%d6
    .else
    moveq #4,%d6
    .endif
candidate:
    cmpa.l %a3,%a0
    beq.w next_candidate
    tst.w 0x34(%a0)
    ble.w next_candidate
    btst #2,0x63(%a0)
    bne.w next_candidate
    btst #5,0x62(%a0)
    bne.w next_candidate
    move.w 0x14(%a0),%d1
    btst #7,0x62(%a3)
    bne.s receiver_depth
    neg.w %d1
receiver_depth:
    cmpi.w #112,%d1
    blt.w next_candidate
    cmpi.w #252,%d1
    bgt.w next_candidate
    move.w (%a0),%d2
    bpl.s receiver_abs
    neg.w %d2
receiver_abs:
    cmpi.w #140,%d2
    bgt.w next_candidate
    add.w %d2,%d2
    subi.w #224,%d1
    bpl.s receiver_cost
    neg.w %d1
receiver_cost:
    add.w %d1,%d2
    move.w %d2,-20(%a6)
    addi.w #24,%d2
    cmp.w -4(%a6),%d2
    bgt.w next_candidate
    move.w (%a0),%d1
    sub.w 0xFFFFB74A,%d1
    move.w %d1,-10(%a6)
    bpl.s abs_dx
    neg.w %d1
abs_dx:
    move.w 0x14(%a0),%d2
    sub.w 0xFFFFB75E,%d2
    move.w %d2,-12(%a6)
    bpl.s abs_dy
    neg.w %d2
abs_dy:
    add.w %d1,%d2
    cmpi.w #32,%d2
    blt.w next_candidate
    cmpi.w #200,%d2
    bgt.w next_candidate
    move.w %d2,%d3
    lsr.w #2,%d3
    add.w %d3,-20(%a6)
    move.w -20(%a6),%d3
    cmp.w -6(%a6),%d3
    bge.w next_candidate
    mulu.w #12,%d2
    move.w %d2,-18(%a6)
    move.w -10(%a6),%d1
    muls.w %d1,%d1
    move.w -12(%a6),%d2
    muls.w %d2,%d2
    add.l %d1,%d2
    move.l %d2,-16(%a6)
    movea.l %a5,%a1
    moveq #5,%d7
opponent:
    tst.w 0x34(%a1)
    bmi.w next_opponent
    btst #2,0x63(%a1)
    bne.w next_opponent
    move.w (%a1),%d1
    sub.w (%a0),%d1
    muls.w %d1,%d1
    move.w 0x14(%a1),%d2
    sub.w 0x14(%a0),%d2
    muls.w %d2,%d2
    add.l %d1,%d2
    cmpi.l #676,%d2
    blt.w next_candidate           | marked receiver
    move.w (%a1),%d1
    sub.w 0xFFFFB74A,%d1
    move.w 0x14(%a1),%d2
    sub.w 0xFFFFB75E,%d2
    move.w %d1,%d3
    muls.w -10(%a6),%d3
    move.w %d2,%d4
    muls.w -12(%a6),%d4
    add.l %d4,%d3                 | projection along the pass segment
    ble.s next_opponent
    cmp.l -16(%a6),%d3
    bge.s next_opponent
    muls.w -12(%a6),%d1
    muls.w -10(%a6),%d2
    sub.l %d2,%d1
    bpl.s cross_abs
    neg.l %d1
cross_abs:
    moveq #0,%d2
    move.w -18(%a6),%d2
    cmp.l %d2,%d1
    ble.w next_candidate         | opponent in a conservative pass corridor
next_opponent:
    adda.w #128,%a1
    dbra %d7,opponent
    move.w -20(%a6),-6(%a6)
    move.w 0x52(%a0),%d1
    cmpi.w #6,%d1
    bcs.s store_receiver
    subq.w #6,%d1
store_receiver:
    move.w %d1,-8(%a6)
next_candidate:
    adda.w #128,%a0
    dbra %d6,candidate
find_done:
    moveq #-1,%d0
    move.w -8(%a6),%d0
    movem.l (%sp)+,%d1-%d7/%a0-%a5
    unlk %a6
    rts

passpick:
    bsr.w findreceiver
    tst.w %d0
    bpl.s pass_return
    moveq #6,%d0
    jmp 0x11086                  | displaced native random teammate choice
pass_return:
    rts

shotgate:
    movem.l %d0-%d2,-(%sp)
    .if WITH_AI_PLAYBOOK
    jsr 0x2DD004
    tst.w %d0
    beq.s regular_shotgate
    movem.l (%sp)+,%d0-%d2
    jmp 0xE412                   | native shot assignment and stack unwind
regular_shotgate:
    .endif
    move.w 0xFFFFB74A,%d0
    bpl.s shot_abs
    neg.w %d0
shot_abs:
    cmpi.w #88,%d0
    ble.s native_shot
    move.w 0xFFFFB75E,%d1
    btst #7,0x62(%a3)
    bne.s shot_depth
    neg.w %d1
shot_depth:
    cmpi.w #152,%d1
    blt.s native_shot
    cmpi.w #264,%d1
    bge.s native_shot
    bsr.w findreceiver
    tst.w %d0
    bmi.s native_shot
    movem.l (%sp)+,%d0-%d2
    rts                          | bad-angle shot deferred: caller considers pass/skates
native_shot:
    movem.l (%sp)+,%d0-%d2
    jsr 0xE264                   | displaced chkpk / BNE .pkill
    bne.s native_pk
    jmp 0xE298
native_pk:
    jmp 0xE2E4

    .if WITH_PASS_CONTINUITY
flight_owner:
    jsr 0x2DD680
    rts
    .endif
