[FE7] The Official AI Documentation Thread

Moved to first post

6 Likes

Yeah! This helps a lot. I haven’t seen any unified-all-information-here about the AI bytes like this before.

@Arch can you make that post a wiki post pretty please?

Bada bam. Great stuff here from everybody!

I’ll be cheerleading from the sidelines.

Just quickly, if you follow the pointer trails based on the table that @Crazycolorz5 found, you’ll find the addresses that specify which characters these will be.

0x8B97A0C - character corresponding to 0x12 (Lucius/0x10)
0x8B97A34 - character corresponding to 0x13 (Raven/0x04)

Edit: Just wanted to confirm that changing these bytes does indeed work.

I imagine that there’s similar sorts of things for other AI bytes–might be worth checking out later.

1 Like

Uhm, I myself am confused as to how you got those offsets. Care to explain in a bit more detail?

I followed this to a pointer table, and went to the 0x12th pointer. I followed that pointer to 0x8B97A14, which has 8 bytes of something and then a pointer to 0x8B97A0C, which has the byte 0x10 (Raven) there. I did the same for the 0x13th pointer which ends in the byte 0x04 (Lucius) there, and the same again for the 0x07th pointer which ends up pointing to a byte that has 0x14 (Nino). I suspect that expanding & repointing the table and copying and pasting the relevant bits in the AI might allow us to create our own custom versions of these or, in the very least, have more of them. :smiley:

Update: 0x8B98908 is the corresponding table for the Movement AI bytes :D. Following this, if you head to the 0x0Bth (Farina talks to Hector) pointer it brings you to 0x8B97FDC. If you go along a little further there’s a 0x02 at 0x8B97FE0. Oh, where have we seen this offset before? Right…

3 Likes

Found where the locations are stored for the second AI bytes that make units move to specific locations.
So 0x13 as the second byte of AI should make units move towards 3,13 on the map.
Using the table at 0x8B98908 that @Agro posted for the second AI Bytes, the 13th pointer points to B98724, these are the first 16 bytes at B98724.
01 00 FF 00 00 00 00 00 49 A5 03 08 (1C 87 B9 08)

In the data above in brackets is a pointer leading to B9871C and at that location, if you look at the four bytes prior so at B98718, you see 03 0D 00 00. 03 0D translated from hex = 3,13; which is the location that units with 0x13 as their second AI byte move to. I’ve tested it and changed the 03 0D and the enemy then moves to the new location specified.

So to change the location units with 0x13 as their second AI byte move to, just edit the bytes at B98718.
And so on for the rest, so for 0x14(move to 18,13 on map), the 14th pointer in the table points to B987A0, and the data at that location contains a pointer to B98798 and at that location, four bytes prior so B98794, is 12 0D 00 00 which is the location 18,13. Hopefully that all makes sense. I’m going through now and noting the offsets of the locations so I’ll post those in a bit.

EDIT
actually it seems the locations aren’t all done in the same way. so I haven’t found them all yet. so far though
0x13 - B98718 (3,13)
0x14 - B98794 (18,13)
0x15 - B98810 (10,24)
0x16 - B9888C (8,2)

1 Like

Where/how did you find this?

1 Like

probably just by following pointers and changing random bytes until stuff happened

So theres these ones and I think I’ve got how the others ones work
0x13 - B98718 (3,13) Change 03 0D
0x14 - B98794 (18,13) Change 12 0D
0x15 - B98810 (10,24) Change 0A 18
0x16 - B9888C (8,2) Change 08 02
0x1D - B9869C (15,17) Change 0F 11

For the others. The bytes to edit are just at the offset the entrys in pointer table point to I think. I haven’t tested this yet though, but i think it should be right

Just follow the pointer and edit the bytes at the location
0x17 - B97578 (6,2)
0C 06 FF 02 - Change 06 02
0x19 - B974B8 (6,9)
0C 06 FF 09 - Change 06 09
0x1A - B974F8 (6,5)
0C 06 FF 05 - Change 06 05
0x1E - B97538 (5,2)
0C 05 FF 02 - Change 05 02

1 Like

Oh – I see. There are 0x13 Aggresion AI pointers. then after that a pointer to 08B98908 is written 3 times… then 3 pointers to 08B98994 O.o… what?

… I’m gonna take a closer look at the asm that uses this…

