Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed some moves' on-hit effects bypassing Substitutes where they shouldn't and some other things discovered along the way #4558

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions data/battle_scripts_1.s
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ BattleScript_EffectSaltCure::
call BattleScript_EffectHit_Ret
tryfaintmon BS_TARGET
jumpiffainted BS_TARGET, TRUE, BattleScript_EffectSaltCure_End
jumpifsubstituteblocks BattleScript_EffectSaltCure_End
applysaltcure BS_TARGET
printstring STRINGID_TARGETISBEINGSALTCURED
waitmessage B_WAIT_TIME_LONG
Expand Down
38 changes: 33 additions & 5 deletions src/battle_script_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -5397,6 +5397,7 @@ static void Cmd_moveend(void)
u16 *choicedMoveAtk = NULL;
u32 endMode, endState;
u32 originallyUsedMove;
u8 currBattler, liveBattlerCount;

if (gChosenMove == MOVE_UNAVAILABLE)
originallyUsedMove = MOVE_NONE;
Expand Down Expand Up @@ -5641,7 +5642,10 @@ static void Cmd_moveend(void)
switch (gBattleStruct->moveEffect2)
{
case MOVE_EFFECT_KNOCK_OFF:
effect = TryKnockOffBattleScript(gBattlerTarget);
if (!DoesSubstituteBlockMove(gBattlerAttacker, gBattlerTarget, gCurrentMove))
{
effect = TryKnockOffBattleScript(gBattlerTarget);
}
break;
case MOVE_EFFECT_STOCKPILE_WORE_OFF:
if (gDisableStructs[gBattlerAttacker].stockpileCounter != 0)
Expand All @@ -5653,7 +5657,9 @@ static void Cmd_moveend(void)
}
break;
case MOVE_EFFECT_SMACK_DOWN:
if (!IsBattlerGrounded(gBattlerTarget) && IsBattlerAlive(gBattlerTarget))
if (!IsBattlerGrounded(gBattlerTarget)
&& IsBattlerAlive(gBattlerTarget)
&& !DoesSubstituteBlockMove(gBattlerAttacker, gBattlerTarget, gCurrentMove))
{
gStatuses3[gBattlerTarget] |= STATUS3_SMACKED_DOWN;
gStatuses3[gBattlerTarget] &= ~(STATUS3_MAGNET_RISE | STATUS3_TELEKINESIS | STATUS3_ON_AIR);
Expand All @@ -5663,7 +5669,9 @@ static void Cmd_moveend(void)
}
break;
case MOVE_EFFECT_REMOVE_STATUS: // Smelling salts, Wake-Up Slap, Sparkling Aria
if ((gBattleMons[gBattlerTarget].status1 & gMovesInfo[gCurrentMove].argument) && IsBattlerAlive(gBattlerTarget))
if ((gBattleMons[gBattlerTarget].status1 & gMovesInfo[gCurrentMove].argument)
&& IsBattlerAlive(gBattlerTarget)
&& !DoesSubstituteBlockMove(gBattlerAttacker, gBattlerTarget, gCurrentMove))
{
gBattleMons[gBattlerTarget].status1 &= ~(gMovesInfo[gCurrentMove].argument);

Expand All @@ -5680,8 +5688,28 @@ static void Cmd_moveend(void)
gBattlescriptCurrInstr = BattleScript_TargetWokeUp;
break;
case STATUS1_BURN:
gBattlescriptCurrInstr = BattleScript_TargetBurnHeal;
break;
// Checks to see if Sparkling Aria should cure a Shield Dust pokemon
if (gBattleMons[gBattlerTarget].ability == ABILITY_SHIELD_DUST || gBattleMons[gBattlerTarget].item == ITEM_COVERT_CLOAK)
{
liveBattlerCount = 0;
for (currBattler = 0; currBattler < gBattlersCount; currBattler++)
{
if (gBattleMons[currBattler].hp != 0)
{
liveBattlerCount++;
}
}
if (liveBattlerCount > 2)
{
gBattlescriptCurrInstr = BattleScript_TargetBurnHeal;
}
break;
}
else
{
gBattlescriptCurrInstr = BattleScript_TargetBurnHeal;
break;
}
}
}
break; // MOVE_EFFECT_REMOVE_STATUS
Expand Down
5 changes: 4 additions & 1 deletion src/battle_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -8615,8 +8615,11 @@ static inline u32 CalcMoveBasePower(u32 move, u32 battlerAtk, u32 battlerDef, u3
break;
case EFFECT_DOUBLE_POWER_ON_ARG_STATUS:
// Comatose targets treated as if asleep
if ((gBattleMons[battlerDef].status1 | (STATUS1_SLEEP * (abilityDef == ABILITY_COMATOSE))) & gMovesInfo[move].argument)
if ((gBattleMons[battlerDef].status1 | (STATUS1_SLEEP * (abilityDef == ABILITY_COMATOSE))) & gMovesInfo[move].argument
&& !((gMovesInfo[move].additionalEffects->moveEffect == MOVE_EFFECT_REMOVE_STATUS) && DoesSubstituteBlockMove(battlerAtk, battlerDef, move)))
{
basePower *= 2;
}
break;
case EFFECT_VARY_POWER_BASED_ON_HP:
basePower = gMovesInfo[move].argument * gBattleMons[battlerDef].hp / gBattleMons[battlerDef].maxHP;
Expand Down
37 changes: 31 additions & 6 deletions test/battle/ability/shield_dust.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,19 +121,44 @@ SINGLE_BATTLE_TEST("Shield Dust does not block self-targeting effects, primary o
}
}

