From 1a2cd5645af10263c852ade80dd349a7989889ca Mon Sep 17 00:00:00 2001 From: Pawkkie <61265402+Pawkkie@users.noreply.github.com> Date: Thu, 1 May 2025 04:15:19 -0400 Subject: [PATCH] Fix roll handling in AI party damage calcs (#6733) --- include/battle_ai_util.h | 2 +- src/battle_ai_switch_items.c | 11 +++-------- src/battle_ai_util.c | 28 +++++++++++++++++++++++----- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index c21fc9f837..17adb67712 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -228,7 +228,7 @@ void IncreaseSleepScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score); void IncreaseConfusionScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score); void IncreaseFrostbiteScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score); -s32 AI_CalcPartyMonDamage(u32 move, u32 battlerAtk, u32 battlerDef, struct BattlePokemon switchinCandidate, bool32 isPartyMonAttacker); +s32 AI_CalcPartyMonDamage(u32 move, u32 battlerAtk, u32 battlerDef, struct BattlePokemon switchinCandidate, enum DamageCalcContext calcContext); u32 AI_WhoStrikesFirstPartyMon(u32 battlerAtk, u32 battlerDef, struct BattlePokemon switchinCandidate, u32 moveConsidered); s32 AI_TryToClearStats(u32 battlerAtk, u32 battlerDef, bool32 isDoubleBattle); bool32 AI_ShouldCopyStatChanges(u32 battlerAtk, u32 battlerDef); diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index a6d25ad5b1..c1ff6d9c4a 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -1404,7 +1404,7 @@ static u32 GetBestMonDmg(struct Pokemon *party, int firstId, int lastId, u8 inva if (aiMove != MOVE_NONE && !IsBattleMoveStatus(aiMove)) { aiMove = GetMonData(&party[i], MON_DATA_MOVE1 + j); - dmg = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, TRUE); + dmg = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, AI_ATTACKING); if (bestDmg < dmg) { bestDmg = dmg; @@ -1859,7 +1859,7 @@ static s32 GetMaxDamagePlayerCouldDealToSwitchin(u32 battler, u32 opposingBattle playerMove = gBattleMons[opposingBattler].moves[i]; if (playerMove != MOVE_NONE && !IsBattleMoveStatus(playerMove) && GetMoveEffect(playerMove) != EFFECT_FOCUS_PUNCH) { - damageTaken = AI_CalcPartyMonDamage(playerMove, opposingBattler, battler, battleMon, FALSE); + damageTaken = AI_CalcPartyMonDamage(playerMove, opposingBattler, battler, battleMon, AI_DEFENDING); if (playerMove == gBattleStruct->choicedMove[opposingBattler]) // If player is choiced, only care about the choice locked move return damageTaken; if (damageTaken > maxDamageTaken) @@ -1990,12 +1990,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId, aiMove = AI_DATA->switchinCandidate.battleMon.moves[j]; if (aiMove != MOVE_NONE && !IsBattleMoveStatus(aiMove)) - { - if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_CONSERVATIVE) - damageDealt = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, TRUE); - else - damageDealt = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, TRUE); - } + damageDealt = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, AI_ATTACKING); // Offensive switchin decisions are based on which whether switchin moves first and whether it can win a 1v1 isSwitchinFirst = AI_WhoStrikesFirstPartyMon(battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, aiMove); diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 23b1a66e46..74f0646ed3 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -3765,20 +3765,20 @@ void FreeRestoreBattleMons(struct BattlePokemon *savedBattleMons) } // party logic -s32 AI_CalcPartyMonDamage(u32 move, u32 battlerAtk, u32 battlerDef, struct BattlePokemon switchinCandidate, bool32 isPartyMonAttacker) +s32 AI_CalcPartyMonDamage(u32 move, u32 battlerAtk, u32 battlerDef, struct BattlePokemon switchinCandidate, enum DamageCalcContext calcContext) { struct SimulatedDamage dmg; uq4_12_t effectiveness; struct BattlePokemon *savedBattleMons = AllocSaveBattleMons(); - if (isPartyMonAttacker) + if (calcContext == AI_ATTACKING) { gBattleMons[battlerAtk] = switchinCandidate; AI_THINKING_STRUCT->saved[battlerDef].saved = TRUE; SetBattlerAiData(battlerAtk, AI_DATA); // set known opposing battler data AI_THINKING_STRUCT->saved[battlerDef].saved = FALSE; } - else + else if (calcContext == AI_DEFENDING) { gBattleMons[battlerDef] = switchinCandidate; AI_THINKING_STRUCT->saved[battlerAtk].saved = TRUE; @@ -3787,13 +3787,31 @@ s32 AI_CalcPartyMonDamage(u32 move, u32 battlerAtk, u32 battlerDef, struct Battl } dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, FALSE, AI_GetWeather()); + // restores original gBattleMon struct FreeRestoreBattleMons(savedBattleMons); - if (isPartyMonAttacker) + if (calcContext == AI_ATTACKING) + { SetBattlerAiData(battlerAtk, AI_DATA); - else + if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_RISKY && !(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_CONSERVATIVE)) + return dmg.maximum; + else if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_CONSERVATIVE && !(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_RISKY)) + return dmg.minimum; + else + return dmg.median; + } + + else if (calcContext == AI_DEFENDING) + { SetBattlerAiData(battlerDef, AI_DATA); + if (AI_THINKING_STRUCT->aiFlags[battlerDef] & AI_FLAG_RISKY && !(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_CONSERVATIVE)) + return dmg.minimum; + else if (AI_THINKING_STRUCT->aiFlags[battlerDef] & AI_FLAG_CONSERVATIVE && !(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_RISKY)) + return dmg.maximum; + else + return dmg.median; + } return dmg.median; }