Release 2026-11-04-r2 · SHA256 faadcee94f832b770cc472742be4c7f11f684a396c458940e3ceea7fbc75b288 · Click a line number for a direct link.
1 .include "features.inc"2| Season mode: playoffs after the season, NHL format. Mini/Light use one game per pairing; full season uses best of 7.3| 16 teams: the top 3 of each division and 2 wild cards per conference (the best of the rest). East = Atlantic +4| Metropolitan (tree slots 8-15, right side), West = Central + Pacific (slots 0-7, left side). In each conference the5| better division winner meets the second wild card, the other winner the first; 2nd meets 3rd in each division.6| Pairs in the tree: (0,1) (2,3) (4,5) (6,7), the winners of (0,1)/(2,3) and (4,5)/(6,7) meet in round 2.7|8| The game's playoffs: $CEF4 = the 16 teams, copied from the ROM table $5576 + 16 * $CEE8 (32 presets) by $17D80;9| New Playoffs ($17D16) picks a preset with your team (Home) in it and stores your slot in $CEEE. State is kept as the10| game's password at $D088 (saved with the settings in battery RAM), so Continue Playoffs works across power-offs.11| Hooks: $17D8E (movea.l #$5576,a1 / adda.w d1,a1) -> jsr fetch / nop: the season's 16 teams instead of a preset;12| $17D4A (move.w d1,$CEEE / move.w d0,$CEE8) -> jsr newpo / nop: your slot in the season's tree.13| "Season playoffs" = a valid season block, not New Season, and your games played >= the season length.14| SRAM $1210 (word, free): 0 not started, 1 set up (New Playoffs or New Playoffs/7 games, no game yet), 2 a playoff game was played15| (the game's own state is then in its password, Continue Playoffs), 3 over (the game ended the playoffs: menu free);16| jdc r18: 3 = out, 4 = champion, 5 = missed the playoffs; 3..5 = over, the season summary has been shown.1718 .equ SRAM_OFF, 0x100019 .equ NBYTES, 16+32*1620 .equ MAGIC, 0x5345534E21 .equ SRAM_RD, 0x1A24422 .equ SRAM_WR, 0x1A1E423 .equ FLAG_OFF, 0x121024 .equ PBUF, 0xFFF400 | season block (528 bytes)25 .equ KEYS, 0xFFF620 | 32 longs: (points*256 + goal difference + 128) * 32 + (31 - team)26 .equ TAKEN, 0xFFF6A0 | 32 bytes27 .equ SEEDS, 0xFFF6C0 | 16 teams in tree order28 .equ QUAL, 0xFFF6D0 | 32 bytes: 1 = top 3 of the division, 2 = wild card, 0 = out29 .equ DR, 0xFFF6F0 | 4 divisions x 3 teams30 .equ TMP, 0xFFF700 | 4 bytes31 .equ HOME, 0xFFD04C3233 .text34 .globl _start35_start: bra.w fetch | +0 hook $17D8E36 bra.w newpo | +4 hook $17D4A37 bra.w seeds | +8 d0 = 0 (and Z) when SEEDS / QUAL are valid38 bra.w autopo | +12 season over, first time: d0 = 0 when the playoffs should start now39 bra.w clrflag | +16 a new season starts40 bra.w spcheck | +20 season menu: are the season's playoffs on? (see there)41 bra.w played | +24 a playoff game was played (season.s)42 bra.w setflag | +28 d0 -> SRAM flag (seasonend.s: 3 out, 4 champion, 5 missed, summary shown)43 bra.w poseason | +32 d0 = 0: this game is one of the season's playoff games in progress4445| ---- $17D8E: a1 = the 16 teams of this tree46fetch: movem.l %d0-%d7/%a0/%a2-%a6,-(%sp)47 bsr.w active48 movem.l (%sp)+,%d0-%d7/%a0/%a2-%a6 | (movem to registers keeps the flags)49 bne.s 1f50 lea SEEDS,%a151 rts521: movea.l #0x5576,%a153 adda.w %d1,%a154 rts5556| ---- $17D4A: New Playoffs has picked a preset (d0) and your slot (d1)57newpo: move.w %d1,0xFFCEEE58 move.w %d0,0xFFCEE859 movem.l %d0-%d7/%a0-%a6,-(%sp)60 bsr.w active61 bne.s 9f62 move.w HOME,%d063 bsr.w slotof64 bmi.s 9f65 move.w %d1,0xFFCEEE66 clr.w 0xFFCEE8679: movem.l (%sp)+,%d0-%d7/%a0-%a668 rts6970| slotof: d0 = team -> d1 = slot in SEEDS (N flag set if not there)71slotof: lea SEEDS,%a072 moveq #0,%d1731: cmp.b (%a0,%d1.w),%d074 beq.s 2f75 addq.w #1,%d176 cmpi.w #16,%d177 blt.s 1b78 moveq #-1,%d179 rts802: tst.w %d181 rts8283| active: season playoffs? d0 = 0 (Z) and SEEDS filled, else d0 = -184active: tst.w 0xFFFFF06C | standalone native modes must not modify a suspended season85 beq.w 8f86 bsr.w seeds87 bne.w 8f88 move.w PBUF+8,%d0 | your games played89 cmp.w PBUF+10,%d0 | season length90 bcs.s 8f91 tst.w PBUF+6 | a season with your team92 beq.s 8f93 moveq #0,%d094 rts958: moveq #-1,%d096 rts9798| ---- autopo: called by the season menu when your season is over. d0 = 0 when it should switch to the playoffs now99| (first time only, and your team made it); the flag is set here.100autopo: movem.l %d1-%d7/%a0-%a6,-(%sp)101 lea TMP,%a0102 move.l #FLAG_OFF,%d0103 moveq #2,%d1104 jsr SRAM_RD105 tst.w TMP106 bne.s 8f | already switched once107 bsr.w active108 bne.s 8f109 move.w PBUF+6,%d0110 subq.w #1,%d0111 bsr.w slotof112 bmi.s 8f | your team did not make it113 moveq #1,%d0114 bsr.w setflag115 moveq #0,%d0116 bra.s 9f1178: moveq #-1,%d01189: movem.l (%sp)+,%d1-%d7/%a0-%a6119 tst.w %d0120 rts121122| ---- spcheck: d0 = -1 not the season's playoffs (menu as usual); 0 = they are on and the menu is already set;123| 1 / 2 / 3 = they are on and Play Mode must be set to this (1 Continue, 2 single game, 3 best of 7). d2 = your team.124spcheck:125 movem.l %d1/%d3-%d7/%a0-%a6,-(%sp)126 bsr.w active127 bne.w 8f128 move.w PBUF+6,%d0129 subq.w #1,%d0130 move.w %d0,%d2 | your team131 bsr.w slotof132 .if MINI_GAMES != 8133 bmi.w 8f | preserve reach after adding current and legacy Mini lengths134 .else135 bmi.s 8f | not in the playoffs136 .endif137 lea TMP,%a0138 move.l #FLAG_OFF,%d0139 moveq #2,%d1140 jsr SRAM_RD141 move.w TMP,%d4142 cmpi.w #3,%d4143 bcc.s 8f | over (3 out, 4 champion)144 moveq #3,%d3 | New Playoffs/7 games145 .if MINI_GAMES != 8146 cmpi.w #MINI_GAMES,PBUF+10147 beq.s 7f148 .endif149 cmpi.w #8,PBUF+10150 beq.s 7f151 cmpi.w #31,PBUF+10152 bne.s 6f1537: moveq #2,%d3 | New Playoffs: one game decides the pairing1546:155 cmpi.w #2,%d4156 bne.s 2f157 move.w 0xFFD048,%d0 | after a game the game sets 1 (go on) or 2/3 (the playoffs are over)158 cmpi.w #2,%d0159 beq.s 1f160 cmpi.w #3,%d0161 bne.s 3f1621: moveq #3,%d0163 bsr.w setflag164 bra.s 8f1653: moveq #1,%d3 | Continue Playoffs166 bra.s 4f1672: tst.w %d4168 bne.s 4f169 moveq #1,%d0170 bsr.w setflag1714: moveq #0,%d0172 cmp.w 0xFFD048,%d3173 bne.s 5f174 cmp.w HOME,%d2175 beq.s 9f1765: move.w %d3,%d0177 bra.s 9f1788: moveq #-1,%d01799: movem.l (%sp)+,%d1/%d3-%d7/%a0-%a6180 tst.w %d0181 rts182183| ---- played: a game in a playoff mode is over (season.s): flag 2 if these are the season's playoffs184played: movem.l %d0-%d7/%a0-%a6,-(%sp)185 bsr.w active186 bne.s 1f187 lea TMP,%a0 | jdc r18: the season's playoffs are over (3..5): a later standalone188 move.l #FLAG_OFF,%d0 | New Playoffs must not reopen them189 moveq #2,%d1190 jsr SRAM_RD191 cmpi.w #3,TMP192 bcc.s 1f193 moveq #2,%d0194 bsr.w setflag1951: movem.l (%sp)+,%d0-%d7/%a0-%a6196 rts197198| ---- poseason (season.s at game over, before played): d0 = 0 when the season's playoffs are in progress (flag 1/2)199| and your team plays this game; else -1. Keeps all other registers.200poseason:201 movem.l %d1-%d7/%a0-%a6,-(%sp)202 bsr.w active203 bne.s 8f204 move.w PBUF+6,%d2205 subq.w #1,%d2206 moveq #0,%d0207 move.b 0xFFC331,%d0208 cmp.w %d0,%d2209 beq.s 1f210 move.b 0xFFC333,%d0211 cmp.w %d0,%d2212 bne.s 8f2131: lea TMP,%a0214 move.l #FLAG_OFF,%d0215 moveq #2,%d1216 jsr SRAM_RD217 move.w TMP,%d0218 beq.s 8f219 cmpi.w #3,%d0220 bcc.s 8f221 moveq #0,%d0222 bra.s 9f2238: moveq #-1,%d02249: movem.l (%sp)+,%d1-%d7/%a0-%a6225 tst.w %d0226 rts227228clrflag:229 movem.l %d0-%d7/%a0-%a6,-(%sp)230 moveq #0,%d0231 bsr.s setflag232 movem.l (%sp)+,%d0-%d7/%a0-%a6233 rts234235| setflag: d0 = value -> SRAM $1210 (word), the hack's checksum ($1FFE = ~sum, $1FFF = sum) kept right236setflag:237 cmpi.w #1,%d0 | jdc r21: the playoffs are set up: clear their statistics block238 bne.s 0f239 jsr 0x2E20082400: movem.l %d0-%d7/%a0-%a6,-(%sp)241 move.w %d0,%d7242 lea TMP,%a0243 move.l #FLAG_OFF,%d0244 moveq #2,%d1245 jsr SRAM_RD246 move.b TMP,%d6 | d6 = - old bytes + new bytes247 add.b TMP+1,%d6248 neg.b %d6249 move.w %d7,%d0250 add.b %d0,%d6251 lsr.w #8,%d0252 add.b %d0,%d6253 move.w %d7,TMP254 lea TMP,%a0255 move.l #FLAG_OFF,%d0256 moveq #2,%d1257 jsr SRAM_WR258 lea TMP,%a0259 move.l #0x1FFE,%d0260 moveq #2,%d1261 jsr SRAM_RD262 move.b TMP+1,%d0263 add.b %d6,%d0264 move.b %d0,TMP+1265 not.b %d0266 move.b %d0,TMP267 lea TMP,%a0268 move.l #0x1FFE,%d0269 moveq #2,%d1270 jsr SRAM_WR271 movem.l (%sp)+,%d0-%d7/%a0-%a6272 rts273274| ---- seeds: the tree and who is in, from the season table in battery RAM275seeds: movem.l %d1-%d7/%a0-%a6,-(%sp)276 lea PBUF,%a0277 move.l #SRAM_OFF,%d0278 move.l #NBYTES,%d1279 jsr SRAM_RD280 cmpi.l #MAGIC,PBUF281 bne.w 90f282 tst.w PBUF+12 | New Season chosen283 bne.w 90f284 | keys285 lea PBUF+16,%a0286 lea KEYS,%a1287 lea TAKEN,%a2288 lea QUAL,%a3289 moveq #0,%d02901: move.w 2(%a0),%d1 | 2 W + OTL + T291 add.w %d1,%d1292 add.w 6(%a0),%d1293 add.w 12(%a0),%d1294 lsl.w #8,%d1295 move.w 8(%a0),%d2 | goal difference, clamped296 sub.w 10(%a0),%d2297 cmpi.w #127,%d2298 ble.s 2f299 moveq #127,%d23002: cmpi.w #-128,%d2301 bge.s 3f302 move.w #-128,%d23033: addi.w #128,%d2304 add.w %d2,%d1305 andi.l #0xFFFF,%d1306 lsl.l #5,%d1307 moveq #31,%d2308 sub.w %d0,%d2309 or.w %d2,%d1 | equal: the lower team index first (as in the tables)310 bset #31,%d1 | never 0 (pick starts from 0)311 move.l %d1,(%a1)+312 clr.b (%a2)+313 clr.b (%a3)+314 lea 16(%a0),%a0315 addq.w #1,%d0316 cmpi.w #32,%d0317 blt.s 1b318 | top 3 of each division319 lea DR,%a4320 moveq #0,%d3 | division3214: moveq #2,%d43225: moveq #0,%d5 | 0 = by division323 bsr.w pick324 move.b %d0,(%a4)+325 lea QUAL,%a0326 move.b #1,(%a0,%d0.w)327 dbra %d4,5b328 addq.w #1,%d3329 cmpi.w #4,%d3330 blt.s 4b331 | each conference: two wild cards, then the tree (conference 1 = West -> slots 0-7, 0 = East -> 8-15)332 moveq #0,%d33336: moveq #1,%d5 | by conference334 bsr.w pick335 move.w %d0,%d6 | WC1336 lea QUAL,%a0337 move.b #2,(%a0,%d0.w)338 bsr.w pick339 move.w %d0,%d7 | WC2340 move.b #2,(%a0,%d0.w)341 lea DR,%a4342 move.w %d3,%d0 | divisions 2c and 2c+1343 add.w %d0,%d0344 mulu.w #3,%d0345 lea (%a4,%d0.w),%a5 | a5 = first division's 3, a6 = second's346 lea 3(%a5),%a6347 lea KEYS,%a0348 moveq #0,%d0349 move.b (%a5),%d0350 lsl.w #2,%d0351 move.l (%a0,%d0.w),%d1352 moveq #0,%d0353 move.b (%a6),%d0354 lsl.w #2,%d0355 cmp.l (%a0,%d0.w),%d1356 bhi.s 7f357 exg %a5,%a6 | the second division's winner is better3587: lea SEEDS+8,%a1 | East359 tst.w %d3360 beq.s 8f361 lea SEEDS,%a1 | West3628: move.b (%a5),(%a1)+ | better winner vs WC2363 move.b %d7,(%a1)+364 move.b 1(%a5),(%a1)+ | 2nd vs 3rd365 move.b 2(%a5),(%a1)+366 move.b (%a6),(%a1)+ | other winner vs WC1367 move.b %d6,(%a1)+368 move.b 1(%a6),(%a1)+369 move.b 2(%a6),(%a1)+370 addq.w #1,%d3371 cmpi.w #2,%d3372 blt.w 6b373 moveq #0,%d0374 bra.s 99f37590: moveq #-1,%d037699: movem.l (%sp)+,%d1-%d7/%a0-%a6377 tst.w %d0378 rts379380| pick: the best team not taken yet in division d3 (d5 = 0) or conference d3 (d5 = 1; 0 East, 1 West) -> d0, taken381pick: movem.l %d1-%d4/%a0-%a2,-(%sp)382 lea KEYS,%a0383 lea TAKEN,%a1384 lea divs,%a2385 moveq #-1,%d0 | best team386 moveq #0,%d1 | best key387 moveq #0,%d2 | team3881: tst.b (%a1,%d2.w)389 bne.s 3f390 moveq #0,%d4391 move.b (%a2,%d2.w),%d4392 tst.w %d5393 beq.s 2f394 lsr.w #1,%d4 | conference3952: cmp.w %d3,%d4396 bne.s 3f397 move.w %d2,%d4398 lsl.w #2,%d4399 cmp.l (%a0,%d4.w),%d1400 bcc.s 3f401 move.l (%a0,%d4.w),%d1402 move.w %d2,%d04033: addq.w #1,%d2404 cmpi.w #32,%d2405 blt.s 1b406 tst.w %d0407 bmi.s 4f408 move.b #1,(%a1,%d0.w)4094: movem.l (%sp)+,%d1-%d4/%a0-%a2410 rts411412| division per team (ANA..WPG): 0 Atlantic, 1 Metropolitan, 2 Central, 3 Pacific (conference = division / 2)413divs: .byte 3,0,0,3,1,2,2,1,2,0,3,0,3,2,0,2,1,1,1,0,1,1,3,3,2,0,0,2,3,3,1,2414 .even415