DOUBLE_BATTLE_TEST("Shield Dust does not block Sparkling Aria in doubles")
DOUBLE_BATTLE_TEST("Shield Dust does or does not block Sparkling Aria depending on number of targets hit")
{
KNOWN_FAILING;
u32 moveToUse;
PARAMETRIZE { moveToUse = MOVE_FINAL_GAMBIT; }
PARAMETRIZE { moveToUse = MOVE_TACKLE; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_VIVILLON) { Ability(ABILITY_SHIELD_DUST); Status1(STATUS1_BURN); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(playerLeft, MOVE_SPARKLING_ARIA); }
TURN { MOVE(playerRight, moveToUse, target: opponentRight); MOVE(playerLeft, MOVE_SPARKLING_ARIA); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPARKLING_ARIA, playerLeft);
MESSAGE("Foe Vivillion's burn was healed.");
STATUS_ICON(opponentLeft, burn: TRUE);
if (moveToUse == MOVE_TACKLE) {
MESSAGE("Foe Vivillon's burn was healed.");
STATUS_ICON(opponentLeft, none: TRUE);
} else {
NONE_OF {
MESSAGE("Foe Vivillon's burn was healed.");
STATUS_ICON(opponentLeft, none: TRUE);
}
}
}
}

SINGLE_BATTLE_TEST("Shield Dust blocks Sparkling Aria in singles")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_VIVILLON) { Ability(ABILITY_SHIELD_DUST); Status1(STATUS1_BURN); }
} WHEN {
TURN { MOVE(player, MOVE_SPARKLING_ARIA); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPARKLING_ARIA, player);
NONE_OF {
MESSAGE("Foe Vivillon's burn was healed.");
STATUS_ICON(opponent, none: TRUE);
}
}
}
162 changes: 162 additions & 0 deletions test/battle/item_effect/covert_cloak.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
#include "global.h"
#include "test/battle.h"

