Skip to content

Commit

Permalink
ShouldSwitchIfGameStatePrompt Tests (#5462)
Browse files Browse the repository at this point in the history
* Weird tests plz help <3

* better RNG tag names?

* DATA.trial for data to reset between trials

* Fix Wonder Guard test

* Unused errors

* Finish new tests

* Split fix into its own PR

* Spacing

* Rename RNG_AI_SWITCH_TOXICD

* Forgot to save file lol

---------

Co-authored-by: Martin Griffin <[email protected]>
  • Loading branch information
Pawkkie and mrgriffin authored Oct 11, 2024
1 parent d7c5bfe commit 464c90a
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 16 deletions.
4 changes: 4 additions & 0 deletions include/random.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ enum RandomTag
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_SHELL_SIDE_ARM,
};

Expand Down
24 changes: 8 additions & 16 deletions src/battle_ai_switch_items.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ static bool32 HasBadOdds(u32 battler, bool32 emitResult)
&& gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 4)))
{
// 50% chance to stay in regardless
if (!RandomPercentage(RNG_AI_SWITCH_HASBADODDS, 50))
if (RandomPercentage(RNG_AI_SWITCH_HASBADODDS, 50))
return FALSE;

// Switch mon out
Expand All @@ -203,7 +203,7 @@ static bool32 HasBadOdds(u32 battler, bool32 emitResult)
return FALSE;

// 50% chance to stay in regardless
if (!RandomPercentage(RNG_AI_SWITCH_HASBADODDS, 50))
if (RandomPercentage(RNG_AI_SWITCH_HASBADODDS, 50))
return FALSE;

// Switch mon out
Expand Down Expand Up @@ -462,16 +462,12 @@ static bool32 ShouldSwitchIfGameStatePrompt(u32 battler, bool32 emitResult)
u16 holdEffect = AI_DATA->holdEffects[battler];
u8 opposingPosition = BATTLE_OPPOSITE(GetBattlerPosition(battler));
u8 opposingBattler = GetBattlerAtPosition(opposingPosition);
s32 moduloChance = 4; //25% Chance Default
s32 chanceReducer = 1; //No Reduce default. Increase to reduce
bool32 hasStatRaised = AnyStatIsRaised(battler);
s32 firstId;
s32 lastId;
s32 i;
struct Pokemon *party;

if (AnyStatIsRaised(battler))
chanceReducer = 5; // Reduce switchout probability by factor of 5 if setup

//Perish Song
if (gStatuses3[battler] & STATUS3_PERISH_SONG
&& gDisableStructs[battler].perishSongTimer == 0
Expand Down Expand Up @@ -567,28 +563,24 @@ static bool32 ShouldSwitchIfGameStatePrompt(u32 battler, bool32 emitResult)
&& !AiExpectsToFaintPlayer(battler))
{
//Toxic
moduloChance = 2; //50%
if (((gBattleMons[battler].status1 & STATUS1_TOXIC_COUNTER) >= STATUS1_TOXIC_TURN(2))
&& gBattleMons[battler].hp >= (gBattleMons[battler].maxHP / 3)
&& (Random() % (moduloChance*chanceReducer)) == 0)
&& (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_BADLY_POISONED, 20) : RandomPercentage(RNG_AI_SWITCH_BADLY_POISONED, 50)))
switchMon = TRUE;

//Cursed
moduloChance = 2; //50%
if (gBattleMons[battler].status2 & STATUS2_CURSED
&& (Random() % (moduloChance*chanceReducer)) == 0)
&& (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_CURSED, 20) : RandomPercentage(RNG_AI_SWITCH_CURSED, 50)))
switchMon = TRUE;

//Nightmare
moduloChance = 3; //33.3%
if (gBattleMons[battler].status2 & STATUS2_NIGHTMARE
&& (Random() % (moduloChance*chanceReducer)) == 0)
&& (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_NIGHTMARE, 15) : RandomPercentage(RNG_AI_SWITCH_NIGHTMARE, 33)))
switchMon = TRUE;

