    .ifndef WITH_MANUAL_KEEPER_PASS
    .equ WITH_MANUAL_KEEPER_PASS,1
    .endif
| B changes to another eligible skater on press; Y remains explicit goalie selection.
| Input D1=new presses, D3=held buttons, D4=pad offset 0/2, A3=old object.
    .equ Q,0xFFFFF048                    | words at +pad: pending switch countdown (30 calls)
    .equ QOBJ,0xFFFFF04C                 | object that requested the switch
    .equ HELD,0xFFFFF050                 | consume B until physical release after a successful switch
    .equ MAGIC,0xFFFFF054
    .text
    .globl _start
_start:
    bra.w early
    bra.w legacy
eligible:
    tst.w 0xFFFFD046                    | native multitap behavior retained
    bne.s no
    cmpi.w #2,%d4
    bhi.s no
    btst #0,0xFFFFC2FA                  | shootout
    bne.s no
    tst.w 0xFFFFD412                    | penalty-shot state
    bne.s no
    btst #2,0xFFFFC2F2                  | whistle/faceoff state
    bne.s no
    btst #3,0x62(%a3)                 | only a human-controlled object
    beq.s no
    btst #0,0x63(%a3)                 | fighting
    bne.s no
    moveq #0,%d0
    rts
no: moveq #-1,%d0
    rts
early:
    movem.l %d0-%d7/%a0-%a6,-(%sp)
    cmpi.w #0x5357,MAGIC
    beq.s initialized
    move.w #0x5357,MAGIC
    clr.l Q
    clr.l HELD
initialized:
    bsr.s eligible
    tst.w %d0
    bne.w reset_original
    lea 0xFFFFF0E0,%a0                 | explicit Y wins over B and clears an old switch latch
    tst.b (%a0,%d4.w)
    bne.w reset_original
    jsr 0x2FDC0C                       | possession can change while an earlier switch consumed B
    tst.w %d0
    beq.s check_consumed
    .if WITH_IMMEDIATE_B
    cmpi.w #2,%d0
    beq.w fresh_switch
    .endif
    lea Q,%a0
    clr.w (%a0,%d4.w)
    move.w #1,8(%a0,%d4.w)            | consume this press/hold/release; keep the requesting skater
    bra.w consume
check_consumed:
    lea HELD,%a0
    tst.w (%a0,%d4.w)
    beq.s ordinary_switch
    btst #4,%d3
    bne.w consume
    clr.w (%a0,%d4.w)
    bra.w consume
    .if WITH_IMMEDIATE_B
fresh_switch:
    move.w 0x52(%a3),%d0
    cmp.w 0xFFFFB7AA,%d0
    .if WITH_MANUAL_KEEPER_PASS
    beq.w reset_original            | owned manual keeper B is a native pass, like an owned skater
    .else
    bne.s fresh_without_puck
    tst.w 0x34(%a3)
    bne.w reset_original
    .endif
fresh_without_puck:
    lea Q,%a2
    move.w #1,(%a2,%d4.w)
    move.w %d0,4(%a2,%d4.w)
    bra.w choose_nearest
    .endif
ordinary_switch:
    jsr 0x2E1008                     | jdc r22: a pass from your own goalie on its way (onetimer.s +8,
    beq.w consume                    | clears Q): B does not switch skaters (spammed B jumped the cursor)
    move.w 0x52(%a3),%d0
    cmp.w 0xFFFFB7AA,%d0
    beq.w reset_original             | current puck carrier: native passing
    lea Q,%a2
    btst #4,%d1
    beq.s pending
    move.w #30,(%a2,%d4.w)
    move.w %d0,4(%a2,%d4.w)
pending:
    tst.w (%a2,%d4.w)
    beq.w original
    cmp.w 4(%a2,%d4.w),%d0
    bne.w reset_original             | automatic selection already changed the controlled object
    subq.w #1,(%a2,%d4.w)
    btst #3,0x63(%a3)                | finish an in-progress pass before assigning another player
    bne.w original
