Release 2026-11-04-r2 · SHA256 bbf6536b597a6f6527973d2d07570507e34012f93c3dd256b4fa6ce398d91e35 · Click a line number for a direct link.
1 .ifndef WITH_REFINEMENTS2 .equ WITH_REFINEMENTS,03 .endif4 .ifndef WITH_REPLAY_HUD5 .equ WITH_REPLAY_HUD,06 .endif7 .ifndef WITH_FRAMED_PP_REPLAY8 .equ WITH_FRAMED_PP_REPLAY,09 .endif10 .if WITH_FRAMED_PP_REPLAY11 .equ PANEL_BYTES,180 | rows18..27: PP/fallback plus original clock/shot12 .else13 .equ PANEL_BYTES,9014 .endif15| Automatic goal replay (jdc 2026-10-25-r25): 1.5 s after every goal the game's own16| Instant Replay ($9FD0, the pause menu's VCR) starts by itself, plays the buffer with a17| scripted C press (r4: was "hold C", a still picture), then leaves with Start, Start (options menu, return to game).18| A + C held on either pad (Xbox X + B, as Abandon Season) skips to the end at once.19| +0 tick: called every frame by crowd.s (score watch, countdown, pause request)20| +4 pause: replaces bsr $7CF8 / bra $7938 at $7948 (the main loop's pause call)21| +8 pad: replaces tst.w $D046 / bne.w $A434 at $A41E (the replay's pad read)22 .equ ARST,0xFFF738 | $A500 idle, $A501 requested, $A502 playing, $A503..$A506 exit23 | (2026-10-26-r3: anything else = idle. Menu screens write text over24 | $FFF7xx; a stale 1..6 made the pad hook feed fake input to the25 | pre-game menu after the season results: "Start Game" hung)26| Maintenance HUD code uses A507 for postgame ownership; it never scripts input.27 .equ ARCNT,0xFFF73A28 .equ CNTDN,0xFFF73C29 .equ LASTG,0xFFF73E30 .equ PLAYLEN,540 | frames of play: the whole buffer (about 520)31 .text32 .globl _start33_start:34 bra.w tick35 bra.w pause36 bra.w pad3738tick:39 movem.l %d0,-(%sp)40 move.w 0xFFFFC6DA,%d0 | goals of both teams41 add.w 0xFFFFCA3E,%d042 andi.w #0xFF,%d043 ori.w #0xA500,%d0 | r30: tagged; at the final horn the game zeroes this44 cmpi.w #1,0xFFFFF0DE | Auto Replays Off: resync, discard pending countdown45 bne.s enabled46 move.w %d0,LASTG47 clr.w CNTDN48 bra.w 9f49enabled:50 cmp.w LASTG,%d0 | RAM (LASTG 0 looked like 3 new goals: a replay after51 beq.s 3f | the game), so an untagged LASTG only resyncs52 cmpi.b #0xA5,LASTG53 bne.s 2f54 cmp.w LASTG,%d055 bcs.s 2f | fewer (a new game): no replay56 btst #0,0xFFFFC2FA | shootout: no replay57 bne.s 2f58 move.w #90,CNTDN592: move.w %d0,LASTG603: tst.w CNTDN61 beq.s 9f62 subq.w #1,CNTDN63 bne.s 9f64 move.w ARST,%d0 | a replay already requested / running?65 subi.w #0xA501,%d066 cmpi.w #5,%d067 bls.s 9f68 move.w #0xA501,ARST | ask the main loop for a pause: ours69 bset #0,0xFFFFC2EC709: movem.l (%sp)+,%d071 rts7273pause:74 cmpi.w #0xA501,ARST75 beq.s 1f76 jsr 0x7CF8 | an ordinary Start: the pause menu77 jmp 0x7938781: bsr.s auto79 jmp 0x793880auto: | the pause routine's frame, with the replay instead of the menu81 move.w #0xA502,ARST82 clr.w ARCNT83 jsr 0x10F3284 move.w %d0,-(%sp)85 move.w 0xFFFFB03E,%d0861: cmp.w 0xFFFFB03E,%d087 beq.s 1b88 move.w (%sp)+,%d089 jsr 0x1A26490 move.w 0xFFFFC2EC,-(%sp)91 .if WITH_REPLAY_HUD92 suba.w #PANEL_BYTES+4,%sp93 move.l %a0,PANEL_BYTES(%sp)94 movea.l %sp,%a095 jsr 0x2EC004 | save the actual lower-left panel before native clear96 movea.l PANEL_BYTES(%sp),%a097 .endif98 jsr 0x7E0E99 jsr 0x9FD0 | Instant Replay100 .if WITH_REPLAY_HUD101 adda.w #PANEL_BYTES+4,%sp102 clr.l 0xFFFFF670103 .endif104 bclr #1,0xFFFFC2F6 | consume replay's redraw latch; no menu dispatcher ran here105 move.w #0xA500,ARST106 clr.w 0xFFF728 | crowd.s TICK: its meter tiles (replaced by REPLAY) next frame107 jmp 0x7D66 | the pause routine's own exit (pops $C2EC, rts to pause)108109pad:110 move.l %d0,-(%sp)111 move.w ARST,%d0 | scripted only while our replay runs ($A502..$A506)112 subi.w #0xA502,%d0113 cmpi.w #4,%d0114 movem.l (%sp)+,%d0 | (movem keeps the flags)115 bls.s 1f116 .if WITH_REFINEMENTS117 | A41E is the native MENU/VCR input reader (enumerated16 UI callers),118 | separate from skating input. Preserve native non-input registers/status.119 tst.w 0xFFFFD046120 beq.s menu_single_pad121 jsr 0xA434122 bra.s menu_input_ready123menu_single_pad:124 jsr 0xA426125menu_input_ready:126 move.w %sr,-(%sp)127 jsr 0x25B038 | explicit native caller -> contextual footer128 jsr 0x25B028 | XboxA/nativeB aliases native Start/back129 move.w (%sp)+,%sr130 rts131 .else132 tst.w 0xFFFFD046 | native133 beq.s 0f134 jmp 0xA4341350: jmp 0xA426136 .endif1371: movem.l %d4,-(%sp)138 jsr 0x11340 | both real pads: A + C held = skip139 move.w %d3,%d4140 jsr 0x11358141 or.w %d3,%d4142 andi.w #0x60,%d4143 cmpi.w #0x60,%d4144 bne.s 2f145 cmpi.w #0xA502,ARST146 bne.s 2f147 move.w #0xA503,ARST1482: movem.l (%sp)+,%d4149 moveq #8,%d0 | no direction150 moveq #0,%d1151 moveq #0,%d2152 moveq #0,%d3153 cmpi.w #0xA502,ARST154 bne.s 3f155 addq.w #1,ARCNT | playing156 cmpi.w #PLAYLEN,ARCNT157 bcs.s 21f158 move.w #0xA503,ARST15921: jsr 0x2EC000 | replaytitle.s: big "REPLAY" instead of the VCR box (r23)160 cmpi.w #2,ARCNT | 2026-10-26-r4: a NEW C press (d1 bit5, $A25E) toggles161 bne.s 22f | play; holding C (d3) only showed the first frame162 moveq #0x20,%d1163 moveq #0x20,%d2164 moveq #0x20,%d316522: rts1663: cmpi.w #0xA503,ARST | r25: one Start leaves at once: with $C2F6 bit0 (options menu167 bne.s 5f | open) the native loop exits on Start ($A358 -> $A39E); the168 bset #0,0xFFFFC2F6 | Options / Reverse Angle box no longer flashes before the game1694: move.w #0x80,%d1170 move.w #0x80,%d2171 move.w #0x80,%d31725: cmpi.w #0xA506,ARST173 bcc.s 6f174 addq.w #1,ARST1756: rts176