We just released a Feb. 5 '89 prototype of DuckTales for the NES!
If you'd like to support our preservation efforts (and this wasn't cheap), please consider donating or supporting us on Patreon. Thank you!

Notes:Final Fight 2

From The Cutting Room Floor
Jump to navigation Jump to search

This page contains notes for the game Final Fight 2.

Addresses on this page correspond to the USA version unless noted otherwise.


80811A, execute - accumulator holds start addresses of palette (+830000)
8180B1, execute - accumulator holds sound effect index to play

(Source: JLukas)

Enemy List

These Pro Action Replay codes can be used to change the first two enemies that appear at the beginning of the first stage. Presumably, U.Andore and F.Andore would've used values 0603, 0604, respectively, but no slots are reserved for them.



Alternately, change the following values directly in a hex editor:


Enemy Index, Name
0300 Mic 
0301 Schot 
0302 Bull 
0303 Mark 
0304 Jack 
0305 Elijah 

For the group above, add 10 to the second byte to make the enemy spawn in a "Kneeling, facing right" position. Add 20 to make them spawn "Kneeling, facing left". As two examples, the codes for the first two kneeling enemies early in stage 1-1 are 0310 (Mic kneeling facing right) and 0323 (Mark kneeling facing left)

Enemy Index, Name
0400 Elick 
0500 Atlas 
0501 Jony 
0600 Andore Jr. 
0601 Andore 
0602 G.Andore 
0700 Leon 
0701 Robert 
0800 Eliot 
0801 Elias 
0900 Joe 
0A00 Won Won 
0B00 Freddie 
0C00 Bratken 
0D00 Philippe 
0E00 Rolent 
0F00 Retu 

(Source: Emptyeye (The direct addresses to change; info about Group 3 kneeling spawns), JLukas (Everything else in the section))

Enemy Names

The enemy names are stored in the chunk of memory beginning at 00016A4B and ending at 00016B9A when viewed in a hex editor. The data for a given enemy is 12 bytes long--the first byte is presumably a pointer to the enemy icon, but this isn't known for sure. Then there's white space, and finally the enemy name. In other words, the enemy names are left-padded with spaces. Note that the first three entries are currently not known as to what they actually are (Possibly encrypted data for displaying the player character names/icons?). "Plaintext" enemy data, therefore, begins at 00016A6F.

For example, to change Mic's name to Michael, you would change the row of data found at 00016A70:

20 20 20 20 20 20 20 20 4D 49 43 04 20 20 20 20 |        MIC.    |


20 20 20 20 4D 49 43 48 41 45 4C 04 20 20 20 20 |    MICHAEL.    |

Do not change it to the below. More accurately, while you can change it to the below, you won't get the results you expect--Mic will still be called Mic, while Schot won't have a name and will have gibberish for an icon.

20 20 20 20 20 20 20 20 4D 49 43 48 41 45 4C 04 |        MICHAEL.|

(Source: Emptyeye)

Player Character Stats

The following addresses correspond to the statistics for the three playable characters, their starting health, and their attacks. Numbers in parentheses in the comments are the corresponding decimal values.

When viewed in a hex editor, the corresponding beginning address is 00016B9B.

82EB9B	8D	
82EB9C	00	//Maki's starting/maximum health. 2 bytes, lower byte first (141)
82EB9D	00	//Maki's defense (00)
82EB9E	2E	//Maki's Extra Joy damage (46)
82EB9F	1E	//Maki's knife damage (30)
82EBA0	1E	//Maki's tonfa damage (30)
82EBA1	14	//Maki's 2X4 damage (20)
82EBA2	08	//Damage of Maki's first knee after grabbing an enemy (8)
82EBA3	0E	//Damage of Maki's second knee after grabbing an enemy (14)
82EBA4	18	//Damage of Maki's third knee after grabbing an enemy (24)
82EBA5	1C	//Damage of Maki's throw (28)
82EBA6	08	//Damage taken by an enemy "catching" a thrown enemy (8)
82EBA7	06	//Damage of Maki's basic jab (6)
82EBA8	08	//Damage of the third hit in Maki's combo (8)
82EBA9	0C	//Damage of the fourth hit in Maki's combo (12)
82EBAA	14	//Damage of the last hit in Maki's combo (20)
82EBAB	0C	//Damage of Maki's "standing" jump kick (12)
82EBAC	08	//Damage of Maki's "Down+Attack" in the air (8)
82EBAD	0E	//Damage of Maki's "flying" jump kick  (14)