SINGLE_BATTLE_TEST("Covert Cloak blocks secondary effects")
{
u16 move;
PARAMETRIZE { move = MOVE_NUZZLE; }
PARAMETRIZE { move = MOVE_INFERNO; }
PARAMETRIZE { move = MOVE_MORTAL_SPIN; }
PARAMETRIZE { move = MOVE_FAKE_OUT; }
PARAMETRIZE { move = MOVE_ROCK_TOMB; }
PARAMETRIZE { move = MOVE_SPIRIT_SHACKLE; }
PARAMETRIZE { move = MOVE_PSYCHIC_NOISE; }

GIVEN {
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_NUZZLE, MOVE_EFFECT_PARALYSIS, 100) == TRUE);
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_INFERNO, MOVE_EFFECT_BURN, 100) == TRUE);
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_MORTAL_SPIN, MOVE_EFFECT_POISON, 100) == TRUE);
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_FAKE_OUT, MOVE_EFFECT_FLINCH, 100) == TRUE);
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_ROCK_TOMB, MOVE_EFFECT_SPD_MINUS_1, 100) == TRUE);
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_SPIRIT_SHACKLE, MOVE_EFFECT_PREVENT_ESCAPE, 100) == TRUE);
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_PSYCHIC_NOISE, MOVE_EFFECT_PSYCHIC_NOISE, 100) == TRUE);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_COVERT_CLOAK); }
} WHEN {
TURN { MOVE(player, move); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, move, player);
HP_BAR(opponent);
NONE_OF {
MESSAGE("Foe Wobbuffet is paralyzed! It may be unable to move!");
MESSAGE("Foe Wobbuffet was burned!");
MESSAGE("Foe Wobbuffet was poisoned!");
MESSAGE("Foe Wobbuffet flinched!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
MESSAGE("Foe Wobbuffet was prevented from healing!");
}
} THEN { // Can't find good way to test trapping
EXPECT(!(opponent->status2 & STATUS2_ESCAPE_PREVENTION));
}
}

SINGLE_BATTLE_TEST("Covert Cloak does not block primary effects")
{
u16 move;
PARAMETRIZE { move = MOVE_INFESTATION; }
PARAMETRIZE { move = MOVE_THOUSAND_ARROWS; }
PARAMETRIZE { move = MOVE_JAW_LOCK; }
PARAMETRIZE { move = MOVE_PAY_DAY; }

GIVEN {
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_INFESTATION, MOVE_EFFECT_WRAP, 0) == TRUE);
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_THOUSAND_ARROWS, MOVE_EFFECT_SMACK_DOWN, 0) == TRUE);
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_JAW_LOCK, MOVE_EFFECT_TRAP_BOTH, 0) == TRUE);
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_PAY_DAY, MOVE_EFFECT_PAYDAY, 0) == TRUE);
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_SMACK_DOWN, MOVE_EFFECT_SMACK_DOWN, 0) == TRUE);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_SKARMORY) { Item(ITEM_COVERT_CLOAK); }
} WHEN {
TURN { MOVE(player, move); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, move, player);
HP_BAR(opponent);
switch (move) {
case MOVE_INFESTATION:
MESSAGE("Foe Skarmory has been afflicted with an infestation by Wobbuffet!");
break;
case MOVE_THOUSAND_ARROWS:
MESSAGE("Foe Skarmory fell straight down!");
break;
case MOVE_JAW_LOCK:
MESSAGE("Neither Pokémon can run away!");
break;
case MOVE_PAY_DAY:
MESSAGE("Coins scattered everywhere!");
break;
}
} THEN { // Can't find good way to test trapping
if (move == MOVE_JAW_LOCK) {
EXPECT(opponent->status2 & STATUS2_ESCAPE_PREVENTION);
EXPECT(player->status2 & STATUS2_ESCAPE_PREVENTION);
}
}
}

SINGLE_BATTLE_TEST("Covert Cloak does not block self-targeting effects, primary or secondary")
{
u16 move;
PARAMETRIZE { move = MOVE_POWER_UP_PUNCH; }
PARAMETRIZE { move = MOVE_RAPID_SPIN; }
PARAMETRIZE { move = MOVE_LEAF_STORM; }
PARAMETRIZE { move = MOVE_METEOR_ASSAULT; }

GIVEN {
ASSUME(MoveHasAdditionalEffectSelf(MOVE_POWER_UP_PUNCH, MOVE_EFFECT_ATK_PLUS_1) == TRUE);
ASSUME(MoveHasAdditionalEffectSelf(MOVE_RAPID_SPIN, MOVE_EFFECT_RAPID_SPIN) == TRUE);
ASSUME(MoveHasAdditionalEffectSelf(MOVE_LEAF_STORM, MOVE_EFFECT_SP_ATK_TWO_DOWN) == TRUE);
ASSUME(MoveHasAdditionalEffectSelf(MOVE_METEOR_ASSAULT, MOVE_EFFECT_RECHARGE) == TRUE);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_COVERT_CLOAK); }
} WHEN {
TURN { MOVE(player, move); }
if (move == MOVE_METEOR_ASSAULT) {
TURN { SKIP_TURN(player); }
}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, move, player);
HP_BAR(opponent);
switch (move) {
case MOVE_POWER_UP_PUNCH:
case MOVE_RAPID_SPIN:
case MOVE_LEAF_STORM:
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
break;
case MOVE_METEOR_ASSAULT: // second turn
MESSAGE("Wobbuffet must recharge!");
break;
}
}
}

