• Welcome to Final Fantasy Hacktics. Please login or sign up.
 
March 29, 2024, 10:48:49 am

News:

Please use .png instead of .bmp when uploading unfinished sprites to the forum!


A monster tame/invite subroutine -Completed-

Started by Heisho, April 29, 2019, 03:24:37 am

Heisho

April 29, 2019, 03:24:37 am Last Edit: May 20, 2019, 06:56:36 pm by Heisho
Hello there!

I've working on some unholy formulas lately and finally made (in my opinion) a subroutine for a formula that will make taming or inviting monsters a little more fun.
The thing is this: It checks the type of monster, tier, damage and status in order to give a hit% based on all those.

Quick example:
A Chocobo will have a base of 30% due his monster class and an extra 10% since its the first tier. Up to 20% more will be added depending on remaining HP and a 5% more for each of the following status: Don't Act, Don't Move, Sleep and Charm adding 20% more giving a total of 80% if all this conditions are met. If the unit is in chicken status an additional 20% is given to the total amount, but if the unit is in Berserk status 30% will be substracted for the total amount. This last two can stack so if you have a enraged chicked roaming the map it will have a -10% after the total sum if you wan to invite it.

Now the code:


[0x00000000] lbu r2,0x0003(r6)   # Load Job ID
[0x00000004] nop   
[0x00000008] addiu r2,r2,0xffa2   # Job ID - 5D
[0x0000000c] sltiu r2,r2,0x0009   
[0x00000010] beq r2,r0,0x000000fc   # Branch if Job ID is 5D or lower or  if Job ID is over 66
[0x00000014] nop   
[0x00000018] ori r2, r0, 0x0001e   # r2=30
[0x0000001c] j 0x00000110   
[0x00000020] nop   
[0x00000024] lbu r2,0x0003(r6)   # Load Job ID
[0x00000028] nop   
[0x0000002c] addiu r2,r2,0xff99   #Job ID - 66
[0x00000030] sltiu r2,r2,0x0006   
[0x00000034] beq r2,r0,0x000000fc   # Branch if Job ID is 66 or lower or  if Job ID is over 6c
[0x00000038] nop   
[0x0000003c] ori r2, r0, 0x00019   # r2=25
[0x00000040] j 0x00000110   
[0x00000044] nop   
[0x00000048] lbu r2,0x0003(r6)   # Load Job ID
[0x0000004c] nop   
[0x00000050] addiu r2,r2,0xff93   # Job ID - 6C
[0x00000054] sltiu r2,r2,0x0006   
[0x00000058] beq r2,r0,0x000000fc   # Branch if Job ID is 6C or lower or  if Job ID is over 72
[0x0000005c] nop   
[0x00000060] ori r2, r0, 0x00014   # r2=20
[0x00000064] j 0x00000110   
[0x00000068] nop   
[0x0000006c] lbu r2,0x0003(r6)   # Load Job ID
[0x00000070] nop   
[0x00000074] addiu r2,r2,0xff8d   # Job ID - 72
[0x00000078] sltiu r2,r2,0x0006   
[0x0000007c] beq r2,r0,0x000000fc   # Branch if Job ID is 72 or lower or  if Job ID is over 78
[0x00000080] nop   
[0x00000084] ori r2, r0, 0x00012   # r2=18
[0x00000088] j 0x00000110   
[0x0000008c] nop   
[0x00000090] lbu r2,0x0003(r6)   # Load Job ID
[0x00000094] nop   
[0x00000098] addiu r2,r2,0xff87   # Job ID - 78
[0x0000009c] sltiu r2,r2,0x0003   
[0x000000a0] beq r2,r0,0x000000fc   # Branch if Job ID is 78 or lower or  if Job ID is over 7B
[0x000000a4] nop   
[0x000000a8] ori r2, r0, 0x0000a   # r2=10
[0x000000ac] j 0x00000110   
[0x000000b0] nop   
[0x000000b4] lbu r2,0x0003(r6)   # Load Job ID
[0x000000b8] nop   
[0x000000bc] addiu r2,r2,0xff84   # Job ID - 7B
[0x000000c0] sltiu r2,r2,0x0009   
[0x000000c4] beq r2,r0,0x000000fc   # Branch if Job ID is 7B or lower or  if Job ID is over 84
[0x000000c8] nop   
[0x000000cc] ori r2, r0, 0x0000f   # r2=15
[0x000000d0] j 0x00000110   
[0x000000d4] nop   
[0x000000d8] lbu r2,0x0003(r6)   # Load Job ID
[0x000000dc] nop   
[0x000000e0] addiu r2,r2,0xff7b   # Job ID - 84
[0x000000e4] sltiu r2,r2,0x0009   
[0x000000e8] beq r2,r0,0x000000fc   # Branch if Job ID is 84 or lower or  if Job ID is over 8D
[0x000000ec] nop   
[0x000000f0] ori r2, r0, 0x0000a   # r2=10
[0x000000f4] j 0x00000110   
[0x000000f8] nop   
[0x000000fc] ori r5, r0,0x0099   
[0x00000100] lbu r3, 0x0003 (r6)   # Load Job ID
[0x00000104] nop   
[0x00000108] beq r3, r5, 0x00000260   # branch if Job ID = 99 (Chaos Daemon)
[0x0000010c] nop   
[0x00000110] lbu r3, 0x0004 (r6)   # Load pallete
[0x00000114] ori r5,r0,0x0000   
[0x00000118] bne r3,r5, 0x0000012c   #Branch if not Tier 1 monster
[0x0000011c] nop   
[0x00000120] ori r3,r0, 0x000a   
[0x00000124] addu r2,r2,r3   # Class + Tier 1 bonus (+10%)
[0x00000128] nop   
[0x0000012c] sh r2,0x002a(r6)   # Store Hit%
[0x00000130] lhu r3, 0x0028(r6)   #Target Cur HP
[0x00000134] lhu r4, 0x002a(r6)   #Target Max HP
[0x00000138] nop   
[0x0000013c] div r3,r4   
[0x00000140] mflo r5   # Cur HP/Max HP
[0x00000144] nop   
[0x00000148] ori r2,r0,0x0064   # R2=100
[0x0000014c] mult r2,r5   # Actual HP %
[0x00000150] mflo r3   
[0x00000154] subu r2,r2,r3   # Hit% = 100 - HP%
[0x00000158] ori r3,r0,0x0005   # r3=5
[0x0000015c] div r2,r3   
[0x00000160] mflo r2   # Hit%/5
[0x00000164] nop   
[0x00000168] lbu r3, 0x002a(r6)   # Load Hit%
[0x0000016c] nop   
[0x00000170] addu r2,r2,r3   # Add Class% + HP Dmg bonus
[0x00000174] nop   
[0x00000178] sh r2,0x002a(r6)   # Store Hit%
[0x0000017c] ori r4, r0, 0x0004   
[0x00000180] lbu r5, 0x005c (r6)   # Load 5th set of current status
[0x00000184] nop   
[0x00000188] bne r4,r5, 0x00001a4   # branch if unit doesn't has don't act (disable)
[0x0000018c] ori r6, r0, 0x0005   
[0x00000190] lbu r3, 0x002a(r6)   # Load Hit%
[0x00000194] nop   
[0x00000198] addu r2,r6,r3   # Add Hit% +  status bonus
[0x0000019c] nop   
[0x000001a0] sh r2,0x002a(r6)   # Store Hit%
[0x000001a4] ori r4, r0, 0x0008   
[0x000001a8] bne r4,r5, 0x00001c4   # branch if unit doesn't has don't move (immobilize)
[0x000001ac] ori r6, r0, 0x0005   
[0x000001b0] lbu r3, 0x002a(r6)   # Load Hit%
[0x000001b4] nop   
[0x000001b8] addu r2,r6,r3   # Add Hit% +  status bonus
[0x000001bc] nop   
[0x000001c0] sh r2,0x002a(r6)   # Store Hit%
[0x000001c4] ori r4, r0, 0x0010   
[0x000001c8] bne r4,r5, 0x00001e4   # branch if unit doesn't has sleep
[0x000001cc] ori r6, r0, 0x0005   
[0x000001d0] lbu r3, 0x002a(r6)   # Load Hit%
[0x000001d4] nop   
[0x000001d8] addu r2,r6,r3   # Add Hit% +  status bonus
[0x000001dc] nop   
[0x000001e0] sh r2,0x002a(r6)   # Store Hit%
[0x000001e4] ori r4, r0, 0x0020   
[0x000001e8] bne r4,r5, 0x0000204   #  branch if unit doesn't has charm
[0x000001ec] ori r6, r0, 0x0005   
[0x000001f0] lbu r3, 0x002a(r6)   # Load Hit%
[0x000001f4] nop   
[0x000001f8] addu r2,r6,r3   # Add Hit% +  status bonus
[0x000001fc] nop   
[0x00000200] sh r2,0x002a(r6)   # Store Hit%
[0x00000204] ori r4, r0, 0x0008   
[0x00000208] lbu r5, 0x005a (r6)   # Load 3rd set of current status
[0x0000020c] nop   
[0x00000210] bne r4,r5, 0x000022c   # branch if unit doesn't has berserk
[0x00000214] ori r6, r0, 0x001e   
[0x00000218] lbu r3, 0x002a(r6)   # Load Hit%
[0x0000021c] nop   
[0x00000220] subu r2,r6,r3   # Substract Hit% -20
[0x00000224] nop   
[0x00000228] sh r2,0x002a(r6)   # Store Hit%
[0x0000022c] ori r4, r0, 0x0004   
[0x00000230] bne r4,r5, 0x000024c   # branch if unit doesn't has chicken
[0x00000234] ori r6, r0, 0x0014   
[0x00000238] lbu r3, 0x002a(r6)   # Load Hit%
[0x0000023c] nop   
[0x00000240] addu r2,r6,r3   # Add Hit% +  20
[0x00000244] nop   
[0x00000248] sh r2,0x002a(r6)   # Store Hit%
[0x0000024c] bgez  r2, 0x00000268   # Branch if Hit% > 0
[0x00000250] nop   
[0x00000254] sh r0,0x002a(r6)   # Store Hit% = 0%
[0x00000258] j 0x00000268   
[0x0000025c] nop   
[0x00000260] ori r2,r0,0x000a   # Store Hit as 10%
[0x00000264] sh r2,0x002a(r6)   # Store Hit%
[0x00000268] jr r31   
[0x0000026c] nop   


