• Welcome to Final Fantasy Hacktics. Please login or sign up.
 

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

61
Help! / Re: Gender Byte
May 21, 2019, 07:09:29 pm
Those are two different arrays of unit data.  The first is the main party data, and the second is the unit data used in the formation screen.  I actually have a more detailed definition of that data structure in the Data/Table Locations page.  (Search for "801c8638 (WORLD.BIN)")

In the case of formation screen unit data offset 0x70, it's copied from party data offset 0x04, so those should have the same value. (This routine is the one that copies the data.)

As for why they sometimes used 2-byte fields when 1-byte fields would suffice, it probably wasn't a conscious decision.  They probably used a short data type instead of a char data type in their C source code, or something along those lines.
62
I had glossed over the palette thing without really looking into what it represented.  That value, offset 0x04 from unit data, as far as I am aware, is actually the unit's team ID (i.e. whose side it's on).  It just so happens that for human enemies that would also affect the palette, but for monsters it's different.  If you were thinking of it in the sense of lower tier vs. higher tier monsters, I think that should just be checked via job ID since each tier is a unique job.

Expanding the first table to check the job IDs is the way I would have handled it, so that looks good to me!

As for the status checks, I found a logic error in the code, on this line:

addu    t7, t3, t4      #   Status byte pointer

It should be:

addu    t7, t2, t4      #   Status byte pointer

Edit - I wouldn't think of the 0x80184360 routine as the Dance/Song Hit% routine.  It's the Hit X% routine and apparently only dance and song use it in the base game.
63
You should be able to just remove the branch by changing BATTLE.BIN at offset 0xD90BC (4 bytes) from 02 00 40 10 to 00 00 00 00.

Patch that does it:

<Patch name="Abilities can flash red without charge time">
  <Location file="BATTLE_BIN" offset="1400BC" mode="ASM" offsetMode="RAM">
    nop
  </Location>
</Patch>
64
According to the Wiki, the relevant routine seems to be this one.  The only thing that really catches my eye at first glance is that it seems to sometimes skip setting the red flashing status if the action is immediate (no charge time), based on the branch at 0x1400bc.
65
No problem, glad to hear the hit % looks right!

Right, so we've calculated the hit % but never applied it in the actual formula code.  There is a bunch of code related to actually making the hit % work that could be inserted, but I think it's easier if we make use of one of the existing routines.  We can do that by storing our Hit % value into the ability's X value instead of the action's hit % (assuming you aren't using X for something else, or have already made use of it in the formula and don't need it anymore).  The way it would work is that we would change the bottom of our new routine (the "end" section) to this:


                end:
                    lui     t0, 0x8019
                    jr      ra
                    sb      v0, 0x38f9(t0)  #   Store Hit% as X


Then in the calling (formula) routine...


#   Evade section up here (if necessary)

#   Custom tame hit % section
jal     @find_monster_tame_hit_percent
nop
jal     0x80184360
nop
bne     v0, zero, formula_end_section       #   Replace "formula_end_section" with the appropriate address (same address as evade would branch to on a miss)
nop

#   Rest of the formula code (...)


I think that should work to get the Hit % actually applying.
66
Completed Mods / Re: FFT: Emergence (PSP)
May 07, 2019, 11:07:55 am
Quote from: BleuVII on May 07, 2019, 09:51:17 am
Unfortunately, on the back end, the coding was really slapdash, which makes WotL extremely hard to work with from a hacking standpoint.


I don't think there's anything particularly wrong with the coding...  if anything, some of the limitations are removed -- code isn't scattered across multiple files, no load delay hazard, etc.  I'm unsure about free space, but there seem to be large gaps (of nops) between some of the routines in the main executable.  It's just... nobody's really bothered to document much of the PSP code, or make hacks for it.  The same goes for some of the modding tools.
67
I did poke around with the Effect Editor somewhat.  The effect Code Scripts section doesn't seem quite right, at least not for the effects I tested.