DOUBLE_BATTLE_TEST("Covert Cloak does or does not block Sparkling Aria depending on number of targets hit")
{
u32 moveToUse;
PARAMETRIZE { moveToUse = MOVE_FINAL_GAMBIT; }
PARAMETRIZE { moveToUse = MOVE_TACKLE; }
GIVEN {
PLAYER(SPECIES_WYNAUT);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_COVERT_CLOAK); Status1(STATUS1_BURN); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(playerRight, moveToUse, target: opponentRight); MOVE(playerLeft, MOVE_SPARKLING_ARIA); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPARKLING_ARIA, playerLeft);
if (moveToUse == MOVE_TACKLE) {
MESSAGE("Foe Wobbuffet's burn was healed.");
STATUS_ICON(opponentLeft, none: TRUE);
} else {
NONE_OF {
MESSAGE("Foe Wobbuffet's burn was healed.");
STATUS_ICON(opponentLeft, none: TRUE);
}
}
}
}

SINGLE_BATTLE_TEST("Covert Cloak blocks Sparkling Aria in singles")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_COVERT_CLOAK); Status1(STATUS1_BURN); }
} WHEN {
TURN { MOVE(player, MOVE_SPARKLING_ARIA); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPARKLING_ARIA, player);
NONE_OF {
MESSAGE("Foe Wobbuffet's burn was healed.");
STATUS_ICON(opponent, none: TRUE);
}
}
}
12 changes: 12 additions & 0 deletions test/battle/move_effect/knock_off.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,15 @@ SINGLE_BATTLE_TEST("Knock Off activates after Rocky Helmet and Weakness Policy")
}
}
}

SINGLE_BATTLE_TEST("Knock Off doesn't knock off items from Pokemon behind substitutes")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_POKE_BALL); }
} WHEN {
TURN { MOVE(opponent, MOVE_SUBSTITUTE); MOVE(player, MOVE_KNOCK_OFF); }
} SCENE {
NOT MESSAGE("Wobbuffet knocked off Foe Wobbuffet's Poké Ball");
}
}
14 changes: 14 additions & 0 deletions test/battle/move_effect/salt_cure.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,17 @@ SINGLE_BATTLE_TEST("If Salt Cure faints the target no status will be applied")
MESSAGE("Foe Wobbuffet fainted!");
}
}

SINGLE_BATTLE_TEST("Salt Cure does not get applied if hitting a Substitute")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_SUBSTITUTE); MOVE(player, MOVE_SALT_CURE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SALT_CURE, player);
MESSAGE("The SUBSTITUTE took damage for Foe Wobbuffet!");
NOT MESSAGE("Foe Wobbuffet is being salt cured!");
}
}
19 changes: 19 additions & 0 deletions test/battle/move_effect/smack_down.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include "global.h"
#include "test/battle.h"

ASSUMPTIONS
{
ASSUME(gMovesInfo[MOVE_SMACK_DOWN].additionalEffects->moveEffect == MOVE_EFFECT_SMACK_DOWN);
}

SINGLE_BATTLE_TEST("Smack Down does not ground mons behind substitutes")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_SKARMORY);
} WHEN {
TURN { MOVE(opponent, MOVE_SUBSTITUTE); MOVE(player, MOVE_SMACK_DOWN); }
} SCENE {
NOT MESSAGE("Foe Skarmory fell straight down!");
}
}
Loading
Loading