Yes, is big. However this is what I'm planning to add on my future patch, that's the reason that you will see a check for a Job ID (99) since this will be a secret character that could be invited.
Also you saw that I used a palette check, this is because the 2nd tier would be more difficult to invite, and the 3rd can't be invited (at least in this patch). And yes, this is my humble version of a "Pokemonesque" formula.

What I would ask from the great ASM masters is to know if this routine makes sense. Meaning that I'm looking for feedback in this one. Just remember that I'm a little too green on this so don't put on the flamethrowers if I messed up. By the way, the branches and jumps redirect to temporary offsets, I'm aware of this. This will be adjusted after I decide where in BATTLE.BIN this will be located. Also I checked and no load delays were detected.

Thanks for reading.

Regards.

  • Modding version: PSX
Grrr, arwg, hiss, and some other zombie noises...
  • Discord username: Heisho

Glain

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>


  • Modding version: Other/Unknown

Heisho

Sorry for the late reply. I was away from my computer.

First of all, thanks a lot man. It really help me to know where I'm making mistakes. Apparently they are in all places.

Now my report:
I just tested it and works, however I think I need to make a few adjustments for the formula that calls this subroutine since it always hit  (unless this is a very lucky day) at 10%, even after some tries. On the other hand it shows the correct amount for hit% when Hp has been drained and regarding other status I'm pending to check them but first I need to review the formula again, I think I'm missing the branch if miss. I'll comeback with more info.

