diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index b2e191c17f..1e5cb325e6 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -121,8 +121,8 @@ u32 AI_GetSwitchinWeather(struct BattlePokemon battleMon); enum WeatherState IsWeatherActive(u32 flags); bool32 CanAIFaintTarget(u32 battlerAtk, u32 battlerDef, u32 numHits); bool32 CanIndexMoveFaintTarget(u32 battlerAtk, u32 battlerDef, u32 index, enum DamageCalcContext calcContext); -bool32 HasDamagingMove(u32 battlerId); -bool32 HasDamagingMoveOfType(u32 battlerId, u32 type); +bool32 HasDamagingMove(u32 battler); +bool32 HasDamagingMoveOfType(u32 battler, u32 type); u32 GetBattlerSecondaryDamage(u32 battlerId); bool32 BattlerWillFaintFromWeather(u32 battler, u32 ability); bool32 BattlerWillFaintFromSecondaryDamage(u32 battler, u32 ability); diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index dfc305ec5b..38e8d341a5 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -2929,30 +2929,38 @@ static inline bool32 IsMoveSleepClauseTrigger(u32 move) return FALSE; } -bool32 HasDamagingMove(u32 battlerId) +bool32 HasDamagingMove(u32 battler) { u32 i; - u16 *moves = GetMovesArray(battlerId); + u16 *moves = GetMovesArray(battler); for (i = 0; i < MAX_MON_MOVES; i++) { - if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && !IsBattleMoveStatus(moves[i])) + if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && GetMovePower(moves[i]) > 0) return TRUE; } return FALSE; } -bool32 HasDamagingMoveOfType(u32 battlerId, u32 type) +bool32 HasDamagingMoveOfType(u32 battler, u32 type) { s32 i; - u16 *moves = GetMovesArray(battlerId); + u16 *moves = GetMovesArray(battler); for (i = 0; i < MAX_MON_MOVES; i++) { - if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE - && GetMoveType(moves[i]) == type && !IsBattleMoveStatus(moves[i])) - return TRUE; + if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && GetMovePower(moves[i]) > 0) + { + u32 moveType = GetDynamicMoveType(GetBattlerMon(battler), moves[i], battler, MON_IN_BATTLE); + + if (moveType != TYPE_NONE && type == moveType) + return TRUE; + if (GetMoveType(moves[i]) == type) + return TRUE; + if (GetMoveEffect(moves[i]) == EFFECT_NATURE_POWER && GetMoveType(GetNaturePowerMove(moves[i])) == type) + return TRUE; + } } return FALSE; diff --git a/test/battle/ai/ai_check_viability.c b/test/battle/ai/ai_check_viability.c index 6d16d4fb6e..5583c3b38f 100644 --- a/test/battle/ai/ai_check_viability.c +++ b/test/battle/ai/ai_check_viability.c @@ -409,3 +409,32 @@ AI_SINGLE_BATTLE_TEST("AI sees Shield Dust immunity to additional effects") TURN { EXPECT_MOVE(opponent, MOVE_CHILLING_WATER); } } } + +AI_DOUBLE_BATTLE_TEST("AI sees type-changing moves as the correct type") +{ + u32 species, fieldStatus, ability; + u64 aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT; + + PARAMETRIZE { fieldStatus = MOVE_RAIN_DANCE; species = SPECIES_PRIMARINA; ability = ABILITY_NONE; } + PARAMETRIZE { fieldStatus = MOVE_RAIN_DANCE; species = SPECIES_PRIMARINA; ability = ABILITY_LIQUID_VOICE; } + PARAMETRIZE { fieldStatus = MOVE_ELECTRIC_TERRAIN; species = SPECIES_GEODUDE_ALOLA; ability = ABILITY_GALVANIZE; } + PARAMETRIZE { aiFlags |= AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_PP_STALL_PREVENTION; + fieldStatus = MOVE_RAIN_DANCE; species = SPECIES_PRIMARINA; ability = ABILITY_NONE; } + PARAMETRIZE { aiFlags |= AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_PP_STALL_PREVENTION; + fieldStatus = MOVE_RAIN_DANCE; species = SPECIES_PRIMARINA; ability = ABILITY_LIQUID_VOICE; } + PARAMETRIZE { aiFlags |= AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_PP_STALL_PREVENTION; + fieldStatus = MOVE_ELECTRIC_TERRAIN; species = SPECIES_GEODUDE_ALOLA; ability = ABILITY_GALVANIZE; } + + GIVEN { + AI_FLAGS(aiFlags); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Moves(fieldStatus, MOVE_RETURN, MOVE_TAUNT); } + OPPONENT(species) { Ability(ability); Moves(MOVE_HYPER_VOICE); } + } WHEN { + if (ability != ABILITY_NONE) + TURN { EXPECT_MOVE(opponentLeft, fieldStatus); } + else + TURN { NOT_EXPECT_MOVE(opponentLeft, fieldStatus); } + } +}