82EBAF	00	//Haggar's starting/maximum health. 2 bytes, lower byte first (141)
82EBB0	00	//Haggar's defense (00)
82EBB1	24	//Haggar's Extra Joy damage (36)
82EBB2	1E	//Haggar's knife damage (30)
82EBB3	1E	//Haggar's tonfa damage (30)
82EBB4	14	//Haggar's 2X4 damage (20)
82EBB5	0A	//Damage of Haggar's first headbutt after grabbing an enemy (10)
82EBB6	10	//Damage of Haggar's second headbutt after grabbing an enemy (16)
82EBB7	24	//Damage of Haggar's third headbutt after grabbing an enemy (36)
82EBB8	24	//Damage of Haggar's suplex (36)
82EBB9	08	//Damage taken by an enemy "catching" a suplexed/piledriven enemy (8)
82EBBA	28	//Damage of Haggar's spinning piledriver (40)
82EBBB	12	//Damage of Haggar's basic jab (18)
82EBBC	12	//Damage of the last hit in Haggar's combo (18)
82EBBD	14	//Damage of any of Haggar's flying attacks (20)
82EBBE	08	//?? Unknown at this time

82EBC0	00	//Carlos's starting/maximum health. 2 bytes, lower byte first (141)
82EBC1	00	//Carlos's defense (00)
82EBC2	24	//Carlos's Extra Joy damage (36)
82EBC3	1E	//Carlos's knife damage (30)
82EBC4	1E	//Carlos's tonfa damage (30)
82EBC5	14	//Carlos's 2X4 damage (20)
82EBC6	09	//Damage of Carlos's first knee after grabbing an enemy (9)
82EBC7	10	//Damage of Carlos's second knee after grabbing an enemy (16)
82EBC8	1C	//Damage of Carlos's third knee after grabbing an enemy (28)
82EBC9	08	//Damage taken by an enemy "catching" a thrown enemy (8)
82EBCA	1C	//Damage of Carlos's throw (28)
82EBCB	0A	//Damage of Carlos's basic jab (10)
82EBCC	0A	//Damage of the third hit in Carlos's combo (10)
82EBCD	10	//Damage of the last hit in Carlos's combo (10)
82EBCE	0C	//Damage of Carlos's "standing" jump kick (12)
82EBCF	08	//Damage of Carlos's "Down+Attack" in the air (8)
82EBD0	0E	//Damage of Carlos's "flying" jump kick  (14)

(Source: Emptyeye)

Enemy Stats

The enemy statistics begin immediately after the above player statistics (Viewed in a hex editor, beginning at 00016BD1). The format is as follows:

-The life of the "group" of enemies, in two bytes (Smaller byte first), for each of 32 potential "internal" difficulty levels. This takes up a total of 64 bytes.
-The defense of the group, taking up 32 bytes, one for each potential internal difficulty.
-Numerous groups of 32 bytes, presumably attack values for that group's various attacks.

The beginning addresses for each group are the following locations. Group numbers correspond to the first byte in the "Enemy Index" section above:

Group 03 (Mic/Schot/Bull/Mark/Jack/Elijah): 82EBD1
Group 04 (Elick): 82ECD1
Group 05 (Jony/Atlas): 82EDB1
Group 06 (Andore Jr./Andore/G.Andore): 82EEB1
Group 07 (Leon/Robert): 82EFF1
Group 08 (Elias/Eliot): 82F111
(Group 09, the Joes, do not seem to appear in this block. Perhaps their data is all hard-coded elsewhere)
Group 0A (Won Won): 82F1D1
Group 0B (Freddie): 82F2F1
Group 0C (Bratken): 82F451
Group 0D (Philippe): 82F5D1
Group 0E (Rolent): 82F6B1
Group 0F (Retu): 82F791

(Source: Emptyeye)

The Ranking System

To do:
Research the difficulties that aren't normal to confirm they work the same way. Also figure out how the Joe enemies work--the game handles them completely differently than every other enemy/enemy group, but the specifics are unknown right now.

