Should switch refactor to facilitate switch prediction (#5466)
Co-authored-by: Martin Griffin <martinrgriffin@gmail.com>
This commit is contained in:
parent
afa7ab9b2e
commit
7413d107ae
13 changed files with 589 additions and 462 deletions
|
@ -361,7 +361,7 @@ struct AiLogicData
|
|||
u16 items[MAX_BATTLERS_COUNT];
|
||||
u16 holdEffects[MAX_BATTLERS_COUNT];
|
||||
u8 holdEffectParams[MAX_BATTLERS_COUNT];
|
||||
u16 predictedMoves[MAX_BATTLERS_COUNT];
|
||||
u16 lastUsedMove[MAX_BATTLERS_COUNT];
|
||||
u8 hpPercents[MAX_BATTLERS_COUNT];
|
||||
u16 partnerMove;
|
||||
u16 speedStats[MAX_BATTLERS_COUNT]; // Speed stats for all battles, calculated only once, same way as damages
|
||||
|
|
|
@ -95,7 +95,6 @@ typedef s32 (*AiScoreFunc)(u32, u32, u32, s32);
|
|||
return score; \
|
||||
}
|
||||
|
||||
u32 ComputeBattleAiScores(u32 battler);
|
||||
void BattleAI_SetupItems(void);
|
||||
void BattleAI_SetupFlags(void);
|
||||
void BattleAI_SetupAIData(u8 defaultScoreMoves, u32 battler);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
void GetAIPartyIndexes(u32 battlerId, s32 *firstId, s32 *lastId);
|
||||
void AI_TrySwitchOrUseItem(u32 battler);
|
||||
u32 GetMostSuitableMonToSwitchInto(u32 battler, bool32 switchAfterMonKOd);
|
||||
bool32 ShouldSwitch(u32 battler, bool32 emitResult);
|
||||
bool32 ShouldSwitch(u32 battler);
|
||||
bool32 IsMonGrounded(u16 heldItemEffect, u32 ability, u8 type1, u8 type2);
|
||||
|
||||
#endif // GUARD_BATTLE_AI_SWITCH_ITEMS_H
|
||||
|
|
|
@ -162,11 +162,16 @@ enum RandomTag
|
|||
RNG_FICKLE_BEAM,
|
||||
RNG_AI_ABILITY,
|
||||
RNG_AI_SWITCH_HASBADODDS,
|
||||
RNG_AI_SWITCH_WONDER_GUARD,
|
||||
RNG_AI_SWITCH_BADLY_POISONED,
|
||||
RNG_AI_SWITCH_CURSED,
|
||||
RNG_AI_SWITCH_NIGHTMARE,
|
||||
RNG_AI_SWITCH_SEEDED,
|
||||
RNG_AI_SWITCH_ABSORBING,
|
||||
RNG_AI_SWITCH_NATURAL_CURE,
|
||||
RNG_AI_SWITCH_REGENERATOR,
|
||||
RNG_AI_SWITCH_ENCORE,
|
||||
RNG_AI_SWITCH_STATS_LOWERED,
|
||||
RNG_AI_SWITCH_SE_DEFENSIVE,
|
||||
RNG_SHELL_SIDE_ARM,
|
||||
RNG_RANDOM_TARGET,
|
||||
RNG_HEALER,
|
||||
|
|
|
@ -232,7 +232,6 @@ void BattleAI_SetupFlags(void)
|
|||
}
|
||||
}
|
||||
|
||||
// sBattler_AI set in ComputeBattleAiScores
|
||||
void BattleAI_SetupAIData(u8 defaultScoreMoves, u32 battler)
|
||||
{
|
||||
s32 i;
|
||||
|
@ -287,14 +286,6 @@ u32 BattleAI_ChooseMoveOrAction(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
// damages/other info computed in GetAIDataAndCalcDmg
|
||||
u32 ComputeBattleAiScores(u32 battler)
|
||||
{
|
||||
sBattler_AI = battler;
|
||||
BattleAI_SetupAIData(0xF, sBattler_AI);
|
||||
return BattleAI_ChooseMoveOrAction();
|
||||
}
|
||||
|
||||
static void CopyBattlerDataToAIParty(u32 bPosition, u32 side)
|
||||
{
|
||||
u32 battler = GetBattlerAtPosition(bPosition);
|
||||
|
@ -397,7 +388,7 @@ void SetBattlerAiData(u32 battler, struct AiLogicData *aiData)
|
|||
aiData->items[battler] = gBattleMons[battler].item;
|
||||
holdEffect = aiData->holdEffects[battler] = AI_DecideHoldEffectForTurn(battler);
|
||||
aiData->holdEffectParams[battler] = GetBattlerHoldEffectParam(battler);
|
||||
aiData->predictedMoves[battler] = gLastMoves[battler];
|
||||
aiData->lastUsedMove[battler] = gLastMoves[battler];
|
||||
aiData->hpPercents[battler] = GetHealthPercentage(battler);
|
||||
aiData->moveLimitations[battler] = CheckMoveLimitations(battler, 0, MOVE_LIMITATIONS_ALL);
|
||||
aiData->speedStats[battler] = GetBattlerTotalSpeedStatArgs(battler, ability, holdEffect);
|
||||
|
@ -729,7 +720,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
|||
bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk);
|
||||
u32 i;
|
||||
u32 weather;
|
||||
u32 predictedMove = aiData->predictedMoves[battlerDef];
|
||||
u32 predictedMove = aiData->lastUsedMove[battlerDef];
|
||||
|
||||
if (IS_TARGETING_PARTNER(battlerAtk, battlerDef))
|
||||
return score;
|
||||
|
@ -2661,7 +2652,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
|||
bool32 partnerProtecting = (gMovesInfo[aiData->partnerMove].effect == EFFECT_PROTECT);
|
||||
bool32 attackerHasBadAbility = (gAbilitiesInfo[aiData->abilities[battlerAtk]].aiRating < 0);
|
||||
bool32 partnerHasBadAbility = (gAbilitiesInfo[atkPartnerAbility].aiRating < 0);
|
||||
u32 predictedMove = aiData->predictedMoves[battlerDef];
|
||||
u32 predictedMove = aiData->lastUsedMove[battlerDef];
|
||||
|
||||
SetTypeBeforeUsingMove(move, battlerAtk);
|
||||
moveType = GetMoveType(move);
|
||||
|
@ -3195,7 +3186,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
|||
u32 effectiveness = aiData->effectiveness[battlerAtk][battlerDef][movesetIndex];
|
||||
|
||||
s32 score = 0;
|
||||
u32 predictedMove = aiData->predictedMoves[battlerDef];
|
||||
u32 predictedMove = aiData->lastUsedMove[battlerDef];
|
||||
u32 predictedMoveSlot = GetMoveSlot(GetMovesArray(battlerDef), predictedMove);
|
||||
bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk);
|
||||
u32 i;
|
||||
|
@ -4369,7 +4360,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
|||
break;
|
||||
case EFFECT_MAGNET_RISE:
|
||||
if (IsBattlerGrounded(battlerAtk) && HasDamagingMoveOfType(battlerDef, TYPE_ELECTRIC)
|
||||
&& !(AI_GetTypeEffectiveness(MOVE_EARTHQUAKE, battlerDef, battlerAtk) == AI_EFFECTIVENESS_x0)) // Doesn't resist ground move
|
||||
&& !(AI_GetMoveEffectiveness(MOVE_EARTHQUAKE, battlerDef, battlerAtk) == AI_EFFECTIVENESS_x0)) // Doesn't resist ground move
|
||||
{
|
||||
if (AI_IsFaster(battlerAtk, battlerDef, move)) // Attacker goes first
|
||||
{
|
||||
|
@ -4387,7 +4378,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
|||
break;
|
||||
case EFFECT_CAMOUFLAGE:
|
||||
if (predictedMove != MOVE_NONE && AI_IsFaster(battlerAtk, battlerDef, move) // Attacker goes first
|
||||
&& !IS_MOVE_STATUS(move) && AI_GetTypeEffectiveness(predictedMove, battlerDef, battlerAtk) != AI_EFFECTIVENESS_x0)
|
||||
&& !IS_MOVE_STATUS(move) && AI_GetMoveEffectiveness(predictedMove, battlerDef, battlerAtk) != AI_EFFECTIVENESS_x0)
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
break;
|
||||
case EFFECT_TOXIC_THREAD:
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -3070,10 +3070,7 @@ bool32 AnyPartyMemberStatused(u32 battlerId, bool32 checkSoundproof)
|
|||
struct Pokemon *party;
|
||||
u32 i, battlerOnField1, battlerOnField2;
|
||||
|
||||
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
|
||||
party = gPlayerParty;
|
||||
else
|
||||
party = gEnemyParty;
|
||||
party = GetBattlerParty(battlerId);
|
||||
|
||||
if (IsDoubleBattle())
|
||||
{
|
||||
|
@ -3361,11 +3358,7 @@ bool32 ShouldUseWishAromatherapy(u32 battlerAtk, u32 battlerDef, u32 move)
|
|||
bool32 needHealing = FALSE;
|
||||
|
||||
GetAIPartyIndexes(battlerAtk, &firstId, &lastId);
|
||||
|
||||
if (GetBattlerSide(battlerAtk) == B_SIDE_PLAYER)
|
||||
party = gPlayerParty;
|
||||
else
|
||||
party = gEnemyParty;
|
||||
party = GetBattlerParty(battlerAtk);
|
||||
|
||||
if (CountUsablePartyMons(battlerAtk) == 0
|
||||
&& (CanTargetFaintAi(battlerDef, battlerAtk) || BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->abilities[battlerAtk])))
|
||||
|
@ -3440,20 +3433,27 @@ s32 AI_CalcPartyMonDamage(u32 move, u32 battlerAtk, u32 battlerDef, struct Battl
|
|||
{
|
||||
gBattleMons[battlerAtk] = switchinCandidate;
|
||||
AI_THINKING_STRUCT->saved[battlerDef].saved = TRUE;
|
||||
SetBattlerAiData(battlerDef, AI_DATA); // set known opposing battler data
|
||||
SetBattlerAiData(battlerAtk, AI_DATA); // set known opposing battler data
|
||||
AI_THINKING_STRUCT->saved[battlerDef].saved = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
gBattleMons[battlerDef] = switchinCandidate;
|
||||
AI_THINKING_STRUCT->saved[battlerAtk].saved = TRUE;
|
||||
SetBattlerAiData(battlerAtk, AI_DATA); // set known opposing battler data
|
||||
SetBattlerAiData(battlerDef, AI_DATA); // set known opposing battler data
|
||||
AI_THINKING_STRUCT->saved[battlerAtk].saved = FALSE;
|
||||
}
|
||||
|
||||
|
||||
dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, FALSE, AI_GetWeather(AI_DATA), rollType);
|
||||
// restores original gBattleMon struct
|
||||
FreeRestoreBattleMons(savedBattleMons);
|
||||
|
||||
if (isPartyMonAttacker)
|
||||
SetBattlerAiData(battlerAtk, AI_DATA);
|
||||
else
|
||||
SetBattlerAiData(battlerDef, AI_DATA);
|
||||
|
||||
return dmg.expected;
|
||||
}
|
||||
|
||||
|
@ -3473,11 +3473,7 @@ s32 CountUsablePartyMons(u32 battlerId)
|
|||
{
|
||||
s32 battlerOnField1, battlerOnField2, i, ret;
|
||||
struct Pokemon *party;
|
||||
|
||||
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
|
||||
party = gPlayerParty;
|
||||
else
|
||||
party = gEnemyParty;
|
||||
party = GetBattlerParty(battlerId);
|
||||
|
||||
if (IsDoubleBattle())
|
||||
{
|
||||
|
@ -3509,11 +3505,7 @@ bool32 IsPartyFullyHealedExceptBattler(u32 battlerId)
|
|||
{
|
||||
struct Pokemon *party;
|
||||
u32 i;
|
||||
|
||||
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
|
||||
party = gPlayerParty;
|
||||
else
|
||||
party = gEnemyParty;
|
||||
party = GetBattlerParty(battlerId);
|
||||
|
||||
for (i = 0; i < PARTY_SIZE; i++)
|
||||
{
|
||||
|
|
|
@ -4209,20 +4209,25 @@ static void HandleTurnActionSelectionState(void)
|
|||
case STATE_TURN_START_RECORD: // Recorded battle related action on start of every turn.
|
||||
RecordedBattle_CopyBattlerMoves(battler);
|
||||
gBattleCommunication[battler] = STATE_BEFORE_ACTION_CHOSEN;
|
||||
u32 isAiRisky = AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_RISKY; // Risky AI switches aggressively even mid battle
|
||||
|
||||
// Do AI score computations here so we can use them in AI_TrySwitchOrUseItem
|
||||
if ((gBattleTypeFlags & BATTLE_TYPE_HAS_AI || IsWildMonSmart())
|
||||
&& (BattlerHasAi(battler) && !(gBattleTypeFlags & BATTLE_TYPE_PALACE)))
|
||||
{
|
||||
AI_DATA->aiCalcInProgress = TRUE;
|
||||
if (ShouldSwitch(battler, FALSE))
|
||||
AI_DATA->shouldSwitch |= (1u << battler);
|
||||
if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_RISKY) // Risky AI switches aggressively even mid battle
|
||||
AI_DATA->mostSuitableMonId[battler] = GetMostSuitableMonToSwitchInto(battler, TRUE);
|
||||
else
|
||||
AI_DATA->mostSuitableMonId[battler] = GetMostSuitableMonToSwitchInto(battler, FALSE);
|
||||
|
||||
gBattleStruct->aiMoveOrAction[battler] = ComputeBattleAiScores(battler);
|
||||
// Setup battler data
|
||||
sBattler_AI = battler;
|
||||
BattleAI_SetupAIData(0xF, sBattler_AI);
|
||||
|
||||
// Setup switching data
|
||||
AI_DATA->mostSuitableMonId[battler] = GetMostSuitableMonToSwitchInto(battler, isAiRisky);
|
||||
if (ShouldSwitch(battler))
|
||||
AI_DATA->shouldSwitch |= (1u << battler);
|
||||
|
||||
// Do scoring
|
||||
gBattleStruct->aiMoveOrAction[battler] = BattleAI_ChooseMoveOrAction();
|
||||
AI_DATA->aiCalcInProgress = FALSE;
|
||||
}
|
||||
// fallthrough
|
||||
|
|
|
@ -1353,11 +1353,7 @@ u8 GetBattlerMoveSlotId(u8 battlerId, u16 moveId)
|
|||
{
|
||||
s32 i;
|
||||
struct Pokemon *party;
|
||||
|
||||
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
|
||||
party = gPlayerParty;
|
||||
else
|
||||
party = gEnemyParty;
|
||||
party = GetBattlerParty(battlerId);
|
||||
|
||||
i = 0;
|
||||
while (1)
|
||||
|
|
|
@ -739,6 +739,7 @@ AI_SINGLE_BATTLE_TEST("AI calculates guaranteed criticals and detects critical i
|
|||
|
||||
AI_DOUBLE_BATTLE_TEST("AI recognizes Volt Absorb received from Trace")
|
||||
{
|
||||
KNOWN_FAILING; // MGriffin's PR that switched two turn charging moves in AI tests broke this test, waiting on a fix
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
|
||||
PLAYER(SPECIES_MAGNETON);
|
||||
|
|
|
@ -68,7 +68,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_RISKY: Mid-battle switches prioritize offensive o
|
|||
PLAYER(SPECIES_SWELLOW) { Level(30); Moves(MOVE_WING_ATTACK, MOVE_BOOMBURST); Speed(5); }
|
||||
OPPONENT(SPECIES_PONYTA) { Level(1); Moves(MOVE_NONE); Speed(4); } // Forces switchout
|
||||
OPPONENT(SPECIES_ARON) { Level(30); Moves(MOVE_HEADBUTT); Speed(4); SpDefense(41); } // Mid battle, AI sends out Aron
|
||||
OPPONENT(SPECIES_ELECTRODE) { Level(30); Moves(MOVE_CHARGE_BEAM); Speed(6); }
|
||||
OPPONENT(SPECIES_ELECTRODE) { Level(30); Moves(MOVE_CHARGE_BEAM); Speed(6); Ability(ABILITY_STATIC); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_WING_ATTACK); EXPECT_SWITCH(opponent, aiRiskyFlag? 2 : 1); }
|
||||
}
|
||||
|
|
|
@ -473,12 +473,14 @@ 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 66% of the time")
|
||||
AI_SINGLE_BATTLE_TEST("Switch AI: AI will switch out if it can't deal damage to a mon with Wonder Guard")
|
||||
{
|
||||
PASSES_RANDOMLY(66, 100, RNG_AI_SWITCH_WONDER_GUARD);
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_SHEDINJA].types[0] == TYPE_BUG);
|
||||
ASSUME(gSpeciesInfo[SPECIES_SHEDINJA].types[1] == TYPE_GHOST);
|
||||
ASSUME(gSpeciesInfo[SPECIES_SHEDINJA].abilities[0] == ABILITY_WONDER_GUARD);
|
||||
ASSUME(gSpeciesInfo[SPECIES_SHEDINJA].abilities[1] == ABILITY_NONE);
|
||||
ASSUME(gSpeciesInfo[SPECIES_SHEDINJA].abilities[2] == ABILITY_NONE);
|
||||
ASSUME(gMovesInfo[MOVE_TACKLE].type == TYPE_NORMAL);
|
||||
ASSUME(gMovesInfo[MOVE_SHADOW_BALL].type == TYPE_GHOST);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
|
||||
|
@ -490,9 +492,8 @@ 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 100% of the time")
|
||||
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(100, 100, RNG_AI_SWITCH_WONDER_GUARD);
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_SHEDINJA].types[0] == TYPE_BUG);
|
||||
ASSUME(gSpeciesInfo[SPECIES_SHEDINJA].types[1] == TYPE_GHOST);
|
||||
|
@ -510,19 +511,22 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it can't d
|
|||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has been Toxic'd for at least two turns 50% of the time with more than 1/3 HP remaining")
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has been Toxic'd for at least two turns 50% of the time with more than 1/3 HP remaining with good switchin")
|
||||
{
|
||||
PASSES_RANDOMLY(50, 100, RNG_AI_SWITCH_BADLY_POISONED);
|
||||
u32 species = SPECIES_NONE, odds = 0;
|
||||
PARAMETRIZE { species = SPECIES_ZIGZAGOON, odds = 0; }
|
||||
PARAMETRIZE { species = SPECIES_HARIYAMA, odds = 50; }
|
||||
PASSES_RANDOMLY(odds, 100, RNG_AI_SWITCH_BADLY_POISONED);
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
|
||||
PLAYER(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE, MOVE_CELEBRATE, MOVE_TOXIC); }
|
||||
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); }
|
||||
PLAYER(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE, MOVE_CELEBRATE, MOVE_TOXIC, MOVE_AURA_SPHERE); }
|
||||
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); }
|
||||
OPPONENT(species) { Moves(MOVE_ROCK_SMASH); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TOXIC); EXPECT_MOVE(opponent, MOVE_TACKLE); }
|
||||
TURN { MOVE(player, MOVE_TACKLE); EXPECT_MOVE(opponent, MOVE_TACKLE); }
|
||||
TURN { MOVE(player, MOVE_TACKLE); EXPECT_SWITCH(opponent, 1); }
|
||||
TURN { MOVE(player, MOVE_AURA_SPHERE); EXPECT_MOVE(opponent, MOVE_TACKLE); }
|
||||
TURN { MOVE(player, MOVE_AURA_SPHERE); EXPECT_SWITCH(opponent, 1); }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -571,3 +575,322 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has bee
|
|||
TURN { MOVE(player, MOVE_LEECH_SEED); EXPECT_SWITCH(opponent, 1); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has been infatuated")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_ATTRACT].effect == EFFECT_ATTRACT);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
|
||||
PLAYER(SPECIES_LUVDISC) { Moves(MOVE_ATTRACT); Gender(MON_FEMALE); }
|
||||
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); Gender(MON_MALE); }
|
||||
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); Gender(MON_MALE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_ATTRACT) ; EXPECT_MOVE(opponent, MOVE_TACKLE); }
|
||||
TURN { MOVE(player, MOVE_ATTRACT) ; EXPECT_SWITCH(opponent, 1); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has been Yawn'd with more than 1/3 HP remaining")
|
||||
{
|
||||
u32 hp;
|
||||
PARAMETRIZE { hp = 30; }
|
||||
PARAMETRIZE { hp = 10; }
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_YAWN].effect == EFFECT_YAWN);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
|
||||
PLAYER(SPECIES_SLAKOTH) { Moves(MOVE_TACKLE, MOVE_YAWN); }
|
||||
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); HP(hp); MaxHP(30); }
|
||||
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_YAWN) ; EXPECT_MOVE(opponent, MOVE_TACKLE); }
|
||||
if (hp == 30)
|
||||
TURN { MOVE(player, MOVE_YAWN) ; EXPECT_SWITCH(opponent, 1); }
|
||||
else
|
||||
TURN { MOVE(player, MOVE_YAWN) ; EXPECT_MOVE(opponent, MOVE_TACKLE); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_DOUBLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has been Yawn'd with more than 1/3 HP remaining (Doubles)")
|
||||
{
|
||||
u32 hp;
|
||||
PARAMETRIZE { hp = 30; }
|
||||
PARAMETRIZE { hp = 10; }
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_YAWN].effect == EFFECT_YAWN);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
|
||||
PLAYER(SPECIES_SLAKOTH) { Moves(MOVE_TACKLE, MOVE_CELEBRATE, MOVE_YAWN); }
|
||||
PLAYER(SPECIES_SLAKOTH) { Moves(MOVE_TACKLE, MOVE_CELEBRATE, MOVE_YAWN); }
|
||||
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); HP(hp); MaxHP(30); }
|
||||
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_YAWN, target: opponentLeft); MOVE(playerRight, MOVE_CELEBRATE, target: opponentLeft); }
|
||||
if (hp == 30)
|
||||
TURN { MOVE(playerLeft, MOVE_YAWN, target: opponentLeft); MOVE(playerRight, MOVE_CELEBRATE, target: opponentLeft); EXPECT_SWITCH(opponentLeft, 2); }
|
||||
else
|
||||
TURN { MOVE(playerLeft, MOVE_YAWN, target: opponentLeft); MOVE(playerRight, MOVE_CELEBRATE, target: opponentLeft); EXPECT_MOVE(opponentLeft, MOVE_TACKLE); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if player's mon is semi-invulnerable and it has an absorber")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_DIVE].type == TYPE_WATER);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
|
||||
PLAYER(SPECIES_LUVDISC) { Moves(MOVE_DIVE); }
|
||||
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_MANTINE) { Moves(MOVE_TACKLE); Ability(ABILITY_WATER_ABSORB); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_DIVE) ; EXPECT_MOVE(opponent, MOVE_TACKLE); }
|
||||
TURN { SKIP_TURN(player); EXPECT_SWITCH(opponent, 1); }
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_WATER_GUN].type == TYPE_WATER);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
|
||||
PLAYER(SPECIES_LUVDISC) { Moves(MOVE_WATER_GUN); }
|
||||
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_SHOCK_WAVE); }
|
||||
OPPONENT(SPECIES_MANTINE) { Moves(MOVE_TACKLE); Ability(ABILITY_WATER_ABSORB); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_WATER_GUN) ; EXPECT_MOVE(opponent, MOVE_SHOCK_WAVE); }
|
||||
TURN { MOVE(player, MOVE_WATER_GUN) ; EXPECT_SWITCH(opponent, 1); }
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_SOLAR_BEAM].type == TYPE_GRASS);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
|
||||
PLAYER(SPECIES_BELLOSSOM) { Moves(MOVE_SOLAR_BEAM); }
|
||||
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_AZUMARILL) { Moves(MOVE_PLAY_ROUGH); Ability(ABILITY_SAP_SIPPER); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SOLAR_BEAM) ; EXPECT_MOVE(opponent, MOVE_TACKLE); }
|
||||
TURN { SKIP_TURN(player); EXPECT_SWITCH(opponent, 1); }
|
||||
}
|
||||
}
|
||||
|
||||
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)")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_DIG].type == TYPE_GROUND);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
|
||||
PLAYER(SPECIES_SANDSHREW) { Moves(MOVE_DIG); }
|
||||
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_SWELLOW) { Moves(MOVE_WING_ATTACK); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_DIG) ; EXPECT_MOVE(opponent, MOVE_TACKLE); }
|
||||
TURN { SKIP_TURN(player); EXPECT_SWITCH(opponent, 1); }
|
||||
}
|
||||
}
|
||||
|
||||
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)")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_DIG].type == TYPE_GROUND);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
|
||||
PLAYER(SPECIES_SANDSHREW) { Moves(MOVE_DIG); }
|
||||
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_BRONZONG) { Moves(MOVE_PSYCHIC); Ability(ABILITY_LEVITATE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_DIG) ; EXPECT_MOVE(opponent, MOVE_TACKLE); }
|
||||
TURN { SKIP_TURN(player); EXPECT_SWITCH(opponent, 1); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has an absorber")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_WATER_GUN].type == TYPE_WATER);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
|
||||
PLAYER(SPECIES_LUVDISC) { Moves(MOVE_WATER_GUN); }
|
||||
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_MANTINE) { Moves(MOVE_TACKLE); Ability(ABILITY_WATER_ABSORB); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_WATER_GUN) ; EXPECT_MOVE(opponent, MOVE_TACKLE); }
|
||||
TURN { MOVE(player, MOVE_WATER_GUN) ; EXPECT_SWITCH(opponent, 1); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if opponent uses two-turn move and it has a switchin that wins 1v1")
|
||||
{
|
||||
u32 move;
|
||||
PARAMETRIZE { move = MOVE_SKY_ATTACK; }
|
||||
PARAMETRIZE { move = MOVE_FLY; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_FLY].effect == EFFECT_SEMI_INVULNERABLE);
|
||||
ASSUME(gMovesInfo[MOVE_SKY_ATTACK].effect == EFFECT_TWO_TURNS_ATTACK);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
|
||||
PLAYER(SPECIES_SWELLOW) { Moves(move); }
|
||||
OPPONENT(SPECIES_MILOTIC) { Moves(MOVE_SURF); }
|
||||
OPPONENT(SPECIES_LAIRON) { Moves(MOVE_ROCK_SLIDE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, move); EXPECT_MOVE(opponent, MOVE_SURF); }
|
||||
TURN { SKIP_TURN(player); EXPECT_SWITCH(opponent, 1); }
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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); }
|
||||
OPPONENT(SPECIES_SWABLU) { Ability(ABILITY_NATURAL_CURE); Moves(MOVE_TACKLE, MOVE_PECK); }
|
||||
OPPONENT(SPECIES_SWABLU) { Ability(ABILITY_NATURAL_CURE); Moves(MOVE_TACKLE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TOXIC); EXPECT_MOVE(opponent, MOVE_PECK); }
|
||||
TURN { MOVE(player, MOVE_TACKLE); EXPECT_SWITCH(opponent, 1); }
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
|
||||
PLAYER(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_SLOWBRO) { MaxHP(100); HP(65); Ability(ABILITY_REGENERATOR); Moves(MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_SLOWBRO) { Ability(ABILITY_REGENERATOR); Moves(MOVE_TACKLE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TACKLE); EXPECT_SWITCH(opponent, 1); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has been Encore'd into a status move")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_ENCORE].effect == EFFECT_ENCORE);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
|
||||
PLAYER(SPECIES_AZURILL) { Moves(MOVE_TACKLE, MOVE_ENCORE); }
|
||||
OPPONENT(SPECIES_ODDISH) { Moves(MOVE_TOXIC, MOVE_SWEET_SCENT, MOVE_INGRAIN, MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_ARON) { Moves(MOVE_METAL_CLAW); }
|
||||
} WHEN {
|
||||
TURN { EXPECT_MOVE(opponent, MOVE_TOXIC); MOVE(player, MOVE_ENCORE); }
|
||||
TURN { MOVE(player, MOVE_ENCORE); EXPECT_SWITCH(opponent, 1); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will stay in if Encore'd into super effective move")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_ENCORE].effect == EFFECT_ENCORE);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
|
||||
PLAYER(SPECIES_AZURILL) { Moves(MOVE_TACKLE, MOVE_ENCORE); }
|
||||
OPPONENT(SPECIES_ODDISH) { Moves(MOVE_ACID); }
|
||||
OPPONENT(SPECIES_ARON) { Moves(MOVE_METAL_CLAW); }
|
||||
} WHEN {
|
||||
TURN { EXPECT_MOVE(opponent, MOVE_ACID); MOVE(player, MOVE_ENCORE); }
|
||||
TURN { EXPECT_MOVE(opponent, MOVE_ACID); MOVE(player, MOVE_TACKLE); }
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_ENCORE].effect == EFFECT_ENCORE);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
|
||||
PLAYER(SPECIES_AZURILL) { Moves(MOVE_TACKLE, MOVE_ENCORE); }
|
||||
OPPONENT(SPECIES_ODDISH) { Moves(MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_ARON) { Moves(MOVE_METAL_CLAW); }
|
||||
} WHEN {
|
||||
TURN { EXPECT_MOVE(opponent, MOVE_TACKLE); MOVE(player, MOVE_ENCORE); }
|
||||
TURN { MOVE(player, MOVE_TACKLE); EXPECT_SWITCH(opponent, 1); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("Switch AI: AI will switch out if mon has Truant and opponent has Protect")
|
||||
{
|
||||
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); }
|
||||
OPPONENT(SPECIES_SLAKING) { Ability(ABILITY_TRUANT); Moves(MOVE_BRICK_BREAK); }
|
||||
OPPONENT(SPECIES_ARON) { Moves(MOVE_TACKLE); }
|
||||
} WHEN {
|
||||
TURN { EXPECT_MOVE(opponent, MOVE_BRICK_BREAK); MOVE(player, MOVE_PROTECT); }
|
||||
TURN { EXPECT_SWITCH(opponent, 1); MOVE(player, MOVE_TACKLE); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("Switch AI: AI will switch out if mon has Truant and opponent has invulnerability move and is faster")
|
||||
{
|
||||
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); }
|
||||
OPPONENT(SPECIES_SLAKING) { Speed(4); Ability(ABILITY_TRUANT); Moves(MOVE_ROCK_SLIDE); }
|
||||
OPPONENT(SPECIES_ARON) { Speed(4); Moves(MOVE_TACKLE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_FLY); EXPECT_MOVE(opponent, MOVE_ROCK_SLIDE); }
|
||||
TURN { SKIP_TURN(player); EXPECT_SWITCH(opponent, 1); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if main attacking stat lowered by 2 stages with good switchin candidate 50% of the time")
|
||||
{
|
||||
u32 aiSpecies = SPECIES_NONE, aiMove = MOVE_NONE, move = MOVE_NONE;
|
||||
|
||||
PASSES_RANDOMLY(50, 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; };
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_CHARM].effect == EFFECT_ATTACK_DOWN_2);
|
||||
ASSUME(gMovesInfo[MOVE_EERIE_IMPULSE].effect == EFFECT_SPECIAL_ATTACK_DOWN_2);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
|
||||
PLAYER(SPECIES_ARON) { Moves(move, MOVE_TACKLE); }
|
||||
OPPONENT(aiSpecies) { Moves(aiMove); }
|
||||
OPPONENT(SPECIES_MILOTIC) { Moves(MOVE_SURF); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, move); EXPECT_MOVE(opponent, aiMove); }
|
||||
TURN { MOVE(player, MOVE_TACKLE); EXPECT_SWITCH(opponent, 1); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if main attacking stat lowered by 3+ stages")
|
||||
{
|
||||
u32 aiSpecies = SPECIES_NONE, aiMove = MOVE_NONE, move = MOVE_NONE, move2 = MOVE_NONE;
|
||||
|
||||
PASSES_RANDOMLY(100, 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; };
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_CHARM].effect == EFFECT_ATTACK_DOWN_2);
|
||||
ASSUME(gMovesInfo[MOVE_EERIE_IMPULSE].effect == EFFECT_SPECIAL_ATTACK_DOWN_2);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
|
||||
PLAYER(SPECIES_ARON) { Moves(move, move2, MOVE_TACKLE); }
|
||||
OPPONENT(aiSpecies) { Moves(aiMove); }
|
||||
OPPONENT(SPECIES_MILOTIC) { Moves(MOVE_SURF); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, move); EXPECT_MOVE(opponent, aiMove); }
|
||||
TURN { MOVE(player, move2); EXPECT_MOVE(opponent, aiMove); }
|
||||
TURN { MOVE(player, MOVE_TACKLE); EXPECT_SWITCH(opponent, 1); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("Switch AI: AI will switch into mon with good type matchup and SE move if current mon has no SE move and no stats raised")
|
||||
{
|
||||
u32 odds = 0, species = SPECIES_NONE, move = MOVE_NONE;
|
||||
PARAMETRIZE { odds = 33; species = SPECIES_SCIZOR; move = MOVE_X_SCISSOR; }
|
||||
PARAMETRIZE { odds = 50; species = SPECIES_DUSCLOPS; move = MOVE_SHADOW_BALL; }
|
||||
PASSES_RANDOMLY(odds, 100, RNG_AI_SWITCH_SE_DEFENSIVE);
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
|
||||
PLAYER(SPECIES_MUNNA) { Moves(MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_MUNNA) { Moves(MOVE_TACKLE); }
|
||||
OPPONENT(species) { Moves(move); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TACKLE); EXPECT_MOVE(opponent, MOVE_TACKLE); }
|
||||
TURN { MOVE(player, MOVE_TACKLE); EXPECT_SWITCH(opponent, 1); }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -780,6 +780,8 @@ void TestRunner_Battle_CheckChosenMove(u32 battlerId, u32 moveId, u32 target)
|
|||
if (!expectedAction->actionSet)
|
||||
return;
|
||||
|
||||
DATA.trial.lastActionTurn = gBattleResults.battleTurnCounter;
|
||||
|
||||
if (!expectedAction->pass)
|
||||
{
|
||||
u32 i, expectedMoveId = 0, countExpected;
|
||||
|
@ -849,6 +851,8 @@ void TestRunner_Battle_CheckSwitch(u32 battlerId, u32 partyIndex)
|
|||
if (!expectedAction->actionSet)
|
||||
return;
|
||||
|
||||
DATA.trial.lastActionTurn = gBattleResults.battleTurnCounter;
|
||||
|
||||
if (!expectedAction->pass)
|
||||
{
|
||||
if (expectedAction->type != B_ACTION_SWITCH)
|
||||
|
|
Loading…
Reference in a new issue