Again, thanks a lot to take your time to correct the mess I made. It really speaks greatly of you Glain.
  • Modding version: PSX
Grrr, arwg, hiss, and some other zombie noises...
  • Discord username: Heisho

Glain

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.
  • Modding version: Other/Unknown

3lric

Seems like a cool hack man. Kinda wish we allowed inviting in Jot5 now lol

Good job.
  • Modding version: PSX

Heisho

Once again, thanks for the help Glain.
Actually I didn't thought of the Dance/Song hit% since I'm going to remove those classes and I was considering that space as free, seems it would have some use for me in the end.

I made a few more tests:
1- The pallette check it seems to be useless, the game somehow is not taking that in consideration by making all classes have the "10% tier 1 bonus" so I removed it, however I started to make experiments with the table with great results:
a) The first values on the table took all jobs before Class ID 5D as 10% for invitation. So I changed it to 00 and then make a table for all monsters classes, it took a little while but in the end it was better since I could assign values for each class, I left the 3rd tier at 0% since I will work like it on my patch. If I got time to spare I will post an updated version with functionality to change percentages of all monsters at will in FFTorgASM.
b) After that I took more tests and all worked great with the HP damage bonus, but...

2- The status. For some reason they are not adding more % after inflicting the status on the table. Perhaps is the byte to check. When I change it to match the Current Statuses as in the Data Table (5C and 5A) the % went to 50% from the very beginning as if all statuses were inflicted:
40% for initial + 20% for Don't Act, Don't Move, Sleep and Charm (5% each) , Berserk (-30%) and Charm(+20%). So I'm still checking what could be the cause...however its 6AM and I think I need to check it later.

