First, if a unit is in recovery mode (explained more below), it attempts its recovery action. If not, then primary AI is attempted. If primary AI “succeeds” then the unit makes its action and the turn is over. If primary AI “fails” then secondary AI is executed, which can also succeed or fail. If secondary AI fails, then the unit has the chance to use a Door Key/Lockpick/Antitoxin (explained more below). If none of these can be used, then the unit does nothing. Generally, primary AI involves performing an action such as attack, staff or steal. Secondary AI usually involves only movement. Note there isn’t actually a mechanical thing insuring this, just that IntSys has done it this way.

Action priority: staff -> steal -> attack/ballista
If unit has multiple usable staves, use the staff with the highest weapon rank. If multiple staves share the highest rank, use the staff that is lowest in inventory.

Target needs to meet a minimum hit requirement. The staff-user needs 5+ hit with accuracy being calculated from the staff-user’s start-of-phase position. The initial position is used even if the staff-user must move forward to get the target within staff range. Also, the staff-user will retreat a few spaces if a target is close, so a status staff can be used at 0-4 hit as long as the initial 5+ hit test is passed.

The character furthest down in deployment list who meets the above requirements is targeted.

0x00 and 0x1C:
Units with 0x00 will not move if walls/terrain block path to enemies. They will begin to move once a path becomes available (like a door being opened). Units with 0x1C will move up against walls/terrain when path to enemies is blocked.

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

Move to character AI:
Units with 0x0D-0x11 that have an allied target: move towards target until target is inside range then alternate turns seeking enemies and moving back to target. Units with 0x21/0x22 that have an allied target: move towards target until target is inside range then stay near target if not attacking.

Door Key: Move towards doors and open.
Lockpick(1): Move towards doors/chests and open (requires STEAL ability).
Antitoxin: If poisoned, retreat and cure poison.
If unit has multiple of these items that can be used, priority is given to the lowest in inventory.

Then if AI2 = 0x04 (brigand AI) or 0x05 (thief AI) and none of the above items were used:

Chest Key (1-use): Move towards chests and open.
Lockpick(2): Move towards CHESTS (not doors) and open (requires STEAL ability).
Note: the chapter’s item bans do not apply to the Lockpick here.
Usage priority to the top Lockpick/Chest Key in inventory.
The Chest Key with 5-uses cannot be used by the AI.

Note that there are 2 opportunities to use Lockpicks
Lockpick(1): Can open both doors and chests, but can be blocked by the item ban.
Lockpick(2): Requires brigand/thief AI, can only open chests, and is unaffected by the item ban.

So, a thief carrying a Lockpick in a chapter with Lockpicks disabled = a thief that will only open chests and will ignore all doors.

A thief with Door Key + Chest Key will be absolutely determined to use the Door Key before opening any chests. This is due to the Door Key check always occurring before the Chest Key check.

Why did I say Lockpick AI requires the steal ability?
Class/char ability 0x08 (Lockpick): Determines whether to gray out Lockpick in inventory and if the player units can use it. For AI-controlled units, the game mistakenly checks class/char ability 0x04 (steal) for Lockpick functionality. This means enemy/NPC Assassins cannot use Lockpicks by default. (IntSys plz)

Quicker explanation:
If enemies aren’t using Door Keys at all, check the chapter’s item ban list. If you want attack-in-range enemies to hold/drop Door Keys without using them, you will need to disable Door Keys.

Door Keys with common AI:
Enemies with “aggressive AI” (00/00) should never use Door Keys unless they are put in a locked room away from the player units.
Enemies with “attack-in-range AI” (00/03) will actually leave their positions
and move towards doors if Door Keys aren’t disabled for the chapter.
Enemies with “stand still AI” (03/03) should never use Door Keys regardless of the item settings for chapter.
Enemies with “thief AI” (06/05) and carrying a combo of Door Keys + Chest Keys
will seek to use Door Keys before using Chest Keys.

First, the AI tries to run AI1. If it doesn’t get a command out of that, labelled as a command failing, it tries AI2. If that also fails, the unit does not move. Note that recovery mode and Door Key usage take place before AI1.

The actual routines performed for each command are in a jump table at 0x81D3678

AI Commands are done in order until 030013B0 is a 1.
The loop automatically sets this to a 1, so it’s the routine’s responsibility to change it to a 0 to continue.
Most actions will end execution. Exceptions are noted.

30013B8 is the command currently being processed.

AI Command Format:

[byte][byte][byte][byte][word][void*][void*]

That usually take on the roles of:

[opcode][chance(For some commands)][0xFF][label/goto][word of data][void*(routine in 01, data in 00)][data*(parameter to the routine)]

Opcodes:

