Release 2026-11-04-r2 · SHA256 06d79cbc970eff56b56ce802aa52267d153a3c8725b477b32ebbb7d0ad110623 · Click a line number for a direct link.
1| Human-side AI goalie waits for a B request, then passes to that pad's skater.2| Requests can wait through recovery. Native hold timer/whistle and explicit manual control remain.3 .equ OBJ,0xFFFFB04A4 .equ REQ,0xFFFFF058 | transient BC64 target+1, passer, OUTL signature5 .equ ASK,0xFFFFF064 | pending physical pad offset+1 (1/3/5/7), goalie object index6 .text7 .globl _start8_start:9 bra.w decide10 bra.w select_target11 bra.w goalie_direction12 bra.w request1314decide:15 movem.l %d0-%d7/%a0-%a6,-(%sp)16 clr.l REQ17 clr.l REQ+418 tst.w 0x34(%a3)19 bne.w original20 btst #3,0x62(%a3)21 bne.w original22 tst.w 0xFFFFD04623 beq.s adapter_ready24 jsr 0x2EA610 | adapter head-to-head retains native goalie behaviour25 bne.w original26adapter_ready:27 btst #0,0xFFFFC2FA28 bne.w original29 tst.w 0xFFFFD41230 bne.w original31 move.b 0xFFFFC2EA,%d032 andi.b #0x11,%d033 bne.w original34 btst #3,0xFFFFC2F635 bne.w original36 move.w 0x52(%a3),%d037 moveq #1,%d538 cmpi.w #5,%d039 beq.s side_ready40 cmpi.w #11,%d041 bne.w original42 moveq #2,%d543side_ready:44 lea 0xFFFFC328,%a145 moveq #3,%d0461: cmp.w (%a1)+,%d547 beq.s human_side48 dbra %d0,1b49 bra.w original | CPU-only keeper retains native AI50human_side:51 tst.w ASK52 beq.w wait | no automatic/random outlet for a human-side AI goalie53 move.w 0x52(%a3),%d054 cmp.w ASK+2,%d055 bne.w cancel56 btst #1,0x63(%a3) | queue a tap until the diving/catch recovery has completed57 bne.w wait58 btst #3,0x63(%a3)59 bne.w wait60 move.w ASK,%d761 subq.w #1,%d762 cmpi.w #6,%d763 bhi.w cancel64 btst #0,%d765 bne.w cancel66 lea 0xFFFFC328,%a167 cmp.w (%a1,%d7.w),%d568 bne.w cancel69 lea 0xFFFFC320,%a170 move.w (%a1,%d7.w),%d071 cmpi.w #11,%d072 bhi.w cancel73 moveq #0,%d1 | DIVU consumes all 32 bits, not only the object index word74 move.w %d0,%d175 divu.w #6,%d176 addq.w #1,%d177 cmp.w %d5,%d178 bne.w cancel79 lsl.w #7,%d080 lea OBJ,%a581 adda.w %d0,%a582 tst.w 0x34(%a5)83 ble.w cancel84 btst #3,0x62(%a5)85 beq.w cancel86 btst #2,0x63(%a5)87 bne.w wait88 btst #5,0x62(%a5)89 bne.w wait90 move.w 0x52(%a5),%d091 addq.w #1,%d092 move.w %d0,REQ93 move.w 0x52(%a3),REQ+294 move.l #0x4F55544C,REQ+495 move.w (%a5),%d096 sub.w (%a3),%d097 move.w 0x14(%a5),%d198 sub.w 0x14(%a3),%d199 jsr 0x10676100 move.w %d0,0xFFFFBEDC101 move.w %d0,0x54(%a3)102 jsr 0xBC64 | native pass, exact target/vector hooks below103 clr.l REQ104 clr.l REQ+4105 move.w 0x52(%a3),%d0106 cmp.w 0xFFFFB7AA,%d0107 beq.s wait | if native pass cannot start yet, retain this possession's request108cancel:109 clr.l ASK110wait:111 movem.l (%sp)+,%d0-%d7/%a0-%a6112 jmp 0xD880113original:114 clr.l ASK115 movem.l (%sp)+,%d0-%d7/%a0-%a6116 tst.w 0x48(%a3)117 bpl.s positive_timer118 jmp 0xD764119positive_timer:120 jmp 0xD76A121122| Called before ordinary B switching. D1=new buttons, D4=physical pad0/2/4/6,123| A3=controlled human skater. D0=1 means queue/consume B; all other registers kept.124request:125 movem.l %d1-%d7/%a0-%a6,-(%sp)126 moveq #0,%d0127 move.w 0xFFFFB7AA,%d2128 bpl.s 1f129 bsr.w incoming | r13: a loose puck at your goalie counts as his1301: | Adapter reads can publish a short request in VBlank; do not race that131 | publication while replacing a previous possession's pending owner.132 move.w %sr,-(%sp)133 ori.w #0x700,%sr134 cmp.w ASK+2,%d2135 beq.s same_owner136 clr.l ASK137same_owner:138 move.w (%sp)+,%sr139 or.w %d3,%d1 | include a held B across the catch/previous switch latch140 btst #4,%d1141 beq.w request_done142 .if WITH_IMMEDIATE_B143 move.l (%sp),%d3 | original new-press D1 before OR with held buttons144 btst #4,%d3145 beq.s queue_original146 lea 0xFFFFF0E4,%a0147 tst.w 0xFFFFD046148 beq.s physical_y149 lea 0xFFFFF0BA,%a0150physical_y:151 tst.b (%a0,%d4.w)152 bne.s queue_original | Y-generated logical B retains the native outlet153 moveq #2,%d0 | ordinary new B switches immediately unless a valid keeper request154 .if WITH_CATCH_AI155 bra.w queue_original | owning AI keeper: pass to this pad's current skater156 .else157 bra.w request_done158 .endif159queue_original:160 .endif161 btst #0,0xFFFFC2FA162 bne.w request_done163 tst.w 0xFFFFD412164 bne.w request_done165 move.b 0xFFFFC2EA,%d3166 andi.b #0x11,%d3167 bne.w request_done168 cmpi.w #6,%d4169 bhi.w request_done170 moveq #1,%d5171 cmpi.w #5,%d2172 beq.s request_side173 cmpi.w #11,%d2174 bne.w request_done175 moveq #2,%d5176request_side:177 lea 0xFFFFC328,%a1178 cmp.w (%a1,%d4.w),%d5179 bne.w request_done180 tst.w 0x34(%a3)181 ble.w request_done182 btst #3,0x62(%a3)183 beq.w request_done184 move.w 0x52(%a3),%d6185 lea 0xFFFFC320,%a1186 cmp.w (%a1,%d4.w),%d6187 bne.w request_done188 move.w %d2,%d3189 lsl.w #7,%d3190 lea OBJ,%a0191 adda.w %d3,%a0192 tst.w 0x34(%a0)193 bne.w request_done194 btst #3,0x62(%a0)195 bne.w request_done | explicit/manual goalie keeps native controls196 move.w %sr,-(%sp)197 ori.w #0x700,%sr198 tst.w ASK199 bne.s request_published | first valid request wins until served/cancelled200 move.w %d4,ASK201 addq.w #1,ASK202 move.w %d2,ASK+2203 .if WITH_OUTLET_DEADLINE204 jsr 0x2DB400 | one-time processing grace for this accepted request205 .endif206request_published:207 move.w (%sp)+,%sr208request_handled:209 moveq #1,%d0210request_done:211 movem.l (%sp)+,%d1-%d7/%a0-%a6212 rts213214| incoming (2026-10-26-r13, jdc: "sometimes B switched skaters instead of the outlet"):215| between the save and the native ownership ($B7AA still loose) a quick B tap was an ordinary216| switch and the outlet never got it. A loose puck within 24 px of this pad's team goalie217| now counts as his: d2 = goalie index, so the tap is queued (ASK) and served on ownership.218incoming:219 movem.l %d0-%d1/%a0,-(%sp)220 cmpi.w #6,%d4221 bhi.s 9f222 lea 0xFFFFC328,%a0223 move.w (%a0,%d4.w),%d0224 moveq #5,%d1225 cmpi.w #1,%d0226 beq.s 2f227 moveq #11,%d1228 cmpi.w #2,%d0229 bne.s 9f2302: move.w %d1,%d0231 lsl.w #7,%d0232 lea OBJ,%a0233 adda.w %d0,%a0234 tst.w 0x34(%a0) | a goalie in that slot235 bne.s 9f236 move.w 0xFFFFB74A,%d0237 sub.w (%a0),%d0238 bpl.s 3f239 neg.w %d02403: cmpi.w #24,%d0241 bhi.s 9f242 move.w 0xFFFFB75E,%d0243 sub.w 0x14(%a0),%d0244 bpl.s 4f245 neg.w %d02464: cmpi.w #24,%d0247 bhi.s 9f248 move.w %d1,%d22499: movem.l (%sp)+,%d0-%d1/%a0250 rts251252select_target:253 move.l %d0,-(%sp)254 cmpi.l #0x4F55544C,REQ+4255 bne.s native_selection256 move.w 0x52(%a3),%d0257 cmp.w REQ+2,%d0258 bne.s native_selection259 move.w REQ,%d0260 subq.w #1,%d0261 cmpi.w #11,%d0262 bhi.s native_selection263 lsl.w #7,%d0264 lea OBJ,%a0265 adda.w %d0,%a0266 movem.l (%sp)+,%d0267 jmp 0xBD64 | exact target; avoid native rescan choosing a CPU in the same direction268native_selection:269 movem.l (%sp)+,%d0270 moveq #5,%d3 | original BCDA..BCE5, including flags for branch at BCE6271 movea.w #0xB04A,%a1272 cmpi.w #6,0x52(%a3)273 jmp 0xBCE6274275goalie_direction:276 move.l %d0,-(%sp)277 cmpi.l #0x4F55544C,REQ+4278 bne.s native_direction279 move.w 0x52(%a3),%d0280 cmp.w REQ+2,%d0281 bne.s native_direction282 movem.l (%sp)+,%d0283 jmp 0xBDD8 | retain actual vector to the checked human, including safe side/back passes284native_direction:285 movem.l (%sp)+,%d0286 tst.w 0xFFB774287 btst #7,0x62(%a3) | preserve both N from velocity and Z from direction bit288 jmp 0xBDC4289