An arcade-style ranking system is used in the game in at least some capacity--each difficulty adjusts starting rank, maximum rank, and how quickly rank increases. Further, the game checks rank every time damage is given or received. Funnily, though, on Normal difficulty, only one enemy in the whole game is definitely affected by this rank (Philippe, the boss of Stage 4), and that one enemy always has 0 defense regardless of their rank!

The ranking system itself is similar, though not identical, to Final Fight SNES's ranking system. There are a total of 32 possible ranks, from 00 to 31 (1F). Every so often, the rank increases--again, how fast is determined by the difficulty.

Where Final Fight 2 differs from its predecessor is in how rank is decreased. There's no decrease on losing a life. Instead, the rank reverts to the starting rank of the chosen difficulty each time you clear a section of a stage (A section being defined as the screen fading out and back in).

The code that checks whether or not to increase the rank each frame is below. In a hex editor, this code begins at 000055B2:

$80/D5B2 C2 20		REP #$20	//Set status to 16-bit
$80/D5B4 AD D6 AD	LDA $ADD6	
$80/D5B7 1A		INC 		//Increment frame counter (Stored in 7EADD6) 
$80/D5B8 CD D4 AD	CMP $ADD4	//Compare to 7EADD4 (How often to increment rank [Every X frames])
$80/D5BB 90 16		BCC $D5D3	//SKIP rank incrementing/zeroing out frame count if NOT time to increment
$80/D5BD E2 20		SEP #$20	//Set status to 8-bit
$80/D5BF AD D8 AD	LDA $ADD8	
$80/D5C2 1A		INC		//Otherwise, load and increment rank
$80/D5C3 CD D3 AD	CMP $ADD3	
$80/D5C6 90 03		BCC $D5CB	
$80/D5C8 AD D3 AD	LDA $ADD3	//If necessary (IE new rank is > max allowed rank), set rank to max allowed rank.
$80/D5CB 8D D8 AD	STA $ADD8	//Store new rank
$80/D5CE C2 20		REP #$20	//Set status to 16-bit
$80/D5D0 A9 00 00	LDA #$0000	//zero out frame counter (If necessary--only after incrementing rank)
$80/D5D3 8D D6 AD	STA $ADD6	//store new frame counter value
$80/D5D6 60 		RTS 		//Return

(Source: Emptyeye)

Starting, Maximum, and Change Frequency of Rank

The below table shows the memory for where the values of the starting rank, maximum rank, and frequency of change of rank is stored in the ROM. Viewed in a hex editor, the corresponding beginning address is 0001D872. Decimal conversions of the values are provided in parantheses at the end of the comments.

83D872	00	//Easy starting rank (0)
83D873	17	//Easy maximum rank (23)
83D874	03	//Normal starting rank (3)
83D875	19	//Normal maximum rank (25)
83D876	05	//Hard starting rank (5)
83D877	1B	//Hard maximum rank (27)
83D878	07	//Expert starting rank (7)
83D879	1D	//Expert maximum rank (29)
83D87A	58 02	//Easy rank change frequency (600) (10 seconds)
83D87C	03	
83D87D	02	//?? These two bytes are unknown at this time. 
83D87E	58 02	//Normal rank change frequency (600) (10 seconds)
83D880	02	
83D881	01	//?? These two bytes are unknown at this time. 
83D882	E0 01	//Hard rank change frequency (480) (8 seconds)
83D884	01	
83D885	01	//?? These two bytes are unknown at this time. 
83D886	2C 01	//Expert rank change frequency (300) (5 seconds)
83D888	01	
83D889	00	//?? These two bytes are unknown at this time

The placement of the unknown bytes, and the values of the first unknown byte in each set, suggest either that the rank system was at one point meant to work like Final Fight SNES, IE where rank would slightly decrease on losing a life, or that Capcom just kept the leftover rank code from Final Fight SNES rather than completely cleaning it up. Rank does not decrease on losing a life in Final Fight 2.

Also notice that the maximum rank on Expert difficulty is 29, although enemies can be (And are--at least one boss on Expert difficulty is hard-coded with a rank of 31) hard-coded with ranks higher than that. More generally, enemies can be hard coded with a rank higher than the maximum rank of the difficulty.

(Source: Emptyeye)

The Damage Formula

