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

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

assassin

  • Bane of Retards
  • *
  • Posts: 1,033
  • space bears are not gentle!
    • View Profile
    • My Barren Webpage
Re: WIP Patch: Permanent Morph bugfix
« Reply #45 on: May 09, 2016, 01:13:50 AM »
Quote
On a side note, does xkas support calling or branching to straight addresses instead of labels? I keep declaring my labels using "org $address" and then put nothing but my label in there, just so I can jump or branch to that address. If I'm just making a call and not inserting code, can't I just type in the address? I can never get that to work but maybe I'm doing it wrong. :/

afaik, absolute calls and jumps can simply have the address.  but relative ones (e.g. BRA) will expect a label.  this is from using xkas v0.06.

---------

Code: [Select]
;To use this, we need to modify init_morph to set 16-bit A both in set_morpher
;and update_decrementor, but there's no room for an extra "REP #$20" without
;relocating parts of that function.


;The silly way
           
;BRA end        ;(ignore this; used for testing the above)
REP #$20        ;We need to set 16-bit A so update_decrementor works,
                ;but init_morph loads $3EE2, expecting it to be 8-bit
                ;What do...?
SEP #$10
LDY $3EE3       ;(Commandeer Y to preserve $3EE3 briefly)
TDC
STA $3EE2       ;We only care about the n flag being clear, so zero $3EE3
JSR init_morph  ;Now init_morph won't reset the Morph timer
STY $3EE3       ;Restore $3EE3
end:
!plpyxa
RTS

ugghhh to this excerpt. :P  a few things:

- why the "SEP #$10" if X/Y are already 8-bit in the calling function?

Code: [Select]
TDC
STA $3EE2       ;We only care about the n flag being clear, so zero $3EE3

so which address are you trying to zero?  if i'm reading your goal right, skip the TDC, and just do a "STZ $3EE3" before the "REP #$20".

Code: [Select]
;(New code, 2 bytes added)
BMI set_morpher ;If no one is morphed, set morpher, init timer, and set decrementor
;(Modified code)
BRA set_decrementor ;If somone is, only update decrementor
;(End of new and modified code)

what is going to be in the "(Modified code)" area?  if there's nothing, then change those two branches into a "BPL set_decrementor".  we will find a way to be rid of this $3EE3 silliness, eventually.

----------

as far as gaining back a little of the precision lost from the move from 65535 to 255, you could: put the ATB multiplier in $E8, use C2/47B7 (16-bit * 8- bit multiplier) to multiply it by 511, then load 16-bit $E8 (as you know the result fits in it), and have an extra LSR.  slight, but it's something.  might take more extra space, but so what?

or go all-out and multiply 65535 by ATB multiplier, then employ 24-bit / 8-bit division, using the Step Mine special effect an as example.  the extra space is a little bothersome, but maybe worth it.  any speed loss is *certainly* fine in my book, given you're not doing this calculation from oft-called C2/1211 anymore.
« Last Edit: May 09, 2016, 03:27:39 AM by assassin »

magitek

  • Antlion
  • *
  • Posts: 67
  • Gender: Male
  • Juggler
    • View Profile
Re: WIP Patch: Permanent Morph bugfix
« Reply #46 on: May 09, 2016, 11:08:46 PM »
afaik, absolute calls and jumps can simply have the address.  but relative ones (e.g. BRA) will expect a label.  this is from using xkas v0.06.

So is this valid?
Code: [Select]
JSR $4781But not this?
Code: [Select]
JSR $C24781What about this?
Code: [Select]
C2/0110: BRA $10

Quote
ugghhh

  :whoa:                     :cycle:


Quote
why not STZ $3EE3

Hehe, that was just for readability. This was joke code; I wanted the code and comments to be arranged in the correct order so as to not spoil the punchline before the setup. ;)
As for the "SEP #$10", that was indeed unnecessary. I was under the mistaken impression that X/Y was 16-bit here.


Quote
what is going to be in the "(Modified code)" area?  if there's nothing, then change those two branches into a "BPL set_decrementor".  we will find a way to be rid of this $3EE3 silliness, eventually.

Oh, I've gotten rid of it by relocating part of C2/0B01 already. This little outburst was just my little way of blowing off some steam after finally getting things working after a long night of frustrated coding. Glad you enjoyed it. :P

Rant warning: the first revision of this had my wrapper function hooked into the middle of C2/09D2, trying to jump to set_decrementor directly and doing some really convoluted stack manipulations beforehand to account for the stack pulls at the end of C2/0B01, all while trying to make sure I preserved all that needed to be preserved for the return to the middle of  C2/09D2. That silly code was my way of getting revenge on those stack manipulations and flag mismatches. :)

