[FE8] The Official AI Documentation Thread

Pointers to AI1 entries: 085A9184
Pointers to AI2 entries: 085A9138

AI1 0x00 through 0x06 are all identical to the FE7 entries.
AI1 0x07 (do not attack Natasha) follows the format for FE7 “do not attack character” entries.

Then umm…
0x08 = Do not attack character 0xFC
0x09 = Do not attack character ??? (points to 00 00 06 00)
0x12 = Do not attack character ??? (points to 00 01 00 01)
0x13 = Do not attack character ??? (points to 00 01 00 00)

These are kind of messed up.
I don’t think it’s a coincidence that in FE7 these entries are for “do not attack character” AI. That reminds me, the 0x09 entry in FE7 is also “do not attack character” with a bad pointer. I guess any AI1 or AI2 that doesn’t get used in FE7/FE8 could be leftover data from an earlier game.

2 Likes

Dang, nice, I didn’t expect that! (er, no offense, Gryz)
Did you use a debugger :D? Welcome to the club.

In this case, no.
I just did a hex editor search on the hunch that the first few entries for AI1 weren’t going to change from FE7.

I have used a debugger before - like in the FE7 AI thread to figure out some of the routines related to AI3 and targeting. I did some debugging stuff before that but not a lot. I’m just really slow and easily frustrated. I actually did try to use a debugger during my search of thief escape points but that was a disaster.

The Summoning AI used by the Demon King:
AI 1 0x14:
At $085A8A7C: 01 00 0F (indicates staff usage and similar)
More importantly, eight bytes later we have two pointers: one to $080411F9 - an AI asm routine - and one to $085A8A70. At this location, we have the following bytes:

05 04 50 00 05 03 0000 ($088D1F54)

$088D1F54 is the ROM location of the unit data of the monsters the Demon King summons. More on this later as I document the routine at $080411F8, but custom summoning AI is not far off!

Here’s some reference on other AI 1 values:

0x07: $5A8A04 (do not attack Natasha)
0x08: $5A8B40 (Do not attack 0xFC)
0x09: $5A8B80 (messed up 'do not attack' pointer)
0x0A: $5A8BA0 (something?)
0x0B: $5A8BA0 (attack enemies in range)
0x0C: $5A8C00 01 00 (some complex thing- two pointers, $0803F019 and $080D8668)
0x0D: $5A8C70 01 00 (as above, but only one pointer to $0803F51D)
0x0E: $5A8F90 01 00 (as 0x0C; ptrs to $0803F791 and $080D8670)
0x0F: $5A8FB0 01 00 (copy of 0x0E)
0x10: $5A8FE0 01 00 ($0803F7DD, $080D8674)
0x11: $5A9040 01 00 ($0803F7DD, $080D8678)
0x12: $5A8A2C 05 64 (do not attack ??? bad formatting)
0x13: $5A8A40 05 64 (like 0x12, bad formatting)

@Arch, wiki my first post in this thread so I can conglomerate all that info into one place!

Is it possible to make so that the AI byte 4 = 0x20 does that, as @Arch suggested?

Do somebody know which is the AI used by brigands/pirates to destroy villages? I tried a few I found in disassembled events but they didn’t work.

[0x00,0x04,0x01,0x00]

I think the second byte being 0x04 is the one that’s supposed to do it along with general thief stuff?

That’s not the case.
I’ve searched for enemy reinforcements data in hex and I found out that the correct AI in FE8 to make pirates/brigands destroy villages is [0x3,0x4,0x9,0x0].
They also “attack in range” and “pursue once the village is destroyed”. They will prioritize the enemies instead of pursuing the villages, if there are any in range.

What exactly is the difference with that AI command compared to the one I gave you? From my experience that command does just what you’ve described. Do the brigands just not pursue after destroying villages? Or do they not destroy them?

I don’t know. I wanted to make sure and used the one that vanilla FE8 uses. Probably, there’s no difference.

