• Welcome to Final Fantasy Hacktics. Please login or sign up.
 
March 28, 2024, 07:53:23 pm

News:

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


How the AI Works - An ongoing project researching the AI's code

Started by Dokurider, December 28, 2016, 06:59:25 pm

Dokurider

Hey guys, I'm going to spend some time looking into the AI's code. I don't know exactly how far I'll get, but I already have some great results.

Unit Target Priority

Located in: AI End of turn, in between turn, etc. (0019d37c)


AI End of turn, in between turn, etc.


0019d37c: 3c02801a lui r2,0x801a
0019d380: 90420d7b lbu r2,0x0d7b(r2)
0019d384: 27bdffe0 addiu r29,r29,0xffe0
0019d388: afb20018 sw r18,0x0018(r29)
0019d38c: 3c12801a lui r18,0x801a
0019d390: 2652f3c4 addiu r18,r18,0xf3c4
0019d394: afbf001c sw r31,0x001c(r29)
0019d398: afb10014 sw r17,0x0014(r29)
0019d39c: 1040000f beq r2,r0,0x0019d3dc branch if able to act
0019d3a0: afb00010 sw r16,0x0010(r29)

if unable to act

0019d3a4: 3c02801a lui r2,0x801a
0019d3a8: 904202b2 lbu r2,0x02b2(r2) Load ?
0019d3ac: 00000000 nop
0019d3b0: 1040000a beq r2,r0,0x0019d3dc Branch if ? = 0
0019d3b4: 00000000 nop
0019d3b8: 0c0678de jal 0x0019e378 Transfer AI Data to Unit Data
0019d3bc: 34040001 ori r4,r0,0x0001 r4 = 1 (extended transfer)
0019d3c0: 3c03801a lui r3,0x801a
0019d3c4: 906302b2 lbu r3,0x02b2(r3) Load ?
0019d3c8: 34020001 ori r2,r0,0x0001
0019d3cc: 10620062 beq r3,r2,0x0019d558 Branch if ? = 1
0019d3d0: 34020002 ori r2,r0,0x0002
0019d3d4: 106200b7 beq r3,r2,0x0019d6b4 Branch if ? = 2
0019d3d8: 00000000 nop

if able to act

0019d3dc: 0c0076ea jal 0x0001dba8 (Calculate Cycles Passed?)
0019d3e0: 34040001 ori r4,r0,0x0001 r4 = 1
0019d3e4: 284201b9 slti r2,r2,0x01b9
0019d3e8: 14400004 bne r2,r0,0x0019d3fc Branch if Cycles Passed? < 0x1b9
0019d3ec: 00000000 nop
0019d3f0: a2400eee sb r0,0x0eee(r18) Store ? = 0
0019d3f4: 080676d9 j 0x0019db64
0019d3f8: 2402ffff addiu r2,r0,0xffff r2 = -1 (fail)
0019d3fc: 0c067858 jal 0x0019e160 Transfer Unit Data to AI Data
0019d400: 00002021 addu r4,r0,r0 r4 = 0 (Extended transfer)
0019d404: a24019bc sb r0,0x19bc(r18) Store ? = 0
0019d408: 34110014 ori r17,r0,0x0014 Counter = 0x14
0019d40c: 26420014 addiu r2,r18,0x0014 r2 = AI Data Pointer + 0x14
0019d410: a0400e18 sb r0,0x0e18(r2) Store ? = 0
0019d414: 2631ffff addiu r17,r17,0xffff Counter --
0019d418: 0621fffd bgez r17,0x0019d410 Branch if Counter >= 0
0019d41c: 2442ffff addiu r2,r2,0xffff Pointer --
0019d420: 92430014 lbu r3,0x0014(r18) Load ?
0019d424: 340200ff ori r2,r0,0x00ff r2 = FF
0019d428: a6400032 sh r0,0x0032(r18) Store ? = 0
0019d42c: 10600017 beq r3,r0,0x0019d48c Branch if Targeting Flags haven't been set?
0019d430: a2420031 sb r2,0x0031(r18) Store Base Hit%? = 255
0019d434: 9243001d lbu r3,0x001d(r18) Load Skillset
0019d438: 00000000 nop
0019d43c: 10600029 beq r3,r0,0x0019d4e4 Branch if Skillset = 0
0019d440: 34020002 ori r2,r0,0x0002 r2 = 2
0019d444: 1062002a beq r3,r2,0x0019d4f0 Branch if Skillset = Defend
0019d448: 00000000 nop
0019d44c: 2650001c addiu r16,r18,0x001c r16 = Acting Unit's ID Pointer
0019d450: 0c05f0f7 jal 0x0017c3dc Attack Preparation Setup
0019d454: 02002021 addu r4,r16,r0 r4 = Acting Unit's ID Pointer
0019d458: 34030001 ori r3,r0,0x0001
0019d45c: 14430005 bne r2,r3,0x0019d474 Branch if CT = 0
0019d460: 00000000 nop
0019d464: 0c06772f jal 0x0019dcbc              Call AI Ability Processing
0019d468: 02002021 addu r4,r16,r0 r4 = Acting Unit's ID Pointer
0019d46c: 104001b9 beq r2,r0,0x0019db54
0019d470: 00000000 nop
0019d474: 8e4317f8 lw r3,0x17f8(r18) load acting units data
0019d478: 34020001 ori r2,r0,0x0001
0019d47c: 0c0676e0 jal 0x0019db80 0019db80 - 0019dca8
0019d480: a0620188 sb r2,0x0188(r3)
0019d484: 08067538 j 0x0019d4e0
0019d488: 00000000 nop
0019d48c: 0c0676e0 jal 0x0019db80 0019db80 - 0019dca8
0019d490: 00000000 nop
0019d494: 9243001d lbu r3,0x001d(r18)
0019d498: 00000000 nop
0019d49c: 10600011 beq r3,r0,0x0019d4e4
0019d4a0: 34020002 ori r2,r0,0x0002
0019d4a4: 10620012 beq r3,r2,0x0019d4f0
0019d4a8: 00000000 nop
0019d4ac: 2650001c addiu r16,r18,0x001c
0019d4b0: 0c05f0f7 jal 0x0017c3dc
0019d4b4: 02002021 addu r4,r16,r0
0019d4b8: 34030001 ori r3,r0,0x0001
0019d4bc: 14430005 bne r2,r3,0x0019d4d4
0019d4c0: 00000000 nop
0019d4c4: 0c06772f jal 0x0019dcbc 0019dcbc - 0019dd88
0019d4c8: 02002021 addu r4,r16,r0
0019d4cc: 104001a1 beq r2,r0,0x0019db54
0019d4d0: 00000000 nop
0019d4d4: 8e4317f8 lw r3,0x17f8(r18)
0019d4d8: 34020001 ori r2,r0,0x0001
0019d4dc: a0620188 sb r2,0x0188(r3)
0019d4e0: 9243001d lbu r3,0x001d(r18)
0019d4e4: 34020002 ori r2,r0,0x0002
0019d4e8: 14620009 bne r3,r2,0x0019d510
0019d4ec: 00000000 nop
0019d4f0: 92440e2e lbu r4,0x0e2e(r18)
0019d4f4: 0c060f80 jal 0x00183e00                 Another intermediate routine
0019d4f8: 00000000 nop
0019d4fc: 8e4317f8 lw r3,0x17f8(r18)
0019d500: 34020064 ori r2,r0,0x0064
0019d504: a2420031 sb r2,0x0031(r18)
0019d508: 34020001 ori r2,r0,0x0001
0019d50c: a0620188 sb r2,0x0188(r3)
0019d510: 9242001d lbu r2,0x001d(r18)
0019d514: 00000000 nop
0019d518: 14400002 bne r2,r0,0x0019d524
0019d51c: 34020064 ori r2,r0,0x0064
0019d520: a2420031 sb r2,0x0031(r18)
0019d524: 92440e2e lbu r4,0x0e2e(r18)
0019d528: 0c060f1b jal 0x00183c6c                 End of Turn
0019d52c: 00000000 nop
0019d530: 3c028019 lui r2,0x8019
0019d534: 8c42f518 lw r2,-0x0ae8(r2) load in between turn control variable
0019d538: 3c038019 lui r3,0x8019
0019d53c: 8c63f51c lw r3,-0x0ae4(r3) load menu control variable?
0019d540: 3c048019 lui r4,0x8019
0019d544: 8c84f520 lw r4,-0x0ae0(r4) load active units ID?
0019d548: a6400eec sh r0,0x0eec(r18)
0019d54c: ae420ee0 sw r2,0x0ee0(r18)
0019d550: ae430ee4 sw r3,0x0ee4(r18)
0019d554: ae440ee8 sw r4,0x0ee8(r18)

