From 320c6cf11f09e8f9c895591904bc6923a3a903e5 Mon Sep 17 00:00:00 2001 From: PhallenTree <168426989+PhallenTree@users.noreply.github.com> Date: Sun, 23 Feb 2025 19:50:52 +0000 Subject: [PATCH] Fixes Coaching on semi-invulnerable ally, Air Balloon being stolen, Immunity abilities being ignored by Mold Breaker (#6327) --- data/battle_scripts_1.s | 2 ++ include/battle.h | 3 ++- src/battle_script_commands.c | 2 +- src/battle_util.c | 16 +++++++++++++--- test/battle/ability/own_tempo.c | 8 ++------ test/battle/ability/pastel_veil.c | 1 - test/battle/hold_effect/air_balloon.c | 1 - test/battle/hold_effect/jaboca_berry.c | 4 ++-- test/battle/move_effect/coaching.c | 1 - test/battle/move_effect/two_turns_attack.c | 2 -- 10 files changed, 22 insertions(+), 18 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 3016540a80..758c6e8bbf 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -1035,6 +1035,7 @@ BattleScript_EffectCoaching:: setallytonexttarget EffectCoaching_CheckAllyStats goto BattleScript_ButItFailed EffectCoaching_CheckAllyStats: + accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON jumpifstat BS_TARGET, CMP_NOT_EQUAL, STAT_ATK, MAX_STAT_STAGE, BattleScript_CoachingWorks jumpifstat BS_TARGET, CMP_NOT_EQUAL, STAT_DEF, MAX_STAT_STAGE, BattleScript_CoachingWorks goto BattleScript_ButItFailed @ ally at max atk, def @@ -3775,6 +3776,7 @@ BattleScript_TwoTurnMovesSecondTurn:: BattleScript_TwoTurnMovesSecondTurnRet: setbyte sB_ANIM_TURN, 1 + setbyte sB_ANIM_TARGETS_HIT, 0 clearstatusfromeffect BS_ATTACKER, MOVE_EFFECT_CHARGING clearsemiinvulnerablebit @ only for moves with EFFECT_SEMI_INVULNERABLE/EFFECT_SKY_DROP return diff --git a/include/battle.h b/include/battle.h index 2659c08844..4e9313d10d 100644 --- a/include/battle.h +++ b/include/battle.h @@ -829,7 +829,8 @@ struct BattleStruct u16 commanderActive[MAX_BATTLERS_COUNT]; u32 stellarBoostFlags[NUM_BATTLE_SIDES]; // stored as a bitfield of flags for all types for each side u8 redCardActivates:1; - u8 padding:7; + u8 bypassMoldBreakerChecks:1; // for ABILITYEFFECT_IMMUNITY + u8 padding:6; u8 usedEjectItem; u8 usedMicleBerry; u8 trainerSlideSpriteIds[MAX_BATTLERS_COUNT]; diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index c3dc016314..a74e0e5bcc 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -3639,7 +3639,7 @@ void SetMoveEffect(bool32 primary, bool32 certain) gProtectStructs[gBattlerTarget].banefulBunkered = FALSE; gProtectStructs[gBattlerTarget].obstructed = FALSE; gProtectStructs[gBattlerTarget].silkTrapped = FALSE; - gProtectStructs[gBattlerAttacker].burningBulwarked = FALSE; + gProtectStructs[gBattlerTarget].burningBulwarked = FALSE; BattleScriptPush(gBattlescriptCurrInstr + 1); if (gCurrentMove == MOVE_HYPERSPACE_FURY) gBattlescriptCurrInstr = BattleScript_HyperspaceFuryRemoveProtect; diff --git a/src/battle_util.c b/src/battle_util.c index 5c32262b43..8096e8e487 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -6251,6 +6251,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 } break; case ABILITYEFFECT_IMMUNITY: + gBattleStruct->bypassMoldBreakerChecks = TRUE; for (battler = 0; battler < gBattlersCount; battler++) { switch (GetBattlerAbility(battler)) @@ -6341,6 +6342,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 return effect; } } + gBattleStruct->bypassMoldBreakerChecks = FALSE; break; case ABILITYEFFECT_SYNCHRONIZE: if (gLastUsedAbility == ABILITY_SYNCHRONIZE && (gHitMarker & HITMARKER_SYNCHRONISE_EFFECT)) @@ -6570,7 +6572,9 @@ u32 GetBattlerAbility(u32 battler) && gBattleMons[battler].ability == ABILITY_COMATOSE) return ABILITY_NONE; - if (noAbilityShield && CanBreakThroughAbility(gBattlerAttacker, battler, gBattleMons[gBattlerAttacker].ability)) + if (!gBattleStruct->bypassMoldBreakerChecks + && noAbilityShield + && CanBreakThroughAbility(gBattlerAttacker, battler, gBattleMons[gBattlerAttacker].ability)) return ABILITY_NONE; return gBattleMons[battler].ability; @@ -6584,7 +6588,9 @@ u32 GetBattlerAbility(u32 battler) && noAbilityShield) return ABILITY_NONE; - if (noAbilityShield && CanBreakThroughAbility(gBattlerAttacker, battler, gBattleMons[gBattlerAttacker].ability)) + if (!gBattleStruct->bypassMoldBreakerChecks + && noAbilityShield + && CanBreakThroughAbility(gBattlerAttacker, battler, gBattleMons[gBattlerAttacker].ability)) return ABILITY_NONE; return gBattleMons[battler].ability; @@ -11436,8 +11442,12 @@ bool32 CanStealItem(u32 battlerStealing, u32 battlerItem, u16 item) return FALSE; } + // It's supposed to pop before trying to steal but this also works + if (ItemId_GetHoldEffect(item) == HOLD_EFFECT_AIR_BALLOON) + return FALSE; + if (!CanBattlerGetOrLoseItem(battlerItem, item) // Battler with item cannot have it stolen - ||!CanBattlerGetOrLoseItem(battlerStealing, item)) // Stealer cannot take the item + || !CanBattlerGetOrLoseItem(battlerStealing, item)) // Stealer cannot take the item return FALSE; return TRUE; diff --git a/test/battle/ability/own_tempo.c b/test/battle/ability/own_tempo.c index 1f3f49c006..01ecdc9434 100644 --- a/test/battle/ability/own_tempo.c +++ b/test/battle/ability/own_tempo.c @@ -58,7 +58,6 @@ SINGLE_BATTLE_TEST("Own Tempo prevents confusion from moves by the user") SINGLE_BATTLE_TEST("Mold Breaker ignores Own Tempo") { - KNOWN_FAILING; // Ideally the func CanBeConfused should be split into AttackerCanBeConfused and TargetCanBeConfused or we do it in the same func but have a check for when battlerAtk == battlerDef GIVEN { ASSUME(gMovesInfo[MOVE_CONFUSE_RAY].effect == EFFECT_CONFUSE); PLAYER(SPECIES_PINSIR) { Ability(ABILITY_MOLD_BREAKER); } @@ -66,16 +65,13 @@ SINGLE_BATTLE_TEST("Mold Breaker ignores Own Tempo") } WHEN { TURN { MOVE(player, MOVE_CONFUSE_RAY); } } SCENE { - NONE_OF { - ABILITY_POPUP(opponent, ABILITY_OWN_TEMPO); - MESSAGE("The opposing Slowpoke's Own Tempo prevents confusion!"); - } + ANIMATION(ANIM_TYPE_MOVE, MOVE_CONFUSE_RAY, player); + NOT MESSAGE("The opposing Slowpoke's Own Tempo prevents confusion!"); } } SINGLE_BATTLE_TEST("Mold Breaker does not prevent Own Tempo from curing confusion right after") { - KNOWN_FAILING; GIVEN { ASSUME(gMovesInfo[MOVE_CONFUSE_RAY].effect == EFFECT_CONFUSE); PLAYER(SPECIES_PINSIR) { Ability(ABILITY_MOLD_BREAKER); }; diff --git a/test/battle/ability/pastel_veil.c b/test/battle/ability/pastel_veil.c index a6b6168547..2b721fd095 100644 --- a/test/battle/ability/pastel_veil.c +++ b/test/battle/ability/pastel_veil.c @@ -33,7 +33,6 @@ DOUBLE_BATTLE_TEST("Pastel Veil prevents Poison Sting poison on partner") SINGLE_BATTLE_TEST("Pastel Veil immediately cures Mold Breaker poison") { - KNOWN_FAILING; GIVEN { ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC); PLAYER(SPECIES_PINSIR) { Ability(ABILITY_MOLD_BREAKER); } diff --git a/test/battle/hold_effect/air_balloon.c b/test/battle/hold_effect/air_balloon.c index 293e1d80ca..c99423edc1 100644 --- a/test/battle/hold_effect/air_balloon.c +++ b/test/battle/hold_effect/air_balloon.c @@ -105,7 +105,6 @@ SINGLE_BATTLE_TEST("Air Balloon pops before it can be stolen with Magician") SINGLE_BATTLE_TEST("Air Balloon pops before it can be stolen with Thief or Covet") { u32 move; - KNOWN_FAILING; PARAMETRIZE { move = MOVE_THIEF; } PARAMETRIZE { move = MOVE_COVET; } GIVEN { diff --git a/test/battle/hold_effect/jaboca_berry.c b/test/battle/hold_effect/jaboca_berry.c index 373780be71..8e69ff1bac 100644 --- a/test/battle/hold_effect/jaboca_berry.c +++ b/test/battle/hold_effect/jaboca_berry.c @@ -54,7 +54,7 @@ SINGLE_BATTLE_TEST("Jaboca Berry tirggers before Bug Bite can steal it") HP_BAR(opponent); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); HP_BAR(player); - MESSAGE("Wyanut was hurt by the opposing Wobbuffet's Jaboca Berry!"); - NOT MESSAGE("Wynaut stole and ate the opposing its target's Jaboca Berry!"); + MESSAGE("Wynaut was hurt by the opposing Wobbuffet's Jaboca Berry!"); + NOT MESSAGE("Wynaut stole and ate the opposing Wobbuffet's Jaboca Berry!"); } } diff --git a/test/battle/move_effect/coaching.c b/test/battle/move_effect/coaching.c index 451ac80495..4d5581ac33 100644 --- a/test/battle/move_effect/coaching.c +++ b/test/battle/move_effect/coaching.c @@ -58,7 +58,6 @@ DOUBLE_BATTLE_TEST("Coaching bypasses Crafty Shield") DOUBLE_BATTLE_TEST("Coaching fails if all allies are is semi-invulnerable") { - KNOWN_FAILING; // Coaching succeeds GIVEN { ASSUME(gMovesInfo[MOVE_FLY].effect == EFFECT_SEMI_INVULNERABLE); PLAYER(SPECIES_WOBBUFFET); diff --git a/test/battle/move_effect/two_turns_attack.c b/test/battle/move_effect/two_turns_attack.c index efeb419ce5..78dd62f093 100644 --- a/test/battle/move_effect/two_turns_attack.c +++ b/test/battle/move_effect/two_turns_attack.c @@ -49,7 +49,6 @@ SINGLE_BATTLE_TEST("Razor Wind needs a charging turn") SINGLE_BATTLE_TEST("Razor Wind doesn't need to charge with Power Herb") { - KNOWN_FAILING; GIVEN { PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_POWER_HERB); } OPPONENT(SPECIES_WOBBUFFET); @@ -69,7 +68,6 @@ SINGLE_BATTLE_TEST("Razor Wind doesn't need to charge with Power Herb") MESSAGE("Wobbuffet became fully charged due to its Power Herb!"); if (B_UPDATED_MOVE_DATA < GEN_5) MESSAGE("Wobbuffet used Razor Wind!"); - // For some reason, this breaks with and only with Razor Wind... ANIMATION(ANIM_TYPE_MOVE, MOVE_RAZOR_WIND, player); HP_BAR(opponent); }