Notes:Final Fight 2
This page contains notes for the game Final Fight 2.
Addresses on this page correspond to the USA version unless noted otherwise.
- 1 Breakpoints
- 2 Enemy List
- 3 Enemy Names
- 4 Player Character Stats
- 5 Enemy Stats
- 6 The Ranking System
- 7 The Damage Formula
- 8 Display 8 or 16-bit value
- 9 Same Player Cheat
- 10 Stored Button Presses Table
- 11 Palettes
- 12 Palette Offsets
- 13 Music Pointers
- 14 Continue Screen
80811A, execute - accumulator holds start addresses of palette (+830000) 8180B1, execute - accumulator holds sound effect index to play
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.
84C265xx 84C266xx 84C26Dxx 84C26Exx
Alternately, change the following values directly in a hex editor:
00024265 00024266 0002426D 0002426E
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
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.|
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) 82EBAE 8D 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 82EBBF 8D 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)
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
The Ranking System
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
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.
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.
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(
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
Success $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
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
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
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 83F680 83F6A0 ---- Drumcan 83F6C0 83F6E0 0600 $0C Andore Jr. 83F700 0601 $0D Andore 83F720 0602 $0E G.Andore 83F740 0801 Elias 83F760 0A00 Won Won 83F780 83F7A0 83F7C0 83F7E0 83F800 ---- (yellow border around character portrait on character select screen) 83F820 0303 Mark 83F840 0304 Jack 83F860 0305 Elijah 83F880 83F8A0 83F8C0 83F8E0 83F900 83F920 0501 Jony 83F940 83F960 83F980 83F9A0 83F9C0 83F9E0 83FA00 83FA20 83FA40 83FA60 83FA80 83FAA0 0E00 Rolent 83FAC0 83FAE0 83FB00 83FB20 83FB40 83FB60 83FB80 83FBA0 ---- Bottle 83FBC0 83FBE0 83FC00 83FC20 83FC40 83FC60 83FC80 83FCA0 83FCC0 83FCE0 83FD00 83FD20 83FD40 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)
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
This is very incomplete.
$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
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