I was kicking myself when I realized that I could just change that BPL to branch to update_incrementor instead of exit and that would make C2/0B01 compatible with my call. When it still didn't work, I was too busy thinking my branch logic was faulty that I didn't realize that my problem was the the m flag mismatch. That BMI/BRA isn't supposed to contain anything, it's indeed supposed to be a BPL.

Lesson learned. Sometimes it's just better to walk away, get some sleep and do something else, then come back with a new set of eyes.


Quote
go all-out and multiply 65535 by ATB multiplier, then employ 24-bit / 8-bit division

I had a look at that, and it turns out I don't need a whole lot of extra space. Multiplying 65535 with the ATB multiplier, then loading 16-bit $E9 neatly serves up 16-bit (65535 * ATB / 256), which I then divide by 8-bit Morph supply, and then halve/quarter depending on Phunbaba bit. This amount of accuracy is enough to match the original decrementor.

By the way, I realized that skipping past the first Phunbaba check robs us of the Morph upgrade after vanquishing the demon. I moved that check to the very top of C2/0B01. Carry is preserved throughout, isn't it?

I've made another change to the code that was obvious after getting some sleep: manipulating bits in 3204,X to set up a call to C2/0AA8 isn't just unnecessary and inefficient, it causes some issues with resetting the decrementor that I haven't bothered to look into, since it's neater to just straight up call our newly renovated C2/0B01 instead. It saves both space and cycles.

Anyway, without further ado, here's the new code, now with 100% less memory mismanagement:
Code: [Select]
;Morph timer affected by Haste and Slow, v2

;This sets the Morph decrementor in init_morph, then calls init_morph
;every time ATB variables are recalculated (When Haste and Stop is
;set or removed, for example).

;There are two versions, one consumes 22 bytes of free space and has an
;accurate calculation of the Morph decrementor. This version conforms
;fully to what the decrementor would be in vanilla. In other words,
;you will notice no difference in the speed of the Morph gauge unless
;Haste or Slow is applied. :)

;The old version consumes 14 bytes of free space and has a slightly
;less accurate calculation. Morph decrementor will be set 1-2 values
;lower than it should be, resulting in a slightly slower Morph bar.
;The maximum difference is about 4 seconds (with a full supply, post-
;Phunbaba (68 seconds instead of 64 seconds).
;Obviously you'll want to use the more accurate version unless you're
;very short on free space in C2.

hirom
;header
!freespace = $C2A65A

;Change Haste multiplier for testing
org $C209E3
db $80                    ;(Haste multiplier = 2x speed)

;Can't be too careful...
!phaxyp = "PHA : PHX : PHY : PHP"
!plpyxa = "PLP : PLY : PLX : PLA"
;...but we probably don't need this.

;hook
org $C2089D
JSR newfunc         ;Normally, the call to recalc_atb

;Updates ATB variables and, if target is Morphed, updates Morph decrementor too
org !freespace
newfunc:
JSR recalc_atb
PHA                 ;init_morph preserves P, X and Y
CPX $3EE2           ;Exit if target isn't Morphed
BNE end
JSR init_morph      ;Update Morph decrementor
end:
PLA
RTS                 ;(Return)
;Relocated part of set_decrementor in C2/0B01
new_dec:
REP #$20            ;Set 16-bit Accumulator
TDC
DEC
JSR multiply24      ;(24-bit $E8 = 65535 * ATB multiplier)
RTS                 ;(Return)




;INIT_MORPH
;Start Morph timer and establish amount to decrement it
org $C20B01
init_morph:
PHX
PHP

phunbaba_check:         ;(9 bytes)
LDA $3EBB
LSR
LSR
ROR
BCS exit                ;(Exit function if bit 2 of $3EBB is set..
                        ; Set for just Phunbaba battle #4 [i.e. Terra's
                        ; second Phunbaba encounter])
ASL                     ;(Put Bit 1 into Carry)

check_morpher:          ;(5 bytes)
LDA $3EE2
BPL set_decrementor:    ;If someone is already Morphed, just update decrementor

set_morpher:            ;(3 bytes)
STX $3EE2               ;(store target in X as Morphed character)

init_timer:             ;(7 bytes)
TDC
REP #$20                ;(Set 16-bit Accumulator)
DEC                     ;(A is $FFFF)
STA $3F30               ;(Morph timer = 65535)
;end init_timer

