    .ifndef WITH_REFINEMENTS
    .equ WITH_REFINEMENTS,0
    .endif
| Optional reach21 and native save/rebound alternatives. Off is the default.
| All four native gameplay entry contracts preserve registers, SR and stack.
| Only a real shot release records provenance. Only its first saved loose contact
| chooses a new outcome. Native keeper animation, stats, pickup and physics remain.
    .equ VALUE,0xFFFFF012
    .equ SHOT,0xFFFFF014
    .equ ACTOR,0xFFFFF016
    .equ DISTANCE,0xFFFFF018
    .equ TRAFFIC,0xFFFFF01A
    .equ EVENT,0xFFFFF01C
    .equ VARIANT,0xFFFFF01E
    .text
    .globl _start
_start:
    bra.w shot
    bra.w reach
    bra.w decision
    bra.w velocity
    bra.w load
    bra.w put
    bra.w reset
    bra.w policy
    bra.w filter_sog
    bra.w accepted_pickup

| Internal ordinary-play guard, D0=1/0; callers retain their whole ABI.
live:
    moveq #0,%d0
    tst.w 0xFFFFD412
    bne.s live_done
    move.b 0xFFFFC2EA,%d0
    andi.w #0x11,%d0
    bne.s live_no
    move.b 0xFFFFC2EC,%d0
    andi.w #0x81,%d0
    bne.s live_no
    move.b 0xFFFFC2FA,%d0
    andi.w #5,%d0
    bne.s live_no
    btst #2,0xFFFFC2F2
    bne.s live_no
    btst #3,0xFFFFC2F6
    bne.s live_no
    moveq #1,%d0
    rts
live_no:
    moveq #0,%d0
live_done:
    rts

shot:
    jsr 0x2FF300                    | original blue-line RNG/distance/CCR, always first
    move.w %sr,-(%sp)
    cmpi.w #1,VALUE
    beq.s shot_enabled
    move.w (%sp)+,%sr
    rts
shot_enabled:
    movem.l %d0-%d7/%a0-%a6,-(%sp)
    clr.w SHOT
    clr.l EVENT
    bsr.w live
    tst.w %d0
    beq.w shot_done
    tst.w 0x34(%a3)
    bmi.w shot_done
    move.w 0x52(%a3),%d0
    cmpi.w #11,%d0
    bhi.w shot_done
    move.w %d0,ACTOR
    move.w 0xFFFFF000,DISTANCE
    ble.w shot_done
    clr.w TRAFFIC
    move.w #264,%d6
    btst #7,0x62(%a3)
    bne.s shot_end
    neg.w %d6
shot_end:
    move.w 0x52(%a3),%d5
    lea 0xFFFFB04A,%a0
    moveq #11,%d7
screen:
    tst.w 0x34(%a0)
    ble.s next_screen
    cmp.w 0x52(%a0),%d5
    beq.s next_screen
    move.w (%a0),%d0
    cmpi.w #24,%d0
    bgt.s next_screen
    cmpi.w #-24,%d0
    blt.s next_screen
    move.w %d6,%d0
    sub.w 0x14(%a0),%d0
    tst.w %d6
    bpl.s screen_depth
    neg.w %d0
screen_depth:
    tst.w %d0
    bmi.s next_screen
    cmpi.w #48,%d0
    bgt.s next_screen
    cmpi.w #3,TRAFFIC
    bcc.s next_screen
    addq.w #1,TRAFFIC
next_screen:
    adda.w #128,%a0
    dbra %d7,screen
    move.w #0x4752,SHOT
shot_done:
    movem.l (%sp)+,%d0-%d7/%a0-%a6
    move.w (%sp)+,%sr
    rts

reach:
    move.w %sr,-(%sp)
    cmpi.w #1,VALUE
    beq.s reach_enabled
    move.w (%sp)+,%sr
    bra.w reach_height
reach_enabled:
    movem.l %d0-%d7/%a0-%a6,-(%sp)
    bsr.w live
    tst.w %d0
    beq.s reach_done
    tst.w 0x34(%a2)
    bne.s reach_done
    cmpi.w #11,0x52(%a2)
    bhi.s reach_done
    btst #1,0xFFFFC2F8             | retain the native special radius12 override
    bne.s reach_done
    move.w #21,0xFFFFBF64
    move.l #441,0xFFFFBF66
    move.w #-21,0xFFFFBF6A
