AI uses Tailwind with Wind Rider and Wind Power (#8983)

This commit is contained in:
GGbond 2026-01-21 19:58:09 +08:00 committed by GitHub
parent 61f8a50751
commit a2c5332e13
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 140 additions and 2 deletions

View File

@ -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;
}

View File

@ -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);

View File

@ -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")
{