From 8efc34eb7e20df2a953abb19e04161d62a75ad15 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Sun, 1 Oct 2023 01:30:28 +0200 Subject: [PATCH 1/6] flinch tests + protect/flinch fix (#3345) --- src/battle_script_commands.c | 3 +- test/battle/move_effect/flinch_hit.c | 71 ++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 test/battle/move_effect/flinch_hit.c diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 588150e5e2..958600a1fd 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -10776,8 +10776,9 @@ static void Cmd_setprotectlike(void) bool32 fail = TRUE; bool32 notLastTurn = TRUE; + u32 lastMove = gLastResultingMoves[gBattlerAttacker]; - if (!gBattleMoves[gLastResultingMoves[gBattlerAttacker]].protectionMove) + if (lastMove == MOVE_UNAVAILABLE || !(gBattleMoves[lastMove].protectionMove)) gDisableStructs[gBattlerAttacker].protectUses = 0; if (gCurrentTurnActionNumber == (gBattlersCount - 1)) diff --git a/test/battle/move_effect/flinch_hit.c b/test/battle/move_effect/flinch_hit.c new file mode 100644 index 0000000000..c8c650db7d --- /dev/null +++ b/test/battle/move_effect/flinch_hit.c @@ -0,0 +1,71 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gBattleMoves[MOVE_HEADBUTT].effect == EFFECT_FLINCH_HIT); +} + +SINGLE_BATTLE_TEST("Headbutt flinches the target if attacker is faster") +{ + bool8 isFaster; + u16 spdPlayer, spdOpponent; + + PARAMETRIZE { isFaster = TRUE; spdPlayer = 10; spdOpponent = 5; } + PARAMETRIZE { isFaster = FALSE; spdPlayer = 5; spdOpponent = 10; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Speed(spdPlayer); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(spdOpponent); } + } WHEN { + TURN { MOVE(player, MOVE_HEADBUTT); } + TURN { MOVE(player, MOVE_HEADBUTT); } + } SCENE { + // 1st turn + ANIMATION(ANIM_TYPE_MOVE, MOVE_HEADBUTT, player); + HP_BAR(opponent); + if (isFaster) { + MESSAGE("Foe Wobbuffet flinched!"); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); + } else { + NOT MESSAGE("Foe Wobbuffet flinched!"); + } + + // 2nd turn + ANIMATION(ANIM_TYPE_MOVE, MOVE_HEADBUTT, player); + HP_BAR(opponent); + if (isFaster) { + MESSAGE("Foe Wobbuffet flinched!"); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); + } else { + NOT MESSAGE("Foe Wobbuffet flinched!"); + } + } +} + +SINGLE_BATTLE_TEST("Protect always works when used after flinching") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Speed(5); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(100); } + } WHEN { + TURN { MOVE(player, MOVE_PROTECT); MOVE(opponent, MOVE_HEADBUTT); } + TURN { MOVE(player, MOVE_TACKLE); MOVE(opponent, MOVE_HEADBUTT); } + TURN { MOVE(player, MOVE_PROTECT); MOVE(opponent, MOVE_HEADBUTT); } + } SCENE { + // 1st turn + ANIMATION(ANIM_TYPE_MOVE, MOVE_PROTECT, player); + MESSAGE("Wobbuffet protected itself!"); + + // 2nd turn + ANIMATION(ANIM_TYPE_MOVE, MOVE_HEADBUTT, opponent); + HP_BAR(player); + MESSAGE("Wobbuffet flinched!"); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player); + + // 3rd turn + ANIMATION(ANIM_TYPE_MOVE, MOVE_PROTECT, player); + MESSAGE("Wobbuffet protected itself!"); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_HEADBUTT, opponent); + } +} From cc1d748b47b3599c3bda3d03efc7b63bda6864a7 Mon Sep 17 00:00:00 2001 From: kittenchilly Date: Sat, 30 Sep 2023 18:34:52 -0500 Subject: [PATCH 2/6] Fixed Shiny Charm doing too many rerolls by default (#3327) Co-authored-by: Eduardo Quezada D'Ottone --- include/config/item.h | 2 +- src/pokemon.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/config/item.h b/include/config/item.h index 0cd89b612d..c0575a352a 100644 --- a/include/config/item.h +++ b/include/config/item.h @@ -2,7 +2,7 @@ #define GUARD_CONFIG_ITEM_H // Item config -#define I_SHINY_CHARM_REROLLS 3 // Amount of re-rolls if the player has the Shiny Charm. Set to 0 to disable Shiny Charm's effects. +#define I_SHINY_CHARM_ADDITIONAL_ROLLS 2 // Amount of additional shiny rolls if the player has the Shiny Charm. Set it to 0 to disable Shiny Charm's effects. #define I_KEY_FOSSILS GEN_LATEST // In Gen4+, all Gen 3 fossils became regular items. #define I_KEY_ESCAPE_ROPE GEN_LATEST // In Gen8, Escape Rope became a Key Item. Keep in mind, this will make it free to buy in marts. #define I_HEALTH_RECOVERY GEN_LATEST // In Gen7+, certain healing items recover a different amount of HP than they used to. diff --git a/src/pokemon.c b/src/pokemon.c index 1320774f1e..a360feb0ba 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -3488,7 +3488,7 @@ void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV, { u32 totalRerolls = 0; if (CheckBagHasItem(ITEM_SHINY_CHARM, 1)) - totalRerolls += I_SHINY_CHARM_REROLLS; + totalRerolls += I_SHINY_CHARM_ADDITIONAL_ROLLS; if (LURE_STEP_COUNT != 0) totalRerolls += 1; From 093c65380107f6bd42bfb96c4fd23978584f9231 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Sun, 1 Oct 2023 15:25:04 +0200 Subject: [PATCH 3/6] Fixed Berserk gene issue in double battles (#3363) * fix berserk gene issue + tests * Update test/battle/hold_effect/berserk_gene.c Co-authored-by: Eduardo Quezada D'Ottone * Update test/battle/hold_effect/berserk_gene.c Co-authored-by: Eduardo Quezada D'Ottone * berserk gene review changes --------- Co-authored-by: Eduardo Quezada D'Ottone --- data/battle_scripts_1.s | 3 + test/battle/hold_effect/berserk_gene.c | 99 +++++++++++++++++++++----- 2 files changed, 85 insertions(+), 17 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index d03e37085c..76987499be 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -10340,6 +10340,8 @@ BattleScript_CouldntFullyProtect:: BattleScript_BerserkGeneRet:: BattleScript_BerserkGeneRet_Anim: + savetarget + copybyte gBattlerTarget, sBATTLER statbuffchange STAT_CHANGE_ALLOW_PTR, BattleScript_BerserkGeneRet_TryConfuse setgraphicalstatchangevalues playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT, sB_ANIM_ARG1 @@ -10362,6 +10364,7 @@ BattleScript_BerserkGeneRet_OwnTempoPrevents: printstring STRINGID_PKMNPREVENTSCONFUSIONWITH waitmessage B_WAIT_TIME_LONG BattleScript_BerserkGeneRet_End: + restoretarget removeitem BS_SCRIPTING end3 diff --git a/test/battle/hold_effect/berserk_gene.c b/test/battle/hold_effect/berserk_gene.c index 6fd0f8a855..8419eff3c3 100644 --- a/test/battle/hold_effect/berserk_gene.c +++ b/test/battle/hold_effect/berserk_gene.c @@ -6,18 +6,18 @@ ASSUMPTIONS ASSUME(gItems[ITEM_BERSERK_GENE].holdEffect == HOLD_EFFECT_BERSERK_GENE); } -SINGLE_BATTLE_TEST("Berserk Gene sharply raises attack at the start of battle", s16 damage) +SINGLE_BATTLE_TEST("Berserk Gene sharply raises attack at the start of a single battle", s16 damage) { - u16 useItem; - PARAMETRIZE { useItem = FALSE; } - PARAMETRIZE { useItem = TRUE; } + u16 item; + PARAMETRIZE { item = ITEM_NONE; } + PARAMETRIZE { item = ITEM_BERSERK_GENE; } GIVEN { - PLAYER(SPECIES_WOBBUFFET) { if (useItem) Item(ITEM_BERSERK_GENE); } + PLAYER(SPECIES_WOBBUFFET) { Item(item); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { MOVE(player, MOVE_TACKLE, WITH_RNG(RNG_CONFUSION, FALSE)); } } SCENE { - if (useItem) + if (item == ITEM_BERSERK_GENE) { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); MESSAGE("Using Berserk Gene, the Attack of Wobbuffet sharply rose!"); @@ -30,20 +30,46 @@ SINGLE_BATTLE_TEST("Berserk Gene sharply raises attack at the start of battle", } } +DOUBLE_BATTLE_TEST("Berserk Gene sharply raises attack at the start of a double battle", s16 damage) +{ + u16 item; + PARAMETRIZE { item = ITEM_NONE; } + PARAMETRIZE { item = ITEM_BERSERK_GENE; } + GIVEN { + PLAYER(SPECIES_WYNAUT); + PLAYER(SPECIES_WOBBUFFET) { Item(item); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerRight, MOVE_TACKLE, target:opponentLeft, WITH_RNG(RNG_CONFUSION, FALSE)); } + } SCENE { + if (item == ITEM_BERSERK_GENE) + { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight); + MESSAGE("Using Berserk Gene, the Attack of Wobbuffet sharply rose!"); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_CONFUSION, playerRight); + MESSAGE("Wobbuffet became confused!"); + } + HP_BAR(opponentLeft, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(2.0), results[1].damage); + } +} + SINGLE_BATTLE_TEST("Berserk Gene activates on switch in", s16 damage) { - u16 useItem; - PARAMETRIZE { useItem = FALSE; } - PARAMETRIZE { useItem = TRUE; } + u16 item; + PARAMETRIZE { item = ITEM_NONE; } + PARAMETRIZE { item = ITEM_BERSERK_GENE; } GIVEN { PLAYER(SPECIES_WYNAUT); - PLAYER(SPECIES_WOBBUFFET) { if (useItem) Item(ITEM_BERSERK_GENE); } + PLAYER(SPECIES_WOBBUFFET) { Item(item); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { SWITCH(player, 1); } TURN { MOVE(player, MOVE_TACKLE, WITH_RNG(RNG_CONFUSION, FALSE)); } } SCENE { - if (useItem) + if (item == ITEM_BERSERK_GENE) { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); MESSAGE("Using Berserk Gene, the Attack of Wobbuffet sharply rose!"); @@ -56,20 +82,20 @@ SINGLE_BATTLE_TEST("Berserk Gene activates on switch in", s16 damage) } } -SINGLE_BATTLE_TEST("Berserk Gene does not confuse a Pokemon with Own Tempo but still raises attack sharply", s16 damage) +SINGLE_BATTLE_TEST("Berserk Gene does not confuse a Pokemon with Own Tempo but still raises attack sharply in a single battle", s16 damage) { - u16 useItem; - PARAMETRIZE { useItem = FALSE; } - PARAMETRIZE { useItem = TRUE; } + u16 item; + PARAMETRIZE { item = ITEM_NONE; } + PARAMETRIZE { item = ITEM_BERSERK_GENE; } GIVEN { - PLAYER(SPECIES_SLOWBRO) { Ability(ABILITY_OWN_TEMPO); if (useItem) Item(ITEM_BERSERK_GENE); } + PLAYER(SPECIES_SLOWBRO) { Ability(ABILITY_OWN_TEMPO); Item(item); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { MOVE(player, MOVE_TACKLE); } } SCENE { - if (useItem) + if (item == ITEM_BERSERK_GENE) { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); MESSAGE("Using Berserk Gene, the Attack of Slowbro sharply rose!"); @@ -83,6 +109,45 @@ SINGLE_BATTLE_TEST("Berserk Gene does not confuse a Pokemon with Own Tempo but s } } +DOUBLE_BATTLE_TEST("Berserk Gene does not confuse a Pokemon with Own Tempo but still raises attack sharply in a double battle", s16 damage) +{ + u16 item; + bool8 positionLeft = FALSE; + + PARAMETRIZE { item = ITEM_NONE; } + PARAMETRIZE { item = ITEM_BERSERK_GENE; positionLeft = TRUE; } + PARAMETRIZE { item = ITEM_BERSERK_GENE; positionLeft = FALSE; } + GIVEN { + if (positionLeft) { + PLAYER(SPECIES_SLOWBRO) { Ability(ABILITY_OWN_TEMPO); Item(item); } + PLAYER(SPECIES_WOBBUFFET); + } else { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_SLOWBRO) { Ability(ABILITY_OWN_TEMPO); Item(item); } + } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { + MOVE((positionLeft != 0) ? playerLeft : playerRight, MOVE_TACKLE, target: opponentLeft); + } + } SCENE { + if (item == ITEM_BERSERK_GENE) + { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, (positionLeft != 0) ? playerLeft : playerRight); + MESSAGE("Using Berserk Gene, the Attack of Slowbro sharply rose!"); + ABILITY_POPUP((positionLeft != 0) ? playerLeft : playerRight, ABILITY_OWN_TEMPO); + MESSAGE("Slowbro's Own Tempo prevents confusion!"); + } + HP_BAR(opponentLeft, captureDamage: &results[i].damage); + NOT MESSAGE("Slowbro became confused!"); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(2.0), results[1].damage); + EXPECT_MUL_EQ(results[0].damage, Q_4_12(2.0), results[2].damage); + EXPECT_EQ(((positionLeft != 0) ? playerLeft : playerRight)->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 2); + } +} + SINGLE_BATTLE_TEST("Berserk Gene does not confuse on Misty Terrain but still raises attack sharply") { GIVEN { From 10adba3af4fa8b28085f749c36614c2221f5d76f Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Sun, 1 Oct 2023 15:30:41 +0200 Subject: [PATCH 4/6] Fixed entry hazards switch in issue (#3316) * fix entry hazards switch in issue * accidental known failing fix --- include/battle.h | 4 ++ include/constants/battle.h | 6 +-- src/battle_anim.c | 8 ++-- src/battle_message.c | 4 +- src/battle_script_commands.c | 22 +++++----- test/battle/hold_effect/cure_status.c | 56 +++++++++++++++++++++++++- test/battle/move_effect/toxic_spikes.c | 32 +++++++++++++++ 7 files changed, 110 insertions(+), 22 deletions(-) diff --git a/include/battle.h b/include/battle.h index 60c583e503..f24d65c945 100644 --- a/include/battle.h +++ b/include/battle.h @@ -99,6 +99,10 @@ struct DisableStruct u8 tarShot:1; u8 octolock:1; u8 cudChew:1; + u8 spikesDone:1; + u8 toxicSpikesDone:1; + u8 stickyWebDone:1; + u8 stealthRockDone:1; }; struct ProtectStruct diff --git a/include/constants/battle.h b/include/constants/battle.h index 0f0d39db8d..5e94f27fe9 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -224,15 +224,13 @@ #define SIDE_STATUS_SAFEGUARD (1 << 5) #define SIDE_STATUS_FUTUREATTACK (1 << 6) #define SIDE_STATUS_MIST (1 << 8) -#define SIDE_STATUS_SPIKES_DAMAGED (1 << 9) +// (1 << 9) previously was SIDE_STATUS_SPIKES_DAMAGED #define SIDE_STATUS_TAILWIND (1 << 10) #define SIDE_STATUS_AURORA_VEIL (1 << 11) #define SIDE_STATUS_LUCKY_CHANT (1 << 12) #define SIDE_STATUS_TOXIC_SPIKES (1 << 13) #define SIDE_STATUS_STEALTH_ROCK (1 << 14) -#define SIDE_STATUS_STEALTH_ROCK_DAMAGED (1 << 15) -#define SIDE_STATUS_TOXIC_SPIKES_DAMAGED (1 << 16) -#define SIDE_STATUS_STICKY_WEB_DAMAGED (1 << 17) +// Missing flags previously were SIDE_STATUS_TOXIC_SPIKES_DAMAGED, SIDE_STATUS_STEALTH_ROCK_DAMAGED, SIDE_STATUS_STICKY_WEB_DAMAGED #define SIDE_STATUS_QUICK_GUARD (1 << 18) #define SIDE_STATUS_WIDE_GUARD (1 << 19) #define SIDE_STATUS_CRAFTY_SHIELD (1 << 20) diff --git a/src/battle_anim.c b/src/battle_anim.c index 9d0c9d77ad..8caa2850cb 100644 --- a/src/battle_anim.c +++ b/src/battle_anim.c @@ -442,7 +442,7 @@ static u8 GetBattleAnimMoveTargets(u8 battlerArgIndex, u8 *targets) { case MOVE_TARGET_FOES_AND_ALLY: if (IS_ALIVE_AND_PRESENT(BATTLE_PARTNER(BATTLE_OPPOSITE(battler)))) { - targets[idx++] = BATTLE_PARTNER(BATTLE_OPPOSITE(battler)); + targets[idx++] = BATTLE_PARTNER(BATTLE_OPPOSITE(battler)); numTargets++; } // fallthrough @@ -455,7 +455,7 @@ static u8 GetBattleAnimMoveTargets(u8 battlerArgIndex, u8 *targets) if (IS_ALIVE_AND_PRESENT(battler)) { targets[idx++] = battler; numTargets++; - } + } break; default: targets[0] = gBattleAnimArgs[battlerArgIndex]; // original @@ -548,7 +548,7 @@ static void CreateSpriteOnTargets(const struct SpriteTemplate *template, u8 argV ntargets = GetBattleAnimMoveTargets(battlerArgIndex, targets); if (ntargets == 0) return; - + for (i = 0; i < ntargets; i++) { if (overwriteAnimTgt) @@ -675,7 +675,7 @@ static void Cmd_createvisualtaskontargets(void) numArgs = GetBattleAnimMoveTargets(battlerArgIndex, targets); if (numArgs == 0) return; - + for (i = 0; i < numArgs; i++) { gBattleAnimArgs[battlerArgIndex] = targets[i]; diff --git a/src/battle_message.c b/src/battle_message.c index a1c862beb4..41e34b44f3 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -553,7 +553,7 @@ static const u8 sText_ShieldedFromCriticalHits[] = _("The {B_CURRENT_MOVE} shiel static const u8 sText_SwitchedAtkAndSpAtk[] = _("{B_ATK_NAME_WITH_PREFIX} switched all its\nchanges to its Attack and\pSp. Atk with the target!"); static const u8 sText_SwitchedDefAndSpDef[] = _("{B_ATK_NAME_WITH_PREFIX} switched all its\nchanges to its Defense and\pSp. Def with the target!"); static const u8 sText_PkmnAcquiredAbility[] = _("{B_DEF_NAME_WITH_PREFIX} acquired\n{B_DEF_ABILITY}!"); -static const u8 sText_PoisonSpikesScattered[] = _("Poison Spikes were scattered all\naround the opposing team's feet!"); +static const u8 sText_PoisonSpikesScattered[] = _("Poison Spikes were scattered all\naround {B_DEF_TEAM2} team's feet!"); static const u8 sText_PkmnSwitchedStatChanges[] = _("{B_ATK_NAME_WITH_PREFIX} switched stat changes\nwith the target!"); static const u8 sText_PkmnSurroundedWithVeilOfWater[] = _("{B_ATK_NAME_WITH_PREFIX} surrounded itself\nwith a veil of water!"); static const u8 sText_PkmnLevitatedOnElectromagnetism[] = _("{B_ATK_NAME_WITH_PREFIX} levitated on\nelectromagnetism!"); @@ -627,7 +627,7 @@ static const u8 sText_MagicBounceActivates[] = _("The {B_DEF_NAME_WITH_PREFIX} b static const u8 sText_ProteanTypeChange[] = _("{B_ATK_NAME_WITH_PREFIX}'s {B_ATK_ABILITY} transformed\nit into the {B_BUFF1} type!"); static const u8 sText_SymbiosisItemPass[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} passed its {B_LAST_ITEM}\nto {B_ATK_NAME_WITH_PREFIX} through {B_LAST_ABILITY}!"); static const u8 sText_StealthRockDmg[] = _("Pointed stones dug into\n{B_SCR_ACTIVE_NAME_WITH_PREFIX}!"); -static const u8 sText_ToxicSpikesAbsorbed[] = _("The poison spikes disappeared\nfrom around the opposing team's feet!"); +static const u8 sText_ToxicSpikesAbsorbed[] = _("The poison spikes disappeared\nfrom around {B_DEF_TEAM2} team's feet!"); static const u8 sText_ToxicSpikesPoisoned[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} was poisoned!"); static const u8 sText_StickyWebSwitchIn[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} was\ncaught in a Sticky Web!"); static const u8 sText_HealingWishCameTrue[] = _("The healing wish came true\nfor {B_ATK_NAME_WITH_PREFIX}!"); diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 958600a1fd..d9e8349241 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -3773,7 +3773,6 @@ static void Cmd_tryfaintmon(void) { BattleScriptPop(); gBattlescriptCurrInstr = cmd->instr; - gSideStatuses[GetBattlerSide(battler)] &= ~(SIDE_STATUS_SPIKES_DAMAGED | SIDE_STATUS_TOXIC_SPIKES_DAMAGED | SIDE_STATUS_STEALTH_ROCK_DAMAGED | SIDE_STATUS_STICKY_WEB_DAMAGED); } else { @@ -6880,7 +6879,7 @@ static void Cmd_switchineffects(void) gBattleStruct->storedLunarDance &= ~(gBitTable[battler]); } } - else if (!(gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SPIKES_DAMAGED) + else if (!(gDisableStructs[battler].spikesDone) && (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SPIKES) && GetBattlerAbility(battler) != ABILITY_MAGIC_GUARD && IsBattlerAffectedByHazards(battler, FALSE) @@ -6891,25 +6890,25 @@ static void Cmd_switchineffects(void) if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; - gSideStatuses[GetBattlerSide(battler)] |= SIDE_STATUS_SPIKES_DAMAGED; + gDisableStructs[battler].spikesDone = TRUE; SetDmgHazardsBattlescript(battler, B_MSG_PKMNHURTBYSPIKES); } - else if (!(gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_STEALTH_ROCK_DAMAGED) + else if (!(gDisableStructs[battler].stealthRockDone) && (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_STEALTH_ROCK) && IsBattlerAffectedByHazards(battler, FALSE) && GetBattlerAbility(battler) != ABILITY_MAGIC_GUARD) { - gSideStatuses[GetBattlerSide(battler)] |= SIDE_STATUS_STEALTH_ROCK_DAMAGED; + gDisableStructs[battler].stealthRockDone = TRUE; gBattleMoveDamage = GetStealthHazardDamage(gBattleMoves[MOVE_STEALTH_ROCK].type, battler); if (gBattleMoveDamage != 0) SetDmgHazardsBattlescript(battler, B_MSG_STEALTHROCKDMG); } - else if (!(gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_TOXIC_SPIKES_DAMAGED) + else if (!(gDisableStructs[battler].toxicSpikesDone) && (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_TOXIC_SPIKES) && IsBattlerGrounded(battler)) { - gSideStatuses[GetBattlerSide(battler)] |= SIDE_STATUS_TOXIC_SPIKES_DAMAGED; + gDisableStructs[battler].toxicSpikesDone = TRUE; if (IS_BATTLER_OF_TYPE(battler, TYPE_POISON)) // Absorb the toxic spikes. { gSideStatuses[GetBattlerSide(battler)] &= ~SIDE_STATUS_TOXIC_SPIKES; @@ -6940,12 +6939,12 @@ static void Cmd_switchineffects(void) } } } - else if (!(gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_STICKY_WEB_DAMAGED) + else if (!(gDisableStructs[battler].stickyWebDone) && (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_STICKY_WEB) && IsBattlerAffectedByHazards(battler, FALSE) && IsBattlerGrounded(battler)) { - gSideStatuses[GetBattlerSide(battler)] |= SIDE_STATUS_STICKY_WEB_DAMAGED; + gDisableStructs[battler].stickyWebDone = TRUE; gBattleScripting.battler = battler; SET_STATCHANGER(STAT_SPEED, 1, TRUE); BattleScriptPushCursor(); @@ -6984,7 +6983,10 @@ static void Cmd_switchineffects(void) return; } - gSideStatuses[GetBattlerSide(battler)] &= ~(SIDE_STATUS_SPIKES_DAMAGED | SIDE_STATUS_TOXIC_SPIKES_DAMAGED | SIDE_STATUS_STEALTH_ROCK_DAMAGED | SIDE_STATUS_STICKY_WEB_DAMAGED); + gDisableStructs[battler].stickyWebDone = FALSE; + gDisableStructs[battler].spikesDone = FALSE; + gDisableStructs[battler].toxicSpikesDone = FALSE; + gDisableStructs[battler].stealthRockDone = FALSE; for (i = 0; i < gBattlersCount; i++) { diff --git a/test/battle/hold_effect/cure_status.c b/test/battle/hold_effect/cure_status.c index c8c32ecf76..3be29cbf80 100644 --- a/test/battle/hold_effect/cure_status.c +++ b/test/battle/hold_effect/cure_status.c @@ -186,16 +186,16 @@ SINGLE_BATTLE_TEST("Berry hold effect cures status if a pokemon enters a battle" } } -SINGLE_BATTLE_TEST("Pokemon can be further poisoned with Toxic spikes after a status healing hold effect was previously used") +SINGLE_BATTLE_TEST("Opponent Pokemon can be further poisoned with Toxic spikes after a status healing hold effect was previously used") { u16 item; PARAMETRIZE { item = ITEM_PECHA_BERRY; } PARAMETRIZE { item = ITEM_LUM_BERRY; } - KNOWN_FAILING; GIVEN { ASSUME(gItems[ITEM_PECHA_BERRY].holdEffect == HOLD_EFFECT_CURE_PSN); + ASSUME(gItems[ITEM_LUM_BERRY].holdEffect == HOLD_EFFECT_CURE_STATUS); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WYNAUT) { Item(item); } @@ -204,12 +204,64 @@ SINGLE_BATTLE_TEST("Pokemon can be further poisoned with Toxic spikes after a st TURN { SWITCH(opponent, 1); } TURN { SWITCH(opponent, 0); } } SCENE { + MESSAGE("Wobbuffet used Toxic Spikes!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC_SPIKES, player); + MESSAGE("Poison Spikes were scattered all around the opposing team's feet!"); + // 1st switch-in + MESSAGE("2 sent out Wynaut!"); ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent); STATUS_ICON(opponent, poison: TRUE); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); + if (item == ITEM_PECHA_BERRY) { + MESSAGE("Foe Wynaut's Pecha Berry cured poison!"); + } else { + MESSAGE("Foe Wynaut's Lum Berry cured its poison problem!"); + } STATUS_ICON(opponent, poison: FALSE); + // 2nd switch-in + MESSAGE("2 sent out Wobbuffet!"); ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent); STATUS_ICON(opponent, poison: TRUE); } } + +// Basically same as above, but with the sides reversed. +SINGLE_BATTLE_TEST("Player Pokemon can be further poisoned with Toxic spikes after a status healing hold effect was previously used") +{ + u16 item; + + PARAMETRIZE { item = ITEM_PECHA_BERRY; } + PARAMETRIZE { item = ITEM_LUM_BERRY; } + + GIVEN { + ASSUME(gItems[ITEM_PECHA_BERRY].holdEffect == HOLD_EFFECT_CURE_PSN); + ASSUME(gItems[ITEM_LUM_BERRY].holdEffect == HOLD_EFFECT_CURE_STATUS); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET) {Item(item); } + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_TOXIC_SPIKES); } + TURN { SWITCH(player, 1); } + TURN { SWITCH(player, 2); } + } SCENE { + MESSAGE("Foe Wobbuffet used Toxic Spikes!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC_SPIKES, opponent); + MESSAGE("Poison Spikes were scattered all around your team's feet!"); + // 1st switch-in + MESSAGE("Go! Wobbuffet!"); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, player); + STATUS_ICON(player, poison: TRUE); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + if (item == ITEM_PECHA_BERRY) { + MESSAGE("Wobbuffet's Pecha Berry cured poison!"); + } else { + MESSAGE("Wobbuffet's Lum Berry cured its poison problem!"); + } + STATUS_ICON(player, poison: FALSE); + // 2nd switch-in + MESSAGE("Go! Wynaut!"); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, player); + STATUS_ICON(player, poison: TRUE); + } +} diff --git a/test/battle/move_effect/toxic_spikes.c b/test/battle/move_effect/toxic_spikes.c index 3be2d1627f..43de89ede9 100644 --- a/test/battle/move_effect/toxic_spikes.c +++ b/test/battle/move_effect/toxic_spikes.c @@ -208,3 +208,35 @@ SINGLE_BATTLE_TEST("Toxic Spikes are removed by Poison-types affected by Magnet NOT STATUS_ICON(opponent, poison: TRUE); } } + +SINGLE_BATTLE_TEST("Toxic Spikes inflicts poison on switch in after Primal Reversed mon fainted") // Oddly specific, but encountered during testing +{ + GIVEN { + ASSUME(gBattleMoves[MOVE_MEMENTO].effect == EFFECT_MEMENTO); // Faints the user. + PLAYER(SPECIES_WOBBUFFET) {Speed(5); } + PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); Speed(1); } + PLAYER(SPECIES_WYNAUT) {Speed(5); } + OPPONENT(SPECIES_WOBBUFFET) {Speed(15); } + } WHEN { + TURN { MOVE(opponent, MOVE_TOXIC_SPIKES); } + TURN { SWITCH(player, 1); } + TURN { MOVE(player, MOVE_MEMENTO); SEND_OUT(player, 2); } + } SCENE { + MESSAGE("Foe Wobbuffet used Toxic Spikes!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC_SPIKES, opponent); + MESSAGE("Poison Spikes were scattered all around your team's feet!"); + // Switch in + MESSAGE("Go! Groudon!"); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, player); + STATUS_ICON(player, poison: TRUE); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, player); + MESSAGE("Groudon's Primal Reversion! It reverted to its primal form!"); + // Memento + MESSAGE("Groudon used Memento!"); + MESSAGE("Groudon fainted!"); + // 2nd switch-in + MESSAGE("Go! Wynaut!"); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, player); + STATUS_ICON(player, poison: TRUE); + } +} From f840f7eb564306cc3e591bd9d6d09ca50d1cb9bc Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Sun, 1 Oct 2023 15:35:12 +0200 Subject: [PATCH 5/6] Fix Red Card not getting consumed after Sticky Web activation (#3364) --- data/battle_scripts_1.s | 2 +- test/battle/hold_effect/red_card.c | 55 ++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 76987499be..4f668ae19e 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -6892,7 +6892,6 @@ BattleScript_RoarSuccessSwitch:: BattleScript_RoarSuccessSwitch_Ret: swapattackerwithtarget @ continuation of RedCardActivates restoretarget - removeitem BS_TARGET setbyte sSWITCH_CASE, B_SWITCH_NORMAL return @@ -10170,6 +10169,7 @@ BattleScript_RedCardActivates:: swapattackerwithtarget jumpifstatus3 BS_EFFECT_BATTLER, STATUS3_ROOTED, BattleScript_RedCardIngrain jumpifability BS_EFFECT_BATTLER, ABILITY_SUCTION_CUPS, BattleScript_RedCardSuctionCups + removeitem BS_SCRIPTING setbyte sSWITCH_CASE, B_SWITCH_RED_CARD forcerandomswitch BattleScript_RedCardEnd @ changes the current battle script. the rest happens in BattleScript_RoarSuccessSwitch_Ret, if switch is successful diff --git a/test/battle/hold_effect/red_card.c b/test/battle/hold_effect/red_card.c index aad7fea64a..50354a5c1d 100644 --- a/test/battle/hold_effect/red_card.c +++ b/test/battle/hold_effect/red_card.c @@ -22,6 +22,8 @@ SINGLE_BATTLE_TEST("Red Card switches the attacker with a random non-fainted rep ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); MESSAGE("Wobbuffet held up its Red Card against Foe Wobbuffet!"); MESSAGE("Foe Bulbasaur was dragged out!"); + } THEN { + EXPECT(player->item == ITEM_NONE); } } @@ -43,6 +45,8 @@ DOUBLE_BATTLE_TEST("Red Card switches the target with a random non-battler, non- ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, playerLeft); MESSAGE("Wobbuffet held up its Red Card against Foe Wobbuffet!"); MESSAGE("Foe Bulbasaur was dragged out!"); + } THEN { + EXPECT(playerLeft->item == ITEM_NONE); } } @@ -61,6 +65,8 @@ SINGLE_BATTLE_TEST("Red Card does not activate if holder faints") ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); MESSAGE("Wobbuffet held up its Red Card against Foe Wobbuffet!"); } + } THEN { + EXPECT(player->item == ITEM_NONE); } } @@ -78,6 +84,8 @@ SINGLE_BATTLE_TEST("Red Card does not activate if target is behind a Substitute" ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); MESSAGE("Wobbuffet held up its Red Card against Foe Wobbuffet!"); } + } THEN { + EXPECT(player->item == ITEM_RED_CARD); // Not activated, so still has the item. } } @@ -95,6 +103,8 @@ SINGLE_BATTLE_TEST("Red Card activates after the last hit of a multi-hit move") HP_BAR(player); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); MESSAGE("Wobbuffet held up its Red Card against Foe Wobbuffet!"); + } THEN { + EXPECT(player->item == ITEM_NONE); } } @@ -111,6 +121,8 @@ SINGLE_BATTLE_TEST("Red Card does not activate if no replacements") ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); MESSAGE("Wobbuffet held up its Red Card against Foe Wobbuffet!"); } + } THEN { + EXPECT(player->item == ITEM_RED_CARD); // Not activated, so still has the item. } } @@ -128,6 +140,8 @@ SINGLE_BATTLE_TEST("Red Card does not activate if replacements fainted") ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); MESSAGE("Wobbuffet held up its Red Card against Foe Wobbuffet!"); } + } THEN { + EXPECT(player->item == ITEM_RED_CARD); // Not activated, so still has the item. } } @@ -145,6 +159,8 @@ SINGLE_BATTLE_TEST("Red Card does not activate if knocked off") ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); MESSAGE("Wobbuffet held up its Red Card against Foe Wobbuffet!"); } + } THEN { + EXPECT(player->item == ITEM_NONE); } } @@ -173,6 +189,8 @@ SINGLE_BATTLE_TEST("Red Card does not activate if stolen by a move") MESSAGE("Wobbuffet held up its Red Card against Foe Wobbuffet!"); } } + } THEN { + EXPECT(player->item == ITEM_NONE); } } @@ -201,6 +219,8 @@ SINGLE_BATTLE_TEST("Red Card does not activate if stolen by Magician") MESSAGE("Wobbuffet held up its Red Card against Foe Fennekin!"); } } + } THEN { + EXPECT(player->item == ITEM_NONE); } } @@ -229,6 +249,9 @@ DOUBLE_BATTLE_TEST("Red Card activates for only the fastest target") ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, playerRight); MESSAGE("Wynaut held up its Red Card against Foe Wynaut!"); MESSAGE("Foe Wobbuffet was dragged out!"); + } THEN { + EXPECT(playerLeft->item == ITEM_NONE); + EXPECT(playerRight->item == ITEM_NONE); } } @@ -377,4 +400,36 @@ SINGLE_BATTLE_TEST("Red Card activates before Emergency Exit") } } +SINGLE_BATTLE_TEST("Red Card is consumed after dragged out replacement has its Speed lowered by Sticky Web") +{ + GIVEN { + ASSUME(gBattleMoves[MOVE_STICKY_WEB].effect == EFFECT_STICKY_WEB); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT) { Moves(MOVE_TACKLE); } + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_RED_CARD); } + } WHEN { + TURN { MOVE(opponent, MOVE_STICKY_WEB); } + TURN { MOVE(player, MOVE_TACKLE); } + TURN { MOVE(player, MOVE_TACKLE); } + } SCENE { + // 1st turn Sticky Web + ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, opponent); + // 2nd turn Red Card activation + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); + MESSAGE("Foe Wobbuffet held up its Red Card against Wobbuffet!"); + MESSAGE("Wynaut was dragged out!"); + MESSAGE("Wynaut was caught in a Sticky Web!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + // 3rd turn, Red Card was consumed, it can't trigger again + NONE_OF { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); + MESSAGE("Foe Wobbuffet held up its Red Card against Wynaut!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + } + } THEN { + EXPECT(opponent->item == ITEM_NONE); + } +} + // SINGLE_BATTLE_TEST("Red Card activates but fails if the attacker has Dynamaxed") From dc119b27c27315df19765d31f7b99d2f134b7831 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Sun, 1 Oct 2023 19:06:43 +0200 Subject: [PATCH 6/6] Fix Intimidate Contrary in double battles --- data/battle_scripts_1.s | 1 + test/battle/ability/contrary.c | 48 +++++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 4f668ae19e..a1ccf6f2b1 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -8537,6 +8537,7 @@ BattleScript_IntimidateLoop: jumpifability BS_TARGET, ABILITY_GUARD_DOG, BattleScript_IntimidateInReverse BattleScript_IntimidateEffect: copybyte sBATTLER, gBattlerAttacker + setstatchanger STAT_ATK, 1, TRUE statbuffchange STAT_CHANGE_NOT_PROTECT_AFFECTED | STAT_CHANGE_ALLOW_PTR, BattleScript_IntimidateLoopIncrement setgraphicalstatchangevalues jumpifability BS_TARGET, ABILITY_CONTRARY, BattleScript_IntimidateContrary diff --git a/test/battle/ability/contrary.c b/test/battle/ability/contrary.c index 4e4417e19b..76c3d68c58 100644 --- a/test/battle/ability/contrary.c +++ b/test/battle/ability/contrary.c @@ -6,7 +6,7 @@ ASSUMPTIONS ASSUME(gBattleMoves[MOVE_TACKLE].split == SPLIT_PHYSICAL); } -SINGLE_BATTLE_TEST("Contrary raises Attack when Intimidated", s16 damage) +SINGLE_BATTLE_TEST("Contrary raises Attack when Intimidated in a single battle", s16 damage) { u32 ability; PARAMETRIZE { ability = ABILITY_CONTRARY; } @@ -30,6 +30,52 @@ SINGLE_BATTLE_TEST("Contrary raises Attack when Intimidated", s16 damage) } } +DOUBLE_BATTLE_TEST("Contrary raises Attack when Intimidated in a double battle", s16 damageLeft, s16 damageRight) +{ + u32 abilityLeft, abilityRight; + + PARAMETRIZE { abilityLeft = ABILITY_CONTRARY; abilityRight = ABILITY_CONTRARY; } + PARAMETRIZE { abilityLeft = ABILITY_TANGLED_FEET; abilityRight = ABILITY_TANGLED_FEET; } + PARAMETRIZE { abilityLeft = ABILITY_CONTRARY; abilityRight = ABILITY_TANGLED_FEET; } + PARAMETRIZE { abilityLeft = ABILITY_TANGLED_FEET; abilityRight = ABILITY_CONTRARY; } + + GIVEN { + PLAYER(SPECIES_MIGHTYENA) { Ability(ABILITY_INTIMIDATE); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_SPINDA) { Ability(abilityLeft); } + OPPONENT(SPECIES_SPINDA) { Ability(abilityRight); } + } WHEN { + TURN { MOVE(opponentLeft, MOVE_TACKLE, target: playerLeft); MOVE(opponentRight, MOVE_TACKLE, target: playerRight); } + } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_INTIMIDATE); + if (abilityLeft == ABILITY_CONTRARY) { + ABILITY_POPUP(opponentLeft, ABILITY_CONTRARY); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft); + MESSAGE("Foe Spinda's Attack rose!"); + } else { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft); + MESSAGE("Mightyena's Intimidate cuts Foe Spinda's attack!"); + } + if (abilityRight == ABILITY_CONTRARY) { + ABILITY_POPUP(opponentRight, ABILITY_CONTRARY); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight); + MESSAGE("Foe Spinda's Attack rose!"); + } else { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight); + MESSAGE("Mightyena's Intimidate cuts Foe Spinda's attack!"); + } + HP_BAR(playerLeft, captureDamage: &results[i].damageLeft); + HP_BAR(playerRight, captureDamage: &results[i].damageRight); + } THEN { + EXPECT_EQ(opponentLeft->statStages[STAT_ATK], (abilityLeft == ABILITY_CONTRARY) ? DEFAULT_STAT_STAGE+1 : DEFAULT_STAT_STAGE-1); + EXPECT_EQ(opponentRight->statStages[STAT_ATK], (abilityRight == ABILITY_CONTRARY) ? DEFAULT_STAT_STAGE+1 : DEFAULT_STAT_STAGE-1); + } + FINALLY { + EXPECT_MUL_EQ(results[1].damageLeft, Q_4_12(2.25), results[0].damageLeft); + EXPECT_MUL_EQ(results[1].damageRight, Q_4_12(2.25), results[0].damageRight); + } +} + SINGLE_BATTLE_TEST("Contrary raises stats after using a move which would normally lower them: Overheat", s16 damageBefore, s16 damageAfter) { u32 ability;