Okay, I want to clear up what I’ve been looking at(mostly because this is still kinda complicated even with annotations) so here goes.

  1. We load 0x8B989F0, which is a pointer to…
  2. We dereference it, getting 0x08B98994
  3. We find the 1stAI-th entry in that pointer table and dereference if.
  4. We take the 1stAIData byte times 0x10 and add that to what we just got.
  5. (some processing, but usually) The first byte there is taken (e.g. for AI = 0x00, 0x00, we get 05)
  6. At the table at 0x81D3678, we use that index and jump to it. (More complicated stuff if the number is >=1B)

Okay, so the tables we get (that are 0x10 bytes long) by following the 1st and 2nd AI bytes look something like this (Annotating as I go)

05 64 FF 00 00 00 00 00 00 00 00 00 00 00 00 00
AI = 0x00, 0x00

The 0th byte is the jump table index to use.
The 1st byte is something chance based, I think – [some routine generates a random multiple of 0x64 and subtracts one.][1] If the chance is unfulfilled then it … branches and does something.
The 2nd byte is written to RAM(at 0x0203A96A), so it might be important?
The 3rd byte is read by 08037890
[1]:https://dl.dropboxusercontent.com/u/92273434/FE%20Hacking%2C%20Public%20Files/AI%20Analysis/08000E30

1 Like

I just went to this address and saw that there was a pointer to 0x8B989F0. I assumed that the pointer to the movement AI table was somewhere nearby and just searched for other pointers (there aren’t many in that area) and followed the pointers through

0x30013B4 - Whether to use 1st AI Byte or 3rd AI Byte(at least, in these calculations). 0x0 = 1st. Any other value = 3rd.
Read and branched upon at 08037894

0x30013B0 - Branched upon at 080378CC…

Aggression AI 0x08 = Do not attack character 0x0A (citizen)

I did some more testing and found there is a difference between the two groups.

After reaching destination, if the unit is lured away from point and later has no enemies in range:
0x13, 0x14, 0x15, 0x16, 0x1D = will move back to target coordinate
0x17, 0x19, 0x1A, 0x1E = will not move back

Yeah, there does seem to be a random factor. An enemy with 0x02 will frequently not move or attack on the enemy phase.

0x00 = 05 64 FF
0x01 = 05 50 FF
0x02 = 05 32 FF
0x03 = 07 64 FF
0x04 = 07 50 FF
0x05 = 07 32 FF

So I guess 0x00 - 0x05 can be defined as:

0x00 = Attack units 100%
0x01 = Attack units 80%, do nothing 20%
0x02 = Attack units 50%, do nothing 50%
0x03 = Attack without moving 100%
0x04 = Attack without moving 80%, do nothing 20%
0x05 = Attack without moving 50%, do nothing 50%

1 Like

Update: Aggression AI 0x12 = Do not attack characters 0x10 (Lucius) and 0x1B (Priscilla)

You can have multiple “do not attack” characters by pointing to a character list like:
1A 00 1B 00 1C 00 00 00 (end list with 00 00)


Aggression AI 0x0A - Only attack character 0x03 (tutorial Lyn)

04 64 FF 00 03 00 00 00 00 00 00 00 00 00 00 00

Change 03 to target character of choice. It seems this AI only allows for 1 character.


Units with “do not attack certain character” AI or “only attack certain character” AI and have 0x00 for second AI byte can still move towards prohibited characters. Units with 0x03 for the second byte will not be triggered by prohibited characters.

2 Likes

Offset please.

Entry 0x0A in the aggression AI table = 0B97ABC. Target character at 0B97AC0


I’m confused by the table[AI1][AI2] thing. If movement AI has its own table, why is AI2 being used as an index in the aggression table?

In the RAM, an enemy with AI [AA,BB,CC,DD] has AI stored like this:
CC DD AA 00 BB 00

The 00 after AI1 and the 00 after AI2 can change values.
For example, an enemy with AI 06,1E,09,00 (move to 05,02)

Turn 1

09 00 06 00 1E 00

Turn 2 (moved closer to 05,02)

09 00 06 01 1E 00

Turn 3 (reached 05,02)

09 00 06 01 1E 01

Turn 4

09 00 06 01 1E 03

Is it possible these values after AI1 and AI2 are being used as the secondary index for the AI tables? Possibly as a way to indicate a state change since several AI change behavior after certain conditions?

Okay, then I was probably confused by the Unit struct. I’ll check bak over my decomentation and clear this up.

What you have is absolutely correct. I just… read off the battle data struct and assumed it was the same, eheh.

– I’m calling the byte after AI1 1stAIData and the byte after AI2 2ndAIData