diff --git a/include/random.h b/include/random.h index cb4e636e14..cd7e26b589 100644 --- a/include/random.h +++ b/include/random.h @@ -197,6 +197,7 @@ enum RandomTag RNG_TRACE, RNG_FICKLE_BEAM, RNG_AI_ABILITY, + RNG_AI_HASBADODDS, RNG_SHELL_SIDE_ARM, }; diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index a0a44cb98d..d23c0c1e32 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -148,8 +148,8 @@ static bool32 HasBadOdds(u32 battler, bool32 emitResult) playerMove = gBattleMons[opposingBattler].moves[i]; if (playerMove != MOVE_NONE && gMovesInfo[playerMove].power != 0) { - struct SimulatedDamage dmg = AI_CalcDamage(playerMove, opposingBattler, battler, &effectiveness, FALSE, weather, DMG_ROLL_HIGHEST); - if (dmg.expected > maxDamageTaken) + damageTaken = AI_CalcDamage(playerMove, opposingBattler, battler, &effectiveness, FALSE, weather, DMG_ROLL_HIGHEST).expected; + if (damageTaken > maxDamageTaken) maxDamageTaken = damageTaken; } } @@ -172,7 +172,7 @@ static bool32 HasBadOdds(u32 battler, bool32 emitResult) return FALSE; // Start assessing whether or not mon has bad odds - // Jump straight to swtiching out in cases where mon gets OHKO'd + // Jump straight to switching out in cases where mon gets OHKO'd if (((getsOneShot && gBattleMons[opposingBattler].speed > gBattleMons[battler].speed) // If the player OHKOs and outspeeds OR OHKOs, doesn't outspeed but isn't 2HKO'd || (getsOneShot && gBattleMons[opposingBattler].speed <= gBattleMons[battler].speed && maxDamageDealt < gBattleMons[opposingBattler].hp / 2)) && (gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 2 // And the current mon has at least 1/2 their HP, or 1/4 HP and Regenerator @@ -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 (Random() % 2 == 0) + if (!RandomPercentage(RNG_AI_HASBADODDS, 50)) return FALSE; // Switch mon out @@ -203,7 +203,7 @@ static bool32 HasBadOdds(u32 battler, bool32 emitResult) return FALSE; // 50% chance to stay in regardless - if (Random() % 2 == 0) + if (!RandomPercentage(RNG_AI_HASBADODDS, 50)) return FALSE; // Switch mon out diff --git a/test/battle/ai/ai_switching.c b/test/battle/ai/ai_switching.c index fcc8e322ca..b3927509f0 100644 --- a/test/battle/ai/ai_switching.c +++ b/test/battle/ai/ai_switching.c @@ -121,7 +121,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Avoid infinite loop if damage { GIVEN { ASSUME(gItemsInfo[ITEM_LEFTOVERS].holdEffect == HOLD_EFFECT_LEFTOVERS); - AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES); + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_SMART_MON_CHOICES); PLAYER(SPECIES_MEOWTH_GALARIAN) { Level(100); Moves(MOVE_GROWL, MOVE_FAKE_OUT, MOVE_HONE_CLAWS); } // Scenario courtesy of Duke, who triggered the bug in the first place OPPONENT(SPECIES_MEOWTH_GALARIAN) { Level(5); Moves(MOVE_GROWL, MOVE_FAKE_OUT, MOVE_HONE_CLAWS); } @@ -357,3 +357,21 @@ AI_SINGLE_BATTLE_TEST("AI won't use trapping behaviour if player only has 1 mon TURN{ MOVE(player, MOVE_PROTECT); EXPECT_MOVE(opponent, MOVE_SELF_DESTRUCT); EXPECT_SEND_OUT(opponent, 2); } } } + +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_HASBADODDS); + GIVEN { + ASSUME(gSpeciesInfo[SPECIES_RHYDON].types[0] == TYPE_GROUND); + ASSUME(gSpeciesInfo[SPECIES_PELIPPER].types[0] == TYPE_WATER); + ASSUME(gSpeciesInfo[SPECIES_PELIPPER].types[1] == TYPE_FLYING); + ASSUME(gMovesInfo[MOVE_THUNDERBOLT].type == TYPE_ELECTRIC); + ASSUME(gMovesInfo[MOVE_EARTHQUAKE].type == TYPE_GROUND); + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES); + PLAYER(SPECIES_ELECTRODE) { Moves(MOVE_THUNDERBOLT, MOVE_THUNDER_WAVE, MOVE_THUNDER_SHOCK); } + OPPONENT(SPECIES_PELIPPER) { Moves(MOVE_EARTHQUAKE); }; + OPPONENT(SPECIES_RHYDON) { Moves(MOVE_EARTHQUAKE); Ability(ABILITY_ROCK_HEAD); } + } WHEN { + TURN { MOVE(player, MOVE_THUNDERBOLT) ; EXPECT_SWITCH(opponent, 1); } + } +}