Determining damage to an enemy is pretty simple:
-Take the value of the attack in the "Player Character Stats" section above.
-Multiply that value by (32 - enemy defense)
-Divide that result by 32
-Round down, if necessary

Note that this formula is also used for determining damage from an enemy to the player. However, since all three player characters have a defense value of 00 (See the Player Character Stats section above), this simplifies to always being the value of the enemy attack.

(Source: Emptyeye)

Display 8 or 16-bit value

The programming to display an 8-bit hex value is used (by the continue countdown timer in 2P mode when one player runs out of lives), but not the 16-bit part. No pattern matches for 22468580 (JSL $808546) were found.

Display 16-bit value
$80/8546 E2 20       SEP #$20
$80/8548 48          PHA                     //Push the upper 8 bits to display later
$80/8549 EB          XBA
$80/854A 22 51 85 80 JSL $808551[$80:8551]   //Display 8-bit value
$80/854E E2 20       SEP #$20
$80/8550 68          PLA                     //Pull the upper 8 bits
Display 8-bit value
$80/8551 48          PHA
$80/8552 C2 30       REP #$30
$80/8554 29 F0 00    AND #$00F0              //Keep only upper 4 bits (first digit)
$80/8557 4A          LSR A
$80/8558 4A          LSR A
$80/8559 4A          LSR A
$80/855A AA          TAX
$80/855B BF 7F E4 82 LDA $82E47F,x           //Get tile index
$80/855F 99 3E 22    STA $223E,y             //Store to tilemap
$80/8562 C8          INY
$80/8563 C8          INY
$80/8564 E2 20       SEP #$20
$80/8566 68          PLA
$80/8567 C2 20       REP #$20
$80/8569 29 0F 00    AND #$000F              //Keep only lower 4 bits (second digit)
$80/856C 0A          ASL A
$80/856D AA          TAX                     //
$80/856E BF 7F E4 82 LDA $82E47F,x           //Get tile index
$80/8572 99 3E 22    STA $223E,y             //Store to tilemap
$80/8575 C8          INY
$80/8576 C8          INY
$80/8577 6B          RTL

Tile Index Values