? = 1

0019d558: 0c0076ea jal 0x0001dba8 0001dba8 - 0001dcec
0019d55c: 34040001 ori r4,r0,0x0001
0019d560: 28420139 slti r2,r2,0x0139
0019d564: 1040016c beq r2,r0,0x0019db18 Exit if
0019d568: 00000000 nop
0019d56c: 96420eec lhu r2,0x0eec(r18)
0019d570: 00000000 nop
0019d574: 24420001 addiu r2,r2,0x0001
0019d578: a6420eec sh r2,0x0eec(r18)
0019d57c: 96420eec lhu r2,0x0eec(r18)
0019d580: 00000000 nop
0019d584: 2c420100 sltiu r2,r2,0x0100
0019d588: 10400041 beq r2,r0,0x0019d690
0019d58c: 00000000 nop
0019d590: 0c0609fc jal 0x001827f0
0019d594: 00002021 addu r4,r0,r0
0019d598: 00408821 addu r17,r2,r0
0019d59c: 3225ff00 andi r5,r17,0xff00
0019d5a0: 323100ff andi r17,r17,0x00ff
0019d5a4: 001110c0 sll r2,r17,0x03
0019d5a8: 00511023 subu r2,r2,r17
0019d5ac: 00021180 sll r2,r2,0x06
0019d5b0: 3c038019 lui r3,0x8019
0019d5b4: 246308cc addiu r3,r3,0x08cc
0019d5b8: 00438021 addu r16,r2,r3
0019d5bc: 3402ff00 ori r2,r0,0xff00
0019d5c0: 10a20033 beq r5,r2,0x0019d690
0019d5c4: 34020300 ori r2,r0,0x0300
0019d5c8: 14a20005 bne r5,r2,0x0019d5e0
0019d5cc: 34020200 ori r2,r0,0x0200
0019d5d0: 0c062f82 jal 0x0018be08
0019d5d4: 02202021 addu r4,r17,r0
0019d5d8: 08067590 j 0x0019d640
0019d5dc: 00008821 addu r17,r0,r0
0019d5e0: 14a2000d bne r5,r2,0x0019d618
0019d5e4: 34020100 ori r2,r0,0x0100
0019d5e8: 0c06772f jal 0x0019dcbc 0019dcbc - 0019dd88
0019d5ec: 2604016e addiu r4,r16,0x016e
0019d5f0: 1040014f beq r2,r0,0x0019db30
0019d5f4: 340200ff ori r2,r0,0x00ff
0019d5f8: a202015d sb r2,0x015d(r16) store no ability CT
0019d5fc: 92020058 lbu r2,0x0058(r16) load statii
0019d600: 920301bb lbu r3,0x01bb(r16) load status infliction
0019d604: 304200f6 andi r2,r2,0x00f6 remove performing/charging
0019d608: 306300f6 andi r3,r3,0x00f6 remove performing/charging
0019d60c: a2020058 sb r2,0x0058(r16) store new status
0019d610: 0806758f j 0x0019d63c
0019d614: a20301bb sb r3,0x01bb(r16) store new status infliction
0019d618: 14a20008 bne r5,r2,0x0019d63c
0019d61c: 00002021 addu r4,r0,r0
0019d620: 0c067c57 jal 0x0019f15c 0019f15c - 0019f254
0019d624: 02202821 addu r5,r17,r0
0019d628: 10400003 beq r2,r0,0x0019d638
0019d62c: 02511821 addu r3,r18,r17
0019d630: 34020001 ori r2,r0,0x0001
0019d634: a0620e18 sb r2,0x0e18(r3)
0019d638: a2000186 sb r0,0x0186(r16) store turn over
0019d63c: 00008821 addu r17,r0,r0
0019d640: 340400ff ori r4,r0,0x00ff
0019d644: 3c038019 lui r3,0x8019
0019d648: 246308cc addiu r3,r3,0x08cc
0019d64c: 00608021 addu r16,r3,r0
0019d650: 92020001 lbu r2,0x0001(r16) load unit ID
0019d654: 00000000 nop
0019d658: 10440006 beq r2,r4,0x0019d674 branch if doesn't exist
0019d65c: 00000000 nop
0019d660: 92020058 lbu r2,0x0058(r16) load status
0019d664: 00000000 nop
0019d668: 30420009 andi r2,r2,0x0009
0019d66c: 14400006 bne r2,r0,0x0019d688 branch if charging/performing
0019d670: 34020015 ori r2,r0,0x0015
0019d674: 26310001 addiu r17,r17,0x0001
0019d678: 2a220015 slti r2,r17,0x0015
0019d67c: 1440fff3 bne r2,r0,0x0019d64c branch if counter < 0x15
0019d680: 260301c0 addiu r3,r16,0x01c0 next unit
0019d684: 34020015 ori r2,r0,0x0015
0019d688: 1622ffb3 bne r17,r2,0x0019d558 branch if counter != 0x15
0019d68c: 00000000 nop
0019d690: 8e420ee0 lw r2,0x0ee0(r18)
0019d694: 8e430ee4 lw r3,0x0ee4(r18)
0019d698: 8e440ee8 lw r4,0x0ee8(r18)
0019d69c: 3c018019 lui r1,0x8019
0019d6a0: ac22f518 sw r2,-0x0ae8(r1)
0019d6a4: 3c018019 lui r1,0x8019
0019d6a8: ac23f51c sw r3,-0x0ae4(r1)
0019d6ac: 3c018019 lui r1,0x8019
0019d6b0: ac24f520 sw r4,-0x0ae0(r1)

