Fix Foresight/Miracle Eye repeated-use behavior (#9025)

This commit is contained in:
GGbond 2026-01-26 21:48:39 +08:00 committed by GitHub
parent 30db62d4b7
commit 21492e0f23
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 227 additions and 5 deletions

View File

@ -2357,6 +2357,9 @@ BattleScript_TryTailwindAbilitiesLoop_WindPower:
BattleScript_EffectMiracleEye::
attackcanceler
accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE
jumpifgenconfiglowerthan CONFIG_MIRACLE_EYE_FAIL, GEN_5, BattleScript_MiracleEyeSet
jumpifvolatile BS_TARGET, VOLATILE_MIRACLE_EYE, BattleScript_ButItFailed
BattleScript_MiracleEyeSet:
setvolatile BS_TARGET, VOLATILE_MIRACLE_EYE
goto BattleScript_IdentifiedFoe
@ -3479,7 +3482,11 @@ BattleScript_EffectSpikes::
BattleScript_EffectForesight::
attackcanceler
accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON
jumpifgenconfiglowerthan CONFIG_FORESIGHT_FAIL, GEN_3, BattleScript_ForesightFailCheck
jumpifgenconfiglowerthan CONFIG_FORESIGHT_FAIL, GEN_5, BattleScript_ForesightSet
BattleScript_ForesightFailCheck:
jumpifvolatile BS_TARGET, VOLATILE_FORESIGHT, BattleScript_ButItFailed
BattleScript_ForesightSet:
setvolatile BS_TARGET, VOLATILE_FORESIGHT
BattleScript_IdentifiedFoe:
attackanimation

View File

@ -128,6 +128,8 @@
#define B_AFTER_YOU_TURN_ORDER GEN_LATEST // In Gen8+, After You doesn't fail if the turn order wouldn't change after use.
#define B_QUASH_TURN_ORDER GEN_LATEST // In Gen8+, Quash-affected battlers move according to speed order. Before Gen8, Quash-affected battlers move in the order they were affected by Quash.
#define B_DESTINY_BOND_FAIL GEN_LATEST // In Gen7+, Destiny Bond fails if used repeatedly.
#define B_FORESIGHT_FAIL GEN_LATEST // In Gen2 and Gen5+, Foresight fails if used against a target already under its effect.
#define B_MIRACLE_EYE_FAIL GEN_LATEST // In Gen5+, Miracle Eye fails if used against a target already under its effect.
#define B_PURSUIT_TARGET GEN_LATEST // In Gen4+, Pursuit attacks a switching opponent even if they weren't targeting them. Before Gen4, Pursuit only attacks a switching opponent that it originally targeted.
#define B_SKIP_RECHARGE GEN_LATEST // In Gen1, recharging moves such as Hyper Beam skip the recharge if the target gets KO'd
#define B_ENCORE_TARGET GEN_LATEST // In Gen5+, encored moves are allowed to choose a target

View File

@ -119,6 +119,8 @@
F(AFTER_YOU_TURN_ORDER, afterYouTurnOrder, (u32, GEN_COUNT - 1)) \
F(QUASH_TURN_ORDER, quashTurnOrder, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(DESTINY_BOND_FAIL, destinyBondFail, (u32, GEN_COUNT - 1)) \
F(FORESIGHT_FAIL, foresightFail, (u32, GEN_COUNT - 1)) \
F(MIRACLE_EYE_FAIL, miracleEyeFail, (u32, GEN_COUNT - 1)) \
F(PURSUIT_TARGET, pursuitTarget, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(SKIP_RECHARGE, skipRecharge, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(ENCORE_TARGET, encoreTarget, (u32, GEN_COUNT - 1)) \

View File

@ -1,14 +1,123 @@
#include "global.h"
#include "test/battle.h"
TO_DO_BATTLE_TEST("Foresight removes Ghost's type immunity to Normal and Fighting types")
ASSUMPTIONS
{
ASSUME(GetMoveEffect(MOVE_FORESIGHT) == EFFECT_FORESIGHT);
}
SINGLE_BATTLE_TEST("Foresight removes Ghost's type immunity to Normal and Fighting types")
{
GIVEN {
ASSUME(GetMoveType(MOVE_SCRATCH) == TYPE_NORMAL);
ASSUME(GetMoveType(MOVE_LOW_KICK) == TYPE_FIGHTING);
ASSUME(GetSpeciesType(SPECIES_GENGAR, 0) == TYPE_GHOST);
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_FORESIGHT, MOVE_SCRATCH, MOVE_LOW_KICK); }
OPPONENT(SPECIES_GENGAR) { Moves(MOVE_SPLASH); }
} WHEN {
TURN { MOVE(player, MOVE_FORESIGHT); MOVE(opponent, MOVE_SPLASH); }
TURN { MOVE(player, MOVE_SCRATCH); MOVE(opponent, MOVE_SPLASH); }
TURN { MOVE(player, MOVE_LOW_KICK); MOVE(opponent, MOVE_SPLASH); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_FORESIGHT, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, player);
HP_BAR(opponent);
ANIMATION(ANIM_TYPE_MOVE, MOVE_LOW_KICK, player);
HP_BAR(opponent);
}
}
SINGLE_BATTLE_TEST("Foresight always hits unless the target is semi-invulnerable")
{
bool32 semiInvulnerable = FALSE;
PARAMETRIZE { semiInvulnerable = FALSE; }
PARAMETRIZE { semiInvulnerable = TRUE; }
GIVEN {
ASSUME(GetMoveEffect(MOVE_DOUBLE_TEAM) == EFFECT_EVASION_UP);
ASSUME(GetMoveEffect(MOVE_FLY) == EFFECT_SEMI_INVULNERABLE);
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_FORESIGHT, MOVE_SPLASH); Speed(10); }
OPPONENT(SPECIES_SQUAWKABILLY) { Moves(MOVE_DOUBLE_TEAM, MOVE_FLY); Speed(20); }
} WHEN {
if (semiInvulnerable)
TURN { MOVE(player, MOVE_FORESIGHT); MOVE(opponent, MOVE_FLY); }
else
TURN { MOVE(player, MOVE_FORESIGHT); MOVE(opponent, MOVE_DOUBLE_TEAM); }
if (semiInvulnerable)
TURN { MOVE(player, MOVE_SPLASH); SKIP_TURN(opponent); }
} SCENE {
if (semiInvulnerable) {
MESSAGE("The opposing Squawkabilly avoided the attack!");
} else {
ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_TEAM, opponent);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
ANIMATION(ANIM_TYPE_MOVE, MOVE_FORESIGHT, player);
}
}
}
SINGLE_BATTLE_TEST("Foresight causes moves against the target to ignore positive evasion stat stages")
{
PASSES_RANDOMLY(100, 100, RNG_ACCURACY);
GIVEN {
ASSUME(GetMoveEffect(MOVE_DOUBLE_TEAM) == EFFECT_EVASION_UP);
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_FORESIGHT, MOVE_SCRATCH); Speed(10); }
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_DOUBLE_TEAM, MOVE_SPLASH); Speed(20); }
} WHEN {
TURN { MOVE(player, MOVE_FORESIGHT); MOVE(opponent, MOVE_DOUBLE_TEAM); }
TURN { MOVE(player, MOVE_SCRATCH); MOVE(opponent, MOVE_SPLASH); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_TEAM, opponent);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
ANIMATION(ANIM_TYPE_MOVE, MOVE_FORESIGHT, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, player);
HP_BAR(opponent);
}
}
SINGLE_BATTLE_TEST("Foresight fails if the target is already under its effect (Gen 2 and Gen5+)")
{
u32 genConfig = GEN_2;
PARAMETRIZE { genConfig = GEN_2; }
PARAMETRIZE { genConfig = GEN_5; }
GIVEN {
WITH_CONFIG(CONFIG_FORESIGHT_FAIL, genConfig);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_FORESIGHT); }
TURN { MOVE(player, MOVE_FORESIGHT); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_FORESIGHT, player);
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_FORESIGHT, player);
MESSAGE("But it failed!");
}
}
SINGLE_BATTLE_TEST("Foresight doesn't fail if the target is already under its effect (Gen 3-4)")
{
u32 genConfig = GEN_3;
PARAMETRIZE { genConfig = GEN_3; }
PARAMETRIZE { genConfig = GEN_4; }
GIVEN {
WITH_CONFIG(CONFIG_FORESIGHT_FAIL, genConfig);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_FORESIGHT); }
TURN { MOVE(player, MOVE_FORESIGHT); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_FORESIGHT, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_FORESIGHT, player);
NOT MESSAGE("But it failed!");
}
}
TO_DO_BATTLE_TEST("Foresight causes accuracy/evasion stat changes only between the user/target when the user's accuracy stage is less than the target's evasion stage (Gen 2)")
TO_DO_BATTLE_TEST("Foresight causes all moves against the target to ignore evasion stat changes (Gen 3)")
TO_DO_BATTLE_TEST("Foresight causes all moves against the target to ignore only positive evasion stat changes (Gen 4+)") // Eg. Doesn't ignore Sweet Scent
TO_DO_BATTLE_TEST("Foresight doesn't cause moves used against the target to always hit (Gen 2-3)")
TO_DO_BATTLE_TEST("Foresight causes moves used against the target to always hit (Gen 4+)")
TO_DO_BATTLE_TEST("Foresight does not make moves hit semi-invulnerable targets")
TO_DO_BATTLE_TEST("Foresight fails if the target is already under its effect (Gen 2 and Gen5+)")
TO_DO_BATTLE_TEST("Foresight doesn't fail if the target is already under its effect (Gen 3-4)")
TO_DO_BATTLE_TEST("Baton Pass passes Foresight's effect (Gen 2)");
TO_DO_BATTLE_TEST("Baton Pass doesn't pass Foresight's effect (Gen 3+)");

