From 411a236ce767c6c6bfbe3a12c79674426022a364 Mon Sep 17 00:00:00 2001 From: Pawkkie <61265402+Pawkkie@users.noreply.github.com> Date: Wed, 19 Mar 2025 04:32:59 -0400 Subject: [PATCH] Fix AI using Scald / fire moves against frozen / frostbitten targets (#6442) --- include/battle_script_commands.h | 1 + src/battle_ai_main.c | 15 +++++++++++++++ src/battle_script_commands.c | 3 +-- test/battle/ai/ai.c | 31 +++++++++++++++++++++++++++++-- 4 files changed, 46 insertions(+), 4 deletions(-) diff --git a/include/battle_script_commands.h b/include/battle_script_commands.h index 1b72239d00..ead678e993 100644 --- a/include/battle_script_commands.h +++ b/include/battle_script_commands.h @@ -58,6 +58,7 @@ u8 GetFirstFaintedPartyIndex(u8 battlerId); bool32 IsMoveAffectedByParentalBond(u32 move, u32 battler); void SaveBattlerTarget(u32 battler); void SaveBattlerAttacker(u32 battler); +bool32 CanBurnHitThaw(u16 move); extern void (* const gBattleScriptingCommandsTable[])(void); extern const struct StatFractions gAccuracyStageRatios[]; diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index c7bf1b1bb7..1b0fe8b45a 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -854,6 +854,21 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) if (gBattleStruct->battlerState[battlerDef].commandingDondozo) RETURN_SCORE_MINUS(20); + // Don't use anything but super effective thawing moves if target is frozen if any other attack available + if (((GetMoveType(move) == TYPE_FIRE && GetMovePower(move) != 0) || CanBurnHitThaw(move)) && effectiveness < UQ_4_12(2.0) && (gBattleMons[battlerDef].status1 & (STATUS1_FROSTBITE | STATUS1_FREEZE))) + { + u32 aiMove; + for (i = 0; i < MAX_MON_MOVES; i++) + { + aiMove = gBattleMons[battlerAtk].moves[i]; + if (GetMoveType(aiMove) != TYPE_FIRE && !CanBurnHitThaw(aiMove) && GetMovePower(gBattleMons[battlerAtk].moves[i] != 0)) + { + ADJUST_SCORE(-1); + break; + } + } + } + if (effectiveness == UQ_4_12(0.0)) { RETURN_SCORE_MINUS(20); diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index ac8b633b84..a1623c8b4b 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -340,7 +340,6 @@ void ApplyExperienceMultipliers(s32 *expAmount, u8 expGetterMonId, u8 faintedBat static void RemoveAllWeather(void); static void RemoveAllTerrains(void); static bool8 CanAbilityPreventStatLoss(u16 abilityDef); -static bool8 CanBurnHitThaw(u16 move); static u32 GetNextTarget(u32 moveTarget, bool32 excludeCurrent); static void TryUpdateEvolutionTracker(u32 evolutionMethod, u32 upAmount, u16 usedMove); static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u8 *failInstr, u16 move); @@ -16794,7 +16793,7 @@ static bool8 CanAbilityPreventStatLoss(u16 abilityDef) return FALSE; } -static bool8 CanBurnHitThaw(u16 move) +bool32 CanBurnHitThaw(u16 move) { u8 i; diff --git a/test/battle/ai/ai.c b/test/battle/ai/ai.c index 3a72508c17..cc9582a4bd 100644 --- a/test/battle/ai/ai.c +++ b/test/battle/ai/ai.c @@ -846,6 +846,34 @@ AI_SINGLE_BATTLE_TEST("AI won't use Sucker Punch if it expects a move of the sam } } +AI_SINGLE_BATTLE_TEST("AI won't use thawing moves if target is frozen unless it is super effective or it has no other options") +{ + u32 aiFlags = 0; u32 status = 0; u32 aiMove = 0; + PARAMETRIZE { status = STATUS1_FREEZE; aiMove = MOVE_SCALD; aiFlags = 0; } + PARAMETRIZE { status = STATUS1_FREEZE; aiMove = MOVE_SCALD; aiFlags = AI_FLAG_CHECK_BAD_MOVE; } + PARAMETRIZE { status = STATUS1_FROSTBITE; aiMove = MOVE_SCALD; aiFlags = 0; } + PARAMETRIZE { status = STATUS1_FROSTBITE; aiMove = MOVE_SCALD; aiFlags = AI_FLAG_CHECK_BAD_MOVE; } + PARAMETRIZE { status = STATUS1_FREEZE; aiMove = MOVE_EMBER; aiFlags = 0; } + PARAMETRIZE { status = STATUS1_FREEZE; aiMove = MOVE_EMBER; aiFlags = AI_FLAG_CHECK_BAD_MOVE; } + PARAMETRIZE { status = STATUS1_FROSTBITE; aiMove = MOVE_EMBER; aiFlags = 0; } + PARAMETRIZE { status = STATUS1_FROSTBITE; aiMove = MOVE_EMBER; aiFlags = AI_FLAG_CHECK_BAD_MOVE; } + + GIVEN { + ASSUME(GetMoveType(MOVE_EMBER) == TYPE_FIRE); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_WATER_GUN) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(gMovesInfo[MOVE_SCALD].thawsUser == TRUE); + AI_FLAGS(aiFlags | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_TACKLE); Status1(status); } + OPPONENT(SPECIES_VULPIX) { Moves(MOVE_TACKLE, aiMove); } + } WHEN { + if (aiFlags == AI_FLAG_CHECK_BAD_MOVE) + TURN { MOVE(player, MOVE_TACKLE); EXPECT_MOVE(opponent, MOVE_TACKLE); } + else + TURN { MOVE(player, MOVE_TACKLE); EXPECT_MOVE(opponent, aiMove); } + } +} + AI_SINGLE_BATTLE_TEST("AI score for Mean Look will be decreased if target can escape") { GIVEN { @@ -855,5 +883,4 @@ AI_SINGLE_BATTLE_TEST("AI score for Mean Look will be decreased if target can es } WHEN { TURN { SCORE_EQ_VAL(opponent, MOVE_MEAN_LOOK, 90); } } -} - +} \ No newline at end of file