? = 2 (Starting turn?) Unit Priority Routine (The lower, the better)

0019d6b4: 0c0076ea jal 0x0001dba8 Derive 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,0x0019d6d8 Branch if you pleased the Frame RNG gods today
0019d6c4: 3c030100 lui r3,0x0100
0019d6c8: 0c067858 jal 0x0019e160 Transfer Unit Data to AI Data
0019d6cc: 34040001 ori r4,r0,0x0001
0019d6d0: 080676c9 j 0x0019db24 Basically 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,0x0019d808 Skip 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,r5 r4 = 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,0x00f8 remove 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,0x0019d73c branch 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,0x0019d73c branch if reraise
0019d734: 34620001 ori r2,r3,0x0001 add 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,0x0019d760 branch if not petrified
0019d74c: 00000000 nop
0019d750: 90820004 lbu r2,0x0004(r4) load AI settings
0019d754: 00000000 nop
0019d758: 34420002 ori r2,r2,0x0002 add 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,0x0019d784 branch if not jumping
0019d770: 00000000 nop
0019d774: 90820004 lbu r2,0x0004(r4)
0019d778: 00000000 nop
0019d77c: 34420004 ori r2,r2,0x0004 Unit 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,0x0019d7ec Next 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,0x0019d7ec Next 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,0x0019d7d4 branch 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,0x0019d7ec Next 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,0x0019d7ec Next Unit if death-sentenced
0019d7e4: 34620080 ori r2,r3,0x0080 Unit needs to be dealt with flag
0019d7e8: a0820004 sb r2,0x0004(r4) store new flags
0019d7ec: 24c601c0 addiu r6,r6,0x01c0 Unit Data Pointer++
0019d7f0: 26310001 addiu r17,r17,0x0001 Unit Counter++
0019d7f4: 2a220015 slti r2,r17,0x0015
0019d7f8: 1440ffbe bne r2,r0,0x0019d6f4 perform for all units
0019d7fc: 24a50010 addiu r5,r5,0x0010 Unit AI Data++
0019d800: 080676d5 j 0x0019db54
0019d804: 00000000 nop
0019d808: 0c06772b jal 0x0019dcac 0019dcac - 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,r0 r9 = Unit AI
0019d824: 02405021 addu r10,r18,r0 r10 = 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,0x0019daa8 branch if doesn't exist
0019d838: 00002821 addu r5,r0,r0 r5 = Current Status Loop Counter
0019d83c: 3c028019 lui r2,0x8019
0019d840: 244208cc addiu r2,r2,0x08cc
0019d844: 01628021 addu r16,r11,r2 r16 = unit data
0019d848: 01204021 addu r8,r9,r0 r8 = 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,0x07 current HP * 80
0019d85c: 00e2001a div r7,r2 current HP * 80 / maxHP
0019d860: 00003812 mflo r7 r7 = Unit Target Priority Value (curHP% of 0x80)

0019d864: 04a10002 bgez r5,0x0019d870 Branch if this isn't first status loop (the Blank Status)
0019d868: 00a01021 addu r2,r5,r0 r2 = Current Status Loop Counter
0019d86c: 24a20007 addiu r2,r5,0x0007 r2 = 7 (To counteract negative loops??)
0019d870: 000210c3 sra r2,r2,0x03 Status ID / 8
0019d874: 02021821 addu r3,r16,r2 Get 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,r2 r2 = Status ID - {0,10,18,20,28}
0019d884: 00431804 sllv r3,r3,r2 Will always equal 0x80 if Status in question is present
0019d888: 30630080 andi r3,r3,0x0080
0019d88c: 1060003b beq r3,r0,0x0019d97c Next 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,0x0019d8c4 Branch 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,0x0019d8cc branch if not Charmed
0019d8c0: 24a3fff6 addiu r3,r5,0xfff6 Exclude Blank to Invite statuses
0019d8c4: 0481002d bgez r4,0x0019d97c Branch if Status Target Priority is not negative (Blood Suck/Confuse is zero)
0019d8c8: 24a3fff6 addiu r3,r5,0xfff6 Exclude Blank to Invite statuses
0019d8cc: 2c62001c sltiu r2,r3,0x001c
0019d8d0: 10400029 beq r2,r0,0x0019d978 Branch 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,r2 Status Target Value * Evade Mod

