? = 2 (Starting turn?) Unit Priority Routine (The lower, the better)
0019d6b4: 0c0076ea jal 0x0001dba8Derive RNG from Frame Data? 0019d6b8: 34040001 ori r4,r0,0x0001 0019d6bc: 284201b9 slti r2,r2,0x01b9(I assume 0x01ff is the highest value?) 0019d6c0: 14400005 bne r2,r0,0x0019d6d8Branch if you pleased the Frame RNG gods today 0019d6c4: 3c030100 lui r3,0x0100 0019d6c8: 0c067858 jal 0x0019e160Transfer Unit Data to AI Data 0019d6cc: 34040001 ori r4,r0,0x0001 0019d6d0: 080676c9 j 0x0019db24Basically Exit Routine(Is this why sometimes units will just skip turns?) 0019d6d4: 34020002 ori r2,r0,0x0002(A 70/511(13.7%) chance of being screwed by the RNG in Arena lol) 0019d6d8: 8e420cb4 lw r2,0x0cb4(r18) 0019d6dc: 00000000 nop 0019d6e0: 00431024 and r2,r2,r3 0019d6e4: 10400048 beq r2,r0,0x0019d808Skip Loop if r2 =/= 0x01000000 0019d6e8: 00008821 addu r17,r0,r0 0019d6ec: 00003021 addu r6,r0,r0 0019d6f0: 3405182c ori r5,r0,0x182c 0019d6f4: 02452021 addu r4,r18,r5r4 = AI decision data 0019d6f8: 3c028019 lui r2,0x8019 0019d6fc: 244208cc addiu r2,r2,0x08cc 0019d700: 90830004 lbu r3,0x0004(r4)load AI settings? 0019d704: 00c28021 addu r16,r6,r2 0019d708: 306300f8 andi r3,r3,0x00f8remove Unit needs Reviving/Unstoning, Unit is Jumping 0019d70c: a0830004 sb r3,0x0004(r4)store new flags 0019d710: 92020058 lbu r2,0x0058(r16)load status 0019d714: 00000000 nop 0019d718: 30420020 andi r2,r2,0x0020 0019d71c: 10400007 beq r2,r0,0x0019d73cbranch if if not dead 0019d720: 00000000 nop 0019d724: 9202005a lbu r2,0x005a(r16)load status 0019d728: 00000000 nop 0019d72c: 30420020 andi r2,r2,0x0020 0019d730: 14400002 bne r2,r0,0x0019d73cbranch if reraise 0019d734: 34620001 ori r2,r3,0x0001add Need Revive flag 0019d738: a0820004 sb r2,0x0004(r4)store new AI setting 0019d73c: 92020059 lbu r2,0x0059(r16) 0019d740: 00000000 nop 0019d744: 30420080 andi r2,r2,0x0080 0019d748: 10400005 beq r2,r0,0x0019d760branch if not petrified 0019d74c: 00000000 nop 0019d750: 90820004 lbu r2,0x0004(r4)load AI settings 0019d754: 00000000 nop 0019d758: 34420002 ori r2,r2,0x0002add Need UnPetrifed flag 0019d75c: a0820004 sb r2,0x0004(r4)store flag 0019d760: 92020058 lbu r2,0x0058(r16) 0019d764: 00000000 nop 0019d768: 30420004 andi r2,r2,0x0004 0019d76c: 10400005 beq r2,r0,0x0019d784branch if not jumping 0019d770: 00000000 nop 0019d774: 90820004 lbu r2,0x0004(r4) 0019d778: 00000000 nop 0019d77c: 34420004 ori r2,r2,0x0004Unit is Jumping Flag 0019d780: a0820004 sb r2,0x0004(r4)store flag 0019d784: 90830004 lbu r3,0x0004(r4) 0019d788: 00000000 nop 0019d78c: 30620080 andi r2,r3,0x0080 0019d790: 14400016 bne r2,r0,0x0019d7ecNext Unit if unit is Charging/Performing? 0019d794: 00000000 nop 0019d798: 92020059 lbu r2,0x0059(r16) 0019d79c: 00000000 nop 0019d7a0: 30420080 andi r2,r2,0x0080 0019d7a4: 14400011 bne r2,r0,0x0019d7ecNext Unit if petrified 0019d7a8: 00000000 nop 0019d7ac: 92020058 lbu r2,0x0058(r16) 0019d7b0: 00000000 nop 0019d7b4: 30420020 andi r2,r2,0x0020 0019d7b8: 10400006 beq r2,r0,0x0019d7d4branch if not dead 0019d7bc: 00000000 nop 0019d7c0: 9202005a lbu r2,0x005a(r16) 0019d7c4: 00000000 nop 0019d7c8: 30420020 andi r2,r2,0x0020 0019d7cc: 10400007 beq r2,r0,0x0019d7ecNext Unit if No Reraise 0019d7d0: 00000000 nop 0019d7d4: 9202005c lbu r2,0x005c(r16) 0019d7d8: 00000000 nop 0019d7dc: 30420001 andi r2,r2,0x0001 0019d7e0: 14400002 bne r2,r0,0x0019d7ecNext Unit if death-sentenced 0019d7e4: 34620080 ori r2,r3,0x0080Unit needs to be dealt with flag 0019d7e8: a0820004 sb r2,0x0004(r4)store new flags 0019d7ec: 24c601c0 addiu r6,r6,0x01c0Unit Data Pointer++ 0019d7f0: 26310001 addiu r17,r17,0x0001Unit Counter++ 0019d7f4: 2a220015 slti r2,r17,0x0015 0019d7f8: 1440ffbe bne r2,r0,0x0019d6f4perform for all units 0019d7fc: 24a50010 addiu r5,r5,0x0010Unit AI Data++ 0019d800: 080676d5 j 0x0019db54 0019d804: 00000000 nop 0019d808: 0c06772b jal 0x0019dcac0019dcac - 0019dcb8 0019d80c: 00000000 nop 0019d810: 3c0c8019 lui r12,0x8019 0019d814: 258c3de0 addiu r12,r12,0x3de0 0019d818: 3c0d801a lui r13,0x801a 0019d81c: 8dadf3c0 lw r13,-0x0c40(r13) 0019d820: 02404821 addu r9,r18,r0r9 = Unit AI 0019d824: 02405021 addu r10,r18,r0r10 = Unit AI 0019d828: 00005821 addu r11,r0,r0
<Unit Priority Loop> 0019d82c: 9145198c lbu r5,0x198c(r10)load units battle ID? 0019d830: 340200ff ori r2,r0,0x00ff 0019d834: 10a2009c beq r5,r2,0x0019daa8branch if doesn't exist 0019d838: 00002821 addu r5,r0,r0r5 = Current Status Loop Counter 0019d83c: 3c028019 lui r2,0x8019 0019d840: 244208cc addiu r2,r2,0x08cc 0019d844: 01628021 addu r16,r11,r2r16 = unit data 0019d848: 01204021 addu r8,r9,r0r8 = Unit AI 0019d84c: 00003021 addu r6,r0,r0
0019d850: 96070028 lhu r7,0x0028(r16)load current HP 0019d854: 9602002a lhu r2,0x002a(r16)load max HP 0019d858: 000739c0 sll r7,r7,0x07current HP * 80 0019d85c: 00e2001a div r7,r2current HP * 80 / maxHP 0019d860: 00003812 mflo r7r7 = Unit Target Priority Value (curHP% of 0x80)
0019d864: 04a10002 bgez r5,0x0019d870Branch if this isn't first status loop (the Blank Status) 0019d868: 00a01021 addu r2,r5,r0r2 = Current Status Loop Counter 0019d86c: 24a20007 addiu r2,r5,0x0007r2 = 7 (To counteract negative loops??) 0019d870: 000210c3 sra r2,r2,0x03Status ID / 8 0019d874: 02021821 addu r3,r16,r2Get Unit Current Status 0019d878: 90630058 lbu r3,0x0058(r3)load Current Status 1, 2, 3, 4, or 5 0019d87c: 000210c0 sll r2,r2,0x03{0,1,2,3,4} * 8 0019d880: 00a21023 subu r2,r5,r2r2 = Status ID - {0,10,18,20,28} 0019d884: 00431804 sllv r3,r3,r2Will always equal 0x80 if Status in question is present 0019d888: 30630080 andi r3,r3,0x0080 0019d88c: 1060003b beq r3,r0,0x0019d97cNext Status if Current Status not present 0019d890: 00000000 nop 0019d894: 92020059 lbu r2,0x0059(r16)load Current Status 2 0019d898: 3c01801a lui r1,0x801a 0019d89c: 00260821 addu r1,r1,r6 0019d8a0: 8424f308 lh r4,-0x0cf8(r1)load Status Modifers for Target Priority Value 0019d8a4: 30420014 andi r2,r2,0x0014 0019d8a8: 14400006 bne r2,r0,0x0019d8c4Branch if Confuse/Blood Suck 0019d8ac: 00000000 nop 0019d8b0: 9202005c lbu r2,0x005c(r16)load Current Status 5 0019d8b4: 00000000 nop 0019d8b8: 30420020 andi r2,r2,0x0020 0019d8bc: 10400003 beq r2,r0,0x0019d8ccbranch if not Charmed 0019d8c0: 24a3fff6 addiu r3,r5,0xfff6Exclude Blank to Invite statuses 0019d8c4: 0481002d bgez r4,0x0019d97cBranch if Status Target Priority is not negative (Blood Suck/Confuse is zero) 0019d8c8: 24a3fff6 addiu r3,r5,0xfff6Exclude Blank to Invite statuses 0019d8cc: 2c62001c sltiu r2,r3,0x001c 0019d8d0: 10400029 beq r2,r0,0x0019d978Branch and add zero to the Target Priority if Blank to Invite (Reflect/DS as well) 0019d8d4: 00031080 sll r2,r3,0x02(Status ID - 9) * 4 0019d8d8: 004c1021 addu r2,r2,r12 0019d8dc: 8c420000 lw r2,0x0000(r2)Get Jump Address (only 0x1c addresses...) 0019d8e0: 00000000 nop 0019d8e4: 00400008 jr r2 0019d8e8: 00000000 nop
Blind 0019d8ec: 91021839 lbu r2,0x1839(r8)Evade Mod (# evadeable (physical?) abilities ") 0019d8f0: 08067641 j 0x0019d904 0019d8f4: 00820018 mult r4,r2Status Target Value * Evade Mod
Silence 0019d8f8: 91021838 lbu r2,0x1838(r8)Load Silence Blocking Mod 0019d8fc: 00000000 nop 0019d900: 00820018 mult r4,r2Status Target Value * Silence Mod 0019d904: 00001012 mflo r2 0019d908: 0441001b bgez r2,0x0019d978Increase Unit Target Priority Value and go to next status 0019d90c: 00022083 sra r4,r2,0x02Status Target Value / 4 0019d910: 24420003 addiu r2,r2,0x0003Status Target Value + 3 0019d914: 0806765e j 0x0019d978Subtract from Target Value and Next Status 0019d918: 00022083 sra r4,r2,0x02Status Target Value / 4
Confusion/Charm/Blood Suck 0019d91c: 9202005b lbu r2,0x005b(r16)load Current Status 4 0019d920: 00000000 nop 0019d924: 30420006 andi r2,r2,0x0006 0019d928: 14400006 bne r2,r0,0x0019d944branch if slow/stop 0019d92c: 000417c2 srl r2,r4,0x1fStatus Target Value / 0x1f 0019d930: 9202005c lbu r2,0x005c(r16)load Current Status 5 0019d934: 00000000 nop 0019d938: 3042001c andi r2,r2,0x001c 0019d93c: 1040000e beq r2,r0,0x0019d978Modify Target Value and next status if not sleep/don't move/act 0019d940: 000417c2 srl r2,r4,0x1fStatus Target Value / 0x1f 0019d944: 00821021 addu r2,r4,r2Status Target Value + {0 if positive, 1 if negative} 0019d948: 0806765e j 0x0019d978 0019d94c: 00022043 sra r4,r2,0x01Status Target Value + {0,1} / 4
Slow/Stop/Sleep/Don't Move/Don't Act 0019d950: 92020059 lbu r2,0x0059(r16)load Current Status 2 0019d954: 00000000 nop 0019d958: 30420014 andi r2,r2,0x0014 0019d95c: 14400007 bne r2,r0,0x0019d97cAdd nothing to Target Priority; next status if confuse/blood suck 0019d960: 00000000 nop 0019d964: 9202005c lbu r2,0x005c(r16)load Current Status 5 0019d968: 00000000 nop 0019d96c: 30420020 andi r2,r2,0x0020 0019d970: 14400002 bne r2,r0,0x0019d97cAdd nothing to Target Priority; next status if charm 0019d974: 00000000 nop
Everything Else: 0019d978: 00e43821 addu r7,r7,r4Add Status Target Value to Unit Target Priority 0019d97c: 24a50001 addiu r5,r5,0x0001Next Status 0019d980: 28a20028 slti r2,r5,0x0028 0019d984: 1440ffb7 bne r2,r0,0x0019d864loop until all statuses are looked for 0019d988: 24c60002 addiu r6,r6,0x0002Next Status Target Value (Halfword)
0019d9a0: 9142198c lbu r2,0x198c(r10)load unit battle ID? 0019d9a4: 00002821 addu r5,r0,r0 0019d9a8: 00021180 sll r2,r2,0x06 0019d9ac: 004d3021 addu r6,r2,r13r6 = unit AI extended status data 0019d9b0: 02051021 addu r2,r16,r5r2 = unit data 0019d9b4: 00c51821 addu r3,r6,r5r3 = unit AI extended status data 0019d9b8: 9044001a lbu r4,0x001a(r2)load Head slot equipment 0019d9bc: 90620036 lbu r2,0x0036(r3)load helmet 0019d9c0: 00000000 nop 0019d9c4: 14820002 bne r4,r2,0x0019d9d0branch if items are missing (Broken/Stolen) 0019d9c8: 24a50001 addiu r5,r5,0x0001 0019d9cc: 24e70033 addiu r7,r7,0x0033Unit Target Priority Value + 0x33 if information matches (Target is not as desirable to target) 0019d9d0: 28a20007 slti r2,r5,0x0007 0019d9d4: 1440fff7 bne r2,r0,0x0019d9b4Look for missing Helmet, Armor, Acc., R Weapon, R Shield, L Weapon and L Shield 0019d9d8: 02051021 addu r2,r16,r5r2 = next unit data
0019d9dc: 9604002e lhu r4,0x002e(r16)load max MP 0019d9e0: 00000000 nop 0019d9e4: 10800014 beq r4,r0,0x0019da38branch if unit has no MP 0019d9e8: 00000000 nop 0019d9ec: 9606002c lhu r6,0x002c(r16)load current MP 0019d9f0: 91231836 lbu r3,0x1836(r9)Load Lowest MP Cost 0019d9f4: 00c01021 addu r2,r6,r0 0019d9f8: 00063180 sll r6,r6,0x06CurMP * 40 0019d9fc: 0043102b sltu r2,r2,r3r2 = curMP < Lowest MP Cost 0019da00: 00c4001a div r6,r4(CurMP * 40) / Max MP 0019da04: 00003012 mflo r6 0019da08: 10400002 beq r2,r0,0x0019da14Branch if unit doesn't have enough MP to cast spells. 0019da0c: 00000000 nop 0019da10: 00063042 srl r6,r6,0x01curMP% / 4 0019da14: 91221837 lbu r2,0x1837(r9)MP Using Ability Mod 0019da18: 00000000 nop 0019da1c: 00c20018 mult r6,r2(curMP% / 10) * MP Mod 0019da20: 00001012 mflo r2Caster Hate 0019da24: 04410003 bgez r2,0x0019da34Branch if no spell unit has uses MP 0019da28: 00023083 sra r6,r2,0x02Caster Hate / 4 0019da2c: 24420003 addiu r2,r2,0x0003Caster Hate + 3 0019da30: 00023083 sra r6,r2,0x02Caster Hate + 3 / 4 0019da34: 00e63821 addu r7,r7,r6Add Caster Hate to Target Priority Value
0019da38: 92020005 lbu r2,0x0005(r16)load ENTD flags 0019da3c: 00000000 nop 0019da40: 000210c2 srl r2,r2,0x03flags / 8 0019da44: 30420006 andi r2,r2,0x0006Get Team 0019da48: 3c018019 lui r1,0x8019 0019da4c: 00220821 addu r1,r1,r2 0019da50: 9426f5f4 lhu r6,-0x0a0c(r1)Load Current? Team Golem Amount 0019da54: 92430e17 lbu r3,0x0e17(r18)Load average max hp of team 0019da58: 00c02821 addu r5,r6,r0 0019da5c: 000631c0 sll r6,r6,0x07CurGolem * 80 0019da60: 00c3001a div r6,r3CurGolem * 80 / Average Team HP 0019da64: 00001812 mflo r3Golem Fear 0019da68: 00521021 addu r2,r2,r18 0019da6c: 94420e3c lhu r2,0x0e3c(r2)load Max? Team Golem Amount 0019da70: 00000000 nop 0019da74: 00a2282b sltu r5,r5,r2CurGolem < MaxGolem? 0019da78: 10a00002 beq r5,r0,0x0019da84-1 to Priority if Golem is undamaged 0019da7c: 00e33821 addu r7,r7,r3Add Golem Hate to Target Priority Value (Big mistake, has no real value when it's added to everyone) 0019da80: 24e7ffff addiu r7,r7,0xffffTarget Priority - 1
0019da84: 91221834 lbu r2,0x1834(r9)Load Enemy Flag 0019da88: 00000000 nop 0019da8c: 10400002 beq r2,r0,0x0019da98Branch if not Enemy 0019da90: 00000000 nop 0019da94: 00073823 subu r7,r0,r7Invert Target Priority
0019da98: 96420032 lhu r2,0x0032(r18)Load Current Unit Target Priority Value 0019da9c: 00000000 nop 0019daa0: 00471021 addu r2,r2,r7Add/Subtract from current Target Priority 0019daa4: a6420032 sh r2,0x0032(r18)Save New Unit Target Priority Value
0019daa8: 25290010 addiu r9,r9,0x0010Unit AI Data++ 0019daac: 254a0001 addiu r10,r10,0x0001Unit AI++ 0019dab0: 26310001 addiu r17,r17,0x0001Unit++ 0019dab4: 2a220015 slti r2,r17,0x0015 0019dab8: 1440ff5c bne r2,r0,0x0019d82cLoop for all units 0019dabc: 256b01c0 addiu r11,r11,0x01c0Unit Data++ </Unit Priority loop>
0019dac0: 92420000 lbu r2,0x0000(r18)Load Skillset 0019dac4: 3c018006 lui r1,0x8006 0019dac8: 00220821 addu r1,r1,r2 0019dacc: 90235cb4 lbu r3,0x5cb4(r1)load action menu byte 0019dad0: 34020002 ori r2,r0,0x0002 0019dad4: 1462000b bne r3,r2,0x0019db04branch if not weapon inventory 0019dad8: 3402017e ori r2,r0,0x017e 0019dadc: 86430002 lh r3,0x0002(r18)load ability ID 0019dae0: 00000000 nop 0019dae4: 10620007 beq r3,r2,0x0019db04branch if ability = throw shuriken 0019dae8: 34020189 ori r2,r0,0x0189 0019daec: 10620005 beq r3,r2,0x0019db04branch if ability = throw ball (So both will be spammed?) 0019daf0: 00000000 nop 0019daf4: 92420031 lbu r2,0x0031(r18)load base hit% 0019daf8: 00000000 nop 0019dafc: 00021042 srl r2,r2,0x01base hit/2 0019db00: a2420031 sb r2,0x0031(r18)store new base hit% 0019db04: 0c0678de jal 0x0019e378Transfer AI Data to Unit Data 0019db08: 00002021 addu r4,r0,r0 0019db0c: a24019b7 sb r0,0x19b7(r18) 0019db10: 080676d9 j 0x0019db64jump to end, return r2 = 0x01 0019db14: 34020001 ori r2,r0,0x0001 </2 >
0019db18: 0c067858 jal 0x0019e160 0019db1c: 34040001 ori r4,r0,0x0001 0019db20: 34020001 ori r2,r0,0x0001 0019db24: a2420eee sb r2,0x0eee(r18) 0019db28: 080676d9 j 0x0019db64jump to end, return r2=0xffff 0019db2c: 2402ffff addiu r2,r0,0xffff
<End> 0019db30: 8e420ee0 lw r2,0x0ee0(r18) 0019db34: 8e430ee4 lw r3,0x0ee4(r18) 0019db38: 8e440ee8 lw r4,0x0ee8(r18) 0019db3c: 3c018019 lui r1,0x8019 0019db40: ac22f518 sw r2,-0x0ae8(r1) 0019db44: 3c018019 lui r1,0x8019 0019db48: ac23f51c sw r3,-0x0ae4(r1) 0019db4c: 3c018019 lui r1,0x8019 0019db50: ac24f520 sw r4,-0x0ae0(r1) 0019db54: 0c0678de jal 0x0019e378Transfer AI Data to Unit Data 0019db58: 00002021 addu r4,r0,r0 0019db5c: a24019b7 sb r0,0x19b7(r18) 0019db60: 00001021 addu r2,r0,r0return r2 = 0x00 0019db64: 8fbf001c lw r31,0x001c(r29) 0019db68: 8fb20018 lw r18,0x0018(r29) 0019db6c: 8fb10014 lw r17,0x0014(r29) 0019db70: 8fb00010 lw r16,0x0010(r29) 0019db74: 27bd0020 addiu r29,r29,0x0020 0019db78: 03e00008 jr r31 0019db7c: 00000000 nop
*Note: The entire routine isn't done yet, but the subroutine I'm about to talk about will prove very interesting and is documented.
Summary: Target Value Formula
(HP Value[curHP * 128 / maxHP] + Total Status Values + (51 * # of items broken up to 7) + Caster Hate [(curMP% / 16) * # MP using Abilities, 0 if not enough MP] + Golem Fear [CurGolem * 128 / Average Team HP (- 1 if Golem not damaged)]) * (-1 if unit is Enemy, 1 if ally)
HP Value goes from 0% to 128%. Multiply by 25/32 to get 0% - 100%.
This is the formula that the AI uses the determine how much priority an individual unit gets.
The more negative the value, the higher on the enemy target priority that unit becomes. The lower the target's HP, the more of a target that unit becomes, which makes sense. However there most likely is a threshold and the unit will be ignored if it gets too negative.
I assume that the Priority Value is interpreted as effective curHP%. So if a unit has -50% effective curHP%, the AI assumes that unit is pretty incapacitated and will ignore them for a unit that has 5% effective curHP%. However, units in critical are flagged and singled out, so the AI doesn't ignore units with no HP left but a ton of non-fatal statuses.
Units that are Petrified, Dead with no Reraise, Death Sentenced, and Charging/Performing skip giving a Target Value at all. Charging and Performing do not need to contribute to Priority because they already have their own routines to processes them. Same goes for Dead and Petrify.
Now, what exactly, does the AI do with this Target Value next, I've yet to determine. Observations:
You didn't make a sacrifice to the RNG gods today, I'm just gonna sit and spin my wheels instead
0019d6b4: 0c0076ea jal 0x0001dba8Derive RNG from Frame Data? 0019d6b8: 34040001 ori r4,r0,0x0001 0019d6bc: 284201b9 slti r2,r2,0x01b9(I assume 0x01ff is the highest value?) 0019d6c0: 14400005 bne r2,r0,0x0019d6d8Branch if you pleased the Frame RNG gods today 0019d6c4: 3c030100 lui r3,0x0100 0019d6c8: 0c067858 jal 0x0019e160Transfer Unit Data to AI Data 0019d6cc: 34040001 ori r4,r0,0x0001 0019d6d0: 080676c9 j 0x0019db24Basically Exit Routine(Is this why sometimes units will just skip turns?) 0019d6d4: 34020002 ori r2,r0,0x0002(A 70/511(13.7%) chance of being screwed by the RNG in Arena lol)
This confuses me a bit, but no matter how you slice it, it does seem that the AI will occasionally skip assigning units a Target Value at all or basically decide not to do anything at all this turn. The odds of that happening is pretty small because while this might be a 13.7% of that happening every time you come here, the AI comes to this routine several times. So it's more like a .13X% very tiny chance of that happening. Still, giving the amount of decisions the AI makes just per battle, it can and has been observed to happen. Blind and Silence gain more value to the AI the more abilities you have that are Evadable/Silenceable
Blind 0019d8ec: 91021839 lbu r2,0x1839(r8)Evade Mod (# evadeable (physical?) abilities ") 0019d8f0: 08067641 j 0x0019d904 0019d8f4: 00820018 mult r4,r2Status Target Value * Evade Mod {0-4}
Silence 0019d8f8: 91021838 lbu r2,0x1838(r8)Load Silence Blocking Mod 0019d8fc: 00000000 nop 0019d900: 00820018 mult r4,r2Status Target Value * Silence Mod {0-4} 0019d904: 00001012 mflo r2 0019d908: 0441001b bgez r2,0x0019d978Increase Unit Target Priority Value and go to next status 0019d90c: 00022083 sra r4,r2,0x02Status Target Value / 4 0019d910: 24420003 addiu r2,r2,0x0003Status Target Value + 3 0019d914: 0806765e j 0x0019d978Subtract from Target Value and Next Status 0019d918: 00022083 sra r4,r2,0x02Status Target Value / 4
This is probably why the AI doesn't seem to like adding Blind a lot in Arena, or even at all. The AI doesn't take into an account just how much damage a unit can actually do. Attack, even if they deal a truck load of damage, is only one skill to the AI. It cannot tell the immediate difference between a White Mage with Healing Staff and a Berserk Cursed Ring Two Handed Main Gauche killer.Since there aren't too many physically evadable skills in the game, the AI just tends to not want to use Blind all that much it seems, only ever adding -12.5% priority at one time. So simply having no abilities at all is apparently just as good as Blind Immunity. The AI looks at the percentage of units with P-Ev, not the total.
It should be a different story for Silence, but I only ever seen the AI cast Silence as an interrupt, not ever by itself to debuff, even though it's desire to should be much higher, right? Units become bigger targets the more equips they lose
0019d9a0: 9142198c lbu r2,0x198c(r10)load unit battle ID? 0019d9a4: 00002821 addu r5,r0,r0 0019d9a8: 00021180 sll r2,r2,0x06 0019d9ac: 004d3021 addu r6,r2,r13r6 = unit AI extended status data 0019d9b0: 02051021 addu r2,r16,r5r2 = unit data 0019d9b4: 00c51821 addu r3,r6,r5r3 = unit AI extended status data 0019d9b8: 9044001a lbu r4,0x001a(r2)load Head slot equipment 0019d9bc: 90620036 lbu r2,0x0036(r3)load helmet 0019d9c0: 00000000 nop 0019d9c4: 14820002 bne r4,r2,0x0019d9d0branch if items are missing (Broken/Stolen) 0019d9c8: 24a50001 addiu r5,r5,0x0001 0019d9cc: 24e70033 addiu r7,r7,0x0033Unit Target Priority Value + 0x33 if information matches (Target is not as desirable to target) 0019d9d0: 28a20007 slti r2,r5,0x0007 0019d9d4: 1440fff7 bne r2,r0,0x0019d9b4Look for missing Helmet, Armor, Acc., R Weapon, R Shield, L Weapon and L Shield 0019d9d8: 02051021 addu r2,r16,r5r2 = next unit data
Seems pretty straight forward. The more stuff you lose, the bigger of a target you become. What is a bit surprising is that all items lost are treated equal. In practice however, you also lose Max HP for losing Armor anyways, so you become an even bigger target than normal. The AI really fucking hates Mages
0019d9dc: 9604002e lhu r4,0x002e(r16)load max MP 0019d9e0: 00000000 nop 0019d9e4: 10800014 beq r4,r0,0x0019da38branch if unit has no MP 0019d9e8: 00000000 nop 0019d9ec: 9606002c lhu r6,0x002c(r16)load current MP 0019d9f0: 91231836 lbu r3,0x1836(r9)Load Lowest MP Cost 0019d9f4: 00c01021 addu r2,r6,r0 0019d9f8: 00063180 sll r6,r6,0x06CurMP * 40 0019d9fc: 0043102b sltu r2,r2,r3r2 = curMP < Lowest MP Cost 0019da00: 00c4001a div r6,r4(CurMP * 40) / Max MP 0019da04: 00003012 mflo r6 0019da08: 10400002 beq r2,r0,0x0019da14Branch if unit doesn't have enough MP to cast spells. 0019da0c: 00000000 nop 0019da10: 00063042 srl r6,r6,0x01curMP% / 2 0019da14: 91221837 lbu r2,0x1837(r9)MP Using Ability Mod 0019da18: 00000000 nop 0019da1c: 00c20018 mult r6,r2(curMP% / 20) * MP Mod {0-4} 0019da20: 00001012 mflo r2Caster Hate 0019da24: 04410003 bgez r2,0x0019da34Branch if no spell this unit has uses MP 0019da28: 00023083 sra r6,r2,0x02Caster Hate / 4 0019da2c: 24420003 addiu r2,r2,0x0003Caster Hate + 3 0019da30: 00023083 sra r6,r2,0x02Caster Hate + 3 / 4 0019da34: 00e63821 addu r7,r7,r6Add Caster Hate to Target Priority Value
The AI puts priority on units that have lots of mana and can cast a variety of spells. So if you ever wondered why they gun after your weak little mages all the time, this is why. The price these guys can gain can get stupid high at time, just take your MP, divide by 16, and multiply it by your number of spells to get a grasp on just how much the AI hates spellcasters. Robe of Lords might as well be a giant Kick Me sign. The AI takes into account the percentage of spells with MP costs. Golem is complete cancer
0019da38: 92020005 lbu r2,0x0005(r16)load ENTD flags 0019da3c: 00000000 nop 0019da40: 000210c2 srl r2,r2,0x03flags / 8 0019da44: 30420006 andi r2,r2,0x0006Get Team 0019da48: 3c018019 lui r1,0x8019 0019da4c: 00220821 addu r1,r1,r2 0019da50: 9426f5f4 lhu r6,-0x0a0c(r1)Load Current? Team Golem Amount 0019da54: 92430e17 lbu r3,0x0e17(r18)Load average max hp of team 0019da58: 00c02821 addu r5,r6,r0 0019da5c: 000631c0 sll r6,r6,0x07CurGolem * 80 0019da60: 00c3001a div r6,r3CurGolem * 80 / Average Team HP 0019da64: 00001812 mflo r3Golem Fear 0019da68: 00521021 addu r2,r2,r18 0019da6c: 94420e3c lhu r2,0x0e3c(r2)load Max? Team Golem Amount 0019da70: 00000000 nop 0019da74: 00a2282b sltu r5,r5,r2CurGolem < MaxGolem? 0019da78: 10a00002 beq r5,r0,0x0019da84-1 to Priority if Golem is undamaged 0019da7c: 00e33821 addu r7,r7,r3Add Golem Hate to Target Priority Value (Big mistake, has no real value when it's added to everyone) 0019da80: 24e7ffff addiu r7,r7,0xffffTarget Priority - 1
To clarify, this is not exactly why the AI drops everything it's doing to break Golem and makes the AI retarded. However, this is not really helping at all. You can clearly see the fault in adding the same amount of priority value to all units in a team. it's useless at best. Nuke this section please.
Finally, here are the Status Target Priority Values.
Status Priority Values (19f308) Values, I assume, are interpreted as curHP%, thus, each status is +/- effective curHP.
Title: Re: How the AI Works - An ongoing project researching the AI's code
Post by: Eternal on December 28, 2016, 08:25:45 pm
This is great stuff! Keep up the amazing work, Doku. :)
Title: Re: How the AI Works - An ongoing project researching the AI's code
Post by: Dokurider on December 28, 2016, 08:33:10 pm
A few more comments:
Remember that for certain skillsets, the abilities in them only ever count as one skill. For an example, Jump is only ever counted as 0x018a, Level Jump 2 and only that, no matter how many other jumps you've learned. Same goes for Elemental, and I believe Throw as well.
Oil has a very low priority value (-5.5%), which was why it had to be constantly bundled with other statuses and effects to be used by the AI. Makes a bit of sense seeing that in Vanilla, Oil didn't work at all.
Blind is -12.5% for each P-Ev skill known, including Attack. Silence is -17.5% for each silenceable ability known.
Transparent and Reraise have very high positive values, which might be why the AI gets so aggressive when they have them.
Anything that drops the target's priority to -50% might trigger the 'ignore completely' routine, which includes Confuse, Charm, and Blood Suck (Death Sentence gets it's own special flag and gets skipped in this routine). We could experiment and lower them to see if the AI continues to ignore confused/charmed lone targets.
Title: Re: How the AI Works - An ongoing project researching the AI's code
Post by: Dokurider on January 07, 2017, 12:04:56 am
Okay before I get into my next deal, a few clarifications and corrections:
The AI does not care how much MP you have, only the current percentage and if you have enough to cast your Lowest MP cost spell.
In fact, as you'll soon see, the AI puts far more stock into your spells than your curMP.
Shout out to Choto for uploading the routine I'm basing this all of on (http://ffhacktics.com/wiki/Usable_Ability_Setting/ENTD_AI_Calculations) and I presume documenting this routine and pretty much every other routine in the wiki lol.
I'll keep the code down to a minimum this time because the code is already documented.
How the AI calculates it's Blind/Silence/Caster factor Step 1: Usable Abilites
The AI starts by figuring out what abilities it has is usable. It starts off with Attack, then it starts going into it's skillsets. While it processes Throw, Math, Charge and Jump a little differently, it's nothing really eyebrow raising except perhaps the way Charging with Guns is treated (refuses to use Charge for guns it seems?) In any case, it first checks to see if the skill is flagged as Usable by the AI. It then checks to see if the ability in question uses MP and if it does, do you even have the Max MP to even cast it?
Yes it does reduce the MP Cost by Half of MP, but the 1/3 of MP did not update the AI to reflect this. A fix is in the works, so don't fret too much.
Then it renders abilities unusable if the ability is a faith spell on a unit with innate Innocent, or the unit doesn't have the requred Sword/Materia Blade to use said ability. You can't know a skill that requires Monster Skill without...Monster Skill, and more importantly, if you are not in fact a monster yourself. If the ability in question is 0x170 (Potion and other special abilities) or higher, it will skip all of that and go to the final step. Keep that in mind if you're trying to make those skills normal.
And finally, of course, it has to have actually learned the ability in the first place. Once it has cleared all of that and the skillset in question is not Jump, it will trot out the list of known abilities for that skillset. Repeat for the other skillset. Finally it will save all of this, plus Frog Attack. Yes, the AI always knows Frog Attack as well as Attack. I suppose you can think of it as the Struggle of FFT. It's also what Monster units use when Berserked. The AI always counting Attack and Frog Attack in it's skill counting is very important to remember for later. Step 2: Deriving Silence/P-Ev/MP skill counts and some small usage flagging
Now that we have our list of Usable abilities, we can derive our Silence/Blind/Caster mods from them. It's about what you'd expect. Add up all abilities that are physically evadable (aka evade with motion), silenceable, and uses MP. There are no restrictions against any of them other than being flagged as such.
It stores the Lowest and Highest MP costs that unit has. It flags Linear/Vertical/Triple Bracelet|Attack, and any attack over 3 range + AoE as 0x0400. It flags Reflect/Silencable or has an AoE of 0 as 0x0200. Step 3: How to get your Blind/Silence/Caster values and how to game the system.
0019a148: 02802021 addu r4,r20,r0 Divisor = Number of Abilities 0019a14c: 0c0668b3 jal 0x 0019a2cc Dividend * 4 / Divisor 0019a150: 02e02821 addu r5,r23,r0 Dividend = Silence Ignoring Abilities 0019a154: 02802021 addu r4,r20,r0 Divisor = Number of Abilities 0019a158: 03c02821 addu r5,r30,r0 Dividend = MP Using Abilities 0019a15c: 0c0668b3 jal 0x 0019a2cc Dividend * 4 / Divisor 0019a160: a222000c sb r2,0x000c(r17) Store MP Silence Blocking Mod 0019a164: 8fa50010 lw r5,0x0010(r29) Load Evade ignoring Abilities 0019a168: 02802021 addu r4,r20,r0 Divisor = Number of Abilities 0019a16c: 0c0668b3 jal 0x 0019a2cc Dividend * 4 / Divisor 0019a170: a222000b sb r2,0x000b(r17) Store MP Using Mod 0019a174: 26240004 addiu r4,r17,0x0004 r4 = ? Pointer + 4 0019a178: 26c50167 addiu r5,r22,0x0167 r5 = Pointer to Unit's ENTD AI Data? 0019a17c: 34060005 ori r6,r0,0x0005 Limit = 5 0019a180: 0c066ad2 jal 0x 0019ab48 Transfer Byte Values 0019a184: a222000d sb r2,0x000d(r17) Store Evade Ignoring Mod
So the basic formula for determine your unit's Blind/Silence/Caster factor is:
Quote(# of effected spells * 4) / Total Usable spells
This will get you a number between 0-4, with 0 being less than 25% and 4 being 100%. Remember that you must always factor in both Attack and Frog Attack into your calculations.
For an example, a unit that has no skills learned, will only know Attack and Frog Attack. He has a Silence and Caster factor of 0, but a Blind factor of 4, because:
Quote[# of P-EV abilities=2] * 4 / [# of total abilities=2] = 4
So he would be a prime Blind target, assuming he was vulnerable to Blind. But if he learned any one (1) non P-Ev ability, his Blind factor would drop dramatically to 2. Picking up two more non P-Ev skills would bump his total skills usable to 5 and his Blind factor to 1. He might as well be a mage with a Healing Staff.
So I wasn't completely accurate when I said the AI can't "tell the immediate difference between a White Mage with Healing Staff and a Berserk Cursed Ring Two Handed Main Gauche killer", because it kinda can. But it can be easily gamed to duck being targeted.
So if you want your Casters to duck being targeted, remember you always have two non MP using skills to balance against, thus you will never have a max Silence/Caster factor of 4.
Can I simply have a Summon Magic secondary on my Male Lancer, learn as many Summons as feasible and then never get targeted by Blind ever? Not exactly. Remember that the AI kicks out any skill from it's usable pool if it has an MP cost exceeding it's Max MP. But if you have enough MP to cast any of them even once, then yes, you can grab that cheap caster aggro and be a taunt tank...exactly once before the AI casts a spell, and then you're completely out of MP and the game yanks your aggro license.
That's about everything for today. It's not a major revelation today, sorry, but I'm a little overdue. I made a few edits to the original post to fix some mistakes in my original analysis. I don't have too many complaints about how the AI calculates the factors, except the caster value. It should compensate for Attack/Frog Attack.
Title: Re: How the AI Works - An ongoing project researching the AI's code
Post by: Dokurider on January 21, 2017, 04:05:36 am
Hey folks, got another section for you guys.
AI Ability Use (19e5d8) has been known about for a while, but only lightly documented until now. This routine doesn't really so much decide what abilities to use, so much as says what abilities to not use. Nevertheless what you're about to read will enlighten you.
Return r2: 0 = Unusable 1 = OK to use 2 = Not OK to use
0019e5d8: 27bdffc0 addiu r29,r29,0xffc0 0019e5dc: afbe0038 sw r30,0x0038(r29) 0019e5e0: 3c1e801a lui r30,0x801a 0019e5e4: 27def3c4 addiu r30,r30,0xf3c4 r30 = AI data 0019e5e8: 000410c0 sll r2,r4,0x03 0019e5ec: 00441023 subu r2,r2,r4 0019e5f0: 00021180 sll r2,r2,0x06 0019e5f4: 3c038019 lui r3,0x8019 0019e5f8: 246308cc addiu r3,r3,0x08cc r3 = Unit Data 0019e5fc: afb60030 sw r22,0x0030(r29) 0019e600: 0043b021 addu r22,r2,r3 0019e604: 00041100 sll r2,r4,0x04 0019e608: 2442182c addiu r2,r2,0x182c r2 = decision data 0019e60c: afb70034 sw r23,0x0034(r29) 0019e610: 005eb821 addu r23,r2,r30 r23 = decision data 0019e614: 3c02801a lui r2,0x801a 0019e618: 8c42f3d0 lw r2,-0x0c30(r2)Load AI Ability Flags 0019e61c: 3c07801a lui r7,0x801a 0019e620: 90e7f3c5 lbu r7,-0x0c3b(r7) Load Unit AI Pointer 0019e624: 3c032000 lui r3,0x2000 0019e628: afbf003c sw r31,0x003c(r29) 0019e62c: afb5002c sw r21,0x002c(r29) 0019e630: afb40028 sw r20,0x0028(r29) 0019e634: afb30024 sw r19,0x0024(r29) 0019e638: afb20020 sw r18,0x0020(r29) 0019e63c: afb1001c sw r17,0x001c(r29) 0019e640: afb00018 sw r16,0x0018(r29)
<Enemy/Ally Targeting> 0019e644: 00431024 and r2,r2,r3 0019e648: 10400005 beq r2,r0,0x0019e660Branch if can target allies 0019e64c: afa70010 sw r7,0x0010(r29) 0019e650: 92e20008 lbu r2,0x0008(r23) load enemy flag 0019e654: 00000000 nop 0019e658: 10400225 beq r2,r0,0x0019eef0 Don't use this skill on an Ally you can't hit anyways 0019e65c: 00001021 addu r2,r0,r0 0019e660: 8fc2000c lw r2,0x000c(r30) load ability AI behavior flags 0019e664: 3c034000 lui r3,0x4000 0019e668: 00431024 and r2,r2,r3 0019e66c: 10400005 beq r2,r0,0x0019e684 <Target Self> if can target enemies 0019e670: 00000000 nop 0019e674: 92e20008 lbu r2,0x0008(r23) load enemy flag 0019e678: 00000000 nop 0019e67c: 1440021c bne r2,r0,0x0019eef0 Don't use this skill on an enemy you can't target anyways 0019e680: 00001021 addu r2,r0,r0
<Target Self> 0019e684: 93c20e2e lbu r2,0x0e2e(r30) load acting unit id 0019e688: 00000000 nop 0019e68c: 1482000f bne r4,r2,0x0019e6cc <Reflect Check> if unit is not self 0019e690: 00000000 nop 0019e694: 87c30002 lh r3,0x0002(r30) load ability ID 0019e698: 00000000 nop 0019e69c: 28620170 slti r2,r3,0x0170 0019e6a0: 1040000a beq r2,r0,0x0019e6cc<Reflect Check> if Ability is a normal skill 0019e6a4: 000310c0 sll r2,r3,0x03 0019e6a8: 00431023 subu r2,r2,r3 0019e6ac: 00021040 sll r2,r2,0x01 0019e6b0: 3c018006 lui r1,0x8006 0019e6b4: 00220821 addu r1,r1,r2 0019e6b8: 9022fbf4 lbu r2,-0x040c(r1) load ability flags 0019e6bc: 00000000 nop 0019e6c0: 30420001 andi r2,r2,0x0001 0019e6c4: 1440020a bne r2,r0,0x0019eef0 Exit because you can't hit yourself with this spell 0019e6c8: 00001021 addu r2,r0,r0
<Reflect Check> 0019e6cc: 10a0000b beq r5,r0,0x0019e6fcBypass Reflect Check <Faith Check> 0019e6d0: 00000000 nop 0019e6d4: 8fc2000c lw r2,0x000c(r30)Load Usage 0019e6d8: 00000000 nop 0019e6dc: 30424000 andi r2,r2,0x4000 0019e6e0: 10400006 beq r2,r0,0x0019e6fc <Faith Check> if not reflectable 0019e6e4: 02c02821 addu r5,r22,r0Get Unit Data Pointer 0019e6e8: 8fa40010 lw r4,0x0010(r29)Get Clockticks 0019e6ec: 0c067bc9 jal 0x0019ef24Check if Status Should/Can be Added 0019e6f0: 34060026 ori r6,r0,0x0026Check for Reflect 0019e6f4: 144001fe bne r2,r0,0x0019eef0Unit has Reflect, don't use 0019e6f8: 00001021 addu r2,r0,r0
<Faith Check> 0019e6fc: 8fc2000c lw r2,0x000c(r30)Load Usage 0019e700: 00000000 nop 0019e704: 30420400 andi r2,r2,0x0400 0019e708: 10400006 beq r2,r0,0x0019e724 <Jump Check> if not faith ability 0019e70c: 02c02821 addu r5,r22,r0 0019e710: 8fa40010 lw r4,0x0010(r29) 0019e714: 0c067bc9 jal 0x0019ef2Check if Status Should/Can be Added 0019e718: 34060021 ori r6,r0,0x0021Check for Innocent 0019e71c: 144001f4 bne r2,r0,0x0019eef0Unit has Innocent, don't use 0019e720: 00001021 addu r2,r0,r0
<Jump Check> 0019e724: 8fa40010 lw r4,0x0010(r29) 0019e728: 02c02821 addu r5,r22,r0 0019e72c: 0c067bc9 jal 0x0019ef2Check if Status Should/Can be Added 0019e730: 34060005 ori r6,r0,0x0005Check for Jump 0019e734: 144001ee bne r2,r0,0x0019eef0Unit is Jumping, don't use 0019e738: 00001021 addu r2,r0,r0
<If Dead> 0019e73c: 8fc2000c lw r2,0x000c(r30)Load Usage 0019e740: 00000000 nop 0019e744: 30420020 andi r2,r2,0x0020 0019e748: 10400005 beq r2,r0,0x0019e760 <Dead with Reraise> if this ability doesn't cancel status 0019e74c: 0000a021 addu r20,r0,r0 0019e750: 93c20007 lbu r2,0x0007(r30) load status infliction 1 0019e754: 00000000 nop 0019e758: 30420020 andi r2,r2,0x0020 0019e75c: 0002a02b sltu r20,r0,r2 r20 = Unit is dead or spell will add dead
<Dead with Reraise> 0019e760: 92e20007 lbu r2,0x0007(r23) load type of target 0019e764: 00000000 nop 0019e768: 30420040 andi r2,r2,0x0040 0019e76c: 10400009 beq r2,r0,0x0019e794 <Dead> if unit doesn't have reraise as well 0019e770: 00000000 nop 0019e774: 93d00001 lbu r16,0x0001(r30) load CT 0019e778: 0c0666e6 jal 0x00199b98Calculate Clockticks Until Unit Acts 0019e77c: 02c02021 addu r4,r22,r0 0019e780: 0202802a slt r16,r16,r2 0019e784: 1600003e bne r16,r0,0x0019e880Don't use this ability because unit will get up before then 0019e788: 00000000 nop 0019e78c: 168001d8 bne r20,r0,0x0019eef0Unit is dead but has reraise, don't revive 0019e790: 00001021 addu r2,r0,r0
<Dead> 0019e794: 92e20007 lbu r2,0x0007(r23) 0019e798: 00000000 nop 0019e79c: 30420020 andi r2,r2,0x0020 0019e7a0: 10400009 beq r2,r0,0x0019e7c8 <If Petrified> if not even dead 0019e7a4: 00000000 nop 0019e7a8: 93d00001 lbu r16,0x0001(r30) 0019e7ac: 0c066722 jal 0x00199c88Get number of clockticks till able to revive dead unit 0019e7b0: 02c02021 addu r4,r22,r0 0019e7b4: 0050102a slt r2,r2,r16 0019e7b8: 14400031 bne r2,r0,0x0019e880It's too late to revive this unit (Won't be able to go off in time) 0019e7bc: 00000000 nop 0019e7c0: 128001cb beq r20,r0,0x0019eef0Ability doesn't cure Dead, don't use 0019e7c4: 00001021 addu r2,r0,r0
<If Petrified> 0019e7c8: 92c20059 lbu r2,0x0059(r22)Load Current Status 2 0019e7cc: 00000000 nop 0019e7d0: 30420080 andi r2,r2,0x0080 0019e7d4: 1040000b beq r2,r0,0x0019e804 <If Wall> if not petrified 0019e7d8: 02c02821 addu r5,r22,r0 0019e7dc: 8fc2000c lw r2,0x000c(r30)Load AI Ability Flags 0019e7e0: 00000000 nop 0019e7e4: 30420020 andi r2,r2,0x0020 0019e7e8: 104001c1 beq r2,r0,0x0019eef0 Ability doesn't cure Petrify, don't use 0019e7ec: 00001021 addu r2,r0,r0 0019e7f0: 93c20008 lbu r2,0x0008(r30) load status infliction 2 0019e7f4: 00000000 nop 0019e7f8: 30420080 andi r2,r2,0x0080 0019e7fc: 104001bc beq r2,r0,0x0019eef0 Ability doesn't use Petrify, don't use 0019e800: 00001021 addu r2,r0,r0
<If Wall> 0019e804: 8fa40010 lw r4,0x0010(r29) 0019e808: 0c067bc9 jal 0x0019ef2Check if Status Should/Can be Added 0019e80c: 3406001f ori r6,r0,0x001fCheck for Wall 0019e810: 1040000b beq r2,r0,0x0019e840<Elemental Null> if unit doesn't have wall 0019e814: 00000000 nop 0019e818: 8fc2000c lw r2,0x000c(r30) 0019e81c: 00000000 nop 0019e820: 30420020 andi r2,r2,0x0020 0019e824: 104001b2 beq r2,r0,0x0019eef0 Ability doesn't cancel Wall, don't use 0019e828: 00001021 addu r2,r0,r0 0019e82c: 93c2000a lbu r2,0x000a(r30) load status infliction 4 0019e830: 00000000 nop 0019e834: 30420001 andi r2,r2,0x0001 0019e838: 104001ad beq r2,r0,0x0019eef0 Ability doesn't cancel Wall, don't use 0019e83c: 00001021 addu r2,r0,r0
<Elemental Null> 0019e840: 93d40010 lbu r20,0x0010(r30) load ability elements 0019e844: 00000000 nop 0019e848: 1280000f beq r20,r0,0x0019e888<Undead Reverse> if no elements 0019e84c: 00000000 nop 0019e850: 92c2006e lbu r2,0x006e(r22) Load target elemental nullification 0019e854: 00000000 nop 0019e858: 02821024 and r2,r20,r2 0019e85c: 12820008 beq r20,r2,0x0019e880This unit blocks the element, don't use this ability 0019e860: 34020008 ori r2,r0,0x0008
<Float> 0019e864: 16820008 bne r20,r2,0x0019e888Skip Float Evaluation if not Earth Elemental 0019e868: 00000000 nop 0019e86c: 92c2005a lbu r2,0x005a(r22)Load Current Status 3 0019e870: 00000000 nop 0019e874: 30420040 andi r2,r2,0x0040 0019e878: 10400003 beq r2,r0,0x0019e888 <Undead Reverse> if not float 0019e87c: 00000000 nop 0019e880: 08067bbc j 0x0019eef0Unit has float, don't use ability 0019e884: 00001021 addu r2,r0,r0
<Healing Undead Ally> 0019e8c0: 92c20058 lbu r2,0x0058(r22)Current Status 1 0019e8c4: 00000000 nop 0019e8c8: 30420010 andi r2,r2,0x0010 0019e8cc: 14400050 bne r2,r0,0x0019ea10 <HP Ability> if ally = undead 0019e8d0: 00000000 nop 0019e8d4: 08067bbc j 0x0019eef0Ally isn't Undead, this will hurt them 0019e8d8: 34020002 ori r2,r0,0x0002
<Elemental Absorb> 0019e8dc: 92e20008 lbu r2,0x0008(r23) load enemy flag 0019e8e0: 00000000 nop 0019e8e4: 10400009 beq r2,r0,0x0019e90c <Charmed Ally> if Ally 0019e8e8: 02c02821 addu r5,r22,r0 0019e8ec: 92c2006d lbu r2,0x006d(r22) Elemental absorb 0019e8f0: 93c30010 lbu r3,0x0010(r30) load ability elements 0019e8f4: 00000000 nop 0019e8f8: 00431024 and r2,r2,r3 absorbs & elements 0019e8fc: 10400044 beq r2,r0,0x0019ea10 <HP Ability> if no elements being absorbed by enemies/Enemy is undead 0019e900: 34020002 ori r2,r0,0x0002 0019e904: 08067bbc j 0x0019eef0Don't use this ability because it'll heal them 0019e908: 00000000 nop
<Charmed Ally> 0019e90c: 8fa40010 lw r4,0x0010(r29) 0019e910: 0c067bc9 jal 0x0019ef2Check if Status Should/Can be Added 0019e914: 34060022 ori r6,r0,0x0022Check for Charm 0019e918: 10400005 beq r2,r0,0x0019e930Branch if unit doesn't have any Charm 0019e91c: 02c02021 addu r4,r22,r0 0019e920: 0c067bec jal 0x0019efb0Check if Charm, Don't Act or Move can be added before unit acts 0019e924: 34050022 ori r5,r0,0x0022Check for Charm 0019e928: 14400002 bne r2,r0,0x0019e934Branch if it can be removed in time 0019e92c: 34140001 ori r20,r0,0x0001Charm is present 0019e930: 0000a021 addu r20,r0,r0Target has no Charm
0019e934: 8fc2000c lw r2,0x000c(r30) Load AI Flags 0019e938: 00000000 nop 0019e93c: 30420080 andi r2,r2,0x0080 0019e940: 10400015 beq r2,r0,0x0019e998 <Elemental Healing> if not hp affecting ability (Why?) 0019e944: 00000000 nop 0019e948: 93c20000 lbu r2,0x0000(r30) load skillset 0019e94c: 3c018006 lui r1,0x8006 0019e950: 00220821 addu r1,r1,r2 0019e954: 90235cb4 lbu r3,0x5cb4(r1) load action byte 0019e958: 3402000a ori r2,r0,0x000a 0019e95c: 1062000e beq r3,r2,0x0019e998 <Elemental Healing> if Charge 0019e960: 00000000 nop
<Break Confuse> 0019e964: 92c20059 lbu r2,0x0059(r22)Load Current Status 2 0019e968: 00000000 nop 0019e96c: 30420010 andi r2,r2,0x0010 0019e970: 1440015f bne r2,r0,0x0019eef0 Break Confuse 0019e974: 34020001 ori r2,r0,0x0001 <Break Sleep> 0019e978: 8fa40010 lw r4,0x0010(r29) 0019e97c: 02c02821 addu r5,r22,r0 0019e980: 0c067bc9 jal 0x0019ef2Check if Status Should/Can be Added 0019e984: 34060023 ori r6,r0,0x0023Check for Sleep 0019e988: 14400046 bne r2,r0,0x0019eaa4Break Sleep 0019e98c: 00000000 nop <Break Charm> 0019e990: 16800157 bne r20,r0,0x0019eef0Break Charm with this ability 0019e994: 34020001 ori r2,r0,0x0001
<Elemental Healing> 0019e998: 92c2006d lbu r2,0x006d(r22) Elemental absorb 0019e99c: 93c30010 lbu r3,0x0010(r30) load elements 0019e9a0: 00000000 nop 0019e9a4: 00431024 and r2,r2,r3 elements & absorbs 0019e9a8: 10400006 beq r2,r0,0x0019e9c4 <Don't Attack Ally> if unit doesn't absorb this element 0019e9ac: 00000000 nop 0019e9b0: 92e20007 lbu r2,0x0007(r23) AI Decision Flag 0019e9b4: 00000000 nop 0019e9b8: 30420001 andi r2,r2,0x0001 0019e9bc: 1440014c bne r2,r0,0x0019eef0 Heal this unit if they have >50% HP 0019e9c0: 34020001 ori r2,r0,0x0001
<Don't Attack Ally> 0019e9c4: 92c20059 lbu r2,0x0059(r22)Load Current Status 2 0019e9c8: 00000000 nop 0019e9cc: 30420014 andi r2,r2,0x0014 0019e9d0: 14400003 bne r2,r0,0x0019e9e0 <Disable Ally> if confusion or blood suck 0019e9d4: 00000000 nop 0019e9d8: 12800145 beq r20,r0,0x0019eef0No reason to attack an allythen 0019e9dc: 34020002 ori r2,r0,0x0002
<Disable Ally> 0019e9e0: 8fc2000c lw r2,0x000c(r30) 0019e9e4: 00000000 nop 0019e9e8: 30420010 andi r2,r2,0x0010 0019e9ec: 1040ffb9 beq r2,r0,0x0019e8d4 Branch to Exit if no add status; No reason to use this on an ally (Why branch all the way up there?) 0019e9f0: 3c031c06 lui r3,0x1c06 Sleep, Don't Move, Don't Act, Slow and Stop 0019e9f4: 8fc20008 lw r2,0x0008(r30) 0019e9f8: 00000000 nop 0019e9fc: 00431024 and r2,r2,r3 0019ea00: 1440013b bne r2,r0,0x0019eef0 Use only these statuses to deal with Confused/Blood Suck Allies 0019ea04: 34020001 ori r2,r0,0x0001 0019ea08: 08067bbc j 0x0019eef0Don't use any other status 0019ea0c: 34020002 ori r2,r0,0x0002
<HP Ability> 0019ea10: 8fc2000c lw r2,0x000c(r30) 0019ea14: 00000000 nop 0019ea18: 30420080 andi r2,r2,0x0080 0019ea1c: 10400006 beq r2,r0,0x0019ea38 <MP Ability> if not HP affecting 0019ea20: 00000000 nop 0019ea24: 92c2005c lbu r2,0x005c(r22)Load Current Status 5 0019ea28: 00000000 nop 0019ea2c: 30420001 andi r2,r2,0x0001 0019ea30: 1040012f beq r2,r0,0x0019eef0 Attack Enemy unless Death Sentence 0019ea34: 34020001 ori r2,r0,0x0001 <MP Ability> 0019ea38: 8fc2000c lw r2,0x000c(r30) 0019ea3c: 00000000 nop 0019ea40: 30420040 andi r2,r2,0x0040 0019ea44: 10400007 beq r2,r0,0x0019ea64 <Target Allies> if not MP affecting 0019ea48: 00000000 nop 0019ea4c: 96c3002c lhu r3,0x002c(r22) Load mp 0019ea50: 92e2000a lbu r2,0x000a(r23) load lowest mp cost 0019ea54: 00000000 nop 0019ea58: 0043102b sltu r2,r2,r3 0019ea5c: 14400124 bne r2,r0,0x0019eef0 This unit has enough MP to cast his lowest MP ability 0019ea60: 34020001 ori r2,r0,0x0001
<Target Allies> 0019ea64: 8fc3000c lw r3,0x000c(r30) 0019ea68: 00000000 nop 0019ea6c: 30620001 andi r2,r3,0x0001 0019ea70: 10400036 beq r2,r0,0x0019eb4c <Target Ally and Enemy> if not target allies 0019ea74: 30622000 andi r2,r3,0x2000 0019ea78: 1040000f beq r2,r0,0x0019eab8 <Allied Ability> if no Undead Reverse 0019ea7c: 00000000 nop 0019ea80: 92e20008 lbu r2,0x0008(r23) load enemy flag 0019ea84: 00000000 nop 0019ea88: 10400008 beq r2,r0,0x0019eaac <Allied Ability> if Ally 0019ea8c: 00000000 nop 0019ea90: 92c30058 lbu r3,0x0058(r22)Load Current Status 1 0019ea94: 00000000 nop 0019ea98: 30630010 andi r3,r3,0x0010 0019ea9c: 10600114 beq r3,r0,0x0019eef0 This unit isn't undead, no reason to heal this enemy 0019eaa0: 34020002 ori r2,r0,0x0002 0019eaa4: 08067bbc j 0x0019eef0Heal Undead for damage 0019eaa8: 34020001 ori r2,r0,0x0001
<Allied Ability> 0019eaac: 92c20058 lbu r2,0x0058(r22)Load Current Status 1 0019eab0: 08067aaf j 0x0019eabcJump to check 0019eab4: 30420010 andi r2,r2,0x0010 undead check
0019eab8: 92e20008 lbu r2,0x0008(r23) 0019eabc: 00000000 nop 0019eac0: 1440010b bne r2,r0,0x0019eef0 Don't heal Enemy/Undead Ally 0019eac4: 34020002 ori r2,r0,0x0002 0019eac8: 92c2005c lbu r2,0x005c(r22)Load Current Status 5 0019eacc: 00000000 nop 0019ead0: 30420001 andi r2,r2,0x0001 0019ead4: 10400009 beq r2,r0,0x0019eafc <Heal HP> if not death sentence 0019ead8: 00000000 nop 0019eadc: 8fc3000c lw r3,0x000c(r30)Load AI Flags 0019eae0: 00000000 nop 0019eae4: 30630010 andi r3,r3,0x0010 0019eae8: 10600101 beq r3,r0,0x0019eef0 Don't use this ability because it doesn't add Reraise 0019eaec: 00001021 addu r2,r0,r0 0019eaf0: 93c20009 lbu r2,0x0009(r30)Load Inflicted Status 3 0019eaf4: 08067bbb j 0x0019eeecCheck if Reraise before exiting 0019eaf8: 30420020 andi r2,r2,0x0020
<Heal HP> 0019eafc: 8fc2000c lw r2,0x000c(r30) 0019eb00: 00000000 nop 0019eb04: 30420080 andi r2,r2,0x0080 0019eb08: 10400006 beq r2,r0,0x0019eb24 <Heal MP> if not HP ability 0019eb0c: 00000000 nop 0019eb10: 92e20007 lbu r2,0x0007(r23)Load AI Targeting 0019eb14: 00000000 nop 0019eb18: 30420001 andi r2,r2,0x0001 0019eb1c: 144000f4 bne r2,r0,0x0019eef0 Heal unit if low hp (less than 50%) 0019eb20: 34020001 ori r2,r0,0x0001
0019eb60: 144000e3 bne r2,r0,0x0019eef0 This ability deals damage so it's fine to use 0019eb64: 34020001 ori r2,r0,0x0001 0019eb68: 30620040 andi r2,r3,0x0040 0019eb6c: 144000e0 bne r2,r0,0x0019eef0 This ability deals MP Damage so it's fine to use 0019eb70: 34020001 ori r2,r0,0x0001
<Adding status> 0019eb74: 8fc2000c lw r2,0x000c(r30) 0019eb78: 00000000 nop 0019eb7c: 30420010 andi r2,r2,0x0010 0019eb80: 10400073 beq r2,r0,0x0019ed50 <Cancel Status> if no add status 0019eb84: 00000000 nop 0019eb88: 0000a021 addu r20,r0,r0 0019eb8c: 03d41021 addu r2,r30,r20 0019eb90: 02d41821 addu r3,r22,r20 0019eb94: 90500007 lbu r16,0x0007(r2)Load Inflicted Status List 0019eb98: 90620058 lbu r2,0x0058(r3) load Current status 0019eb9c: 00000000 nop 0019eba0: 02021024 and r2,r16,r2 0019eba4: 02028026 xor r16,r16,r2 Remove statuses already present 0019eba8: 12000065 beq r16,r0,0x0019ed40 <Status++> if inflicting status that's already there/no status in that block 0019ebac: 00000000 nop 0019ebb0: 90620053 lbu r2,0x0053(r3) load status immunity 0019ebb4: 00000000 nop 0019ebb8: 02021024 and r2,r16,r2 0019ebbc: 02028026 xor r16,r16,r2Remove status immunities 0019ebc0: 1200005f beq r16,r0,0x0019ed40<Status++> if unit is immune to status/no statuses in that block 0019ebc4: 34020002 ori r2,r0,0x0002 0019ebc8: 1282001f beq r20,r2,0x0019ec48<Current Status 3> 0019ebcc: 2a820003 slti r2,r20,0x0003 0019ebd0: 10400005 beq r2,r0,0x0019ebe8<Current Status 4 and 5> 0019ebd4: 34020001 ori r2,r0,0x0001 0019ebd8: 1282000a beq r20,r2,0x0019ec04Go to <Current Status 2> 0019ebdc: 32020008 andi r2,r16,0x0008Check for Silence 0019ebe0: 08067b4e j 0x0019ed38<Confirm Status> 0019ebe4: 00000000 nop
<Current Status 4 and 5> 0019ebe8: 34020003 ori r2,r0,0x0003 0019ebec: 1282002e beq r20,r2,0x0019eca8<Current Status 4> 0019ebf0: 34020004 ori r2,r0,0x0004 0019ebf4: 1282004a beq r20,r2,0x0019ed20<Current Status 5> 0019ebf8: 00000000 nop 0019ebfc: 08067b4e j 0x0019ed38<Confirm Status> 0019ec00: 00000000 nop
<Current Status 2> <Silence> 0019ec04: 10400007 beq r2,r0,0x0019ec24<Blind> if not Silenced 0019ec08: 32020020 andi r2,r16,0x0020Check for Blind 0019ec0c: 92e2000c lbu r2,0x000c(r23) Load Silenceable Abilities Modifier 0019ec10: 00000000 nop 0019ec14: 14400003 bne r2,r0,0x0019ec24 <Blind> if Target has any Silenceable ability (Silence Modifier) 0019ec18: 32020020 andi r2,r16,0x0020Check for Blind 0019ec1c: 3a100008 xori r16,r16,0x0008Remove Silence because unit doesn't have Silenceable abilities 0019ec20: 32020020 andi r2,r16,0x0020Check for Blind <Blind> 0019ec24: 10400044 beq r2,r0,0x0019ed38<Confirm Status> if not adding Blind 0019ec28: 00000000 nop 0019ec2c: 92e2000d lbu r2,0x000d(r23) load Evadable Abilities Modifier 0019ec30: 00000000 nop 0019ec34: 2c420002 sltiu r2,r2,0x0002 0019ec38: 1040003f beq r2,r0,0x0019ed38 <Confirm Status> if Evade Mod > 1 (Greater than 25% of abilities learned) 0019ec3c: 00000000 nop 0019ec40: 08067b4e j 0x0019ed38<Confirm Status> 0019ec44: 3a100020 xori r16,r16,0x0020Remove Blind because Unit doesn't have enough Evadable abilities
<Current Status 3> <Reraise> 0019ec48: 32020020 andi r2,r16,0x0020 0019ec4c: 10400008 beq r2,r0,0x0019ec70<Frog> if not adding Reraise 0019ec50: 32020002 andi r2,r16,0x0002 0019ec54: 92e20007 lbu r2,0x0007(r23)Load AI Targeting 0019ec58: 00000000 nop 0019ec5c: 30420001 andi r2,r2,0x0001 0019ec60: 14400003 bne r2,r0,0x0019ec70 <Frog> if low hp (>50%) unit 0019ec64: 32020002 andi r2,r16,0x0002Check for Frog 0019ec68: 3a100020 xori r16,r16,0x0020Don't add Reraise if not at 50% HP or less 0019ec6c: 32020002 andi r2,r16,0x0002Check for Frog <Frog> 0019ec70: 10400006 beq r2,r0,0x0019ec8c<Float> if not adding Frog 0019ec74: 00000000 nop 0019ec78: 92e20008 lbu r2,0x0008(r23) load enemy flag 0019ec7c: 00000000 nop 0019ec80: 14400002 bne r2,r0,0x0019ec8c <Float> if enemy 0019ec84: 00000000 nop 0019ec88: 3a100002 xori r16,r16,0x0002Remove Frog (don't turn your allies into frogs I guess) <Float> 0019ec8c: 92e20007 lbu r2,0x0007(r23) 0019ec90: 00000000 nop 0019ec94: 30420080 andi r2,r2,0x0080 0019ec98: 14400027 bne r2,r0,0x0019ed38 <Confirm Status> if critical hp unit 0019ec9c: 00000000 nop 0019eca0: 08067b4e j 0x0019ed38<Confirm Status> 0019eca4: 321000bf andi r16,r16,0x00bfDon't add Float unless critical (lol)
<Current Status 4> <Regen> 0019eca8: 32020040 andi r2,r16,0x0040 0019ecac: 10400007 beq r2,r0,0x0019eccc<Protect/Shell/Wall> if not adding Regen 0019ecb0: 00000000 nop 0019ecb4: 92e20007 lbu r2,0x0007(r23) 0019ecb8: 00000000 nop 0019ecbc: 30420001 andi r2,r2,0x0001 0019ecc0: 14400002 bne r2,r0,0x0019eccc <Protect/Shell/Wall> if low hp unit 0019ecc4: 00000000 nop 0019ecc8: 3a100040 xori r16,r16,0x0040Remove Regen (Don't add Regen unless at 50% or less HP) <Protect/Shell/Wall> 0019eccc: 92e20007 lbu r2,0x0007(r23) 0019ecd0: 00000000 nop 0019ecd4: 30420080 andi r2,r2,0x0080 0019ecd8: 14400003 bne r2,r0,0x0019ece8 <Haste/Slow> if critical hp unit 0019ecdc: 3202000c andi r2,r16,0x000cCheck for Haste/Slow 0019ece0: 321000ce andi r16,r16,0x00ceRemove Protect/Shell/Wall (Don't add Protect/Shell/Wall unless Critical) 0019ece4: 3202000c andi r2,r16,0x000cCheck for Haste/Slow <Haste/Slow> 0019ece8: 10400013 beq r2,r0,0x0019ed38<Confirm Status> if not adding Haste/Slow 0019ecec: 00000000 nop 0019ecf0: 92c2005b lbu r2,0x005b(r22) Load Current Status 4 0019ecf4: 00000000 nop 0019ecf8: 30420002 andi r2,r2,0x0002 0019ecfc: 14400006 bne r2,r0,0x0019ed18 Branch to remove/not add Haste/Slow if Stop 0019ed00: 00000000 nop 0019ed04: 92c2005c lbu r2,0x005c(r22)Load Current Status 5 0019ed08: 00000000 nop 0019ed0c: 30420010 andi r2,r2,0x0010 0019ed10: 10400009 beq r2,r0,0x0019ed38 <Confirm Status> if not sleep 0019ed14: 00000000 nop 0019ed18: 08067b4e j 0x0019ed38<Confirm Status> 0019ed1c: 321000f3 andi r16,r16,0x00f3Remove Haste/Slow
<Current Status 5> <Faith/Reflect> 0019ed20: 92e20007 lbu r2,0x0007(r23) 0019ed24: 00000000 nop 0019ed28: 30420080 andi r2,r2,0x0080 0019ed2c: 14400002 bne r2,r0,0x0019ed38 <Confirm Status> if critical hp unit 0019ed30: 00000000 nop 0019ed34: 3210007d andi r16,r16,0x007dRemove Faith and Reflect (Don't add Faith/Reflect unless critical)
<Confirm Status> 0019ed38: 1600006d bne r16,r0,0x0019eef0Ability is adding a status 0019ed3c: 34020001 ori r2,r0,0x0001
<Status++> 0019ed40: 26940001 addiu r20,r20,0x0001Next Status Block 0019ed44: 2a820005 slti r2,r20,0x0005 0019ed48: 1440ff91 bne r2,r0,0x0019eb90Loop until Current Status 5 0019ed4c: 03d41021 addu r2,r30,r20 </Add Status>
<Cancel Status> 0019ed50: 8fc2000c lw r2,0x000c(r30) 0019ed54: 00000000 nop 0019ed58: 30420020 andi r2,r2,0x0020 0019ed5c: 1040004e beq r2,r0,0x0019ee98 <Affect Stats> if not cancel status 0019ed60: 00000000 nop 0019ed64: 0000a021 addu r20,r0,r0 0019ed68: 03d41021 addu r2,r30,r20 0019ed6c: 02d41821 addu r3,r22,r20 0019ed70: 90500007 lbu r16,0x0007(r2) load status infliction 0019ed74: 90620058 lbu r2,0x0058(r3) load current status 0019ed78: 00000000 nop 0019ed7c: 02028024 and r16,r16,r2 0019ed80: 12000041 beq r16,r0,0x0019ee88 <Cancel++> if unit doesn't have statuses to be removed 0019ed84: 00000000 nop 0019ed88: 9062004e lbu r2,0x004e(r3) load innate status 0019ed8c: 00000000 nop 0019ed90: 02021024 and r2,r16,r2 0019ed94: 02028026 xor r16,r16,r2 0019ed98: 1200003b beq r16,r0,0x0019ee88 <Cancel++> if unit's status is innate and cannot be removed 0019ed9c: 2a820003 slti r2,r20,0x0003 0019eda0: 14400019 bne r2,r0,0x0019ee08<Cancel Status 1 - 3> 0019eda4: 34020001 ori r2,r0,0x0001
<Cancel Status 4 and 5> 0019eda8: 00009021 addu r18,r0,r0 0019edac: 0014a8c0 sll r21,r20,0x03r21 = Cancel Status 0019edb0: 34070080 ori r7,r0,0x0080r7 = 0x0080 0019edb4: 02479807 srav r19,r7,r18r19 = 80 >> Current Status (0 - 4) 0019edb8: 02131024 and r2,r16,r19 0019edbc: 1040000d beq r2,r0,0x0019edf4<Next Status> if not Canceling that status 0019edc0: 00000000 nop 0019edc4: 8fa40010 lw r4,0x0010(r29) 0019edc8: 02c02821 addu r5,r22,r0 0019edcc: 02b28821 addu r17,r21,r18 0019edd0: 0c067bc9 jal 0x0019ef2Check if Status Should/Can be Added 0019edd4: 02203021 addu r6,r17,r0Check for [current status] 0019edd8: 10400005 beq r2,r0,0x0019edf0Remove Cancel Status if status can't be removed/isn't there 0019eddc: 02c02021 addu r4,r22,r0 0019ede0: 0c067bec jal 0x0019efb0Check if Charm, Don't Act or Don't Move can be added/removed? before unit acts 0019ede4: 02202821 addu r5,r17,r0 0019ede8: 14400002 bne r2,r0,0x0019edf4<Next Status> if all statuses, but especially Charm/Don't Act/Don't Move can be removed in time 0019edec: 00000000 nop 0019edf0: 02138026 xor r16,r16,r19Remove Cancel Status if status can't be removed/isn't there/Can't be removed in time <Next Status> 0019edf4: 26520001 addiu r18,r18,0x0001 0019edf8: 2a420008 slti r2,r18,0x0008 0019edfc: 1440ffed bne r2,r0,0x0019edb4Go through all statuses 0019ee00: 34070080 ori r7,r0,0x0080 0019ee04: 34020001 ori r2,r0,0x0001
<Cancel Status 1 - 3> 0019ee08: 12820005 beq r20,r2,0x0019ee20<Cancel Status 2> 0019ee0c: 34020002 ori r2,r0,0x0002 0019ee10: 12820014 beq r20,r2,0x0019ee64<Cancel Status 3> 0019ee14: 32020002 andi r2,r16,0x0002 0019ee18: 08067ba0 j 0x0019ee80<Confirm Cancel> (Nothing special for Cancel Status 1) 0019ee1c: 00000000 nop
<Cancel Status 2> <Silence> 0019ee20: 32020008 andi r2,r16,0x0008 0019ee24: 10400007 beq r2,r0,0x0019ee44<Blind> if ability doesn't cancel Silence 0019ee28: 32020020 andi r2,r16,0x0020Check for Blind 0019ee2c: 92e2000c lbu r2,0x000c(r23)Load Silenceable Ability Mod 0019ee30: 00000000 nop 0019ee34: 14400003 bne r2,r0,0x0019ee44 <Blind> if unit has any silenceable abilities 0019ee38: 32020020 andi r2,r16,0x0020Check for Blind 0019ee3c: 3a100008 xori r16,r16,0x0008Remove Silence 0019ee40: 32020020 andi r2,r16,0x0020Check for Blind <Blind> 0019ee44: 1040000e beq r2,r0,0x0019ee80<Confirm Cancel> if not cancel Blind 0019ee48: 00000000 nop 0019ee4c: 92e2000d lbu r2,0x000d(r23) Load Evadable Ability Mod 0019ee50: 00000000 nop 0019ee54: 1440000a bne r2,r0,0x0019ee80 <Confirm Cancel> if unit has any evadeable abilities 0019ee58: 00000000 nop 0019ee5c: 08067ba0 j 0x0019ee80<Confirm Cancel> 0019ee60: 3a100020 xori r16,r16,0x0020Remove Blind
<Cancel Status 3> 0019ee64: 10400006 beq r2,r0,0x0019ee80<Confirm Cancel> if no cancel Frog 0019ee68: 00000000 nop 0019ee6c: 92e20008 lbu r2,0x0008(r23) Load Enemy Flag 0019ee70: 00000000 nop 0019ee74: 10400002 beq r2,r0,0x0019ee80 <Confirm Cancel> if ally 0019ee78: 00000000 nop 0019ee7c: 3a100002 xori r16,r16,0x0002Remove Frog (Don't want to undo frog, now do we?)
<Confirm Cancel> 0019ee80: 1600001b bne r16,r0,0x0019eef0Ability is canceling a status 0019ee84: 34020001 ori r2,r0,0x0001
<Cancel++> 0019ee88: 26940001 addiu r20,r20,0x0001Next Cancel Status block 0019ee8c: 2a820005 slti r2,r20,0x0005 0019ee90: 1440ffb6 bne r2,r0,0x0019ed6cBranch if Cancel Status 5 0019ee94: 03d41021 addu r2,r30,r20 </Cancel Status>
<Affect Stats> 0019ee98: 8fc2000c lw r2,0x000c(r30) load usage flags 0019ee9c: 00000000 nop 0019eea0: 30420008 andi r2,r2,0x0008 0019eea4: 1040000e beq r2,r0,0x0019eee0 <Unequip> if not affecting stats 0019eea8: 34020076 ori r2,r0,0x0076 0019eeac: 87c30002 lh r3,0x0002(r30) load ability ID 0019eeb0: 00000000 nop 0019eeb4: 10620005 beq r3,r2,0x0019eecc Skip RNG if Praise 0019eeb8: 34020092 ori r2,r0,0x0092 0019eebc: 10620003 beq r3,r2,0x0019eecc Skip RNG if Accumulate 0019eec0: 34020096 ori r2,r0,0x0096 0019eec4: 1462000a bne r3,r2,0x0019eef0 Roll the dice on any other stat ability besides Yell 0019eec8: 34020001 ori r2,r0,0x0001 0019eecc: 0c0088c3 jal 0x0002230Random Number Generator 0019eed0: 00000000 nop 0019eed4: 30420001 andi r2,r2,0x0001 0019eed8: 10400005 beq r2,r0,0x0019eef0 Use stat abilities randomly (!) 0019eedc: 34020001 ori r2,r0,0x0001
<Unequip> 0019eee0: 8fc2000c lw r2,0x000c(r30) 0019eee4: 00000000 nop 0019eee8: 30420004 andi r2,r2,0x0004 Check if ability is Unequip 0019eeec: 0002102b sltu r2,r0,r2 Use Ability if true
<If Wall> 0019e804: 8fa40010 lw r4,0x0010(r29) 0019e808: 0c067bc9 jal 0x0019ef2Check if Status Should/Can be Added 0019e80c: 3406001f ori r6,r0,0x001fCheck for Wall 0019e810: 1040000b beq r2,r0,0x0019e840<Elemental Null> if unit doesn't have wall 0019e814: 00000000 nop 0019e818: 8fc2000c lw r2,0x000c(r30) 0019e81c: 00000000 nop 0019e820: 30420020 andi r2,r2,0x0020 0019e824: 104001b2 beq r2,r0,0x0019eef0 Ability doesn't cancel Wall, don't use 0019e828: 00001021 addu r2,r0,r0 0019e82c: 93c2000a lbu r2,0x000a(r30) load status infliction 4 0019e830: 00000000 nop 0019e834: 30420001 andi r2,r2,0x0001 0019e838: 104001ad beq r2,r0,0x0019eef0 Ability doesn't cancel Wall, don't use 0019e83c: 00001021 addu r2,r0,r0
So far, this routine prevents the AI from targeting Enemies with Ally Only spells (and vice versa), targeting itself if the spell can't target caster, targeting units with Reflect if spell is reflectable (there is a bypass option, more on this later), targeting Innocent units if a Faith spell, Petrified units unless the ability cures it, and Jumping units. Don't target enemy units that null/absorb your element or are undead and will absorb your damage. Don't revive units with Reraise. They can even tell when it's too late to revive a unit and their spell won't go off in time. Most of this is expected and surprises no one. What might though is that Wall actually has code here.
This is about what you'd expect: Don't target units with Wall, duh. That is, unless you can cancel the status. It's interesting that Wall was far enough along in development that it has it's own processing in this routine. I wasn't really expecting the AI to know how to handle Wall at all. Wall must have been removed from the game rather late in the game's development then. Maybe they realized that becoming invincible on command for 32 CT and still being able to act was kinda broken even for FFT? Even if you could dispel it?
<Charmed Ally> 0019e90c: 8fa40010 lw r4,0x0010(r29) 0019e910: 0c067bc9 jal 0x0019ef2Check if Status Should/Can be Added 0019e914: 34060022 ori r6,r0,0x0022Check for Charm 0019e918: 10400005 beq r2,r0,0x0019e930Branch if unit doesn't have any Charm 0019e91c: 02c02021 addu r4,r22,r0 0019e920: 0c067bec jal 0x0019efb0Check if Charm, Don't Act or Move can be added before unit acts 0019e924: 34050022 ori r5,r0,0x0022Check for Charm 0019e928: 14400002 bne r2,r0,0x0019e934Branch if it can be removed in time 0019e92c: 34140001 ori r20,r0,0x0001Charm is present 0019e930: 0000a021 addu r20,r0,r0Target has no Charm
0019e934: 8fc2000c lw r2,0x000c(r30) Load AI Flags 0019e938: 00000000 nop 0019e93c: 30420080 andi r2,r2,0x0080 0019e940: 10400015 beq r2,r0,0x0019e998 <Elemental Healing> if not hp affecting ability (Why?) 0019e944: 00000000 nop 0019e948: 93c20000 lbu r2,0x0000(r30) load skillset 0019e94c: 3c018006 lui r1,0x8006 0019e950: 00220821 addu r1,r1,r2 0019e954: 90235cb4 lbu r3,0x5cb4(r1) load action byte 0019e958: 3402000a ori r2,r0,0x000a 0019e95c: 1062000e beq r3,r2,0x0019e998 <Elemental Healing> if Charge 0019e960: 00000000 nop
<Break Confuse> 0019e964: 92c20059 lbu r2,0x0059(r22)Load Current Status 2 0019e968: 00000000 nop 0019e96c: 30420010 andi r2,r2,0x0010 0019e970: 1440015f bne r2,r0,0x0019eef0 Break Confuse 0019e974: 34020001 ori r2,r0,0x0001 <Break Sleep> 0019e978: 8fa40010 lw r4,0x0010(r29) 0019e97c: 02c02821 addu r5,r22,r0 0019e980: 0c067bc9 jal 0x0019ef2Check if Status Should/Can be Added 0019e984: 34060023 ori r6,r0,0x0023Check for Sleep 0019e988: 14400046 bne r2,r0,0x0019eaa4Break Sleep 0019e98c: 00000000 nop <Break Charm> 0019e990: 16800157 bne r20,r0,0x0019eef0Break Charm with this ability 0019e994: 34020001 ori r2,r0,0x0001
<Elemental Healing> 0019e998: 92c2006d lbu r2,0x006d(r22) Elemental absorb 0019e99c: 93c30010 lbu r3,0x0010(r30) load elements 0019e9a0: 00000000 nop 0019e9a4: 00431024 and r2,r2,r3 elements & absorbs 0019e9a8: 10400006 beq r2,r0,0x0019e9c4 <Don't Attack Ally> if unit doesn't absorb this element 0019e9ac: 00000000 nop 0019e9b0: 92e20007 lbu r2,0x0007(r23) AI Decision Flag 0019e9b4: 00000000 nop 0019e9b8: 30420001 andi r2,r2,0x0001 0019e9bc: 1440014c bne r2,r0,0x0019eef0 Heal this unit if they have >50% HP 0019e9c0: 34020001 ori r2,r0,0x0001
<Don't Attack Ally> 0019e9c4: 92c20059 lbu r2,0x0059(r22)Load Current Status 2 0019e9c8: 00000000 nop 0019e9cc: 30420014 andi r2,r2,0x0014 0019e9d0: 14400003 bne r2,r0,0x0019e9e0 <Disable Ally> if confusion or blood suck 0019e9d4: 00000000 nop 0019e9d8: 12800145 beq r20,r0,0x0019eef0No reason to attack an ally then 0019e9dc: 34020002 ori r2,r0,0x0002
This is how the AI is allowed to target it's allies with damage abilities to break Charm/Confuse/Sleep. The AI is finnicky in removing Charm somewhat. It won't remove Charm if it can't get the spell off before the unit acts. It shouldn't matter for Throw Stone, but it might for everything else with a charge.
Speaking of Charge, the AI won't use Charge to break these statuses. Of course that leaves Jump on the table. This can be fixed to check for Charge and Jump, but it requires extra space to do so because of all the load delays. But since Arena doesn't use Charge, you could just have the game check for Jump instead. Then you should have no more Jumping on sleeping units.
There is also Elemental Healing here as well. It works the same way normal healing does (more on that later). What's really odd about it, is that if an ability has an Element, but doesn't deal HP damage, the AI thinks it's blocked by Absorption and won't use it! That is absolutely not the case for any non damage formula, most of which can't even accept/don't check for Elements in their spells, and there are no non damage spells in Vanilla that even have Elements. I actually think this might just be an oversight because it could have just branched to the very next section and it would have been very relevant for it to do so.
Also in theory, the AI, if you made a unit Always: Confused, should constantly attempt to break a unit's Confusion because it doesn't check if it's an innate like it does Sleep and Charm.
How the AI deals with Blood Suck units (and Confusion as well)
<Don't Attack Ally> 0019e9c4: 92c20059 lbu r2,0x0059(r22)Load Current Status 2 0019e9c8: 00000000 nop 0019e9cc: 30420014 andi r2,r2,0x0014 0019e9d0: 14400003 bne r2,r0,0x0019e9e0 <Disable Ally> if confusion or blood suck 0019e9d4: 00000000 nop 0019e9d8: 12800145 beq r20,r0,0x0019eef0No reason to attack an allythen 0019e9dc: 34020002 ori r2,r0,0x0002
<Disable Ally> 0019e9e0: 8fc2000c lw r2,0x000c(r30) 0019e9e4: 00000000 nop 0019e9e8: 30420010 andi r2,r2,0x0010 0019e9ec: 1040ffb9 beq r2,r0,0x0019e8d4 Branch to Exit if no add status; No reason to use this on an ally (Why branch all the way up there?) 0019e9f0: 3c031c06 lui r3,0x1c06 Sleep, Don't Move, Don't Act, Slow and Stop 0019e9f4: 8fc20008 lw r2,0x0008(r30) 0019e9f8: 00000000 nop 0019e9fc: 00431024 and r2,r2,r3 0019ea00: 1440013b bne r2,r0,0x0019eef0 Use only these statuses to deal with Confused/Blood Suck Allies 0019ea04: 34020001 ori r2,r0,0x0001 0019ea08: 08067bbc j 0x0019eef0Don't use any other status 0019ea0c: 34020002 ori r2,r0,0x0002
Another way that the AI deals with Blood Suck and Confused units (besides curing it), is to disable them with statuses. The AI will only use Sleep, Don't Move, Don't Act, Slow and Stop on Blood Suck and Confused units.
I have to disagree with having Confusion here at all. It's easy enough to cure, so a Confused Unit shouldn't be getting disabled by it's own units. Meanwhile, Blood Suck need harsher statuses to be dealt with. I used to just straight up kill Blood Sucked units when I couldn't heal them because it was easier to just remove BS that way and I think the AI should think this as well.
<HP Ability> 0019ea10: 8fc2000c lw r2,0x000c(r30) 0019ea14: 00000000 nop 0019ea18: 30420080 andi r2,r2,0x0080 0019ea1c: 10400006 beq r2,r0,0x0019ea38 <MP Ability> if not HP affecting 0019ea20: 00000000 nop 0019ea24: 92c2005c lbu r2,0x005c(r22)Load Current Status 5 0019ea28: 00000000 nop 0019ea2c: 30420001 andi r2,r2,0x0001 0019ea30: 1040012f beq r2,r0,0x0019eef0 Attack Enemy unless Death Sentence 0019ea34: 34020001 ori r2,r0,0x0001 <MP Ability> 0019ea38: 8fc2000c lw r2,0x000c(r30) 0019ea3c: 00000000 nop 0019ea40: 30420040 andi r2,r2,0x0040 0019ea44: 10400007 beq r2,r0,0x0019ea64 <Target Allies> if not MP affecting 0019ea48: 00000000 nop 0019ea4c: 96c3002c lhu r3,0x002c(r22) Load mp 0019ea50: 92e2000a lbu r2,0x000a(r23) load lowest mp cost 0019ea54: 00000000 nop 0019ea58: 0043102b sltu r2,r2,r3 0019ea5c: 14400124 bne r2,r0,0x0019eef0 This unit has enough MP to cast his lowest MP ability 0019ea60: 34020001 ori r2,r0,0x0001
...
<Allied Ability> 0019eaac: 92c20058 lbu r2,0x0058(r22)Load Current Status 1 0019eab0: 08067aaf j 0x0019eabcJump to check 0019eab4: 30420010 andi r2,r2,0x0010 undead check
0019eab8: 92e20008 lbu r2,0x0008(r23) 0019eabc: 00000000 nop 0019eac0: 1440010b bne r2,r0,0x0019eef0 Don't heal Enemy/Undead Ally 0019eac4: 34020002 ori r2,r0,0x0002 0019eac8: 92c2005c lbu r2,0x005c(r22)Load Current Status 5 0019eacc: 00000000 nop 0019ead0: 30420001 andi r2,r2,0x0001 0019ead4: 10400009 beq r2,r0,0x0019eafc <Heal HP> if not death sentence 0019ead8: 00000000 nop 0019eadc: 8fc3000c lw r3,0x000c(r30)Load AI Flags 0019eae0: 00000000 nop 0019eae4: 30630010 andi r3,r3,0x0010 0019eae8: 10600101 beq r3,r0,0x0019eef0 Don't use this ability because it doesn't add Reraise 0019eaec: 00001021 addu r2,r0,r0 0019eaf0: 93c20009 lbu r2,0x0009(r30)Load Inflicted Status 3 0019eaf4: 08067bbb j 0x0019eeecCheck if Reraise before exiting 0019eaf8: 30420020 andi r2,r2,0x0020
AI will not deal HP damage to Death Sentence. They will also use MP Damage until the unit can't cast anymore spells. This is not a surprise. What might be a surprise is that the AI won't use Ally Spells that don't add Reraise on them either...even if the spell in question would heal Death Sentence.
QuoteBut the AI cures Death Sentence all the time with Refute
That's actually because Refute is not an Ally or an Enemy spell. Ignoring Death Sentence units only applies when the spell in question is either an Ally or Enemy spell. Not being either bypasses this behavior, allowing for curing or attacking.
The AI will only heal HP and MP if the unit is under 50% of their respective stat. This is fine for HP, but it's very noticeable when attempting to heal MP. It's a hard 50% too.
How the AI adds statuses - Adding Blind and Silence
<Current Status 2> <Silence> 0019ec04: 10400007 beq r2,r0,0x0019ec24<Blind> if not Silenced 0019ec08: 32020020 andi r2,r16,0x0020Check for Blind 0019ec0c: 92e2000c lbu r2,0x000c(r23) Load Silenceable Abilities Modifier 0019ec10: 00000000 nop 0019ec14: 14400003 bne r2,r0,0x0019ec24 <Blind> if Target has any Silenceable ability (Silence Modifier) 0019ec18: 32020020 andi r2,r16,0x0020Check for Blind 0019ec1c: 3a100008 xori r16,r16,0x0008Remove Silence because unit doesn't have Silenceable abilities 0019ec20: 32020020 andi r2,r16,0x0020Check for Blind <Blind> 0019ec24: 10400044 beq r2,r0,0x0019ed38<Confirm Status> if not adding Blind 0019ec28: 00000000 nop 0019ec2c: 92e2000d lbu r2,0x000d(r23) load Evadable Abilities Modifier 0019ec30: 00000000 nop 0019ec34: 2c420002 sltiu r2,r2,0x0002 0019ec38: 1040003f beq r2,r0,0x0019ed38 <Confirm Status> if Evade Mod > 1 (Greater than 50% of abilities learned) 0019ec3c: 00000000 nop 0019ec40: 08067b4e j 0x0019ed38<Confirm Status> 0019ec44: 3a100020 xori r16,r16,0x0020Remove Blind because Unit doesn't have enough Evadable abilities
First off, the routine checks if the status in question is already present or the target is immune to it, no surprises there.
The AI will only consider adding Blind and Silence if the respective modifiers are high enough. Recall that the AI keeps track of how many Silenceable and Blindable moves you know and it saves this value as 0-4, with 4 being 100% and 0 being less than 25%.
The AI will not even entertain adding Silence to a unit that has no silenceable statuses learned. Reasonable. However, the AI will not consider adding Blind if you have less than 50% P-Ev skills learned. This includes Attack and Frog Attack. This could probably be lowered to 25%.
How the AI adds statuses - Adding Reraise, Frog and Float
<Current Status 3> <Reraise> 0019ec48: 32020020 andi r2,r16,0x0020 0019ec4c: 10400008 beq r2,r0,0x0019ec70<Frog> if not adding Reraise 0019ec50: 32020002 andi r2,r16,0x0002 0019ec54: 92e20007 lbu r2,0x0007(r23)Load AI Targeting 0019ec58: 00000000 nop 0019ec5c: 30420001 andi r2,r2,0x0001 0019ec60: 14400003 bne r2,r0,0x0019ec70 <Frog> if low hp (>50%) unit 0019ec64: 32020002 andi r2,r16,0x0002Check for Frog 0019ec68: 3a100020 xori r16,r16,0x0020Don't add Reraise if not at 50% HP or less 0019ec6c: 32020002 andi r2,r16,0x0002Check for Frog <Frog> 0019ec70: 10400006 beq r2,r0,0x0019ec8c<Float> if not adding Frog 0019ec74: 00000000 nop 0019ec78: 92e20008 lbu r2,0x0008(r23) load enemy flag 0019ec7c: 00000000 nop 0019ec80: 14400002 bne r2,r0,0x0019ec8c <Float> if enemy 0019ec84: 00000000 nop 0019ec88: 3a100002 xori r16,r16,0x0002Remove Frog (don't turn your allies into frogs I guess) <Float> 0019ec8c: 92e20007 lbu r2,0x0007(r23) 0019ec90: 00000000 nop 0019ec94: 30420080 andi r2,r2,0x0080 0019ec98: 14400027 bne r2,r0,0x0019ed38 <Confirm Status> if critical hp unit 0019ec9c: 00000000 nop 0019eca0: 08067b4e j 0x0019ed38<Confirm Status> 0019eca4: 321000bf andi r16,r16,0x00bfDon't add Float unless critical (lol)
The AI will not add Reraise on a unit unless they are under 50% HP. They also will not try to turn their allies into frogs. Finally, the AI will never use Float on itself unless it's in critical. Yes, you read that correctly. In critical. More on this in the next section.
]How the AI adds statuses - Adding Regen, Protect, Shell, Haste, Slow, and Wall (Part 2) Alternate Title: How to Train Your AI to Preemptively Buff
<Current Status 4> <Regen> 0019eca8: 32020040 andi r2,r16,0x0040 0019ecac: 10400007 beq r2,r0,0x0019eccc<Protect/Shell/Wall> if not adding Regen 0019ecb0: 00000000 nop 0019ecb4: 92e20007 lbu r2,0x0007(r23) 0019ecb8: 00000000 nop 0019ecbc: 30420001 andi r2,r2,0x0001 0019ecc0: 14400002 bne r2,r0,0x0019eccc <Protect/Shell/Wall> if low hp unit 0019ecc4: 00000000 nop 0019ecc8: 3a100040 xori r16,r16,0x0040Remove Regen (Don't add Regen unless at 50% or less HP) <Protect/Shell/Wall> 0019eccc: 92e20007 lbu r2,0x0007(r23) 0019ecd0: 00000000 nop 0019ecd4: 30420080 andi r2,r2,0x0080 0019ecd8: 14400003 bne r2,r0,0x0019ece8 <Haste/Slow> if critical hp unit 0019ecdc: 3202000c andi r2,r16,0x000cCheck for Haste/Slow 0019ece0: 321000ce andi r16,r16,0x00ceRemove Protect/Shell/Wall (Don't add Protect/Shell/Wall unless Critical) 0019ece4: 3202000c andi r2,r16,0x000cCheck for Haste/Slow <Haste/Slow> 0019ece8: 10400013 beq r2,r0,0x0019ed38<Confirm Status> if not adding Haste/Slow 0019ecec: 00000000 nop 0019ecf0: 92c2005b lbu r2,0x005b(r22) Load Current Status 4 0019ecf4: 00000000 nop 0019ecf8: 30420002 andi r2,r2,0x0002 0019ecfc: 14400006 bne r2,r0,0x0019ed18 Branch to remove/not add Haste/Slow if Stop 0019ed00: 00000000 nop 0019ed04: 92c2005c lbu r2,0x005c(r22)Load Current Status 5 0019ed08: 00000000 nop 0019ed0c: 30420010 andi r2,r2,0x0010 0019ed10: 10400009 beq r2,r0,0x0019ed38 <Confirm Status> if not sleep 0019ed14: 00000000 nop 0019ed18: 08067b4e j 0x0019ed38<Confirm Status> 0019ed1c: 321000f3 andi r16,r16,0x00f3Remove Haste/Slow
Here you go. So why won't the AI preemptively buff themselves with any positive statuses besides Haste? Because it's not so much Haste is special or anything, but because Haste is the only positive status that doesn't have a restriction. Yeah don't use Haste/Slow on Stop/Sleeping units, but that's besides the point.
Protect, Shell, (and Wall) will not be used unless the unit in question is in Critical. Why Critical instead of 50% HP like Regen is beyond me but it makes it kinda useless for the AI. It makes sense that these status aren't usable at full HP in Vanilla because you don't have any skill restrictions and the developers probably got pissed at the AI constantly buffing itself instead of fighting.
At the very least, Protect and Shell should be used like Haste. In fact, make it so that the AI will only use Protect/Shell/Haste if they are above 50% HP. That way, they aren't using these statuses when they just got revived.
The AI adds Regen when it's Poisoned. I think why this is, is because the AI isn't adding Regen in it's mind, it's canceling Poison.
Interesting that Wall also got this treatment as well. This means that the developers really played around with Wall long enough to try to curb it's usage.
<Current Status 5> <Faith/Reflect> 0019ed20: 92e20007 lbu r2,0x0007(r23) 0019ed24: 00000000 nop 0019ed28: 30420080 andi r2,r2,0x0080 0019ed2c: 14400002 bne r2,r0,0x0019ed38 <Confirm Status> if critical hp unit 0019ed30: 00000000 nop 0019ed34: 3210007d andi r16,r16,0x007dRemove Faith and Reflect (Don't add Faith/Reflect unless critical)
More usage nerfs to positive statuses. This is why sometimes you see the AI use Faith and Reflect on itself when it's in critical, recalling that Faith and Reflect have slightly positive priorities and are kinda seen as gaining HP. Making the AI add Faith in a smart way is going to require some space to do, but it can be done. Same goes for Reflect. Death Sentence could probably be restricted to use on units with 50% or greater as well.
How the AI Removes Status - Charm, Don't Act and Don't Move
<Cancel Status 4 and 5> 0019eda8: 00009021 addu r18,r0,r0 0019edac: 0014a8c0 sll r21,r20,0x03r21 = Cancel Status 0019edb0: 34070080 ori r7,r0,0x0080r7 = 0x0080 0019edb4: 02479807 srav r19,r7,r18r19 = 80 >> Current Status (0 - 4) 0019edb8: 02131024 and r2,r16,r19 0019edbc: 1040000d beq r2,r0,0x0019edf4<Next Status> if not Canceling that status 0019edc0: 00000000 nop 0019edc4: 8fa40010 lw r4,0x0010(r29) 0019edc8: 02c02821 addu r5,r22,r0 0019edcc: 02b28821 addu r17,r21,r18 0019edd0: 0c067bc9 jal 0x0019ef2Check if Status Should/Can be Added 0019edd4: 02203021 addu r6,r17,r0Check for [current status] 0019edd8: 10400005 beq r2,r0,0x0019edf0Remove Cancel Status if status can't be removed/isn't there 0019eddc: 02c02021 addu r4,r22,r0 0019ede0: 0c067bec jal 0x0019efb0Check if Charm, Don't Act or Don't Move can be added/removed? before unit acts 0019ede4: 02202821 addu r5,r17,r0 0019ede8: 14400002 bne r2,r0,0x0019edf4<Next Status> if all statuses, but especially Charm/Don't Act/Don't Move can be removed in time 0019edec: 00000000 nop 0019edf0: 02138026 xor r16,r16,r19Remove Cancel Status if status can't be removed/isn't there/Can't be removed in time <Next Status> 0019edf4: 26520001 addiu r18,r18,0x0001 0019edf8: 2a420008 slti r2,r18,0x0008 0019edfc: 1440ffed bne r2,r0,0x0019edb4Go through all statuses 0019ee00: 34070080 ori r7,r0,0x0080 0019ee04: 34020001 ori r2,r0,0x0001
The AI checks to see if the unit doesn't have the status or it's innate. No surprises there.
The AI will only remove Charm, Don't Act and Don't Move before a unit's turn. If the Ability CT is too high to do this, then it won't remove them.
How the AI Removes Status - Blind/Silence and Frog
<Cancel Status 3> 0019ee64: 10400006 beq r2,r0,0x0019ee80<Confirm Cancel> if no cancel Frog 0019ee68: 00000000 nop 0019ee6c: 92e20008 lbu r2,0x0008(r23) Load Enemy Flag 0019ee70: 00000000 nop 0019ee74: 10400002 beq r2,r0,0x0019ee80 <Confirm Cancel> if ally 0019ee78: 00000000 nop 0019ee7c: 3a100002 xori r16,r16,0x0002Remove Frog (Don't want to undo frog, now do we?)
The only difference from adding Blind/Silence is that the AI will cure Blind as long as you have any Evadable abilities. Since all units have Attack, that should be all the time, right? Also don't remove Frog from your enemies, k thanks.
<Affect Stats> 0019ee98: 8fc2000c lw r2,0x000c(r30) load usage flags 0019ee9c: 00000000 nop 0019eea0: 30420008 andi r2,r2,0x0008 0019eea4: 1040000e beq r2,r0,0x0019eee0 <Unequip> if not affecting stats 0019eea8: 34020076 ori r2,r0,0x0076 0019eeac: 87c30002 lh r3,0x0002(r30) load ability ID 0019eeb0: 00000000 nop 0019eeb4: 10620005 beq r3,r2,0x0019eecc Skip RNG if Praise 0019eeb8: 34020092 ori r2,r0,0x0092 0019eebc: 10620003 beq r3,r2,0x0019eecc Skip RNG if Accumulate 0019eec0: 34020096 ori r2,r0,0x0096 0019eec4: 1462000a bne r3,r2,0x0019eef0 Roll the dice on any other stat ability besides Yell 0019eec8: 34020001 ori r2,r0,0x0001 0019eecc: 0c0088c3 jal 0x0002230Random Number Generator 0019eed0: 00000000 nop 0019eed4: 30420001 andi r2,r2,0x0001 0019eed8: 10400005 beq r2,r0,0x0019eef0 Use stat abilities randomly (!) 0019eedc: 34020001 ori r2,r0,0x0001
This is a bit of a shocker. If it's not Praise, Accumulate, or Yell, the AI's gotta roll the dice. This is why the AI doesn't use Stat abilities that much. There's probably a better way of doing this, perhaps only use on <50% HP units? Actually fucking look at their stats?
<Unequip> 0019eee0: 8fc2000c lw r2,0x000c(r30) 0019eee4: 00000000 nop 0019eee8: 30420004 andi r2,r2,0x0004 Check if ability is Unequip 0019eeec: 0002102b sltu r2,r0,r2 Use Ability if true
Okay then.
So there you guys have it. This routine doesn't so much tell the AI what to select, so much as it tells the AI what not to select. There is some for improvement, so go ahead and leave some thoughts on how to improve this routine.
Title: Re: How the AI Works - An ongoing project researching the AI's code
Post by: Eternal on January 21, 2017, 08:07:03 am
Great work as always. This topic is really fascinating. Thoughts on Float though: I know I've seen it use Float outside of Critical after seeing an Earth spell. Heck, I think I've seen it used before an Earth spell was used, but the AI still "saw" it in the party's skillset.
Title: Re: How the AI Works - An ongoing project researching the AI's code
Post by: Dokurider on January 21, 2017, 12:26:50 pm
Quote from: Eternal on January 21, 2017, 08:07:03 am Great work as always. This topic is really fascinating. Thoughts on Float though: I know I've seen it use Float outside of Critical after seeing an Earth spell. Heck, I think I've seen it used before an Earth spell was used, but the AI still "saw" it in the party's skillset.
You're certainly right. I'm positive there's an auxiliary usage routine that enables usage to mitigate spells/the midcharge behavior. Adding Reflect, Innocent, interrupting a unit's spell, all very well documented behaviors. I'll certainly keep an eye out for them.
EDIT: Oh wait, duh, it's right there in my face. I'll explain in a minute, I forgot to talk about the Reflect Bypass anyways.
Title: Re: How the AI Works - An ongoing project researching the AI's code
Post by: Dokurider on January 21, 2017, 01:28:58 pm
<Reflect Check> 0019e6cc: 10a0000b beq r5,r0,0x0019e6fcBypass Reflect Check <Faith Check> 0019e6d0: 00000000 nop 0019e6d4: 8fc2000c lw r2,0x000c(r30)Load Usage 0019e6d8: 00000000 nop 0019e6dc: 30424000 andi r2,r2,0x4000 0019e6e0: 10400006 beq r2,r0,0x0019e6fc <Faith Check> if not reflectable 0019e6e4: 02c02821 addu r5,r22,r0Get Unit Data Pointer 0019e6e8: 8fa40010 lw r4,0x0010(r29)Get Clockticks 0019e6ec: 0c067bc9 jal 0x0019ef24Check if Status Should/Can be Added 0019e6f0: 34060026 ori r6,r0,0x0026Check for Reflect 0019e6f4: 144001fe bne r2,r0,0x0019eef0Unit has Reflect, don't use 0019e6f8: 00001021 addu r2,r0,r0
I forgot to finish talking about this.
Apparently, the AI sets if it wants to bypass targeting Reflect units with Reflect or not. So why the hell would it try to target Reflectunits with a Reflectable spell? To use that unit to bounce Reflect off of course. This is merely the start of how the AI banks spells off of Reflect units.
<Faith Check> 0019e6fc: 8fc2000c lw r2,0x000c(r30)Load Usage 0019e700: 00000000 nop 0019e704: 30420400 andi r2,r2,0x0400 0019e708: 10400006 beq r2,r0,0x0019e724 <Jump Check> if not faith ability 0019e70c: 02c02821 addu r5,r22,r0 0019e710: 8fa40010 lw r4,0x0010(r29) 0019e714: 0c067bc9 jal 0x0019ef2Check if Status Should/Can be Added 0019e718: 34060021 ori r6,r0,0x0021Check for Innocent 0019e71c: 144001f4 bne r2,r0,0x0019eef0Unit has Innocent, don't use 0019e720: 00001021 addu r2,r0,r0
<Jump Check> 0019e724: 8fa40010 lw r4,0x0010(r29) 0019e728: 02c02821 addu r5,r22,r0 0019e72c: 0c067bc9 jal 0x0019ef2Check if Status Should/Can be Added 0019e730: 34060005 ori r6,r0,0x0005Check for Jump 0019e734: 144001ee bne r2,r0,0x0019eef0Unit is Jumping, don't use 0019e738: 00001021 addu r2,r0,r0
<If Wall> 0019e804: 8fa40010 lw r4,0x0010(r29) 0019e808: 0c067bc9 jal 0x0019ef2Check if Status Should/Can be Added 0019e80c: 3406001f ori r6,r0,0x001fCheck for Wall 0019e810: 1040000b beq r2,r0,0x0019e840<Elemental Null> if unit doesn't have wall 0019e814: 00000000 nop 0019e818: 8fc2000c lw r2,0x000c(r30) 0019e81c: 00000000 nop 0019e820: 30420020 andi r2,r2,0x0020 0019e824: 104001b2 beq r2,r0,0x0019eef0 Ability doesn't cancel Wall, don't use 0019e828: 00001021 addu r2,r0,r0 0019e82c: 93c2000a lbu r2,0x000a(r30) load status infliction 4 0019e830: 00000000 nop 0019e834: 30420001 andi r2,r2,0x0001 0019e838: 104001ad beq r2,r0,0x0019eef0 Ability doesn't cancel Wall, don't use 0019e83c: 00001021 addu r2,r0,r0
<Float> 0019e864: 16820008 bne r20,r2,0x0019e888Skip Float Evaluation if not Earth Elemental 0019e868: 00000000 nop 0019e86c: 92c2005a lbu r2,0x005a(r22)Load Current Status 3 0019e870: 00000000 nop 0019e874: 30420040 andi r2,r2,0x0040 0019e878: 10400003 beq r2,r0,0x0019e888 <Undead Reverse> if not float 0019e87c: 00000000 nop 0019e880: 08067bbc j 0x0019eef0Unit has float, don't use ability 0019e884: 00001021 addu r2,r0,r0
So how does the AI attempt to mitigate spells? If the unit can't midcharge the spell directly, it will then ask this question: "Hypothetically, if I had Innocent, Reflect, Jump, Wall or Float, would this ability I have null the spell being targeted on me?" And if this routine returns 0, "Yes, it will mitigate the spell." then it enables usage. It's a theory I have however. I have to actually see if the governing routines do this, but I think it's pretty likely it does.
Title: Re: How the AI Works - An ongoing project researching the AI's code
Post by: Raijinili on March 21, 2017, 04:52:40 pm
I wanted to work on externalizing the AI, when I came across this topic. "Externalizing" meaning, when a character on a particular team is to take a turn, the emulator pauses, calls an external script (one per team) to decide what to do, writes the choices into memory, jumps to the FFT code, and resumes. The eventual goal is to have custom AI tournaments.
I ignore the problem of finding an emulator that can do this, and want to figure out: - Where to stop. (Entry point of turn-decider.) - What data to expose to the script. - Where to write to. - Where to resume. (Exit point of decider.)
I know you're looking into the part of the code that I want to bypass, but did you happen to stumble upon anything that would help me?
(For complete automation, there needs to be a hack to make "Crystal" automatically pick "Heal HP/MP", but I'm also ignoring that for now.)
Title: Re: How the AI Works - An ongoing project researching the AI's code
Post by: Gaignun on March 22, 2017, 10:11:11 pm
I think that would be very interesting, and also educational.
For accessibility, it might be best to have the scripts written in a custom, higher level language, then have them parsed and compiled into ASM. If the scripts must be written in ASM, then I do not believe there will be enough people that know ASM (and can write the scripts without bugs) to even run a tournament.
Title: Re: How the AI Works - An ongoing project researching the AI's code
Post by: Dokurider on March 23, 2017, 06:44:40 pm
Oops sorry about the delayed response, Raijinili.
Unfortunately, the complete work flow of the AI is still somewhat of a mystery to me. I've been focusing more on individual decision mechanics rather than the overall flow. It's something I'll get to eventually, but right now, I wouldn't know exactly where the AI decision hierarchy begins in earnest, and where a good entry would need to go. If you come to the arena discord or PM me though, I could give you a more detailed run down of what I do currently know.
Title: Re: How the AI Works - An ongoing project researching the AI's code
Post by: Raijinili on March 26, 2017, 09:44:57 pm
For accessibility, it might be best to have the scripts written in a custom, higher level language, then have them parsed and compiled into ASM. If the scripts must be written in ASM, then I do not believe there will be enough people that know ASM (and can write the scripts without bugs) to even run a tournament.
Edit: To keep this from distracting too much away from Dokurider's work, I made a new topic. http://ffhacktics.com/smf/index.php?topic=11674.0
Title: Re: How the AI Works - An ongoing project researching the AI's code
Post by: Dokurider on April 30, 2017, 11:10:05 pm
In case you guys still want to follow my progress into the AI's workings, I post my hacks on my hacking topic in the hacking section on a hacking website. (http://ffhacktics.com/smf/index.php?topic=10381.msg220335#msg220335) I'm pretty close to have something big to post here, but not being able to record anymore is kind of a bummer.
Title: Re: How the AI Works - An ongoing project researching the AI's code
Post by: Dokurider on May 09, 2017, 07:01:54 pm
Okay kids, huddle 'round. You have another lecture to listen to.
The AI's idea of normal movement is to move as close to a target unit as close as possible or to move away from the enemy team as much as possible. To accomplish this, it gives each panel three metrics to determine the best panel to move to.
(19f778) is the Distance from Target or Target Distance. This is the most straight forward of the Movement Metrics. It's simply how far away is this panel away from the target, with 0 being the panel that the target unit is standing on.
(19f9b8) is the Panel Priority. This is usually the Priority Value gained from just merely stopping on a panel. This is usually the "Do Nothing" value and is usually the same value for all panels in movement range. This should only change if moving onto a panel that has a spell being charged on it. The AI does not see traps. This value can be ignored for the most part.
(19f538) is the Distance from all Enemy Units or Enemy Distance. This metric basically boils down to, "Which panel is the most isolated, most farthest away, from all non-disabled enemies?" Every panel in movement range takes every single enemy within 10 range, gets how far away it is, subtracts the range from 10, then totals it into it's correlating space. What all this means is that the AI will move away from as many enemies as possible within 10 distance.
Furthermore, the AI has two main movement routines. (19693c) is the main movement routine aka the Post Action Movement Routine. It relies on the metrics described above to find the best panel to move to. The Post Action Movement Routine is usually tasked to flee from the enemy team, rather than to advance onto it's target. This is very notable when the AI is in Critical. Instead of running towards a healing teammate, it runs away from the enemy team, often isolating itself from any kind of support.
(19af18) contains several subroutines responsible for Pre-Action Movement, among many other important routines. It contains the movement routines responsible for positioning the AI to make an attack. It ranges from simply moving as close as possible, to advancing positioning for restricted and special ranges and AoEs like Linear and Direct. In addition, this routine ends up changing what target the AI will attack, usually because of Priority.
In vanilla, many of the AI's movement routines are told to emphasize Enemy Distance over Target Distance, meaning they frequently run away. And they will always run away unless they are in Pre-Action.
In addition, the Post-Action Movement routine processes tiles in a different way than the other movement routines. In particular, Post-Action Movement does not kick out equal results, meaning it ends up saving the Last Panel Processed. Meanwhile, the Pre-Action routine does kick out equal results, meaning it ends up saving the First Panel Processed.
What this ends up doing is that the AI will constantly move back and forth between the two different results that the two routines produced. Both panels are equal, but are the first and last panels processed. The AI will attempt to satisfy them both, depending on whether the unit is in Pre or Post Action.
In practice, this behavior is masked by the AI's constant movement, so the AI is rarely in a Post-Action state. It can be seen if the AI is already right besides a disabled enemy. They will constantly move between attacking and moving away as long as the target doesn't move.
These are just about the only factors the AI considers during Movement Decision. Aside from the Cowardly/Critical AI, there is no real self preservation or moderation logic in play besides the CT checking for charging spells and even that gets ignored in certain circumstances in Vanilla. If they can move the entire distance to make a play, they will. They will run right into the heart of the enemy team without even the slightest hesitation. That is the simple reality of Pre-Action Movement. Post-Action Movement is not much better either.
The only reason why the AI doesn't always move as far as it can when it's closing the distance between targets or running away, is that it must also satisfy the other Distance Metric, often using it as a tiebreaker between equal results. So you'll see the AI only move 3 panels instead of 4 panels when running away because it also has orders to stay close to it's healing unit, so it ends up moving slightly closer to it's healing ally while running away.