øAslickproductions.org/forum/index.php?PHPSESSID=5f0fck550j2m4m2fpbtkj2vkm1&topic=2219.0e:/My Web Sites/Slick Productions - FFIV Message Board/slickproductions.org/forum/index0450-2.htmlslickproductions.org/forum/index.php?PHPSESSID=5f0fck550j2m4m2fpbtkj2vkm1&board=8.80e:/My Web Sites/Slick Productions - FFIV Message Board/slickproductions.org/forum/index0450-2.html.zx %h^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÈ ,/Ø]OKtext/htmlISO-8859-1gzip@øÕØ]ÿÿÿÿÿÿÿÿTue, 10 Mar 2020 23:55:14 GMT0ó°° ®0®P®€§²ð® %h^ÿÿÿÿÿÿÿÿ\8Ø] WIP Patch: Permanent Morph bugfix

Author Topic: WIP Patch: Permanent Morph bugfix  (Read 8421 times)

magitek

  • Antlion
  • *
  • Posts: 67
  • Gender: Male
  • Juggler
    • View Profile
WIP Patch: Permanent Morph bugfix
« on: May 01, 2016, 08:02:21 AM »
This bug is referenced in Master ZEDs guide as "Permanent Morph status until the end of battle". This should fix the instances of the bug that aren't caused by Rippler.

It additionally causes the Morph gauge to pause if Terra is afflicted with Stop, or if someone else is under the influence of Quick.

I just want to note that Leet Sketcher is the one who originally did the research and came up with the actual bugfix for the bug (on my request).
He is the one who noted the weirdness of how Stop and Quick, being time freezes, still wouldn't impede the Morph timer from ticking down. I built off of his ideas to make this patch. Shoulder of giants, and all that. I'm posting this publicly because I want to get feedback and help with an issue, not to take credit for his work after I originally saddled him with this project. :)

With that said, here is the code. If anyone can figure out a way to shrink this function by two bytes how to fix the brief pause when Reverting after the gauge runs out during an animation, that would be much appreciated.

EDIT: it seems that removing the JSR $0B36 (update_supply) isn't the cause of Terra's brief pause, as that happens even with that instruction still in place. Not sure if removing that instruction changes anything at all. The pause doesn't happen in vanilla, it's caused by not clearing $3EE2. Oh well. I updated the comments in the code.

Code: [Select]
;Fixes the Permanent Morph bug (both Quick and Stop/Sleep/Freeze)
;Also halts the Morph timer if Terra is afflicted with Stop, or if someone else
;is under the influence of Quick. Also introduces a minor bug, see below. :/

hirom                 ;do not change
;header               ;uncomment this if your ROM has a header

;Leet Sketcher's original fix
;org $C21227
;NOP #5               ;Don't null "who is Morphed" variable for now
                      ; Removing this seems to cause Terra to get stuck in the
                      ; stepped forward position briefly when she uses Revert
                      ; if the timer runs out during an attack animation. No
                      ; other screwiness immediately apparent...

;Full fix
org $C21211
;Start of new code (7 bytes used)
LDA $3AA0,X
BIT #$10              ;(is entity Wounded, Petrified, or Stopped, or is
                      ; somebody else under the influence of Quick?)