But the Emitter Control and Effect Timing/Control sections have some juicy knowledge buried in there regarding effect location/camera movement/rotation that I didn't notice on the first go-around.  This allows the proper data to be pinpointed without needing a debugger.  I've updated the relevant post to use the easier method.

Potentially, you could just make some of these changes in the editor directly, but it's good to know where the data is and/or how to find it.
68
Changing Effect colors/palette at runtime

I was able to place a hook into the code at 0x801a1930 in what I'm calling the Effect Stage Processing routine.
This is after the effect has been loaded but before the palette setup has been run.  (If you do hook this code, just remember that you still have to load the effect ID (from 0x801c24d0) as a parameter for the next routine...  I may or may not have crashed the game a few times and/or turned units into glitch blocks by forgetting to do this...)

To find the palette data:

Effect data pointer = Word (4-byte value) loaded from (EffectID * 4) + 0x801b48d0
Palette offset = Word (4-byte value) loaded from (Effect data pointer + 0x24)
Palette pointer = Effect data pointer + Palette offset

Code to get palette pointer may look something like this:
(If effect ID is in r4/a0)

sll     t1, a0, 2
lw      t2, 0x801b48d0 (t1)
nop

lw      t1, 0x24 (t2)       #   Effect palette data offset
nop

addu    t1, t2, t1          #   Effect palette data pointer


An effect palette contains 256 (0x100) colors at 2 bytes each, so it's 512 (0x200) bytes long.  It appears from looking at the code that there is actually another palette stored directly after the first one that is usually just all zeroes, but overall the palette data seems to be treated as two 256-color palettes next to each other for a total of 1024 (0x400) bytes.

The color information for each palette entry, by bit, is [ABBBBBGG][GGGRRRRR] where the bracketed sections are the bytes and the high order byte is listed first (they would be reversed in RAM).  Alpha value is 1 bit and RGB are 5 bits each (values ranging from 0 to 31).

Extracting the ARGB values from the combined value:

red = color & 0x1f
green = (color & 0x3d0) >> 5
blue = (color & 0x7c00) >> 10
alpha = color >> 15

Re-combining ARGB values back into a single color value (assuming values are in bounds):

color = red | (green << 5) | (blue << 10) | (alpha << 15)

Whatever changes you make to the colors here at runtime should be reflected in the displayed effect!
69
Changing Effects that animate on a single target to animate on multiple targets

My example effect for this one is Knife Hand / Damage Split (ID 0x155 = 341) (E341.BIN), which only animates on a single target.

At 0x801b48d0 in RAM is a table of data that defines where the effect file header is stored (in RAM) for each effect ID.
For ID 0x155, the table location is: 0x155 * 4 + 0x801b48d0 = 0x801b4e24
The value at 0x801b4e24 is 0x801c3cfc, the RAM location where the header data starts.
Effect files are loaded into RAM at 0x801c2500, so this results in a file offset of 0x801c3cfc - 0x801c2500 = 0x17FC.

Most effects have their header data stored right at the start of the file, but this one is different.  The start of this effect file is actually... an ASM subroutine.  More on that later.

Anyhow, at 0x17FC in the file, we find the header data.  These are offsets (from the start of header data) of where each section of the effect file starts.  Choto documented these (and a whole bunch of info about effect files) with a bunch more detail but I'm not sure if it's anywhere on the Wiki!


28 00 00 00
8C 02 00 00
E0 02 00 00     <-- Effect script offset (from start of header data)
08 03 00 00
F0 06 00 00
00 00 00 00
54 10 00 00
6C 10 00 00
F4 28 00 00
4C 29 00 00


"E0 02 00 00" is 0x02E0 in little endian.  0x17FC + 0x02E0 = 0x1ADC, where the effect script starts in the file.  Essentially, it's a series of script instructions that tell the effect how to animate.

Broken down by script instruction, and with the offsets shown (from the start of the effect script data), it looks like this (hex):


00: 05 30
02: 06 00 5F 00
06: 2A 00
08: 27 00
0A: 1F 00 26 00