This is strange. I should test to see if AI2 0x4 behaves this way in FE7…

Correction: they’ll prioritize the enemies that they can kill, otherwise they’ll just go for the villages instead.

Ok. [0x00, 0x04] should always attack enemies that are in range.

It appears the same as in FE7. This is a conditional check for having a target in Mov/2 range.

If there’s something with a pointer to D8664, that’s checking for within 2*mov range. -6C is mov/2 again.

In FE7, the pattern of the data used were for opening doors/looting.
This also matches up with what 0x10 and 0x11 actually are in FE7 (steal/open locks; and open doors)

Worth mentioning here that the Label opcode in FE8 is 0x1C instead of 0x1B like it is in FE7. Maybe one additional built in AI??

Added a ton of stuff. These have ? by them because they have the same structure as the corresponding entries in FE7, but I haven’t actually confirmed their effects. They look the same though, so I think that’s accurate.

HOW THE AI DETERMINES WHAT TO STEAL

3B7C8:
Initialization: Push r4-r7, r14. Move r0 (RAM char struct pointer of character being looked at) into r7. Move 0xFF to r4 and r5, and move 0x0 to r4. Load the item id of the first item into r0. BL to 3B794.

3B794:
At 5A83A4, there’s an array of item halfwords, arranged in order of descending importance, and terminated with 0xFFFF. This function iterates through the array and compares each value to the item id in question. r0 has a counter of how far into the array the item is, and this number is what is returned. If the item isn’t in the array by the time it reads 0xFFFF (read: not stealable), it moves 0xFFFFFFFF into r0.

Once returned, compare r0 to r6. If (signed) less than, move r0 to r6 (current most valulable item according to that array), and move the inventory slot into r5. Load the next item and repeat the previous steps.

Once all the items have been iterated through, move r5 (slot with most valuable item) to r0 and return (3DC0C is a BL 3B7C8). Get the item id of that slot and bl to 3B794 again to get the “how valuable is this item” number.
Once obtained, load r3 with [sp,#0x14], which has the previous contender of “most valuable item”. Compare r0 and r3; if r0 is (signed) less than, store r0 in the space r3 used to be
Not entirely sure what happens next. Loads 202E4D8, dereferences that, then does a bunch of other stuff. I think one of the pointers has the allegiance byte of the current character being looked at?
After a while, it stores r6 (current most valuable item) into sp,[0x18].

Gist:
Value is determined by location in an array located at 5A83A4. Only item ID is checked, not weapon type. Therefore, you can repoint and expand this to make enemy thieves steal whatever according to a priority table of your making.
If a character has 2 of the same most valuable items, the one in the lowest (lowest meaning closest to bottom, not numerically) slot will be stolen, regardless of uses.
If two characters have the same most valuable item, the one with a lower deployment number will be stolen from, regardless of uses.

1 Like

Unit position will be the tiebreaker in this scenario.

In FE7, many AI routines start at the bottom-right corner then scan rows right-to-left until it reaches the top-left corner. When an item of equal priority is encountered, it becomes the new steal target. So, when 2 units have the same most valuable item, stealing priority goes to the upmost then leftmost unit. I did a quick test in FE8 and this still seems to be the case.

Here’s a general outline of the FE7 steal AI (08038C44):
Examine each map tile. Start at bottom-right corner, stop at top-left corner, read rows right-to-left.
Check conditions for each tile:

  1. Tile is within steal range
  2. Tile contains a unit
  3. Unit cannot be in the same alliance as thief
  4. There is a open, reachable position around unit (where to execute the steal command)
  5. Thief speed >= target speed
  6. Unit has an item from the stealable item table (lower index = higher priority)
  7. Item index in stealable item table <= index of best item seen so far
    If all conditions met, unit/item becomes the new best target
    Repeat until all tiles have been examined
    Write steal command if a valid target was found

Could you repost this into the FE7 thread as well?