Users browsing this thread: 1 Guest(s)
Patch: Pugs Rage

#1
Posts: 145
Threads: 20
Thanks Received: 162
Thanks Given: 77
Joined: Feb 2016
Reputation: 8
Status
Enlight
author: SilentEnigma
Version 1.2 released 2021-12-31
Download


Okay! I think this is ready enough.

This patch makes it possible to view the Pugs rage in the field menu and select it in battle.

Big thanks to @assassin for a lot of way-paving on this topic previously at Slick:
https://web.archive.org/https://slickpro...ic=2245.60


& shouts out again to @seibaby for the post that got the wheels turning for me.

A few tidbits on the implementation:
  • In the field menu list (non-Checklist variants), Null is now indicated by "any unexpected I.D. for the rage normally displayed at that position"
  • In the battle menu rage list, Null is now indicated by "any value equal to the preceding value in the list" determined by the max index in the compressed list
  • The learned rage counter $3A9A is allowed to overflow.
  • If $3A9A overflows, a different RNG function (0 - 255 range) is used to pick the random rage ID
  • The random rage IDs for Muddle status are now initialized once together at the start of battle, rather than once before first use. (#$FF needs to indicate Pugs, so it can no longer serve as a null (uninitialized) value here) The rage ID for each ally is 2 bytes, so the high byte is now used to indicate null / non-null, rather than the low byte.
  • The strange loop C2/05ED - C2/05F9 has been nuked.
  • Combining with Terii Senshi's "Rage" makes it possible to learn & use all 256 rages.
The main compromise is that Gau must have at least one rage learned at all times. This is the case with vanilla FF3us, so I think it should be a fair tradeoff for most.

See the Readme for more & better info.


Attached Files
.zip  PugsRage_v1.2.zip (12.32 KB, 6 downloads)
Quote  
[-] The following 3 users say Thank You to SilentEnigma for this post:
  • assassin (12-06-2021), CVReynolds (12-28-2021), Gi Nattak (12-22-2021)

#2
Posts: 199
Threads: 1
Thanks Received: 80
Thanks Given: 26
Joined: Oct 2015
Reputation: 18
Status
None
Code:
Archive Contents
-------------------------------

 PugsRage_H.ips               = basic patch for headered ROMs
 PugsRage_NH.ips              = basic patch for unheadered ROMs

[...]

*oppressive sun is beating down*

 PugsRage-AZ-Des_H.ips        = w/ RagAZ+Descriptions (headered)
 PugsRage-AZ-Des_NH.ips       = w/ RagAZ+Descriptions (unheadered)

[...]

*spots two blurry images of civilization in the distance*

 PugsRage-Check-Des_H.ips     = w/ Checklist+Descriptions (headered)
 PugsRage-Check-Des_NH.ips    = w/ Checklist+Descriptions (unheadered)

[...]

*collapses in a heap*

readme.txt = this file

(weakly:) ...w...water!

this rivals some of leet sketcher's patch releases for Archive Contents size!  that must've been fun to make. ;P

Quote:
  • The random rage IDs for Muddle status are now initialized once together at the start of battle, rather than once before first use. (#$FF needs to indicate Pugs, so it can no longer serve as a null (uninitialized) value here)
  • The strange loop C2/05ED - C2/05F9 has been nuked.

will Function C2/1560 still have C2/1566 (which i think is run for Mimic; worth confirming) defer to an existing Rager with this pre-setting of the $33A8,indices now having occurred?

---

more generally: kickass work.  it'll take me awhile to process all that.

not knowing enough about the relevant Bank C1 code was a key hurdle i faced in considering tackling this (though hardly the only one).  it's curious how little you wound up having to change there!

another was not wanting to have to 16-bit-ize a bunch of things just to allow one more Rage: it'd involve either overhauls and more RAM claiming, or nasty fudges.  i'd known that the field Rage menu (generated in Bank C3) could contain placeholder/intermediate data (as opposed to the Monster ID), as you don't actually *select* anything on it ... unlike the battle Rage menu (of C2), which was thus more formidable.  glad you were able to devise an intermediate system for the latter.
Quote  
[-] The following 1 user says Thank You to assassin for this post:
  • SilentEnigma (12-06-2021)

#3
Posts: 145
Threads: 20
Thanks Received: 162
Thanks Given: 77
Joined: Feb 2016
Reputation: 8
Status
Enlight
(12-06-2021, 04:54 AM)assassin Wrote: this rivals some of leet sketcher's patch releases for Archive Contents size!  that must've been fun to make. ;P

I think it's safe to say I will not be including a set of anti-patches with this. lol

(12-06-2021, 04:54 AM)assassin Wrote: will Function C2/1560 still have C2/1566 (which i think is run for Mimic; worth confirming) defer to an existing Rager with this pre-setting of the $33A8,indices now having occurred?

(The code in question...)
Code:
Rage

C2/1560: B9 A8 33     LDA $33A8,Y    (get monster #)
C2/1563: 1A           INC
C2/1564: D0 13        BNE $1579      (branch if it's already defined)
C2/1566: AE 93 3A     LDX $3A93      (if it's undefined [like with Mimic], get the
                                     index of another Rager, so we can copy their
                                     monster #)
C2/1569: E0 14        CPX #$14
C2/156B: 90 02        BCC $156F      (if the Rager index corresponds to a character
                                     [0, 2, 4, 6] or an enemy [8, 10, 12, 14, 16, 18],
                                     consider it valid and branch.)
C2/156D: A2 00        LDX #$00       (if not, default to looking at character #1)
C2/156F: BD A8 33     LDA $33A8,X    (get that other Rager's monster)
C2/1572: 99 A8 33     STA $33A8,Y    (save it as our current Rager's monster)
C2/1575: 7B           TDC
C2/1576: 99 A9 33     STA $33A9,Y
C2/1579: 8C 93 3A     STY $3A93      (save the index of our current Rager)

Oof, who snuck that reference to $33A8,Y in there!?
...Yeah, I didn't touch this function. Looks like Mimic will grab the wrong rage 99% of the time. (Viva la 1.1!)

I will need to find another way to detect that a mimic is taking place at that moment.
Or, it might be as simple as changing C2/1560 to "LDA $33A9,Y" since the high byte still holds #$FF until the rage occurs, after which it holds #$00. If all works out, that should get us back to vanilla behavior.

But it seems like even vanilla is a bit off, too. Won't Mimic use a stale rage ID in the following scenarios?

  1. Gau rages
  2. Gogo mimics Gau
  3. Gau & Gogo get KO'd
  4. Gau & Gogo revive
  5. Gau rages again (different rage)
  6. Gogo mimcs Gau again
- or -
  1. Gogo rages
  2. Gogo gets KO'd
  3. Gogo revives
  4. Gau rages (different rage)
  5. Gogo mimics Gau
I'm pretty sure the rage ID for each character never gets set back to null during battle.

Anyway, thanks for the tip-off.

(12-06-2021, 04:54 AM)assassin Wrote: it's curious how little you wound up having to change there!

It was few months ago, but iirc the menu stuff in C1 practically wrote itself compared to C2. I'll just assume I was super careful about C1, at least until C2 gets tightened up.
Quote  

#4
Posts: 145
Threads: 20
Thanks Received: 162
Thanks Given: 77
Joined: Feb 2016
Reputation: 8
Status
Enlight
The patch has been updated to v1.1 to address the oversight with mimicked rages.

(12-06-2021, 03:32 PM)SilentEnigma Wrote: Or, it might be as simple as changing C2/1560 to "LDA $33A9,Y" since the high byte still holds #$FF until the rage occurs, after which it holds #$00. If all works out, that should get us back to vanilla behavior.

This alone would have worked, but it also made sense to extend the idea.
Using the high byte for all the applicable null checks, it is no longer necessary to pre-load a random rage ID for each ally at the start of battle. The update uses the high byte method instead, which as an added bonus reduces the free space used by 2 bytes.

Thanks again @assassin for the nudge.

(12-06-2021, 03:32 PM)SilentEnigma Wrote: But it seems like even vanilla is a bit off, too. Won't Mimic use a stale rage ID in the following scenarios?
...
I'm pretty sure the rage ID for each character never gets set back to null during battle.

I tested both scenarios in vanilla, and they behave as suspected.
Never pegged myself as a bug finder for the battle system, but here we are!

Santa
Quote  
[-] The following 1 user says Thank You to SilentEnigma for this post:
  • assassin (12-24-2021)

#5
Posts: 199
Threads: 1
Thanks Received: 80
Thanks Given: 26
Joined: Oct 2015
Reputation: 18
Status
None
your patch is currently robust to the following list:

00 01 02 02 03 04 05 05 05 06 07 07 08 08 08 [...]

in terms of menu handling.  however, given that you ditched the strange loop C2/05ED - C2/05F9 and don't attempt to replicate its list crawling or sanity checking, i believe your patch is NOT robust to the above list in terms of random selection.

if that is acceptable/intended *and* you're willing to go further in that direction, i _think_ you could save ROM space by leaning harder on the $3A9A counter variable and the fact that the in-battle Rage list is compressed (i.e. blank-less).  this should allow the following corner-cuttings / optimizations:

1) shrink Function C2/A691 by a few bytes, replacing the $257D,X check with a $3A9A check:
Code:
phx
tax
pha
lda $3a9a
dec
cmp $01,s
pla
lda $257e,x
plx
rep #$12
bcs done
sep #$02
done:
rtl
i'm not even sure that'll run as intended.

2) drop most of the C2/A6AB function by no longer padding the end of the list.

----

the thing is, i LIKE that your current patch method is robust, for menu handling, to the above example.  so i'm not ACTUALLY advocating you change things in this way.  rather, i'm interested in whether you think it'd work (both the idea and my code attempt), and if so, how many bytes could be squeezed out of the patch code.  or conversely, whether you think it's worth adding "smart crawling" dupe-accounting to the random Rage selection.  (not to say it's necessarily an either-or choice; neither could also suffice.)

admittedly, i first decided to make this post back when i thought i could reduce C2/A691 by ~8 bytes, before remembering to account for the ($3A9A == 0) edge case. Tongue
Quote  
[-] The following 1 user says Thank You to assassin for this post:
  • SilentEnigma (12-24-2021)

#6
Posts: 145
Threads: 20
Thanks Received: 162
Thanks Given: 77
Joined: Feb 2016
Reputation: 8
Status
Enlight
Great stuff, @assassin.

Now, assuming I've done my job right with modding C2/5841 - C2/585F (building the compressed list @ $257E), your example list should not be possible. The only duplicates should be the padding at the end. (Just like you should never actually see FFh in the middle of the compressed list in vanilla. Am I missing something?)

To help my case, I believe the battle rage list was originally not going to be compressed. Then the strange loop would have been necessary:
(note the slightly tweaked C2/05F2)
Code:
Hypothetical Early Build:

C2/05ED: BD 7E 25     LDA $257E,X    (Rage menu.  was filled in C2/580C routine.)
C2/05F0: C9 FF        CMP #$FF
C2/05F2: F0 04        BEQ $05F8      (branch if that menu slot was null [BEQ $0600 in FF3us 1.0])
C2/05F4: C6 EE        DEC $EE        (decrement our random index)
C2/05F6: F0 05        BEQ $05FD      (if it's zero, branch, and use the menu item last read)
C2/05F8: E8           INX
C2/05F9: D0 F2        BNE $05ED      (loop again to check next menu entry)
C2/05FB: 80 03        BRA $0600      (if we've looped a full 256 times and somehow there's
                                     been no match with the random index, branch and just
                                     use enemy #0)

This resembles the loop C2/053C - C2/0549 for locating a randomly selected Magic/Lore spell from an uncompressed list.
With this in mind, I do not take the rage loop itself as any evidence that it is possible to have a compressed rage list with nulls in the middle.

If I am mistaken, then I would definitely want to restore the correct game behavior via some similar list-crawling as you suggested. (But I think we're good, so... onward!)

You raise a great point with the rage count, and that is a beautiful revamp for C2/A691 -- Since every list item of index 0 through ($3A9A) - 1 is going to be a valid rage ID, then why get fancy with duplicate IDs? Just as well to compare the list index to ($3A9A) - 1 and call it a day. Excellent.

We still need the "SEP #$10" at the beginning, but besides that it's testing great so far. We only get 3 bytes out of C2/A691, but then C2/A6AB can be eliminated entirely.
In total, it is going to save about 24 bytes.  Victory

If all checks out, I'll generate another set of patches to incorporate your optimization.

Thanks!

By the way, C2/585F in the "AZ" variants of this patch has a benign bug...
Code:
Pugs Rage v1.1:
C2/585F: D0 E3       BNE $5844  ; noted as BNE $5846 in the readme

Should be:
C2/585F: D0 E5       BNE $5846


Merry Christmas! Santa
Quote  
[-] The following 1 user says Thank You to SilentEnigma for this post:
  • assassin (12-24-2021)

#7
Posts: 199
Threads: 1
Thanks Received: 80
Thanks Given: 26
Joined: Oct 2015
Reputation: 18
Status
None
thanks.

i think (and hope) so.  yeah, my example should just be a hypothetical input.  for some reason, i was half uncomfortable "downgrading" your function to no longer be robust to even that. :/  but since you're comfortable with it, and the patch's random selection does not account for such a situation, might as well make the optimizations.

good theory on the reason for the strange loop, and the C2/05F2 change is sensible and elucidating.  i'd pretty much attributed vanilla's way to a sanity check with "emergency ejection", but that seems a bit abortive and panicky.  your way, complete with the branch tweak, is more logical and useful.  it's plausible that Square would miss code branching too far, if they changed the list format before that code ever activated.

Quote:With this in mind, I do not take the rage loop itself as any evidence that it is possible to have a compressed rage list with nulls in the middle.

good.  i saw no corroborating evidence, either, but would have been antsy about dropping it, "just in case".

re C2/A691:

1. thanks.

2. i was about to include the "SEP #$10" after initially glossing over it to focus on parts i was editing.  but then, i was thinking that the new function is agnostic to Index Register size:
a) it doesn't directly use X with immediates (e.g. "CPX #$00").
b) vanilla already does "C1/8531: BD 7E 25    LDA $257E,X   <= X holds the rage ID" without specifying/switching register size right before.

however, i forgot about the C1/662D path!  so yeah, it's safer to keep the "SEP #$10".  now, upon further examination yet, i think we might be able to:
a) insert "TDC" right before "LDA ($4F)", as C1/63FE will be zeroing the top half of A imminently, anyway.
b) accommodate (a) by changing C1/6635 to a BRA.

but it might not be worth it just to save 2 bytes, as your SEP is very straightforward and reliable (i.e. no code following needed to know X/Y size).

on (b)'s subject of optimizing vanilla callers (of C2/A691): is C1/853A indeed a pointless instruction?  if so, any way to harvest the 3-byte savings that'd result?  (none comes to mind, as C2/A691 needs to be fully callable by C1/662D as well.)

----

Quote:We only get 3 bytes out of C2/A691, but then C2/A6AB can be eliminated entirely.
In total, it is going to save about 24 bytes.  [Image: victory.gif]

If all checks out, I'll generate another set of patches to incorporate your optimization.

Thanks!
you're welcome. Santa
Quote  
[-] The following 1 user says Thank You to assassin for this post:
  • CVReynolds (12-28-2021)

#8
Posts: 34
Threads: 1
Thanks Received: 52
Thanks Given: 34
Joined: Sep 2018
Reputation: 4
Status
None
Congratulations on this fix and thank you. I always wanted someone to fix the Pugs Rage, but I always thought it wouldn't be possible. :O

Do you think it would it be possible to make Gau learn the Chupon and Siegfried Rages immediately upon encountering those enemies in the Colosseum? I know it's different than the usual learning method, but I think it's a better fix than dropping them and their incomplete battle scripts on the Veldt (and the complications that come with it).
Quote  

#9
Posts: 145
Threads: 20
Thanks Received: 162
Thanks Given: 77
Joined: Feb 2016
Reputation: 8
Status
Enlight
The patch has been updated to version 1.2 to incorporate @assassin's optimization.

(12-24-2021, 02:37 PM)assassin Wrote: now, upon further examination yet, i think we might be able to:
a) insert "TDC" right before "LDA ($4F)", as C1/63FE will be zeroing the top half of A imminently, anyway.
b) accommodate (a) by changing C1/6635 to a BRA.

but it might not be worth it just to save 2 bytes, as your SEP is very straightforward and reliable (i.e. no code following needed to know X/Y size).

Oh, I would totally trade readability for two bytes.
Unfortunately, we need to keep the B register value intact so that this 16-bit write is good:

Code:
C1/63FE:    C220        REP #$20        (from C1/6647, C1/6651 etc.)
C1/6400:    9153        STA ($53),Y

...Otherwise the first letter of the rage name is hidden :/

(12-24-2021, 02:37 PM)assassin Wrote: on (b)'s subject of optimizing vanilla callers (of C2/A691): is C1/853A indeed a pointless instruction?  if so, any way to harvest the 3-byte savings that'd result?  (none comes to mind, as C2/A691 needs to be fully callable by C1/662D as well.)

Yeah, looks pointless to me. Not sure how it could be used either. Good to know though.

(12-28-2021, 04:45 PM)CVReynolds Wrote: Do you think it would it be possible to make Gau learn the Chupon and Siegfried Rages immediately upon encountering those enemies in the Colosseum? I know it's different than the usual learning method, but I think it's a better fix than dropping them and their incomplete battle scripts on the Veldt (and the complications that come with it).

Sounds very doable. I'll check it out.

Happy New Year! Hello
Quote  
[-] The following 2 users say Thank You to SilentEnigma for this post:
  • assassin (01-02-2022), CVReynolds (01-01-2022)

#10
Posts: 199
Threads: 1
Thanks Received: 80
Thanks Given: 26
Joined: Oct 2015
Reputation: 18
Status
None
eep, i majorly brainfarted, and lumped A in with X and Y as far as size changes clearing the top half!
Quote  



Forum Jump:

Users browsing this thread: 1 Guest(s)


Theme by Madsiur2017Custom Graphics by JamesWhite