From 8f320a8d33a3a7222471a5c1bf10108f325430a9 Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Mon, 8 Nov 2021 11:37:41 -0500 Subject: [PATCH 1/8] some ai updates, recycle + ripen logic --- include/battle_ai_util.h | 2 ++ src/battle_ai_main.c | 13 +++++++++- src/battle_ai_util.c | 56 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 1b2591899b..6da519342f 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -52,6 +52,8 @@ bool32 ShouldRecover(u8 battlerAtk, u8 battlerDef, u16 move, u8 healPercent); bool32 ShouldSetScreen(u8 battlerAtk, u8 battlerDef, u16 moveEffect); bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 moveIndex); bool32 IsRecycleEncouragedItem(u16 item); +bool32 IsHpRestoringBerry(u16 item); +bool32 IsStatBoostingBerry(u16 item); bool32 CanKnockOffItem(u8 battler, u16 item); bool32 IsAbilityOfRating(u16 ability, s8 rating); s8 GetAbilityRating(u16 ability); diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 7fbb432603..b8dbdebac8 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -2969,6 +2969,10 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { case ABILITY_MOXIE: case ABILITY_BEAST_BOOST: + case ABILITY_CHILLING_NEIGH: + case ABILITY_GRIM_NEIGH: + case ABILITY_AS_ONE_ICE_RIDER: + case ABILITY_AS_ONE_SHADOW_RIDER: if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // attacker should go first { if (CanIndexMoveFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) @@ -2980,7 +2984,6 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // move effect checks switch (moveEffect) { - case EFFECT_HIT: break; case EFFECT_SLEEP: @@ -4101,6 +4104,14 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score++; if (IsRecycleEncouragedItem(GetUsedHeldItem(battlerAtk))) score++; + if (AI_DATA->atkAbility == ABILITY_RIPEN) + { + u16 item = GetUsedHeldItem(battlerAtk); + if (IsStatBoostingBerry(item) && atkHpPercent > 60) + score++; + else if (IsHpRestoringBerry(item) && atkHpPercent < 60) + score++; // TODO check if player can still faint us after we heal + } break; case EFFECT_BRICK_BREAK: if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_REFLECT) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 71dc78d0aa..3ccf065a50 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -3368,6 +3368,44 @@ static const u16 sRecycleEncouragedItems[] = // TODO expand this }; +// Its assumed that the berry is strategically given, so no need to check benefits of the berry +bool32 IsStatBoostingBerry(u16 item) +{ + switch (item) + { + case ITEM_LIECHI_BERRY: + case ITEM_GANLON_BERRY: + case ITEM_SALAC_BERRY: + case ITEM_PETAYA_BERRY: + case ITEM_APICOT_BERRY: + //case ITEM_LANSAT_BERRY: + case ITEM_STARF_BERRY: + #ifdef ITEM_EXPANSION + case ITEM_MICLE_BERRY: + #endif + return TRUE; + default: + return FALSE; + } +} + +bool32 IsHpRestoringBerry(u16 item) +{ + switch (item) + { + case ITEM_ORAN_BERRY: + case ITEM_SITRUS_BERRY: + case ITEM_FIGY_BERRY: + case ITEM_WIKI_BERRY: + case ITEM_MAGO_BERRY: + case ITEM_AGUAV_BERRY: + case ITEM_IAPAPA_BERRY: + return TRUE; + default: + return FALSE; + } +} + bool32 IsRecycleEncouragedItem(u16 item) { u32 i; @@ -3389,6 +3427,9 @@ void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score) if (GetHealthPercentage(battlerAtk) < 80 && AI_RandLessThan(128)) return; + + if (CanAIFaintTarget(battlerAtk, battlerDef, 0)) + return; // Damaging moves would get a score boost from AI_TryToFaint or PreferStrongestMove so we don't consider them here switch (statId) { @@ -3461,6 +3502,9 @@ void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score) void IncreasePoisonScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) { + if (CanAIFaintTarget(battlerAtk, battlerDef, 0)) + return; + if (AI_CanPoison(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove) && GetHealthPercentage(battlerDef) > 20) { if (!HasDamagingMove(battlerDef)) @@ -3481,6 +3525,9 @@ void IncreasePoisonScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) void IncreaseBurnScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) { + if (CanAIFaintTarget(battlerAtk, battlerDef, 0)) + return; + if (AI_CanBurn(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) { (*score)++; // burning is good @@ -3497,6 +3544,9 @@ void IncreaseBurnScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) void IncreaseParalyzeScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) { + if (CanAIFaintTarget(battlerAtk, battlerDef, 0)) + return; + if (AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) { u8 atkSpeed = GetBattlerTotalSpeedStat(battlerAtk); @@ -3515,6 +3565,9 @@ void IncreaseParalyzeScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) void IncreaseSleepScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) { + if (CanAIFaintTarget(battlerAtk, battlerDef, 0)) + return; + if (AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) *score += 2; else @@ -3530,6 +3583,9 @@ void IncreaseSleepScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) void IncreaseConfusionScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) { + if (CanAIFaintTarget(battlerAtk, battlerDef, 0)) + return; + if (AI_CanConfuse(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove) && AI_DATA->defHoldEffect != HOLD_EFFECT_CURE_CONFUSION && AI_DATA->defHoldEffect != HOLD_EFFECT_CURE_STATUS) From e5a0630596a83fe823d5bae01f12aa8dc79d7cfd Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Mon, 8 Nov 2021 11:42:32 -0500 Subject: [PATCH 2/8] add ai flag checks alongside CanFaintTarget --- src/battle_ai_util.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 3ccf065a50..60083bb29c 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -1703,7 +1703,7 @@ u32 CountNegativeStatStages(u8 battlerId) bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility) { - if (IsAiFaster(AI_CHECK_FASTER) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + if (IsAiFaster(AI_CHECK_FASTER) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. if (gBattleMons[battlerDef].statStages[STAT_ATK] > 4 @@ -1719,7 +1719,7 @@ bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility) bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility) { - if (IsAiFaster(AI_CHECK_FASTER) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + if (IsAiFaster(AI_CHECK_FASTER) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. if (gBattleMons[battlerDef].statStages[STAT_DEF] > 4 @@ -1735,7 +1735,7 @@ bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility) bool32 ShouldLowerSpeed(u8 battlerAtk, u8 battlerDef, u16 defAbility) { - if (IsAiFaster(AI_CHECK_FASTER) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + if (IsAiFaster(AI_CHECK_FASTER) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. if (IsAiFaster(AI_CHECK_SLOWER) @@ -1749,7 +1749,7 @@ bool32 ShouldLowerSpeed(u8 battlerAtk, u8 battlerDef, u16 defAbility) bool32 ShouldLowerSpAtk(u8 battlerAtk, u8 battlerDef, u16 defAbility) { - if (IsAiFaster(AI_CHECK_FASTER) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + if (IsAiFaster(AI_CHECK_FASTER) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. if (gBattleMons[battlerDef].statStages[STAT_SPATK] > 4 @@ -1764,7 +1764,7 @@ bool32 ShouldLowerSpAtk(u8 battlerAtk, u8 battlerDef, u16 defAbility) bool32 ShouldLowerSpDef(u8 battlerAtk, u8 battlerDef, u16 defAbility) { - if (IsAiFaster(AI_CHECK_FASTER) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + if (IsAiFaster(AI_CHECK_FASTER) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. if (gBattleMons[battlerDef].statStages[STAT_SPDEF] > 4 @@ -1779,7 +1779,7 @@ bool32 ShouldLowerSpDef(u8 battlerAtk, u8 battlerDef, u16 defAbility) bool32 ShouldLowerAccuracy(u8 battlerAtk, u8 battlerDef, u16 defAbility) { - if (IsAiFaster(AI_CHECK_FASTER) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + if (IsAiFaster(AI_CHECK_FASTER) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. if (defAbility != ABILITY_CONTRARY @@ -1793,7 +1793,7 @@ bool32 ShouldLowerAccuracy(u8 battlerAtk, u8 battlerDef, u16 defAbility) bool32 ShouldLowerEvasion(u8 battlerAtk, u8 battlerDef, u16 defAbility) { - if (IsAiFaster(AI_CHECK_FASTER) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + if (IsAiFaster(AI_CHECK_FASTER) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. if (gBattleMons[battlerDef].statStages[STAT_EVASION] > DEFAULT_STAT_STAGE @@ -3428,7 +3428,7 @@ void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score) if (GetHealthPercentage(battlerAtk) < 80 && AI_RandLessThan(128)) return; - if (CanAIFaintTarget(battlerAtk, battlerDef, 0)) + if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return; // Damaging moves would get a score boost from AI_TryToFaint or PreferStrongestMove so we don't consider them here switch (statId) @@ -3502,7 +3502,7 @@ void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score) void IncreasePoisonScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) { - if (CanAIFaintTarget(battlerAtk, battlerDef, 0)) + if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return; if (AI_CanPoison(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove) && GetHealthPercentage(battlerDef) > 20) @@ -3525,7 +3525,7 @@ void IncreasePoisonScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) void IncreaseBurnScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) { - if (CanAIFaintTarget(battlerAtk, battlerDef, 0)) + if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return; if (AI_CanBurn(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) @@ -3544,7 +3544,7 @@ void IncreaseBurnScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) void IncreaseParalyzeScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) { - if (CanAIFaintTarget(battlerAtk, battlerDef, 0)) + if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return; if (AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) @@ -3565,7 +3565,7 @@ void IncreaseParalyzeScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) void IncreaseSleepScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) { - if (CanAIFaintTarget(battlerAtk, battlerDef, 0)) + if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return; if (AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) @@ -3583,7 +3583,7 @@ void IncreaseSleepScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) void IncreaseConfusionScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) { - if (CanAIFaintTarget(battlerAtk, battlerDef, 0)) + if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return; if (AI_CanConfuse(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove) From 01cf8e6452d592b5d8010a25fab32dcf0eab9ab7 Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Mon, 8 Nov 2021 11:55:06 -0500 Subject: [PATCH 3/8] add AI_MoveMakesContact, dissuade multi-hit attacks against rocky helmet --- include/battle_ai_util.h | 1 + src/battle_ai_main.c | 3 +++ src/battle_ai_util.c | 9 +++++++++ 3 files changed, 13 insertions(+) diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 6da519342f..cc626fa5e4 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -58,6 +58,7 @@ bool32 CanKnockOffItem(u8 battler, u16 item); bool32 IsAbilityOfRating(u16 ability, s8 rating); s8 GetAbilityRating(u16 ability); bool32 AI_IsAbilityOnSide(u32 battlerId, u32 ability); +bool32 AI_MoveMakesContact(u32 ability, u32 holdEffect, u16 move); // stat stage checks bool32 AnyStatIsRaised(u8 battlerId); diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index b8dbdebac8..cc0f8b2c7b 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -3246,6 +3246,9 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_MULTI_HIT: case EFFECT_DOUBLE_HIT: case EFFECT_TRIPLE_KICK: + if (AI_MoveMakesContact(AI_DATA->atkAbility, AI_DATA->atkHoldEffect, move) + && AI_DATA->defHoldEffect == HOLD_EFFECT_ROCKY_HELMET) + score -= 2; break; case EFFECT_CONVERSION: if (!IS_BATTLER_OF_TYPE(battlerAtk, gBattleMoves[gBattleMons[battlerAtk].moves[0]].type)) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 60083bb29c..19dfab8577 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -3598,3 +3598,12 @@ void IncreaseConfusionScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) *score += 2; } } + +bool32 AI_MoveMakesContact(u32 ability, u32 holdEffect, u16 move) +{ + if (TestMoveFlags(move, FLAG_MAKES_CONTACT) + && ability != ABILITY_LONG_REACH + && holdEffect != HOLD_EFFECT_PROTECTIVE_PADS) + return TRUE; + return FALSE; +} From 4566b5234fde6772184f191471455d3296ddf547 Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Mon, 8 Nov 2021 11:56:51 -0500 Subject: [PATCH 4/8] magic guard user doesnt care about rocky helmet --- src/battle_ai_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index cc0f8b2c7b..317f79d977 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -3247,6 +3247,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_DOUBLE_HIT: case EFFECT_TRIPLE_KICK: if (AI_MoveMakesContact(AI_DATA->atkAbility, AI_DATA->atkHoldEffect, move) + && AI_DATA->atkAbility != ABILITY_MAGIC_GUARD && AI_DATA->defHoldEffect == HOLD_EFFECT_ROCKY_HELMET) score -= 2; break; From 6f6e0d6baf6abe2b58b2ebe37d64ac5579b89873 Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Mon, 8 Nov 2021 21:27:40 -0500 Subject: [PATCH 5/8] add recycle hp berry logic --- src/battle_ai_main.c | 8 ++++++-- src/battle_ai_util.c | 5 ++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 317f79d977..1dcb86805d 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -4111,10 +4111,14 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (AI_DATA->atkAbility == ABILITY_RIPEN) { u16 item = GetUsedHeldItem(battlerAtk); + u16 toHeal = (ItemId_GetHoldEffectParam(item) == 10) ? 10 : gBattleMons[battlerAtk].maxHP / ItemId_GetHoldEffectParam(item); + if (IsStatBoostingBerry(item) && atkHpPercent > 60) score++; - else if (IsHpRestoringBerry(item) && atkHpPercent < 60) - score++; // TODO check if player can still faint us after we heal + else if (IsHpRestoringBerry(item) && !CanAIFaintTarget(battlerAtk, battlerDef, 0) + && ((GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0 && CanTargetFaintAiWithMod(battlerDef, battlerAtk, 0, 0)) + || !CanTargetFaintAiWithMod(battlerDef, battlerAtk, toheal, 0))) + score++; // Recycle healing berry if we can't otherwise faint the target and the target wont kill us after we activate the berry } break; case EFFECT_BRICK_BREAK: diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 19dfab8577..dc85901e32 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -3389,11 +3389,14 @@ bool32 IsStatBoostingBerry(u16 item) } } -bool32 IsHpRestoringBerry(u16 item) +bool32 IsHpRestoringBerry(u8 battlerAtk, u16 item) { switch (item) { case ITEM_ORAN_BERRY: + if (gBattleMons[battlerAtk].maxHp <= 50) + return TRUE; // Only worth it in the early game + return FALSE; case ITEM_SITRUS_BERRY: case ITEM_FIGY_BERRY: case ITEM_WIKI_BERRY: From e635930a150918581e2d6266335327592058450b Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Mon, 8 Nov 2021 21:33:00 -0500 Subject: [PATCH 6/8] fixes --- include/battle_ai_util.h | 2 +- src/battle_ai_main.c | 4 ++-- src/battle_ai_util.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index cc626fa5e4..4fe36c48d5 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -52,7 +52,7 @@ bool32 ShouldRecover(u8 battlerAtk, u8 battlerDef, u16 move, u8 healPercent); bool32 ShouldSetScreen(u8 battlerAtk, u8 battlerDef, u16 moveEffect); bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 moveIndex); bool32 IsRecycleEncouragedItem(u16 item); -bool32 IsHpRestoringBerry(u16 item); +bool32 ShouldRestoreHpBerry(u8 battlerAtk, u16 item); bool32 IsStatBoostingBerry(u16 item); bool32 CanKnockOffItem(u8 battler, u16 item); bool32 IsAbilityOfRating(u16 ability, s8 rating); diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 1dcb86805d..fcd11d1c3c 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -4115,9 +4115,9 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (IsStatBoostingBerry(item) && atkHpPercent > 60) score++; - else if (IsHpRestoringBerry(item) && !CanAIFaintTarget(battlerAtk, battlerDef, 0) + else if (ShouldRestoreHpBerry(battlerAtk, item) && !CanAIFaintTarget(battlerAtk, battlerDef, 0) && ((GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0 && CanTargetFaintAiWithMod(battlerDef, battlerAtk, 0, 0)) - || !CanTargetFaintAiWithMod(battlerDef, battlerAtk, toheal, 0))) + || !CanTargetFaintAiWithMod(battlerDef, battlerAtk, toHeal, 0))) score++; // Recycle healing berry if we can't otherwise faint the target and the target wont kill us after we activate the berry } break; diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index dc85901e32..c90c9cdab4 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -3389,12 +3389,12 @@ bool32 IsStatBoostingBerry(u16 item) } } -bool32 IsHpRestoringBerry(u8 battlerAtk, u16 item) +bool32 ShouldRestoreHpBerry(u8 battlerAtk, u16 item) { switch (item) { case ITEM_ORAN_BERRY: - if (gBattleMons[battlerAtk].maxHp <= 50) + if (gBattleMons[battlerAtk].maxHP <= 50) return TRUE; // Only worth it in the early game return FALSE; case ITEM_SITRUS_BERRY: From 276b454b4088d7ffd4f57e22fdc5982056375f11 Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Fri, 12 Nov 2021 08:13:17 -0500 Subject: [PATCH 7/8] primal weather checks --- src/battle_ai_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index fcd11d1c3c..3e51b0dc4a 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -1392,22 +1392,22 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_SANDSTORM: - if (gBattleWeather & WEATHER_SANDSTORM_ANY //TODO | WEATHER_PRIMAL_ANY) + if (gBattleWeather & (WEATHER_SANDSTORM_ANY | WEATHER_PRIMAL_ANY) || PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove)) score -= 8; break; case EFFECT_SUNNY_DAY: - if (gBattleWeather & WEATHER_SUN_ANY //TODO | WEATHER_PRIMAL_ANY) + if (gBattleWeather & (WEATHER_SUN_ANY | WEATHER_PRIMAL_ANY) || PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove)) score -= 8; break; case EFFECT_RAIN_DANCE: - if (gBattleWeather & WEATHER_RAIN_ANY //TODO | WEATHER_PRIMAL_ANY) + if (gBattleWeather & (WEATHER_RAIN_ANY | WEATHER_PRIMAL_ANY) || PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove)) score -= 8; break; case EFFECT_HAIL: - if (gBattleWeather & WEATHER_HAIL_ANY //TODO | WEATHER_PRIMAL_ANY) + if (gBattleWeather & (WEATHER_HAIL_ANY | WEATHER_PRIMAL_ANY) || PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove)) score -= 8; break; From 9fdd6fffee4d06d56f610ff3265adcb4571dbc3c Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Mon, 15 Nov 2021 10:45:23 -0500 Subject: [PATCH 8/8] AI_GetAbility supports hidden abilities --- src/battle_ai_util.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index c90c9cdab4..499969ec33 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -1133,18 +1133,17 @@ s32 AI_GetAbility(u32 battlerId) || gBattleMons[battlerId].ability == ABILITY_MAGNET_PULL || gBattleMons[battlerId].ability == ABILITY_ARENA_TRAP) return gBattleMons[battlerId].ability; - + + // AI has no knowledge of opponent, so it guesses which ability. if (gBaseStats[gBattleMons[battlerId].species].abilities[0] != ABILITY_NONE) { - if (gBaseStats[gBattleMons[battlerId].species].abilities[1] != ABILITY_NONE) + u16 abilityGuess = ABILITY_NONE; + while (abilityGuess == ABILITY_NONE) { - // AI has no knowledge of opponent, so it guesses which ability. - return gBaseStats[gBattleMons[battlerId].species].abilities[Random() & 1]; - } - else - { - return gBaseStats[gBattleMons[battlerId].species].abilities[0]; // It's definitely ability 1. + abilityGuess = gBaseStats[gBattleMons[battlerId].species].abilities[Random() % NUM_ABILITY_SLOTS]; } + + return abilityGuess; } return ABILITY_NONE; // Unknown. }