Fix switch AI considering non-choiced SE moves when choiced (#6892)

This commit is contained in:
Pawkkie 2025-05-23 08:20:36 -04:00 committed by GitHub
parent d3cadf093e
commit 71f1c97d3e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 28 additions and 14 deletions

View File

@ -22,7 +22,7 @@
#include "constants/moves.h"
// this file's functions
static bool32 HasSuperEffectiveMoveAgainstOpponents(u32 battler, bool32 noRng);
static bool32 CanUseSuperEffectiveMoveAgainstOpponents(u32 battler);
static bool32 FindMonWithFlagsAndSuperEffective(u32 battler, u16 flags, u32 moduloPercent);
static bool32 ShouldUseItem(u32 battler);
static bool32 AiExpectsToFaintPlayer(u32 battler);
@ -463,7 +463,7 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler)
return FALSE;
if (gBattleStruct->prevTurnSpecies[battler] != gBattleMons[battler].species && !(gAiThinkingStruct->aiFlags[battler] & AI_FLAG_PREDICT_MOVE)) // AI mon has changed, player's behaviour no longer reliable; override this if using AI_FLAG_PREDICT_MOVE
return FALSE;
if (HasSuperEffectiveMoveAgainstOpponents(battler, TRUE) && (RandomPercentage(RNG_AI_SWITCH_ABSORBING_STAY_IN, STAY_IN_ABSORBING_PERCENTAGE) || gAiLogicData->aiPredictionInProgress))
if (CanUseSuperEffectiveMoveAgainstOpponents(battler) && (RandomPercentage(RNG_AI_SWITCH_ABSORBING_STAY_IN, STAY_IN_ABSORBING_PERCENTAGE) || gAiLogicData->aiPredictionInProgress))
return FALSE;
if (AreStatsRaised(battler))
return FALSE;
@ -785,7 +785,7 @@ static bool32 ShouldSwitchIfAbilityBenefit(u32 battler)
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
}
static bool32 HasSuperEffectiveMoveAgainstOpponents(u32 battler, bool32 noRng)
static bool32 CanUseSuperEffectiveMoveAgainstOpponents(u32 battler)
{
s32 i;
u16 move;
@ -798,15 +798,12 @@ static bool32 HasSuperEffectiveMoveAgainstOpponents(u32 battler, bool32 noRng)
for (i = 0; i < MAX_MON_MOVES; i++)
{
move = gBattleMons[battler].moves[i];
if (move == MOVE_NONE)
if (move == MOVE_NONE || AI_DoesChoiceItemBlockMove(battler, move))
continue;
if (AI_GetMoveEffectiveness(move, battler, opposingBattler) >= UQ_4_12(2.0))
{
if (noRng)
return TRUE;
if (Random() % 10 != 0)
return TRUE;
return TRUE;
}
}
}
@ -820,15 +817,12 @@ static bool32 HasSuperEffectiveMoveAgainstOpponents(u32 battler, bool32 noRng)
for (i = 0; i < MAX_MON_MOVES; i++)
{
move = gBattleMons[battler].moves[i];
if (move == MOVE_NONE)
if (move == MOVE_NONE || AI_DoesChoiceItemBlockMove(battler, move))
continue;
if (AI_GetMoveEffectiveness(move, battler, opposingBattler) >= UQ_4_12(2.0))
{
if (noRng)
return TRUE;
if (Random() % 10 != 0)
return TRUE;
return TRUE;
}
}
}
@ -1174,7 +1168,7 @@ bool32 ShouldSwitch(u32 battler)
// We don't use FindMonWithFlagsAndSuperEffective with AI_FLAG_SMART_SWITCHING, so we can bail early.
if (gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)
return FALSE;
if (HasSuperEffectiveMoveAgainstOpponents(battler, FALSE))
if (CanUseSuperEffectiveMoveAgainstOpponents(battler))
return FALSE;
if (AreStatsRaised(battler))
return FALSE;

View File

@ -230,3 +230,23 @@ AI_SINGLE_BATTLE_TEST("Choiced Pokémon will only see choiced moves when conside
TURN { MOVE(player, MOVE_CLOSE_COMBAT); EXPECT_SWITCH(opponent, 1); }
}
}
AI_SINGLE_BATTLE_TEST("Choiced Pokémon will only see choiced moves when considering switching with FindMonThatAbsorbsMove")
{
PASSES_RANDOMLY(SHOULD_SWITCH_ABSORBS_MOVE_PERCENTAGE, 100, RNG_AI_SWITCH_ABSORBING);
GIVEN {
ASSUME(gSpeciesInfo[SPECIES_SANDSHREW].types[0] == TYPE_GROUND);
ASSUME(GetMoveType(MOVE_SCRATCH) == TYPE_NORMAL);
ASSUME(GetMoveType(MOVE_THUNDERBOLT) == TYPE_ELECTRIC);
ASSUME(GetMoveType(MOVE_WATER_GUN) == TYPE_WATER);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES);
PLAYER(SPECIES_WOOPER) { Ability(ABILITY_WATER_ABSORB); Moves(MOVE_CELEBRATE); }
PLAYER(SPECIES_DWEBBLE) { Moves(MOVE_WATER_GUN); }
OPPONENT(SPECIES_MUDKIP) { Item(ITEM_CHOICE_SCARF); Moves(MOVE_SCRATCH, MOVE_WATER_GUN); }
OPPONENT(SPECIES_WOOPER) { Ability(ABILITY_WATER_ABSORB); Moves(MOVE_SCRATCH); }
} WHEN {
TURN { SWITCH(player, 1); EXPECT_MOVE(opponent, MOVE_SCRATCH); }
TURN { MOVE(player, MOVE_WATER_GUN); EXPECT_MOVE(opponent, MOVE_SCRATCH); }
TURN { MOVE(player, MOVE_WATER_GUN); EXPECT_SWITCH(opponent, 1); }
}
}