diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index ce51e4100c..f695f14e7e 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -46,6 +46,7 @@ static inline void BattleAI_DoAIProcessing_PredictedSwitchin(struct AiThinkingSt static bool32 IsPinchBerryItemEffect(enum HoldEffect holdEffect); static bool32 DoesAbilityBenefitFromSunOrRain(u32 battler, enum Ability ability, u32 weather); static void AI_CompareDamagingMoves(u32 battlerAtk, u32 battlerDef); +static u32 GetWindAbilityScore(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData); // ewram EWRAM_DATA const u8 *gAIScriptPtr = NULL; // Still used in contests @@ -3945,6 +3946,26 @@ static bool32 DoesAbilityBenefitFromSunOrRain(u32 battler, enum Ability ability, return FALSE; } +static u32 GetWindAbilityScore(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData) +{ + u32 score = 0; + + if (aiData->abilities[battlerAtk] == ABILITY_WIND_RIDER) + { + score = IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_ATK); + } + else if (aiData->abilities[battlerAtk] == ABILITY_WIND_POWER) + { + if (gBattleMons[battlerAtk].volatiles.chargeTimer == 0 + && HasDamagingMoveOfType(battlerAtk, TYPE_ELECTRIC)) + { + score = DECENT_EFFECT; + } + } + + return score; +} + static enum MoveComparisonResult CompareMoveAccuracies(u32 battlerAtk, u32 battlerDef, u32 moveSlot1, u32 moveSlot2) { u32 acc1 = gAiLogicData->moveAccuracy[battlerAtk][battlerDef][moveSlot1]; @@ -5604,6 +5625,14 @@ static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, enum Move move if (CountUsablePartyMons(battlerAtk) != 0) ADJUST_SCORE(WEAK_EFFECT); + + if (!(gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_TAILWIND)) + { + u32 windAbilityScore = GetWindAbilityScore(battlerAtk, battlerDef, aiData); + + if (windAbilityScore > 0) + ADJUST_SCORE(windAbilityScore); + } } else { @@ -5617,15 +5646,26 @@ static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, enum Move move tailwindScore += 1; if (speed <= foe2Speed && (speed * 2) > foe2Speed) tailwindScore += 1; - if (partnerSpeed <= foe1Speed && (speed * 2) > foe1Speed) + if (partnerSpeed <= foe1Speed && (partnerSpeed * 2) > foe1Speed) tailwindScore += 1; - if (partnerSpeed <= foe1Speed && (speed * 2) > foe1Speed) + if (partnerSpeed <= foe2Speed && (partnerSpeed * 2) > foe2Speed) tailwindScore += 1; if (tailwindScore > 0) tailwindScore += 1; ADJUST_SCORE(tailwindScore); + + if (!(gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_TAILWIND)) + { + u32 windAbilityScore = GetWindAbilityScore(battlerAtk, battlerDef, aiData); + + if (IsBattlerAlive(BATTLE_PARTNER(battlerAtk))) + windAbilityScore += GetWindAbilityScore(BATTLE_PARTNER(battlerAtk), battlerDef, aiData); + + if (windAbilityScore > 0) + ADJUST_SCORE(windAbilityScore); + } } break; } diff --git a/test/battle/ai/ai_check_viability.c b/test/battle/ai/ai_check_viability.c index b12e3d1dce..43b5f49129 100644 --- a/test/battle/ai/ai_check_viability.c +++ b/test/battle/ai/ai_check_viability.c @@ -397,6 +397,51 @@ AI_SINGLE_BATTLE_TEST("AI uses Trick Room (singles)") } } +AI_SINGLE_BATTLE_TEST("AI uses Tailwind to trigger Wind Rider (Single)") +{ + bool32 expectTailwind; + u16 tailwindSpecies; + enum Ability tailwindAbility; + + PARAMETRIZE { tailwindSpecies = SPECIES_BRAMBLEGHAST; tailwindAbility = ABILITY_WIND_RIDER; expectTailwind = TRUE; } + PARAMETRIZE { tailwindSpecies = SPECIES_BRAMBLEGHAST; tailwindAbility = ABILITY_INFILTRATOR; expectTailwind = FALSE; } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_TAILWIND) == EFFECT_TAILWIND); + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY); + PLAYER(SPECIES_WOBBUFFET) { Speed(20); } + OPPONENT(tailwindSpecies) { Ability(tailwindAbility); Speed(9); Moves(MOVE_TAILWIND, MOVE_HEADBUTT); } + } WHEN { + if (expectTailwind) + TURN { EXPECT_MOVE(opponent, MOVE_TAILWIND); } + else + TURN { NOT_EXPECT_MOVE(opponent, MOVE_TAILWIND); } + } +} + +AI_SINGLE_BATTLE_TEST("AI uses Tailwind to trigger Wind Power (Single)") +{ + bool32 expectTailwind; + u16 tailwindSpecies; + enum Ability tailwindAbility; + + PARAMETRIZE { tailwindSpecies = SPECIES_KILOWATTREL; tailwindAbility = ABILITY_WIND_POWER; expectTailwind = TRUE; } + PARAMETRIZE { tailwindSpecies = SPECIES_KILOWATTREL; tailwindAbility = ABILITY_COMPETITIVE; expectTailwind = FALSE; } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_TAILWIND) == EFFECT_TAILWIND); + ASSUME(GetMoveType(MOVE_THUNDERSHOCK) == TYPE_ELECTRIC); + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY); + PLAYER(SPECIES_WOBBUFFET) { Speed(20); } + OPPONENT(tailwindSpecies) { Ability(tailwindAbility); Speed(9); Moves(MOVE_TAILWIND, MOVE_THUNDERSHOCK); } + } WHEN { + if (expectTailwind) + TURN { EXPECT_MOVE(opponent, MOVE_TAILWIND); } + else + TURN { NOT_EXPECT_MOVE(opponent, MOVE_TAILWIND); } + } +} + AI_SINGLE_BATTLE_TEST("AI uses Quick Guard against Quick Attack when opponent would take poison damage") { PASSES_RANDOMLY(PREDICT_MOVE_CHANCE, 100, RNG_AI_PREDICT_MOVE); diff --git a/test/battle/ai/ai_doubles.c b/test/battle/ai/ai_doubles.c index 3844533e33..b94e7cec71 100644 --- a/test/battle/ai/ai_doubles.c +++ b/test/battle/ai/ai_doubles.c @@ -973,6 +973,59 @@ AI_DOUBLE_BATTLE_TEST("AI uses Tailwind") } } +AI_DOUBLE_BATTLE_TEST("AI uses Tailwind to trigger Wind Rider (Doubles)") +{ + bool32 expectTailwind; + u16 tailwindSpecies, partnerSpecies; + enum Ability tailwindAbility, partnerAbility; + + PARAMETRIZE { tailwindSpecies = SPECIES_BRAMBLEGHAST; tailwindAbility = ABILITY_WIND_RIDER; partnerSpecies = SPECIES_BRAMBLEGHAST; partnerAbility = ABILITY_WIND_RIDER; expectTailwind = TRUE; } + PARAMETRIZE { tailwindSpecies = SPECIES_BRAMBLEGHAST; tailwindAbility = ABILITY_WIND_RIDER; partnerSpecies = SPECIES_BRAMBLEGHAST; partnerAbility = ABILITY_INFILTRATOR; expectTailwind = TRUE; } + PARAMETRIZE { tailwindSpecies = SPECIES_BRAMBLEGHAST; tailwindAbility = ABILITY_INFILTRATOR; partnerSpecies = SPECIES_BRAMBLEGHAST; partnerAbility = ABILITY_WIND_RIDER; expectTailwind = TRUE; } + PARAMETRIZE { tailwindSpecies = SPECIES_BRAMBLEGHAST; tailwindAbility = ABILITY_INFILTRATOR; partnerSpecies = SPECIES_BRAMBLEGHAST; partnerAbility = ABILITY_INFILTRATOR; expectTailwind = FALSE; } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_TAILWIND) == EFFECT_TAILWIND); + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_DOUBLE_BATTLE); + PLAYER(SPECIES_WOBBUFFET) { Speed(20); } + PLAYER(SPECIES_WOBBUFFET) { Speed(20); } + OPPONENT(tailwindSpecies) { Ability(tailwindAbility); Speed(9); Moves(MOVE_TAILWIND, MOVE_HEADBUTT); } + OPPONENT(partnerSpecies) { Ability(partnerAbility); Speed(9); Moves(MOVE_HEADBUTT); } + } WHEN { + if (expectTailwind) + TURN { EXPECT_MOVE(opponentLeft, MOVE_TAILWIND); } + else + TURN { NOT_EXPECT_MOVE(opponentLeft, MOVE_TAILWIND); } + } +} + +AI_DOUBLE_BATTLE_TEST("AI uses Tailwind to trigger Wind Power (Doubles)") +{ + bool32 expectTailwind; + u16 tailwindSpecies, partnerSpecies; + enum Ability tailwindAbility, partnerAbility; + + PARAMETRIZE { tailwindSpecies = SPECIES_KILOWATTREL; tailwindAbility = ABILITY_WIND_POWER; partnerSpecies = SPECIES_KILOWATTREL; partnerAbility = ABILITY_WIND_POWER; expectTailwind = TRUE; } + PARAMETRIZE { tailwindSpecies = SPECIES_KILOWATTREL; tailwindAbility = ABILITY_WIND_POWER; partnerSpecies = SPECIES_KILOWATTREL; partnerAbility = ABILITY_COMPETITIVE; expectTailwind = TRUE; } + PARAMETRIZE { tailwindSpecies = SPECIES_KILOWATTREL; tailwindAbility = ABILITY_COMPETITIVE; partnerSpecies = SPECIES_KILOWATTREL; partnerAbility = ABILITY_WIND_POWER; expectTailwind = TRUE; } + PARAMETRIZE { tailwindSpecies = SPECIES_KILOWATTREL; tailwindAbility = ABILITY_COMPETITIVE; partnerSpecies = SPECIES_KILOWATTREL; partnerAbility = ABILITY_COMPETITIVE; expectTailwind = FALSE; } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_TAILWIND) == EFFECT_TAILWIND); + ASSUME(GetMoveType(MOVE_THUNDERSHOCK) == TYPE_ELECTRIC); + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_DOUBLE_BATTLE); + PLAYER(SPECIES_WOBBUFFET) { Speed(20); } + PLAYER(SPECIES_WOBBUFFET) { Speed(20); } + OPPONENT(tailwindSpecies) { Ability(tailwindAbility); Speed(21); Moves(MOVE_TAILWIND, MOVE_THUNDERSHOCK); } + OPPONENT(partnerSpecies) { Ability(partnerAbility); Speed(21); Moves(MOVE_THUNDERSHOCK); } + } WHEN { + if (expectTailwind) + TURN { EXPECT_MOVE(opponentLeft, MOVE_TAILWIND); } + else + TURN { NOT_EXPECT_MOVE(opponentLeft, MOVE_TAILWIND); } + } +} + AI_DOUBLE_BATTLE_TEST("AI uses Guard Split to improve its stats") {