BNE exit              ;(Exit if any are true)
;End of new code
REP #$20              ;(Set 16-bit Accumulator)
SEC                                         
LDA $3F30             ;(Load the morph timer)
SBC $3F32             ;(Subtract morph decrement amount)
STA $3F30             ;(Save the new morph timer)
SEP #$20              ;(Set 8-bit Accumulator)
BCS update_gauge      ;(Branch if it's greater than zero)
STZ $3F31             ;(zero top byte of Morph timer.  i assume we're
                      ; neglecting to zero $3F30 just to avoid adding a
                      ; "REP" instruction.)
                      ;(The Morph supply will refill when the timer
                      ; runs out if we don't do this)
;Start of removed code (8 bytes freed)
;JSR update_supply    ;(removed, don't uncomment)
                      ;(adjust Morph supply [in this case, zero it] to match
                      ;our new Morph timer)
                      ;
                      ; Needs to be removed to free up space.
                      ;
;(This is what causes the original bug: we remove it and free up 5 bytes)
;LDA #$FF             ;(removed, don't uncomment)
;STA $3EE2            ;(removed, don't uncomment)
                      ;(Store #$FF to Morphed targets byte [no longer have a
                      ; Morphed target])
                      ; Removing this seems to cause Terra to get stuck in the
                      ; stepped forward position briefly when she uses Revert
                      ; if the timer runs out during an attack animation. No
                      ; other screwiness immediately apparent...
;end of removed code
NOP                   ;One byte left unused from the above; padding.
LDA #$04
STA $3A7A             ;(Store Revert as command)
JSR queue_revert      ;(queue it?)
update_gauge:
LDA $3F31             ;(Load the remaining amount of morph time DIV 256,
                      ; if any)
STA $3B04,X           ;(Store it to the character's Morph gauge?)

exit:
RTS

org $C24EB2
queue_revert:

org $C20B36
update_supply:
« Last Edit: May 01, 2016, 03:09:47 PM by magitek »
Don't feed the trolls. Use proper grammar, spelling, and punctuation. Eat your vegetables.

magitek

  • Antlion
  • *
  • Posts: 67
  • Gender: Male
  • Juggler
    • View Profile
Re: WIP Patch: Permanent Morph bugfix
« Reply #1 on: May 01, 2016, 11:52:58 AM »
Checking for Stop and Quick by itself eliminates those triggers for the bug without mucking about with $3EE2 (which causes the Revert pause). Unfortunately, that still leaves the Sleep and Freeze triggers for the bug.

Sleep and Freeze don't cause time to stop so the Morph gauge should be allowed to run out within the duration of those statuses. However, It might be possible to hook function C2/5161 (Remove Stop, Reflect, Freeze, or Sleep when time is up), to check for an expired Morph, and queue up Revert from there. Probably not without using free space, though...
Don't feed the trolls. Use proper grammar, spelling, and punctuation. Eat your vegetables.

assassin

  • Bane of Retards
  • *
  • Posts: 1,033
  • space bears are not gentle!
    • View Profile
    • My Barren Webpage
Re: WIP Patch: Permanent Morph bugfix
« Reply #2 on: May 01, 2016, 05:03:10 PM »
- yeah, leaving $3EE2 uncleared probably causes some of my comment at the end of Function C2/1211 to occur.
- i can't get onboard with dropping "JSR $0B36" just to save space.  it might be safe, with Revert hopefully issuing it, but it's poor form.  i don't see why he'd/you'd make a gamble that Square didn't need to write something, when the only thing to gain out of being right is a few bytes.
- looks like C2/4BCE is thwarting Revert while asleep.  in contrast, slumberers can still be affected by periodic damage/healing, so maybe broaden the command check at C2/4BB2?  who knows what side effects there'll be, though.

now, a standing up Revert might look out of place for somebody who's supposed to be sleeping, but it's only a graphical issue. :)

13375K31C43R

  • Ultros
  • *
  • Posts: 675
  • Gender: Male
    • View Profile
    • Leet Sketcher's Final Fantasy III Patches
Re: WIP Patch: Permanent Morph bugfix
« Reply #3 on: May 02, 2016, 01:12:30 AM »
Another thing I've noticed is that, even when you win a battle, while the rewards are being displayed, if Terra's still Morphed, the Morph timer will still count down. That especially is weird to me, I think it's unfair as well, unless this is Square trying to encourage you to move on quickly. If that's the case, I can understand Quick as well; however, Stop is still totally unfair in my opinion.
"Do not meddle in the affairs of wizards, for they are subtle and quick to anger." -Gildor from The Lord of the Rings

assassin

  • Bane of Retards
  • *
  • Posts: 1,033
  • space bears are not gentle!
    • View Profile
    • My Barren Webpage
Re: WIP Patch: Permanent Morph bugfix
« Reply #4 on: May 02, 2016, 02:28:33 AM »
the Morph supply is updated before you confirm any messages, so you won't get burned unless you let the timer run down all the way (when the supply will update again).

they zero the Morph gauge(s) right after that first update, suggesting they want an empty one displayed.  but because the Morph timer decrement function (C2/1211) is still called, the gauge gets re-synchronized with the Morph timer.  it would make sense to stop calling this function after the battle is won -- yet the ironic thing is, the empty gauge would never show up then, because the game doesn't bother to call C2/5C54 outside of the first function (and battle start-up).

face it: they're just idiots.  if they were trying to dis-incentivize certain behavior, their code is really sending mixed messages.  the battle's over, so it's indeed unfair.

your Stop and other-Quick check makes perfect sense.
« Last Edit: May 02, 2016, 06:59:41 AM by assassin »

magitek

  • Antlion
  • *
  • Posts: 67
  • Gender: Male
  • Juggler
    • View Profile
Re: WIP Patch: Permanent Morph bugfix
« Reply #5 on: May 02, 2016, 09:02:35 AM »
I appreciate that you're a stickler for good coding, Assassin, and with the FFVI code you can't be too careful. However, it seems to me that the function to update Morph supply doesn't need to be called every frame. JSR $0B36 is called from C2/0AA8, which in turn is called from C2/083F which is called at the end of every turn. Waiting until end of turn to update the Morph supply shouldn't cause issues.

It will be a non-issue anyway if I want to fix the bug while still clearing $3EE2 in C2/1211. In that case I need to reach into free space to insert the check for Quick and Stop.

Leet Sketcher came up with the idea to leave $3EE2 uncleared until Revert is successfully executed. It seemed like a good way to make sure that Terra Reverts no matter what, but it causes that pause, and I'm not sure why it only happens when the timer runs out during an attack animation. I don't know where to start looking for a fix. Maybe it's a fool's errand to try and clear $3EE2 later, but perhaps it's possible to hook into somewhere else to clear $3EE2 after Morph status is definitely removed so that whatever causes the pause doesn't occur. Revert doesn't clear $3EE2, it just sets Morph status to be removed, by the way.

Anyway, I would prefer to find a way to make sure she Reverts immediately after Sleep and Freeze wear off instead of during, but I tried your suggestion:

Code: [Select]
org $C24BB6
JMP newstuff    ;hook here

org $C2A65A     ;wherever there's free space
newstuff:
BCS proceed     ;Branch and proceed if command is >=1Eh
CMP #$04
BEQ proceed     ;or if it is Revert
JMP $C24BB8     ;otherwise return
proceed:
JMP $C24BD5

I think there's a more efficient way to structure those branches and jumps, but it works, both for Sleep and Freeze. Even if it looks funny. Perhaps it might be more aesthetically pleasing to hook into however Sleep and Freeze are removed when their timers run out, and queue Revert from there, instead.

Clearing $3EE2 at the end of battle fixes the issue with the Morph gauge ticking down, by the way.
Code: [Select]
org $C24908
JSR clear_gauge_and_var

org $C2A65A   ;find dat free space
clear_gauge_and_var:
STZ $3B04,X    ;zero morph gauge
LDA #$FF
STA $3EE2       ;clear "who is morphed"
RTS
Don't feed the trolls. Use proper grammar, spelling, and punctuation. Eat your vegetables.

assassin

  • Bane of Retards
  • *
  • Posts: 1,033
  • space bears are not gentle!
    • View Profile
    • My Barren Webpage
Re: WIP Patch: Permanent Morph bugfix
« Reply #6 on: May 02, 2016, 10:14:25 AM »
However, it seems to me that the function to update Morph supply doesn't need to be called every frame.

that function is only called when C2/1211 detects the Morph timer has expired.

Quote
It seemed like a good way to make sure that Terra Reverts no matter what, but it causes that pause, and I'm not sure why it only happens when the timer runs out during an attack animation.

like i said earlier, read my big comment at the end of Function C2/1211.

Quote
Revert doesn't clear $3EE2, it just sets Morph status to be removed, by the way.

true, but the C2/0AA8 call that follows right after Revert will clear it.

Quote
Anyway, I would prefer to find a way to make sure she Reverts immediately after Sleep and Freeze wear off instead of during, but I tried your suggestion:

[...]

I think there's a more efficient way to structure those branches and jumps, but it works, both for Sleep and Freeze. Even if it looks funny. Perhaps it might be more aesthetically pleasing to hook into however Sleep and Freeze are removed when their timers run out, and queue Revert from there, instead.

glad it works.  i see what you're saying on waiting, but separating the Reversion from the timer depletion gets tricky.  besides, if Terra can run out of gas while in Sleep/Freeze, why should she get to stay Morphed and continue receiving its benefits?  what's keeping her in the status?

both conceptually and for coding ease, i tend to see reversion as something that doesn't require her active participation.  if she's awake, let her stand and spin.  but otherwise, a compromise would be to make the animation more subtle if she's in certain statuses.

Quote
Clearing $3EE2 at the end of battle fixes the issue with the Morph gauge ticking down, by the way.
very nice and direct.  i hadn't written any code, but the crap i was mulling was more complicated (e.g. trying to detect it was post-battle somehow  :lame:).

also, congrats on ending a 7-year dormancy.  :laugh:

"Posts:  8 (0.003 per day)"

not many active users can compete with this, outside of Drakkhen and kveldolf.

13375K31C43R

  • Ultros
  • *
  • Posts: 675
  • Gender: Male
    • View Profile
    • Leet Sketcher's Final Fantasy III Patches
Re: WIP Patch: Permanent Morph bugfix
« Reply #7 on: May 02, 2016, 10:27:21 AM »
I think the reason for the pause is because Revert ends up being queued multiple times. The reason why Function 1211 clears the Morphed character byte is probably to prevent this, but it ends up causing the Permanent Morph issue. If I'm right, then all you need to do before queueing Revert is to make sure it's not already queued. There's a bit of code in my "Dead in the Air" Fix A that can help you out.
"Do not meddle in the affairs of wizards, for they are subtle and quick to anger." -Gildor from The Lord of the Rings

assassin

  • Bane of Retards
  • *
  • Posts: 1,033
  • space bears are not gentle!
    • View Profile
    • My Barren Webpage
Re: WIP Patch: Permanent Morph bugfix
« Reply #8 on: May 02, 2016, 11:03:31 AM »
i don't see the clearing of $3EE2 as the root cause of the problem.  rather, it stems from Square failing to account for certain statuses, and even ignoring time stoppage when decrementing the Morph timer.

in the latter case, most of Function C2/1211 should be skipped (and indeed will be with your added Stop/other-Quick check), so it's arbitrary to try and pin the problem on $3EE2.  why single out 2 instructions when 10+ are wrongly being executed?  and why skip the 2 ALL the time just to account for statuses that *might* be -- but usually aren't -- possessed?

provided that the time-stoppage flub is dealt with, and some Sleep/Freeze awareness is added, things will work properly, and you won't need blunter measures like checking for whether Revert's already been queued.

iow, you're trying to balance out an overly-aggressive omission of "LDA #$FF / STA $3EE2" with a highly-broad queue screening.  it seems more sensible to identify the specific cases that cause the bug and go after those.

magitek

  • Antlion
  • *
  • Posts: 67
  • Gender: Male
  • Juggler
    • View Profile
Re: WIP Patch: Permanent Morph bugfix
« Reply #9 on: May 02, 2016, 02:21:49 PM »
Quote
and why skip the 2 ALL the time just to account for statuses that *might* be -- but usually aren't -- possessed?

Well, because they might not be strictly necessary if they can be replaced with a check for Revert to not stack upon itself, instead, and it fixes the bug.

I think both solutions have their merit and elegance. One is setting things up so that each of the conditions for the bug become irrelevant, and the other is bypassing each of the conditions that allow the bug to pop up separately. However, you're close to winning me over to your case, Assassin, with the point that, mechanically, it shouldn't be possible to artificially prolong the Morph duration with Sleep or Freeze to reap its protection.

I was thinking, too, that the graphical issue would be neatly solved with some conditional animation, but I have no idea where to start on that. Creating animation replacements is straying a little from pure bugfixing, but what is modding if not an art? I'd replace the "Stand up / Step forward / Spin / Step back" animation sequence with a simple blink animation (similar to Gogo's battle entrance).
Perhaps a bit of blinking combined with falling into the dead position briefly, change the sprite, and sit back up as unmorphed Terra; that'd look pretty neat. Unfortunately, I don't know the first thing about battle animations. I assume the Revert animation script gets loaded from somewhere outside of C2, then stored into a variable, which is then read by some function that handles animation. But I don't know where any of that happens, now do I know how to locate a different animation and substituting it for Revert. Much, much, less writing and calling a new animation script.


Quote
provided that the time-stoppage flub is dealt with, and some Sleep/Freeze awareness is added, things will work properly

Since all of that is now fixed, I have only one small reservation: do you think it would still be possible to trigger the bug with frame-perfect timing, by hitting Terra with Stop or having someone else enter Quick just as the Morph timer ran out, but before Revert could be executed? I can't make it happen during testing, but I don't have the patience for testing with frame-perfect input. This is the difference between "fixed" and "well hidden" that will gnaw at my conscience late at night.

Quote
also, congrats on ending a 7-year dormancy.

Thanks. :) I've kept busy even though I haven't been particularly active online.
Don't feed the trolls. Use proper grammar, spelling, and punctuation. Eat your vegetables.

13375K31C43R

  • Ultros
  • *
  • Posts: 675
  • Gender: Male
    • View Profile
    • Leet Sketcher's Final Fantasy III Patches
Re: WIP Patch: Permanent Morph bugfix
« Reply #10 on: May 02, 2016, 03:22:09 PM »
Check out Everything's battle animation doc which you can find here.
"Do not meddle in the affairs of wizards, for they are subtle and quick to anger." -Gildor from The Lord of the Rings

magitek

  • Antlion
  • *
  • Posts: 67
  • Gender: Male
  • Juggler
    • View Profile
Re: WIP Patch: Permanent Morph bugfix
« Reply #11 on: May 02, 2016, 03:55:49 PM »
I think the reason for the pause is because Revert ends up being queued multiple times. The reason why Function 1211 clears the Morphed character byte is probably to prevent this, but it ends up causing the Permanent Morph issue. If I'm right, then all you need to do before queueing Revert is to make sure it's not already queued. There's a bit of code in my "Dead in the Air" Fix A that can help you out.

Nice investigatory work, detective. That solved our conundrum.

Now we have two different bugfixes for the same bug, awesome! Well, one and a half. I'd still like to fix the animation issue in the other version.

Thanks for linking that document, now I'll be up all night. :wink: :angry: :childish:
Don't feed the trolls. Use proper grammar, spelling, and punctuation. Eat your vegetables.

13375K31C43R

  • Ultros
  • *
  • Posts: 675
  • Gender: Male
    • View Profile
    • Leet Sketcher's Final Fantasy III Patches
Re: WIP Patch: Permanent Morph bugfix
« Reply #12 on: May 02, 2016, 04:30:00 PM »
Well, wouldn't you know it? I found something even worse: if Terra runs away after Morphing, her Morph timer will continue to count down indefinitely for the rest of the battle. Thankfully, I know how to fix this. There is a Morph check at C2/1143 that determines whether Function 1211 should be called; this Morph check always happens every frame, regardless of whether or not Terra is present. All that's needed is to move that Morph check within the conditions set inside the frame loop.
"Do not meddle in the affairs of wizards, for they are subtle and quick to anger." -Gildor from The Lord of the Rings

assassin

  • Bane of Retards
  • *
  • Posts: 1,033
  • space bears are not gentle!
    • View Profile
    • My Barren Webpage
Re: WIP Patch: Permanent Morph bugfix
« Reply #13 on: May 02, 2016, 04:56:08 PM »
Quote
Since all of that is now fixed, I have only one small reservation: do you think it would still be possible to trigger the bug with frame-perfect timing, by hitting Terra with Stop or having someone else enter Quick just as the Morph timer ran out, but before Revert could be executed? I can't make it happen during testing, but I don't have the patience for testing with frame-perfect input. This is the difference between "fixed" and "well hidden" that will gnaw at my conscience late at night.

given C2/4BB2 is being made *more* permissive by the suggested patch, i hope this would not be an issue.

what i think could happen is the reverse:
- Morph timer is near running down
- cast Flare on a monster (nice long animation, good for testing)
- monster queues a counter, let's say a Stop spell
- during Flare animation, Morph timer expires, queues Revert
- you get Stopped
- more permissive C2/4BB2 allows Revert to go through, even though the character is now stopped.
- ..........does that bother us?

i'd actually tested the above, but with a periodic damage/healing timer in place of Morph timer, so it's not purely theoretical.  C2/4BDD indeed tried to execute the Regen "turn", but it didn't heal me, i believe because of C2/5018 exiting.

afaik, the Revert command has no such exit.  which is good from the standpoint of not having the reversion disappear into a black hole.  but a little bad from the standpoint that we're very briefly waiving the time stoppage to complete the command.

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

as for waiting for the Revert on Sleep/Freeze, i've considered having C2/1211 check for those statuses, and if so, refusing to perform the final Morph tick (i.e. one where the deduction exceeds the current timer).  this should be effectively pretty similar, without trying to wrangle the disconnect between expiration and reversion that other coding approaches might have.

yes, it's arbitrary to do every tick except the last.  but in my mind, no more arbitrary than a Morph-expired character somehow still having the status.  (pardon the repeat complaint. ;) )

note that because this change would probably be done _instead_ of relaxing C2/4BB2, i wonder if it might allow the worse scenario you asked about above.

magitek

  • Antlion
  • *
  • Posts: 67
  • Gender: Male
  • Juggler
    • View Profile
Re: WIP Patch: Permanent Morph bugfix
« Reply #14 on: May 02, 2016, 05:03:37 PM »
Well, wouldn't you know it? I found something even worse: if Terra runs away after Morphing, her Morph timer will continue to count down indefinitely for the rest of the battle. Thankfully, I know how to fix this. There is a Morph check at C2/1143 that determines whether Function 1211 should be called; this Morph check always happens every frame, regardless of whether or not Terra is present. All that's needed is to move that Morph check within the conditions set inside the frame loop.

What a can of worms this is... :scared:

So if I understand you correctly, your fix would look like this?

Code: [Select]
Original code:
C2/1141: A2 12        LDX #$12
C2/1143: EC E2 3E     CPX $3EE2      (Is this target Morphed?)
C2/1146: D0 03        BNE $114B      (Branch if not)
C2/1148: 20 11 12     JSR $1211      (Do morph timer decrement)
C2/114B: BD A0 3A     LDA $3AA0,X
C2/114E: 4A           LSR
C2/114F: 90 33        BCC $1184      (If entity not present in battle, branch to next one)
...
C2/1186: 10 BB        BPL $1143      (Loop if targets remaining)

Modified code:
C2/1141: A2 12        LDX #$12
C2/1143: BD A0 3A     LDA $3AA0,X
C2/1146: 4A           LSR
C2/1147: 90 3B        BCC $1184      (If entity not present in battle, branch to next one)
C2/1149: EC E2 3E     CPX $3EE2      (Is this target Morphed?)
C2/114C: D0 03        BNE $1151      (Branch if not)
C2/114E: 20 11 12     JSR $1211      (Do morph timer decrement)
...
C2/1186: 10 BB        BPL $1143      (Loop if targets remaining)
Don't feed the trolls. Use proper grammar, spelling, and punctuation. Eat your vegetables.