View File

@ -1,4 +1,106 @@
#include "global.h"
#include "test/battle.h"
TO_DO_BATTLE_TEST("TODO: Write Miracle Eye (Move Effect) test titles")
ASSUMPTIONS
{
ASSUME(GetMoveEffect(MOVE_MIRACLE_EYE) == EFFECT_MIRACLE_EYE);
}
SINGLE_BATTLE_TEST("Miracle Eye removes Dark-type immunity to Psychic-type moves")
{
GIVEN {
ASSUME(GetMoveType(MOVE_PSYCHIC) == TYPE_PSYCHIC);
ASSUME(GetSpeciesType(SPECIES_UMBREON, 0) == TYPE_DARK);
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_MIRACLE_EYE, MOVE_PSYCHIC); }
OPPONENT(SPECIES_UMBREON) { Moves(MOVE_SPLASH); }
} WHEN {
TURN { MOVE(player, MOVE_PSYCHIC); MOVE(opponent, MOVE_SPLASH); }
TURN { MOVE(player, MOVE_MIRACLE_EYE); MOVE(opponent, MOVE_SPLASH); }
TURN { MOVE(player, MOVE_PSYCHIC); MOVE(opponent, MOVE_SPLASH); }
} SCENE {
NOT HP_BAR(opponent);
ANIMATION(ANIM_TYPE_MOVE, MOVE_MIRACLE_EYE, player);
HP_BAR(opponent);
}
}
SINGLE_BATTLE_TEST("Miracle Eye always hits unless the target is semi-invulnerable")
{
bool32 semiInvulnerable = FALSE;
PARAMETRIZE { semiInvulnerable = FALSE; }
PARAMETRIZE { semiInvulnerable = TRUE; }
GIVEN {
ASSUME(GetMoveEffect(MOVE_DOUBLE_TEAM) == EFFECT_EVASION_UP);
ASSUME(GetMoveEffect(MOVE_FLY) == EFFECT_SEMI_INVULNERABLE);
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_MIRACLE_EYE, MOVE_SPLASH); Speed(10); }
OPPONENT(SPECIES_SQUAWKABILLY) { Moves(MOVE_DOUBLE_TEAM, MOVE_FLY); Speed(20); }
} WHEN {
if (semiInvulnerable)
TURN { MOVE(player, MOVE_MIRACLE_EYE); MOVE(opponent, MOVE_FLY); }
else
TURN { MOVE(player, MOVE_MIRACLE_EYE); MOVE(opponent, MOVE_DOUBLE_TEAM); }
if (semiInvulnerable)
TURN { MOVE(player, MOVE_SPLASH); SKIP_TURN(opponent); }
} SCENE {
if (semiInvulnerable) {
MESSAGE("Wobbuffet's attack missed!");
} else {
ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_TEAM, opponent);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
ANIMATION(ANIM_TYPE_MOVE, MOVE_MIRACLE_EYE, player);
}
}
}
SINGLE_BATTLE_TEST("Miracle Eye causes moves against the target to ignore positive evasion stat stages")
{
PASSES_RANDOMLY(100, 100, RNG_ACCURACY);
GIVEN {
ASSUME(GetMoveEffect(MOVE_DOUBLE_TEAM) == EFFECT_EVASION_UP);
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_MIRACLE_EYE, MOVE_SCRATCH); Speed(10); }
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_DOUBLE_TEAM, MOVE_SPLASH); Speed(20); }
} WHEN {
TURN { MOVE(player, MOVE_MIRACLE_EYE); MOVE(opponent, MOVE_DOUBLE_TEAM); }
TURN { MOVE(player, MOVE_SCRATCH); MOVE(opponent, MOVE_SPLASH); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_TEAM, opponent);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
ANIMATION(ANIM_TYPE_MOVE, MOVE_MIRACLE_EYE, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, player);
HP_BAR(opponent);
}
}
SINGLE_BATTLE_TEST("Miracle Eye fails if the target is already affected by Miracle Eye (Gen5+)")
{
GIVEN {
WITH_CONFIG(CONFIG_MIRACLE_EYE_FAIL, GEN_5);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_MIRACLE_EYE); }
TURN { MOVE(player, MOVE_MIRACLE_EYE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_MIRACLE_EYE, player);
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_MIRACLE_EYE, player);
MESSAGE("But it failed!");
}
}
SINGLE_BATTLE_TEST("Miracle Eye does not fail if the target is already affected by Miracle Eye (Gen4)")
{
GIVEN {
WITH_CONFIG(CONFIG_MIRACLE_EYE_FAIL, GEN_4);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_MIRACLE_EYE); }
TURN { MOVE(player, MOVE_MIRACLE_EYE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_MIRACLE_EYE, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_MIRACLE_EYE, player);
NOT MESSAGE("But it failed!");
}
}