From 0e37bfd7ff1ecd97bbaa29ae0174051487a4bee9 Mon Sep 17 00:00:00 2001 From: Pawkkie <61265402+Pawkkie@users.noreply.github.com> Date: Tue, 15 Jul 2025 12:07:26 -0400 Subject: [PATCH] Fix stat change / stat ID ambiguity (#7346) Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com> --- src/battle_ai_util.c | 42 +++++++++++++++++++++++++++++++++++------- test/battle/ai/ai.c | 13 +++++++++++++ 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 2d7136eefc..7b5e8e0d37 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -4141,13 +4141,41 @@ bool32 IsRecycleEncouragedItem(u32 item) return FALSE; } -static enum AIScore IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, enum StatChange statId, bool32 considerContrary) +static u32 GetStatBeingChanged(enum StatChange statChange) +{ + switch(statChange) + { + case STAT_CHANGE_ATK: + case STAT_CHANGE_ATK_2: + return STAT_ATK; + case STAT_CHANGE_DEF: + case STAT_CHANGE_DEF_2: + return STAT_DEF; + case STAT_CHANGE_SPEED: + case STAT_CHANGE_SPEED_2: + return STAT_SPEED; + case STAT_CHANGE_SPATK: + case STAT_CHANGE_SPATK_2: + return STAT_SPATK; + case STAT_CHANGE_SPDEF: + case STAT_CHANGE_SPDEF_2: + return STAT_SPDEF; + case STAT_CHANGE_ACC: + return STAT_ACC; + case STAT_CHANGE_EVASION: + return STAT_EVASION; + } + return 0; // STAT_HP, should never be getting changed +} + +static enum AIScore IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, enum StatChange statChange, bool32 considerContrary) { enum AIScore tempScore = NO_INCREASE; u32 noOfHitsToFaint = NoOfHitsForTargetToFaintAI(battlerDef, battlerAtk); u32 aiIsFaster = AI_IsFaster(battlerAtk, battlerDef, TRUE); u32 shouldSetUp = ((noOfHitsToFaint >= 2 && aiIsFaster) || (noOfHitsToFaint >= 3 && !aiIsFaster) || noOfHitsToFaint == UNKNOWN_NO_OF_HITS); u32 i; + u32 statId = GetStatBeingChanged(statChange); if (considerContrary && gAiLogicData->abilities[battlerAtk] == ABILITY_CONTRARY) return NO_INCREASE; @@ -4206,7 +4234,7 @@ static enum AIScore IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, tempScore += WEAK_EFFECT; } - switch (statId) + switch (statChange) { case STAT_CHANGE_ATK: if (HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL) && shouldSetUp) @@ -4269,7 +4297,7 @@ static enum AIScore IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, } break; case STAT_CHANGE_ACC: - if (gBattleMons[battlerAtk].statStages[STAT_ACC] <= 3) // Increase only if necessary + if (gBattleMons[battlerAtk].statStages[statId] <= 3) // Increase only if necessary tempScore += DECENT_EFFECT; break; case STAT_CHANGE_EVASION: @@ -4283,14 +4311,14 @@ static enum AIScore IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, return tempScore; } -u32 IncreaseStatUpScore(u32 battlerAtk, u32 battlerDef, enum StatChange statId) +u32 IncreaseStatUpScore(u32 battlerAtk, u32 battlerDef, enum StatChange statChange) { - return IncreaseStatUpScoreInternal(battlerAtk, battlerDef, statId, TRUE); + return IncreaseStatUpScoreInternal(battlerAtk, battlerDef, statChange, TRUE); } -u32 IncreaseStatUpScoreContrary(u32 battlerAtk, u32 battlerDef, enum StatChange statId) +u32 IncreaseStatUpScoreContrary(u32 battlerAtk, u32 battlerDef, enum StatChange statChange) { - return IncreaseStatUpScoreInternal(battlerAtk, battlerDef, statId, FALSE); + return IncreaseStatUpScoreInternal(battlerAtk, battlerDef, statChange, FALSE); } void IncreasePoisonScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) diff --git a/test/battle/ai/ai.c b/test/battle/ai/ai.c index 3fe975fc66..62eae623bc 100644 --- a/test/battle/ai/ai.c +++ b/test/battle/ai/ai.c @@ -881,3 +881,16 @@ AI_SINGLE_BATTLE_TEST("Move scoring comparison properly awards bonus point to be TURN { EXPECT_MOVE(opponent, MOVE_WATER_SPOUT); } } } + +AI_SINGLE_BATTLE_TEST("AI will stop setting up at +4") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT); + PLAYER(SPECIES_ZIGZAGOON) { Moves(MOVE_CELEBRATE); } + OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE, MOVE_IRON_DEFENSE); } + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); EXPECT_MOVE(opponent, MOVE_IRON_DEFENSE); } + TURN { MOVE(player, MOVE_CELEBRATE); EXPECT_MOVE(opponent, MOVE_IRON_DEFENSE); } + TURN { MOVE(player, MOVE_CELEBRATE); EXPECT_MOVE(opponent, MOVE_TACKLE); } + } +}