reach_done:
    movem.l (%sp)+,%d0-%d7/%a0-%a6
    move.w (%sp)+,%sr
reach_height:
    cmpi.w #15,0xFFFFB762           | displaced native height limit and flags
    jmp 0x1503A

| Policy inputs: D0 roll0..99, D1 shot distance, D2 capped screen count.
| Outputs D0 category0catch,1corner,2short-rink,3long-rink,4slow-goal,5fast-goal.
| Experimental probabilities, never claimed as measured real-hockey frequencies.
policy:
    moveq #20,%d3                   | long shots:20catch/40corner/15short/10long/10slow/5fast
    cmpi.w #160,%d1
    bcc.s distance_ready
    moveq #10,%d3                   | close shots:10catch/40corner/15short/15long/15slow/5fast
 distance_ready:
    tst.w %d2
    beq.s catch_threshold
    subq.w #5,%d3                   | traffic transfers5catch and5corner points to slow leaks
 catch_threshold:
    cmp.w %d3,%d0
    bcs.s caught
    addi.w #40,%d3
    tst.w %d2
    beq.s corner_threshold
    subq.w #5,%d3
 corner_threshold:
    cmp.w %d3,%d0
    bcs.s corner
    addi.w #15,%d3
    cmp.w %d3,%d0
    bcs.s short_rink
    cmpi.w #160,%d1
    bcc.s long_distance
    addi.w #15,%d3
    bra.s long_threshold
 long_distance:
    addi.w #10,%d3
 long_threshold:
    cmp.w %d3,%d0
    bcs.s long_rink
    cmpi.w #95,%d0
    bcs.s slow_goal
    moveq #5,%d0
    rts
 caught: moveq #0,%d0
    rts
 corner: moveq #1,%d0
    rts
 short_rink: moveq #2,%d0
    rts
 long_rink: moveq #3,%d0
    rts
 slow_goal: moveq #4,%d0
    rts

decision:
    move.w %sr,-(%sp)
    cmpi.w #1,VALUE
    beq.s decision_enabled
    move.w (%sp)+,%sr
    bra.w native_compare
decision_enabled:
    movem.l %d0-%d7/%a0-%a6,-(%sp)
    clr.l EVENT
    bsr.w live
    tst.w %d0
    beq.w original_decision
    tst.w 0x34(%a2)
    bne.w original_decision
    tst.w 0xFFFFB7AA
    bpl.w original_decision
    cmpi.w #0x4752,SHOT
    bne.w original_decision
    move.w DISTANCE,%d0
    ble.w original_decision
    cmp.w 0xFFFFF000,%d0
    bne.w original_decision
    move.w ACTOR,%d0
    cmp.w 0xFFFFBED8,%d0
    bne.w original_decision
    cmp.w 0xFFFFBEDA,%d0            | a later pass or stick deflection is no longer this shot
    bne.w original_decision
    clr.w SHOT                     | consume the first eligible provenance, even for a slow native catch
    move.w 0xFFFFB772,%d1
    ext.l %d1
    bpl.s input_x
    neg.l %d1
input_x:
    move.w 0xFFFFB774,%d2
    ext.l %d2
    bpl.s input_y
    neg.l %d2
input_y:
    cmp.l %d2,%d1
    bcc.s input_max
    move.l %d2,%d1
input_max:
    cmpi.l #32766,%d1
    bls.s input_bounded
    move.l #32766,%d1
input_bounded:
    andi.w #0xFFFE,%d1
    cmpi.w #0x0800,%d1
    bcs.w original_decision         | very slow pucks keep the native catch/rebound decision
    move.w %d1,%d4                  | conservative speed cap; output L1 never exceeds input max
    move.w #100,%d0
    jsr 0x11086                    | bounded native draw, only after a real eligible save
    move.w DISTANCE,%d1
    move.w TRAFFIC,%d2
    bsr.w policy
    move.w %d0,EVENT
    beq.s chosen_catch
    move.w #0x474C,SHOT             | this untouched parry has already counted its SOG
    move.w ACTOR,%d1
    lsl.w #7,%d1
    lea 0xFFFFB04A,%a0
    adda.w %d1,%a0
    moveq #0,%d1
    move.b 0x66(%a0),%d1
    move.w %d1,TRAFFIC              | pending state retains the credited roster instead of screen count
    moveq #2,%d0
    jsr 0x11086
    or.w %d4,%d0
    move.w %d0,VARIANT              | even incoming speed cap, low bit is left/right variation
    movem.l (%sp)+,%d0-%d7/%a0-%a6
    move.w (%sp)+,%sr
    jmp 0x1555A                    | native detachment, cooldown, save phase and puck animation
