From 1ca5b23f19da951893a83123eae1b99329e80ca9 Mon Sep 17 00:00:00 2001 From: Pawkkie <61265402+Pawkkie@users.noreply.github.com> Date: Mon, 22 Sep 2025 13:47:23 -0400 Subject: [PATCH] Fix abusable two-turn-move switch behaviour (#7770) --- include/config/ai.h | 2 +- src/battle_ai_switch_items.c | 3 ++- test/battle/ai/ai_switching.c | 10 +++++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/include/config/ai.h b/include/config/ai.h index 877b3da427..b834829edf 100644 --- a/include/config/ai.h +++ b/include/config/ai.h @@ -15,7 +15,7 @@ #define SHOULD_SWITCH_ABSORBS_MOVE_PERCENTAGE 100 #define SHOULD_SWITCH_ABSORBS_HIDDEN_POWER_PERCENTAGE 50 #define SHOULD_SWITCH_TRAPPER_PERCENTAGE 100 -#define SHOULD_SWITCH_FREE_TURN_PERCENTAGE 100 +#define SHOULD_SWITCH_FREE_TURN_PERCENTAGE 50 #define STAY_IN_ABSORBING_PERCENTAGE 66 // Chance to stay in if outgoing mon has super effective move against player, will prevent switching out for an absorber with this likelihood #define SHOULD_SWITCH_HASBADODDS_PERCENTAGE 50 #define SHOULD_SWITCH_ENCORE_STATUS_PERCENTAGE 100 diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index 6340b921c6..391b40af98 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -621,6 +621,7 @@ static bool32 ShouldSwitchIfOpponentChargingOrInvulnerable(u32 battler) if (IsDoubleBattle() || !(gAiThinkingStruct->aiFlags[battler] & AI_FLAG_SMART_SWITCHING)) return FALSE; + // In a world with a unified ShouldSwitch function, also want to check whether we already win 1v1 and if we do don't switch; not worth doubling the HasBadOdds computation for now if (isOpposingBattlerChargingOrInvulnerable && gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE && RandomPercentage(RNG_AI_SWITCH_FREE_TURN, GetSwitchChance(SHOULD_SWITCH_FREE_TURN))) return SetSwitchinAndSwitch(battler, PARTY_SIZE); @@ -658,7 +659,7 @@ static bool32 ShouldSwitchIfTrapperInParty(u32 battler) if (CanAbilityTrapOpponent(monAbility, opposingBattler) || (CanAbilityTrapOpponent(gAiLogicData->abilities[opposingBattler], opposingBattler) && monAbility == ABILITY_TRACE)) { // If mon in slot i is the most suitable switchin candidate, then it's a trapper than wins 1v1 - if (i == gAiLogicData->mostSuitableMonId[battler] && RandomPercentage(RNG_AI_SWITCH_FREE_TURN, GetSwitchChance(SHOULD_SWITCH_FREE_TURN))) + if (i == gAiLogicData->mostSuitableMonId[battler] && RandomPercentage(RNG_AI_SWITCH_TRAPPER, GetSwitchChance(SHOULD_SWITCH_TRAPPER))) return SetSwitchinAndSwitch(battler, PARTY_SIZE); } } diff --git a/test/battle/ai/ai_switching.c b/test/battle/ai/ai_switching.c index b1aad9afb2..f6d7304a6b 100644 --- a/test/battle/ai/ai_switching.c +++ b/test/battle/ai/ai_switching.c @@ -748,15 +748,15 @@ AI_DOUBLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has bee } } -AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if player's mon is semi-invulnerable and it has an absorber") +AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if player's mon is semi-invulnerable and it has a good switchin") { PASSES_RANDOMLY(SHOULD_SWITCH_FREE_TURN_PERCENTAGE, 100, RNG_AI_SWITCH_FREE_TURN); GIVEN { ASSUME(GetMoveType(MOVE_DIVE) == TYPE_WATER); - AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING); - PLAYER(SPECIES_LUVDISC) { Moves(MOVE_DIVE); } + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES); + PLAYER(SPECIES_LUVDISC) { Level(1); Moves(MOVE_DIVE); } OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_SCRATCH); } - OPPONENT(SPECIES_MANTINE) { Moves(MOVE_SCRATCH); Ability(ABILITY_WATER_ABSORB); } + OPPONENT(SPECIES_PIKACHU) { Moves(MOVE_THUNDERBOLT); } } WHEN { TURN { MOVE(player, MOVE_DIVE) ; EXPECT_MOVE(opponent, MOVE_SCRATCH); } TURN { SKIP_TURN(player); EXPECT_SWITCH(opponent, 1); } @@ -810,7 +810,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if player's m AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if player's mon is charging and it has a good switchin immunity (ability)") { - PASSES_RANDOMLY(SHOULD_SWITCH_FREE_TURN_PERCENTAGE, 100, RNG_AI_SWITCH_FREE_TURN); + PASSES_RANDOMLY(SHOULD_SWITCH_ABSORBS_MOVE_PERCENTAGE, 100, RNG_AI_SWITCH_ABSORBING); GIVEN { ASSUME(GetMoveType(MOVE_DIG) == TYPE_GROUND); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);