[FE7] The Official AI Documentation Thread

080190B4 4813 ldr r0,=#0x202E3D8 @I don't know what's here.

It’d be much appreciated if anyone could figure out what the data here is?

(#0x202E3E4 too, but that’s just 0xC past the other location)

I think I found where the game calculates enemy thieves stealing things!

080385C8 6818     ldr     r0,[r3]			@Character of unit being processed
080385CA 6859     ldr     r1,[r3,#0x4]		@Class
080385CC 6A80     ldr     r0,[r0,#0x28]		@Abilities...
080385CE 6A89     ldr     r1,[r1,#0x28]
080385D0 4308     orr     r0,r1
080385D2 2104     mov     r1,#0x4			@Steal
080385D4 4008     and     r0,r1
080385D6 2800     cmp     r0,#0x0
080385D8 D011     beq     #0x80385FE

Maybe I can make enemy thieves that knows how to steal weapons?

@Gryz, I have an experiment for you.
Find the priority of the things an enemy with AI of [0x00, 0x00, 0x00, 0x00] will do. Ignore recovery state, but will they prioritize healing an ally, then using an offensive staff, then stealing, then opening doors/chests, then attacking/charging, or what?

  1. Status staff
  2. Heal an ally
  3. Steal
  4. Attack/charge
  5. Open

Lethal attacks still have lower priority than status/heal/steal.
Units with AI [00,00,00,00] won’t open chests and will only open doors if there are no other possible paths to the enemies.

1 Like

Interesting – I thought that. Just based on the staff code being placed separately. Does it matter whether the status staff or the healing staff is placed first/second in the inventory or is it always the status staff?

Yeah, it looks like the status staff is always chosen over the healing staff.
If the unit has multiple status staves then the bottom staff is used first. But this doesn’t seem to be the case with multiple healing staves since the unit picked Mend over Heal regardless of inventory position (and both staves would have fully healed the target)

Oh, that reminds me, dondon created a topic about status staff AI in FE6
http://serenesforest.net/forums/index.php?showtopic=45514
This info appears to hold true for FE7 as well.

Also, it seems that units need at least 5 hit in order to use a status staff.

Units with AI1 = 0x06 will not use status staves, use healing staves, steal or attack. Open is still allowed.
Units with AI4 = 0x20 will not retreat before using a status staff.

Um, I started to investigate how AI3 is used (while also trying to get better at ASM and debugging…)

Overview:

  • Select an unit in attacker’s range, generate a value I will refer to as TP (target points)
  • Compare TP with highest TP target seen so far - set current unit as highest if TP is greater
  • Repeat until no more units in range
  • Attack unit with highest TP

AI3 = 0x00: first entry - 081D36F4

02 01 01 01 01 01 01 01 0A 0F 00 00 05 00 00 00 00 00 00 00

AI3 = 0x08: second entry - 081D3708

01 02 02 02 00 00 00 00 0A 0F 00 00 05 00 00 00 00 00 00 00

I will refer to these entries as TP Modifiers. From what I can tell, bytes 0-7 get used as multipliers (x0, x1, x2) to various TP bonuses and reductions.


Lethal damage

Lethal damage check
08039018 : cmp r0, #0x0
r0 = HP the defender would have after a successful attack
If damage would be lethal, TP = 0x32 (50) and skip the expected value step


Expected value to TP conversion

Expected value calculation:
08039040 : mul r1, r0
r0 = attacker’s final hit. r1 = attacker’s final damage

switch to ARM mode
r3: TP = expected value / 100
08039050 return back to THUMB mode

Multiply TP by TP_Modifier[0]
Example: If AI3 = 0x00 then TP x 2. If AI3 = 0x08 then TP x 1.

If TP is greater than 0x28 (40) set TP to 0x28


TP bonus if defender’s HP is below 20

At 08039070…
TP bonus = 20 - remaining HP the defender would have after a successful attack
Example: If defender has 30 HP and the attack would do 25 damage, then TP bonus = 15

Multiply bonus by TP_Modifier[1]
Add bonus to TP in r4


There are more functions afterwards with similar structure. Some value gets calculated, the value is multiplied by TP_Modifier[0-7], and then the value is added to or subtracted from TP which gets loaded into r4.

Then at 0803928A…
if (TP <= 0) then TP = expected value conversion from above
else TP = TP x 40

TP gets stored at the address in r6 + 0x08

080386F0 : TP from each target gets compared

3 Likes

This is pretty damned cool. I wonder if there’s ways of adjusting the formula such that certain characters/classes are prioritised over others (Shade/Provoke, anyone?).

Definitely - you’d have to branch to free space to write the target-checking code (or cut out some checks that aren’t necessary), but it wouldn’t be too difficult.

Great work Gryz! This goes into a lot more helpful detail than my rough notes.

Can you also check the priority of mounting a ballista and dismounting a used up ballista? If my guess is right, dismounting the ballista should come after staves, but before steal, and mounting a ballista will have be below attack, only if they can’t reach an enemy this turn. I think. Just from cursory examination of the code and making guesses as to what some things do.

I’ve got a question about movement AI/aggression AI and I’m hoping one of you guys who have tested this more thoroughly will be able to answer or even test it out for me as I’m on borrowed time to meet the deadline for FEE3 and probably won’t make it.

I want to have a chapter set up such that a band of wyvern knights are patrolled the edges of a map. If everything goes accordingly, the wyvern knights will cycle between 0x13-0x16 for movement AI (with adjusted coordinates) such that they move in this cyclic fashion. The boss should ONLY move and attack if three characters are in range, otherwise he will continue to fly around the map. The generic wyverns will simply be set to follow the boss. An AFEV will change the group’s AI such that after the boss’s battle quote they will target anyone.

I’m not sure how to go about this, but I’m certain that it can be done. My current plan is to have this setup for the boss:

AI Byte 1: Do not attack [all player characters except Henrick, Damion, Bronwyn]
AI Byte 2: Turn 1/2 - move to top right corner, Turn 3/4 - move to top left corner, Turn 5/6 - move to bottom left corner (and so on and so forth; using CHAI on a turn event)
AI Byte 3: Recovery of some amount
AI Byte 4: Nothing

However, I want the boss to prioritise attacking Henrick/Damion/Bronwyn over moving to the specified coordinates. Will this set-up do that for me or will the boss move towards those coordinates before attacking?

… sorry I got nothing. I was thinking of throwing together a demo (of the very first custom FE7 AI) of an enemy moving around in a square…

But sorry, we’re just not advanced enough for that first AI yet :frowning: .

All good, @Venno just tested it out for me and it looks like enemies with a Move to Coordinate AI will attack player units before they move to their designated place (hooray!). So it looks like I’m all good.

BTW, it appears that AI2 is more of a “backup” AI, or something, like, it’s done when AI1 doesn’t return something satisfactory. I think. It’s just my gut feeling from looking at routines and making new Ai1s. I could be wrong. But I know for sure it’s not “aggression” and “movement”.

2 Likes

I’m a bein’ flexin’ my hackin’ muscles.

5 Likes

sweeeeeeeeeeet

are you jesus

Jesus Christ: ROM Hacking Superstar!

1 Like

btw, mind adding this to the wiki-post of mega-decumentation?

Pre-ballista:
Staves and steal definitely have higher priority than mount. Units won’t mount ballista if there are no enemies in ballista range. It looks like attack and mount+attack have equal priority. During the targeting process, the unit analyzes in-range enemies with both the ballista and weapons in inventory.

In the ballista:
The unit can use staves but won’t steal. Ballista units normally don’t move, but the ballista can move when using staves.

Post-ballista:
Unit will dismount if there is no more ammo and the unit isn’t going to use a staff. The dismount turn is kind of strange, the unit can either attack without moving or move without attacking. The unit can’t steal until 1 turn after dismounting.

There’s an issue with ballista in the targeting process…
For the expected value calculation at 08039040, the ballista’s might and hit aren’t included in the damage and hit values.

Something else I stumbled across…
08038B9A : TP for ballista targets apparently gets compared here instead of 080386F0

1 Like