0x00 - Conditional Branch based on RAM location. Usually 0203A972
The 0x1 byte tells the mode to operate. The 0x3 byte tells where to GOTO.
The word(at 0x4) tells what it should compare against
00 : if word at 0x04 < memory then branch.
01 : if word at 0x04 <= memory then branch.
02 : if word at 0x04 == memory then branch.
03 : if word at 0x04 >= memory then branch.
04 : if word at 0x04 > memory then branch.
05 : if word at 0x04 != memory then branch.
0x01 - Execute given routine (Might do an AI, might check a condition?)
@param: r0 = &Data
@return: 00 = continue AI execution 01 = execute AI
0x02 - Change AI + Execute (Does not take up the unit's turn, that is)
0x03 - Unconditional GOTO
0x04 - If word2's character is deployed, attack them if they're in range (don't attack anyone else even if they are the only ones in range). If the character is not deployed, attack anyone in range.
0x05 - Attack in range (takes a probability). Fails if it cannot take an action in range.
0x06 - Nop (always fails)
0x07 - Execute action without moving. Fails if it cannot take an action without moving.
0x08 - Does nothing? Not seen in default AI codes?
0x09 - Does nothing? Not seen in default AI codes?
0x0A - Does nothing? Not seen in default AI codes?
0x0B - Does nothing? Not seen in default AI codes?
0x0C - Move towards [Byte 0x1, Byte 0x3]. Takes the action and does not advance the AI-PC until the tile is stepped on.
0x0D - Move towards character in 2nd word if not in range
Used in conjunction with []#define InitiateTalk(charsPointer) "RoutineAI(0x0803A58D, charsPointer)"]
Sets memory to:
0x2 if target is in range (this itself does no action)
0x4 if target is not deployed
0x3 or 0x1 otherwise(?)
If target is in range, seems to indicate the location of the target for a subsequent InitateTalk?
0x0E - Nop (always fails)
0x0F - Does nothing? Not seen in default AI codes?
0x10 - Loot/destroy villages. Doesn't proceed the AI-PC until the unit is unable to loot/destroy anymore.
0x11 - Run away from opponents?
0x12 - Move towards opponents, but not those in *(3rd word). Ignore when blocked
0x13 - Move towards opponents. Move as close as possible when blocked.
0x14 - Does nothing? Not seen in default AI codes?
0x15 - Does nothing? Not seen in default AI codes?
0x16 - Random Movement
0x17 - Escape
0x18 - Move towards and attack walls. If no more exist, turns into AttackInRange? Fails if no more walls and no enemy in range.
0x19 - Attack in range?
0x1A - Lags a lot, then moves randomly?
0x1B - LABEL

Healing AI + Targeting AI - AI Byte 3

Bits 1-3 of AI byte 3 are used for healing AI. Bits 4-8 of AI byte 3 are used for targeting AI.
Add healing and targeting settings together to form third AI byte (AI3 0x09 = Healing 0x01 + Targeting 0x08)

Healing

When a unit’s HP falls below a certain percentage it enters “recovery mode”
Being in recovery mode has these effects:

If a vulnerary or elixir is in inventory, retreat from enemies and use item

Retreat towards an allied healer (only if unit can stay out of enemy range)

Retreat to nearest fort (only if unit can stay out of enemy range)

Recovery Mode thresholds:
0x00 = Enter recovery mode when HP is less than 50%. Exit when HP is 100%
0x01 = Enter recovery mode when HP is less than 30%. Exit when HP is 80% or greater
0x02 = Enter recovery mode when HP is less than 10%. Exit when HP is 50% or greater
0x03 = Enter recovery mode when HP is less than 80%. Exit when HP is 100%
0x04 = Unable to enter recovery mode

Attack using the weapon-target option that results in the highest TP (target points).

For each weapon in inventory (top to bottom)
{
For each unit in range (deployment order)
{
Determine attack position
Calculate TP for weapon-target option
If TP >= highest TP seen so far, set this weapon-target option as highest.
}
}

In event of TP tie, inventory order and deployment order are the tiebreakers. Select weapon-target option with lower weapon in inventory then unit further down in deployment list.

TP Modification Table

TP calculations are modified by the value of the third AI byte. The table is located at 1D36F4.
The table has 32 entries. Here are the first six rows:

TP bonus = 20 - Defender’s remaining HP. Assume all attacks will hit. Set to 0 if result less than 0
Example: If defender has 30 HP and the attack would do 25 damage, then TP bonus = 15
Multiply bonus by TP_Modifier[0x01]

[2] Bonus: Near allied units (08039094)

TP bonus for each allied unit in a 3 space radius around attack position
The attacker will receive a bonus from itself if its pre-attack position is inside the bonus area
1 space away = 3 TP, 2 spaces away = 2 TP, 3 spaces away = 1 TP

1
2 1
1 2 3 2 1
1 2 3 3 2 1
1 2 3 2 1
1 2 1
1

The gap in the outer layer is due to a bug
Multiply bonus by TP_Modifier[0x02]
Cap bonus to 10 TP

TP penalty for attack position being inside range of opponents’ strongest weapons
TP penalty from each foe = (attack power with strongest weapon)/2
Add up penalties from each foe then divide total by 8

Yeah, there seems to be some kind of structure in the RAM at 0x2020140, with each slot being 0x34 bytes. The first byte is the character number of the unit being processed. I’m investigating what the rest are.
(It’s written to at 080A13EC)

This code is run at the start of the enemy phase and before each unit’s move…

EDIT: Wait, no, I think this routine is writing the data the game uses to suspend, as it writes after each battle, phase change, etc… still an interesting find though…

I did some experimenting with FE7 and learned some stuff about second AI byte 0x06 and 0x1C.

Second AI byte = 0x06
Begin to move when an unit enters activation area (attack range calculated with move x 2)
Example: a stationary knight will move when a unit waits in a space that could be attacked if the knight had 8 move instead of 4. Also, unlike 0x03, the enemy will continue moving even if units move out of range.

Second AI byte = 0x1C
In FE7 this AI is assigned to enemies (usually archers/mages) who are isolated from the player units due to walls and closed doors. If the enemy has no units in range, move towards the nearest player unit as much as possible.

In small enclosed areas that can be covered entirely by an enemy’s move, this AI is kind of pointless. But this can have use in larger enclosed areas. It allows the enemy to “follow” player units rather than have range locked to starting/current position.

Yes. But it’s more complicated from that. Based on the code, it seems that each entry in that table(specified by AI 1) is a pointer to a table… with a real routine specified by AI 2. I think.
In other words

Not so complicated. I think I can make it
Edit: Since there is an issue about changing RES into MAG, this patch is made to compensate that (using RES bonus to add STR). If you want the original stat bonus, edit the patch with a hex editor at 0x35 (04) and change it into 00. This patch uses 08D80000, 64 byte.
Download