Switch chance config support (#6187)

This commit is contained in:
Pawkkie 2025-02-09 18:30:54 -05:00 committed by GitHub
parent 174bc2f29f
commit 579fa6410d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 248 additions and 63 deletions

View File

@ -1,6 +1,39 @@
#ifndef GUARD_BATTLE_AI_SWITCH_ITEMS_H
#define GUARD_BATTLE_AI_SWITCH_ITEMS_H
enum ShouldSwitchScenario
{
SHOULD_SWITCH_WONDER_GUARD,
SHOULD_SWITCH_ABSORBS_MOVE,
SHOULD_SWITCH_TRAPPER,
SHOULD_SWITCH_FREE_TURN,
SHOULD_SWITCH_TRUANT,
SHOULD_SWITCH_ALL_MOVES_BAD,
SHOULD_SWITCH_PERISH_SONG,
SHOULD_SWITCH_YAWN,
SHOULD_SWITCH_BADLY_POISONED,
SHOULD_SWITCH_BADLY_POISONED_STATS_RAISED,
SHOULD_SWITCH_CURSED,
SHOULD_SWITCH_CURSED_STATS_RAISED,
SHOULD_SWITCH_NIGHTMARE,
SHOULD_SWITCH_NIGHTMARE_STATS_RAISED,
SHOULD_SWITCH_SEEDED,
SHOULD_SWITCH_SEEDED_STATS_RAISED,
SHOULD_SWITCH_INFATUATION,
SHOULD_SWITCH_HASBADODDS,
SHOULD_SWITCH_NATURAL_CURE_STRONG,
SHOULD_SWITCH_NATURAL_CURE_STRONG_STATS_RAISED,
SHOULD_SWITCH_NATURAL_CURE_WEAK,
SHOULD_SWITCH_NATURAL_CURE_WEAK_STATS_RAISED,
SHOULD_SWITCH_REGENERATOR,
SHOULD_SWITCH_REGENERATOR_STATS_RAISED,
SHOULD_SWITCH_ENCORE_STATUS,
SHOULD_SWITCH_ENCORE_DAMAGE,
SHOULD_SWITCH_CHOICE_LOCKED,
SHOULD_SWITCH_ATTACKING_STAT_MINUS_TWO,
SHOULD_SWITCH_ATTACKING_STAT_MINUS_THREE_PLUS,
};
enum SwitchType
{
SWITCH_AFTER_KO,

49
include/config/ai.h Normal file
View File

@ -0,0 +1,49 @@
#ifndef GUARD_CONFIG_AI_H
#define GUARD_CONFIG_AI_H
// For the details on what specific factors the switching functions are considering, go read the corresponding function inside ShouldSwitch in src/battle_ai_switch_items.c
// These configuration options control how likely the AI is to switch if it determines that a switch meets all of its criteria
// Think of them almost like success rates; if the AI has determined that it needs to switch out to hit Wonder Guard, how often do you want it to actually take that course of action? Etc.
// AI switch chances; if you want more complex behaviour, modify GetSwitchChance
#define SHOULD_SWITCH_WONDER_GUARD_PERCENTAGE 100
#define SHOULD_SWITCH_TRUANT_PERCENTAGE 100
#define SHOULD_SWITCH_ALL_MOVES_BAD_PERCENTAGE 100
// AI smart switching chances; if you want more complex behaviour, modify GetSwitchChance
#define SHOULD_SWITCH_ABSORBS_MOVE_PERCENTAGE 100
#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
#define SHOULD_SWITCH_HASBADODDS_PERCENTAGE 50
#define SHOULD_SWITCH_ENCORE_STATUS_PERCENTAGE 100
#define SHOULD_SWITCH_ENCORE_DAMAGE_PERCENTAGE 50
#define SHOULD_SWITCH_CHOICE_LOCKED_PERCENTAGE 100 // Only if locked into status move
#define SHOULD_SWITCH_ATTACKING_STAT_MINUS_TWO_PERCENTAGE 50
#define SHOULD_SWITCH_ATTACKING_STAT_MINUS_THREE_PLUS_PERCENTAGE 100
// AI smart switching chances for bad statuses
#define SHOULD_SWITCH_PERISH_SONG_PERCENTAGE 100
#define SHOULD_SWITCH_YAWN_PERCENTAGE 100
#define SHOULD_SWITCH_BADLY_POISONED_PERCENTAGE 50
#define SHOULD_SWITCH_BADLY_POISONED_STATS_RAISED_PERCENTAGE 20
#define SHOULD_SWITCH_CURSED_PERCENTAGE 50
#define SHOULD_SWITCH_CURSED_STATS_RAISED_PERCENTAGE 20
#define SHOULD_SWITCH_NIGHTMARE_PERCENTAGE 33
#define SHOULD_SWITCH_NIGHTMARE_STATS_RAISED_PERCENTAGE 15
#define SHOULD_SWITCH_SEEDED_PERCENTAGE 25
#define SHOULD_SWITCH_SEEDED_STATS_RAISED_PERCENTAGE 10
#define SHOULD_SWITCH_INFATUATION_PERCENTAGE 100
// AI smart switching chances for beneficial abilities
#define SHOULD_SWITCH_NATURAL_CURE_STRONG_PERCENTAGE 66
#define SHOULD_SWITCH_NATURAL_CURE_STRONG_STATS_RAISED_PERCENTAGE 10
#define SHOULD_SWITCH_NATURAL_CURE_WEAK_PERCENTAGE 25
#define SHOULD_SWITCH_NATURAL_CURE_WEAK_STATS_RAISED_PERCENTAGE 10
#define SHOULD_SWITCH_REGENERATOR_PERCENTAGE 50
#define SHOULD_SWITCH_REGENERATOR_STATS_RAISED_PERCENTAGE 20
// AI prediction chances
#define PREDICT_SWITCH_CHANCE 50
#endif // GUARD_CONFIG_AI_H

View File

@ -10,6 +10,7 @@
#include "config/overworld.h"
#include "config/dexnav.h"
#include "config/summary_screen.h"
#include "config/ai.h"
// Invalid Versions show as "----------" in Gen 4 and Gen 5's summary screen.
// In Gens 6 and 7, invalid versions instead show "a distant land" in the summary screen.

View File

@ -171,12 +171,22 @@ enum RandomTag
RNG_AI_SWITCH_CURSED,
RNG_AI_SWITCH_NIGHTMARE,
RNG_AI_SWITCH_SEEDED,
RNG_AI_SWITCH_YAWN,
RNG_AI_SWITCH_PERISH_SONG,
RNG_AI_SWITCH_INFATUATION,
RNG_AI_SWITCH_ABSORBING,
RNG_AI_SWITCH_ABSORBING_STAY_IN,
RNG_AI_SWITCH_NATURAL_CURE,
RNG_AI_SWITCH_REGENERATOR,
RNG_AI_SWITCH_ENCORE,
RNG_AI_SWITCH_CHOICE_LOCKED,
RNG_AI_SWITCH_STATS_LOWERED,
RNG_AI_SWITCH_SE_DEFENSIVE,
RNG_AI_SWITCH_TRUANT,
RNG_AI_SWITCH_WONDER_GUARD,
RNG_AI_SWITCH_TRAPPER,
RNG_AI_SWITCH_FREE_TURN,
RNG_AI_SWITCH_ALL_MOVES_BAD,
RNG_SHELL_SIDE_ARM,
RNG_RANDOM_TARGET,
RNG_AI_PREDICT_ABILITY,

View File

@ -37,6 +37,74 @@ static void InitializeSwitchinCandidate(struct Pokemon *mon)
AI_DATA->switchinCandidate.hypotheticalStatus = FALSE;
}
u32 GetSwitchChance(enum ShouldSwitchScenario shouldSwitchScenario)
{
// Modify these cases if you want unique behaviour based on other data (trainer class, difficulty, etc.)
switch(shouldSwitchScenario)
{
case SHOULD_SWITCH_WONDER_GUARD:
return SHOULD_SWITCH_WONDER_GUARD_PERCENTAGE;
case SHOULD_SWITCH_ABSORBS_MOVE:
return SHOULD_SWITCH_ABSORBS_MOVE_PERCENTAGE;
case SHOULD_SWITCH_TRAPPER:
return SHOULD_SWITCH_TRAPPER_PERCENTAGE;
case SHOULD_SWITCH_FREE_TURN:
return SHOULD_SWITCH_FREE_TURN_PERCENTAGE;
case SHOULD_SWITCH_TRUANT:
return SHOULD_SWITCH_TRUANT_PERCENTAGE;
case SHOULD_SWITCH_ALL_MOVES_BAD:
return SHOULD_SWITCH_ALL_MOVES_BAD_PERCENTAGE;
case SHOULD_SWITCH_PERISH_SONG:
return SHOULD_SWITCH_PERISH_SONG_PERCENTAGE;
case SHOULD_SWITCH_YAWN:
return SHOULD_SWITCH_YAWN_PERCENTAGE;
case SHOULD_SWITCH_BADLY_POISONED:
return SHOULD_SWITCH_BADLY_POISONED_PERCENTAGE;
case SHOULD_SWITCH_BADLY_POISONED_STATS_RAISED:
return SHOULD_SWITCH_BADLY_POISONED_STATS_RAISED_PERCENTAGE;
case SHOULD_SWITCH_CURSED:
return SHOULD_SWITCH_CURSED_PERCENTAGE;
case SHOULD_SWITCH_CURSED_STATS_RAISED:
return SHOULD_SWITCH_CURSED_STATS_RAISED_PERCENTAGE;
case SHOULD_SWITCH_NIGHTMARE:
return SHOULD_SWITCH_NIGHTMARE_PERCENTAGE;
case SHOULD_SWITCH_NIGHTMARE_STATS_RAISED:
return SHOULD_SWITCH_NIGHTMARE_STATS_RAISED_PERCENTAGE;
case SHOULD_SWITCH_SEEDED:
return SHOULD_SWITCH_SEEDED_PERCENTAGE;
case SHOULD_SWITCH_SEEDED_STATS_RAISED:
return SHOULD_SWITCH_SEEDED_STATS_RAISED_PERCENTAGE;
case SHOULD_SWITCH_INFATUATION:
return SHOULD_SWITCH_INFATUATION_PERCENTAGE;
case SHOULD_SWITCH_HASBADODDS:
return SHOULD_SWITCH_HASBADODDS_PERCENTAGE;
case SHOULD_SWITCH_NATURAL_CURE_STRONG:
return SHOULD_SWITCH_NATURAL_CURE_STRONG_PERCENTAGE;
case SHOULD_SWITCH_NATURAL_CURE_STRONG_STATS_RAISED:
return SHOULD_SWITCH_NATURAL_CURE_STRONG_STATS_RAISED_PERCENTAGE;
case SHOULD_SWITCH_NATURAL_CURE_WEAK:
return SHOULD_SWITCH_NATURAL_CURE_WEAK_PERCENTAGE;
case SHOULD_SWITCH_NATURAL_CURE_WEAK_STATS_RAISED:
return SHOULD_SWITCH_NATURAL_CURE_WEAK_STATS_RAISED_PERCENTAGE;
case SHOULD_SWITCH_REGENERATOR:
return SHOULD_SWITCH_REGENERATOR_PERCENTAGE;
case SHOULD_SWITCH_REGENERATOR_STATS_RAISED:
return SHOULD_SWITCH_REGENERATOR_STATS_RAISED_PERCENTAGE;
case SHOULD_SWITCH_ENCORE_STATUS:
return SHOULD_SWITCH_ENCORE_STATUS_PERCENTAGE;
case SHOULD_SWITCH_ENCORE_DAMAGE:
return SHOULD_SWITCH_ENCORE_DAMAGE_PERCENTAGE;
case SHOULD_SWITCH_CHOICE_LOCKED:
return SHOULD_SWITCH_CHOICE_LOCKED_PERCENTAGE;
case SHOULD_SWITCH_ATTACKING_STAT_MINUS_TWO:
return SHOULD_SWITCH_ATTACKING_STAT_MINUS_TWO_PERCENTAGE;
case SHOULD_SWITCH_ATTACKING_STAT_MINUS_THREE_PLUS:
return SHOULD_SWITCH_ATTACKING_STAT_MINUS_THREE_PLUS_PERCENTAGE;
default:
return 100;
}
}
u32 GetThinkingBattler(u32 battler)
{
if (AI_DATA->aiSwitchPredictionInProgress)
@ -198,7 +266,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler)
&& gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 4)))
{
// 50% chance to stay in regardless
if (RandomPercentage(RNG_AI_SWITCH_HASBADODDS, 50) && !AI_DATA->aiSwitchPredictionInProgress)
if (RandomPercentage(RNG_AI_SWITCH_HASBADODDS, (100 - GetSwitchChance(SHOULD_SWITCH_HASBADODDS))) && !AI_DATA->aiSwitchPredictionInProgress)
return FALSE;
// Switch mon out
@ -218,7 +286,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler)
return FALSE;
// 50% chance to stay in regardless
if (RandomPercentage(RNG_AI_SWITCH_HASBADODDS, 50) && !AI_DATA->aiSwitchPredictionInProgress)
if (RandomPercentage(RNG_AI_SWITCH_HASBADODDS, (100 - GetSwitchChance(SHOULD_SWITCH_HASBADODDS))) && !AI_DATA->aiSwitchPredictionInProgress)
return FALSE;
// Switch mon out
@ -237,7 +305,8 @@ static bool32 ShouldSwitchIfTruant(u32 battler)
&& gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 2
&& AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE)
{
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
if (RandomPercentage(RNG_AI_SWITCH_TRUANT, GetSwitchChance(SHOULD_SWITCH_TRUANT)))
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
}
return FALSE;
}
@ -271,7 +340,9 @@ static bool32 ShouldSwitchIfAllMovesBad(u32 battler)
}
}
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
if (RandomPercentage(RNG_AI_SWITCH_ALL_MOVES_BAD, GetSwitchChance(SHOULD_SWITCH_ALL_MOVES_BAD)))
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
return FALSE;
}
static bool32 FindMonThatHitsWonderGuard(u32 battler)
@ -320,7 +391,7 @@ static bool32 FindMonThatHitsWonderGuard(u32 battler)
if (move != MOVE_NONE)
{
// Found a mon
if (AI_GetMoveEffectiveness(move, battler, opposingBattler) >= UQ_4_12(2.0))
if (AI_GetMoveEffectiveness(move, battler, opposingBattler) >= UQ_4_12(2.0) && RandomPercentage(RNG_AI_SWITCH_WONDER_GUARD, GetSwitchChance(SHOULD_SWITCH_WONDER_GUARD)))
return SetSwitchinAndSwitch(battler, i);
}
}
@ -351,7 +422,7 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler)
if (gBattleStruct->prevTurnSpecies[battler] != gBattleMons[battler].species) // AI mon has changed, player's behaviour no longer reliable; note to override this if using AI_FLAG_PREDICT_MOVE
return FALSE;
if (HasSuperEffectiveMoveAgainstOpponents(battler, TRUE) && (RandomPercentage(RNG_AI_SWITCH_ABSORBING, 66) || AI_DATA->aiSwitchPredictionInProgress))
if (HasSuperEffectiveMoveAgainstOpponents(battler, TRUE) && (RandomPercentage(RNG_AI_SWITCH_ABSORBING_STAY_IN, STAY_IN_ABSORBING_PERCENTAGE) || AI_DATA->aiSwitchPredictionInProgress))
return FALSE;
if (IsDoubleBattle())
@ -436,7 +507,7 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler)
for (j = 0; j < numAbsorbingAbilities; j++)
{
// Found a mon
if (absorbingTypeAbilities[j] == monAbility)
if (absorbingTypeAbilities[j] == monAbility && RandomPercentage(RNG_AI_SWITCH_ABSORBING, GetSwitchChance(SHOULD_SWITCH_ABSORBS_MOVE)))
return SetSwitchinAndSwitch(battler, i);
}
}
@ -452,7 +523,7 @@ static bool32 ShouldSwitchIfOpponentChargingOrInvulnerable(u32 battler)
if (IsDoubleBattle() || !(AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING))
return FALSE;
if (isOpposingBattlerChargingOrInvulnerable && AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE)
if (isOpposingBattlerChargingOrInvulnerable && AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE && RandomPercentage(RNG_AI_SWITCH_FREE_TURN, GetSwitchChance(SHOULD_SWITCH_FREE_TURN)))
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
return FALSE;
@ -489,7 +560,7 @@ static bool32 ShouldSwitchIfTrapperInParty(u32 battler)
if (CanAbilityTrapOpponent(monAbility, opposingBattler) || (CanAbilityTrapOpponent(AI_GetBattlerAbility(opposingBattler), opposingBattler) && monAbility == ABILITY_TRACE))
{
// If mon in slot i is the most suitable switchin candidate, then it's a trapper than wins 1v1
if (i == AI_DATA->mostSuitableMonId[battler])
if (i == AI_DATA->mostSuitableMonId[battler] && RandomPercentage(RNG_AI_SWITCH_FREE_TURN, GetSwitchChance(SHOULD_SWITCH_FREE_TURN)))
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
}
}
@ -508,15 +579,17 @@ static bool32 ShouldSwitchIfBadlyStatused(u32 battler)
//Perish Song
if (gStatuses3[battler] & STATUS3_PERISH_SONG
&& gDisableStructs[battler].perishSongTimer == 0
&& monAbility != ABILITY_SOUNDPROOF)
switchMon = TRUE;
&& monAbility != ABILITY_SOUNDPROOF
&& RandomPercentage(RNG_AI_SWITCH_PERISH_SONG, GetSwitchChance(SHOULD_SWITCH_PERISH_SONG)))
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)
{
//Yawn
if (gStatuses3[battler] & STATUS3_YAWN
&& CanBeSlept(battler, monAbility, BLOCKED_BY_SLEEP_CLAUSE)
&& gBattleMons[battler].hp > gBattleMons[battler].maxHP / 3)
&& gBattleMons[battler].hp > gBattleMons[battler].maxHP / 3
&& RandomPercentage(RNG_AI_SWITCH_YAWN, GetSwitchChance(SHOULD_SWITCH_YAWN)))
{
switchMon = TRUE;
@ -546,6 +619,9 @@ static bool32 ShouldSwitchIfBadlyStatused(u32 battler)
&& !(gBattleMons[battler].status2 & STATUS2_FORESIGHT)
&& !(gStatuses3[battler] & STATUS3_MIRACLE_EYED))
switchMon = FALSE;
if (switchMon)
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
}
// Secondary Damage
@ -556,35 +632,33 @@ static bool32 ShouldSwitchIfBadlyStatused(u32 battler)
if (((gBattleMons[battler].status1 & STATUS1_TOXIC_COUNTER) >= STATUS1_TOXIC_TURN(2))
&& gBattleMons[battler].hp >= (gBattleMons[battler].maxHP / 3)
&& AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE
&& (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_BADLY_POISONED, 20) : RandomPercentage(RNG_AI_SWITCH_BADLY_POISONED, 50)))
switchMon = TRUE;
&& (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_BADLY_POISONED, GetSwitchChance(SHOULD_SWITCH_BADLY_POISONED_STATS_RAISED)) : RandomPercentage(RNG_AI_SWITCH_BADLY_POISONED, GetSwitchChance(SHOULD_SWITCH_BADLY_POISONED))))
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
//Cursed
if (gBattleMons[battler].status2 & STATUS2_CURSED
&& (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_CURSED, 20) : RandomPercentage(RNG_AI_SWITCH_CURSED, 50)))
switchMon = TRUE;
&& (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_CURSED, GetSwitchChance(SHOULD_SWITCH_CURSED_STATS_RAISED)) : RandomPercentage(RNG_AI_SWITCH_CURSED, GetSwitchChance(SHOULD_SWITCH_CURSED))))
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
//Nightmare
if (gBattleMons[battler].status2 & STATUS2_NIGHTMARE
&& (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_NIGHTMARE, 15) : RandomPercentage(RNG_AI_SWITCH_NIGHTMARE, 33)))
switchMon = TRUE;
&& (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_NIGHTMARE, GetSwitchChance(SHOULD_SWITCH_NIGHTMARE_STATS_RAISED)) : RandomPercentage(RNG_AI_SWITCH_NIGHTMARE, GetSwitchChance(SHOULD_SWITCH_NIGHTMARE))))
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
//Leech Seed
if (gStatuses3[battler] & STATUS3_LEECHSEED
&& (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_SEEDED, 10) : RandomPercentage(RNG_AI_SWITCH_SEEDED, 25)))
switchMon = TRUE;
&& (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_SEEDED, GetSwitchChance(SHOULD_SWITCH_SEEDED_STATS_RAISED)) : RandomPercentage(RNG_AI_SWITCH_SEEDED, GetSwitchChance(SHOULD_SWITCH_SEEDED))))
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
}
// Infatuation
if (gBattleMons[battler].status2 & STATUS2_INFATUATION
&& !AiExpectsToFaintPlayer(battler))
switchMon = TRUE;
&& !AiExpectsToFaintPlayer(battler)
&& RandomPercentage(RNG_AI_SWITCH_INFATUATION, GetSwitchChance(SHOULD_SWITCH_INFATUATION)))
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
}
if (switchMon)
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
else
return FALSE;
return FALSE;
}
static bool32 ShouldSwitchIfAbilityBenefit(u32 battler)
@ -602,13 +676,13 @@ static bool32 ShouldSwitchIfAbilityBenefit(u32 battler)
//Attempt to cure bad ailment
if (gBattleMons[battler].status1 & (STATUS1_SLEEP | STATUS1_FREEZE | STATUS1_TOXIC_POISON)
&& AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE
&& (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_NATURAL_CURE, 10) : RandomPercentage(RNG_AI_SWITCH_NATURAL_CURE, 66)))
&& (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_NATURAL_CURE, GetSwitchChance(SHOULD_SWITCH_NATURAL_CURE_STRONG_STATS_RAISED)) : RandomPercentage(RNG_AI_SWITCH_NATURAL_CURE, GetSwitchChance(SHOULD_SWITCH_NATURAL_CURE_STRONG))))
break;
//Attempt to cure lesser ailment
if ((gBattleMons[battler].status1 & STATUS1_ANY)
&& (gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 2)
&& AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE
&& (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_NATURAL_CURE, 10) : RandomPercentage(RNG_AI_SWITCH_NATURAL_CURE, 25)))
&& (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_NATURAL_CURE, GetSwitchChance(SHOULD_SWITCH_NATURAL_CURE_WEAK_STATS_RAISED)) : RandomPercentage(RNG_AI_SWITCH_NATURAL_CURE, GetSwitchChance(SHOULD_SWITCH_NATURAL_CURE_WEAK))))
break;
return FALSE;
@ -619,7 +693,7 @@ static bool32 ShouldSwitchIfAbilityBenefit(u32 battler)
return FALSE;
if ((gBattleMons[battler].hp <= ((gBattleMons[battler].maxHP * 2) / 3))
&& AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE
&& (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_REGENERATOR, 20) : RandomPercentage(RNG_AI_SWITCH_REGENERATOR, 50)))
&& (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_REGENERATOR, GetSwitchChance(SHOULD_SWITCH_REGENERATOR_STATS_RAISED)) : RandomPercentage(RNG_AI_SWITCH_REGENERATOR, GetSwitchChance(SHOULD_SWITCH_REGENERATOR))))
break;
return FALSE;
@ -858,7 +932,7 @@ static bool32 ShouldSwitchIfEncored(u32 battler)
return FALSE;
// Switch out if status move
if (GetMoveCategory(encoredMove) == DAMAGE_CATEGORY_STATUS)
if (GetMoveCategory(encoredMove) == DAMAGE_CATEGORY_STATUS && RandomPercentage(RNG_AI_SWITCH_ENCORE, GetSwitchChance(SHOULD_SWITCH_ENCORE_STATUS)))
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
// Stay in if effective move
@ -866,7 +940,7 @@ static bool32 ShouldSwitchIfEncored(u32 battler)
return FALSE;
// Switch out 50% of the time otherwise
else if ((RandomPercentage(RNG_AI_SWITCH_ENCORE, 50) || AI_DATA->aiSwitchPredictionInProgress) && AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE)
else if ((RandomPercentage(RNG_AI_SWITCH_ENCORE, GetSwitchChance(SHOULD_SWITCH_ENCORE_DAMAGE)) || AI_DATA->aiSwitchPredictionInProgress) && AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE)
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
return FALSE;
@ -878,7 +952,7 @@ static bool32 ShouldSwitchIfBadChoiceLock(u32 battler)
if (HOLD_EFFECT_CHOICE(holdEffect) && gBattleMons[battler].ability != ABILITY_KLUTZ)
{
if (GetMoveCategory(AI_DATA->lastUsedMove[battler]) == DAMAGE_CATEGORY_STATUS)
if (GetMoveCategory(AI_DATA->lastUsedMove[battler]) == DAMAGE_CATEGORY_STATUS && RandomPercentage(RNG_AI_SWITCH_CHOICE_LOCKED, GetSwitchChance(SHOULD_SWITCH_CHOICE_LOCKED)))
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
}
@ -904,11 +978,11 @@ static bool32 ShouldSwitchIfAttackingStatsLowered(u32 battler)
// 50% chance if attack at -2 and have a good candidate mon
else if (attackingStage == DEFAULT_STAT_STAGE - 2)
{
if (AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE && (RandomPercentage(RNG_AI_SWITCH_STATS_LOWERED, 50) || AI_DATA->aiSwitchPredictionInProgress))
if (AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE && (RandomPercentage(RNG_AI_SWITCH_STATS_LOWERED, GetSwitchChance(SHOULD_SWITCH_ATTACKING_STAT_MINUS_TWO)) || AI_DATA->aiSwitchPredictionInProgress))
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
}
// If at -3 or worse, switch out regardless
else if (attackingStage < DEFAULT_STAT_STAGE - 2)
else if ((attackingStage < DEFAULT_STAT_STAGE - 2) && RandomPercentage(RNG_AI_SWITCH_STATS_LOWERED, GetSwitchChance(SHOULD_SWITCH_ATTACKING_STAT_MINUS_THREE_PLUS)))
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
}
@ -921,11 +995,11 @@ static bool32 ShouldSwitchIfAttackingStatsLowered(u32 battler)
// 50% chance if attack at -2 and have a good candidate mon
else if (spAttackingStage == DEFAULT_STAT_STAGE - 2)
{
if (AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE && (RandomPercentage(RNG_AI_SWITCH_STATS_LOWERED, 50) || AI_DATA->aiSwitchPredictionInProgress))
if (AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE && (RandomPercentage(RNG_AI_SWITCH_STATS_LOWERED, GetSwitchChance(SHOULD_SWITCH_ATTACKING_STAT_MINUS_TWO)) || AI_DATA->aiSwitchPredictionInProgress))
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
}
// If at -3 or worse, switch out regardless
else if (spAttackingStage < DEFAULT_STAT_STAGE - 2)
else if ((spAttackingStage < DEFAULT_STAT_STAGE - 2) && RandomPercentage(RNG_AI_SWITCH_STATS_LOWERED, GetSwitchChance(SHOULD_SWITCH_ATTACKING_STAT_MINUS_THREE_PLUS)))
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
}
return FALSE;

