• Our software update is now concluded. You will need to reset your password to log in. In order to do this, you will have to click "Log in" in the top right corner and then "Forgot your password?".
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

Research: Trainer AI in Firered

knizz

192
Posts
16
Years
  • Seen Oct 28, 2020
Hello.

I found what seems to be the scrips that determine how trainers act during battles. It's a different bytecode than that used for NPCs, or moves, or moveanimations, or overworld effects, etc.

It runs a series of 32 scripts for each move in the moveset, the scripts can add or subtract to a score for this move depending on the circumstances and then quit.
Unlike the npc scripts there aren't serveral variables that you can access by number but only one that you can use freely, and another one that contains the id of the move being considered right now.
In case a command can use either variable as input, there are two variants of it with separate codes.
(In my notes __8 is the free variable and _2 is the move being considered, I'm renaming these however wherever I encounter them in my notes. _8, _16 and _32 refer to the lengths one byte, two bytes, four bytes)
Many of these commands are followed by one byte that specifies if it refers to the attacking pokemon (1) or defending pokemon (0).

The dispatch table is at 083F55A4. Meanings as far as I have figured them out so far are:
Spoiler:

Reminder regarding status1 and status2. The Pokemon Information relevant for a battle is copied from their own data structures into four structures at 02023BE4 (two for player side, two for opponent side). JPAN documented this in this post: http://www.pokecommunity.com/showpost.php?p=7156541&postcount=5 (in the RAM-structures spoiler) and status1 and status2 are part of that structure.

The array of 32 pointers to such scripts is at 081D9BF4.
Code:
081D9BF4:   081D9C74 081DA445  081DBA6F 081DBA8D
081D9C04:   081DBAEF 081DBADF  081DBB16 081DBB3B
081D9C14:   081DBB3C 081DBC91  081DBCED 081DBCED
081D9C24:   081DBCED 081DBCED  081DBCED 081DBCED
081D9C34:   081DBCED 081DBCED  081DBCED 081DBCED
081D9C44:   081DBCED 081DBCED  081DBCED 081DBCED
081D9C54:   081DBCED 081DBCED  081DBCED 081DBCED
081D9C64:   081DBCED 081DBCA8  081DBCD6 081DBCDD

It's worth noting that the entry "081DBCED", that appears multiple times here, doesn't do anything and can be replaced by custom move-rating-scripts.

Here are some lightly documented examples:
Spoiler:

More information can be found in my IDA database.

At this point I need to thank JPAN. Never before have I relied on JPANs research this much.
 
Last edited:

knizz

192
Posts
16
Years
  • Seen Oct 28, 2020
I also made some overview graphics, for people that are also reverse engineering the battle system.

Notes:
A → B (solid) means "A calls B.".
A → B (dashed) means "A causes B to be called.".
A → B (dotted) is like a call (solid), in the sense that after B is done, A continues running, but it is realized through means like function pointers (dashed).

The blue part exists in at least seven variants for different circumstances. And each battle side (player side 1&2, and opponent side 1&2) can use a different set of the blue functions. It's also likely that the blue part is the interface for link battles.

'bs', 'bx', and 'bc' have no special meanings here ('b' is for 'battle'). I just use random letters to group these.


First graphic describes how a move script can start a move animation script.
Spoiler:

The second graphic describes the startup-process of a battle. I omitted the lines from "c1_exec_bc_and_bx" to the other boxes because it got messy, instead I colored the boxes green.
Spoiler:

The third graphic emphasizes that move scripts can be run by different subsystems (by a bc_ callback directly, or through a bs_ callback).
Spoiler:


I omitted the addresses in most places, but you can look up these names in my database. (Or ask me)
 
Last edited:

daniilS

busy trying to do stuff not done yet
409
Posts
10
Years
  • Age 24
  • Seen Jan 29, 2024
I've taken a quick glance at the different trainer ai scripts, and here's a short summary of what they do:
Code:
0	won't use moves that have no or a negative effect
1	will actually create some difference in viability scores based on basic calculations
2	starts understanding things like type effectiveness, damage and fainting
3	with a chance of about 3/10, some status moves will get priority on the first turn (list of move scripts at 081DBAA7)
4	with a chance of about 5/10, move effects in this list will get priority: http://pastebin.com/raw.php?i=TP5gCBHp
5	with a chance of about 4/10, non-damaging moves will get priority
6	if there are other pokes left on the ai's team, with a chance of a bit more than 6/10 it will give priority to non-damaging moves. chance raises to a bit more than 9/10 if the user (possibly also its ally) has baton pass
7	nop
8	ai will start looking at health percentages and decide using moves based on that
9	broken/unfinished, does nothing
10-28	nop
29	roamer; will attempt to flee on the first turn
30	safari
31	unused; will flee on 20% health and lower
 
Last edited:

daniilS

busy trying to do stuff not done yet
409
Posts
10
Years
  • Age 24
  • Seen Jan 29, 2024
double post because this update deserves it

So, know how sometimes even a smart AI will fail to guess/recognise the opponent's ability?
Well, turns out that is a bug. Long story short: ability usage history can be stored for each of the two/four participants in a battle. It is however only stored for the player: the routine won't do anything if you ask it to store it for the opponent. However, there's a problem: the big and scary function ability_something does magic with abilities, and sometimes it needs to receive the battle side as an argument. When it doesn't need that, the argument will be 0. But at the end of the routine, it will save the ability to history if it was used, and there's the problem: 0 means player's side, and the ability gets registered as if it were used by your poke. So, let's say, if the opponent sends out a poke with intimidate, then the AI will think it is actually your poke that has intimidate, until it gets to activate its real ability. This all was fixed in Emerald.

Now, actually fixing this would mean tracking down every time ability_something is called with an empty argument for the battle side, and that's just too much work. Instead, I offer you guys this solution: I have rewritten the routine that stores the used ability into history: if it's asked to store your poke's ability into history, it will check if your poke actually does have that ability, and if it doesn't, then it won't store anything. Just insert the following routine at 0xC71D0:
Code:
.thumb
.equ loc, 0x080C71D0

check:
	ldr r3, battle_data
	mov r2, #0x58
	mul r2, r0
	add r2, r3
	add r2, #0x20
	ldrb r2, [r2]
	cmp r1, r2
	beq store
doublecheck:
	cmp r0, #0x0
	bne end
	mov r0, #0x2
	b check
store:
	ldr r2, b_resources
	ldr r2, [r2]
	ldr r2, [r2, #0x18]
	add r2, #0x20
	strb r1, [r2, r0]
end:
	bx lr

.align 2
battle_data:	.word 0x02023BE4
b_resources:	.word 0x02023FF4
The AI should now properly guess your poke's ability.
 
Last edited:
534
Posts
11
Years
  • Age 26
  • Seen Jul 24, 2023
I've taken a quick glance at the different trainer ai scripts, and here's a short summary of what they do:
Code:
0    won't use ridiculously stupid moves
1    will actually create some difference in viability scores based on basic calculations
2    calculates if the opponent and/or the user will faint because of the move
3    if it's the first turn, then there's a chance a status move will get priority
4    there's a chance moves with cool additional effects will get priority
5    makes the ai like status moves a tad more in some situations. possibly makes the ai more stupid, not sure
6    does magic that may take future into account, including baton pass calculations. seems to generally become smarter
7    nop
8    ai will start looking at health percentages and decide using moves based on that. becomes smart
9    broken/unfinished, does nothing
10-28    nop
29    knizz said it's used for the old man
30    safari
31    roamer

Can I ask if this is the value we would put at the Pokemon AI Value in A-Trainer or is this something else? If it IS something else, where do we put it?
 

daniilS

busy trying to do stuff not done yet
409
Posts
10
Years
  • Age 24
  • Seen Jan 29, 2024
Can I ask if this is the value we would put at the Pokemon AI Value in A-Trainer or is this something else? If it IS something else, where do we put it?

Don't use A-Trainer: it calls the IV value the AI value. The only two editors that get this right are Jambo51's unnamed trainer editor and Kurapika's Trainer Editor in G3T—however, neither of them allows setting the value to its true max. I've asked Kurapika to fix this, so let's wait and see. Otherwise you could just manually change it with a hex editor.
 
199
Posts
12
Years
  • Seen Jul 18, 2016
Don't use A-Trainer: it calls the IV value the AI value. The only two editors that get this right are Jambo51's unnamed trainer editor and Kurapika's Trainer Editor in G3T—however, neither of them allows setting the value to its true max. I've asked Kurapika to fix this, so let's wait and see. Otherwise you could just manually change it with a hex editor.

The AI value in A-Trainer is marked as unknown. Unsure if you knew that but whatever...
Also I was wondering if they were preset strategies and I seem to have mistakenly thought that 7 was the best.

Umm, what does nop mean in a case like this though? Would it just select moves randomly or something?
 

daniilS

busy trying to do stuff not done yet
409
Posts
10
Years
  • Age 24
  • Seen Jan 29, 2024
The AI value in A-Trainer is marked as unknown. Unsure if you knew that but whatever...
Also I was wondering if they were preset strategies and I seem to have mistakenly thought that 7 was the best.

Umm, what does nop mean in a case like this though? Would it just select moves randomly or something?

A NOP literally does nothing. It won't alter the viability scores, so if that's all you select then it's equal to a wild battle. And yes, people had thought 7 was the max, but I'm not sure if they checked more than the first byte or if they checked stuff like the Trainer Tower. And what do you mean by preset strategies?
 
Last edited:
199
Posts
12
Years
  • Seen Jul 18, 2016
A NOP literally does nothing. It won't alter the viability scores, so of that's all you select them it's equal to a wild battle. And yes, people had thought 7 was the max, but I'm not sure if they checked more than the first byte or if they checked stuff like the Trainer Tower. And what do you mean by preset strategies?

By preset I mean that they were made so the AI could use things like baton pass well if the value was set to 06 or would use moves with secondary effects more if set to 04
That probably wasn't the best way to describe it though. :/
 

daniilS

busy trying to do stuff not done yet
409
Posts
10
Years
  • Age 24
  • Seen Jan 29, 2024
The AI value in A-Trainer is marked as unknown. Unsure if you knew that but whatever...

UPDATE:
Turns out A-trainer allows giving that unknown a max value of 0xFFFF, so turns out that's the only program that supports giving trainers a proper AI atm...

Also I've just updated the two posts from last night. The AI scripts' descriptions now contain enough information, and the bugfixroutine should more or less work in double battles.
 
Last edited:
794
Posts
10
Years
I've taken a quick glance at the different trainer ai scripts, and here's a short summary of what they do:
Code:
0    won't use moves that have no or a negative effect
1    will actually create some difference in viability scores based on basic calculations
2    starts understanding things like type effectiveness, damage and fainting
3    with a chance of about 3/10, some tatus moves will get priority on the first turn (list of move scripts at 081DBAA7)
4    with a chance of about 5/10, moves in this list will get priority: http://pastebin.com/raw.php?i=TP5gCBHp
5    with a chance of about 4/10, non-damaging moves will get priority
6    if there are other pokes left on the ai's team, with a chance of a bit more than 6/10 it will give priority to non-damaging moves. chance raises to a bit more than 9/10 if the user (possibly also its ally) has baton pass
[B]7    nop[/B]
A NOP literally does nothing. It won't alter the viability scores, so of that's all you select them it's equal to a wild battle
.....
[/QUOTE]

Are you sure 7 does nothing? I was always giving this value to strong trainers like leaders and they acted smart. Always going for super effectiveness, often setting up + clever baton passing, they were even able to stall(to a certain degree)
 

daniilS

busy trying to do stuff not done yet
409
Posts
10
Years
  • Age 24
  • Seen Jan 29, 2024
Are you sure 7 does nothing? I was always giving this value to strong trainers like leaders and they acted smart. Always going for super effectiveness, often setting up + clever baton passing, they were even able to stall(to a certain degree)

Seems like I forgot to mention on this thread that the AI value is a bitfield. So if you give a trainer an AI value of 7 (which was assumed to be the max), you activate script 0, 1 and 2.
 

Splash

But nothing happened.
658
Posts
14
Years
Seems like I forgot to mention on this thread that the AI value is a bitfield. So if you give a trainer an AI value of 7 (which was assumed to be the max), you activate script 0, 1 and 2.

Okay what I'm understanding here is that if you give a value of 7 in the AI value of any tool, the tool will assume that it is the max? Am I correct?
 

Deokishisu

Mr. Magius
990
Posts
18
Years
Seems like I forgot to mention on this thread that the AI value is a bitfield. So if you give a trainer an AI value of 7 (which was assumed to be the max), you activate script 0, 1 and 2.

Okay, now all of the behavior I've been seeing by messing around with that value makes sense. Thanks for all the awesome work (and knizz too!), especially the fix for Firered up there.
 
Last edited:
794
Posts
10
Years
Seems like I forgot to mention on this thread that the AI value is a bitfield. So if you give a trainer an AI value of 7 (which was assumed to be the max), you activate script 0, 1 and 2.

Sorry to bother you, but could you explain what scripts are activated by values 0 - 6? Or how to check what value activates what scripts?
 

daniilS

busy trying to do stuff not done yet
409
Posts
10
Years
  • Age 24
  • Seen Jan 29, 2024
Okay what I'm understanding here is that if you give a value of 7 in the AI value of any tool, the tool will assume that it is the max? Am I correct?
Use A-Trainer for now: it allows a max value of 16 bits.
Okay, now all of the behavior I've been seeing by messing around with that value makes sense. Thanks for all the awesome work, especially the fix for Firered up there.
You should really be thanking knizz; He is the one who discovered and documented everything, while I just corrected and updated a few things, and used that info to describe what the scripts do.
Sorry to bother you, but could you explain what scripts are activated by values 0 - 6? Or how to check what value activates what scripts?
The AI value is a 32-bit bitfield. Every bit, from the 0th to the 31th, activates one of the scripts.
 

daniilS

busy trying to do stuff not done yet
409
Posts
10
Years
  • Age 24
  • Seen Jan 29, 2024
The routine that determines if the AI will switch is located at 08039C84, with the actual thinking happening at 08039A80. I have no idea how it works.


The routine that determines if the AI will use an item is located at 0803A1F4. It will identify the type of item at 0803A198:
Code:
1	full restore
2	heal hp
3	restore status	
4	increase stat	
5	guard spec		
6	other
(see http://www.pokecommunity.com/showpost.php?p=6745155&postcount=11 for more info on battle items).
Then, it will run checks based on the type of item - 1 (see the jump table at 0803A304). For example, it will use a full restore if the hp of the poke is less than 25% of its max hp.


If anyone wants to analyse those routines further, please do.
 
Back
Top