So, this is my report so far and here are the changes to the code:

<Patch name="Monster tame hit % (partial)">
        <Location file="BATTLE_BIN" offset="156000" mode="DATA" offsetMode="RAM">
   5D 00   
   5F 28 60 1E 61 00
   62 28 63 1E 64 00
   65 28 66 1E 67 00
   68 23 69 19 6A 00
   6B 23 6C 19 6D 00
   6E 1E 6F 14 70 00
   71 1E 72 14 73 00
   74 1C 75 12 76 00
   77 1C 78 12 79 00
   7A 14 7B 0A 7C 00
   7D 19 7E 0F 7F 00
   80 19 81 0F 82 00
   83 19 84 0F 85 00
   86 14 87 0A 88 00
   89 14 8A 0A 8B 00
   8C 14 8D 0A 8E 00
   00 00

        </Location>
        <Location file="BATTLE_BIN" offset="156064" 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, 0x80156064
               
                    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, hp_percent_calc
                    sltu    t4, t0, t3
                    bne     t4, zero, hp_percent_calc
                    nop
                    j       job_bonus_check_loop
                    addiu   t2, t2, 2       #   Move to next element
                   




Regards.
  • Modding version: PSX
Grrr, arwg, hiss, and some other zombie noises...
  • Discord username: Heisho

Glain

May 19, 2019, 12:56:14 pm #6 Last Edit: May 19, 2019, 05:06:31 pm by Glain
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.
  • Modding version: Other/Unknown

Heisho

Interesting info. By the way I expanded the status table a little more, adding positive status as negative %, meaning that if the enemy monster has positive status will be more difficult to tame/capture, etc. I think this might be the final version. Thanks a lot for the help Glain, now I need to study more about tables and those sorts of things.

Here is the final result:


<?xml version="1.0" encoding="utf-8"?>
<Patches>
<Patch name="Formula 2B - Monster Tame">
    <Location file="BATTLE_BIN" offset="122A90">
E8FFBD27
1000BFAF
00000000
4058050C
00000000
D810060C
00000000
02004014
00000000
C91F060C
00000000
1000BF8F
1800BD27
0800E003
00000000
    </Location>
  </Patch>

<Patch name="Monster tame hit %">
<Description>Determines hit percent based on monster class ID, HP remaining, and current status. It also has a check for a Class to be 10% always (default Class ID=99, Archaic Demon), if you don't want it, change it accordingly.Credits to Glain for the corrections.</Description>
        <Location file="BATTLE_BIN" offset="156000" mode="DATA" offsetMode="RAM">
   5D 00   
   5F 28 60 1E 61 00
   62 28 63 1E 64 00
   65 28 66 1E 67 00
   68 23 69 19 6A 00
   6B 23 6C 19 6D 00
   6E 1E 6F 14 70 00
   71 1E 72 14 73 00
   74 1C 75 12 76 00
   77 1C 78 12 79 00
   7A 14 7B 0A 7C 00
   7D 19 7E 0F 7F 00
   80 19 81 0F 82 00
   83 19 84 0F 85 00
   86 14 87 0A 88 00
   89 14 8A 0A 8B 00
   8C 14 8D 0A 8E 00
   00 00

        </Location>
        <Location file="BATTLE_BIN" offset="156064" mode="DATA" offsetMode="RAM">
            04 04 05
            04 08 05
            04 10 05
            04 20 05
            02 08 E2
            02 04 14
            03 20 F6
            03 10 F6
            03 08 F6
            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, 0x80156064
               
                    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, hp_percent_calc
                    sltu    t4, t0, t3
                    bne     t4, zero, hp_percent_calc
                    nop
                    j       job_bonus_check_loop
                    addiu   t2, t2, 2       #   Move to next element
                   
               
                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, t2, 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:
                    lui     t0, 0x8019
                    jr      ra
                    sb      v0, 0x38f9(t0)  #   Store Hit% as X
        </Location>
    </Patch>


</Patches>


Enjoy and have fun, if you want to change which formula to use just change the offset of it.

@Glain: Sorry about the confusion, I just name the HIT X% as it was on the wiki.
  • Modding version: PSX
Grrr, arwg, hiss, and some other zombie noises...
  • Discord username: Heisho

Vanya

Neat.
Sounds like a big improvement over the original.
  • Modding version: Other/Unknown
¯\(°_0)/¯