Final Fantasy IV SNES - Critical Hit Bug Fix?

Started by 8.bit.fan, November 15, 2018, 03:12:31 AM

Previous topic - Next topic

FlamePurge

Alright, I think I have a rough draft of the readme started... Anyone have the time to look over it? I wrote things down as I understood them.

Final Fantasy IV - Critical Hit Bug Fix

by Grimoire LD and chillyfeez

No ownership is claimed by the two mod authors over Final Fantasy IV or the franchise from which it originates. Please credit the authors if you use this fix in your mod.

------------

There are several possible ways for a character to permanently lose their ability to perform critical hits.

"Some weapons prevent critical hits from occurring at all, and there's a bug where this bit is not unset when the weapon is removed."

(source: https://gamefaqs.gamespot.com/snes/588330-final-fantasy-iv/faqs/54945)

"Lose Critical Attack Ability: There are two ways to lose critical attack ability. The first is to be in the group and be in a position where in the next 'auto-fight' (such as when Tellah fights Edward or Cecil fights Kain) the character's spot is not taken up by one of the NPC fighters. Meaning that in the case where Golbez and FuSoYa are fighting against Zemus, if there is a character on the team that still has crit, he can keep his critical attack by being in the same position as either one of those characters. Or he would lose it if he was in a different position. However, it was later also discovered that the characters that aren't in the 'auto-fight' will retain critical attacks IF and only if the group on the right dies.

The second way to lose critical attack ability is to be dead when a fight starts. In both these cases there is no way to regain critical strike ability. Not by saving and reseting the game, powering off, sleeping in an inn, leaving the party, or any other number of ways you could think of. The ability to critical strike is lost forever if either of these conditions are met."

(source: http://tasvideos.org/2033S.html)

This patch fixes the incorrect behavior by:
1. Removing the restriction on critical hits in auto-fights
2. Continuing to write critical hit data for teammates who are incapacitated when a battle begins

Unfortunately, since this data is saved to your save file, there's no way for existing saves to recover lost critical hit abilities.
Check out and discuss my projects

POWCo-op

In the last line, you could say written to your save file to avoid repetition. This patch will make playing FF4 more enjoyable!
Now you're playing in... three dimensions.

chillyfeez

Afaik, criticals aren't restricted in autobattles, the game just skips over writing critical percentages for characters who don't participate in them (which causes the permanent loss).
Ongoing project: "Final Fantasy IV: A Threat From Within"

Latest Demo

FlamePurge

here's the updated end of the readme:

This patch fixes the incorrect behavior by:
1. Writing critical hit percentages for characters who aren't participating in auto-battles, instead of skipping them like before
2. Continuing to write critical hit data for teammates who are incapacitated when a battle begins

Unfortunately, since this data is written to your save file, there's no way for existing saves to recover lost critical hit abilities. Players will have to start a new game in order for the fix to work.


btw does this fix weapons with the "no crit" byte set making characters lose their crit ability?
Check out and discuss my projects

Grimoire LD

To our knowledge... there is no such thing. Chillyfeez and I have both tested this, I by doing little more than increasing Natural critical hit rate, equipping those "critical hit-less" weapons did not prevent critical hits at all. It is our thought that due to the easy loss of crits through being dead or Not being in the same spot as the fighter in an auto-battle, may have caused these rumors to appear.

FlamePurge

#65
alright, awesome. submitted to the site. i just need to update credits and add chillyfeez as a co-author

edit - it's live on the site. FFII US v1.1 only, headered or unheadered. https://www.romhacking.net/hacks/4256/ submitted an update with chillyfeez as a co-author, and submitted credits.
Check out and discuss my projects

Rodimus Primal

Quote from: vivify93 on December 06, 2018, 09:04:38 PM
alright, awesome. submitted to the site. i just need to update credits and add chillyfeez as a co-author

edit - it's live on the site. FFII US v1.1 only, headered or unheadered. https://www.romhacking.net/hacks/4256/ submitted an update with chillyfeez as a co-author, and submitted credits.

Excellent! Glad the fix is simple enough and it works. I'm going to add it to the next update of Namingway Edition. Are you doing so for Project II?


FlamePurge

Yes, I am! Before I make another big update, though, I was waiting to see if Crow was going to release a version of his equipment screen mod for vanilla FFIV, and see if it's compatible with it.



If it is, it's definitely going on Project II as well!  :D
Check out and discuss my projects

chillyfeez

Yeah, that is an awesome thing.
If he does make a patch for vanilla, though, be careful. There's no doubt some custom assembly involved in drawing those windows, and that means there's a chance it would clash with User Options.
If that ends up being the case, I might be able to move some User Options stuff somewhere else in ROM for you.
Ongoing project: "Final Fantasy IV: A Threat From Within"

Latest Demo

FlamePurge

That's very true. We'll have to play it by ear. Thank you!
Check out and discuss my projects

teahouser

This was a very interesting thread to follow. You were able to pinpoint the bug in the code and fix the problem that nobody has addressed in decades, very impressive.

I was going to do a playthrough of ff IV soon,can I use this patch on an already patched Namingway version?

FlamePurge

Check out and discuss my projects

chillyfeez

Quote from: teahouser on December 09, 2018, 09:12:09 PM
This was a very interesting thread to follow. You were able to pinpoint the bug in the code and fix the problem that nobody has addressed in decades, very impressive.

Grimoire LD and I spent the better part of three years dissecting FFIV. The most remarkable part of all this is probably that we hadn't addressed the issue sooner.
;)
Ongoing project: "Final Fantasy IV: A Threat From Within"

Latest Demo

Crow!

#73
Regarding my stat screen mod shown above, it does in fact use almost all of the unused data immediately after the menu display data - 0xde68 through 0xe2ff gets used.  Hacks that add new options to the customization screen would likely have used that particular ROM region, which would create a conflict.

When I eventually release that mod for public use (atm it's a The Lunarian Shuffle exclusive), I'll be releasing the ASM as well as the raw data, so someone who needs an option screen hack as well and knows what they're doing could offload some of the subroutines and data to another section of the ROM - expanding the ROM by one bank would work, if nothing else.

In other news, I think I'll add an option to fix various stat glitches, including this one, the permanence of Long Range (looks like Dragoon ZERO already tackled this one), the Adamant armor permanent weaknesses glitch,  and the failure of enemies to load the evasion and magic evasion they are supposed to have.

-------

Edit: turns out the Adamant armor problem wasn't too hard to fix.

Here is the root of the Adamant unequipping problem.  It loads extreme resistances, and if it finds any, it sets the opposites, plus the "extreme" flag, into the extreme weaknesses byte.
However, the game does nothing whatsoever if it finds no extreme weaknesses, thus leaving the old values there!
$03/9a78 ldy #$0026
$03/9a7b lda ($80),y << Loads extreme resistances
$03/9a7d sta $a9
$03/9a7f jsr $9da8 << This subroutine picks opposite elements: Fire and Ice are swapped, as are Holy and Darkness.
$03/9a82 beq $9a8b << This will fire if there was no Holy, Dark, Ice, or Fire stuff in the resistances
$03/9a84 ldy #$0021
$03/9a87 ora #$80 << Throw in an "extreme" flag.  I actually don't know if this does anything.
$03/9a89 sta ($80),y << Here is where it gets set.
$03/9a8b ldy #$0022 << Destination of the branch; goes on to edit other stuff.

So, in cases where beq fires, what we want to do is put a 0 into the extreme weakness flag.  This can be achieved by simply rearranging the commands as follows:

ldy #$0026
lda ($80),y
sta $a9
ldy #$0021
jsr $9da8
beq $+WriteExtremeWeakness
ora #$80
WriteExtremeWeakness:
sta ($80),y
ldy #$0022

Subroutine $9da8 does not touch Y, so loading Y earlier is fine.  The only thing the game now skips when there are no extreme weaknesses to write is OR-ing in the "extremeness" flag.

TL;DR: apply this code to 0x19a7f on an unheadered, v1.1 ROM:
A0 21 00 20 A8 9D F0 02 09 80 91 80


--------

Edit 2: And while we're at it, making enemy evasion work wasn't too hard once I figured out enough about what the game was actually doing.

NOTE: This might make the game a lot harder!  I'm not really sure just how big the impact of enemies having their intended evasion is.  Future releases of the game consistently chose not to restore this evasion, which might suggest that it would have been overbearing.

The culprit this time appears to be a simple typo by Square in the battle loading routine.  Essentially the same typo is made in the physical as well as magical defense loading routines.  Here's the erroneous physical one:
$03/90ce lda $291c
$03/90d1 sta $2028,x
$03/90d4 lda $291d
$03/90d7 sta $202a,x  << Oops!
$03/90da lda $291e
$03/90dd sta $202a,x

And here's magic evade:
$03/90e6 lda $291c
$03/90e9 sta $2022,x
$03/90ec lda $291d
$03/90ef sta $2024,x  << Oops!
$03/90f2 lda $291e
$03/90f5 sta $2024,x

The byte order goes evade multiplier, evade rate, then defense.  The middle byte is being written on the last byte, then immediately overwritten by the correct last byte, leaving every enemy without its proper evade rate, although they do have the correct evade multiplier.

The code we want is:
$03/90d7 sta $2029,x
...
$03/90ef sta $2023,x

The fix to this, then is only two bytes.  On an unheadered v1.1 US ROM, the bytes to change are:
0x190d8 = 0x29
0x190f0 = 0x23


chillyfeez

I think we looked at enemy evasion once on slick and after playing with it a bit collectively decided that it was better off left alone. Harder, yes, but not in a fun challenge way. In a simply needlessly frustrating way.

User Options would most likely move to a new place in ROM more easily than Crow's equipment screen. It's just a collection of relatively simple tweaks that in most cases are just a matter of a single subroutine jump (except the ATB counter - that's a frigging mess).
Ongoing project: "Final Fantasy IV: A Threat From Within"

Latest Demo

8.bit.fan

Just want to say great work again on fixing this bug chillyfeez and Grimoire!  :woot!:

And that inventory display is amazing Crow!
In the year of 200X, a super robot named Mega Man...
http://www.8bitfan.info/
FF4 Ultima Discord: https://discord.gg/4MqjwJt

Grimoire LD

#76
I must say I exclaimed out loud "That is so cool!" When I saw your custom equipment menu. Though I wonder what those values next to the character's portrait mean... oh they're stats, brilliant! I look forward to trying that out in time.

It is such a shame that Slickproductions is still down. Well, the Adamant Armor fix is here as the only patch I've submitted, but you have a cleaner code to fix this.

As Chillyfeez mentioned I fixed up evasion long ago. I was never of the opinion as Chillyfeez and Deathlike2 were that it made things needlessly frustrating. I felt it was something they meant to have, as all strategy guides from early on mentioned these evasion chances. It is also the only reason for enemies to have Defense Multipliers because in the base game enemy Defense is ridiculously low, aside from Flans.

It is fixed throughout Combat Boost and while it makes a different it makes the game a lot less focused on just straight-attacking without strategy, Since Evasion Chance is by multiplier so say... the turtles in Antlion cave have a 90% chance to evade. That means they will only evade the first multiplier while the second one will strike through (as long as that hit in hit calculation) decreasing the damage roughly by half.



Quote from: Crow! on December 10, 2018, 03:33:56 PM
Regarding my stat screen mod shown above, it does in fact use almost all of the unused data immediately after the menu display data - 0xde68 through 0xe2ff gets used.  Hacks that add new options to the customization screen would likely have used that particular ROM region, which would create a conflict.

When I eventually release that mod for public use (atm it's a The Lunarian Shuffle exclusive), I'll be releasing the ASM as well as the raw data, so someone who needs an option screen hack as well and knows what they're doing could offload some of the subroutines and data to another section of the ROM - expanding the ROM by one bank would work, if nothing else.

In other news, I think I'll add an option to fix various stat glitches, including this one, the permanence of Long Range (looks like Dragoon ZERO already tackled this one), the Adamant armor permanent weaknesses glitch,  and the failure of enemies to load the evasion and magic evasion they are supposed to have.

-------

Edit: turns out the Adamant armor problem wasn't too hard to fix.

Here is the root of the Adamant unequipping problem.  It loads extreme resistances, and if it finds any, it sets the opposites, plus the "extreme" flag, into the extreme weaknesses byte.
However, the game does nothing whatsoever if it finds no extreme weaknesses, thus leaving the old values there!
$03/9a78 ldy #$0026
$03/9a7b lda ($80),y << Loads extreme resistances
$03/9a7d sta $a9
$03/9a7f jsr $9da8 << This subroutine picks opposite elements: Fire and Ice are swapped, as are Holy and Darkness.
$03/9a82 beq $9a8b << This will fire if there was no Holy, Dark, Ice, or Fire stuff in the resistances
$03/9a84 ldy #$0021
$03/9a87 ora #$80 << Throw in an "extreme" flag.  I actually don't know if this does anything.
$03/9a89 sta ($80),y << Here is where it gets set.
$03/9a8b ldy #$0022 << Destination of the branch; goes on to edit other stuff.

So, in cases where beq fires, what we want to do is put a 0 into the extreme weakness flag.  This can be achieved by simply rearranging the commands as follows:

ldy #$0026
lda ($80),y
sta $a9
ldy #$0021
jsr $9da8
beq $+WriteExtremeWeakness
ora #$80
WriteExtremeWeakness:
sta ($80),y
ldy #$0022

Subroutine $9da8 does not touch Y, so loading Y earlier is fine.  The only thing the game now skips when there are no extreme weaknesses to write is OR-ing in the "extremeness" flag.

TL;DR: apply this code to 0x19a7f on an unheadered, v1.1 ROM:
A0 21 00 20 A8 9D F0 02 09 80 91 80


--------

Edit 2: And while we're at it, making enemy evasion work wasn't too hard once I figured out enough about what the game was actually doing.

NOTE: This might make the game a lot harder!  I'm not really sure just how big the impact of enemies having their intended evasion is.  Future releases of the game consistently chose not to restore this evasion, which might suggest that it would have been overbearing.

The culprit this time appears to be a simple typo by Square in the battle loading routine.  Essentially the same typo is made in the physical as well as magical defense loading routines.  Here's the erroneous physical one:
$03/90ce lda $291c
$03/90d1 sta $2028,x
$03/90d4 lda $291d
$03/90d7 sta $202a,x  << Oops!
$03/90da lda $291e
$03/90dd sta $202a,x

And here's magic evade:
$03/90e6 lda $291c
$03/90e9 sta $2022,x
$03/90ec lda $291d
$03/90ef sta $2024,x  << Oops!
$03/90f2 lda $291e
$03/90f5 sta $2024,x

The byte order goes evade multiplier, evade rate, then defense.  The middle byte is being written on the last byte, then immediately overwritten by the correct last byte, leaving every enemy without its proper evade rate, although they do have the correct evade multiplier.

The code we want is:
$03/90d7 sta $2029,x
...
$03/90ef sta $2023,x

The fix to this, then is only two bytes.  On an unheadered v1.1 US ROM, the bytes to change are:
0x190d8 = 0x29
0x190f0 = 0x23


chillyfeez

I guess "needlessly frustrating" is an oversimplification.
I guess my real feeling is that it just makes the game a lot more tedious. My biggest problem with FFIV has always been the pacing of the battle system. If you turn battle speed up too high, it's damn near impossible (later in the game, unless you grind). If you turn the speed down, it's easier to formulate an appropriate strategy for each battle, but things take for-freaking-ever. Turning on enemy evasion, while it does force more strategizing, increases the "forever" -ness of the battles.
I also am of the opinion that one should not do anything that compromises the effect of melee combat without also "fixing" either the psyche spell or the price of ethers.
Ongoing project: "Final Fantasy IV: A Threat From Within"

Latest Demo

Crow!

I tried out evasion and decided to ditch it.  My issue was that the vanilla numbers for evasion really, really punish you for trying to use Magic against bosses.  My best guess is that they were noticing bosses were taking more hits from e.g. Slow than they were expecting given the evasion numbers they had put in, and rather than realizing their evasion didn't work, they tried jacking up just the MEvade numbers to about 4x what would make logical sense in an effort to make it do what they expected.

Net result is that early game bosses have about 6x as much MEvade as your end-game mages do, and it goes up from there.  Physical evasion, meanwhile, is generally slightly behind what your own shield wielding characters have at any stage.

chillyfeez

Which is all especially weird considering they could have just made certain spells (like slow,if they wanted) not work on bnosses at all.
Ongoing project: "Final Fantasy IV: A Threat From Within"

Latest Demo