choose_nearest:
    .if WITH_IMMEDIATE_B
    move.w 0xFFFFB74A,%d2
    move.w 0xFFFFB75E,%d3
    .else
    move.w 0xFFFFB772,%d2
    asr.w #8,%d2
    add.w 0xFFFFB74A,%d2
    move.w 0xFFFFB774,%d3
    asr.w #8,%d3
    add.w 0xFFFFB75E,%d3
    .endif
    lea 0xFFFFB04A,%a0
    lea 0xFFFFC328,%a1
    cmpi.w #1,(%a1,%d4.w)
    beq.s team_ready
    cmpi.w #2,(%a1,%d4.w)
    bne.w reset_original
    adda.w #0x300,%a0
team_ready:
    moveq #-1,%d5                    | best object
    moveq #-1,%d6                    | best squared distance
    moveq #5,%d7
candidate:
    tst.w 0x34(%a0)
    ble.s next                       | goalie/injured/unavailable slot
    move.w 0x52(%a0),%d0
    cmp.w 4(%a2,%d4.w),%d0
    beq.s next                       | actually change player, rather than selecting the same one
    btst #2,0x63(%a0)
    bne.s next
    btst #3,0x62(%a0)
    bne.s next                       | never take the other human's player
    btst #5,0x62(%a0)
    bne.s next                       | unavailable action/knockdown
    move.w %d2,%d0
    sub.w (%a0),%d0
    muls.w %d0,%d0
    move.w %d3,%d1
    sub.w 0x14(%a0),%d1
    muls.w %d1,%d1
    add.l %d1,%d0
    cmp.l %d6,%d0
    bhi.s next
    move.l %d0,%d6
    move.w 0x52(%a0),%d5
next:
    adda.w #0x80,%a0
    dbra %d7,candidate
    tst.w %d5
    .if WITH_IMMEDIATE_B
    bmi.w original
    .else
    bmi.s original
    .endif
    .if WITH_IMMEDIATE_B
    move.w %sr,-(%sp)
    ori.w #0x700,%sr
    move.b 0x63(%a3),-(%sp)
    bclr #3,0x63(%a3)                 | Native assignment otherwise refuses the released pass animation
    .endif
    move.w %d5,%d0
    tst.w %d4
    bne.s assign_p2
    jsr 0xC0BC
    bra.s assigned
assign_p2:
    jsr 0xC0DA
assigned:
    .if WITH_IMMEDIATE_B
    move.b (%sp)+,0x63(%a3)           | preserve the actual in-flight pass/animation state
    move.w (%sp)+,%sr
    | A brief B tap must also publish the outlet for the newly selected skater.
    | Use the original physical press, even if the hold ends before its next tick.
    move.l 4(%sp),%d1
    move.l 12(%sp),%d3
    bclr #4,%d1
    ori.w #16,%d3
    move.l %a3,-(%sp)
    move.w %d5,%d0
    lsl.w #7,%d0
    lea 0xFFFFB04A,%a3
    adda.w %d0,%a3
    jsr 0x2FDC0C
    movea.l (%sp)+,%a3
    .endif
    lea Q,%a2
    clr.w (%a2,%d4.w)
    move.w #1,8(%a2,%d4.w)
    movem.l (%sp)+,%d0-%d7/%a0-%a6
    rts                              | the old object's input handler ends after selection
consume:
    movem.l (%sp)+,%d0-%d7/%a0-%a6
    bclr #4,%d1
    bclr #4,%d2
    bclr #4,%d3
    bra.s original_flags
reset_original:
    cmpi.w #2,%d4
    bhi.s original
    lea Q,%a0
    clr.w (%a0,%d4.w)
    clr.w 8(%a0,%d4.w)
original:
    movem.l (%sp)+,%d0-%d7/%a0-%a6
original_flags:
    btst #3,0x63(%a3)                 | replaced pass-lock check at B1B6
    bne.s original_pass
    jmp 0xB1C0
original_pass:
    jmp 0xBA88
legacy:
    move.l %d0,-(%sp)
    bsr.w eligible
    tst.w %d0
    movem.l (%sp)+,%d0
    bne.s original_b
    jmp 0xB42E                       | native delayed/release B switch and B-hold goalie disabled
original_b:
    btst #4,%d3
    beq.s released
    jmp 0xB2E2
released:
    jmp 0xB35C
