From b12fcd8c7e4818b5d18f6f22f9c5c2930a7addf5 Mon Sep 17 00:00:00 2001 From: Pawkkie <61265402+Pawkkie@users.noreply.github.com> Date: Sat, 26 Jul 2025 13:59:17 -0400 Subject: [PATCH] Fix dynamic move types in switching (#7415) --- include/config/ai.h | 1 + include/random.h | 1 + src/battle_ai_switch_items.c | 6 ++++-- test/battle/ai/ai_switching.c | 15 +++++++++++++++ 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/include/config/ai.h b/include/config/ai.h index c82e46773a..d5f42696eb 100644 --- a/include/config/ai.h +++ b/include/config/ai.h @@ -13,6 +13,7 @@ // AI smart switching chances; if you want more complex behaviour, modify GetSwitchChance #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 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 diff --git a/include/random.h b/include/random.h index 38a464e457..283813b1b1 100644 --- a/include/random.h +++ b/include/random.h @@ -192,6 +192,7 @@ enum RandomTag RNG_AI_SWITCH_ALL_MOVES_BAD, RNG_AI_CONSERVE_TERA, RNG_AI_SWITCH_ALL_SCORES_BAD, + RNG_AI_SWITCH_ABSORBING_HIDDEN_POWER, RNG_AI_PP_STALL_DISREGARD_MOVE, RNG_AI_SUCKER_PUNCH, RNG_SHELL_SIDE_ARM, diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index 7c5348176f..526c81c7ca 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -481,12 +481,14 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler) u16 monAbility, aiMove; u32 opposingBattler = GetOppositeBattler(battler); u32 incomingMove = GetIncomingMove(battler, opposingBattler, gAiLogicData); - u32 incomingType = GetMoveType(incomingMove); + u32 incomingType = CheckDynamicMoveType(GetBattlerMon(opposingBattler), incomingMove, opposingBattler, MON_IN_BATTLE); bool32 isOpposingBattlerChargingOrInvulnerable = (IsSemiInvulnerable(opposingBattler, incomingMove) || IsTwoTurnNotSemiInvulnerableMove(opposingBattler, incomingMove)); s32 i, j; if (!(gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) return FALSE; + if (GetMoveEffect(incomingMove) == EFFECT_HIDDEN_POWER && RandomPercentage(RNG_AI_SWITCH_ABSORBING_HIDDEN_POWER, SHOULD_SWITCH_ABSORBS_HIDDEN_POWER_PERCENTAGE)) + 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 (CanUseSuperEffectiveMoveAgainstOpponents(battler) && (RandomPercentage(RNG_AI_SWITCH_ABSORBING_STAY_IN, STAY_IN_ABSORBING_PERCENTAGE) || gAiLogicData->aiPredictionInProgress)) @@ -1034,7 +1036,7 @@ static bool32 ShouldSwitchIfBadChoiceLock(u32 battler) bool32 moveAffectsTarget = TRUE; if (lastUsedMove != MOVE_NONE && (AI_GetMoveEffectiveness(lastUsedMove, battler, opposingBattler) == UQ_4_12(0.0) - || CanAbilityAbsorbMove(battler, opposingBattler, gAiLogicData->abilities[opposingBattler], lastUsedMove, GetMoveType(lastUsedMove), AI_CHECK) + || CanAbilityAbsorbMove(battler, opposingBattler, gAiLogicData->abilities[opposingBattler], lastUsedMove, CheckDynamicMoveType(GetBattlerMon(battler), lastUsedMove, battler, MON_IN_BATTLE), AI_CHECK) || CanAbilityBlockMove(battler, opposingBattler, gAiLogicData->abilities[battler], gAiLogicData->abilities[opposingBattler], lastUsedMove, AI_CHECK))) moveAffectsTarget = FALSE; diff --git a/test/battle/ai/ai_switching.c b/test/battle/ai/ai_switching.c index 4c05c620a5..e8eb9f7ec4 100644 --- a/test/battle/ai/ai_switching.c +++ b/test/battle/ai/ai_switching.c @@ -1339,3 +1339,18 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will consider player's priori TURN { MOVE(player, MOVE_KNOCK_OFF); EXPECT_SWITCH(opponent, 1); } } } + +AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will consider Hidden Power when triggering absorbing switches") +{ + PASSES_RANDOMLY(SHOULD_SWITCH_ABSORBS_HIDDEN_POWER_PERCENTAGE, 100, RNG_AI_SWITCH_ABSORBING_HIDDEN_POWER); + GIVEN { + ASSUME(B_REDIRECT_ABILITY_IMMUNITY >= GEN_5); + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING); + PLAYER(SPECIES_ZIGZAGOON) { Moves(MOVE_HIDDEN_POWER); HPIV(31); AttackIV(30); DefenseIV(31); SpAttackIV(30); SpDefenseIV(31); SpeedIV(30); } + OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_SCRATCH); } + OPPONENT(SPECIES_NINETALES) { Moves(MOVE_SCRATCH); Ability(ABILITY_FLASH_FIRE); } + } WHEN { + TURN { MOVE(player, MOVE_HIDDEN_POWER); EXPECT_MOVE(opponent, MOVE_SCRATCH); } + TURN { MOVE(player, MOVE_HIDDEN_POWER); EXPECT_SWITCH(opponent, 1); } + } +}