;OLD SET_DECREMENTOR function, consumes no free space, but is less accurate
;set_decrementor:        ;(24 bytes)
;(New code, adds 11 bytes)
;REP #$20                ;This gets skipped if there was already a Morpher
;LDA #$FF00
;ORA $3ADD,X             ;Low byte holds ATB multiplier, high byte holds FFh
;JSR multiply16          ;(16-bit A = FFh * ATB multiplier)
;(End of new code)
;LDX $1CF6               ;(Morph supply)
;JSR divide              ;((ATB Multiplier * 255) / Morph supply) (16-bit A / 8-bit X)
;BCC upgrade             ;(Branch if bit 1 of $3EBB not set.
                        ; This bit is set in Terra's 2nd Phunbaba battle
                        ; [i.e. Phunbaba #4], and lasts afterward.  So
                        ; Terra gains some resolve here. ^__^)
;LSR                     ;(A = (255 * ATB multiplier / Morph supply) / 2 [pre-Phunbaba])
;upgrade:
;LSR                     ;(A = (255 * ATB multiplier / Morph supply) / 4 [post-Phunbaba])
;store_decrementor:
;STA $3F32               ;(Amount to decrement morph time counter)

;NEW SET_DECREMENTOR function, more accurate, consumes 11 bytes of free space
;(35 bytes total; 24 here, 11 bytes in free space)
;(The function is really 31 bytes; 7 are moved, 4 are call/return)
set_decrementor:        ;(24 bytes)
;(New code, adds 10 bytes)
LDA $3ADD,X             ;ATB multiplier
STA $E8                 ;Save it for multiplication
JSR new_dec             ;(What it looks like)
                        ;new_dec:
                        ;REP #$20             ;Set 16-bit Accumulator
                        ;TDC
                        ;DEC                  ;(A = 65535)
                        ;JSR multiply24       ;(24-bit $E8 = 65535 * ATB multiplier)
                        ;RTS
LDA $E9                 ;(A = (65535 * ATB) / 256)
;(End of new code)
LDX $1CF6               ;(Morph supply)
JSR divide              ;(Division function, A = ([65535 * ATB] / 256)  / Morph supply)
BCC upgrade             ;(Branch if bit 1 of $3EBB not set.
                        ; This bit is set in Terra's 2nd Phunbaba battle
                        ; [i.e. Phunbaba #4], and lasts afterward.  So
                        ; Terra gains some resolve here. ^__^)
LSR                     ;(([(65535 * ATB) / 256] / Morph supply) / 4 + 1 [post-Phunbaba]
upgrade:
LSR                     ;(([(65535 * ATB) / 256] / Morph supply) / 2 + 1 [pre-Phunbaba]
INC
store_decrementor:
STA $3F32               ;(Amount to decrement morph time counter)

;(Removed code, for reference. Removes 11 bytes)
;LSR
;LSR
;CMP #$0800 
;BCC nocap
;LDA #$07FF             ;(this will cap amount to decrement morph time
;                       ; counter at 2048)
;
;                       ;Removed for space. Morph is disabled unless Morph
;                       ;supply is at least 16, in which case amount to decrement
;                       ;will be at most 512 (old), or 2032 (new).
;                       ;Old: (65535 / 16) / 8 + 1 = 512)
;                       ;New: ([(65535 * 255) / 256] / 16) / 2 + 1 = 2040
;                       ;That's with the Haste multiplier being maxed.
;nocap:
;INC                    ;Sacrificed to make that REP #$20 :/
;(End of removed code)

;(Unchanged code, for reference)
exit:
PLP
PLX
RTS
;(End of unchanged code)


;Called addresses (for labeling)
;Multiplies low byte of A * high byte of A.  Stores result in 16-bit A.
org $C24781
multiply16:

;Multiplication Function 2
;Results:
;16-bit A = (8-bit $E8 * 16-bit A) / 256
;24-bit $E8 = 3 byte (8-bit $E8 * 16-bit A)
;16-bit $EC = 8-bit $E8 * high byte of A
org $C247B7
multiply24:

;Divides 16-bit A / 8-bit X
;Stores answer in 16-bit A.  Stores remainder in 8-bit X.
org $C24792
divide:

;Recalculate ATB
org $C209D2
recalc_atb:
« Last Edit: May 09, 2016, 11:23:21 PM by magitek »
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 #47 on: May 10, 2016, 03:16:07 AM »
re valid assembler: definitely yes on the first one, likely yes on the second (but maybe try "JSL"), leaning no on the third (but i've never tried using a relative operand like that before, so maybe your way will work).

the joke was a bit lost on me.  though you did have me thinking, "why is he going through all this trouble to avoid growing C2/0B01 when he's consuming all this free space in the process?  doesn't he know he can JSR?  he seemed smarter in his earlier posts."  you exploited the leeway that comes with being a new patch maker. ;P  but this now means i'll judge you like a veteran from here forward.

glad you came up with something better.

C2/47B7 actually leaves with 16-bit $E9 in A, so you can drop the "LDA $E9".

and it just dawned on me that (65535 * num) is a special case that equals (65536 * num) - num.  so just put num in $EA, pretend $E9 and $E8 are 0, and do an imaginary subtraction of num from that 24-bit value.  you'll always need borrows out of the top 2 bytes, so we can have:

Code: [Select]
LDA $3ADD,X
dec
; sta $ea    (for clarity, don't actually need to save this)
xba
lda #$ff
; sta $e9   (for clarity, don't actually need to save this)
rep #$20

or 1 byte smaller:

Code: [Select]
tdc
LDA $3ADD,X
xba
rep #$20
dec

obviously, these have no flexibility whatsoever if you ever want to change 65535 to another value.  but they are very fast.

assassin

  • Bane of Retards
  • *
  • Posts: 1,033
  • space bears are not gentle!
    • View Profile
    • My Barren Webpage
Re: WIP Patch: Permanent Morph bugfix
« Reply #48 on: May 10, 2016, 02:09:18 PM »
a well-timed Haste or Slow casting might mitigate the problem of the "a possible loophole ..." scenario laid out in my May 5th post.  the now-recalculated, post-timer-expiration Morph decrementor will be rather large, so that will minimize the wait for a follow-up Revert to be queued.  (a wait that should really be infinitesimal or nonexistent, so this is an improvement, however weird).

oops, think i got that wrong, by assuming that a very low Morph supply would simply give a very large decrementor.  but the supply in that example is 0, and there are problems calling C2/0B01 with that:
- you edited out the decrementor capping at 2048.
- even with capping, the earlier "JSR $4792" will perform a divide by 0, and return nonsense.

so it's better called "an ill-timed Haste or Slow casting". :/

thus, i recommend adding back the capping check, and adding a "BEQ $0B2C" before the "JSR $4792", so a minimum supply gives a maximum decrementor.

while it might be tempting to drop the "JSR $0B36" to avoid this particular issue, my May 05, 2016, 10:18:44 PM CDT (May 06, 2016, 03:18:44 AM GMT) post -- and numerous others -- explains why doing that is nonsense and risky.

magitek

  • Antlion
  • *
  • Posts: 67
  • Gender: Male
  • Juggler
    • View Profile
Re: WIP Patch: Permanent Morph bugfix
« Reply #49 on: May 10, 2016, 02:14:40 PM »
C2/47B7 actually leaves with 16-bit $E9 in A, so you can drop the "LDA $E9".

D'oh. Thanks.

Quote
and it just dawned on me that (65535 * num) is a special case that equals (65536 * num) - num.  so just put num in $EA, pretend $E9 and $E8 are 0, and do an imaginary subtraction of num from that 24-bit value.  you'll always need borrows out of the top 2 bytes, so we can have:

Code: [Select]
LDA $3ADD,X
dec
; sta $ea    (for clarity, don't actually need to save this)
xba
lda #$ff
; sta $e9   (for clarity, don't actually need to save this)
rep #$20

That's really neat! Just one question, why do you mention $E8-EA? Those don't seem to have anything to do with this method, or am I missing something?


Quote
or 1 byte smaller:

VERY nice. With this method, update_decrementor fits inline in C2/0B01. Now, if we can find a way to reduce C2/09D2 by three bytes to fit our call, this patch can be completely inline. Thanks! :)
Don't feed the trolls. Use proper grammar, spelling, and punctuation. Eat your vegetables.

Imzogelmo

  • Ogopogo Aficianado
  • *
  • Posts: 241
  • Gender: Male
  • Ask me about my other job.
    • View Profile
    • NEPROMR
Re: WIP Patch: Permanent Morph bugfix
« Reply #50 on: May 10, 2016, 02:31:23 PM »
I'm gonna have to read this a couple more times to really appreciate the nuances, but it's nice to see someone tackle this bug. I remember looking at it years ago, and never really settled on a solution because it seemed to touch on so many areas. I think I was right about that.  :isuck:
5/31/16 - I have an assembly of the battle portion of C2, relocated to the F0 bank, which has both vanilla and patch code in my dropbox. I'll be updating it with additional patches as I have time. I will *not* be releasing it publicly, but ask me for the link and I'll share.

assassin

  • Bane of Retards
  • *
  • Posts: 1,033
  • space bears are not gentle!
    • View Profile
    • My Barren Webpage
Re: WIP Patch: Permanent Morph bugfix
« Reply #51 on: May 10, 2016, 02:36:06 PM »
That's really neat! Just one question, why do you mention $E8-EA? Those don't seem to have anything to do with this method, or am I missing something?

just to picture something holding the 24-bit value that you're subtracting the 8-bit value from.

Quote
VERY nice. With this method, update_decrementor fits inline in C2/0B01. Now, if we can find a way to reduce C2/09D2 by three bytes to fit our call, this patch can be completely inline. Thanks! :)

you're welcome.  but it's gotta be more than 3 bytes to fit both the $3EE2 test and the call, no?  that said, i'm not sure why you have "PHA / PLA" surrounding the call to init_morph.

assassin

  • Bane of Retards
  • *
  • Posts: 1,033
  • space bears are not gentle!
    • View Profile
    • My Barren Webpage
Re: WIP Patch: Permanent Morph bugfix
« Reply #52 on: May 10, 2016, 03:30:03 PM »
the second old post of mine i'm correcting today:

Quote
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).

C2/5C54 is actually called from C2/111B, not C2/1211.  so i think an empty gauge would show up in end battle even if the latter is no longer called, but should really test it.

magitek

  • Antlion
  • *
  • Posts: 67
  • Gender: Male
  • Juggler
    • View Profile
Re: WIP Patch: Permanent Morph bugfix
« Reply #53 on: May 10, 2016, 05:39:35 PM »
a possible loophole is if the Morph timer gets reduced to something like FFFFh (and then 00FFh) when a Revert-prohibiting status is in effect, and you have a VERY small Morph decrementor (e.g. 16d).  once the status is gone, Revert won't necessarily be queued right after, as the next few calls to C2/1211 won't zero Morph's timer.  should the battle end quickly, you're now hoping that the end-of-battle code calls C2/0B36.  i don't like relying on it for this, especially given there are multiple ways for a battle to end, and thus multiple holes to plug for patchmakers.

I'm not 100% sure I understand what you're trying to explain, so bear with me... when you say "something like FFFFh", you mean if the subtraction is performed when $3F32 > $3F30, correct? As in, the last tick of the timer?
So if I understand you correctly, this is caused by not zeroing $3F30 in C2/1211? The smallest natural decrementor is 8 (Max supply, after Phunbaba, with Slow), so if $3F30 was exactly FFh, there can be a delay of up to 32 frames to run down the timer again and re-queue Revert, during which the battle could end, thus preventing Revert for about half a second. Correct?

With the Stop/Quick/Freeze check in effect, those statuses will prevent C2/1211 from running the few remaining ticks of the timer down and re-queueing Revert until they end, while Sleep will let it keep running down over and over again and try to re-queue Revert every 32 (at most) frames, until the battle ends. If I'm not mistaken.

As you say, this could also happen if the battle ends while Terra is Sleeping, or if Stopped/Frozen (and her timer ran out during their animation), or if her timer ran out while someone cast Quick, and then finished the battle while Quicked.

In the case of Stop/Freeze/Quick being in effect through battle end, since we pause C2/1211 for those statuses, we're always relying on battle ending code to correctly update the supply. In any case, since we're stopping the timer for battle end, we should make sure all battle endings update the supply as well.

a well-timed Haste or Slow casting might mitigate the problem of the "a possible loophole ..." scenario laid out in my May 5th post.  the now-recalculated, post-timer-expiration Morph decrementor will be rather large, so that will minimize the wait for a follow-up Revert to be queued.  (a wait that should really be infinitesimal or nonexistent, so this is an improvement, however weird).
---
oops, think i got that wrong, by assuming that a very low Morph supply would simply give a very large decrementor.  but the supply in that example is 0, and there are problems calling C2/0B01 with that:
- you edited out the decrementor capping at 2048.
- even with capping, the earlier "JSR $4792" will perform a divide by 0, and return nonsense.

so it's better called "an ill-timed Haste or Slow casting". :/

thus, i recommend adding back the capping check, and adding a "BEQ $0B2C" before the "JSR $4792", so a minimum supply gives a maximum decrementor.

while it might be tempting to drop the "JSR $0B36" to avoid this particular issue, my May 05, 2016, 10:18:44 PM CDT (May 06, 2016, 03:18:44 AM GMT) post -- and numerous others -- explains why doing that is nonsense and risky.

Sorry to open the debate on this again, but this just has me MORE convinced that updating the supply the very instant the timer runs out is the risky option. I seems safer to update the supply only once we've cleared $3EE2, thus stopping the calls to C2/1211 AND C2/0B01.

I just think it makes sense to only update supply after Morph definitely has ended, as marked by Revert executing, or the battle ending. In other words, dropping the "JSR $0B36" in C2/1211 in favour of a "STZ $3F30".

Quote
i think an empty gauge would show up in end battle even if the latter is no longer called, but should really test it.

I'm not exactly sure if by "empty gauge" you mean "no decreasing green gauge" or a literally empty gauge (no increasing white ATB gauge either). If it's the former, clearing $3EE2 at battle end (thus stopping the calls to C2/1211) does indeed clear the green bar and restores the white ATB bar.

Quote
but it's gotta be more than 3 bytes to fit both the $3EE2 test and the call, no?  that said, i'm not sure why you have "PHA / PLA" surrounding the call to init_morph.

You're right, preserving A isn't needed, my mistake.

When I said three bytes, I was thinking that we could let C2/0B01 handle the check, but that only checks "if someone is morphed", not "is current target morphed" and we don't want casting Haste/Slow on someone ELSE to change the speed on Terra's Morph bar.

This is a somewhat risky suggestion what with all the hack authors out there, but couldn't we change the LDA $3EE2/BPL in C2/0B01 to CPX $3EE2/BEQ? In vanilla, there should only exist one Morpher (Terra) at a time (not considering craziness like the Rippler bug, but setting Morph via Rippler doesn't initialize their timer, so it doesn't set $3EE2 either).

I would hope any potential hack authors interested in allowing multiple Morphers and using this patch would read the documentation I intend to write (where this caveat would naturally feature) and find out how to remedy the problem (commenting/uncommenting some lines in the included .asm file).

 :edit:
Anyone wanting a hack with multiple Morphers has other problems anyway, since there is only one timer and one supply (and only Terra can add to it, I think). They would have to rewrite the Morph code anyway to account for multiple Morphers. Changing the LDA/BPL to CPX/BEQ would actually FIX the problem of multiple Morphers resetting each other's timers make it worse by only timing the first last morpher, (even if they are running down the supply while doing so), even if it would in addition to introducing some weirdness with Haste/Slow affecting everyone's gauges. I suppose it actually makes sense that they would each be updating the decrementor, too, with the Morph supply being shared.
 :edit:
No, wait, that wouldn't fix it, that would make it worse, since only the first Morpher would get a timer and the others would get free unlimited Morph.  :isuck:
« Last Edit: May 10, 2016, 06:08:36 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 #54 on: May 10, 2016, 09:35:43 PM »
By the way...

Code: [Select]
$3AA0 76543210
                7: allow battle menu to open (cleared when character/monster is seized)
                6: psyche was just cleared
                5: advance wait counter just triggered (never used ???)
                4: something with condemned
                3: action counter just triggered (ATB gauge is stopped)
                2: ogre nix can't break
                1: skip advance wait
                0: target is present
$3AA1 76543210
                7: something with regen/poison/seizure (DoT)
                6: pending action from run/control/psyche/seize (triggers subroutine at C2/0977)
                5: row (0 = front, 1 = back)
                4: target has a pending DoT action
                3:
                2: protection from instant death
                1: defense mode (used def. command)
                0: pending action goes directly to action queue

From the ff6hacking.com wiki. Great RAM map!
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 #55 on: May 11, 2016, 01:32:35 AM »
a possible loophole is if the Morph timer gets reduced to something like FFFFh (and then 00FFh) when a Revert-prohibiting status is in effect, and you have a VERY small Morph decrementor (e.g. 16d).  once the status is gone, Revert won't necessarily be queued right after, as the next few calls to C2/1211 won't zero Morph's timer.  should the battle end quickly, you're now hoping that the end-of-battle code calls C2/0B36.  i don't like relying on it for this, especially given there are multiple ways for a battle to end, and thus multiple holes to plug for patchmakers.

I'm not 100% sure I understand what you're trying to explain, so bear with me... when you say "something like FFFFh", you mean if the subtraction is performed when $3F32 > $3F30, correct? As in, the last tick of the timer?
So if I understand you correctly, this is caused by not zeroing $3F30 in C2/1211? The smallest natural decrementor is 8 (Max supply, after Phunbaba, with Slow), so if $3F30 was exactly FFh, there can be a delay of up to 32 frames to run down the timer again and re-queue Revert, during which the battle could end, thus preventing Revert for about half a second. Correct?

in order:

yes, yes.
yes.
close; i think 64 frames with Slow, because C2/111B exits every other frame.

Quote
With the Stop/Quick/Freeze check in effect, those statuses will prevent C2/1211 from running the few remaining ticks of the timer down and re-queueing Revert until they end, while Sleep will let it keep running down over and over again and try to re-queue Revert every 32 (at most) frames, until the battle ends. If I'm not mistaken.

i thought Freeze was in the same category as Sleep, not Stop/Quick.  it's not a time-freeze; for instance, periodic damage/healing still work under it.  just carving out an exception for Morph -- if that's what you're indeed driving at -- seems a bit inconsistent.


Quote
As you say, this could also happen if the battle ends while Terra is Sleeping, or if Stopped/Frozen (and her timer ran out during their animation), or if her timer ran out while someone cast Quick, and then finished the battle while Quicked.

In the case of Stop/Freeze/Quick being in effect through battle end, since we pause C2/1211 for those statuses, we're always relying on battle ending code to correctly update the supply. In any case, since we're stopping the timer for battle end, we should make sure all battle endings update the supply as well.

but as i also said, my loophole "example is more obnoxious" than some of those, "given the Morph timer initially expired _during_ battle".

however, no disagreement that fixing battle ending scenarios is important.  it's just that when we lean on them for what's actually a mid-battle (albeit almost end-battle) change, we're putting more of our eggs in one basket.

Quote
a well-timed Haste or Slow casting might mitigate the problem of the "a possible loophole ..." scenario laid out in my May 5th post.  the now-recalculated, post-timer-expiration Morph decrementor will be rather large, so that will minimize the wait for a follow-up Revert to be queued.  (a wait that should really be infinitesimal or nonexistent, so this is an improvement, however weird).
---
oops, think i got that wrong, by assuming that a very low Morph supply would simply give a very large decrementor.  but the supply in that example is 0, and there are problems calling C2/0B01 with that:
- you edited out the decrementor capping at 2048.
- even with capping, the earlier "JSR $4792" will perform a divide by 0, and return nonsense.

so it's better called "an ill-timed Haste or Slow casting". :/

thus, i recommend adding back the capping check, and adding a "BEQ $0B2C" before the "JSR $4792", so a minimum supply gives a maximum decrementor.

while it might be tempting to drop the "JSR $0B36" to avoid this particular issue, my May 05, 2016, 10:18:44 PM CDT (May 06, 2016, 03:18:44 AM GMT) post -- and numerous others -- explains why doing that is nonsense and risky.

Sorry to open the debate on this again, but this just has me MORE convinced that updating the supply the very instant the timer runs out is the risky option. I seems safer to update the supply only once we've cleared $3EE2, thus stopping the calls to C2/1211 AND C2/0B01.

correct me if i'm wrong..  this risk presents once you do the following:

1) stop clearing $3EE2, in an effort to fix the bug.  noting that it's not the only way to fix it; relaxing C2/4BB2 could also work.

AND

2) give Function C2/0B01 a responsibility not held in the original game: handling Haste/Slow toggling.  noting that it's not the only option; Haste/Slow could instead use a modified decrementor on-the-fly in C2/1211.

AND

3) despite C2/0B01 having MORE responsibility in the patch, making it LESS robust by dropping the 2048 decrementor cap.  simply because you want to save space.

am i wrong on any of those three?

it seems to me that there's nothing inherently risky about C2/0B36 calls, until you choose to modify the game in a very specific way -- with one of those changes being driven not by any logical flaw in the vanilla code, but purely by space savings.

Quote
I just think it makes sense to only update supply after Morph definitely has ended, as marked by Revert executing, or the battle ending. In other words, dropping the "JSR $0B36" in C2/1211 in favour of a "STZ $3F30".

i still lean towards thinking you're nuts. :P

but a devil's advocate argument to fuck with myself:
if the Morph timer counts down from 65535 to 500, we don't update the Morph supply.  yet when it goes from 500 to 0, updating Morph supply is now vital?  while 0 is indeed a special case, is it special enough to say that a change of 500 outweighs a change of 65035?


Quote
Quote
i think an empty gauge would show up in end battle even if the latter is no longer called, but should really test it.

I'm not exactly sure if by "empty gauge" you mean "no decreasing green gauge" or a literally empty gauge (no increasing white ATB gauge either). If it's the former, clearing $3EE2 at battle end (thus stopping the calls to C2/1211) does indeed clear the green bar and restores the white ATB bar.

cool.. i wasn't sure exactly what i meant, just that the zeroing of the Morph gauge variable should show up in some way.
« Last Edit: May 11, 2016, 03:16:15 AM by assassin »

assassin

  • Bane of Retards
  • *
  • Posts: 1,033
  • space bears are not gentle!
    • View Profile
    • My Barren Webpage
Re: WIP Patch: Permanent Morph bugfix
« Reply #56 on: May 11, 2016, 02:55:25 AM »
Quote
When I said three bytes, I was thinking that we could let C2/0B01 handle the check, but that only checks "if someone is morphed", not "is current target morphed" and we don't want casting Haste/Slow on someone ELSE to change the speed on Terra's Morph bar.

This is a somewhat risky suggestion what with all the hack authors out there, but couldn't we change the LDA $3EE2/BPL in C2/0B01 to CPX $3EE2/BEQ? In vanilla, there should only exist one Morpher (Terra) at a time (not considering craziness like the Rippler bug, but setting Morph via Rippler doesn't initialize their timer, so it doesn't set $3EE2 either).

looks like you talked yourself out of it..  but to chime in, i don't favor sacrificing capability just to save a few bytes.

tangent: setting Morph via a fictional yet somehow-more-conventional-than-Rippler way of a hacked Fire spell does seem to initialize the timer.  this is another reason why i don't favor dropping the 2048 decrementor capping.  Square has in place an elegant system via C2/083F that can get Morph up and running if any turn * sets the status, not merely one command.  however, to have this flexibility while avoiding nonsensical decrementors, you can't lean solely on the Morph menu code's $1CF6 check; the C2/0B01 capping needs to be there.

* not Rippler, which only affects Morph due to a bug.  it's a bit of a special case, likely foiled because some other entity already had Morph going into the Lore.

this isn't the only reason why i want to keep the cap; my last few posts mentioned another.  but it is a case of what happens when free space concerns trump all else, imho.  yes, you can't anticipate and cater to every hypothetical hack out there when coding a patch.  but simply *maintaining* capability present in the original game isn't so much catering to them, as simply playing it safe.  when did free space become THAT scarce?

is it a point of pride, having a "no free space needed!" tag on one's patch?  keep in mind that optimization =/= omission.  many of the people nerdy enough to care about a patch's consumption in the first place will see willy nilly lopping off of Square code for what it is, rather than be impressed.  now, i'm not actually saying the drops are done to impress people..  rather, i think there's a tendency to see Square's byte count usage as a watermark of sorts, that we should stay below.  but given lots of their code is Swiss cheese, why?!  isn't it natural that making things work right without tossing existing functionality might require more space?  some patches lend themselves to optimizing (not omitting) around this, while others not as much.

--------

regarding the mapping of the evil bytes: nice!

Code: [Select]
2: ogre nix can't break
but it does more than this, as seen at C2/1158.  these damned bits doing more than one thing, with only one of the uses being apparent to me, is why i often hesitate to name them at all.  i'm not actually saying my way is better, since there's help in getting *something* down on paper.  but should incomplete descriptions like this get a ", and ???" appended, just to convey they're still in-progress?

anyway, this documentation hopefully brings us closer to fixing the "Infinite turns w/ Quick and X-Magic" bug.  it seems like it should be fairly simple once a few bits are (were?) deciphered, but lack of clarity on these bits has kept me (and others) from acting.

Xenovant

  • Tunnel Armor
  • *
  • Posts: 154
  • (ಠ_ಠ)
    • View Profile
Re: WIP Patch: Permanent Morph bugfix
« Reply #57 on: May 11, 2016, 09:36:08 AM »
anyway, this documentation hopefully brings us closer to fixing the "Infinite turns w/ Quick and X-Magic" bug.  it seems like it should be fairly simple once a few bits are (were?) deciphered, but lack of clarity on these bits has kept me (and others) from acting.

I don't know if it's a coincidence or the destiny mocking me, but yesterday, I was looking exactly at this, trying to find the cause and how to fix it... with no luck, of course  :happy:

It wasn't the first time either, I tried to fix it a couple of years ago, too  :isuck: xDD

assassin

  • Bane of Retards
  • *
  • Posts: 1,033
  • space bears are not gentle!
    • View Profile
    • My Barren Webpage
Re: WIP Patch: Permanent Morph bugfix
« Reply #58 on: May 11, 2016, 01:49:14 PM »
magitek:

Quote
I would hope any potential hack authors interested in allowing multiple Morphers and using this patch would read the documentation I intend to write (where this caveat would naturally feature) and find out how to remedy the problem (commenting/uncommenting some lines in the included .asm file).

while i still am not a fan of the cap drop, maybe going this avenue and showing the old code would deal with any hackers who might give Morph status via alternate means.  a compromise of sorts.  i'd keep the code in and operational, but it's ultimately not my call.

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

Xenovant: have no shame; it's elusive.  i'm zeroing in a little on suspecting Function C2/091F as what'll need editing, but that's just a guess for now.

EDIT: maybe have the C2/0962 area detect whether the C2/093D area freshly set the top bit of $3AA0?  that's even more of a guess, but i think this function is going to be key somehow.
« Last Edit: May 11, 2016, 02:16:00 PM by assassin »

assassin

  • Bane of Retards
  • *
  • Posts: 1,033
  • space bears are not gentle!
    • View Profile
    • My Barren Webpage
Re: WIP Patch: Permanent Morph bugfix
« Reply #59 on: May 11, 2016, 03:01:14 PM »
give this a whirl:
http://assassin17.brinkster.net/forum-posts/quick-gembox-try-fix1.asm

disclaimer: i really don't know what i'm doing.  very likely to have side effects.  EDIT: maybe the skippage should be confined to the final Quick turn.
« Last Edit: May 11, 2016, 03:06:37 PM by assassin »