Silence
0019d8f8: 91021838 lbu r2,0x1838(r8) Load Silence Blocking Mod
0019d8fc: 00000000 nop
0019d900: 00820018 mult r4,r2 Status Target Value * Silence Mod
0019d904: 00001012 mflo r2
0019d908: 0441001b bgez r2,0x0019d978 Increase Unit Target Priority Value and go to next status
0019d90c: 00022083 sra r4,r2,0x02 Status Target Value / 4
0019d910: 24420003 addiu r2,r2,0x0003 Status Target Value + 3
0019d914: 0806765e j 0x0019d978 Subtract from Target Value and Next Status
0019d918: 00022083 sra r4,r2,0x02 Status 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,0x0019d944 branch if slow/stop
0019d92c: 000417c2 srl r2,r4,0x1f Status 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,0x0019d978 Modify Target Value and next status if not sleep/don't move/act
0019d940: 000417c2 srl r2,r4,0x1f Status Target Value / 0x1f
0019d944: 00821021 addu r2,r4,r2 Status Target Value + {0 if positive, 1 if negative}
0019d948: 0806765e j 0x0019d978
0019d94c: 00022043 sra r4,r2,0x01 Status 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,0x0019d97c Add 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,0x0019d97c Add nothing to Target Priority; next status if charm
0019d974: 00000000 nop

Everything Else:
0019d978: 00e43821 addu r7,r7,r4 Add Status Target Value to Unit Target Priority
0019d97c: 24a50001 addiu r5,r5,0x0001 Next Status
0019d980: 28a20028 slti r2,r5,0x0028
0019d984: 1440ffb7 bne r2,r0,0x0019d864 loop until all statuses are looked for
0019d988: 24c60002 addiu r6,r6,0x0002 Next Status Target Value (Halfword)

0019d98c: 92020006 lbu r2,0x0006(r16) load gender
0019d990: 00000000 nop
0019d994: 30420020 andi r2,r2,0x0020
0019d998: 14400010 bne r2,r0,0x0019d9dc branch if monster
0019d99c: 00000000 nop

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,r13 r6 = unit AI extended status data
0019d9b0: 02051021 addu r2,r16,r5 r2 = unit data
0019d9b4: 00c51821 addu r3,r6,r5 r3 = 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,0x0019d9d0 branch if items are missing (Broken/Stolen)
0019d9c8: 24a50001 addiu r5,r5,0x0001
0019d9cc: 24e70033 addiu r7,r7,0x0033 Unit 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,0x0019d9b4 Look for missing Helmet, Armor, Acc., R Weapon, R Shield, L Weapon and L Shield
0019d9d8: 02051021 addu r2,r16,r5 r2 = next unit data

0019d9dc: 9604002e lhu r4,0x002e(r16) load max MP
0019d9e0: 00000000 nop
0019d9e4: 10800014 beq r4,r0,0x0019da38 branch 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,0x06 CurMP * 40
0019d9fc: 0043102b sltu r2,r2,r3 r2 = curMP < Lowest MP Cost
0019da00: 00c4001a div r6,r4 (CurMP * 40) / Max MP
0019da04: 00003012 mflo r6
0019da08: 10400002 beq r2,r0,0x0019da14 Branch if unit doesn't have enough MP to cast spells.
0019da0c: 00000000 nop
0019da10: 00063042 srl r6,r6,0x01 curMP% / 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 r2 Caster Hate
0019da24: 04410003 bgez r2,0x0019da34 Branch if no spell unit has uses MP
0019da28: 00023083 sra r6,r2,0x02 Caster Hate / 4
0019da2c: 24420003 addiu r2,r2,0x0003 Caster Hate + 3
0019da30: 00023083 sra r6,r2,0x02 Caster Hate + 3 / 4
0019da34: 00e63821 addu r7,r7,r6 Add Caster Hate to Target Priority Value