View File

@ -4160,7 +4160,7 @@ void SetupAISwitchingData(u32 battler, enum SwitchType switchType)
gBattleStruct->prevTurnSpecies[opposingBattler] = gBattleMons[opposingBattler].species;
// Determine whether AI will use predictions this turn
AI_DATA->predictingSwitch = RandomPercentage(RNG_AI_PREDICT_SWITCH, 50);
AI_DATA->predictingSwitch = RandomPercentage(RNG_AI_PREDICT_SWITCH, PREDICT_SWITCH_CHANCE);
}
// AI's data

View File

@ -24,6 +24,8 @@ AI_SINGLE_BATTLE_TEST("Choiced Pokémon switch out after using a status move onc
PARAMETRIZE { ability = ABILITY_KLUTZ; heldItem = choiceItems[j]; }
}
PASSES_RANDOMLY(SHOULD_SWITCH_CHOICE_LOCKED_PERCENTAGE, 100, RNG_AI_SWITCH_CHOICE_LOCKED);
GIVEN {
ASSUME(GetMoveCategory(MOVE_YAWN) == DAMAGE_CATEGORY_STATUS);
ASSUME(GetMoveEffect(MOVE_YAWN) == EFFECT_YAWN);

View File

@ -27,18 +27,6 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_PREDICT_SWITCH: AI would switch out in Pursuit sc
}
}
AI_SINGLE_BATTLE_TEST("AI_FLAG_PREDICT_SWITCH: AI would switch out in Wonder Guard scenario")
{
GIVEN {
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES);
PLAYER(SPECIES_SHEDINJA) { Moves(MOVE_PURSUIT, MOVE_CRUNCH); }
OPPONENT(SPECIES_GENGAR) { Moves(MOVE_PSYCHIC); }
OPPONENT(SPECIES_SWELLOW) { Moves(MOVE_PECK); }
} WHEN {
TURN { MOVE(player, MOVE_PURSUIT); EXPECT_SWITCH(opponent, 1); }
}
}
AI_SINGLE_BATTLE_TEST("AI_FLAG_PREDICT_SWITCH: AI will use hit escape moves on predicted switches")
{
PASSES_RANDOMLY(5, 10, RNG_AI_PREDICT_SWITCH);
@ -137,7 +125,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_PREDICT_SWITCH | AI_FLAG_PREDICT_INCOMING_MON: AI
AI_SINGLE_BATTLE_TEST("AI_FLAG_PREDICT_SWITCH: AI would switch out in predicted-incoming-mon scenario")
{
PASSES_RANDOMLY(5, 10, RNG_AI_SWITCH_HASBADODDS);
PASSES_RANDOMLY(SHOULD_SWITCH_HASBADODDS_PERCENTAGE, 100, RNG_AI_SWITCH_HASBADODDS);
GIVEN {
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES);
PLAYER(SPECIES_TYRANITAR) { Moves(MOVE_CRUNCH, MOVE_SPORE); }

View File

@ -24,6 +24,7 @@ AI_SINGLE_BATTLE_TEST("AI gets baited by Protect Switch tactics") // This behavi
// General switching behaviour
AI_SINGLE_BATTLE_TEST("AI switches if Perish Song is about to kill")
{
PASSES_RANDOMLY(SHOULD_SWITCH_PERISH_SONG_PERCENTAGE, 100, RNG_AI_SWITCH_PERISH_SONG);
GIVEN {
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
PLAYER(SPECIES_WOBBUFFET);
@ -46,6 +47,7 @@ AI_DOUBLE_BATTLE_TEST("AI will not try to switch for the same pokemon for 2 spot
PARAMETRIZE {flags = AI_FLAG_SMART_SWITCHING; }
PARAMETRIZE {flags = 0; }
PASSES_RANDOMLY(SHOULD_SWITCH_ALL_MOVES_BAD_PERCENTAGE, 100, RNG_AI_SWITCH_ALL_MOVES_BAD);
GIVEN {
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | flags);
PLAYER(SPECIES_RATTATA);
@ -67,8 +69,22 @@ AI_DOUBLE_BATTLE_TEST("AI will not try to switch for the same pokemon for 2 spot
}
}
AI_SINGLE_BATTLE_TEST("AI will switch out if it has no move that affects the player")
{
PASSES_RANDOMLY(SHOULD_SWITCH_ALL_MOVES_BAD_PERCENTAGE, 100, RNG_AI_SWITCH_ALL_MOVES_BAD);
GIVEN {
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
PLAYER(SPECIES_RATTATA);
OPPONENT(SPECIES_GENGAR) { Moves(MOVE_SHADOW_BALL); }
OPPONENT(SPECIES_RATTATA) { Moves(MOVE_TACKLE); }
} WHEN {
TURN { EXPECT_SWITCH(opponent, 1); }
}
}
AI_DOUBLE_BATTLE_TEST("AI will not try to switch for the same pokemon for 2 spots in a double battle (Wonder Guard)")
{
PASSES_RANDOMLY(SHOULD_SWITCH_WONDER_GUARD_PERCENTAGE, 100, RNG_AI_SWITCH_WONDER_GUARD);
GIVEN {
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING);
PLAYER(SPECIES_SHEDINJA);
@ -430,7 +446,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch in trapping mon m
u32 aiSmartSwitchingFlag = 0;
PARAMETRIZE { aiSmartSwitchingFlag = 0; }
PARAMETRIZE { aiSmartSwitchingFlag = AI_FLAG_SMART_SWITCHING; }
PASSES_RANDOMLY(SHOULD_SWITCH_TRAPPER_PERCENTAGE, 100, RNG_AI_SWITCH_TRAPPER);
GIVEN {
ASSUME(gSpeciesInfo[SPECIES_GOLURK].types[0] == TYPE_GROUND);
ASSUME(gSpeciesInfo[SPECIES_GOLURK].types[1] == TYPE_GHOST);
@ -488,6 +504,7 @@ AI_SINGLE_BATTLE_TEST("AI won't use trapping behaviour if player only has 1 mon
AI_SINGLE_BATTLE_TEST("AI will trap player using Trace if player has a trapper")
{
PASSES_RANDOMLY(SHOULD_SWITCH_TRAPPER_PERCENTAGE, 100, RNG_AI_SWITCH_TRAPPER);
GIVEN {
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING);
PLAYER(SPECIES_DUGTRIO) { Ability(ABILITY_ARENA_TRAP); Moves(MOVE_ROCK_TOMB); }
@ -501,7 +518,7 @@ AI_SINGLE_BATTLE_TEST("AI will trap player using Trace if player has a trapper")
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if mon would be OKHO'd and they have a good switchin 50% of the time")
{
PASSES_RANDOMLY(50, 100, RNG_AI_SWITCH_HASBADODDS);
PASSES_RANDOMLY(SHOULD_SWITCH_HASBADODDS_PERCENTAGE, 100, RNG_AI_SWITCH_HASBADODDS);
GIVEN {
ASSUME(gSpeciesInfo[SPECIES_RHYDON].types[0] == TYPE_GROUND);
ASSUME(gSpeciesInfo[SPECIES_PELIPPER].types[0] == TYPE_WATER);
@ -520,6 +537,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if mon would
AI_SINGLE_BATTLE_TEST("Switch AI: AI will switch out if it can't deal damage to a mon with Wonder Guard")
{
PASSES_RANDOMLY(SHOULD_SWITCH_WONDER_GUARD_PERCENTAGE, 100, RNG_AI_SWITCH_WONDER_GUARD);
GIVEN {
ASSUME(gSpeciesInfo[SPECIES_SHEDINJA].types[0] == TYPE_BUG);
ASSUME(gSpeciesInfo[SPECIES_SHEDINJA].types[1] == TYPE_GHOST);
@ -539,6 +557,7 @@ AI_SINGLE_BATTLE_TEST("Switch AI: AI will switch out if it can't deal damage to
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it can't deal damage to a mon with Wonder Guard")
{
PASSES_RANDOMLY(SHOULD_SWITCH_WONDER_GUARD_PERCENTAGE, 100, RNG_AI_SWITCH_WONDER_GUARD);
GIVEN {
ASSUME(gSpeciesInfo[SPECIES_SHEDINJA].types[0] == TYPE_BUG);
ASSUME(gSpeciesInfo[SPECIES_SHEDINJA].types[1] == TYPE_GHOST);
@ -560,7 +579,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has bee
{
u32 species = SPECIES_NONE, odds = 0;
PARAMETRIZE { species = SPECIES_ZIGZAGOON, odds = 0; }
PARAMETRIZE { species = SPECIES_HARIYAMA, odds = 50; }
PARAMETRIZE { species = SPECIES_HARIYAMA, odds = SHOULD_SWITCH_BADLY_POISONED_PERCENTAGE; }
PASSES_RANDOMLY(odds, 100, RNG_AI_SWITCH_BADLY_POISONED);
GIVEN {
ASSUME(GetMoveEffect(MOVE_TOXIC) == EFFECT_TOXIC);
@ -577,7 +596,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has bee
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has been Curse'd 50% of the time")
{
PASSES_RANDOMLY(50, 100, RNG_AI_SWITCH_CURSED);
PASSES_RANDOMLY(SHOULD_SWITCH_CURSED_PERCENTAGE, 100, RNG_AI_SWITCH_CURSED);
GIVEN {
ASSUME(GetMoveEffect(MOVE_CURSE) == EFFECT_CURSE);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
@ -593,7 +612,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has bee
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has been Nightmare'd 33% of the time")
{
PASSES_RANDOMLY(33, 100, RNG_AI_SWITCH_NIGHTMARE);
PASSES_RANDOMLY(SHOULD_SWITCH_NIGHTMARE_PERCENTAGE, 100, RNG_AI_SWITCH_NIGHTMARE);
GIVEN {
ASSUME(GetMoveEffect(MOVE_NIGHTMARE) == EFFECT_NIGHTMARE);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
@ -608,7 +627,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has bee
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has been Leech Seed'd 25% of the time")
{
PASSES_RANDOMLY(25, 100, RNG_AI_SWITCH_SEEDED);
PASSES_RANDOMLY(SHOULD_SWITCH_SEEDED_PERCENTAGE, 100, RNG_AI_SWITCH_SEEDED);
GIVEN {
ASSUME(GetMoveEffect(MOVE_LEECH_SEED) == EFFECT_LEECH_SEED);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
@ -623,6 +642,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has bee
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has been infatuated")
{
PASSES_RANDOMLY(SHOULD_SWITCH_INFATUATION_PERCENTAGE, 100, RNG_AI_SWITCH_INFATUATION);
GIVEN {
ASSUME(GetMoveEffect(MOVE_ATTRACT) == EFFECT_ATTRACT);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
@ -640,6 +660,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has bee
u32 hp;
PARAMETRIZE { hp = 30; }
PARAMETRIZE { hp = 10; }
PASSES_RANDOMLY(SHOULD_SWITCH_YAWN_PERCENTAGE, 100, RNG_AI_SWITCH_YAWN);
GIVEN {
ASSUME(GetMoveEffect(MOVE_YAWN) == EFFECT_YAWN);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
@ -660,6 +681,7 @@ AI_DOUBLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has bee
u32 hp;
PARAMETRIZE { hp = 30; }
PARAMETRIZE { hp = 10; }
PASSES_RANDOMLY(SHOULD_SWITCH_YAWN_PERCENTAGE, 100, RNG_AI_SWITCH_YAWN);
GIVEN {
ASSUME(GetMoveEffect(MOVE_YAWN) == EFFECT_YAWN);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
@ -680,6 +702,7 @@ AI_DOUBLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has bee
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if player's mon is semi-invulnerable and it has an absorber")
{
PASSES_RANDOMLY(SHOULD_SWITCH_FREE_TURN_PERCENTAGE, 100, RNG_AI_SWITCH_FREE_TURN);
GIVEN {
ASSUME(GetMoveType(MOVE_DIVE) == TYPE_WATER);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
@ -694,7 +717,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if player's m
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has an absorber but current mon has SE move 33% of the time")
{
PASSES_RANDOMLY(33, 100, RNG_AI_SWITCH_ABSORBING);
PASSES_RANDOMLY(33, 100, RNG_AI_SWITCH_ABSORBING_STAY_IN);
GIVEN {
ASSUME(GetMoveType(MOVE_WATER_GUN) == TYPE_WATER);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
@ -709,7 +732,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has an
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if player's mon is charging and it has an absorber")
{
PASSES_RANDOMLY(100, 100, RNG_AI_SWITCH_ABSORBING);
PASSES_RANDOMLY(SHOULD_SWITCH_ABSORBS_MOVE_PERCENTAGE, 100, RNG_AI_SWITCH_ABSORBING);
GIVEN {
ASSUME(GetMoveType(MOVE_SOLAR_BEAM) == TYPE_GRASS);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
@ -724,6 +747,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if player's m
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if player's mon is charging and it has a good switchin immunity (type)")
{
PASSES_RANDOMLY(SHOULD_SWITCH_FREE_TURN_PERCENTAGE, 100, RNG_AI_SWITCH_FREE_TURN);
GIVEN {
ASSUME(GetMoveType(MOVE_DIG) == TYPE_GROUND);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
@ -738,6 +762,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if player's m
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if player's mon is charging and it has a good switchin immunity (ability)")
{
PASSES_RANDOMLY(SHOULD_SWITCH_FREE_TURN_PERCENTAGE, 100, RNG_AI_SWITCH_FREE_TURN);
GIVEN {
ASSUME(GetMoveType(MOVE_DIG) == TYPE_GROUND);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
@ -799,7 +824,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if opponent u
AI_SINGLE_BATTLE_TEST("Switch AI: AI will switch out if badly statused with >= 50% HP remaining and has Natural Cure and a good switchin 66% of the time")
{
PASSES_RANDOMLY(66, 100, RNG_AI_SWITCH_NATURAL_CURE);
PASSES_RANDOMLY(SHOULD_SWITCH_NATURAL_CURE_STRONG_PERCENTAGE, 100, RNG_AI_SWITCH_NATURAL_CURE);
GIVEN {
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
PLAYER(SPECIES_ODDISH) { Moves(MOVE_TOXIC, MOVE_TACKLE); }
@ -813,7 +838,7 @@ AI_SINGLE_BATTLE_TEST("Switch AI: AI will switch out if badly statused with >= 5
AI_SINGLE_BATTLE_TEST("Switch AI: AI will switch out if it has <= 66% HP remaining and has Regenerator and a good switchin 50% of the time")
{
PASSES_RANDOMLY(50, 100, RNG_AI_SWITCH_REGENERATOR);
PASSES_RANDOMLY(SHOULD_SWITCH_REGENERATOR_PERCENTAGE, 100, RNG_AI_SWITCH_REGENERATOR);
GIVEN {
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
PLAYER(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); }
@ -826,6 +851,7 @@ AI_SINGLE_BATTLE_TEST("Switch AI: AI will switch out if it has <= 66% HP remaini
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has been Encore'd into a status move")
{
PASSES_RANDOMLY(SHOULD_SWITCH_ENCORE_STATUS_PERCENTAGE, 100, RNG_AI_SWITCH_ENCORE);
GIVEN {
ASSUME(GetMoveEffect(MOVE_ENCORE) == EFFECT_ENCORE);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
@ -855,7 +881,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will stay in if Encore'd into
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if Encore'd into neutral move with good switchin 50% of the time")
{
KNOWN_FAILING; // AI still switches even if ShouldSwitch is set to immediately return FALSE, something external seems to be triggering this
PASSES_RANDOMLY(50, 100, RNG_AI_SWITCH_ENCORE);
PASSES_RANDOMLY(SHOULD_SWITCH_ENCORE_DAMAGE_PERCENTAGE, 100, RNG_AI_SWITCH_ENCORE);
GIVEN {
ASSUME(GetMoveEffect(MOVE_ENCORE) == EFFECT_ENCORE);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
@ -870,6 +896,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if Encore'd i
AI_SINGLE_BATTLE_TEST("Switch AI: AI will switch out if mon has Truant and opponent has Protect")
{
PASSES_RANDOMLY(SHOULD_SWITCH_TRUANT_PERCENTAGE, 100, RNG_AI_SWITCH_TRUANT);
GIVEN {
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT);
PLAYER(SPECIES_ARON) { Moves(MOVE_TACKLE, MOVE_PROTECT); }
@ -883,6 +910,7 @@ AI_SINGLE_BATTLE_TEST("Switch AI: AI will switch out if mon has Truant and oppon
AI_SINGLE_BATTLE_TEST("Switch AI: AI will switch out if mon has Truant and opponent has invulnerability move and is faster")
{
PASSES_RANDOMLY(SHOULD_SWITCH_TRUANT_PERCENTAGE, 100, RNG_AI_SWITCH_TRUANT);
GIVEN {
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT);
PLAYER(SPECIES_SWELLOW) { Speed(5); Moves(MOVE_FLY); }
@ -898,7 +926,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if main attac
{
u32 aiSpecies = SPECIES_NONE, aiMove = MOVE_NONE, move = MOVE_NONE;
PASSES_RANDOMLY(50, 100, RNG_AI_SWITCH_STATS_LOWERED);
PASSES_RANDOMLY(SHOULD_SWITCH_ATTACKING_STAT_MINUS_TWO_PERCENTAGE, 100, RNG_AI_SWITCH_STATS_LOWERED);
PARAMETRIZE {move = MOVE_CHARM; aiSpecies = SPECIES_FLAREON; aiMove = MOVE_FIRE_FANG; };
PARAMETRIZE {move = MOVE_EERIE_IMPULSE; aiSpecies = SPECIES_ESPEON; aiMove = MOVE_CONFUSION; };
@ -919,7 +947,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if main attac
{
u32 aiSpecies = SPECIES_NONE, aiMove = MOVE_NONE, move = MOVE_NONE, move2 = MOVE_NONE;
PASSES_RANDOMLY(100, 100, RNG_AI_SWITCH_STATS_LOWERED);
PASSES_RANDOMLY(SHOULD_SWITCH_ATTACKING_STAT_MINUS_THREE_PLUS_PERCENTAGE, 100, RNG_AI_SWITCH_STATS_LOWERED);
PARAMETRIZE {move = MOVE_GROWL; move2 = MOVE_CHARM; aiSpecies = SPECIES_FLAREON; aiMove = MOVE_FIRE_FANG; };
PARAMETRIZE {move = MOVE_CONFIDE; move2 = MOVE_EERIE_IMPULSE; aiSpecies = SPECIES_ESPEON; aiMove = MOVE_STORED_POWER; };