From 9c6dfb7c0c27f04f26aefb2096fa668a6bc69748 Mon Sep 17 00:00:00 2001 From: ghoulslash <41651341+ghoulslash@users.noreply.github.com> Date: Wed, 15 May 2024 14:39:03 -0400 Subject: [PATCH] Move RestoreBattlerData out of Ai_CalcDmg and add SaveBattlerData Protections (#4156) * move restorebattlerdata out of Ai_CalcDmg * fix SetBattlerdata calls * add saved field to struct AI_SavedBattleMon to prevent overwriting saved mon info * AI_CalcPartyMonDamage set opposing battler known data --------- Co-authored-by: ghoulslash --- include/battle.h | 3 ++- src/battle_ai_main.c | 5 +++++ src/battle_ai_util.c | 33 ++++++++++++++++++++++----------- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/include/battle.h b/include/battle.h index b5ecf08335..72239928e0 100644 --- a/include/battle.h +++ b/include/battle.h @@ -312,7 +312,8 @@ struct AI_SavedBattleMon u16 ability; u16 moves[MAX_MON_MOVES]; u16 heldItem; - u16 species; + u16 species:15; + u16 saved:1; u8 types[3]; }; diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 68b9b1d2f9..ffd99c7cbd 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -438,6 +438,8 @@ static void SetBattlerAiMovesData(struct AiLogicData *aiData, u32 battlerAtk, u3 moves = GetMovesArray(battlerAtk); weather = AI_GetWeather(aiData); + SetBattlerData(battlerAtk); + // Simulate dmg for both ai controlled mons and for player controlled mons. for (battlerDef = 0; battlerDef < battlersCount; battlerDef++) { @@ -445,6 +447,7 @@ static void SetBattlerAiMovesData(struct AiLogicData *aiData, u32 battlerAtk, u3 continue; SaveBattlerData(battlerDef); + SetBattlerData(battlerDef); for (i = 0; i < MAX_MON_MOVES; i++) { s32 dmg = 0; @@ -462,7 +465,9 @@ static void SetBattlerAiMovesData(struct AiLogicData *aiData, u32 battlerAtk, u3 aiData->simulatedDmg[battlerAtk][battlerDef][i] = dmg; aiData->effectiveness[battlerAtk][battlerDef][i] = effectiveness; } + RestoreBattlerData(battlerDef); } + RestoreBattlerData(battlerAtk); } void SetAiLogicDataForTurn(struct AiLogicData *aiData) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index b81705a366..a3b4553607 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -143,10 +143,11 @@ void ClearBattlerItemEffectHistory(u32 battlerId) void SaveBattlerData(u32 battlerId) { - if (!BattlerHasAi(battlerId)) + if (!BattlerHasAi(battlerId) && !AI_THINKING_STRUCT->saved[battlerId].saved) { u32 i; + AI_THINKING_STRUCT->saved[battlerId].saved = TRUE; AI_THINKING_STRUCT->saved[battlerId].ability = gBattleMons[battlerId].ability; AI_THINKING_STRUCT->saved[battlerId].heldItem = gBattleMons[battlerId].item; AI_THINKING_STRUCT->saved[battlerId].species = gBattleMons[battlerId].species; @@ -196,7 +197,7 @@ static bool32 ShouldFailForIllusion(u32 illusionSpecies, u32 battlerId) void SetBattlerData(u32 battlerId) { - if (!BattlerHasAi(battlerId)) + if (!BattlerHasAi(battlerId) && AI_THINKING_STRUCT->saved[battlerId].saved) { u32 i, species, illusionSpecies, side; side = GetBattlerSide(battlerId); @@ -240,10 +241,11 @@ void SetBattlerData(u32 battlerId) void RestoreBattlerData(u32 battlerId) { - if (!BattlerHasAi(battlerId)) + if (!BattlerHasAi(battlerId) && AI_THINKING_STRUCT->saved[battlerId].saved) { u32 i; + AI_THINKING_STRUCT->saved[battlerId].saved = FALSE; gBattleMons[battlerId].ability = AI_THINKING_STRUCT->saved[battlerId].ability; gBattleMons[battlerId].item = AI_THINKING_STRUCT->saved[battlerId].heldItem; gBattleMons[battlerId].species = AI_THINKING_STRUCT->saved[battlerId].species; @@ -354,9 +356,15 @@ bool32 MovesWithCategoryUnusable(u32 attacker, u32 target, u32 category) // To save computation time this function has 2 variants. One saves, sets and restores battlers, while the other doesn't. s32 AI_CalcDamageSaveBattlers(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectiveness, bool32 considerZPower) { + s32 dmg = 0; SaveBattlerData(battlerAtk); SaveBattlerData(battlerDef); - return AI_CalcDamage(move, battlerAtk, battlerDef, typeEffectiveness, considerZPower, AI_GetWeather(AI_DATA)); + SetBattlerData(battlerAtk); + SetBattlerData(battlerDef); + dmg = AI_CalcDamage(move, battlerAtk, battlerDef, typeEffectiveness, considerZPower, AI_GetWeather(AI_DATA)); + RestoreBattlerData(battlerAtk); + RestoreBattlerData(battlerDef); + return dmg; } static inline s32 LowestRollDmg(s32 dmg) @@ -457,9 +465,6 @@ s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectivenes bool32 toggledTera = FALSE; struct AiLogicData *aiData = AI_DATA; - SetBattlerData(battlerAtk); - SetBattlerData(battlerDef); - // Temporarily enable Z-Moves for damage calcs if (considerZPower && IsViableZMove(battlerAtk, move)) { @@ -592,9 +597,6 @@ s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectivenes dmg = 0; } - RestoreBattlerData(battlerAtk); - RestoreBattlerData(battlerDef); - // convert multiper to AI_EFFECTIVENESS_xX *typeEffectiveness = AI_GetEffectiveness(effectivenessMultiplier); @@ -3282,11 +3284,20 @@ s32 AI_CalcPartyMonDamage(u32 move, u32 battlerAtk, u32 battlerDef, struct Battl s32 dmg; u8 effectiveness; struct BattlePokemon *savedBattleMons = AllocSaveBattleMons(); - if(isPartyMonAttacker) + + if (isPartyMonAttacker) + { gBattleMons[battlerAtk] = switchinCandidate; + SetBattlerData(battlerDef); // set known opposing battler data + } else + { gBattleMons[battlerDef] = switchinCandidate; + SetBattlerData(battlerAtk); // set known opposing battler data + } + dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, FALSE, AI_GetWeather(AI_DATA)); + // restores original gBattleMon struct FreeRestoreBattleMons(savedBattleMons); return dmg; }