chosen_catch:
    movem.l (%sp)+,%d0-%d7/%a0-%a6
    move.w (%sp)+,%sr
    jmp 0x15628                    | native catch, ownership and co-op keeper control
original_decision:
    movem.l (%sp)+,%d0-%d7/%a0-%a6
    move.w (%sp)+,%sr
native_compare:
    cmp.w 0xFFFFB772,%d0
    blt.w native_rebound
    jmp 0x15604
native_rebound:
    jmp 0x1555A

velocity:
    move.b %d0,0x28(%a3)            | both displaced native stores, including their flags
    move.b %d1,0x2A(%a3)
    move.w %sr,-(%sp)
    cmpi.w #1,VALUE
    beq.s velocity_enabled
    move.w (%sp)+,%sr
    rts
velocity_enabled:
    movem.l %d0-%d7/%a0-%a6,-(%sp)
    move.w EVENT,%d4
    clr.w EVENT
    subq.w #1,%d4
    cmpi.w #4,%d4
    bhi.w velocity_done
    bsr.w live
    tst.w %d0
    beq.w velocity_done
    move.w #1,%d5                   | defending net sign from actual keeper world position
    tst.w 0x14(%a2)
    bpl.s net_sign
    neg.w %d5
net_sign:
    moveq #1,%d6
    move.w VARIANT,%d3
    move.w %d3,%d2
    andi.w #0xFFFE,%d2
    cmpi.w #0x0800,%d2
    bcs.w velocity_done
    btst #0,%d3
    beq.s x_sign
    neg.w %d6
x_sign:
    tst.w %d4
    bne.s not_corner
    move.w #0x2000,%d0
    move.w #0x0800,%d1
    bra.s apply_vector
not_corner:
    cmpi.w #1,%d4
    bne.s not_short
    move.w #0x0800,%d0
    move.w #-0x1000,%d1
    bra.s apply_vector
not_short:
    cmpi.w #2,%d4
    bne.s not_long
    move.w #0x1400,%d0
    move.w #-0x2000,%d1
    bra.s apply_vector
not_long:
    cmpi.w #3,%d4
    bne.s fast_leak
    move.w #0x0100,%d0
    move.w #0x0C00,%d1
    cmpi.b #64,0x5E(%a2)
    bcc.s apply_vector
    move.b #64,0x5E(%a2)
    bra.s apply_vector
fast_leak:
    move.w #0x0200,%d0
    move.w #0x2000,%d1
    cmpi.b #24,0x5E(%a2)
    bcc.s apply_vector
    move.b #24,0x5E(%a2)
apply_vector:
    move.w %d1,%d3
    bpl.s desired_y
    neg.w %d3
desired_y:
    add.w %d0,%d3
    cmp.w %d3,%d2
    bcc.s signs
    mulu.w %d2,%d0
    divu.w %d3,%d0
    muls.w %d2,%d1
    divs.w %d3,%d1
signs:
    muls.w %d6,%d0
    muls.w %d5,%d1
    move.w %d0,0x28(%a3)
    move.w %d1,0x2A(%a3)
    clr.w 0x2C(%a3)
velocity_done:
    movem.l (%sp)+,%d0-%d7/%a0-%a6
    move.w (%sp)+,%sr
    rts

record:
    lea 0x209A65,%a0                | native / Full / Light / Mini, logical4D32..39
    tst.w 0xFFFFF06C
    beq.s record_done
    move.w 0xFFFFF06A,%d0
    subq.w #1,%d0
    cmpi.w #2,%d0
    bhi.s record_done
    addq.w #1,%d0
    lsl.w #2,%d0
    adda.w %d0,%a0
record_done:
    rts
load:
    move.w %sr,-(%sp)
    movem.l %d0-%d1/%a0,-(%sp)
    .if WITH_REFINEMENTS
    move.w #1,VALUE
    .else
    clr.w VALUE
    .endif
    clr.l SHOT
    clr.l DISTANCE
    clr.l EVENT
    bsr.s record
    moveq #0,%d0
    move.b (%a0),%d0
    move.w %d0,%d1
    andi.w #0xFE,%d1
    cmpi.w #0x72,%d1
    bne.s loaded
    not.b %d0
    cmp.b 2(%a0),%d0
    bne.s loaded
    not.b %d0
    andi.w #1,%d0
    move.w %d0,VALUE
