experimental/fourgoalie.s

Download file

Release 2026-11-04-r2 · SHA256 b41b0a23dc743a45f6f9a6303289f982241ecbd110b7d1cb6cfb2ca0c275c79c · Click a line number for a direct link.

1    .ifndef WITH_MANUAL_KEEPER_PASS2    .equ WITH_MANUAL_KEEPER_PASS,13    .endif4| 4-Way Play goalie hold/request/Y, preserving native P3/P4 input-bank swaps.5| +0 early B, +4 legacy B, +8 Y reader, +12 Y handler, +16 cooperative sides,6| +20 new-game reset. Native D4 is always0/2; C318>=0 identifies P3/P4.7    .equ YREQ,0xFFF0B2              | four bytes at even offsets0/2/4/68    .equ YHELD,0xFFF0BA             | four held-Y states, same offsets9    .equ BHELD,0xFFF0C2             | four words: consume B until released10    .equ MAGIC,0xFFF0CA11    .equ ASK,0xFFF06412    .equ OBJ,0xFFFFB04A13    .text14    .globl _start15_start:16    bra.w early17    bra.w legacy18    bra.w reader19    bra.w handler20    bra.w cooperative21    bra.w reset22reset:23    clr.w MAGIC24    clr.l ASK25    rts26init:27    cmpi.w #0x3447,MAGIC28    beq.s 9f29    clr.l YREQ30    clr.l YREQ+431    clr.l YHELD32    clr.l YHELD+433    clr.l BHELD34    clr.l BHELD+435    move.w #0x3447,MAGIC369:  rts3738| Z only when at least one human is present and every active pad is on one side.39| Opposing human teams retain the native adapter behaviour. Registers preserved.40cooperative:41    movem.l %d0-%d2/%a0,-(%sp)42    lea 0xFFFFC328,%a043    moveq #0,%d044    moveq #3,%d2451:  move.w (%a0)+,%d146    beq.s 3f47    cmpi.w #2,%d148    bhi.s 8f49    tst.w %d050    beq.s 2f51    cmp.w %d0,%d152    bne.s 8f532:  move.w %d1,%d0543:  dbra %d2,1b55    tst.w %d056    beq.s 8f57    moveq #0,%d058    bra.s 9f598:  moveq #-1,%d0609:  movem.l (%sp)+,%d0-%d2/%a061    rts6263allowed:64    bsr.s cooperative65    .if WITH_IMMEDIATE_B66    bne.s b_noncooperative67    .else68    bne.s 8f69    .endif70allowed_states:71    btst #0,0xFFFFC2FA72    bne.s 8f73    tst.w 0xFFFFD41274    bne.s 8f75    btst #2,0xFFFFC2F276    bne.s 8f77    btst #3,0x62(%a3)78    beq.s 8f79    btst #0,0x63(%a3)80    bne.s 8f81    moveq #0,%d082    rts838:  moveq #-1,%d084    rts85    .if WITH_IMMEDIATE_B86b_noncooperative:87    btst #4,%d188    beq.s 8b89    bra.w allowed_states90    .endif91realpad:                             | input handler bank -> physical offset, D0 only92    move.w %d4,%d093    tst.w 0xFFFFC31894    bmi.s 9f95    addq.w #4,%d0969:  rts97early:98    tst.w 0xFFFFD04699    beq.w oldearly100    movem.l %d0-%d7/%a0-%a6,-(%sp)101    bsr.w init102    bsr.s allowed103    bne.w native_early104    bsr.s realpad105    move.w %d0,%d4106    lea YREQ,%a0107    tst.b (%a0,%d4.w)108    bne.w native_early              | explicit Y wins; its reader did not synthesize B109    jsr 0x2FDC0C110    tst.w %d0111    beq.w 1f112    .if WITH_IMMEDIATE_B113    cmpi.w #2,%d0114    beq.w fast115    .endif116    lea BHELD,%a0117    move.w #1,(%a0,%d4.w)118    bra.w consume1191:  lea BHELD,%a0120    tst.w (%a0,%d4.w)121    beq.s flight122    btst #4,%d3123    bne.w consume124    clr.w (%a0,%d4.w)125    bra.w consume126flight:                              | do not switch while a pass from your goalie is travelling127    tst.w 0xFFFFB7AA128    bpl.s fast129    move.w 0xFFFFBEDA,%d0130    cmpi.w #5,%d0131    beq.w 2f132    cmpi.w #11,%d0133    bne.s fast1342:  lsl.w #7,%d0135    lea OBJ,%a0136    move.b 0x62(%a0,%d0.w),%d0137    move.b 0x62(%a3),%d2138    eor.b %d2,%d0139    btst #6,%d0140    bne.s fast141    bra.w consume142| fast (2026-10-26-r22, jdc): with the adapter there was no B switch at all for co-op pads143| (the native held-B switch is off so that Y takes the keeper). A new B press, when this144| pad's player is not the puck carrier and no pass is in progress, selects the free skater145| of the pad's side nearest the puck (no goalie, no other human's player, not knocked146| down), also from a human goalie. D4 = physical pad 0..6 here; native assignment C0BC /147| C0DA keeps the bank's 0/2 (P3/P4 run in a swapped P1/P2 bank, copied back by the game).148fast:149    btst #4,%d1150    beq.w native_early151    move.w 0x52(%a3),%d0152    cmp.w 0xFFFFB7AA,%d0153    .if WITH_IMMEDIATE_B154    .if WITH_MANUAL_KEEPER_PASS155    beq.w native_early              | owning manual keeper must reach native B72E/BC06 passing156    .else157    bne.s fast_without_possession158    tst.w 0x34(%a3)159    bne.w native_early160    .endif161fast_without_possession:162    .else163    beq.w native_early164    btst #3,0x63(%a3)165    bne.w native_early166    .endif167    move.w %d4,%d7                   | physical pad168    andi.w #2,%d7                    | the bank's own offset169    .if WITH_IMMEDIATE_B170    move.w 0xFFFFB74A,%d2171    move.w 0xFFFFB75E,%d3172    .else173    move.w 0xFFFFB772,%d2            | puck, a few frames ahead (as switch.s)174    asr.w #8,%d2175    add.w 0xFFFFB74A,%d2176    move.w 0xFFFFB774,%d3177    asr.w #8,%d3178    add.w 0xFFFFB75E,%d3179    .endif180    lea OBJ,%a0181    lea 0xFFFFC328,%a1182    cmpi.w #1,(%a1,%d7.w)183    beq.s 3f184    cmpi.w #2,(%a1,%d7.w)185    bne.w native_early186    adda.w #0x300,%a01873:  moveq #-1,%d5                    | best object188    moveq #-1,%d6                    | best squared distance189    swap %d7190    move.w #5,%d71914:  tst.w 0x34(%a0)192    ble.s 5f                         | goalie / injured / unavailable slot193    move.w 0x52(%a0),%d0194    cmp.w 0x52(%a3),%d0195    beq.s 5f                         | another player, not the same one196    btst #2,0x63(%a0)197    bne.s 5f198    btst #3,0x62(%a0)199    bne.s 5f                         | never another human's player200    btst #5,0x62(%a0)201    bne.s 5f                         | knocked down / unavailable202    move.w %d2,%d0203    sub.w (%a0),%d0204    muls.w %d0,%d0205    move.w %d3,%d1206    sub.w 0x14(%a0),%d1207    muls.w %d1,%d1208    add.l %d1,%d0209    cmp.l %d6,%d0210    bhi.s 5f211    move.l %d0,%d6212    move.w 0x52(%a0),%d52135:  adda.w #0x80,%a0214    dbra %d7,4b215    swap %d7216    tst.w %d5217    bmi.w native_early               | nobody free: as before218    .if WITH_IMMEDIATE_B219    move.w %sr,-(%sp)220    ori.w #0x700,%sr221    move.b 0x63(%a3),-(%sp)222    bclr #3,0x63(%a3)                 | Native assignment otherwise refuses the released pass animation223    .endif224    move.w %d5,%d0225    tst.w %d7226    bne.s 6f227    jsr 0xC0BC228    bra.s 7f2296:  jsr 0xC0DA2307:231    .if WITH_IMMEDIATE_B232    move.b (%sp)+,0x63(%a3)           | preserve the actual in-flight pass/animation state233    move.w (%sp)+,%sr234    | A brief B tap must also publish the outlet for the newly selected skater.235    | Use the original physical press, even if the hold ends before its next tick.236    move.l 4(%sp),%d1237    move.l 12(%sp),%d3238    bclr #4,%d1239    ori.w #16,%d3240    move.l %a3,-(%sp)241    move.w %d5,%d0242    lsl.w #7,%d0243    lea 0xFFFFB04A,%a3244    adda.w %d0,%a3245    jsr 0x2FDC0C246    movea.l (%sp)+,%a3247    .endif248    lea BHELD,%a0                    | consume this press until B is released249    move.w #1,(%a0,%d4.w)250    movem.l (%sp)+,%d0-%d7/%a0-%a6251    rts                              | the old object's input handler ends after selection252consume:253    movem.l (%sp)+,%d0-%d7/%a0-%a6254    bclr #4,%d1255    bclr #4,%d2256    bclr #4,%d3257    bra.s original_flags258native_early:259    movem.l (%sp)+,%d0-%d7/%a0-%a6260original_flags:261    btst #3,0x63(%a3)262    bne.s 1f263    jmp 0xB1C02641:  jmp 0xBA88265oldearly:266    .if WITH_IMMEDIATE_B267    jmp 0x2DB000268    .else269    jmp 0x2FD900                     | original two-pad fast-switch code and RAM stay intact270    .endif271legacy:272    tst.w 0xFFFFD046273    beq.s 9f274    move.l %d0,-(%sp)275    bsr.w allowed276    tst.w %d0277    movem.l (%sp)+,%d0278    bne.s original_b279    jmp 0xB42E                       | co-op adapter: Y, not a held B, explicitly takes the keeper280original_b:281    btst #4,%d3282    beq.s 1f283    jmp 0xB2E22841:  jmp 0xB35C2859:286    .if WITH_IMMEDIATE_B287    jmp 0x2DB004288    .else289    jmp 0x2FD904290    .endif291292reader:293    tst.w 0xFFFFD046294    beq.w oldreader295    .if WITH_QUICKGAME296    tst.w 0xFFFFF84C297    bne.s quick_reader298    .endif299    bsr.w cooperative300    bne.w oldreader301    .if WITH_QUICKGAME302quick_reader:303    .endif304    movem.l %d3/%a1,-(%sp)305    bsr.w init306    moveq #0,%d0307    move.b 0xFFFFBF06,%d0          | hardware reader's bits7:6 select virtual pad0..3308    lsr.w #6,%d0309    add.w %d0,%d0310    bsr.w latch_b                   | keep a brief hardware B request even between skater input updates311    lea YREQ,%a1312    btst #1,%d2313    bne.w yrelease314    tst.b 8(%a1,%d0.w)315    bmi.w yreturn316    bne.w yasb317    btst #0,0xFFFFC2FA             | native shootout/penalty-shot controls remain untouched318    bne.w yasb319    tst.w 0xFFFFD412320    bne.w yasb321    lea 0xFFFFC328,%a1322    move.w (%a1,%d0.w),%d3323    beq.w yasb324    cmpi.w #2,%d3325    bhi.w yasb326    subq.w #1,%d3327    add.w %d3,%d3328    lea 0xFFFFD05A,%a1329    tst.w (%a1,%d3.w)              | goalie control is per side, not per physical pad330    bne.w yasb331    lea 0xFFFFC320,%a1332    move.w (%a1,%d0.w),%d3333    bmi.w yasb334    cmpi.w #11,%d3335    bhi.w yasb336    move.w 0xFFFFB7AA,%d2337    bmi.s ywant338    cmp.w %d2,%d3                  | r24 (jdc): Y stays a pass only with YOUR puck or your own339    beq.s yoldb                    | goalie's (the outlet); with a teammate skater's puck Y took340    cmpi.w #5,%d2                  | B's place and (r22) switched skaters instead of the keeper341    beq.s 1f342    cmpi.w #11,%d2343    bne.s ywant3441:  subq.w #6,%d2345    subq.w #6,%d3346    eor.w %d2,%d3347    bpl.s yoldb348ywant:349    clr.l ASK                       | an explicit manual-Y request wins over a queued outlet350    lea YREQ,%a1351    st (%a1,%d0.w)352    st 8(%a1,%d0.w)353    bra.s yreturn354yoldb:355    lea YHELD,%a1356    move.b #1,(%a1,%d0.w)357    bra.s yasb358yrelease:359    clr.b (%a1,%d0.w)360    clr.b 8(%a1,%d0.w)361yreturn:362    movem.l (%sp)+,%d3/%a1363    jmp 0x1FFBF0364yasb:365    bclr #4,%d1366    bsr.w latch_b367    movem.l (%sp)+,%d3/%a1368    jmp 0x1FFC0A369oldreader:370    jmp 0x2FE040371372| Raw active-low B in D1, physical pad offset in D0. Called while polling that373| adapter pad, before the native game can replace a one-frame input sample.374| Only requests a human-side AI keeper already holding/within24 px of the puck.375latch_b:376    movem.l %d0-%d5/%a0-%a1,-(%sp)377    move.w %sr,-(%sp)378    btst #4,%d1379    bne.w latch_done380    btst #7,0xFFFFC2EC               | raw menu/replay buttons must not become deferred game requests381    bne.w latch_done382    btst #0,0xFFFFC2EC383    bne.w latch_done384    btst #0,0xFFFFC2FA385    bne.w latch_done386    tst.w 0xFFFFD412387    bne.w latch_done388    move.b 0xFFFFC2EA,%d1389    andi.b #0x11,%d1390    bne.w latch_done391    btst #2,0xFFFFC2F2392    bne.w latch_done393    btst #3,0xFFFFC2F6394    bne.w latch_done395    lea 0xFFFFC328,%a1396    move.w (%a1,%d0.w),%d1397    moveq #5,%d2398    cmpi.w #1,%d1399    beq.s 1f400    moveq #11,%d2401    cmpi.w #2,%d1402    bne.w latch_done4031:  lea 0xFFFFC320,%a1404    move.w (%a1,%d0.w),%d3405    cmpi.w #11,%d3406    bhi.w latch_done407    lsl.w #7,%d3408    lea OBJ,%a1409    tst.w 0x34(%a1,%d3.w)410    ble.w latch_done411    btst #3,0x62(%a1,%d3.w)412    beq.w latch_done413    move.w %d2,%d3414    lsl.w #7,%d3415    lea (%a1,%d3.w),%a0416    tst.w 0x34(%a0)417    bne.w latch_done418    btst #3,0x62(%a0)419    bne.w latch_done420    move.w 0xFFFFB7AA,%d3421    cmp.w %d2,%d3422    beq.s 4f423    tst.w %d3424    bpl.s latch_done425    move.w 0xFFFFB74A,%d3426    sub.w (%a0),%d3427    bpl.s 2f428    neg.w %d34292:  cmpi.w #24,%d3430    bhi.s latch_done431    move.w 0xFFFFB75E,%d3432    sub.w 0x14(%a0),%d3433    bpl.s 3f434    neg.w %d34353:  cmpi.w #24,%d3436    bhi.s latch_done4374:  ori.w #0x700,%sr                 | check-and-publish together: first valid hardware request wins438    cmp.w ASK+2,%d2439    bne.s 5f440    tst.w ASK441    bne.s latch_done4425:  addq.w #1,%d0443    move.w %d0,ASK444    move.w %d2,ASK+2445    .if WITH_OUTLET_DEADLINE446    jsr 0x2DB400                     | first hardware publication only; holds never refresh it447    .endif448latch_done:449    move.w (%sp)+,%sr450    movem.l (%sp)+,%d0-%d5/%a0-%a1451    rts452453handler:454    tst.w 0xFFFFD046455    beq.w oldhandler456    .if WITH_QUICKGAME457    tst.w 0xFFFFF84C458    bne.s quick_handler459    .endif460    bsr.w cooperative461    bne.w oldhandler462    .if WITH_QUICKGAME463quick_handler:464    .endif465    movem.l %d0-%d1/%a1,-(%sp)466    bsr.w realpad467    lea YREQ,%a1468    tst.b (%a1,%d0.w)469    beq.w no_y470    clr.b (%a1,%d0.w)471    lea BHELD,%a1472    clr.w (%a1,%d0.w)473    tst.w 0xFFFFD412474    bne.w no_y475    btst #0,0xFFFFC2FA476    bne.w no_y477    move.w 0xFFFFB7AA,%d0478    bmi.s 1f479    cmp.w %d6,%d0                 | r24: refuse while this player carries the puck or your own480    beq.s no_y                    | goalie holds it (Y is then the outlet request)481    cmpi.w #5,%d0482    beq.s 4f483    cmpi.w #11,%d0484    bne.s 1f4854:  move.w %d6,%d1486    subq.w #6,%d0487    subq.w #6,%d1488    eor.w %d1,%d0489    bpl.s no_y4901:  moveq #5,%d0491    cmpi.w #5,%d6492    ble.s 2f493    moveq #11,%d04942:  jsr 0xB86A495    tst.w %d0496    bmi.s no_y497    move.w %d0,%d1498    lsl.w #7,%d1499    lea OBJ,%a1500    btst #3,0x62(%a1,%d1.w)501    bne.s no_y                     | never steal a keeper already controlled by another pad502    clr.l ASK503    addq.l #4,%sp504    movem.l (%sp)+,%d1/%a1505    tst.w %d4                     | physical P3/P4 use the native temporary C320/C322 bank506    bne.s 3f507    jmp 0xC0BC5083:  jmp 0xC0DA509no_y:510    movem.l (%sp)+,%d0-%d1/%a1511    jmp 0x20011A512oldhandler:513    jmp 0x2FE100514