• Welcome to Final Fantasy Hacktics. Please login or sign up.
 
April 25, 2024, 12:08:48 am

News:

Don't be hasty to start your own mod; all our FFT modding projects are greatly understaffed! Find out how you can help in the Recruitment section or our Discord!


Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Messages - Glain

561
PSX FFT Hacking / Re: ALMA 3: previewability 0.1
June 27, 2011, 12:43:31 pm
More recent version of MIPS or not, I dunno. It's something to do with the way the emulators work that diverges from what the actual PSX hardware does, in certain conditions. I don't really think we can know why that is unless we actually saw the source code of the emulators... but it's not important, as we should be considering the load delay anyway.
562
Ah, you've uncovered a bug. That was supposed to work, but the program was doing some things incorrectly. I've gone ahead and fixed it; I've attached a new version to the original post. Happy encoding... let me know if you find anything else that seems off!

Edit: I'm sure 0xaaaaaa is just an example, but if you do try to use that as a test case, I should probably point out that it isn't a valid address for j, as it's not a multiple of 4 and therefore can't be a code address :) I was testing encode/decode on it and was confusing myself when I saw that it decoded to [j 0xaaaaa8] but that's correct because it's the closest previous code address.
563
Good to see this thread. I agree with fdc in that we need to rewrite previous patches that don't account for load delay, as they would have to be considered unstable.

Just to be a bit more clear and provide some examples on what we need to do here...

Anytime you use a load command (lw,lh,lb,lhu,lbu,etc) that loads data from memory, the next line is the load delay slot for that command and the value being loaded is not ready yet. The register's value is not ready to be used until the line after the load delay slot (the second line after the load command). Basically, you have to worry about the load delay slot when you use commands that start with l, with the exception of lui, because that particular command doesn't load anything from memory.

As fdc pointed out, you can usually just place a nop command between the load command and where the value is used. However, if you can rearrange code in another way to avoid using values before they're ready, that may be a better solution. As an example, here's an attempt to take the value in register r8, add two values from memory to it, and save it to another location.

Wrong version
lbu r2,0x0022(r4)       # [Load byte] : r2 = [First value from memory]
addu r8,r8,r2             # r8 = r8 + r2                                                                         (r2's delay slot : Attempt to use r2 here is invalid!)
lbu r3,0x0023(r4)       # [Load byte] : r3 = [Second value from memory]
addu r8,r8,r3             # r8 = r8 + r3                                                                         (r3's delay slot : Attempt to use r3 here is invalid!)
sb r8,0x0024(r4)        # Save r8 (the sum) to memory

Correct version
lbu r2,0x0022(r4)       # [Load byte] : r2 = [First value from memory]                                     
lbu r3,0x0023(r4)       # [Load byte] : r3 = [Second value from memory]           (r2's delay slot) 
addu r8,r8,r2             # r8 = r8 + r2                                                           (r3's delay slot, but it's fine to use r2 here)
addu r8,r8,r3             # r8 = r8 + r3                                                           (It's fine to use r3 here)                       
sb r8,0x0024(r4)        # Save r8 (the sum) to memory

There's nothing wrong with having consecutive load statements (subroutines do this all the time when they load values off the stack), as long as you use different destination registers (why wouldn't you?). You just have to make sure you don't use a register if it is in its own delay slot.
564
A few issues were brought to my attention with this, so it looks like it needed an update. I attached it to the original post. I also edited the OP to clean it up a bit.

Anyhow, v4's changelog:
     * Fixed a bug where the program failed to encode certain I-type instructions (bgez,blez,bgtz,bltz,bgezal,bltzal).
     * Fixed a bug where the program could incorrectly decode certain I-type instructions (bgez,blez,bgtz,bltz,bgezal,bltzal).
     * Added support for mthi/mtlo instructions.
565
PSX FFT Hacking / Re: ALMA 3: previewability 0.1
June 20, 2011, 06:44:49 pm
The MIPS II vs MIPS IV stuff seems a bit out of left field to me. Actually, according to this link, the PSX processor (R3000) is actually MIPS I and not MIPS II.

