From 3c5c68ac582ae668e65c5626746dfe5a3e2c76b9 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Sun, 16 Jul 2023 08:24:59 +0200 Subject: [PATCH] Fix how AI categorizes Weak moves and give priority to always hits moves when needed (#3109) * ai weak move fix and always hits move prioritarizing --- include/battle_ai_util.h | 1 + src/battle_ai_main.c | 21 +++++++++++++++++++++ src/battle_ai_util.c | 8 ++++++-- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 67ff6968e2..284022092c 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -85,6 +85,7 @@ bool32 ShouldLowerEvasion(u8 battlerAtk, u8 battlerDef, u16 defAbility); bool32 IsAffectedByPowder(u8 battler, u16 ability, u16 holdEffect); bool32 MovesWithSplitUnusable(u32 attacker, u32 target, u32 split); s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef, u8 *effectiveness, bool32 considerZPower); +u32 GetNoOfHitsToKO(u32 dmg, s32 hp); u8 GetMoveDamageResult(u16 move); u32 GetCurrDamageHpPercent(u8 battlerAtk, u8 battlerDef); u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef); diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 97ae1f35cc..c40d8a649e 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -3102,6 +3102,19 @@ static bool32 IsPinchBerryItemEffect(u16 holdEffect) return FALSE; } +static u32 GetAIMostDamagingMoveId(u8 battlerAtk, u8 battlerDef) +{ + u32 i, id = 0; + u32 mostDmg = 0; + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (AI_DATA->simulatedDmg[battlerAtk][battlerDef][i] > mostDmg) + id = i, mostDmg = AI_DATA->simulatedDmg[battlerAtk][battlerDef][i]; + } + return id; +} + // AI_FLAG_CHECK_VIABILITY - a weird mix of increasing and decreasing scores static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { @@ -3122,6 +3135,14 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // check always hits if (!IS_MOVE_STATUS(move) && gBattleMoves[move].accuracy == 0) { + // If 2 moves can KO the target in the same number of turns, but one of them always hits and there is a risk the other move could miss, prioritize the always hits move. + if (gBattleMons[battlerDef].statStages[STAT_EVASION] > 6 || gBattleMons[battlerAtk].statStages[STAT_ACC] < 6) + { + u32 mostDmgMoveId = GetAIMostDamagingMoveId(battlerAtk, battlerDef); + u32 *dmgs = AI_DATA->simulatedDmg[battlerAtk][battlerDef]; + if (GetNoOfHitsToKO(dmgs[mostDmgMoveId], gBattleMons[battlerDef].hp) == GetNoOfHitsToKO(dmgs[AI_THINKING_STRUCT->movesetIndex], gBattleMons[battlerDef].hp)) + score++; + } if (gBattleMons[battlerDef].statStages[STAT_EVASION] >= 10 || gBattleMons[battlerAtk].statStages[STAT_ACC] <= 2) score++; if (AI_RandLessThan(100) && (gBattleMons[battlerDef].statStages[STAT_EVASION] >= 8 || gBattleMons[battlerAtk].statStages[STAT_ACC] <= 4)) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 9fdf081234..d7e32a452d 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -953,6 +953,11 @@ static u32 WhichMoveBetter(u32 move1, u32 move2) return 2; } +u32 GetNoOfHitsToKO(u32 dmg, s32 hp) +{ + return hp / (dmg + 1) + 1; +} + u8 GetMoveDamageResult(u16 move) { s32 i, checkedMove, bestId, currId, hp; @@ -1018,9 +1023,8 @@ u8 GetMoveDamageResult(u16 move) currId = AI_THINKING_STRUCT->movesetIndex; if (currId == bestId) AI_THINKING_STRUCT->funcResult = MOVE_POWER_BEST; - // Compare percentage difference. else if ((moveDmgs[currId] >= hp || moveDmgs[bestId] < hp) // If current move can faint as well, or if neither can - && (moveDmgs[bestId] * 100 / hp) - (moveDmgs[currId] * 100 / hp) <= 30 + && GetNoOfHitsToKO(moveDmgs[currId], hp) - GetNoOfHitsToKO(moveDmgs[bestId], hp) <= 2 // Consider a move weak if it needs to be used at least 2 times more to faint the target, compared to the best move. && WhichMoveBetter(gBattleMons[sBattler_AI].moves[bestId], gBattleMons[sBattler_AI].moves[currId]) != 0) AI_THINKING_STRUCT->funcResult = MOVE_POWER_GOOD; else