0E: 1D 00 1A 00
12: 28 00
14: 25 00
16: 00 00 0E 00

1A: 25 00
1C: 16 00 00 00 26 00
22: 00 00 1A 00
26: 04 00


When run, it's like a header section, a loop, and an ending section.
Header section commands: 05, 06, 2A, 27, 1F
Loop commands: 1D, 28, 25, 00
Ending section commands: 25, 16, 00, 04

Compared to an effect that animates on multiple targets, say, Fire:


00: 05 20
02: 27 00
04: 1F 00 22 00

08: 1E 00 16 00
0C: 29 00 24 00
10: 25 00
12: 00 00 08 00

16: 25 00
18: 16 00 00 00 22 00
1D: 00 00 16 00
22: 04 00

24: 1D 00 30 00
28: 28 00
2A: 25 00
2C: 00 00 24 00

30: 25 00
32: 16 00 00 00 3C 00
38: 00 00 30 00
3C: 04 00


Header section commands: 05, 27, 1F
Loop commands (1): 1E, 29, 25, 00       <-- This seems to handle multiple targets
Ending section (1) commands: 25, 16, 00, 04
Loop commands (2): 1D, 28, 25, 00
Ending section (2) commands: 25, 16, 00, 04

Here is a somewhat general idea of what some of these script instructions are:


ID          Bytes       Desc

0x00        4           Jump (unconditional)
0x04        2           End Effect
0x05        2           Begin Effect
0x06        4           Setup Custom Routine Pointer
0x16        6           Decision branch?
0x1d        4           Conditional branch (Timing, duration?)
0x1e        4           Conditional branch (multi-target?)
0x1f        4           Conditional branch (based on hit counter)?
0x25        2           Effect processing (advance frame)?
0x27        2           Store motion data?
0x28        2           Graphics (timing?)
0x29        4           Graphics (multi-target?), can branch
0x2a        2           Clear temp data?


(You can also figure out the order that script instructions are being run by setting an execute breakpoint at 0x1a4d44 and noting which IDs are run in which order.)

Damage Split's header section is bigger because it has to set up a pointer to its own custom subroutine which it defines.

The key difference is that Damage Split doesn't have the first loop and ending section.  If we add it in:


00: 05 30
02: 06 00 5F 00
06: 2A 00
08: 27 00
0A: 1F 00 28 00
0E: 1E 00 1C 00
12: 29 00 2A 00
16: 25 00
18: 00 00 0E 00
1C: 25 00
1E: 16 00 00 00 28 00
24: 00 00 1C 00
28: 04 00
2A: 1D 00 36 00
2E: 28 00
30: 25 00
32: 00 00 2A 00
36: 25 00
38: 16 00 00 00 42 00
3E: 00 00 36 00
42: 04 00


As just the hex:

05 20 06 00 5F 00 2A 00 27 00 1F 00 28 00 1E 00
1C 00 29 00 2A 00 25 00 00 00 0E 00 25 00 16 00
00 00 28 00 00 00 1C 00 04 00 1D 00 36 00 28 00
25 00 00 00 2A 00 25 00 16 00 00 00 42 00 00 00
36 00 04 00


This seems to actually work as a pretty good all-purpose multi-target effect script for anything that doesn't have a custom routine or has one at the start of the file.  If there is another location for the custom routine then the 5F might need to change.

We can then replace the old effect script hex with the new effect script hex in the effect file (moving the rest of the file down). (This can be done in HxD by highlighting the old effect script and doing a Paste Insert with the new hex)

That handles the effect script itself, but this just added some bytes to the file.  In the case of Damage Split, the new script was 0x1C = 28 bytes larger.  That means the header section offsets have to be updated, way back up at file offset 0x17FC.

New offsets:

28 00 00 00
8C 02 00 00
E0 02 00 00     <-- Effect script offset (from start of header data)
24 03 00 00
0C 07 00 00
00 00 00 00
70 10 00 00
88 10 00 00
10 29 00 00
68 29 00 00


