Mechanic · enemies & ai · action, fighting game, boxing
Attack pattern
The fixed or partly random sequence of moves a computer opponent works through, which players learn and exploit.
On this page
An attack pattern is the order of moves an opponent follows. Mike Tyson’s Punch-Out!! writes each move as a script of timed steps1 and picks the next one from a list in which some steps go by chance2. Glass Joe’s right hook is one such script3.
- Script and chanceMike Tyson's Punch-Out!! (1987). Each move is a script of timed steps that branches on block, duck, or dodge; a selector list picks the next, some steps by an n-in-16 roll.1,2,3
Games
| Game | Year | How | Note |
|---|---|---|---|
| Mike Tyson's Punch-Out!! | 1987 | Script and chance | each move is a script of timed steps that branches on block, duck, or dodge; a selector list picks the next, some steps by an n-in-16 roll |
Every claim about this mechanic, by game (3)
References
- ^ abIn 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
$Bto$Fthe 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$81in OppCurState: the opponent's wait state, in the comment's words.Codenmikstas/mike-tysons-punch-out-disassemblyrevisedHow we know
4654;This function is the entry point for updating the opponent's state. It uses the upper nibble of 4655;a control byte to pick a function to run from the table below. The function it calls may then 4656;call another set of functions with the lower nibble of the same control byte(or it may not). ⋮ 4664LC556: AND #$0F ;Keep lower nibble for later. ⋮ 4670LC55C: JSR Div16 ;($BF99)Shift upper nibble to lower nibble. 4671LC55F: JSR IndFuncJump ;($AED4)Indirect jump to desired function below. ⋮ 4673LC562: .word OppLoadSprites, SpritesNxtXYState, $C5B3, $C5B7 4674LC56A: .word $C5C8, $C5CE, SprtMove, OppMoveSprites 4675LC572: .word OppSetTimer, $C600, OppBigMove, OppStateUpdate1 4676LC57A: .word OppStateUpdate1, OppStateUpdate1, OppStateUpdate1, OppStateUpdate2
source_files/PRG_BankDEF.asm lines 4654–4676 at 60b2fa0 · upstream ↗ 4889OppStateUpdate1: 4890LC670: TXA ;Get index into table below. 4891LC671: JSR IndFuncJump ;($AED4)Indirect jump to desired function below. ⋮ 4893LC674: .word OppCallFunc, OppReturnFunc, NULL_PNTR, NULL_PNTR 4894LC67C: .word OppVarStTime, OppNotPunch, $C6CA, $C6D7 4895LC684: .word $C6DF, $C6EA, NULL_PNTR, NULL_PNTR 4896LC68C: .word InitAudio
source_files/PRG_BankDEF.asm lines 4889–4896 at 60b2fa0 · upstream ↗ 5017OppStateUpdate2: 5018LC720: TXA ;Get index into table below. 5019LC721: JSR IndFuncJump ;($AED4)Indirect jump to desired function below. ⋮ 5021LC724: .word PunchActive, OppStateJump, ChkMemAndBranch, ChkRepeatState 5022LC72C: .word OppWaitState, OppRepeat, OppPunchDirDmg, OppDefInline 5023LC734: .word $C7E1, OppPunch, WriteZPageByte, OppSpecTimer 5024LC73C: .word OppComboWait, $C816, $C81D, StateDone
source_files/PRG_BankDEF.asm lines 5017–5024 at 60b2fa0 · upstream ↗ 508.alias ST_SPRITES $00 ;Load sprite data for current opponent sub-state. ⋮ 513.alias ST_TIMER $80 ;Number of frames for sub-state to wait. ⋮ 515.alias ST_CALL_FUNC $E0 ;Call an opponent state subroutine. 516.alias ST_RETURN_FUNC $E1 ;Return from an opponent state subroutine. ⋮ 519.alias ST_PNCH_ACTIVE $F0 ;Indicates an opponent's punch is active. 520.alias ST_JUMP $F1 ;Jump to new state base address and index. 521.alias ST_CHK_BRANCH $F2 ;Check memory for value and branch in state data if value found. 522.alias ST_CHK_REPEAT $F3 ;Check if a sub-state needs to repeat. 523.alias ST_WAIT_STATE $F4 ;Put opponent into wait state. 524.alias ST_REPEAT $F5 ;Load a repeat value for this sub-state. 525.alias ST_PUNCH_SIDE $F6 ;Indicate what side of Little Mac a punch is approaching. ⋮ 527.alias ST_PUNCH $F9 ;Indicate the opponent is punching. ⋮
source_files/Mike_Tysons_Punchout_Defines.asm lines 508–531 at 60b2fa0 · upstream ↗ 5028PunchActive: 5029LC744: LDX OppPunchSts ;Is the punch initialized but not yet processed? 5030LC746: BMI OppStateWait ;If so, branch. ⋮ 5038LC74E: DEC OppStateIndex ;Stay on this state and exit. ⋮ 5042LC751: CPX #PUNCH_LANDED ;Was punch landed? 5043LC753: BEQ PunchLanded ;If so, branch. ⋮ 5045LC755: BCC PunchBlckDck ;Was punch blocked or ducked? If so, branch. ⋮ 5048LC757: DEX ;Dodged punch must have index increased by 2 (4-2=2). ⋮ 5051LC758: DEX ;Only decrement punch status by 1 for block/duck. 5052LC759: TXA ; 5053LC75A: CLC ; 5054LC75B: ADC OppStateIndex ;Get the index to jump to for blocked/ducked or dodged punches. ⋮
source_files/PRG_BankDEF.asm lines 5028–5072 at 60b2fa0 · upstream ↗ 540.alias PUNCH_BLOCKED $01 ;Punch blocked by Little Mac. 541.alias PUNCH_DUCKED $02 ;Punch is ducked by Little Mac. 542.alias PUNCH_LANDED $03 ;Punch hit Little Mac. 543.alias PUNCH_DODGED $04 ;Punch dodged by Little Mac.
source_files/Mike_Tysons_Punchout_Defines.asm lines 540–543 at 60b2fa0 · upstream ↗ 5147OppWaitState: 5148LC7B6: LDA #$81 ; 5149LC7B8: STA OppCurState ;Put the opponent into their wait state.
source_files/PRG_BankDEF.asm lines 5147–5150 at 60b2fa0 · upstream ↗ 5259StateDone: 5260LC821: DEC OppStateIndex ; 5261LC823: LDA #STAT_FINISHED ;Indicate the end of the current state has been reached. ⋮ 5264LC825: STA OppStateStatus ;
source_files/PRG_BankDEF.asm lines 5259–5264 at 60b2fa0 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-22.
- ^ abThe NES Rev 1 picks an opponent's next move with a second, uncommented script reader at
$B196, run from the main game loop. While$38is nonzero and OppCurState is 1 (the wait state, in the atlas's reading of the defines), it decrements$39on each call and, when that reaches zero, reads a list of command bytes. In the atlas's reading of the code:0n ssets OppCurState tosand$39to n, the count of calls before the next command (n = 0 gives 256, as$39wraps to$FF);1n ijumps to list indexiwhen n is greater than the low four bits of a random byte, n/16 of the time (computed), and always when n is 15; and2nwith eight state bytes after it sets$39to 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$85E9in bank 7 sets to the sum of two scrambles:$ED, bits of FrameCounter moved to new positions, and$EC, moved bits of$19with$19AND$81ORed in.$19is 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.$AEF1rotates$18three times after each read. Bytes from$80up hold other commands, not read here.Codenmikstas/mike-tysons-punch-out-disassemblyrevisedHow we know
725MainGameEngine: ⋮ 752LA6A2: JSR $B196
source_files/PRG_BankDEF.asm lines 725–752 at 60b2fa0 · upstream ↗ 2213LB196: LDA $38 2214LB198: BEQ $B1CD 2215LB19A: LDX OppCurState 2216LB19C: DEX 2217LB19D: BNE $B1CD 2218LB19F: DEC $39 2219LB1A1: BNE $B1CD 2220LB1A3: INC $39 2221LB1A5: LDY $3A 2222LB1A7: LDA ($3B),Y 2223LB1A9: AND #$0F 2224LB1AB: TAX ⋮
source_files/PRG_BankDEF.asm lines 2213–2261 at 60b2fa0 · upstream ↗ 1731LAEAB: STA $EF 1732LAEAD: LDA #$0F 1733LAEAF: STA $EE 1734LAEB1: LDA $EF 1735LAEB3: CMP $EE 1736LAEB5: BEQ $AEC7 1737LAEB7: LDA $18 1738LAEB9: JSR $AEF1 1739LAEBC: AND $EE 1740LAEBE: STA $EE 1741LAEC0: LDA $EF 1742LAEC2: CMP $EE ⋮
source_files/PRG_BankDEF.asm lines 1731–1745 at 60b2fa0 · upstream ↗ 1783LAEF1: ROR $18 1784LAEF3: ROR $18 1785LAEF5: ROR $18 1786LAEF7: RTS
source_files/PRG_BankDEF.asm lines 1783–1786 at 60b2fa0 · upstream ↗ 725L85E9: LDA FrameCounter ;($1E) 726L85EB: ROR 727L85EC: STA $E8 ⋮ 733L85F5: AND #$08 734L85F7: STA $ED ⋮ 759L8625: STA $ED 760L8627: LDA Joy1Buttons ⋮ 789L865C: ORA $EC 790L865E: CLC 791L865F: ADC $19 792L8661: STA $19 793L8663: ROR ⋮
source_files/PRG_Bank007.asm lines 725–831 at 60b2fa0 · upstream ↗ 12L8012: JMP $85E9source_files/PRG_Bank007.asm line 12 at 60b2fa0 · upstream ↗ 705LA644: INC FrameCounter ;($1E) ⋮ 709LA64C: JSR PushPRGBank07 ;($AA3C) 710LA64F: JSR $8012
source_files/PRG_BankDEF.asm lines 705–710 at 60b2fa0 · upstream ↗ 802LA6F8: INC FrameCounter ;($1E) ⋮ 826LA724: JSR PushPRGBank07 ;($AA3C) 827LA727: JSR $8012
source_files/PRG_BankDEF.asm lines 802–827 at 60b2fa0 · upstream ↗ 53.alias OppCurState $90 ;Opponent's current state. Set MSB=initialize new state.source_files/Mike_Tysons_Punchout_Defines.asm line 53 at 60b2fa0 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-22.
- ^ abGlass 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$24while 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$45for a block, which jumps into his straight punch's state at index$3B, and index$49for 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.Codenmikstas/mike-tysons-punch-out-disassemblyrevisedHow we know
634GJRighHook: ⋮ 637L8C4D: .byte ST_CALL_FUNC ;Call state data subroutine 638L8C4E: .word DefenseStats3 ;Defense data pointer. ⋮ 649L8C54: .byte ST_SPRITES_XY+6 ;Load sprites, change position, 6 frames for this sub-state. ⋮ 655L8C58: .byte ST_PUNCH ;Indicate opponent is punching. ⋮ 658L8C59: .byte ST_DEFENSE ;Load opponent's defense data from following 4 bytes. ⋮ 664L8C5F: .byte ST_WRITE_BYTE ;Write a byte to zero page memory. 665L8C60: .byte GameStatusBB ;address $BB. 666L8C61: .byte OPP_RGHT_HOOK ;Indicate a right hook is being thrown. ⋮ 678L8C67: .byte ST_WRITE_BYTE ;Write a byte to zero page memory. 679L8C68: .byte OppOutlineTimer ;Change opponent's outline color to indicate its time to dodge. 680L8C69: .byte $84 ;Change outline color for 4 frames. ⋮
source_files/PRG_Bank000.asm lines 634–709 at 60b2fa0 · upstream ↗ 641L8C50: .byte ST_REPEAT ;Load sub-state repeat. 642L8C51: .byte $01 ;No repeat for this sub-state.
source_files/PRG_Bank000.asm lines 641–642 at 60b2fa0 · upstream ↗ 685;Index #$1E. 686L8C6B: .byte ST_CHK_REPEAT ;Check if repeat counter is active. 687L8C6C: .byte $24 ;Jump to index #$24 is repeat counter is active.
source_files/PRG_Bank000.asm lines 685–687 at 60b2fa0 · upstream ↗ 5130ChkRepeatState: 5131LC7A7: DEC OppStRepeatCntr ;Decrement sub-state repeat counter. 5132LC7A9: BEQ ChkRepeatEnd ;Does state need to be repeated? If not, branch to exit.
source_files/PRG_BankDEF.asm lines 5130–5143 at 60b2fa0 · upstream ↗ 717;Index #$32. 718L8C7F: .byte ST_PNCH_ACTIVE ;Indicate a punch is active. ⋮ 723;Index #$36 - Punch landed. 724L8C83: .byte ST_TIMER ;Load timer for this sub-state. 725L8C84: .byte $04 ;This sub-state lasts 4 frames. ⋮ 728L8C85: .byte ST_SPRT_MV_NU+4 ;Move sprites. Sub-state lasts for 4 frames. ⋮ 744L8C8D: .byte ST_SPRT_MV_NU+15 ;Move sprites. Sub-state lasts for 15 frames. ⋮ 751;Index #$44. 752L8C91: .byte ST_END ;End of state.
source_files/PRG_Bank000.asm lines 717–752 at 60b2fa0 · upstream ↗ 718L8C7F: .byte ST_PNCH_ACTIVE ;Indicate a punch is active. 719L8C80: .byte $45 ;Index to jump to if punch was blocked. 720L8C81: .byte $49 ;Index to jump to if punch was ducked. 721L8C82: .byte $49 ;Index to jump to if punch was dodged. ⋮ 755L8C92: .byte ST_JUMP ;Jump to new state and index. 756L8C93: .word GJStrtPunch ;Base address of new state. 757L8C95: .byte $3B ;Index of new state. ⋮ 760L8C96: .byte ST_SPEC_TIMER ;Load a special timer value. ⋮ 763L8C97: .byte ST_CALL_FUNC ;Call state data subroutine 764L8C98: .word DefenseStats6 ;Defense data pointer. ⋮ 787L8CA4: .byte ST_COMBO_WAIT ;Wait for the combo timer to expire. ⋮ 790L8CA5: .byte ST_WAIT_STATE ;Put opponent into wait state.
source_files/PRG_Bank000.asm lines 710–790 at 60b2fa0 · upstream ↗ 1078DefenseStats6: 1079L92B0: .byte ST_DEFENSE ;Load opponent's defense data from following 4 bytes. 1080L92B1: .byte $00, $00 ;Face punch defense values. 1081L92B3: .byte $00, $00 ;Stomach punch defense values.
source_files/PRG_Bank000.asm lines 1078–1081 at 60b2fa0 · upstream ↗ 4938OppVarStTime: 4939LC6BD: LDA VariableStTime ; 4940LC6C0: STA OppStateTimer ;Set a varying amount of time for this opponent's state time.
source_files/PRG_BankDEF.asm lines 4938–4941 at 60b2fa0 · upstream ↗ 1100;Glass Joe Fight data. Loaded into $05A0 through $05FF. ⋮ 1113L9325: .byte $04 ;Base damage if opponent lands a hit on Little Mac.
source_files/PRG_Bank000.asm lines 1100–1113 at 60b2fa0 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-22.
Sources
Code
- (nmikstas), Nick Mikstas. 2020. “Mike Tyson's Punch-Out!! (NES), partial disassembly (nmikstas).” Commit 60b2fa0. nmikstas/mike-tysons-punch-out-disassembly @ 60b2fa0 · licence, all uses