diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index ce98f3b357..13e438a5d4 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -421,19 +421,50 @@ static inline s32 DmgRoll(s32 dmg) return dmg; } -bool32 IsDamageMoveUnusable(u32 battlerAtk, u32 battlerDef, u32 move, u32 moveType) +bool32 IsDamageMoveUnusable(u32 battlerAtk, u32 battlerDef, u32 move, u32 moveType, uq4_12_t effectiveness, u32 weather) { + u32 battlerDefAbility; + u32 partnerDefAbility; struct AiLogicData *aiData = AI_DATA; + if (effectiveness == UQ_4_12(0.0)) + return TRUE; if (gBattleStruct->battlerState[battlerDef].commandingDondozo) return TRUE; - if (CanAbilityBlockMove(battlerAtk, battlerDef, move, aiData->abilities[battlerDef], ABILITY_CHECK_TRIGGER)) + // aiData->abilities does not check for Mold Breaker since it happens during combat so it needs to be done manually + if (IsMoldBreakerTypeAbility(battlerAtk, aiData->abilities[battlerAtk]) || MoveIgnoresTargetAbility(move)) + { + battlerDefAbility = ABILITY_NONE; + partnerDefAbility = ABILITY_NONE; + } + else + { + battlerDefAbility = aiData->abilities[battlerDef]; + partnerDefAbility = aiData->abilities[BATTLE_PARTNER(battlerDef)]; + } + + if (CanAbilityBlockMove(battlerAtk, battlerDef, move, battlerDefAbility, ABILITY_CHECK_TRIGGER)) return TRUE; - if (CanAbilityAbsorbMove(battlerAtk, battlerDef, aiData->abilities[battlerDef], move, moveType, ABILITY_CHECK_TRIGGER)) + if (CanAbilityAbsorbMove(battlerAtk, battlerDef, battlerDefAbility, move, moveType, ABILITY_CHECK_TRIGGER)) return TRUE; + // Limited to Lighning Rod and Storm Drain because otherwise the AI would consider Water Absorb, etc... + if (partnerDefAbility == ABILITY_LIGHTNING_ROD || partnerDefAbility == ABILITY_STORM_DRAIN) + { + if (CanAbilityAbsorbMove(battlerAtk, BATTLE_PARTNER(battlerDef), partnerDefAbility, move, moveType, ABILITY_CHECK_TRIGGER)) + return TRUE; + } + + if (HasWeatherEffect()) + { + if (weather & B_WEATHER_SUN_PRIMAL && moveType == TYPE_WATER) + return TRUE; + if (weather & B_WEATHER_RAIN_PRIMAL && moveType == TYPE_FIRE) + return TRUE; + } + switch (GetMoveEffect(move)) { case EFFECT_DREAM_EATER: @@ -469,6 +500,11 @@ bool32 IsDamageMoveUnusable(u32 battlerAtk, u32 battlerDef, u32 move, u32 moveTy if (!gDisableStructs[battlerAtk].isFirstTurn) return TRUE; break; + case EFFECT_EXPLOSION: + case EFFECT_MIND_BLOWN: + if (battlerDefAbility == ABILITY_DAMP || partnerDefAbility == ABILITY_DAMP) + return TRUE; + break; } return FALSE; @@ -658,7 +694,7 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u u32 movePower = GetMovePower(move); if (movePower) - isDamageMoveUnusable = IsDamageMoveUnusable(battlerAtk, battlerDef, move, moveType); + isDamageMoveUnusable = IsDamageMoveUnusable(battlerAtk, battlerDef, move, moveType, effectivenessMultiplier, weather); if (movePower && !isDamageMoveUnusable) { diff --git a/test/battle/ai/ai.c b/test/battle/ai/ai.c index 5359ebe58f..a22097c815 100644 --- a/test/battle/ai/ai.c +++ b/test/battle/ai/ai.c @@ -915,6 +915,36 @@ SINGLE_BATTLE_TEST("AI correctly records used moves") } } +AI_SINGLE_BATTLE_TEST("AI sees that Primal weather can block a move by type") +{ + GIVEN { + ASSUME(GetMoveType(MOVE_HYDRO_PUMP) == TYPE_WATER); + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT); + PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); Moves(MOVE_SCRATCH); } + OPPONENT(SPECIES_BLASTOISE) { Moves(MOVE_HYDRO_PUMP, MOVE_POUND); } + } WHEN { + TURN { MOVE(player, MOVE_SCRATCH); EXPECT_MOVE(opponent, MOVE_POUND); } + } +} + +AI_DOUBLE_BATTLE_TEST("AI sees opposing drain ability") +{ + GIVEN { + ASSUME(GetMoveType(MOVE_THUNDERBOLT) == TYPE_ELECTRIC); + ASSUME(GetMoveType(MOVE_RAZOR_LEAF) != TYPE_ELECTRIC); + ASSUME(GetMoveType(MOVE_METAL_CLAW) != TYPE_ELECTRIC); + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT); + PLAYER(SPECIES_RAICHU) { Ability(ABILITY_LIGHTNING_ROD); Moves(MOVE_CELEBRATE); } + PLAYER(SPECIES_KRABBY) { Ability(ABILITY_VOLT_ABSORB); Moves(MOVE_CELEBRATE); } + OPPONENT(SPECIES_MAGNETON) { Moves(MOVE_THUNDERBOLT, MOVE_RAZOR_LEAF); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_THUNDERBOLT, MOVE_METAL_CLAW); } + } WHEN { + TURN { + NOT_EXPECT_MOVE(opponentLeft, MOVE_THUNDERBOLT); + NOT_EXPECT_MOVE(opponentRight, MOVE_THUNDERBOLT); } + } +} + AI_SINGLE_BATTLE_TEST("AI will not set up Weather if it wont have any affect") { u32 ability; @@ -934,4 +964,3 @@ AI_SINGLE_BATTLE_TEST("AI will not set up Weather if it wont have any affect") TURN { MOVE(player, MOVE_SCRATCH); EXPECT_MOVE(opponent, MOVE_RAIN_DANCE); } } } -