Everything below the effect script offset has 0x1C added (except for the 00 00 00 00).

Saving that and re-importing that effect file into the ISO, the Knife Hand / Damage Split effect can now animate over multiple targets. 

Since the file size changed, the file info in the ISO also has to change to reflect the new file size or you won't be able to import it.  I used TOC Changer for this.
We can get away with changing the file size as long as the size on disk of the file doesn't change.  In this case, the file size goes from 34124 to 34152 bytes but the size on disk remains at 36864 bytes.
70
Changing where an Effect animates

Using Heaven's Cloud effect (E137.BIN) as an example:
In the Effect header data (this is at the start of E137.BIN but can be more complicated to find in other effects; more detail on how to find this data in the next post):


28 00 00 00
A0 06 00 00
08 08 00 00
48 08 00 00     <-- Emitter control section offset
8C 11 00 00
00 00 00 00
F0 1A 00 00
08 1B 00 00
90 33 00 00
5C 34 00 00


At offset 0x0848 from the start of header data here, we find the number of emitters (12):
02 00 0C 00

There are 16 more bytes of header data.  After that, each emitter has a section that is 0xC4 (196) bytes long.  The fourth byte (offset 3) for each emitter section contains the number that defines where the effect animates (for more detail, see the Effect Graphics routine):


Test values (partial)

Value           Description

0x02            Animates on targeted panel
0x04            Animates on/over source unit
0x06            Animates on each target unit?


For the first emitter section, this value is at offset 0x85F in the file.  Each one after that is the previous value + 0xC4.  Given that there are 12 emitters, this means the final value is at 0x10CB.
Changing the byte from 04 to 02 at the specified locations (excluding the 06 at 0x1007) made Heaven's Cloud animate on the target panel!



I figured out how to do this by using a debugger to find the correct offsets to change for a given effect.  As of now, it isn't enough to just visually inspect the data as I don't think we (currently) know enough about the details of the animation data.

There is a data structure created before an effect is loaded that is stored at RAM address 0x801bad0c.  It's sometimes referenced in the effect code and includes a variety of data.  As I was testing with a Draw Out effect (Heaven's Cloud), my first major breakthrough in trying to change the location of the effect animation is when I realized that the acting unit's unit misc ID was being stored at 0x801badb2 (0xa6 offset from the 0x801bad0c data) and decided to try changing it.  That changed which unit the effect animated over!

That ID was being read in a few places, yielding some interesting results:


0x1badb2 read:
0x1a49c8    <-- Changes which unit does the casting animation
0x1ab050    <-- Changes which unit the camera rotates toward
0x1ab408    <-- Changes which unit the camera centers on
0x1a9108    <-- Changes which unit the effect animates over
0x1a623c    <-- ?


I also realized the data structure contained some more... interesting data:


0x1badca - x coord
0x1badcc - z coord (map level)
0x1badce - y coord

These change location of Ultima's effect but not Heaven's Cloud's...

Reads:
0x1a62e0    <-- Changes effect animation's height (based on tile)?
0x1a64e0    <-- Changes where effect animates!
0x1a7cf0    <-- ?
0x1aaba8    <-- ?
0x1aabbc    <-- Changes where the camera centers


While interesting, this still didn't really tell me why some effects animated over the target panel and some over the source unit.  However, in partially documenting the large Effect Graphics routine, I came upon decision code that sometimes loaded the target panel location... and sometimes source unit data... and sometimes a few other things!

The main decision code starts at 0x801a646c, where I put an execute breakpoint.  The pointer being used here is r23's value + 2, and the test value is in r3.  Here I was able to which values in the effect data the decision code was looking at:


Execute breakpoint 0x801a646c

Heaven's Cloud:

r23             r3          file offset (r23 - 0x801c24fd) (high order byte)

0x801c2fa8      0x0400      0xAAB
0x801c2e20      0x0400      0x923
0x801c337c      0x0400      0xE7F
0x801c306c      0x0400      0xB6F
0x801c3130      0x0400      0xC33
0x801c2ee4      0x0400      0x9E7
0x801c31f4      0x0400      0xCF7
0x801c32b8      0x0400      0xDBB
0x801c2d5c      0x0400      0x85F
0x801c35c8      0x0400      0x10CB
0x801c3440      0x0400      0xF43
0x801c3504      0x0600      0x1007






There was still one issue, though:  the camera still rotated toward and centered on the source unit, not the target panel.
From the header data:


28 00 00 00
A0 06 00 00
08 08 00 00
48 08 00 00     
8C 11 00 00
00 00 00 00
F0 1A 00 00
08 1B 00 00    <-- Relevant offset that contains camera section
90 33 00 00
5C 34 00 00


The start of this section is 0x1b08.  There are three offsets that point you to camera commands:
   + 0x0806: 0x230e (Values: 7)
   + 0x168a: 0x3192 ((Non-zero) Values: 0x0444, 0x0543)
   + 0x185a: 0x3362 ((Non-zero) Values: 0x04c7, 0x0507)

The code does a bitwise-and with 0x01e0 on these values to get the final value it checks:


Test values (partial)
0x01c0: Rotate (or center) toward target panel ?
0x0140: Rotate (or center) toward source unit ?
0x0100: Rotate (or center) back to original point ?


By changing 0x543 to 0x5C3 (changing 0x43 to 0xC3 at file offset 0x3196), both the camera rotation and center went to the target panel instead of the source unit!



Camera routines:
0x1aad98 rotate
0x1ab1d4 center


Figuring out where the effect camera routines were, I set a breakpoint on the routine that calls the effect camera rotation routine...


Execute breakpoint 0x801ad1c0:
(0x801ad1e4?)

(Heaven's Cloud)
ptr             origValue   testValue   ptrOffset       ptr + ptrOffset     file offset (-0x801c2500)
0x801c400c      0x0543      0x0140      0x168a          0x801c5696          0x3196         
0x801c4008      7           0           0x0806          0x801c480e          0x230e         
0x801c400c      0x0507      0x0100      0x185a          0x801c5866          0x3366   

(Ultima)
ptr             origValue   testValue   ptrOffset       ptr + ptrOffset
0x801c4ba2      0x0421      0x0020      0x168a          0x801c622c
0x801c4ba6      0x05c3      0x01c0      0x168a          0x801c6230
0x801c4bae      0x04c3      0x00c0      0x168a          0x801c6238
0x801c4ba2      0x0583      0x0180      0x0806          0x801c53a8
0x801c4ba2      0x0507      0x0100      0x185a          0x801c63fc


These were move involved to trace because of branching code, but the first value in each effect seemed to stand out.


Here is a patch that would make the changes:


<Patch name="Change E137 to animate on target panel">
    <Location file="EFFECT_E137_BIN" offset="AAB" mode="DATA">
        02
    </Location>
    <Location file="EFFECT_E137_BIN" offset="923" mode="DATA">
        02
    </Location>
    <Location file="EFFECT_E137_BIN" offset="E7F" mode="DATA">
        02
    </Location>
    <Location file="EFFECT_E137_BIN" offset="B6F" mode="DATA">
        02
    </Location>
    <Location file="EFFECT_E137_BIN" offset="C33" mode="DATA">
        02
    </Location>
    <Location file="EFFECT_E137_BIN" offset="9E7" mode="DATA">
        02
    </Location>
    <Location file="EFFECT_E137_BIN" offset="CF7" mode="DATA">
        02
    </Location>
    <Location file="EFFECT_E137_BIN" offset="DBB" mode="DATA">
        02
    </Location>
    <Location file="EFFECT_E137_BIN" offset="85F" mode="DATA">
        02
    </Location>
    <Location file="EFFECT_E137_BIN" offset="10CB" mode="DATA">
        02
    </Location>
    <Location file="EFFECT_E137_BIN" offset="F43" mode="DATA">
        02
    </Location>
    <Location file="EFFECT_E137_BIN" offset="3196" mode="DATA">
        C3
    </Location>
</Patch>
71
Recently I began investigating Effects because I wanted to use some of them for abilities in ways that wouldn't normally work.  For example, some effects only animate on one target, even if the ability hits multiple targets.  Some of them only center around the caster, even if the ability was targeted away from the caster (like the Draw Out effects). 

Here I'm going through three different ways to modify effects:

    * Changing where an Effect animates (target panel vs. source unit, for example)
    * Changing Effects that animate on a single target to animate on multiple targets
    * Changing Effect colors/palette at runtime

There wasn't a whole lot of previous documentation about this, so I had to do quite a bit of investigation, and I'm documenting what I found for posterity.  Choto's notes on effect data locations and routines (from years before!) were really helpful.
72
Several points:

Rather than hardcoding the job bonuses and status checks, you could add tables (arrays) of data that hold them.  For the job bonuses, you could have a table of two-byte sets, where the first is the value to check if the job ID is less than, and the second is the bonus.  I'd end it with 00 00 as sentinel values.  Here's what I believe it would look like:

5D 0A 66 1E 6C 19 72 14 78 12 7B 0A 84 0F 8D 0A 00 00

Similarly, for status checks... you could do an array of three-byte sets.  For example, byte 1 is which status byte to check (starting at 0), byte 2 is the value to check for, and byte 3 is the bonus.  Byte 3 could be interpreted as a negative number by using the sign-extended load byte instruction (lb):

04 04 05 04 08 05 04 10 05 04 20 05 02 08 E2 02 04 20 00 00 00

Then the code could run loops and look for these statuses.

Some things to point out:
   * Tons of inefficient loading and storing of the same values over and over again even though we already have them in the correct registers!
   * r6 is being used as target unit pointer... but then later you try to load and store Hit % from it as if it's the action pointer.
   * div performs integer division.  (HP / MaxHP) == 0 unless HP == MaxHP (when it's 1).  That would entirely mess up the calculation.
   * Your HP percentage bonus calculation, when all is said and done, as far as I can tell, comes out to ((MaxHP - HP) * 20) / MaxHP

This would be my initial take on it.  Keep in mind I didn't test anything:


    <Patch name="Monster tame hit % (partial)">
        <Location file="BATTLE_BIN" offset="156000" mode="DATA" offsetMode="RAM">
            5D 0A 66 1E 6C 19 72 14 78 12 7B 0A 84 0F 8D 0A 00 00
        </Location>
        <Location file="BATTLE_BIN" offset="156050" mode="DATA" offsetMode="RAM">
            04 04 05 04 08 05 04 10 05 04 20 05 02 08 E2 02 04 20 00 00 00
        </Location>
        <Location file="BATTLE_BIN" offset="156100" mode="ASM" offsetMode="RAM">
            @find_monster_tame_hit_percent:
                .label  address_job_bonus_array, 0x80156000
                .label  address_status_check_array, 0x80156050
               
                    lui     t0, 0x8019
                    lw      a0, 0x2d98(t0)  #   Target
                    lw      a1, 0x2d90(t0)  #   Action (affecting Target)
               
                    lbu     t0, 3(a0)       #   JobID
                   
                    #   If JobID = 0x99, Hit% = 10
                    li      t1, 0x99
                    beq     t0, t1, end
                    li      v0, 10         
                   
                    la      t2, address_job_bonus_array
                job_bonus_check_loop:
                    lbu     t3, 0(t2)       #   Threshold JobID
                    lbu     v0, 1(t2)       #   Job bonus
                    beq     t3, zero, tier1_check
                    sltu    t4, t0, t3
                    bne     t4, zero, tier1_check
                    nop
                    j       job_bonus_check_loop
                    addiu   t2, t2, 2       #   Move to next element
                   
                tier1_check:
                    lbu     t2, 4(a0)       #   Palette
                    nop
                    beq     t2, zero, hp_percent_calc
                    nop
                    addiu   v0, v0, 10      #   Add 10 to Hit% if tier 1
               
                hp_percent_calc:
                    lhu     t2, 0x28(a0)    #   HP
                    lhu     t3, 0x2a(a0)    #   MaxHP
                    nop
                    subu    t4, t3, t2      #   (MaxHP - HP)
                    sll     t5, t4, 2       #   (MaxHP - HP) * 4
                    addu    t5, t5, t4      #   (MaxHP - HP) * 5
                    sll     t5, t5, 2       #   (MaxHP - HP) * 20
                    divu    t5, t3
                    mflo    t2              #   ((MaxHP - HP) * 20) / MaxHP
                    addu    v0, v0, t2      #   Add to Hit%
               
                    addiu   t2, a0, 0x58
                    la      t3, address_status_check_array
                status_loop:
                    lbu     t4, 0(t3)       #   Status byte index
                    lbu     t5, 1(t3)       #   Status effect mask
                    lb      t6, 2(t3)       #   Value to add
                    beq     t4, zero, low_check
                    addu    t7, t3, t4      #   Status byte pointer
                    lbu     t4, 0(t7)       #   Status byte
                    nop
                    and     t4, t4, t5      #   Check for status
                    beq     t4, zero, status_loop_bottom
                    nop
                    addu    v0, v0, t6      #   If status exists on unit, add value
                status_loop_bottom:
                    j       status_loop
                    addiu   t3, t3, 3       #   Move to next element
               
                low_check:
                    slti    t2, v0, 0       #   If Hit% is less than 0...
                    beq     t2, zero, high_check
                    nop
                    li      v0, 0           #   Set Hit% = 0
                   
                high_check:
                    sltiu   t2, v0, 100     #   If Hit% is greater than or equal to 100...
                    bne     t2, zero, end
                    nop
                    li      v0, 100         #   Set Hit% = 100
                   
                end:
                    jr      ra
                    sh      v0, 0x2a(a1)    #   Store Hit%
        </Location>
    </Patch>


73
PSX FFT Hacking / Re: ASM Requests
April 19, 2019, 11:56:37 am
Quote from: hitokiro on April 18, 2019, 08:05:29 pm
Hello everyone~

I was wondering if there was a straightforward way to transform a gameshark code into an ASM hack? Specifically I'd like to patch "JP Never Decreases" into my game. The code I found for this is:

D004760C 0001
8011FAD4 0000

Or I suppose if there's already an ASM hack for this, that would also be super. I looked through as many lists as I could but didn't see it.


...Does this gameshark code actually work? It looks like it should crash the game...

But anyway, yes, this one would be:

<Patch name="Crashes game when learning ability">
  <Location file="WORLD_WORLD_BIN" offset="11FAD4" offsetMode="RAM">
    00 00
  </Location>
</Patch>


However, if you want one that doesn't crash the game:

<Patch name="JP Never Decreases">
  <Location file="WORLD_WORLD_BIN" offset="11FAD6" offsetMode="RAM">
    40
  </Location>
</Patch>
74
Help! / Re: Status CT timer to turn number
February 27, 2019, 06:22:41 pm
That looks like a breakpoint on either a read or a write (signified by "RW" in the breakpoints window), and a read triggered it:

0x8019ab54: lbu r2, 0(r5)


That takes the value in RAM at the memory address in r5 (+ 0) and copies it into register r2.  We can see the value of r5 = 0x80190938, which is an address included in your breakpoint.
(Using 0x190938 - 0x190939 for the breakpoint will cause it to trigger for both locations; you should be able to use 0x190938 for both start and end)

The call stack there isn't actually showing the call stack but just the current instruction.  If you step through a few lines, it should eventually load the call stack properly again.  Sometimes you have to step all the way through the current routine to get it to happen.  Not entirely sure why...

Anyhow, what we're interested in is a write to the death sentence CT, not a read of it.  You can set up the breakpoint to only be for writing and you'll just see "W" instead of "RW" in the breakpoint window.  That should hopefully find the code we want to see!

Also, for clarity: addu r6, r6, r4 is r6 = r6 + r4, not r6 + r6 = r4.  The first register listed is the one assigned to, and it's nearly always that way for any instruction that modifies a register value.
75
Help! / Re: Status CT timer to turn number
February 25, 2019, 09:59:11 pm
No need to play detective with where the value is in RAM because we already know.  This is a very handy reference.

In-battle unit data in RAM starts at address 0x801908cc and the size of a unit is 0x1c0 bytes.  They're stored sequentially in one big array.  If you use debugging tools to inspect the values of these RAM addresses at runtime, you should be able to find your test unit.

From the reference above, we also know the death sentence CT is offset 0x006c from the start of a specific unit's data.  That should give you a specific RAM address for your test unit.  You can set up a write breakpoint at that memory location which will break execution when the value is changed.
76
Help! / Re: Status CT timer to turn number
February 24, 2019, 09:55:23 pm
Oh, those comments are from my annotation of that code on the Wiki.  The code itself doesn't actually have comments in it.

Yes, the jal statement you highlighted is the one that calls the routine.  That code probably runs for every clocktick, whereas the code that handles the death sentence CT probably only runs on unit turns so I imagine it's somewhere else.  Finding that code is the question, and that's where I'd use a debugger.
77
Help! / Re: Status CT timer to turn number
February 24, 2019, 08:07:42 pm
Heh heh heh.  Apparently you haven't seen much of FFT's code yet.

It's probably hardcoded by status ID.  The routine that handles decreasing status CT for those that use clockticks is here and the routine that calls it is here.  It's looking directly at status IDs.

I'm not sure, however, where the code is that affects the countdown for death sentence.  Looks like a job for a debugger -- breakpoint when the value changes.
78
Completed Mods / Re: Auto-SCC Patch
February 17, 2019, 02:34:28 am
Quote from: Pixy on February 16, 2019, 11:53:56 am
How does this affect the actual battles? For example, in that particular instance, is Agrias a Geomancer during the actual Bariaus Valley fight or is she forced that way after?


She's a Holy Knight during the battle, and is then locked into the chosen SCC class afterwards.  The general rule is that Guests will be the same as usual until they join you.  I also didn't want that battle in particular to be a lot more difficult if you had chosen a less sturdy class.

Quote from: Pixy on February 16, 2019, 11:53:56 am
Strange change for the Rubber Shoes. It's not terribly important but it does change the fight At the Gate of Lionel Castle. Why change it?


For that reason.  The Rubber Shoes make you immune to damage from everybody in that battle except Gafgarion (and maybe the summoner?).  I don't think it was intended for Rubber Shoes to break the battle that badly, because the enemy units in the Lionel Gate battle are actually assigned to have random equipment, and it just so happens the game can only select the lightning weapons because of the unit levels.

Quote from: Pixy on February 16, 2019, 11:53:56 am
The "crits always do bonus damage" business is also a little strange to me. I'm for quality of life changes but anything that shakes the foundation of the game, even if it's only a little, makes the challenge slightly different from the original. Of course, if that was your goal, this is a solid patch through and through, and may be worth a try one day.


I understand that point of view, but I think of "crits that aren't really crits" as a bug that should be fixed.  It's strange for the visual and audio effects of a crit to happen but for no bonus damage to be dealt, and I don't see why that would be desirable behavior in any circumstance.
79
The three values in the Animation tab are really just numbers, corresponding to certain IDs.  They don't represent a set of flags, so editing each bit individually makes no sense, and you can just edit the numbers directly in the textboxes.  The checkboxes were removed for that reason.

I'm pretty sure one of those numbers (the third?) is the ID of the quote that sometimes comes up when you use the corresponding ability, with 0 meaning no quote.
80
Help! / Re: FFTorgASM appears to be doing nothing
February 12, 2019, 09:05:30 pm
That should have worked.  It turns out... there was a bug in my elemental hack!  Thanks for reporting the issue.  I've fixed the problem and uploaded a new zip in my ASM thread.