Fixed Shield Dust, added tests (#4137)
* Fixed Shield Dust, added tests Also fixed a duplicate macro caused by near-simultaneous PR merges (oops) * Added KNOWN_FAILING Sparkling Aria test --------- Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com>
This commit is contained in:
parent
c2c97d3c1c
commit
f7ec44c2ea
5 changed files with 145 additions and 65 deletions
|
@ -83,62 +83,6 @@
|
|||
// Extracts the lower 16 bits of a 32-bit number
|
||||
#define LOHALF(n) ((n) & 0xFFFF)
|
||||
|
||||
/* (Credit to MGriffin) A rather monstrous way of finding the set bit in a word.
|
||||
Invalid input causes a compiler error. Sample: https://cexplore.karathan.at/z/x1hm7B */
|
||||
#define BIT_INDEX(n) \
|
||||
(n) == (1 << 0) ? 0 : \
|
||||
(n) == (1 << 1) ? 1 : \
|
||||
(n) == (1 << 2) ? 2 : \
|
||||
(n) == (1 << 3) ? 3 : \
|
||||
(n) == (1 << 4) ? 4 : \
|
||||
(n) == (1 << 5) ? 5 : \
|
||||
(n) == (1 << 6) ? 6 : \
|
||||
(n) == (1 << 7) ? 7 : \
|
||||
(n) == (1 << 8) ? 8 : \
|
||||
(n) == (1 << 9) ? 9 : \
|
||||
(n) == (1 << 10) ? 10 : \
|
||||
(n) == (1 << 11) ? 11 : \
|
||||
(n) == (1 << 12) ? 12 : \
|
||||
(n) == (1 << 13) ? 13 : \
|
||||
(n) == (1 << 14) ? 14 : \
|
||||
(n) == (1 << 15) ? 15 : \
|
||||
(n) == (1 << 16) ? 16 : \
|
||||
(n) == (1 << 17) ? 17 : \
|
||||
(n) == (1 << 18) ? 18 : \
|
||||
(n) == (1 << 19) ? 19 : \
|
||||
(n) == (1 << 20) ? 20 : \
|
||||
(n) == (1 << 21) ? 21 : \
|
||||
(n) == (1 << 22) ? 22 : \
|
||||
(n) == (1 << 23) ? 23 : \
|
||||
(n) == (1 << 24) ? 24 : \
|
||||
(n) == (1 << 25) ? 25 : \
|
||||
(n) == (1 << 26) ? 26 : \
|
||||
(n) == (1 << 27) ? 27 : \
|
||||
(n) == (1 << 28) ? 28 : \
|
||||
(n) == (1 << 29) ? 29 : \
|
||||
(n) == (1 << 30) ? 30 : \
|
||||
(n) == (1 << 31) ? 31 : \
|
||||
*(u32 *)NULL
|
||||
|
||||
#define COMPRESS_BITS_0 0, 1
|
||||
#define COMPRESS_BITS_1 1, 1
|
||||
#define COMPRESS_BITS_2 2, 1
|
||||
#define COMPRESS_BITS_3 3, 1
|
||||
#define COMPRESS_BITS_4 4, 1
|
||||
#define COMPRESS_BITS_5 5, 1
|
||||
#define COMPRESS_BITS_6 6, 1
|
||||
#define COMPRESS_BITS_7 7, 1
|
||||
|
||||
/* Will try and compress a set bit (or up to three sequential bits) into a single byte
|
||||
Input must be of the form (upper << lower) where upper can be up to 3, lower up to 31 */
|
||||
#define COMPRESS_BITS(_val) COMPRESS_BITS_STEP_2 _val
|
||||
#define COMPRESS_BITS_STEP_2(_unpacked) COMPRESS_BITS_STEP_3(COMPRESS_BITS_## _unpacked)
|
||||
#define COMPRESS_BITS_STEP_3(...) COMPRESS_BITS_STEP_4(__VA_ARGS__)
|
||||
#define COMPRESS_BITS_STEP_4(upper, lower) (((upper % 8) << 5) + (BIT_INDEX(lower)))
|
||||
|
||||
/* Will read a compressed bit stored by COMPRESS_BIT into a single byte */
|
||||
#define UNCOMPRESS_BITS(compressed) ((compressed >> 5) << (compressed & 0x1F))
|
||||
|
||||
// There are many quirks in the source code which have overarching behavioral differences from
|
||||
// a number of other files. For example, diploma.c seems to declare rodata before each use while
|
||||
// other files declare out of order and must be at the beginning. There are also a number of
|
||||
|
@ -180,9 +124,6 @@ Input must be of the form (upper << lower) where upper can be up to 3, lower up
|
|||
#define NUM_FLAG_BYTES ROUND_BITS_TO_BYTES(FLAGS_COUNT)
|
||||
#define NUM_TRENDY_SAYING_BYTES ROUND_BITS_TO_BYTES(NUM_TRENDY_SAYINGS)
|
||||
|
||||
// Converts a string to a compound literal, essentially making it a pointer to const u8
|
||||
#define COMPOUND_STRING(str) (const u8[]) _(str)
|
||||
|
||||
// This produces an error at compile-time if expr is zero.
|
||||
// It looks like file.c:line: size of array `id' is negative
|
||||
#define STATIC_ASSERT(expr, id) typedef char id[(expr) ? 1 : -1];
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
#define STR(...) STR_(__VA_ARGS__)
|
||||
#define STR_(...) #__VA_ARGS__
|
||||
|
||||
/* Converts a string to a compound literal, essentially making it a pointer to const u8 */
|
||||
#define COMPOUND_STRING(str) (const u8[]) _(str)
|
||||
|
||||
/* Expands to the first/second/third/fourth argument. */
|
||||
#define FIRST(a, ...) a
|
||||
#define SECOND(a, ...) __VA_OPT__(FIRST(__VA_ARGS__))
|
||||
|
|
|
@ -2806,11 +2806,9 @@ void SetMoveEffect(bool32 primary, bool32 certain)
|
|||
// Just in case this flag is still set
|
||||
gBattleScripting.moveEffect &= ~MOVE_EFFECT_CERTAIN;
|
||||
|
||||
if ((battlerAbility == ABILITY_SHIELD_DUST
|
||||
|| GetBattlerHoldEffect(gEffectBattler, TRUE) == HOLD_EFFECT_COVERT_CLOAK)
|
||||
if (!primary && affectsUser != MOVE_EFFECT_AFFECTS_USER
|
||||
&& !(gHitMarker & HITMARKER_STATUS_ABILITY_EFFECT)
|
||||
&& !primary
|
||||
&& (gBattleScripting.moveEffect <= MOVE_EFFECT_TRI_ATTACK || gBattleScripting.moveEffect >= MOVE_EFFECT_SMACK_DOWN)) // Exclude stat lowering effects
|
||||
&& (battlerAbility == ABILITY_SHIELD_DUST || GetBattlerHoldEffect(gEffectBattler, TRUE) == HOLD_EFFECT_COVERT_CLOAK))
|
||||
{
|
||||
if (battlerAbility == ABILITY_SHIELD_DUST)
|
||||
RecordAbilityBattle(gEffectBattler, battlerAbility);
|
||||
|
|
|
@ -14969,9 +14969,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
|
|||
.ignoresSubstitute = TRUE,
|
||||
.metronomeBanned = TRUE,
|
||||
.sketchBanned = (B_SKETCH_BANS >= GEN_9),
|
||||
.additionalEffects = ADDITIONAL_EFFECTS(
|
||||
.additionalEffects = ADDITIONAL_EFFECTS({
|
||||
// Feint move effect handled in script as it goes before animation
|
||||
{
|
||||
.moveEffect = MOVE_EFFECT_DEF_MINUS_1,
|
||||
.self = TRUE,
|
||||
}),
|
||||
|
|
139
test/battle/ability/shield_dust.c
Normal file
139
test/battle/ability/shield_dust.c
Normal file
|
@ -0,0 +1,139 @@
|
|||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Shield Dust 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(MoveHasMoveEffectWithChance(MOVE_NUZZLE, MOVE_EFFECT_PARALYSIS, 100) == TRUE);
|
||||
ASSUME(MoveHasMoveEffectWithChance(MOVE_INFERNO, MOVE_EFFECT_BURN, 100) == TRUE);
|
||||
ASSUME(MoveHasMoveEffectWithChance(MOVE_MORTAL_SPIN, MOVE_EFFECT_POISON, 100) == TRUE);
|
||||
ASSUME(MoveHasMoveEffectWithChance(MOVE_FAKE_OUT, MOVE_EFFECT_FLINCH, 100) == TRUE);
|
||||
ASSUME(MoveHasMoveEffectWithChance(MOVE_ROCK_TOMB, MOVE_EFFECT_SPD_MINUS_1, 100) == TRUE);
|
||||
ASSUME(MoveHasMoveEffectWithChance(MOVE_SPIRIT_SHACKLE, MOVE_EFFECT_PREVENT_ESCAPE, 100) == TRUE);
|
||||
ASSUME(MoveHasMoveEffectWithChance(MOVE_PSYCHIC_NOISE, MOVE_EFFECT_PSYCHIC_NOISE, 100) == TRUE);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_VIVILLON) { Ability(ABILITY_SHIELD_DUST); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, move); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, player);
|
||||
HP_BAR(opponent);
|
||||
NONE_OF {
|
||||
MESSAGE("Foe Vivillon is paralyzed! It may be unable to move!");
|
||||
MESSAGE("Foe Vivillon was burned!");
|
||||
MESSAGE("Foe Vivillon was poisoned!");
|
||||
MESSAGE("Foe Vivillon flinched!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
MESSAGE("Foe Vivillon was prevented from healing!");
|
||||
}
|
||||
} THEN { // Can't find good way to test trapping
|
||||
EXPECT(!(opponent->status2 & STATUS2_ESCAPE_PREVENTION));
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Shield Dust 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(MoveHasMoveEffectWithChance(MOVE_INFESTATION, MOVE_EFFECT_WRAP, 0) == TRUE);
|
||||
ASSUME(MoveHasMoveEffectWithChance(MOVE_THOUSAND_ARROWS, MOVE_EFFECT_SMACK_DOWN, 0) == TRUE);
|
||||
ASSUME(MoveHasMoveEffectWithChance(MOVE_JAW_LOCK, MOVE_EFFECT_TRAP_BOTH, 0) == TRUE);
|
||||
ASSUME(MoveHasMoveEffectWithChance(MOVE_PAY_DAY, MOVE_EFFECT_PAYDAY, 0) == TRUE);
|
||||
ASSUME(MoveHasMoveEffectWithChance(MOVE_SMACK_DOWN, MOVE_EFFECT_SMACK_DOWN, 0) == TRUE);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_VIVILLON) { Ability(ABILITY_SHIELD_DUST); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, move); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, player);
|
||||
HP_BAR(opponent);
|
||||
switch (move)
|
||||
{
|
||||
case MOVE_INFESTATION:
|
||||
MESSAGE("Foe Vivillon has been afflicted with an infestation by Wobbuffet!");
|
||||
break;
|
||||
case MOVE_THOUSAND_ARROWS:
|
||||
MESSAGE("Foe Vivillon 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("Shield Dust 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(MoveHasMoveEffectSelf(MOVE_POWER_UP_PUNCH, MOVE_EFFECT_ATK_PLUS_1) == TRUE);
|
||||
ASSUME(MoveHasMoveEffectSelf(MOVE_RAPID_SPIN, MOVE_EFFECT_RAPIDSPIN) == TRUE);
|
||||
ASSUME(MoveHasMoveEffectSelf(MOVE_LEAF_STORM, MOVE_EFFECT_SP_ATK_TWO_DOWN) == TRUE);
|
||||
ASSUME(MoveHasMoveEffectSelf(MOVE_METEOR_ASSAULT, MOVE_EFFECT_RECHARGE) == TRUE);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_VIVILLON) { Ability(ABILITY_SHIELD_DUST); }
|
||||
} 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("Shield Dust does not block Sparkling Aria in doubles")
|
||||
{
|
||||
KNOWN_FAILING;
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_VIVILLON) { Ability(ABILITY_SHIELD_DUST); Status1(STATUS1_BURN); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { 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);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue