Please login or register.

Login with username, password and session length
Advanced search  

News:

Use of ePSXe before 2.0 is highly discouraged. Mednafen/RetroArch is recommended for playing/testing, pSX is recommended for debugging.

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

Pages: [1] 2 3 ... 27
1
Help! / Re: Routines that determine Move/Act CT costs
« on: May 30, 2019, 01:09:22 PM »
This routine looks like the right one.

As for a breakpoint that could determine this?  That would be a write breakpoint on a unit CT value (offset 0x0039 from the start of the unit's in-battle data - array starting at 0x801908cc - see this reference).

2
Help! / Re: Gender Byte
« on: May 21, 2019, 11: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.

3
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.

4
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:

5
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.

6
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:

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

Then in the calling (formula) routine...

Code: [Select]
#   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.

7
Completed Patches / Re: FFT: Emergence (PSP)
« on: May 07, 2019, 03:07:55 PM »
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.

8
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.

9
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)
Code: [Select]
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!

10
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!

Code: [Select]
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):

Code: [Select]
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:

Code: [Select]
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:

Code: [Select]
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:

Code: [Select]
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:
Code: [Select]
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:
Code: [Select]
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.

11
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):

Code: [Select]
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):

Code: [Select]
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!




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:

Code: [Select]
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:

Code: [Select]
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!


Here is a patch that would make the changes:


12
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.

13
PSX FFT Hacking / Re: A monster tame/invite subroutine -in progress-
« on: April 30, 2019, 11:43:56 PM »
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:



14
PSX FFT Hacking / Re: ASM Requests
« on: April 19, 2019, 03:56:37 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:
Code: [Select]
<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:
Code: [Select]
<Patch name="JP Never Decreases">
  <Location file="WORLD_WORLD_BIN" offset="11FAD6" offsetMode="RAM">
    40
  </Location>
</Patch>

15
Help! / Re: Status CT timer to turn number
« on: February 27, 2019, 10: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:
Code: [Select]
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.

16
Help! / Re: Status CT timer to turn number
« on: February 26, 2019, 01:59:11 AM »
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.

17
Help! / Re: Status CT timer to turn number
« on: February 25, 2019, 01:55:23 AM »
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.

18
Help! / Re: Status CT timer to turn number
« on: February 25, 2019, 12:07:42 AM »
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.

19
Completed Patches / Re: Auto-SCC Patch
« on: February 17, 2019, 06:34:28 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.

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.

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.

20
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.

Pages: [1] 2 3 ... 27