From 5df6f0b753614b1fea516357d4f8c21206d9d91d Mon Sep 17 00:00:00 2001 From: GhoulMage Date: Tue, 29 Oct 2024 20:18:29 +0100 Subject: [PATCH] `AI_FLAG_ACE_POKEMON` takes into account separate trainers (#5608) --- docs/tutorials/ai_flags.md | 4 ++-- include/pokemon.h | 1 + src/battle_ai_switch_items.c | 2 +- src/battle_controller_opponent.c | 6 +++--- src/pokemon.c | 19 +++++++++++++++++++ 5 files changed, 26 insertions(+), 6 deletions(-) diff --git a/docs/tutorials/ai_flags.md b/docs/tutorials/ai_flags.md index fdbfc27fac..7b77305c13 100644 --- a/docs/tutorials/ai_flags.md +++ b/docs/tutorials/ai_flags.md @@ -134,10 +134,10 @@ Affects when the AI chooses to switch. AI will make smarter decisions about when * The current mon loses the 1v1 quickly and has at least ½ HP, or ¼ and Regenerator ## `AI_FLAG_ACE_POKEMON` -Marks the last Pokemon in the party as the Ace Pokemon. It will not be used unless it is the last one remaining, or is forced to be switched in (Roar, U-Turn with 1 mon remaining, etc.) +Marks the last Pokemon in the party as the Ace Pokemon. It will not be used unless it is the last one remaining, or is forced to be switched in (Roar, U-Turn with 1 mon remaining, etc.). If you are challenged by two different trainers at the same time, only the ones with this flag will have Ace Pokémon. For example vs one trainer with `AI_FLAG_ACE_POKEMON`and the other without, there will be a total of 1 Ace Pokémon. ## `AI_FLAG_DOUBLE_ACE_POKEMON` -Marks the last two Pokémon in the party as Ace Pokémon, with the same behaviour as `AI_FLAG_ACE_POKEMON`. Intented for double battles where you battle one trainer id that represents two trainers, ie Twins, Couples. +Marks the last two Pokémon in the party as Ace Pokémon, with the same behaviour as `AI_FLAG_ACE_POKEMON`. Intented for double battles where you battle one trainer id that represents two trainers, ie Twins, Couples. If you apply this flag to trainers outside of double battles or in cases where two trainers can challenge you at the same time, it has the same behaviour. For example vs two trainers with `AI_FLAG_DOUBLE_ACE_POKEMON` there will be a total of 4 Ace Pokémon. ## `AI_FLAG_OMNISCIENT` AI has full knowledge of player moves, abilities, and hold items, and can use this knowledge when making decisions. diff --git a/include/pokemon.h b/include/pokemon.h index 700fad7a1b..8a618f5fe1 100644 --- a/include/pokemon.h +++ b/include/pokemon.h @@ -785,6 +785,7 @@ u8 GiveMonToPlayer(struct Pokemon *mon); u8 CopyMonToPC(struct Pokemon *mon); u8 CalculatePlayerPartyCount(void); u8 CalculateEnemyPartyCount(void); +u8 CalculateEnemyPartyCountInSide(u32 battler); u8 GetMonsStateToDoubles(void); u8 GetMonsStateToDoubles_2(void); u16 GetAbilityBySpecies(u16 species, u8 abilityNum); diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index 06a69e4f60..03f5378a64 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -41,7 +41,7 @@ static bool32 IsAceMon(u32 battler, u32 monPartyId) { if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_ACE_POKEMON && !(gBattleStruct->forcedSwitch & (1u << battler)) - && monPartyId == CalculateEnemyPartyCount()-1) + && monPartyId == CalculateEnemyPartyCountInSide(battler)-1) return TRUE; if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_DOUBLE_ACE_POKEMON && !(gBattleStruct->forcedSwitch & (1u << battler)) diff --git a/src/battle_controller_opponent.c b/src/battle_controller_opponent.c index 4ede13e590..ef12589681 100644 --- a/src/battle_controller_opponent.c +++ b/src/battle_controller_opponent.c @@ -686,11 +686,11 @@ static void OpponentHandleChoosePokemon(u32 battler) || chosenMonId == gBattlerPartyIndexes[battler2]) continue; if ((AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_ACE_POKEMON) - && ((chosenMonId != CalculateEnemyPartyCount() - 1) || CountAIAliveNonEggMonsExcept(PARTY_SIZE) == pokemonInBattle)) + && ((chosenMonId == CalculateEnemyPartyCountInSide(battler) - 1) || CountAIAliveNonEggMonsExcept(PARTY_SIZE) == pokemonInBattle)) continue; if ((AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_DOUBLE_ACE_POKEMON) - && (((chosenMonId != CalculateEnemyPartyCount() - 1) || (chosenMonId != CalculateEnemyPartyCount() - 1)) - || CountAIAliveNonEggMonsExcept(PARTY_SIZE) == pokemonInBattle)) + && (((chosenMonId == CalculateEnemyPartyCountInSide(battler) - 1) || (chosenMonId == CalculateEnemyPartyCountInSide(battler) - 2)) + || (CountAIAliveNonEggMonsExcept(PARTY_SIZE) == pokemonInBattle || CountAIAliveNonEggMonsExcept(PARTY_SIZE-1) == pokemonInBattle))) continue; // mon is valid break; diff --git a/src/pokemon.c b/src/pokemon.c index c8ebdb7fff..9f716e3a79 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -3367,6 +3367,20 @@ u8 CalculatePartyCount(struct Pokemon *party) return partyCount; } +u8 CalculatePartyCountOfSide(u32 battler, struct Pokemon *party) +{ + s32 partyCount, partySize; + GetAIPartyIndexes(battler, &partyCount, &partySize); + + while (partyCount < partySize + && GetMonData(&party[partyCount], MON_DATA_SPECIES, NULL) != SPECIES_NONE) + { + partyCount++; + } + + return partyCount; +} + u8 CalculatePlayerPartyCount(void) { gPlayerPartyCount = CalculatePartyCount(gPlayerParty); @@ -3379,6 +3393,11 @@ u8 CalculateEnemyPartyCount(void) return gEnemyPartyCount; } +u8 CalculateEnemyPartyCountInSide(u32 battler) +{ + return CalculatePartyCountOfSide(battler, gEnemyParty); +} + u8 GetMonsStateToDoubles(void) { s32 aliveCount = 0;