If we're worried about different versions of the same architecture, then there might be some commands in later versions of MIPS that don't exist on the PSX processor, but we tend to use a pretty specific subset of commands for most things anyhow. I'd be a bit surprised if we suddenly started using commands that don't exist on the processor. For example, if you can use my app (MassHexASM) to encode it, it should be supported by the R3000. I'm actually a bit surprised I haven't gotten any feedback on that app being unable to encode something or other (I'm not sure I got the whole R3000 command set).

The only thing that really comes to mind here that would be relevant with earlier vs. later versions of MIPS would be a load delay slot thing, but that seems too obvious...
566
PSX FFT Hacking / Re: ASM Collective BATTLE.BIN Map
June 13, 2011, 08:20:49 pm
The checkboxes are what the evade ASM is checking when it does the whole "Skip A-EV if accessory slot isn't an accessory" kind of thing. I thought that might be why the evasion was being skipped, but it seems that's not the case.

There's another funky thing about the left/right hand slots. In battle, it's stored like: ([Right hand weapon], [Right hand shield], [Left hand weapon], [Left hand shield]). All as separate slots. Anything that doesn't apply is just set to [Empty]. So if a character had a weapon and a shield, it would be: ([Equipped Weapon], [Empty], [Empty], [Equipped Shield]).

I set up a quick scenario like this, using Gold Shield as the armlet-type shield and put it on Mustadio, and ran it in the pSX debugger. What I saw in memory for Mustadio's equipment was this:

[Left hand weapon] = [Romanda Gun]
[Left hand shield] = [Empty]
[Right hand weapon] = [Gold Shield]
[Right hand shield] = [Empty]

...Oops. The obvious guess would be that switching the item type made the game believe that the Gold Shield belonged in the weapon slot instead of the shield slot. It's got me a bit curious, so I may look into it later.
567
PSX FFT Hacking / Re: ASM Collective BATTLE.BIN Map
June 11, 2011, 09:01:26 pm
Quote from: Celdia on June 11, 2011, 05:23:25 pm
Okay, so I ran into a snag I didn't foresee in my design stages and figured you guys could figure this one out. I think Glain's post at the top of this page actually might have the answer in it technically. Its another one of my simple ideas that I don't think applies so simply behind the code.

I made Platina Shield into an Armlet Type item, making it equipable by everyone in their Hand slots. The equip preview displays correctly but the item won't apply any evasion % to the unit its equipped on. I want it to apply Armlet-type Item Evade % to Shield Evade on the unit. I'm wondering if my problem is something like the notation in (SECTION 4) "# Skip A-EV if Accessory isn't actually an accessory" causing it to ignore the evasion on the item because its claiming to be a shield but isn't.


It looks like that could happen if Platina Shield no longer had the Shield checkbox selected in FFTPatcher (to the right of item type).
568
PSX FFT Hacking / Re: ASM Collective BATTLE.BIN Map
June 08, 2011, 11:40:28 pm
Quote from: Celdia on June 08, 2011, 08:25:07 am
@FDC: I was looking to rewrite formula 5E to replace PA for every instance of MA and found you had the formula flagged as a clone of 1E. Surprise, surprise, I come in here and find out you've got this already figured out. I just need to make sure that I'm reading everything right and that its not actually calling 1E's code so that I can change 5E without altering 1E.


I can probably comment on this as I've done a few formula hacks.

It's not that 1E and 5E necessarily have anything to do with each other, except that they both call a common routine... the one that calculates damage. That is, all the work in calculating damage is done here (in both formulas):

0c062269 jal 0x001889a4   Truth Formula

As far as I can tell, changing 5E without changing 1E would mean you'd either have to create a new routine for 5E to call, or edit the existing one to take a parameter that can tell it whether to use PA or MA.
569
I tried to trace that routine a few times... it's fairly insane and the recursion makes it hard to remember how far into it you are. I'm not entirely sure how many registers it changes, but it's a lot.

FFT's compiled code was compiled under these conventions, which specifies that registers r16-r23 ($s0-$s7) must be preserved across routine calls (i.e., that these registers must be in the same state they started in when the routine returns). Standard practice is to assume that all other standard-use registers are overwritten (and that is probably not far off for this routine).

So basically, before calling a routine, save what you want saved either to:
1. The stack
2. r16-r23 (but you must save these registers to the stack before using them, and load them when done before returning)
3. Memory somewhere (if you want to save something outside the scope of this routine's stack frame, i.e. a global variable)

Since this is true for every routine, it saves us from having to figure out which routines change which registers, unless we're so cramped for space that we can't do things the normal way. But I'd assume this particular routine (0x13b590) changes everything but r16-r23, because it's an absolute beast.
570
Help! / Re: Ramza's Job Change
May 28, 2011, 11:15:17 am
There might be a few other places you'd have to change, and there are probably a few more pieces to this puzzle, but yeah. You'd have to rearrange base classes, of course (04 is one of Delita's, and you'll encroach upon more as you go higher).

I'm not even sure how general this is. It might not only apply to Ramza, actually... the check is basically (is base job < threshold ? OKAY, OVERWRITE!).
571
Help! / Re: Ramza's Job Change
May 28, 2011, 12:57:23 am
I believe I just figured it out. This is very interesting...

It looks like Ramza's base job (and some of his other data) is automatically overwritten if the relevant ENTD places Ramza (base class 01,02,or 03) with Join After Event specified!

I managed to get his base job from 01 to 03 after Zeakden by using 03 Ramza instead of 02 Ramza in the 110 Orbonne Monastery ENTD.
What about Chapter 3 to Chapter 4, you say? Ramza is still 02 Ramza at the scene where he's talking to Rafa and Malak after the whole Riovanes thing happens... but there's another scene between Olan and Orlandu (ENTD 137) that appears before you can start doing anything in Chapter 4. Looking at that scene in ENTD, Olan and Orlandu are there as expected... but wait, what's Ramza doing in there? He's not present in the scene, but he's there in the ENTD, set to invisible, set to 03 Ramza / 03 Squire and Join After Event...

...yeah.

...There must be a few checks in this routine or somewhere else that make sure that we're looking at a Ramza, Join After Event unit in the ENTD and that the unit we're on is Ramza, but anyhow, here's the juicy part:


(...)
0005acb8: 0c0166bc jal 0x00059af0
0005acbc: 02202021 addu r4,r17,r0               # Get unit offset for specified index (out-of-battle data)
0005acc0: 00402021 addu r4,r2,r0
0005acc4: 90830001 lbu r3,0x0001(r4)
0005acc8: 340200ff ori r2,r0,0x00ff
0005accc: 1062002b beq r3,r2,0x0005ad7c                      # If unit didn't exist, skip ?                 
0005acd0: 00000000 nop
0005acd4: 90820000 lbu r2,0x0000(r4)            # Load in base job of specified unit
0005acd8: 00000000 nop
0005acdc: 2c420004 sltiu r2,r2,0x0004            # Are we Ramza? (Base job < 4) (Wonderful hardcoding!!)
0005ace0: 10400026 beq r2,r0,0x0005ad7c            # If not, skip
0005ace4: 00000000 nop
0005ace8: 90820002 lbu r2,0x0002(r4)            
0005acec: 92430000 lbu r3,0x0000(r18)            # Load in base job from the ENTD
0005acf0: 2c420003 sltiu r2,r2,0x0003
0005acf4: a0830000 sb r3,0x0000(r4)               # Overwrite Ramza's base job with it!!!
(Continue overwriting Ramza's data and doing other things...)
572
So I found a way to use the story progression byte after all...

Way back in my first post in the thread (and the entire forum, as it happens), I made reference to attempting this, and finding the WORLD.BIN subroutine (RAM 0xef1a8) that seemed to get it. After a bunch of investigation, I seem to have found that same routine in BATTLE.BIN at RAM 0x13b590. It's the same code but with some different addresses, because we're elsewhere in memory. Makes you wonder why the routine isn't just in SCUS, but anyhow, since it's in BATTLE.BIN, I can use it in the gear picking code.

I believe this routine is actually what gets any script variable, i.e., those set/checked by TEST.EVT and ATTACK.OUT, with r4 = [the index of the variable]. Story progression is variable 0x6F (and this parameter is specified in WORLD.BIN as well when checking the shop items, but I didn't understand the significance of it before). That means, if I want the story progression byte, I go:

jal 0x0013b590
ori r4,r0,0x006f

Not so bad. Using story progression instead of unit offset 0x0169, we get this:


andi r5,r5,0x00ff          # Most likely worthless, but carried over from 0x5cc98
addiu r29,r29,-0x001c      # Make space on the stack
sw r31,0x0014(r29)         # Save return address to stack
sw r13,0x0004(r29)         # Save 0x5cc98's args to the stack (registers might be changed by 0x13b590)
sw r5,0x0008(r29)
sw r6,0x000c(r29)
sw r7,0x0010(r29)
jal 0x0013b590            # Find story progression variable! (code for this variable = 0x6f)
ori r4,r0,0x006f
ori r14,r2,0            # r14 = r2 (Story progression variable)
lw r31,0x0014(r29)         # Load return address from stack
lw r13,0x0004(r29)         # Load 0x5cc98's args from the stack
lw r5,0x0008(r29)
lw r6,0x000c(r29)
lw r7,0x0010(r29)
addiu r29,r29,0x001c      # Set stack back to original size
ori r2,r0,0x0020         # Set r2 back (0x5cc98)
jr r31                  # Return
nop


It's still nearly the same amount of space as the other one, even though there's far less relevant logic, because I had to save a bunch of registers on the stack that the gear-picking routine was using and I didn't know if 0x13b590 would overwrite them (it probably did). I also had to change the gear-picking routine to check the item's story progression instead of the item level (8 bytes to the right).

Anyhow! [Story progression] and [Unit offset 0x0169] patches are mutually exclusive, but the [more selective gear] patch/bugfix is totally independent of either of them.

Unlike the unit offset one, the story progression patch should be fire and forget -- no need to set anything in FFTPatcher, unless you wanted to edit item tiers. You may see a bit less gear variety though, since there are less item tiers than there are levels.


 <Patch name="Random unit gear based on story progression">
   <Description>
     Random unit gear based on story progression
   </Description>
   <Location file="BATTLE_BIN" offset="F59BC">  
     FF00A530
     E4FFBD27
     1400BFAF
     0400ADAF
     0800A5AF
     0C00A6AF
     1000A7AF
     64ED040C
     6F000434
     00004E34
     1400BF8F
     0400AD8F
     0800A58F
     0C00A68F
     1000A78F
     1C00BD27
     20000234
     0800E003
     00000000
   </Location>
   <Location file="SCUS_942_21" offset="4D49C">
     9400BFAF
     21688000
     6F72050C
     20000234
   </Location>
   <Location file="SCUS_942_21" offset="4D52C">
     00000000
   </Location>
   <Location file="SCUS_942_21" offset="4D5D8">
     0A00A390
   </Location>
 </Patch>

573
Help! / Re: Ramza's Job Change
May 26, 2011, 07:53:46 pm
I happened to have a save after Zeakden, so I looked into this a little bit...

Ramza's sprite set / base class is changed from 01 to 02 at RAM address 0x5acf4, part of a subroutine call beginning at 0x5ac1c (Itself called at 0x5a9f0). It's a long routine, and it sets a few other things (current job also changes from 01 to 02 here, for example). Looks like it's basically a "change unit parameters" call or something. (or maybe just "change base class / job" but it seemed to be doing too much for just that).

From eyeballing the addresses, that code would be in SCUS. Not sure what exactly causes this code to be called in the first place, but maybe this'll give a starting point?

Other notes:

Before changing the data, it makes a call to a routine at 0x59af0 (note, not the same as 0x5a9f0 that calls it; why do these addresses have to be so similar? grrr) with r4=0 and gets back an address to Ramza's unit data, so I suspect that routine probably gives back an address in memory to the unit with index specified by r4.
574
I talked to fdc a while back about looking at some of the evasion routines, and one thing we talked about was that there were several routines for different kinds of evasion... three called from formulas (physical, charge, and magic). And looking into that, there's another routine that finds the various evasion numbers (A-EV, S-EV, C-EV) within the physical/magic sections that's nearly duplicated, just that it grabs magic evade instead of physical evade for the magic sections. It also turns out that those routines are next to each other in BATTLE.BIN... which means, if we wrote one big routine, we could save some space... or if we decided to change one, we'd only have to change it in one place, in theory.

I came up with this as a combined routine for finding either physical or magic evade numbers (This was the test case I was using for my app, by the way). Here I'm using r4 ($a0) as the parameter (0=physical, 1=magic):



COMBINED EVASION NUMBERS ROUTINE
PARAMETERS: r4 = TYPE (0 = physical, 1 = magical)

# SETUP (r16 = TYPE)
addiu r29,r29,0xffe8
sw r31, 0x0010(r29)
sw r16, 0x0014(r29)
addu r16,r4,r0                              # r16 = r4
lui r4,0x8019
lw r4,0x2d98(r4)                           # r4 = [Target unit]         
bne r16,r0,(SECTION3)                        # Skip next section if Type==MAGIC
addu r7,r0,r0                              # r7 (Can use weapon guard) = 0 (false)

(SECTION2):                        # CHECK FOR WEAPON GUARD (PHYSICAL)
lbu r2,0x008e(r4)                              
nop
andi r2,r2,0x0040                           # r2 = [Reaction is Weapon Guard]   
beq r2,r0,(SECTION3)                           
nop            
jal 0x0018130c                              # CALL: Weapon Guard usability            
nop
sltiu r7,r2,0x0001                           # r7 = !r2                              

(SECTION3):                        # INITIALIZE
ori r2,r0,0x0064
lui r1,0x8019
sb r2,0x38dc(r1)                           # Hit rate = 100
lui r1,0x8019
sb r0,0x38de(r1)                           # A-EV = 0
lui r1,0x8019
sb r0,0x38df(r1)                           # R-EV = 0
lui r1,0x8019
sb r0,0x38e0(r1)                           # L-EV = 0
bne r16,r0,(SECTION3p1)                        
addu r2,r0,r0                               
lbu r2,0x0043(r4)                           

(SECTION3p1):                     # C-EV
lui r1,0x8019
sb r2,0x38e1(r1)                           # C-EV = (Type==MAGIC) ? 0 : [C-EV]
lbu r2,0x0006(r4)                                                   
nop
andi r2,r2,0x0020
bne r2,r0,(RETURN)                           # If target is monster, RETURN
nop

(SECTION4):                        # A-EV
lbu r2,0x001c(r4)
lui r5,0x8006
addiu r5,r5,0x2eb8
sll r3,r2,0x01
addu r3,r3,r2
sll r3,r3,0x02
addu r3,r3,r5
lbu r2,0x0003(r3)            
nop
andi r2,r2,0x0008
beq r2,r0,(SECTION5)                        # Skip A-EV if Accessory isn't actually an accessory
nop
lbu r2,0x0004(r3)
nop
sll r2,r2,0x01
lui r1,0x8006
addu r1,r1,r2
addu r1,r1,r16                              # Use magic evade (1 offset higher) if Type==MAGIC
lbu r2,0x3f58(r1)                           # r2 = [Accessory A-EV]
lui r1,0x8019
sb r2,0x38de(r1)                           # Save [A-EV]

(SECTION5):                        # R-EV (Right hand)
lbu r3,0x001d(r4)                           # r3 = [Right hand weapon of target unit]
nop
sll r2,r3,0x01
addu r2,r2,r3
sll r2,r2,0x02               
lui r1,0x8006
addu r1,r1,r2               
lbu r5,0x2ebb(r1)            
lbu r3,0x001e(r4)                           # r3 = [Right hand shield of target unit]
lbu r8,0x2ebc(r1)            
sll r2,r3,0x01
addu r2,r2,r3
sll r2,r2,0x02               
lui r1,0x8006
addu r1,r1,r2               
lbu r3,0x2ebb(r1)            
lbu r6,0x2ebc(r1)            
andi r2,r5,0x0080            
beq r2,r0,(SECTION5p1)                        # IF [Right hand weapon] not a weapon, skip to shield section
nop
beq r7,r0,(SECTION5p1)                        # IF [No weapon guard], skip to shield section
sll r2,r8,0x03
lui r1,0x8006
addu r1,r1,r2            
addu r1,r1,r16                              # Use magic evade if Type==MAGIC
lbu r2,0x3abd(r1)                           # r2 = [Right-hand weapon evade]
j (SECTION5p2)                              # Skip to save
nop

(SECTION5p1):                           # Shield section
andi r2,r3,0x0040            
beq r2,r0,(SECTION6)                        # IF [Right hand shield] not a shield, skip
sll r2,r6,0x01
lui r1,0x8006
addu r1,r1,r2
addu r1,r1,r16                              # Use magic evade if Type==MAGIC
lbu r2,0x3eb8(r1)                           # r2 = [Right-hand shield S-EV]

(SECTION5p2):                           # Save R-EV
lui r1,0x8019
sb r2,0x38df(r1)                           # Save [R-EV] (Right hand evade)

(SECTION6):                        # L-EV (Left hand)
lbu r3,0x001f(r4)                           # r3 = [Left hand weapon of target unit]
nop
sll r2,r3,0x01
addu r2,r2,r3
sll r2,r2,0x02               
lui r1,0x8006
addu r1,r1,r2               
lbu r5,0x2ebb(r1)            
lbu r3,0x0020(r4)                           # r3 = [Left hand shield of target unit]
lbu r8,0x2ebc(r1)            
sll r2,r3,0x01
addu r2,r2,r3
sll r2,r2,0x02               
lui r1,0x8006
addu r1,r1,r2               
lbu r3,0x2ebb(r1)                        
lbu r6,0x2ebc(r1)            
andi r2,r5,0x0080            
beq r2,r0,(SECTION6p1)                        # IF [Left hand weapon] not a weapon, skip to shield section
nop
beq r7,r0,(SECTION6p1)                        # IF [No weapon guard], skip to shield section
sll r2,r8,0x03
lui r1,0x8006
addu r1,r1,r2
addu r1,r1,r16                              # Use magic evade if Type==MAGIC
lbu r2,0x3abd(r1)                           # r2 = [Left-hand weapon evade]
j (SECTION6p2)                              # Skip to save
nop

(SECTION6p1):                           # Shield section   
andi r2,r3,0x0040            
beq r2,r0,(RETURN)                           # IF [Left hand shield] not a shield, skip
sll r2,r6,0x01
lui r1,0x8006
addu r1,r1,r2
addu r1,r1,r16                              # Use magic evade if Type==MAGIC
lbu r2,0x3eb8(r1)                           # r2 = [Left-hand shield S-EV]

(SECTION6p2):                           # Save L-EV
lui r1,0x8019
sb r2,0x38e0(r1)                           # Save [L-EV] (Left hand evade)

(RETURN):
lw r31,0x0010(r29)
lw r16,0x0014(r29)
addiu r29,r29,0x0018
jr r31                                    # RETURN
nop


That one is probably just about as big as the routine for physical evade was, so there'd be a decent chunk of space gained here (maybe 50-75 lines?), if we wanted to expand the routine.

Then there'd be the main evasion routine to combine:


COMBINED
PARAMETERS: (r4=TYPE (0=physical, 1=charge(physical), 2=magic))

addiu r29,r29,0xffe8
sw r31,0x0010(r29)
sw r16,0x0014(r29)
sw r17,0x000c(r29)
addu r16,r4,r0               # r16 = r4 (0=physical, 1=charge, 2=magic)
slti r17,r16,0x0002
slti r17,r17,0x0001            # r17 = (0=physical/charge, 1=magic)
jal 0x00184f9c               # Equipment Evasion Setting
addu r4,r17,r0               # (r4 == TYPE)
bne r17,r0,(SECTION2)            # IF (TYPE == MAGIC), skip
nop
jal 0x001852e4               # Concentrate Calculation (Attacker)
nop
jal 0x00185328               # Dark/Confuse/Transparent Calculation (Attacker)
nop

(SECTION2):
jal 0x0018537c               # Abandon Calculation (Defender)
nop
jal 0x001853f4               # Evasion Changes due to Status (Defender)
nop
bne r16,r0,(SECTION3)            # If (TYPE != PHYSICAL), skip
nop
jal 0x00185738               # Weather Effects on Bows/Crossbows
nop

(SECTION3):
bne r17,r0,(SECTION4)            # If (TYPE == MAGIC), skip
nop
jal 0x001854fc               # Facing Evade Calculation
nop

(SECTION4):
jal 0x00185814               # Combined Evasion Roll (Calculates Hit %)
nop
lw r31,0x0010(r29)
lw r16,0x0014(r29)
lw r17,0x000c(r29)
addiu r29,r29,0x0018
jr r31
nop


I also replaced the call to a function that did nothing but delegate to another function (which I mentioned earlier in the thread). This is basically a bunch of function calls, so I was just selecting which ones were needed. Here r4 ($a0) is the type parameter, but now is (0=physical, 1=charge, 2=magic).

Of course, that means all the formulas would have to specify r4's value before calling the combined evasion routine (0x188510). That's annoying but luckily there is a nop after each call to the evasion functions, so you could replace the nop with:

Physical: addu r4,r0,r0
Charge: addiu r4,r0,1
Magic: addiu r4,r0,2

A one-time patch could change them, but it's still annoying because new formulas would have to remember to follow that format. Anyhow, this is just an idea for how to consolidate these routines.
575
All right, I'm releasing an updated version (v3) because I realized it needed a few fixes.

* Added support for comments on the same line as commands. (They'll need to preceded by #)
* Fixed a bug where labels would only be recognized if they were from earlier points in the code. (Branches to labels could only go backwards) (When defining a label you still need to put a : after it)
* Fixed a bug involving placement of tab characters that could cause the program not to recognize lines of code.
* Added support for nor/not instructions.

With this version I encoded a pretty big (100+ statements) code block with labels and comments (and using that as a test case was what prompted the release of this version). The goal, as always, is to be able to just copy/paste ASM and get the hex in the right format.
576
So I was looking at some of the physical evasion stuff, and though it turns out SA had already documented most of what I looked at, I did find something fairly interesting. The last of the physical evade routines is the one that actually does the evasion roll, but my analysis of it would look like this:


00188488: 27bdffe8 addiu r29,r29,0xffe8
0018848c: afbf0010 sw r31,0x0010(r29)
00188490: 0c061605 jal 0x00185814               Combined evasion roll (Sets ability's hit status)
00188494: 00000000 nop
00188498: 3c028019 lui r2,0x8019
0018849c: 8c422d90 lw r2,0x2d90(r2)               
001884a0: 00000000 nop
001884a4: 90420000 lbu r2,0x0000(r2)            
001884a8: 00000000 nop
001884ac: 2c420001 sltiu r2,r2,0x0001            Find ability's evaded status (Why not just use 0x00185814's return value?)

001884b0: 8fbf0010 lw r31,0x0010(r29)
001884b4: 27bd0018 addiu r29,r29,0x0018
001884b8: 03e00008 jr r31                     RETURN r2 (Exactly the same as 0x00185814's return value)
001884bc: 00000000 nop                     


It looks like the entire call is worthless except for the call to another routine... they even return the same thing. I tried replacing the call to 0x188488 with a call to 0x185814 and everything still seemed to work fine, so this may free up some space to replace this code with something else.
577
Hacking/Patching Tools / FFT Patcher (.497)
May 14, 2011, 03:57:55 am

Latest release (.497) here. (Direct download)




Original post from fdc:

I know everyone's been waiting forever for this, so here it is.

This is the original from Melonhead for .478, errors and all.

NEWEST VERSION HERE:
http://ffhacktics.com/smf/index.php?topic=7163.msg212754#msg212754

-Elric
578
Quote from: Lazy Bastard on May 10, 2011, 03:39:30 pm
Nice app. Mind if I add it to the Downloads section of GameHacking.org?

Incidentally, it should be noted that Renegade64 (which, by the way, has been superseded by RenegadeEX) isn't made useless by this tool, except in the specific way you previously used it. It's still a very good hacking tool, with many other uses.


Yeah, I'm pretty sure this context was understood for Renegade. Sure, you can host my program if you want; if I do make updates I'll probably put them here though.

Regarding armips: I checked it out, pretty cool. It looks like it's both an assembler and a patcher, which in certain situations is going to be easier, but in others may not fit as well, like in this case (Since we're using FFTorgASM as patcher, we really just needed an assembler). Just depends on what you're trying to do. If I was just going to assemble codes and was going to load a program as an external file, I'd just use PCSpim probably (heck, it even executes the code).
579
Thanks guys! Glad to see the program being used and speeding things up! Didn't expect I'd just waltz right in and make Renegade totally useless, but if that's what I've done then that's sorta hilarious and awesome at the same time.

Xifanie: Quicksave as in a pSX quicksave, like a save state? That would be interesting... I may have to look into that.

formerdeathcorps: I believe it would encode the negative offsets correctly, but would decode the hex to a positive offset. A new version I've just added to the original post should rectify that. I wasn't sure which instructions treated the offsets as postive/negative, so I got my hands on SPIM and played around a bit.

(I totally didn't just realize that the "addiu" instruction on the stack pointer that I keep seeing in subroutines is actually a subtraction instead of a huge addition... :) I was always wondering how that register got back to its original state... now it makes sense)
580
Latest version now included with FFTPatcher suite! (Thread: https://ffhacktics.com/smf/index.php?topic=7163)

---

After being frustrated with manually switching ASM byte order, I've decided to write MassHexASM, a program that lets you encode directly to little endian, and furthermore, should be able to encode ASM in a format where you just copy/paste the output to an XML patch (or what have you).

This program was written in C#/.NET, so you'll need some version of the .NET framework to get this to run. I believe it should work with .NET version 2.0 or later. Other than that, should be all good. Let me know if you find bugs and I'll do what I can to fix 'em.

Note on using the program: If you define a label, you need to put a colon ( : ) after it. If there is a command on the same line, separate it from the label by at least one space.

Some differences between MassHexASM and the Renegade64 assembler:
     * The little endian format uses the correct byte order: B4,B3,B2,B1. It also outputs the hex directly instead of trying to format for Gameshark.
     * My program encodes BEQ and BNE instructions properly. Renegade64 switches the order of the registers for some reason, which it can get away with because they're just used for an equality check, but it is still weird.
     * Encoding and decoding in the same form with little endian format. In testing, I've looked in the various XML files used by FFTorgASM, pasted patches straight into my program, entered a starting address, specified little endian and decoded it. Useful if you've got encoded hex but can't remember what the ASM is.
     * Ability to specify a starting address without using .org (Important for decoding as well)
     * You can pad the output with spaces if you want to preserve formatting when pasting into an FFTorgASM patch.
     * You should be able to use same-line labels. (i.e. put a label and the next instruction on the same line)
     * Registers can use the $[num] format. (e.g. $4 instead of r4). You can still use names like $s0, $t2, etc.
     * You can specify negatives as offsets in save/load instructions (i.e. -0x7fad, as the screenshot shows). The negative sign has to be before the 0x, not after.
     * Encodes statements without regard to whether or not they make sense. This means Renegade64 will stop you in certain cases where my program won't, primarily when BEQ/BNE addresses are invalid.

Java version now available... check the attachment list. To use it, run "java -jar JMassHexASM.jar" in the command line in the directory that contains the jar file. (Updated: I fixed a bug with the Java version)

Changelog:

v13:
      * LEDecoder has been added to MassHexASM, accessed via a menu item (Form -> LEDecoder), and LEDecoder is no longer a standalone program.
      * MassHexASM now checks the ASM upon encoding or decoding and displays warnings for various possible hazards, listed below.
      * MassHexASM uses the latest version of the ASM Encoder/Decoder, which includes numerous fixes, as well as the latest changes:

     * Added check functionality that warns about various possible hazards:
        * Load delay (Attempt to use a loaded value from memory immediately after loading it; ignored in PSP mode)
        * Unaligned offset (When doing a memory load or store)
        * Using mult or div within 2 commands of mflo/mfhi
        * Adding or subtracting a value from the stack pointer register ($sp, r29) that is not a multiple of 8
        * Putting a branch inside a branch delay slot
       
    * Added the ability to use %hi(address) and %lo(address) to get the high and low 16-bit parts of an address.  The low 16-bit portion is considered to be signed.  e.g.:
        * .label @address_current_action, 0x80192d90
        * # (...)
        * lui   t0, %hi(@address_current_action)
        * # (...)
        * lw    t0, %lo(@address_current_action)(t0)
       
        * Note that %hi(address) will be one higher than first 16 bits when the low 16 bit value is negative.
        *   e.g. %hi(0x8018f5f0) = 0x8019; %lo(0x8018f5f0) = -0x0a10 (0xf5f0).
        * This means that the %hi,%lo combination works well with load and store commands, and also with the (lui, addiu) pattern, but not with the (lui, ori) pattern.
       
    * Fixed some issues with the load and store psuedoinstructions when using values between 0x8000 and 0x10000.
       
    * Modified the error checking functionality to report more errors, particularly when an undefined label is referenced.
       
    * Now recognizes GTE and COP0 register names as used by pSX's disassembly.
    * Added beqz (branch if equal to zero) and bnez (branch if not equal to zero) psuedoinstructions.
   
    * Fixed potential issues with byte order that could have occurred if running on a big endian machine.
   
    * Added "replaceLabels" optional attribute to the <Location> tag in XML patches, which, if set to "true", will replace any labels found in the hex with the correct hex address.  The idea here is basically to be able to create dispatch tables using a list of labels if so desired.
   
    * (Undocumented from last release)
    * Added "equivalences" which function similar to macros. Defined with .eqv and are replaced with the specified value before encoding.  e.g.:
        * .label @address_controller_input, 0x80045944
        * .eqv   %start_button_flag, 0x0800
        * # (...)
        * lw     t0, @address_controller_input
        * nop
        * andi   t0, t0, %start_button_flag
        * # (...)

    * The "li" pseudoinstruction now accepts negative values correctly.

v12:

     * Changed the window anchoring so that resizing the window causes the ASM and/or Hex textboxes to expand.  Expanding the window to the right now causes the ASM textbox to expand (as well as the messages window); expanding downward causes both ASM and Hex to expand.
     * Any label starting with the '@' character is now a "persistent label" that will stay around even if not defined in the current code block.
     * Added ".label" directive to define label addresses without putting them inside the code.  The format is: .label (name), (address).  Example: .label  @clear_data_block, 0x05e644
     * Decoding no longer requires newlines; you should just be able to paste straight from a hex editor and it will decode every 4 bytes (8 hex digits) as a command. 
     * Fixed some bugs relating to labels that contained a command on the same line.
     * The encode/decode textboxes are no longer limited to 32767 characters.

v11:

     MassHexASM

     * Both textboxes are now using a fixed-size font (Courier New) at a bigger size. Widened the ASM textbox to accommodate the bigger font.
     * Error reporting (in the "Messages" area) should now report more errors and be more specific.  You should at least get a warning if it skips a line entirely (e.g. an unrecognized command when encoding).  Decoding will also report unknown commands.

     LEDecoder

     * Can now specify starting address.

     Both (MassHexASM and LEDecoder)

     * "Mode" dropdown added to select between PSX/PSP modes (as well as a generic Base mode).  This will primarily affect coprocessor 2 instructions (GTE, VFPU) which differ between the two.  This won't restrict the instruction set completely to ones supported by the CPU.
     * Added support for many new MIPS instructions up to the MIPS32R2 instruction set.
     * PSX mode should contain GTE instructions. Format is slightly different from psxfin's disassembly. GTE registers (both data and control registers) can be referred to simply using the generic format $(num), which works with all register types.
     * Coprocessor 0 registers can also be referred to using $(num).
     * PSP mode should contain the VFPU commands as well as other PSP-specific commands (bitrev, max, min, etc).
     * With the new instructions recognized, there should be no more unknowns in PSX/PSP code!
     * MassHexASM and LEDecoder now both use the same encoding/decoding engine (as well as FFTorgASM, upon release of the next FFTP version).
     * You should be able to specify addresses >= 0x10000000 (either with the starting address textbox, or a .org statement).
     * Encoding/decoding uses an entirely new process and should be significantly faster (In my testing, a decoding of the PSP's EBOOT.BIN going from about 10s to < 3s on LEDecoder). You'll probably only notice the speed if encoding/decoding a LOT (thousands) of commands at once.
     * The input file formats have changed significantly with a lot more options/flexibility. I can give more detail if needed, though it's somewhat complicated...
     * Decoding a line can produce "illegal" if the decoder found the instruction and determined that the inputs are illegal/impossible (typically this can only happen with ins/ext instructions). An unrecognized encoding is still "unknown".  If the program hits an unexpected error trying to decode a line, it can produce "error", but this shouldn't happen if the program is working properly.
     * You can use ';' to denote comments, just like '#'.
     * Syscall and break should now properly use 20-bit immediates.
     * Decoding is less lenient; invalid code will produce more unknowns.

v10:
     * Fixed a bug where load/store instructions with negative offsets were encoded with incorrect hex (and were treated incorrectly as pseudoinstructions).

v9:
     * Fixed a bug where newlines in the assembly section were erroneously removed when encoding.
     * Added a "name registers" option that uses register names like r2 = v0, r4 = a0, r29 = sp, r31 = ra, etc, when decoding.

     * MassHexASM can now support many psuedoinstructons even if they take multiple lines. The list of psuedoinstructions here should mostly be supported. You can also do fun things like lw r2,0x80192d90 and lbu r3,0x801908cc(r4), although these commands always generate the entire address, so this will be less efficient in cases where you can reuse part of the address. Those two statements would become 5 lines of regular ASM, but this example can be done in 4. As a sidenote, these pseudoinstruction patterns are very apparent in FFT's ASM code.

v8:
     * When decoding, immediates will now properly show as signed or unsigned based on the instruction. These are the affected commands:
         Unsigned: andi, ori, xori, sltiu
         Signed: addi, addiu, slti

     * Added a "Show Addresses" option which will show the appropriate addresses on encode/decode in the left textbox.

     * Added support for 'select all' using ctrl+A.
     * Little Endian is now the default byte order.

v7:
     * Added support for srav, jalr, break (10-bit immediate), syscall (10-bit immediate) and trap (26-bit immediate) commands.
     * Fixed a bug where label addresses could be calculated incorrectly when the input contained instructions on the same lines as labels, resulting in incorrect hex for branch/jump instructions.
   
v6:
     * Fixed a bug where an instruction on the same line as a label could be parsed incorrectly.

v5:
     * Fixed a bug with encoding long immediates (such as in the j command) when all eight hex digits were not specified.

v4:
     * Fixed a bug where the program failed to encode certain I-type instructions (bgez,blez,bgtz,bltz,bgezal,bltzal).
     * Fixed a bug where the program could incorrectly decode certain I-type instructions (bgez,blez,bgtz,bltz,bgezal,bltzal).
     * Added support for mthi/mtlo instructions.

v3:
     * Added support for comments on the same line as commands. (They'll need to preceded by #)
     * Fixed a bug where labels would only be recognized if they were from earlier points in the code.
     * Fixed a bug involving placement of tab characters that could cause the program not to recognize lines of code.
     * Added support for nor/not instructions.

v2:
     * Can now decode to negative offsets in the appropriate cases for addi and similar instructions.