//Leech Seed
moduloChance = 4; //25%
if (gStatuses3[battler] & STATUS3_LEECHSEED
&& (Random() % (moduloChance*chanceReducer)) == 0)
&& (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_SEEDED, 10) : RandomPercentage(RNG_AI_SWITCH_SEEDED, 25)))
switchMon = TRUE;
}

Expand All @@ -606,7 +598,7 @@ static bool32 ShouldSwitchIfGameStatePrompt(u32 battler, bool32 emitResult)
if (FindMonThatAbsorbsOpponentsMove(battler, FALSE)) // Switch if absorber found. Note: FindMonThatAbsorbsOpponentsMove already provides id of the mon to switch into to gBattleStruct->AI_monToSwitchIntoId.
switchMon = TRUE, monIdChosen = TRUE;
if (!AI_OpponentCanFaintAiWithMod(battler, 0)
&& AnyStatIsRaised(battler))
&& hasStatRaised)
switchMon = FALSE;
if (AiExpectsToFaintPlayer(battler)
&& AI_IsSlower(battler, opposingBattler, 0)
Expand Down
62 changes: 62 additions & 0 deletions test/battle/ai/ai_switching.c
Original file line number Diff line number Diff line change
Expand Up @@ -486,3 +486,65 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it can't d
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 Toxic'd for at least two turns 50% of the time with more than 1/3 HP remaining")
{
PASSES_RANDOMLY(50, 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); }
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); }
} 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); }
}
}

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);
GIVEN {
ASSUME(gMovesInfo[MOVE_CURSE].effect == EFFECT_CURSE);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
PLAYER(SPECIES_DUSCLOPS) { Moves(MOVE_FIRE_PUNCH, MOVE_CURSE); }
PLAYER(SPECIES_MILOTIC) { Moves(MOVE_WATER_GUN); }
OPPONENT(SPECIES_DUSCLOPS) { Moves(MOVE_SHADOW_BALL); }
OPPONENT(SPECIES_DUSCLOPS) { Moves(MOVE_SHADOW_BALL); }
} WHEN {
TURN { MOVE(player, MOVE_CURSE) ; EXPECT_MOVE(opponent, MOVE_SHADOW_BALL); }
TURN { MOVE(player, MOVE_FIRE_PUNCH); EXPECT_SWITCH(opponent, 1); }
}
}

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);
GIVEN {
ASSUME(gMovesInfo[MOVE_NIGHTMARE].effect == EFFECT_NIGHTMARE);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
PLAYER(SPECIES_GENGAR) { Moves(MOVE_NIGHTMARE); }
OPPONENT(SPECIES_DUSCLOPS) { Moves(MOVE_SHADOW_BALL); Status1(STATUS1_SLEEP); }
OPPONENT(SPECIES_DUSCLOPS) { Moves(MOVE_SHADOW_BALL); }
} WHEN {
TURN { MOVE(player, MOVE_NIGHTMARE) ; EXPECT_MOVE(opponent, MOVE_SHADOW_BALL); }
TURN { MOVE(player, MOVE_NIGHTMARE) ; EXPECT_SWITCH(opponent, 1); }
}
}

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);
GIVEN {
ASSUME(gMovesInfo[MOVE_LEECH_SEED].effect == EFFECT_LEECH_SEED);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
PLAYER(SPECIES_WHIMSICOTT) { Moves(MOVE_LEECH_SEED); }
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); }
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); }
} WHEN {
TURN { MOVE(player, MOVE_LEECH_SEED) ; EXPECT_MOVE(opponent, MOVE_TACKLE); }
TURN { MOVE(player, MOVE_LEECH_SEED); EXPECT_SWITCH(opponent, 1); }
}
}

0 comments on commit 464c90a

Please sign in to comment.