loaded:
    movem.l (%sp)+,%d0-%d1/%a0
    move.w (%sp)+,%sr
    rts
put:
    move.w %sr,-(%sp)
    movem.l %d0-%d1/%a0,-(%sp)
    bsr.w record
    moveq #0x72,%d0
    cmpi.w #1,VALUE
    bne.s write
    addq.w #1,%d0
write:
    move.b %d0,(%a0)
    not.b %d0
    move.b %d0,2(%a0)
    lea 0x208001,%a0
    moveq #0,%d0
    move.w #0x1FFD,%d1
sum:
    add.b (%a0),%d0
    addq.l #2,%a0
    dbra %d1,sum
    not.b %d0
    move.b %d0,(%a0)
    not.b %d0
    move.b %d0,2(%a0)
    movem.l (%sp)+,%d0-%d1/%a0
    move.w (%sp)+,%sr
    rts
reset:
    move.w 0xFFFFF06C,-(%sp)
    move.w #1,0xFFFFF06C
    .if WITH_REFINEMENTS
    move.w #1,VALUE
    .else
    clr.w VALUE
    .endif
    clr.l SHOT
    clr.l DISTANCE
    clr.l EVENT
    bsr.w put
    move.w (%sp)+,0xFFFFF06C
    rts


| Existing shootout.s normal-shot dispatch. A model parry already counted SOG.
| The same untouched puck entering that same club's goal must not add another.
| New releases, pickups, changed last touch, changed scorer and other clubs keep
| the complete native path. Goal/assist/GA bookkeeping is already native1496A.
filter_sog:
    move.w %sr,-(%sp)
    cmpi.w #1,VALUE
    beq.s filter_enabled
    move.w (%sp)+,%sr
    bra.w native_sog
filter_enabled:
    movem.l %d0-%d7/%a0-%a6,-(%sp)
    cmpi.w #0x474C,SHOT
    bne.w filter_original
    btst #0,0xFFFFC2F4
    beq.w filter_original
    bsr.w live
    tst.w %d0
    beq.w filter_original
    move.w DISTANCE,%d0
    ble.w filter_original
    tst.w 0xFFFFF000              | native body contact can clear distance without possession
    beq.s filter_distance
    cmp.w 0xFFFFF000,%d0
    bne.w filter_original
filter_distance:
    move.w ACTOR,%d0
    cmpi.w #11,%d0
    bhi.w filter_original
    cmp.w 0xFFFFBED8,%d0
    bne.w filter_original
    cmp.w 0xFFFFBEDA,%d0
    bne.w filter_original
    lsl.w #7,%d0
    lea 0xFFFFB04A,%a0
    adda.w %d0,%a0
    movea.w #0xC6CE,%a1
    btst #6,0x62(%a0)
    beq.s filter_side
    adda.w #0x364,%a1
filter_side:
    cmpa.l %a1,%a2
    bne.s filter_original
    move.w TRAFFIC,%d0
    cmpi.w #25,%d0
    bhi.s filter_original
    cmp.w 0x18(%a2),%d0
    bne.s filter_original
    clr.w SHOT
    bclr #4,0xFFFFC2EE
    bclr #3,0xFFFFC2FE               | native completed goal-SOG gate, without duplicate increments
    movem.l (%sp)+,%d0-%d7/%a0-%a6
    move.w (%sp)+,%sr
    rts
filter_original:
    movem.l (%sp)+,%d0-%d7/%a0-%a6
    move.w (%sp)+,%sr
native_sog:
    btst #0,0xFFFFC2EA             | exact original normal-shot dispatch
    beq.s live_sog
    jmp 0x15464
live_sog:
    jmp 0x12F3A

| Universal native accepted possession entry. Body contacts do not reach here.
| Replay both displaced ownership instructions first, retaining exact native CCR.
accepted_pickup:
    move.w 0x52(%a2),%d0
    move.w %d0,0xFFFFB7AA
    move.w %sr,-(%sp)
    cmpi.w #1,VALUE
    bne.s pickup_done
    clr.w SHOT
pickup_done:
    move.w (%sp)+,%sr
    rts
