Release 2026-11-04-r2 · SHA256 a8693679dfe04ef26268935517079f8fb542e45fa5be9e5d986e915eceffa43b · 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| r31: 8x5 shot panel, exactly the score box's size, directly above it:8| HUD plane E000 rows18..22 cols32..39. Smooth charge sprite centered inside;9| native KMH/MPH text uses six interior cells. Full = native raw charge31.10| Preserve recorded speed/charge through automatic replay; use resident HUD11| dash segments there because REPLAY temporarily borrows the crowd meter tiles.12| Clear on the first normal-rink frame after replay (including skip), or after13| the existing240-frame lifetime for ordinary shots. No new pattern VRAM/DMA.14| +0 logic from crowd.s; +4 sprite append (existing80-sprite bound).15 .equ MAGIC,0xFFF64016 .equ SHOOT,0xFFF642 | shooter object + 117 .equ CHG,0xFFF64418 .equ SHOW,0xFFF64619 .equ LIVE,0xFFF64820 .equ BLINK,0xFFF64A21 .equ OBJ,0xFFFFB04A22 .equ TILE,0x7E1 | crowd.s bar tiles: +0 black 32x8, +4 white, +8 red, partials23 .equ PANEL,0xFFF64C | 1 while the panel is in the HUD plane24 .equ ROW0,1825 .if WITH_LEFT_PANEL26 .equ COL0,027 .else28 .equ COL0,3229 .endif30 .equ HELD,0xFFF64E | last shot held throughout automatic replay31 .equ KMH,0xFFF65032 .equ MPH,0xFFF65233 .equ STILE,0x7E1 | r38: the bar's own 4 tiles (crowd.s mkbar), HUD-plane cells34 .equ SBUF,0xFFEA00 | crowd.s BBUF+25635 .equ BX,272+128 | original smooth bar centered inside the 48px interior36 .equ BY,152+12837 .equ VDATA,0xC0000038 .equ VCTRL,0xC0000439 .text40 .globl _start41_start:42 bra.w logic43 bra.w draw44 .if WITH_STARS_HUD45 bra.w stars_prepare | +8 called BEFORE original Stars window drawing46 .else47 .if WITH_LEFT_PANEL48 rts49 nop50 .endif51 .endif52 .if WITH_LEFT_PANEL53 bra.w shotbar | +C shared native bar renderer54 bra.w erase | +10 ownership-aware clear55 bra.w panel_above | +14 native-font fallback56 .endif5758skip: | C set: not on the normal rink view / in the automatic replay59 btst #7,0xFFFFC2EC60 bne.s 1f61 move.l %d0,-(%sp)62 move.w 0xFFF738,%d063 subi.w #0xA502,%d064 .if WITH_STARS_HUD65 cmpi.w #6,%d0 | postgame A507 is a foreign HUD owner, not replay playback66 .else67 cmpi.w #5,%d068 .endif69 movem.l (%sp)+,%d070 bcs.s 1f71 andi.b #0xFE,%ccr72 rts731: ori.b #1,%ccr74 rts7576logic:77 movem.l %d0-%d7/%a0-%a1,-(%sp)78 cmpi.w #0x534D,MAGIC79 beq.s 1f80 move.w #0x534D,MAGIC81 clr.l SHOOT82 clr.l SHOW83 clr.w BLINK84 clr.w HELD85 .if WITH_REFINEMENTS86 clr.w 0xFFFFF8DC87 .endif881: move.w 0xFFF738,%d089 subi.w #0xA502,%d090 cmpi.w #4,%d091 bhi.s not_replay92 tst.w SHOW93 beq.w 9f94 move.w #1,HELD | freeze measured speed and charge, ignore replayed actors95 bra.w 9f96not_replay:97 tst.w HELD98 beq.s normal_view99 clr.w HELD100 clr.w SHOW101 clr.w SHOOT102 clr.w LIVE103 bsr.w erase | replay finished: remove the panel immediately104 bra.w 9f105normal_view:106 bsr.w skip107 bcc.s 11f108 clr.w SHOW | ordinary pause/menus keep no stale panel109 clr.w SHOOT110 clr.w LIVE111 bsr.w erase112 bra.w 9f11311: addq.w #1,BLINK114 tst.w SHOW115 beq.s 2f116 subq.w #1,SHOW117 bne.s 2f118 bsr.w erase | time is up1192: clr.w LIVE120 .if WITH_REFINEMENTS121 jsr 0x258010 | actual held human pass, same native charge bar122 tst.w %d0123 bmi.s no_pass_bar124 move.w %d0,CHG125 move.w #1,LIVE126 move.w #1,0xFFFFF8DC127 clr.w SHOW128 clr.w SHOOT | releasing a pass must not be measured as a shot129 bra.w 9f130no_pass_bar:131 tst.w 0xFFFFF8DC132 beq.s shot_scan133 clr.w 0xFFFFF8DC134 clr.w SHOW135 clr.w SHOOT136 bsr.w erase137shot_scan:138 .endif139 moveq #0,%d6 | the pads' own players only (C320.., sides C328..)1403: lea 0xFFFFC328,%a1141 tst.w (%a1,%d6.w)142 beq.s 4f143 lea 0xFFFFC320,%a1144 move.w (%a1,%d6.w),%d7145 cmpi.w #11,%d7146 bhi.s 4f147 move.w %d7,%d0148 lsl.w #7,%d0149 lea OBJ,%a0150 adda.w %d0,%a0151 cmpi.w #0x7FC,0x58(%a0) | winding up a slapshot with the puck152 beq.s 31f153 cmpi.w #0x92E,0x58(%a0)154 bne.s 4f15531: cmp.w 0xFFFFB7AA,%d7156 bne.s 4f157 move.w %d7,%d0158 addq.w #1,%d0159 move.w %d0,SHOOT160 move.w 0xFFFFBEDE,%d0161 cmpi.w #31,%d0162 bls.s 32f163 moveq #31,%d016432: move.w %d0,CHG165 move.w #1,LIVE166 clr.w SHOW167 bra.w 9f1684: addq.w #2,%d6169 cmpi.w #8,%d6170 bcs.s 3b171 move.w SHOOT,%d7 | released?172 beq.w 9f173 subq.w #1,%d7174 move.w 0xFFFFB7AA,%d0175 cmp.w %d7,%d0176 beq.w 9f | still his (final swing frames)177 clr.w SHOOT178 tst.w %d0179 bpl.w 9f | someone else has it: no shot180 cmp.w 0xFFFFBED8,%d7 | the shooter of the loose puck181 bne.w 9f182 move.w 0xFFFFB772,%d0 | |v| = isqrt(vx^2 + vy^2)183 muls.w %d0,%d0184 move.w 0xFFFFB774,%d1185 muls.w %d1,%d1186 add.l %d1,%d0187 bsr.w isqrt188 move.l %d0,%d3189 mulu.w #763,%d0 | km/h = V * 763 / 2^17190 moveq #17,%d1191 lsr.l %d1,%d0192 move.l %d3,%d4193 mulu.w #237,%d4 | mph = V * 237 / 2^16194 swap %d4195 move.w %d0,KMH196 move.w %d4,MPH197 move.w #240,SHOW1989: bsr.w refresh199 movem.l (%sp)+,%d0-%d7/%a0-%a1200 rts201202| panel: d0 = km/h, d4 = mph -> the score-box panel in the HUD plane203panel:204 .if WITH_LEFT_PANEL205 jmp 0x227000206 .endif207panel_above:208 movem.l %d0-%d7/%a0-%a1,-(%sp)209 move.w %sr,-(%sp)210 ori.w #0x700,%sr211 lea VDATA,%a1212 move.w %d0,%d5213 moveq #0,%d3 | top frame214 bsr.w cellcmd215 move.w #0xA3FF,(%a1)216 moveq #5,%d22171: move.w #0xA400,(%a1)218 dbra %d2,1b219 move.w #0xA401,(%a1)220 moveq #1,%d3 | bar inside the first interior row221 bsr.w cellcmd222 move.w #0xA402,(%a1)223 tst.w HELD | r38 (jdc: skaters passed over the sprite bar): live, the224 bne.s held_bar | bar is four HUD-plane cells of its own, in front of them225coloured_bar:226 bsr.w shotbar227 move.w #0xA403,(%a1)228 move.w %d0,(%a1)229 addq.w #1,%d0230 move.w %d0,(%a1)231 addq.w #1,%d0232 move.w %d0,(%a1)233 addq.w #1,%d0234 move.w %d0,(%a1)235 move.w #0xA403,(%a1)236 bra.s bar_done237held_bar:238 .if WITH_REPLAY_HUD239 bra.w coloured_bar240 .endif241 moveq #0,%d6 | replay uses six resident HUD dash segments242 tst.w HELD243 beq.s bar_empty244 move.w CHG,%d6245 subi.w #15,%d6246 bpl.s dash_positive247 moveq #0,%d6248dash_positive:249 cmpi.w #16,%d6250 bls.s dash_clamped251 moveq #16,%d6252dash_clamped:253 mulu.w #6,%d6254 addi.w #15,%d6255 divu.w #16,%d6256bar_empty:257 moveq #0,%d2258bar_cells:259 move.w #0xA403,%d0260 cmp.w %d6,%d2261 bcc.s dash_ready262 move.w #0x841B,%d0 | native HUD minus, never shares replay-title pattern tiles263dash_ready:264 move.w %d0,(%a1)265 addq.w #1,%d2266 cmpi.w #6,%d2267 bcs.s bar_cells268bar_done:269 move.w #0xA404,(%a1)270 moveq #2,%d3 | native six-cell text: 184KMH / 114MPH271 bsr.w cellcmd272 move.w #0xA402,(%a1)273 tst.w SHOW274 beq.s blank_speeds275 .if WITH_REFINEMENTS276 cmpi.w #1,0xFFFFF8D8277 beq.s selected_mph278 .endif279 move.w %d5,%d0280 bsr.w num3281 move.w #0x8438,(%a1)282 move.w #0x843A,(%a1)283 move.w #0x8435,(%a1)284 .if WITH_REFINEMENTS285 bra.s selected_speed_done286selected_mph:287 move.w %d4,%d0288 bsr.w num3289 move.w #0x843A,(%a1)290 move.w #0x843C,(%a1)291 move.w #0x8435,(%a1)292selected_speed_done:293 move.w #0xA404,(%a1)294 moveq #3,%d3295 bsr.w cellcmd296 move.w #0xA402,(%a1)297 moveq #5,%d2298selected_blank_row:299 move.w #0xA403,(%a1)300 dbra %d2,selected_blank_row301 bra.w speed_end302 .endif303 move.w #0xA404,(%a1)304 moveq #3,%d3305 bsr.w cellcmd306 move.w #0xA402,(%a1)307 move.w %d4,%d0308 bsr.w num3309 move.w #0x843A,(%a1)310 move.w #0x843C,(%a1)311 move.w #0x8435,(%a1)312 bra.s speed_end313blank_speeds:314 moveq #5,%d2315blank_first:316 move.w #0xA403,(%a1)317 dbra %d2,blank_first318 move.w #0xA404,(%a1)319 moveq #3,%d3320 bsr.w cellcmd321 move.w #0xA402,(%a1)322 moveq #5,%d2323blank_second:324 move.w #0xA403,(%a1)325 dbra %d2,blank_second326speed_end:327 move.w #0xA404,(%a1)328 moveq #4,%d3329 bsr.w cellcmd330 move.w #0xA405,(%a1)331 moveq #5,%d23322: move.w #0xA406,(%a1)333 dbra %d2,2b334 move.w #0xA407,(%a1)335 .if WITH_LEFT_PANEL336 move.w #2,PANEL337 .else338 move.w #1,PANEL339 .endif340 move.w (%sp)+,%sr341 movem.l (%sp)+,%d0-%d7/%a0-%a1342 rts343| shotbar: white at low charge, native orange through the middle, solid red at full.344| No palette writes or blink; compose into SBUF -> d0 = first HUD map word.345shotbar:346 movem.l %d1-%d5/%a0,-(%sp)347 move.w CHG,%d5348 subi.w #15,%d5349 bpl.s 1f350 moveq #0,%d53511: mulu.w #30,%d5352 divu.w #16,%d5353 cmpi.w #30,%d5354 bls.s 2f355 moveq #30,%d53562: moveq #1,%d1357 moveq #4,%d2358 move.w #0x8000+STILE,%d4359 cmpi.w #10,%d5 | first third white; native palette 1 colour 5 = orange360 bcs.s 4f361 moveq #5,%d1362 moveq #7,%d2363 move.w #0xA000+STILE,%d4364 cmpi.w #30,%d5365 bcs.s 4f366 moveq #0xA,%d1 | maximum stays red throughout the windup/release3674: move.w %d1,%d3 | key: colour, fill; compose only on a change, or when368 lsl.w #8,%d3 | the panel is new (after a replay REPLAY used $7E1..)369 or.w %d5,%d3370 tst.w PANEL371 beq.s 5f372 cmp.w 0xFFE8F4,%d3373 beq.s 6f3745: move.w %d3,0xFFE8F4375 move.w %d5,%d0376 moveq #2,%d3 | solid top/bottom rows inside the panel (r39)377 lea SBUF,%a0378 jsr 0x2E0024 | crowd.s mkbar379 move.l #SBUF,(%a5)+380 move.w #64,(%a5)+381 move.w #STILE*32,(%a5)+3826: move.w %d4,%d0383 movem.l (%sp)+,%d1-%d5/%a0384 rts385erase: | the panel's 8x5 cells back to transparent $07FF386 tst.w PANEL387 beq.s 9f388 .if WITH_LEFT_PANEL389 cmpi.w #1,PANEL390 bne.s erase_above391 movem.l %d0-%d2/%a1,-(%sp)392 jsr 0x227004393 tst.w %d0394 beq.s compact_erased395 jsr 0x22700C396compact_erased:397 clr.w PANEL398 movem.l (%sp)+,%d0-%d2/%a1399 rts400erase_above:401 movem.l %d0-%d1,-(%sp)402 jsr 0x227010 | native foreign windows may now own this rectangle403 tst.w %d0404 movem.l (%sp)+,%d0-%d1405 bne.s erase_owned_above406 clr.w PANEL407 rts408erase_owned_above:409 .endif410 movem.l %d0-%d3/%a1,-(%sp)411 move.w %sr,-(%sp)412 ori.w #0x700,%sr413 lea VDATA,%a1414 moveq #0,%d34151: bsr.s cellcmd416 moveq #7,%d24172: move.w #0x07FF,(%a1)418 dbra %d2,2b419 addq.w #1,%d3420 cmpi.w #5,%d3421 bcs.s 1b422 clr.w PANEL423 move.w (%sp)+,%sr424 movem.l (%sp)+,%d0-%d3/%a14259: rts426cellcmd: | d3 = panel row 0..4 -> VDP write at (ROW0+d3, COL0) of the HUD plane427 movem.l %d0-%d1,-(%sp)428 moveq #ROW0,%d0 | HUD plane $E000, 64 cells wide (VRAM dump r28)429 add.w %d3,%d0430 lsl.w #7,%d0431 addi.w #COL0*2,%d0 | offset in the plane (< $2000)432 moveq #0,%d1433 move.w %d0,%d1434 swap %d1435 ori.l #0x60000003,%d1 | VRAM write at $E000 + offset436 move.w #0x8F02,VCTRL | auto-increment 2437 move.l %d1,VCTRL438 movem.l (%sp)+,%d0-%d1439 rts440num3: | d0 = 0..999 -> three HUD digit cells (leading blanks)441 movem.l %d0-%d2,-(%sp)442 andi.l #0xFFFF,%d0443 cmpi.w #999,%d0444 bls.s 1f445 move.w #999,%d04461: divu.w #100,%d0447 move.w %d0,%d1 | hundreds448 swap %d0449 andi.l #0xFFFF,%d0450 divu.w #10,%d0 | tens in d0.w, ones in the high word451 move.w #0xA403,%d2452 tst.w %d1453 beq.s 2f454 move.w #0x841E,%d2455 add.w %d1,%d24562: move.w %d2,(%a1)457 move.w #0xA403,%d2458 tst.w %d1459 bne.s 3f460 tst.w %d0461 beq.s 4f4623: move.w #0x841E,%d2463 add.w %d0,%d24644: move.w %d2,(%a1)465 swap %d0466 addi.w #0x841E,%d0467 move.w %d0,(%a1)468 movem.l (%sp)+,%d0-%d2469 rts470isqrt: | d0.l unsigned -> d0 = floor(sqrt)471 movem.l %d1-%d3,-(%sp)472 moveq #0,%d1 | result473 move.l #0x40000000,%d2 | bit4741: cmp.l %d0,%d2475 bls.s 2f476 lsr.l #2,%d2477 bne.s 1b478 bra.s 4f4792: move.l %d1,%d3480 add.l %d2,%d3481 cmp.l %d3,%d0482 bcs.s 3f483 sub.l %d3,%d0484 lsr.l #1,%d1485 add.l %d2,%d1486 bra.s 5f4873: lsr.l #1,%d14885: lsr.l #2,%d2489 bne.s 2b4904: move.l %d1,%d0491 movem.l (%sp)+,%d1-%d3492 rts493494| Keep native HUD map/pattern memory intact. In play the original smooth495| crowd-tile sprite bar sits inside the box; in replay those tiles belong to496| REPLAY, so the fixed recorded charge is shown with native HUD dash glyphs.497refresh:498 .if WITH_LEFT_PANEL499 bsr.w skip500 bcs.s refresh_body501 jsr 0x227008502refresh_body:503 .endif504 tst.w SHOW505 bne.s visible506 tst.w LIVE507 bne.s visible508 tst.w SHOOT509 beq.s refresh_done510visible:511 move.w KMH,%d0512 move.w MPH,%d4513 bsr.w panel514refresh_done:515 rts516517draw: | r38: no sprites (the bar is in the panel's HUD cells)518 rts519olddraw:520 cmpi.w #0x534D,MAGIC521 bne.w 9f522 bsr.w skip523 bcs.w 9f524 tst.w LIVE525 bne.s 1f526 tst.w SHOOT | the last swing frames before the release527 bne.s 1f528 tst.w SHOW529 beq.w 9f5301: movem.l %d0-%d5,-(%sp)531 move.w CHG,%d5 | fill 0..30 px of (CHG - 15) / 16532 subi.w #15,%d5533 bpl.s 2f534 moveq #0,%d55352: mulu.w #30,%d5536 divu.w #16,%d5537 move.w #0x8000+TILE+4,%d3 | white538 cmpi.w #30,%d5539 bcs.s 3f540 move.w #0xA000+TILE+8,%d3 | full: red (palette 1), blinking while still winding up541 tst.w SHOW542 bne.s 3f543 btst #2,BLINK+1544 bne.w 6f5453: move.w #BY,%d2546 move.w %d5,%d0547 lsr.w #3,%d0 | whole tiles548 beq.s 4f549 move.w %d0,%d1550 subq.w #1,%d1551 lsl.w #2,%d1552 move.b %d1,%d0553 move.w #BX+1,%d1554 bsr.w sprs5554: moveq #7,%d0 | partial width 1..7 after them (crowd.s tile order)556 and.w %d5,%d0557 beq.s 6f558 move.w %d3,%d4559 add.w #11,%d4560 add.w %d0,%d4561 subq.w #4,%d4562 cmpi.w #0xA000,%d3563 bcs.s 5f564 addq.w #3,%d45655: move.w %d3,-(%sp)566 move.w %d4,%d3567 move.w %d5,%d1568 andi.w #0xFFF8,%d1569 add.w #BX+1,%d1570 moveq #0,%d0571 bsr.w sprs572 move.w (%sp)+,%d35736: move.w #0x8000+TILE,%d3 | black 32x8 background574 moveq #0x0C,%d0575 move.w #BX,%d1576 move.w #BY,%d2577 bsr.w sprs5788: movem.l (%sp)+,%d0-%d55799: rts580sprs: | d0 size, d1 x, d2 y, d3 attribute (as crowd.s)581 cmpa.w #0xC298,%a6582 bcc.s 9f583 move.w %d2,(%a6)+584 move.b %d0,(%a6)+585 move.b %d6,(%a6)+586 move.w %d3,(%a6)+587 move.w %d1,(%a6)+588 addq.w #1,%d65899: rts590 .even591592 .if WITH_STARS_HUD593stars_prepare:594 movem.l %d0-%d7/%a0-%a1,-(%sp)595 clr.l SHOOT596 clr.l SHOW597 clr.w HELD598 bsr.w erase | still our map cells: native Stars has not drawn yet599 movem.l (%sp)+,%d0-%d7/%a0-%a1600 rts601 .endif602603