0019da38: 92020005 lbu r2,0x0005(r16) load ENTD flags
0019da3c: 00000000 nop
0019da40: 000210c2 srl r2,r2,0x03 flags / 8
0019da44: 30420006 andi r2,r2,0x0006 Get 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,0x07 CurGolem * 80
0019da60: 00c3001a div r6,r3 CurGolem * 80 / Average Team HP
0019da64: 00001812 mflo r3 Golem 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,r2 CurGolem <  MaxGolem?
0019da78: 10a00002 beq r5,r0,0x0019da84 -1 to Priority if Golem is undamaged
0019da7c: 00e33821 addu r7,r7,r3 Add Golem Hate to Target Priority Value (Big mistake, has no real value when it's added to everyone)
0019da80: 24e7ffff addiu r7,r7,0xffff Target Priority - 1

0019da84: 91221834 lbu r2,0x1834(r9) Load Enemy Flag
0019da88: 00000000 nop
0019da8c: 10400002 beq r2,r0,0x0019da98 Branch if not Enemy
0019da90: 00000000 nop
0019da94: 00073823 subu r7,r0,r7 Invert Target Priority

0019da98: 96420032 lhu r2,0x0032(r18) Load Current Unit Target Priority Value
0019da9c: 00000000 nop
0019daa0: 00471021 addu r2,r2,r7 Add/Subtract from current Target Priority
0019daa4: a6420032 sh r2,0x0032(r18) Save New Unit Target Priority Value

0019daa8: 25290010 addiu r9,r9,0x0010 Unit AI Data++
0019daac: 254a0001 addiu r10,r10,0x0001 Unit AI++
0019dab0: 26310001 addiu r17,r17,0x0001 Unit++
0019dab4: 2a220015 slti r2,r17,0x0015
0019dab8: 1440ff5c bne r2,r0,0x0019d82c Loop for all units
0019dabc: 256b01c0 addiu r11,r11,0x01c0 Unit 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,0x0019db04 branch 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,0x0019db04 branch if ability = throw shuriken
0019dae8: 34020189 ori r2,r0,0x0189
0019daec: 10620005 beq r3,r2,0x0019db04 branch 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,0x01 base hit/2
0019db00: a2420031 sb r2,0x0031(r18) store new base hit%
0019db04: 0c0678de jal 0x0019e378 Transfer AI Data to Unit Data
0019db08: 00002021 addu r4,r0,r0
0019db0c: a24019b7 sb r0,0x19b7(r18)
0019db10: 080676d9 j 0x0019db64 jump 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 0x0019db64 jump 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 0x0019e378                 Transfer AI Data to Unit Data
0019db58: 00002021 addu r4,r0,r0
0019db5c: a24019b7 sb r0,0x19b7(r18)
0019db60: 00001021 addu r2,r0,r0 return 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 0x0001dba8 Derive 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,0x0019d6d8 Branch if you pleased the Frame RNG gods today
0019d6c4: 3c030100 lui r3,0x0100
0019d6c8: 0c067858 jal 0x0019e160 Transfer Unit Data to AI Data
0019d6cc: 34040001 ori r4,r0,0x0001
0019d6d0: 080676c9 j 0x0019db24 Basically 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,r2 Status Target Value * Evade Mod {0-4}

Silence
0019d8f8: 91021838 lbu r2,0x1838(r8) Load Silence Blocking Mod
0019d8fc: 00000000 nop
0019d900: 00820018 mult r4,r2 Status Target Value * Silence Mod {0-4}
0019d904: 00001012 mflo r2
0019d908: 0441001b bgez r2,0x0019d978 Increase Unit Target Priority Value and go to next status
0019d90c: 00022083 sra r4,r2,0x02 Status Target Value / 4
0019d910: 24420003 addiu r2,r2,0x0003 Status Target Value + 3
0019d914: 0806765e j 0x0019d978 Subtract from Target Value and Next Status
0019d918: 00022083 sra r4,r2,0x02 Status 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,r13 r6 = unit AI extended status data
0019d9b0: 02051021 addu r2,r16,r5 r2 = unit data
0019d9b4: 00c51821 addu r3,r6,r5 r3 = 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,0x0019d9d0 branch if items are missing (Broken/Stolen)
0019d9c8: 24a50001 addiu r5,r5,0x0001
0019d9cc: 24e70033 addiu r7,r7,0x0033 Unit 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,0x0019d9b4 Look for missing Helmet, Armor, Acc., R Weapon, R Shield, L Weapon and L Shield
0019d9d8: 02051021 addu r2,r16,r5 r2 = 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,0x0019da38 branch 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,0x06 CurMP * 40
0019d9fc: 0043102b sltu r2,r2,r3 r2 = curMP < Lowest MP Cost
0019da00: 00c4001a div r6,r4 (CurMP * 40) / Max MP
0019da04: 00003012 mflo r6
0019da08: 10400002 beq r2,r0,0x0019da14 Branch if unit doesn't have enough MP to cast spells.
0019da0c: 00000000 nop
0019da10: 00063042 srl r6,r6,0x01 curMP% / 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 r2 Caster Hate
0019da24: 04410003 bgez r2,0x0019da34 Branch if no spell this unit has uses MP
0019da28: 00023083 sra r6,r2,0x02 Caster Hate / 4
0019da2c: 24420003 addiu r2,r2,0x0003 Caster Hate + 3
0019da30: 00023083 sra r6,r2,0x02 Caster Hate + 3 / 4
0019da34: 00e63821 addu r7,r7,r6 Add 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,0x03 flags / 8
0019da44: 30420006 andi r2,r2,0x0006 Get 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,0x07 CurGolem * 80
0019da60: 00c3001a div r6,r3 CurGolem * 80 / Average Team HP
0019da64: 00001812 mflo r3 Golem 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,r2 CurGolem <  MaxGolem?
0019da78: 10a00002 beq r5,r0,0x0019da84 -1 to Priority if Golem is undamaged
0019da7c: 00e33821 addu r7,r7,r3 Add Golem Hate to Target Priority Value (Big mistake, has no real value when it's added to everyone)
0019da80: 24e7ffff addiu r7,r7,0xffff Target 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.
0x0058: Current Statuses 1
0x80 - 0% (0000)
0x40 - Crystal -150% -c0(ff40)
0x20 - Dead -150% -c0(ff40)
0x10 - Undead -30.5% -27(ffd9)
0x08 - Charging 0% (0000)
0x04 - Jump 0% (0000)
0x02 - Defending 0% (0000)
0x01 - Performing 0% (0000)
0x0059: Current Statuses 2
0x80 - Petrify -90.6% -74(ff8c)
0x40 - Invite -180.4% -e7(ff19)
0x20 - Darkness -50% [-40(ffc0) * Evadable abilities] + 3 / 4
0x10 - Confusion -50% -40(ffc0) (+1 / 4 if slow/stop/sleep/don't move/act/)
0x08 - Silence -70.3% [-5a(ffa6) * Silence abilities] + 3 / 4
0x04 - Blood Suck -90.6% -74(ff8c) (+1 / 4 if slow/stop/sleep/don't move/act/)
0x02 - Cursed 0%(0000)
0x01 - Treasure -150% -c0(ff40)
0x005a: Current Statuses 3
0x80 - Oil -5.5% -7(fff9)
0x40 - Float 9.4% c(000c)
0x20 - Reraise 39.8% 33(0033)
0x10 - Transparent 29.7% 26(0026)
0x08 - Berserk -30.5% -27(ffd9)
0x04 - Chicken -20.3% -1a(ffe6)
0x02 - Frog -40.6% -34(ffcc)
0x01 - Critical -25% -20(ffe0)
0x005b: Current Statuses 4
0x80 - Poison -20.3% -1a(ffe6)
0x40 - Regen 19.5% 19(0019)
0x20 - Protect 19.5% 19(0019)
0x10 - Shell 19.5% 19(0019)
0x08 - Haste 14.8% 13(0013)
0x04 - Slow -30.5% -27(ffd9) 0 if Confusion/Charm/Blood Suck
0x02 - Stop -70.3% -5a(ffa6) 0 if Confusion/Charm/Blood Suck
0x01 - Wall 50% 40(0040)
0x005c: Current Statuses 5
0x80 - Faith 4.7% 6(0006)
0x40 - Innocent -5.5% -7(fff9)
0x20 - Charm -50% -40(ffc0) (+1 / 4 if slow/stop/sleep/don't move/act/)
0x10 - Sleep -30.5% -27(ffd9) 0 if Confusion/Charm/Blood Suck
0x08 - Don't Move -30.5% -27(ffd9) 0 if Confusion/Charm/Blood Suck
0x04 - Don't Act -50% -40(ffc0) 0 if Confusion/Charm/Blood Suck
0x02 - Reflect 19.5% 19(0019)
0x01 - Death Sentence -80.5% -67(ff99)

Eternal

  • Modding version: PSX & WotL
"You, no less human than we? Ha! Now there's a beastly thought. You've been less than we from the moment your baseborn father fell upon your mother in whatever gutter saw you sired! You've been chattel since you came into the world drenched in common blood!"
  • Discord username: eternal248#1817

Dokurider

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.

Dokurider

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

Dokurider

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.


AI Ability Use

r5 = 0 or 1 (bypass reflect)

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,0x0019e660 Branch 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,0x0019e6fc Bypass 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,r0 Get Unit Data Pointer
0019e6e8: 8fa40010 lw r4,0x0010(r29) Get Clockticks
0019e6ec: 0c067bc9 jal 0x0019ef24 Check if Status Should/Can be Added
0019e6f0: 34060026 ori r6,r0,0x0026 Check for Reflect
0019e6f4: 144001fe bne r2,r0,0x0019eef0 Unit 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 0x0019ef2 Check if Status Should/Can be Added
0019e718: 34060021 ori r6,r0,0x0021 Check for Innocent
0019e71c: 144001f4 bne r2,r0,0x0019eef0 Unit 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 0x0019ef2 Check if Status Should/Can be Added
0019e730: 34060005 ori r6,r0,0x0005 Check for Jump
0019e734: 144001ee bne r2,r0,0x0019eef0 Unit 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 0x00199b98 Calculate Clockticks Until Unit Acts
0019e77c: 02c02021 addu r4,r22,r0
0019e780: 0202802a slt r16,r16,r2
0019e784: 1600003e bne r16,r0,0x0019e880 Don't use this ability because unit will get up before then
0019e788: 00000000 nop
0019e78c: 168001d8 bne r20,r0,0x0019eef0 Unit 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 0x00199c88 Get 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,0x0019e880 It's too late to revive this unit (Won't be able to go off in time)
0019e7bc: 00000000 nop
0019e7c0: 128001cb beq r20,r0,0x0019eef0 Ability 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 0x0019ef2 Check if Status Should/Can be Added
0019e80c: 3406001f ori r6,r0,0x001f Check 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,0x0019e880 This unit blocks the element, don't use this ability
0019e860: 34020008 ori r2,r0,0x0008

<Float>
0019e864: 16820008 bne r20,r2,0x0019e888 Skip 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 0x0019eef0 Unit has float, don't use ability
0019e884: 00001021 addu r2,r0,r0

<Target Enemies>
<Undead Reverse>
0019e888: 8fc3000c lw r3,0x000c(r30)
0019e88c: 00000000 nop
0019e890: 30620002 andi r2,r3,0x0002
0019e894: 10400074 beq r2,r0,0x0019ea68            <Target Allies> if not target enemies
0019e898: 30622000 andi r2,r3,0x2000
0019e89c: 1040000f beq r2,r0,0x0019e8dc            <Elemental Absorb> if this ability doesn't reverse on undead
0019e8a0: 00000000 nop
0019e8a4: 92e20008 lbu r2,0x0008(r23)
0019e8a8: 00000000 nop
0019e8ac: 10400004 beq r2,r0,0x0019e8c0            <Healing Undead Ally> if ally
0019e8b0: 00000000 nop
0019e8b4: 92c20058 lbu r2,0x0058(r22) Load Current Status 1
0019e8b8: 08067a3f j 0x0019e8fc
0019e8bc: 30420010 andi r2,r2,0x0010             r2 = undead check

<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 0x0019eef0 Ally 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 0x0019eef0 Don't use this ability because it'll heal them
0019e908: 00000000 nop

<Charmed Ally>
0019e90c: 8fa40010 lw r4,0x0010(r29)
0019e910: 0c067bc9 jal 0x0019ef2 Check if Status Should/Can be Added
0019e914: 34060022 ori r6,r0,0x0022 Check for Charm
0019e918: 10400005 beq r2,r0,0x0019e930 Branch if unit doesn't have any Charm
0019e91c: 02c02021 addu r4,r22,r0
0019e920: 0c067bec jal 0x0019efb0 Check if Charm, Don't Act or Move can be added before unit acts
0019e924: 34050022 ori r5,r0,0x0022 Check for Charm
0019e928: 14400002 bne r2,r0,0x0019e934 Branch if it can be removed in time
0019e92c: 34140001 ori r20,r0,0x0001 Charm is present
0019e930: 0000a021 addu r20,r0,r0 Target 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 0x0019ef2 Check if Status Should/Can be Added
0019e984: 34060023 ori r6,r0,0x0023 Check for Sleep
0019e988: 14400046 bne r2,r0,0x0019eaa4 Break Sleep
0019e98c: 00000000 nop
<Break Charm>
0019e990: 16800157 bne r20,r0,0x0019eef0 Break 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,0x0019eef0 No reason to attack an ally then
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 0x0019eef0 Don'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 0x0019eef0 Heal Undead for damage
0019eaa8: 34020001 ori r2,r0,0x0001

<Allied Ability>
0019eaac: 92c20058 lbu r2,0x0058(r22) Load Current Status 1
0019eab0: 08067aaf j 0x0019eabc Jump 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 0x0019eeec Check 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

<Heal MP>
0019eb24: 8fc2000c lw r2,0x000c(r30)
0019eb28: 00000000 nop
0019eb2c: 30420040 andi r2,r2,0x0040
0019eb30: 10400006 beq r2,r0,0x0019eb4c            <Target Ally and Enemy> if ability doesn't affect MP
0019eb34: 00000000 nop
0019eb38: 92e20007 lbu r2,0x0007(r23)
0019eb3c: 00000000 nop
0019eb40: 30420002 andi r2,r2,0x0002
0019eb44: 144000ea bne r2,r0,0x0019eef0            Heal unit's MP if low mp (less than 50%)
0019eb48: 34020001 ori r2,r0,0x0001

<Target Ally and Enemy>
0019eb4c: 8fc3000c lw r3,0x000c(r30)
0019eb50: 00000000 nop
0019eb54: 30620003 andi r2,r3,0x0003
0019eb58: 14400006 bne r2,r0,0x0019eb74            <Adding Status> if target enemies or target allies
0019eb5c: 30620080 andi r2,r3,0x0080

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,r2 Remove 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,0x0019ec04 Go to <Current Status 2>
0019ebdc: 32020008 andi r2,r16,0x0008 Check 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,0x0020 Check 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,0x0020 Check for Blind
0019ec1c: 3a100008 xori r16,r16,0x0008 Remove Silence because unit doesn't have Silenceable abilities
0019ec20: 32020020 andi r2,r16,0x0020 Check 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,0x0020 Remove 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,0x0002 Check for Frog
0019ec68: 3a100020 xori r16,r16,0x0020 Don't add Reraise if not at 50% HP or less
0019ec6c: 32020002 andi r2,r16,0x0002 Check 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,0x0002 Remove 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,0x00bf Don'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,0x0040 Remove 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,0x000c Check for Haste/Slow
0019ece0: 321000ce andi r16,r16,0x00ce Remove Protect/Shell/Wall (Don't add Protect/Shell/Wall unless Critical)
0019ece4: 3202000c andi r2,r16,0x000c Check 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,0x00f3 Remove 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,0x007d Remove Faith and Reflect (Don't add Faith/Reflect unless critical)

<Confirm Status>
0019ed38: 1600006d bne r16,r0,0x0019eef0 Ability is adding a status
0019ed3c: 34020001 ori r2,r0,0x0001

<Status++>
0019ed40: 26940001 addiu r20,r20,0x0001 Next Status Block
0019ed44: 2a820005 slti r2,r20,0x0005
0019ed48: 1440ff91 bne r2,r0,0x0019eb90 Loop 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,0x03 r21 = Cancel Status
0019edb0: 34070080 ori r7,r0,0x0080 r7 = 0x0080
0019edb4: 02479807 srav r19,r7,r18 r19 = 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 0x0019ef2 Check if Status Should/Can be Added
0019edd4: 02203021 addu r6,r17,r0 Check for [current status]
0019edd8: 10400005 beq r2,r0,0x0019edf0 Remove Cancel Status if status can't be removed/isn't there
0019eddc: 02c02021 addu r4,r22,r0
0019ede0: 0c067bec jal 0x0019efb0 Check 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,r19 Remove 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,0x0019edb4 Go 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,0x0020 Check 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,0x0020 Check for Blind
0019ee3c: 3a100008 xori r16,r16,0x0008 Remove Silence
0019ee40: 32020020 andi r2,r16,0x0020 Check 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,0x0020 Remove 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,0x0002 Remove Frog (Don't want to undo frog, now do we?)

<Confirm Cancel>
0019ee80: 1600001b bne r16,r0,0x0019eef0 Ability is canceling a status
0019ee84: 34020001 ori r2,r0,0x0001

<Cancel++>
0019ee88: 26940001 addiu r20,r20,0x0001 Next Cancel Status block
0019ee8c: 2a820005 slti r2,r20,0x0005
0019ee90: 1440ffb6 bne r2,r0,0x0019ed6c Branch 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 0x0002230 Random 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

<Exit>
0019eef0: 8fbf003c lw r31,0x003c(r29)
0019eef4: 8fbe0038 lw r30,0x0038(r29)
0019eef8: 8fb70034 lw r23,0x0034(r29)
0019eefc: 8fb60030 lw r22,0x0030(r29)
0019ef00: 8fb5002c lw r21,0x002c(r29)
0019ef04: 8fb40028 lw r20,0x0028(r29)
0019ef08: 8fb30024 lw r19,0x0024(r29)
0019ef0c: 8fb20020 lw r18,0x0020(r29)
0019ef10: 8fb1001c lw r17,0x001c(r29)
0019ef14: 8fb00018 lw r16,0x0018(r29)
0019ef18: 27bd0040 addiu r29,r29,0x0040
0019ef1c: 03e00008 jr r31
0019ef20: 00000000 nop



Comments and Observations


How Wall was supposed to be used - Part 1


<If Wall>
0019e804: 8fa40010 lw r4,0x0010(r29)
0019e808: 0c067bc9 jal 0x0019ef2 Check if Status Should/Can be Added
0019e80c: 3406001f ori r6,r0,0x001f Check 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?



How the AI breaks Charm/Confuse/Sleep with damage


<Charmed Ally>
0019e90c: 8fa40010 lw r4,0x0010(r29)
0019e910: 0c067bc9 jal 0x0019ef2 Check if Status Should/Can be Added
0019e914: 34060022 ori r6,r0,0x0022 Check for Charm
0019e918: 10400005 beq r2,r0,0x0019e930 Branch if unit doesn't have any Charm
0019e91c: 02c02021 addu r4,r22,r0
0019e920: 0c067bec jal 0x0019efb0 Check if Charm, Don't Act or Move can be added before unit acts
0019e924: 34050022 ori r5,r0,0x0022 Check for Charm
0019e928: 14400002 bne r2,r0,0x0019e934 Branch if it can be removed in time
0019e92c: 34140001 ori r20,r0,0x0001 Charm is present
0019e930: 0000a021 addu r20,r0,r0 Target 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 0x0019ef2 Check if Status Should/Can be Added
0019e984: 34060023 ori r6,r0,0x0023 Check for Sleep
0019e988: 14400046 bne r2,r0,0x0019eaa4 Break Sleep
0019e98c: 00000000 nop
<Break Charm>
0019e990: 16800157 bne r20,r0,0x0019eef0 Break 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,0x0019eef0 No 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,0x0019eef0 No reason to attack an ally then
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 0x0019eef0 Don'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 and MP Damage and Death Sentence

<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 0x0019eabc Jump 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 0x0019eeec Check 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.



Healing HP and MP

<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

<Heal MP>
0019eb24: 8fc2000c lw r2,0x000c(r30)
0019eb28: 00000000 nop
0019eb2c: 30420040 andi r2,r2,0x0040
0019eb30: 10400006 beq r2,r0,0x0019eb4c            <Target Ally and Enemy> if ability doesn't affect MP
0019eb34: 00000000 nop
0019eb38: 92e20007 lbu r2,0x0007(r23)
0019eb3c: 00000000 nop
0019eb40: 30420002 andi r2,r2,0x0002
0019eb44: 144000ea bne r2,r0,0x0019eef0            Heal unit's MP if low mp (less than 50%)
0019eb48: 34020001 ori r2,r0,0x0001


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,0x0020 Check 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,0x0020 Check for Blind
0019ec1c: 3a100008 xori r16,r16,0x0008 Remove Silence because unit doesn't have Silenceable abilities
0019ec20: 32020020 andi r2,r16,0x0020 Check 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,0x0020 Remove 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,0x0002 Check for Frog
0019ec68: 3a100020 xori r16,r16,0x0020 Don't add Reraise if not at 50% HP or less
0019ec6c: 32020002 andi r2,r16,0x0002 Check 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,0x0002 Remove 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,0x00bf Don'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,0x0040 Remove 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,0x000c Check for Haste/Slow
0019ece0: 321000ce andi r16,r16,0x00ce Remove Protect/Shell/Wall (Don't add Protect/Shell/Wall unless Critical)
0019ece4: 3202000c andi r2,r16,0x000c Check 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,0x00f3 Remove 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.



How the AI adds statuses - Faith and Reflect

<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,0x007d Remove 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,0x03 r21 = Cancel Status
0019edb0: 34070080 ori r7,r0,0x0080 r7 = 0x0080
0019edb4: 02479807 srav r19,r7,r18 r19 = 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 0x0019ef2 Check if Status Should/Can be Added
0019edd4: 02203021 addu r6,r17,r0 Check for [current status]
0019edd8: 10400005 beq r2,r0,0x0019edf0 Remove Cancel Status if status can't be removed/isn't there
0019eddc: 02c02021 addu r4,r22,r0
0019ede0: 0c067bec jal 0x0019efb0 Check 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,r19 Remove 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,0x0019edb4 Go 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 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,0x0020 Check 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,0x0020 Check for Blind
0019ee3c: 3a100008 xori r16,r16,0x0008 Remove Silence
0019ee40: 32020020 andi r2,r16,0x0020 Check 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,0x0020 Remove 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,0x0002 Remove 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.



The AI uses Stat Abilities randomly.


<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 0x0002230 Random 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?



How the AI uses Break/Steal
<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.

Eternal

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.
  • Modding version: PSX & WotL
"You, no less human than we? Ha! Now there's a beastly thought. You've been less than we from the moment your baseborn father fell upon your mother in whatever gutter saw you sired! You've been chattel since you came into the world drenched in common blood!"
  • Discord username: eternal248#1817

Dokurider

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.

Dokurider

Targeting Reflect Units


<Reflect Check>
0019e6cc: 10a0000b beq r5,r0,0x0019e6fc Bypass 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,r0 Get Unit Data Pointer
0019e6e8: 8fa40010 lw r4,0x0010(r29) Get Clockticks
0019e6ec: 0c067bc9 jal 0x0019ef24 Check if Status Should/Can be Added
0019e6f0: 34060026 ori r6,r0,0x0026 Check for Reflect
0019e6f4: 144001fe bne r2,r0,0x0019eef0 Unit 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.



How the AI mitigates Spells

<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 0x0019ef2 Check if Status Should/Can be Added
0019e718: 34060021 ori r6,r0,0x0021 Check for Innocent
0019e71c: 144001f4 bne r2,r0,0x0019eef0 Unit 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 0x0019ef2 Check if Status Should/Can be Added
0019e730: 34060005 ori r6,r0,0x0005 Check for Jump
0019e734: 144001ee bne r2,r0,0x0019eef0 Unit is Jumping, don't use
0019e738: 00001021 addu r2,r0,r0

<If Wall>
0019e804: 8fa40010 lw r4,0x0010(r29)
0019e808: 0c067bc9 jal 0x0019ef2 Check if Status Should/Can be Added
0019e80c: 3406001f ori r6,r0,0x001f Check 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,0x0019e888 Skip 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 0x0019eef0 Unit 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.

Raijinili

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

Gaignun

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.

Dokurider

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.

Raijinili

Oh well.

Quote from: 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.


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

Dokurider

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. I'm pretty close to have something big to post here, but not being able to record anymore is kind of a bummer.

Dokurider

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.

EDIT: 2800 Post GET.