mirror of
https://github.com/pret/pokeemerald.git
synced 2026-04-25 15:57:29 -05:00
Fixes clear body type effect and clear amulet against protect effects (#6482)
This commit is contained in:
parent
92cb9ab642
commit
ce3d6a924a
|
|
@ -205,6 +205,7 @@ bool32 AreAllMovesUnusable(u32 battler);
|
|||
u8 GetImprisonedMovesCount(u32 battler, u16 move);
|
||||
u8 DoFieldEndTurnEffects(void);
|
||||
s32 GetDrainedBigRootHp(u32 battler, s32 hp);
|
||||
bool32 IsMagicGuardProtected(u32 battler, u32 ability);
|
||||
u8 DoBattlerEndTurnEffects(void);
|
||||
bool32 HandleWishPerishSongOnTurnEnd(void);
|
||||
bool32 HandleFaintedMonActions(void);
|
||||
|
|
|
|||
|
|
@ -339,7 +339,7 @@ static bool32 SetTargetToNextPursuiter(u32 battlerDef);
|
|||
void ApplyExperienceMultipliers(s32 *expAmount, u8 expGetterMonId, u8 faintedBattler);
|
||||
static void RemoveAllWeather(void);
|
||||
static void RemoveAllTerrains(void);
|
||||
static bool8 CanAbilityPreventStatLoss(u16 abilityDef);
|
||||
static bool32 CanAbilityPreventStatLoss(u32 abilityDef);
|
||||
static bool8 CanBurnHitThaw(u16 move);
|
||||
static u32 GetNextTarget(u32 moveTarget, bool32 excludeCurrent);
|
||||
static void TryUpdateEvolutionTracker(u32 evolutionMethod, u32 upAmount, u16 usedMove);
|
||||
|
|
@ -1321,9 +1321,10 @@ static void Cmd_attackcanceler(void)
|
|||
RecordAbilityBattle(gBattlerTarget, gLastUsedAbility);
|
||||
}
|
||||
else if (IsBattlerProtected(gBattlerAttacker, gBattlerTarget, gCurrentMove)
|
||||
&& (gCurrentMove != MOVE_CURSE || IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GHOST))
|
||||
&& (effect != EFFECT_CURSE || IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GHOST))
|
||||
&& (!gBattleMoveEffects[effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS))
|
||||
&& effect != EFFECT_SUCKER_PUNCH
|
||||
&& effect != EFFECT_COUNTER
|
||||
&& effect != EFFECT_UPPER_HAND)
|
||||
{
|
||||
if (IsMoveMakingContact(gCurrentMove, gBattlerAttacker))
|
||||
|
|
@ -6169,14 +6170,31 @@ static u32 GetNextTarget(u32 moveTarget, bool32 excludeCurrent)
|
|||
return battler;
|
||||
}
|
||||
|
||||
static inline bool32 IsProtectivePadsProtected(u32 battler, u32 move)
|
||||
static inline bool32 IsProtectivePadsProtected(u32 battler, u32 move, u32 holdEffect)
|
||||
{
|
||||
if (!IsMoveMakingContact(move, battler))
|
||||
if (holdEffect != HOLD_EFFECT_PROTECTIVE_PADS)
|
||||
return FALSE;
|
||||
|
||||
if (GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_PROTECTIVE_PADS)
|
||||
RecordItemEffectBattle(battler, holdEffect);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline bool32 IsProtectEffectAffected(u32 battler, u32 move)
|
||||
{
|
||||
u32 holdEffect = GetBattlerHoldEffect(gBattlerAttacker, TRUE);
|
||||
if (IsProtectivePadsProtected(battler, move, holdEffect))
|
||||
return TRUE;
|
||||
|
||||
if (holdEffect == HOLD_EFFECT_CLEAR_AMULET)
|
||||
{
|
||||
RecordItemEffectBattle(battler, HOLD_EFFECT_PROTECTIVE_PADS);
|
||||
RecordItemEffectBattle(battler, holdEffect);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
u32 ability = GetBattlerAbility(gBattlerAttacker);
|
||||
if (CanAbilityPreventStatLoss(ability))
|
||||
{
|
||||
RecordAbilityBattle(battler, ability);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -6219,9 +6237,8 @@ static void Cmd_moveend(void)
|
|||
if (gProtectStructs[gBattlerAttacker].touchedProtectLike)
|
||||
{
|
||||
if (gProtectStructs[gBattlerTarget].spikyShielded
|
||||
&& moveEffect != EFFECT_COUNTER
|
||||
&& !IsProtectivePadsProtected(gBattlerAttacker, gCurrentMove)
|
||||
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD)
|
||||
&& !IsProtectivePadsProtected(gBattlerAttacker, gCurrentMove, GetBattlerHoldEffect(gBattlerAttacker, TRUE))
|
||||
&& !IsMagicGuardProtected(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker)))
|
||||
{
|
||||
gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE;
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 8;
|
||||
|
|
@ -6233,7 +6250,7 @@ static void Cmd_moveend(void)
|
|||
effect = 1;
|
||||
}
|
||||
else if (gProtectStructs[gBattlerTarget].kingsShielded
|
||||
&& !IsProtectivePadsProtected(gBattlerAttacker, gCurrentMove))
|
||||
&& !IsProtectEffectAffected(gBattlerAttacker, gCurrentMove))
|
||||
{
|
||||
gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE;
|
||||
i = gBattlerAttacker;
|
||||
|
|
@ -6248,7 +6265,7 @@ static void Cmd_moveend(void)
|
|||
effect = 1;
|
||||
}
|
||||
else if (gProtectStructs[gBattlerTarget].banefulBunkered
|
||||
&& !IsProtectivePadsProtected(gBattlerAttacker, gCurrentMove))
|
||||
&& !IsProtectivePadsProtected(gBattlerAttacker, gCurrentMove, GetBattlerHoldEffect(gBattlerAttacker, TRUE)))
|
||||
{
|
||||
gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE;
|
||||
gBattleScripting.moveEffect = MOVE_EFFECT_POISON | MOVE_EFFECT_AFFECTS_USER;
|
||||
|
|
@ -6260,7 +6277,7 @@ static void Cmd_moveend(void)
|
|||
else if (gProtectStructs[gBattlerTarget].obstructed
|
||||
&& moveEffect != EFFECT_SUCKER_PUNCH
|
||||
&& moveEffect != EFFECT_UPPER_HAND
|
||||
&& !IsProtectivePadsProtected(gBattlerAttacker, gCurrentMove))
|
||||
&& !IsProtectEffectAffected(gBattlerAttacker, gCurrentMove))
|
||||
{
|
||||
gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE;
|
||||
i = gBattlerAttacker;
|
||||
|
|
@ -6272,7 +6289,7 @@ static void Cmd_moveend(void)
|
|||
effect = 1;
|
||||
}
|
||||
else if (gProtectStructs[gBattlerTarget].silkTrapped
|
||||
&& !IsProtectivePadsProtected(gBattlerAttacker, gCurrentMove))
|
||||
&& !IsProtectEffectAffected(gBattlerAttacker, gCurrentMove))
|
||||
{
|
||||
gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE;
|
||||
i = gBattlerAttacker;
|
||||
|
|
@ -6284,7 +6301,7 @@ static void Cmd_moveend(void)
|
|||
effect = 1;
|
||||
}
|
||||
else if (gProtectStructs[gBattlerTarget].burningBulwarked
|
||||
&& !IsProtectivePadsProtected(gBattlerAttacker, gCurrentMove))
|
||||
&& !IsProtectivePadsProtected(gBattlerAttacker, gCurrentMove, GetBattlerHoldEffect(gBattlerAttacker, TRUE)))
|
||||
{
|
||||
gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE;
|
||||
gBattleScripting.moveEffect = MOVE_EFFECT_BURN | MOVE_EFFECT_AFFECTS_USER;
|
||||
|
|
@ -16824,7 +16841,7 @@ static bool8 IsFinalStrikeEffect(u32 moveEffect)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
static bool8 CanAbilityPreventStatLoss(u16 abilityDef)
|
||||
static bool32 CanAbilityPreventStatLoss(u32 abilityDef)
|
||||
{
|
||||
switch (abilityDef)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2207,7 +2207,8 @@ s32 GetDrainedBigRootHp(u32 battler, s32 hp)
|
|||
return hp * -1;
|
||||
}
|
||||
|
||||
static inline bool32 IsBattlerProtectedByMagicGuard(u32 battler, u32 ability)
|
||||
// This should always be the last check. Otherwise the ability might be recorded when it is not supposed to be
|
||||
bool32 IsMagicGuardProtected(u32 battler, u32 ability)
|
||||
{
|
||||
if (ability != ABILITY_MAGIC_GUARD)
|
||||
return FALSE;
|
||||
|
|
@ -2343,7 +2344,7 @@ u8 DoBattlerEndTurnEffects(void)
|
|||
if ((gStatuses3[battler] & STATUS3_LEECHSEED)
|
||||
&& IsBattlerAlive(gStatuses3[battler] & STATUS3_LEECHSEED_BATTLER)
|
||||
&& IsBattlerAlive(battler)
|
||||
&& !IsBattlerProtectedByMagicGuard(battler, ability))
|
||||
&& !IsMagicGuardProtected(battler, ability))
|
||||
{
|
||||
gBattlerTarget = gStatuses3[battler] & STATUS3_LEECHSEED_BATTLER; // Notice gBattlerTarget is actually the HP receiver.
|
||||
gBattlerAttacker = battler;
|
||||
|
|
@ -2374,7 +2375,7 @@ u8 DoBattlerEndTurnEffects(void)
|
|||
case ENDTURN_POISON: // poison
|
||||
if ((gBattleMons[battler].status1 & STATUS1_POISON)
|
||||
&& IsBattlerAlive(battler)
|
||||
&& !IsBattlerProtectedByMagicGuard(battler, ability))
|
||||
&& !IsMagicGuardProtected(battler, ability))
|
||||
{
|
||||
if (ability == ABILITY_POISON_HEAL)
|
||||
{
|
||||
|
|
@ -2402,7 +2403,7 @@ u8 DoBattlerEndTurnEffects(void)
|
|||
case ENDTURN_BAD_POISON: // toxic poison
|
||||
if ((gBattleMons[battler].status1 & STATUS1_TOXIC_POISON)
|
||||
&& IsBattlerAlive(battler)
|
||||
&& !IsBattlerProtectedByMagicGuard(battler, ability))
|
||||
&& !IsMagicGuardProtected(battler, ability))
|
||||
{
|
||||
if (ability == ABILITY_POISON_HEAL)
|
||||
{
|
||||
|
|
@ -2433,7 +2434,7 @@ u8 DoBattlerEndTurnEffects(void)
|
|||
case ENDTURN_BURN: // burn
|
||||
if ((gBattleMons[battler].status1 & STATUS1_BURN)
|
||||
&& IsBattlerAlive(battler)
|
||||
&& !IsBattlerProtectedByMagicGuard(battler, ability))
|
||||
&& !IsMagicGuardProtected(battler, ability))
|
||||
{
|
||||
gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / (B_BURN_DAMAGE >= GEN_7 ? 16 : 8);
|
||||
if (ability == ABILITY_HEATPROOF)
|
||||
|
|
@ -2452,7 +2453,7 @@ u8 DoBattlerEndTurnEffects(void)
|
|||
case ENDTURN_FROSTBITE: // burn
|
||||
if ((gBattleMons[battler].status1 & STATUS1_FROSTBITE)
|
||||
&& IsBattlerAlive(battler)
|
||||
&& !IsBattlerProtectedByMagicGuard(battler, ability))
|
||||
&& !IsMagicGuardProtected(battler, ability))
|
||||
{
|
||||
gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / (B_BURN_DAMAGE >= GEN_7 ? 16 : 8);
|
||||
if (gBattleStruct->moveDamage[battler] == 0)
|
||||
|
|
@ -2465,7 +2466,7 @@ u8 DoBattlerEndTurnEffects(void)
|
|||
case ENDTURN_NIGHTMARES: // spooky nightmares
|
||||
if ((gBattleMons[battler].status2 & STATUS2_NIGHTMARE)
|
||||
&& IsBattlerAlive(battler)
|
||||
&& !IsBattlerProtectedByMagicGuard(battler, ability))
|
||||
&& !IsMagicGuardProtected(battler, ability))
|
||||
{
|
||||
// R/S does not perform this sleep check, which causes the nightmare effect to
|
||||
// persist even after the affected Pokémon has been awakened by Shed Skin.
|
||||
|
|
@ -2487,7 +2488,7 @@ u8 DoBattlerEndTurnEffects(void)
|
|||
case ENDTURN_CURSE: // curse
|
||||
if ((gBattleMons[battler].status2 & STATUS2_CURSED)
|
||||
&& IsBattlerAlive(battler)
|
||||
&& !IsBattlerProtectedByMagicGuard(battler, ability))
|
||||
&& !IsMagicGuardProtected(battler, ability))
|
||||
{
|
||||
gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 4;
|
||||
if (gBattleStruct->moveDamage[battler] == 0)
|
||||
|
|
@ -2502,7 +2503,7 @@ u8 DoBattlerEndTurnEffects(void)
|
|||
{
|
||||
if (--gDisableStructs[battler].wrapTurns != 0) // damaged by wrap
|
||||
{
|
||||
if (IsBattlerProtectedByMagicGuard(battler, ability))
|
||||
if (IsMagicGuardProtected(battler, ability))
|
||||
{
|
||||
gBattleStruct->turnEffectsTracker++;
|
||||
break;
|
||||
|
|
@ -2812,7 +2813,7 @@ u8 DoBattlerEndTurnEffects(void)
|
|||
case ENDTURN_SALT_CURE:
|
||||
if (gStatuses4[battler] & STATUS4_SALT_CURE
|
||||
&& IsBattlerAlive(battler)
|
||||
&& !IsBattlerProtectedByMagicGuard(battler, ability))
|
||||
&& !IsMagicGuardProtected(battler, ability))
|
||||
{
|
||||
gBattlerTarget = battler;
|
||||
if (IS_BATTLER_ANY_TYPE(battler, TYPE_STEEL, TYPE_WATER))
|
||||
|
|
|
|||
|
|
@ -412,3 +412,43 @@ SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke don't prevent S
|
|||
MESSAGE("The opposing Metang used Celebrate!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke protect from Protect's secondary effects")
|
||||
{
|
||||
u32 move = MOVE_NONE;
|
||||
u32 species = SPECIES_NONE;
|
||||
u32 ability = ABILITY_NONE;
|
||||
|
||||
static const u32 moves[] = {
|
||||
MOVE_SPIKY_SHIELD,
|
||||
MOVE_KINGS_SHIELD,
|
||||
MOVE_SILK_TRAP,
|
||||
MOVE_OBSTRUCT,
|
||||
};
|
||||
|
||||
for (u32 j = 0; j < ARRAY_COUNT(moves); j++)
|
||||
{
|
||||
PARAMETRIZE{ move = moves[j]; species = SPECIES_METANG; ability = ABILITY_CLEAR_BODY; }
|
||||
PARAMETRIZE{ move = moves[j]; species = SPECIES_SOLGALEO; ability = ABILITY_FULL_METAL_BODY; }
|
||||
PARAMETRIZE{ move = moves[j]; species = SPECIES_TORKOAL; ability = ABILITY_WHITE_SMOKE; }
|
||||
}
|
||||
|
||||
GIVEN {
|
||||
PLAYER(species) { Ability(ability); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, move); MOVE(player, MOVE_TACKLE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
|
||||
if (move == MOVE_KINGS_SHIELD) {
|
||||
MESSAGE("Wobbuffet's Attack fell!");
|
||||
} else if (move == MOVE_SILK_TRAP) {
|
||||
MESSAGE("Wobbuffet's Speed fell!");
|
||||
} else if (move == MOVE_OBSTRUCT) {
|
||||
MESSAGE("Wobbuffet's Defense harshly fell!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,3 +88,34 @@ SINGLE_BATTLE_TEST("Clear Amulet prevents secondary effects that reduce stats")
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Clear Amulet protects from Protect's secondary effects")
|
||||
{
|
||||
u32 move;
|
||||
|
||||
PARAMETRIZE { move = MOVE_SPIKY_SHIELD; }
|
||||
PARAMETRIZE { move = MOVE_BANEFUL_BUNKER; }
|
||||
PARAMETRIZE { move = MOVE_BURNING_BULWARK; }
|
||||
PARAMETRIZE { move = MOVE_KINGS_SHIELD; }
|
||||
PARAMETRIZE { move = MOVE_SILK_TRAP; }
|
||||
PARAMETRIZE { move = MOVE_OBSTRUCT; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_CLEAR_AMULET); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, move); MOVE(player, MOVE_TACKLE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
|
||||
if (move == MOVE_KINGS_SHIELD) {
|
||||
MESSAGE("Wobbuffet's Attack fell!");
|
||||
} else if (move == MOVE_SILK_TRAP) {
|
||||
MESSAGE("Wobbuffet's Speed fell!");
|
||||
} else if (move == MOVE_OBSTRUCT) {
|
||||
MESSAGE("Wobbuffet's Defense harshly fell!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,9 +97,9 @@ SINGLE_BATTLE_TEST("Protective Pads protects from Protect's secondary effects")
|
|||
if (move == MOVE_SPIKY_SHIELD) {
|
||||
HP_BAR(player);
|
||||
} else if (move == MOVE_BANEFUL_BUNKER) {
|
||||
STATUS_ICON(player, STATUS1_BURN);
|
||||
} else if (move == MOVE_BURNING_BULWARK) {
|
||||
STATUS_ICON(player, STATUS1_POISON);
|
||||
} else if (move == MOVE_BURNING_BULWARK) {
|
||||
STATUS_ICON(player, STATUS1_BURN);
|
||||
} else if (move == MOVE_KINGS_SHIELD) {
|
||||
MESSAGE("Wobbuffet's Attack fell!");
|
||||
} else if (move == MOVE_SILK_TRAP) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,43 @@
|
|||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Counter is not affected by Protect effects")
|
||||
{
|
||||
u32 move;
|
||||
|
||||
PARAMETRIZE { move = MOVE_SPIKY_SHIELD; }
|
||||
PARAMETRIZE { move = MOVE_BANEFUL_BUNKER; }
|
||||
PARAMETRIZE { move = MOVE_BURNING_BULWARK; }
|
||||
PARAMETRIZE { move = MOVE_KINGS_SHIELD; }
|
||||
PARAMETRIZE { move = MOVE_SILK_TRAP; }
|
||||
PARAMETRIZE { move = MOVE_OBSTRUCT; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, move); MOVE(player, MOVE_COUNTER); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_COUNTER, player);
|
||||
if (move == MOVE_SPIKY_SHIELD) {
|
||||
HP_BAR(player);
|
||||
} else if (move == MOVE_BANEFUL_BUNKER) {
|
||||
STATUS_ICON(player, STATUS1_POISON);
|
||||
} else if (move == MOVE_BURNING_BULWARK) {
|
||||
STATUS_ICON(player, STATUS1_BURN);
|
||||
} else if (move == MOVE_KINGS_SHIELD) {
|
||||
MESSAGE("Wobbuffet's Attack fell!");
|
||||
} else if (move == MOVE_SILK_TRAP) {
|
||||
MESSAGE("Wobbuffet's Speed fell!");
|
||||
} else if (move == MOVE_OBSTRUCT) {
|
||||
MESSAGE("Wobbuffet's Defense harshly fell!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Counter will do twice as much damage received from the opponent");
|
||||
TO_DO_BATTLE_TEST("Counter cannot affect ally Pokémon");
|
||||
TO_DO_BATTLE_TEST("Counter hits the last opponent that hit the user"); //Doubles
|
||||
|
|
|
|||
|
|
@ -563,23 +563,3 @@ DOUBLE_BATTLE_TEST("Crafty Shield does not protect against moves that target all
|
|||
MESSAGE("The opposing Sunflora's Defense rose!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Spiky Shield does not damage users on Counter or Mirror Coat")
|
||||
{
|
||||
u32 move;
|
||||
PARAMETRIZE { move = MOVE_MIRROR_COAT; }
|
||||
PARAMETRIZE { move = MOVE_COUNTER; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SPIKY_SHIELD); MOVE(opponent, move); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPIKY_SHIELD, player);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
HP_BAR(opponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user