From b78fccdb663eb51a3ffdc5cd6cfe6e53f0168026 Mon Sep 17 00:00:00 2001 From: Eduardo Quezada Date: Thu, 18 Dec 2025 19:24:52 -0300 Subject: [PATCH] `B_STURDY` config test (#8565) --- include/constants/generational_changes.h | 2 +- src/battle_ai_switch_items.c | 4 ++-- src/battle_ai_util.c | 6 ++--- src/battle_script_commands.c | 2 +- test/battle/ability/sturdy.c | 29 ++++++++++++++++++++---- 5 files changed, 31 insertions(+), 12 deletions(-) diff --git a/include/constants/generational_changes.h b/include/constants/generational_changes.h index f94b7e8309..7d0699d479 100644 --- a/include/constants/generational_changes.h +++ b/include/constants/generational_changes.h @@ -132,7 +132,7 @@ F(SYNCHRONIZE_TOXIC, synchronizeToxic, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \ F(UPDATED_INTIMIDATE, updatedIntimidate, (u32, GEN_COUNT - 1)) \ F(OBLIVIOUS_TAUNT, obliviousTaunt, (u32, GEN_COUNT - 1)) \ - F(STURDY, sturdy, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \ + F(STURDY, sturdy, (u32, GEN_COUNT - 1)) \ F(PLUS_MINUS_INTERACTION, plusMinusInteraction, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \ F(WEATHER_FORMS, weatherForms, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \ F(SYMBIOSIS_GEMS, symbiosisGems, (u32, GEN_COUNT - 1)) \ diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index 5b924d23e5..1c327879cd 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -298,7 +298,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler) // Check if mon gets one shot if (maxDamageTaken > gBattleMons[battler].hp - && !(gItemsInfo[gBattleMons[battler].item].holdEffect == HOLD_EFFECT_FOCUS_SASH || (!IsMoldBreakerTypeAbility(opposingBattler, gAiLogicData->abilities[opposingBattler]) && B_STURDY >= GEN_5 && aiAbility == ABILITY_STURDY))) + && !(gItemsInfo[gBattleMons[battler].item].holdEffect == HOLD_EFFECT_FOCUS_SASH || (!IsMoldBreakerTypeAbility(opposingBattler, gAiLogicData->abilities[opposingBattler]) && GetConfig(CONFIG_STURDY) >= GEN_5 && aiAbility == ABILITY_STURDY))) { getsOneShot = TRUE; } @@ -1852,7 +1852,7 @@ static u32 GetSwitchinHitsToKO(s32 damageTaken, u32 battler) currentHP = currentHP - damageTaken; // One shot prevention effects - if (damageTaken >= maxHP && startingHP == maxHP && (heldItemEffect == HOLD_EFFECT_FOCUS_SASH || (!opponentCanBreakMold && B_STURDY >= GEN_5 && ability == ABILITY_STURDY)) && hitsToKO < 1) + if (damageTaken >= maxHP && startingHP == maxHP && (heldItemEffect == HOLD_EFFECT_FOCUS_SASH || (!opponentCanBreakMold && GetConfig(CONFIG_STURDY) >= GEN_5 && ability == ABILITY_STURDY)) && hitsToKO < 1) currentHP = 1; // If mon is still alive, apply weather impact first, as it might KO the mon before it can heal with its item (order is weather -> item -> status) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 413bbcc8ac..a66a24e2e7 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -1469,7 +1469,7 @@ bool32 CanEndureHit(u32 battler, u32 battlerTarget, u32 move) if (!DoesBattlerIgnoreAbilityChecks(battler, gAiLogicData->abilities[battler], move)) { - if (B_STURDY >= GEN_5 && gAiLogicData->abilities[battlerTarget] == ABILITY_STURDY) + if (GetConfig(CONFIG_STURDY) >= GEN_5 && gAiLogicData->abilities[battlerTarget] == ABILITY_STURDY) return TRUE; if (IsMimikyuDisguised(battlerTarget)) return TRUE; @@ -3351,7 +3351,7 @@ enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, enum Ability defAbility if (!IsBattleMoveStatus(move) && ((gAiLogicData->shouldSwitch & (1u << battlerAtk)) || (AI_BattlerAtMaxHp(battlerDef) && (gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH - || (B_STURDY >= GEN_5 && defAbility == ABILITY_STURDY) + || (GetConfig(CONFIG_STURDY) >= GEN_5 && defAbility == ABILITY_STURDY) || defAbility == ABILITY_MULTISCALE || defAbility == ABILITY_SHADOW_SHIELD)))) return SHOULD_PIVOT; // pivot to break sash/sturdy/multiscale @@ -3359,7 +3359,7 @@ enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, enum Ability defAbility else if (!hasStatBoost) { if (!IsBattleMoveStatus(move) && (AI_BattlerAtMaxHp(battlerDef) && (gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH - || (B_STURDY >= GEN_5 && defAbility == ABILITY_STURDY) + || (GetConfig(CONFIG_STURDY) >= GEN_5 && defAbility == ABILITY_STURDY) || defAbility == ABILITY_MULTISCALE || defAbility == ABILITY_SHADOW_SHIELD))) return SHOULD_PIVOT; // pivot to break sash/sturdy/multiscale diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 92c4bff67c..98eb569ee2 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1929,7 +1929,7 @@ static void Cmd_adjustdamage(void) gLastUsedItem = gBattleMons[battlerDef].item; gBattleStruct->moveResultFlags[battlerDef] |= MOVE_RESULT_FOE_HUNG_ON; } - else if (B_STURDY >= GEN_5 && GetBattlerAbility(battlerDef) == ABILITY_STURDY && IsBattlerAtMaxHp(battlerDef)) + else if (GetConfig(CONFIG_STURDY) >= GEN_5 && GetBattlerAbility(battlerDef) == ABILITY_STURDY && IsBattlerAtMaxHp(battlerDef)) { enduredHit |= 1u << battlerDef; RecordAbilityBattle(battlerDef, ABILITY_STURDY); diff --git a/test/battle/ability/sturdy.c b/test/battle/ability/sturdy.c index 5ba7e16ea8..7087de3a02 100644 --- a/test/battle/ability/sturdy.c +++ b/test/battle/ability/sturdy.c @@ -18,18 +18,37 @@ SINGLE_BATTLE_TEST("Sturdy prevents OHKO moves") } } -SINGLE_BATTLE_TEST("Sturdy prevents OHKOs") +SINGLE_BATTLE_TEST("Sturdy prevents OHKOs (Gen5+)") { + u32 config; + PARAMETRIZE { config = GEN_4; } + PARAMETRIZE { config = GEN_5; } GIVEN { + WITH_CONFIG(CONFIG_STURDY, config); PLAYER(SPECIES_GEODUDE) { Ability(ABILITY_STURDY); MaxHP(100); HP(100); } + PLAYER(SPECIES_GEODUDE); OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(opponent, MOVE_SEISMIC_TOSS); } + TURN { + MOVE(opponent, MOVE_SEISMIC_TOSS); + if (config < GEN_5) { + SEND_OUT(player, 1); + } + } } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_SEISMIC_TOSS, opponent); - HP_BAR(player, hp: 1); - ABILITY_POPUP(player, ABILITY_STURDY); - MESSAGE("Geodude endured the hit using Sturdy!"); + if (config >= GEN_5) { + HP_BAR(player, hp: 1); + ABILITY_POPUP(player, ABILITY_STURDY); + MESSAGE("Geodude endured the hit using Sturdy!"); + } else { + HP_BAR(player, hp: 0); + NONE_OF { + ABILITY_POPUP(player, ABILITY_STURDY); + MESSAGE("Geodude endured the hit using Sturdy!"); + } + SEND_IN_MESSAGE("Geodude"); + } } }