82E47F 3028 3128 3228 3328 3428 3528 3628 3728 0(1(2(3(4(5(6(7(
82E48F 3828 3928 4128 4228 4328 4428 4528 4628 8(9(A(B(C(D(E(F(

(Source: JLukas)

Same Player Cheat

$80/A886 BD A4 AD    LDA $ADA4,x             //Load the set of player button presses starting at 7EADA4
$80/A889 DF D6 E4 82 CMP $82E4D6,x           //Compare to stored button presses table starting at 82E4D6
$80/A895 A9 00 4C    LDA #$4C00              //Set background to blue
$80/A898 8D 3E 20    STA $203E  [$7E:203E]
$80/A89B E2 20       SEP #$20
$80/A89D EE CD AD    INC $ADCD  [$7E:ADCD]   //Turn on same player cheat

(Source: JLukas)

Stored Button Presses Table

82E4D6 0004 = down
82E4D8 0004 = down
82E4DA 0008 = up
82E4DC 0008 = up
82E4DE 0001 = right
82E4E0 0002 = left
82E4E2 0001 = right
82E4E4 0002 = left
82E4E6 2000 = L
82E4E8 1000 = R

(Source: JLukas)


Copy $20 byte palettes from ROM to RAM. The starting ROM address for palettes is $83F560
$80/8117 69 60 F5    ADC #$F560
$80/811A AA          TAX
$80/811B A9 1F 00    LDA #$001F
$80/811E 54 7E 83    MVN 83 7E

(Source: JLukas)

Palette Offsets

Offset, Enemy index, Palette index, Name

83F560 ----     Maki
83F580 ----     Haggar
83F5A0 ----     Carlos
83F5C0 0300     Mic
83F5E0 0301     Schot
83F600 0302     Bull
83F620 0800     Eliot
83F640 0400     Elick
83F660 0500     Atlas
83F6A0 ----     Drumcan
83F6E0 0600 $0C Andore Jr.
83F700 0601 $0D Andore
83F720 0602 $0E G.Andore
83F740 0801     Elias
83F760 0A00     Won Won
83F800 ----     (yellow border around character portrait on character select screen)
83F820 0303     Mark
83F840 0304     Jack
83F860 0305     Elijah
83F920 0501     Jony
83FAA0 0E00     Rolent
83FBA0 ----     Bottle
83FD60 0900     Joe
83FD80 0700     Leon
83FDA0 0701     Robert
83FDC0 ----     Maki (same player 2P mode, blue)
83FDE0 ----     Haggar (same player 2P mode, blue)
83FE00 ----     Carlos (same player 2P mode, orange)
83FE20 ----
83FE40 ----     (identical to 83FE20) - A duplicate set is found in the Japanese version (ie, it has 4 copies total of this palette) This may be unused in the USA version.
83FE60-83FFFF unused space ($01A0 bytes)

(Source: JLukas)

Music Pointers

In a hex editor, the following values correspond to the music indexes for various points in the game. To change the track that loads, change these values. The values correspond to their value in the sound test plus 10 --in other words, if you want to make music 03 play in an area, use 13 as the value. For song 0E, use 1E. And so on.

For byte 2414B and 2414E, "through" means the music simply keeps playing within those sections instead of resetting or changing. This also applies to Round 2 and 3, which have only one song each.

3A2E 	Capcom screen
2BBD 	First intro song
2F29 	Second intro song
5C41	Character select
56F6 	"Intro to Round 1"
14435	Round 1-1
24140	Round 1-2
24141 	Round 1-3
14667 	Round clear for Round 1 through 5
24142  	Round 2
E4C9 	Bonus Round (Both of them)
24146	Round 3
24148	Round 4-1
24149 	Round 4-2
2414B 	Round 5-1 through 5-2
2414D	Round 5-3 (Which is a brief cutscene and nothing else)
2414E  	Round 5-4 through 5-5
24150 	Round 6-1
24151 	Round 6-2
24152	Round 6-3
24153	Round 6-4
26EA9	Round 6-5
115CF	Round 6 clear
4398 	Ending theme
61F7 	Continue screen

(Source: Emptyeye)

Continue Screen

This is very incomplete.

Water Rising

$80/E710 E2 20		SEP #$20
$80/E712 E6 7E		INC $7E
$80/E714 A5 7E		LDA $7E
$80/E716 C9 0A		CMP #$0A
$80/E718 90 18		BCC $E732 //If incrementer less than 10, DO NOT raise water (incrementer increases every frame)
$80/E71A 64 7E		STZ $7E   //Otherwise, zero out incrementer (Located at 0019CB) and proceed.
$80/E71C AD 0E D6	LDA $d60e
$80/E71F C9 00		CMP #$00
$80/E721 D0 0F		BNE $E732 //Compare 7ED60E to 0 and DO NOT raise water if NOT equal to 0. This seems to get set to something 
				  //besides 0 once the "Game Over" begins. 
$80/E723 C2 20		REP #$20
$80/E725 AD 49 AB	LDA $AB49
$80/E728 C9 B0 FF	CMP #$FFB0
$80/E72B B0 05		BCS $E732 //Compare current water height (Located at 7EAB49) to 176. If greater than or equal to 176, DO NOT 
				  //raise it.
$80/E72D EE 49 AB	INC $AB49 //Otherwise, we've passed all the checks, so raise the water one pixel and continue.
$80/E730 80 00 		BRA $E732

(Source: Emptyeye)

Timer Counting Down (One Player)

$80/E381 E2 20 		SEP #$20 
$80/E383 E6 7F		INC $7F 
$80/E385 A5 7F		LDA $7F 
$80/E387 C9 3C		CMP #$3C 
$80/E389 90 15		BCC $E3A0 //If incrementer less than 60, DO NOT decrement timer (incrementer increases every frame)
$80/E38B 64 7F		STZ $7F   //Otherwise, 0 out incrementer (located at 00107F) and proceed.
$80/E38D E2 08		SEP #$08
$80/E38F A5 7E		LDA $7E
$80/E391 38		SEC
$80/E392 E9 01		SBC #$01
$80/E394 85 7E		STA $7E   //Decrease timer (Located at 7E107E in RAM)
$80/E396 C2 08		REP #$08
$80/E398 30 74		BMI $E40E //If negative flag (Countdown at -1), jump to Game Over routine
$80/E39A A9 41		LDA #$41 
$80/E39C 22 B1		JSL $8180B1 //Otherwise, load 65 to A and jump to 8180B1

(Source: Emptyeye)