In Mike Tyson's Punch-Out!! (NES, Rev 1), each opponent move is a script of state data that one interpreter, OppStateUpdate, steps through. A control byte's upper nibble picks a handler, and for upper nibbles $B to $F the lower nibble picks a sub-command from a second table. The commands, named by the disassembly's ST_ constants, load sprites and frame timers, call and return from shared sub-scripts, jump, branch when a zero-page byte holds a given value, repeat a step, mark the opponent as punching, and set the punch's side and damage. At a punch's active step the script waits until the punch is resolved. A landed punch goes on past the step's three index bytes; a blocked, ducked, or dodged one jumps to the first, second, or third index. A path through a move ends with ST_END, which marks the state STAT_FINISHED ("Indicate the end of the current state has been reached", per the comment), or with ST_WAIT_STATE, which stores $81 in OppCurState: the opponent's wait state, in the comment's words. | source_files/PRG_BankDEF.asm L4654–4676source_files/PRG_BankDEF.asm L4889–4896source_files/PRG_BankDEF.asm L5017–5024source_files/Mike_Tysons_Punchout_Defines.asm L508–531source_files/PRG_BankDEF.asm L5028–5072source_files/Mike_Tysons_Punchout_Defines.asm L540–543source_files/PRG_BankDEF.asm L5147–5150source_files/PRG_BankDEF.asm L5259–5264 | Code |
Glass Joe's right hook in the NES Rev 1 is the commented script GJRighHook. It loads defense values, shows sprite data $0A ("6 frames for this sub-state", per the comment), flags the opponent as punching, and writes OPP_RGHT_HOOK to $BB. It then sets OppOutlineTimer to $84, a count of 4 calls of SetOppOutlineClr (the comment: "Change outline color for 4 frames"), and waits a variable time, VariableStTime. At index $1E, ST_CHK_REPEAT jumps to index $24 while its repeat counter, loaded as 1, hasn't run out; with 1 it falls through. If MacStatus holds MAC_SUPER_PUNCH, it branches to index $59; otherwise it starts the punch sound and sets the punch on Little Mac's left side with damage 7, which the comment says is added to base damage. Glass Joe's fight data sets that base damage at 4. At the punch's active step (index $32), a landed punch falls through to index $36: a 4-frame timer (per the comment), sprite moves, and ST_END at index $44. The step gives index $45 for a block, which jumps into his straight punch's state at index $3B, and index $49 for a duck or a dodge, which loads a special timer, sets his defense values to zero, moves his sprites, and waits for the combo timer before the wait state. | source_files/PRG_Bank000.asm L634–709source_files/PRG_Bank000.asm L641–642source_files/PRG_Bank000.asm L685–687source_files/PRG_BankDEF.asm L5130–5143source_files/PRG_Bank000.asm L717–752source_files/PRG_Bank000.asm L710–790source_files/PRG_Bank000.asm L1078–1081source_files/PRG_BankDEF.asm L4938–4941source_files/PRG_Bank000.asm L1100–1113 | Code |
The NES Rev 1 cues a dodge by recoloring the opponent's outline. A script writes OppOutlineTimer with its high bit set; the main game loop calls SetOppOutlineClr, which then clears that bit, keeps the count, and writes the fight's dodge outline color into four sprite palette entries. Each later call counts the timer down, and at zero it writes the normal color back. Glass Joe's fight data gives palette values $26 for the dodge outline and $08 for the normal one, and his right hook sets the timer to $84, a count of 4 later calls (4 frames by the comment), before its variable wait and the punch. | source_files/Mike_Tysons_Punchout_Defines.asm L66source_files/PRG_BankDEF.asm L4493–4530source_files/PRG_BankDEF.asm L725–763source_files/Mike_Tysons_Punchout_Defines.asm L224source_files/PRG_Bank000.asm L1139–1140source_files/PRG_Bank000.asm L677–683 | Code |
Little Mac's hearts in the NES Rev 1 are a two-digit decimal count. Glass Joe's fight data, in its comments, starts rounds 1, 2, and 3 at 20, 20, and 15 hearts, with normal recoveries of 15, 15, and 10 and reduced ones of 9, 9, and 5. The round setup routine, uncommented (it also loads the round's clock rate and starts the round timer), sets hearts to the table's value in round 1 and raises them to it in rounds 2 and 3 if they're lower, and it copies the two recovery values for the round. An uncommented routine at $843E takes hearts away, 1 or 3 at each of its six callers; when the count reaches zero or below it clears MacCanPunch, which the define reads as "Little Mac can't punch". | source_files/PRG_Bank000.asm L1100–1112source_files/Mike_Tysons_Punchout_Defines.asm L207source_files/PRG_BankDEF.asm L2733–2786source_files/PRG_Bank007.asm L514–535source_files/PRG_Bank007.asm L109–110source_files/PRG_Bank007.asm L163–164source_files/Mike_Tysons_Punchout_Defines.asm L94 | Code |
The NES Rev 1 picks an opponent's next move with a second, uncommented script reader at $B196, run from the main game loop. While $38 is nonzero and OppCurState is 1 (the wait state, in the atlas's reading of the defines), it decrements $39 on each call and, when that reaches zero, reads a list of command bytes. In the atlas's reading of the code: 0n s sets OppCurState to s and $39 to n, the count of calls before the next command (n = 0 gives 256, as $39 wraps to $FF); 1n i jumps to list index i when n is greater than the low four bits of a random byte, n/16 of the time (computed), and always when n is 15; and 2n with eight state bytes after it sets $39 to n and starts one of the eight, chosen by the random byte's low three bits. The random byte is $18, which an uncommented routine at $85E9 in bank 7 sets to the sum of two scrambles: $ED, bits of FrameCounter moved to new positions, and $EC, moved bits of $19 with $19 AND $81 ORed in. $19 is a running total, kept from call to call, to which each call adds moved bits of Joy1Buttons. Two paths of the NMI handler call the routine, each right after it increments FrameCounter. $AEF1 rotates $18 three times after each read. Bytes from $80 up hold other commands, not read here. | source_files/PRG_BankDEF.asm L725–752source_files/PRG_BankDEF.asm L2213–2261source_files/PRG_BankDEF.asm L1731–1745source_files/PRG_BankDEF.asm L1783–1786source_files/PRG_Bank007.asm L725–831source_files/PRG_Bank007.asm L12source_files/PRG_BankDEF.asm L705–710source_files/PRG_BankDEF.asm L802–827source_files/Mike_Tysons_Punchout_Defines.asm L53 | Code |
When KnockdownSts is 1 ("Opp down", per the define) in the NES Rev 1, uncommented code at $B2EB counts the knockdown in OppKDRound and OppKDFight, and at the third in a round it stops there. Otherwise, unless $BA held $FF, it reads one entry from the opponent's table at OppRefillPtr (its index set by conditions not traced here). An entry of 0 sets nothing. An entry whose upper nibble n is nonzero sets OppGetUpCount to $99 + n, which the define reads as a count of n. An entry whose upper nibble is 0 picks one of the eight entries of OppGetUpTable with three bits of the random byte $18; Glass Joe's eight read, by the comment's encoding, 2, 3, 4, 5, 6, 8, 3, and 4. | source_files/PRG_BankDEF.asm L2386–2466source_files/PRG_BankDEF.asm L2380–2385source_files/Mike_Tysons_Punchout_Defines.asm L14source_files/Mike_Tysons_Punchout_Defines.asm L100source_files/PRG_Bank000.asm L1134–1135 | Code |