mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-12-26 03:34:15 +01:00
Roost suppresses the user's Flying-type rather than remove and re-add it. Added tests for EFFECT_ROOST. (#3258)
* Fixed Roost clearing type3 when used by a pure Flying-type. (Gen 5+) * Created a test file for Roost. * Marked tests as TODO for now. * Added more tests for HP healed and type changing. * Created a function to handle Roost's Flying suppression when getting a battler's type. Added more tests. * Added test for not-yet-aquired Flying-type. Fixed/rewrote some other tests. * Now using GetBattlerType() in most relevant places. Fixed some tests. * Added tests for interactions between Roost and Delta Stream, type-changing effects, Grassy Terrain healing, Levitate, Air Balloon, Magnet Rise, and Telekinesis. * Added test for interaction between Roost and Reflect Type. * Gen 4 tests merged with Gen 5+ tests. * Removed errant space. Co-authored-by: LOuroboros <lunosouroboros@gmail.com> --------- Co-authored-by: LOuroboros <lunosouroboros@gmail.com>
This commit is contained in:
parent
b18d01878f
commit
89e4f30867
@ -723,7 +723,7 @@ STATIC_ASSERT(sizeof(((struct BattleStruct *)0)->palaceFlags) * 8 >= MAX_BATTLER
|
||||
#define TARGET_TURN_DAMAGED ((gSpecialStatuses[gBattlerTarget].physicalDmg != 0 || gSpecialStatuses[gBattlerTarget].specialDmg != 0))
|
||||
#define BATTLER_DAMAGED(battlerId) ((gSpecialStatuses[battlerId].physicalDmg != 0 || gSpecialStatuses[battlerId].specialDmg != 0))
|
||||
|
||||
#define IS_BATTLER_OF_TYPE(battlerId, type)((gBattleMons[battlerId].type1 == type || gBattleMons[battlerId].type2 == type || (gBattleMons[battlerId].type3 != TYPE_MYSTERY && gBattleMons[battlerId].type3 == type)))
|
||||
#define IS_BATTLER_OF_TYPE(battlerId, type)((GetBattlerType(battlerId, 0) == type || GetBattlerType(battlerId, 1) == type || (GetBattlerType(battlerId, 2) != TYPE_MYSTERY && GetBattlerType(battlerId, 2) == type)))
|
||||
#define SET_BATTLER_TYPE(battlerId, type) \
|
||||
{ \
|
||||
gBattleMons[battlerId].type1 = type; \
|
||||
|
@ -248,5 +248,6 @@ void RemoveConfusionStatus(u32 battler);
|
||||
u8 GetBattlerGender(u32 battler);
|
||||
bool32 AreBattlersOfOppositeGender(u32 battler1, u32 battler2);
|
||||
u32 CalcSecondaryEffectChance(u32 battler, u8 secondaryEffectChance);
|
||||
u8 GetBattlerType(u32 battler, u8 typeIndex);
|
||||
|
||||
#endif // GUARD_BATTLE_UTIL_H
|
||||
|
@ -2430,9 +2430,9 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
break;
|
||||
case EFFECT_SOAK:
|
||||
if (PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)
|
||||
|| (gBattleMons[battlerDef].type1 == TYPE_WATER
|
||||
&& gBattleMons[battlerDef].type2 == TYPE_WATER
|
||||
&& gBattleMons[battlerDef].type3 == TYPE_MYSTERY))
|
||||
|| (GetBattlerType(battlerDef, 0) == TYPE_WATER
|
||||
&& GetBattlerType(battlerDef, 1) == TYPE_WATER
|
||||
&& GetBattlerType(battlerDef, 2) == TYPE_MYSTERY))
|
||||
score -= 10; // target is already water-only
|
||||
break;
|
||||
case EFFECT_THIRD_TYPE:
|
||||
@ -2582,9 +2582,9 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
case EFFECT_SYNCHRONOISE:
|
||||
//Check holding ring target or is of same type
|
||||
if (aiData->holdEffects[battlerDef] == HOLD_EFFECT_RING_TARGET
|
||||
|| IS_BATTLER_OF_TYPE(battlerDef, gBattleMons[battlerAtk].type1)
|
||||
|| IS_BATTLER_OF_TYPE(battlerDef, gBattleMons[battlerAtk].type2)
|
||||
|| IS_BATTLER_OF_TYPE(battlerDef, gBattleMons[battlerAtk].type3))
|
||||
|| IS_BATTLER_OF_TYPE(battlerDef, GetBattlerType(battlerAtk, 0))
|
||||
|| IS_BATTLER_OF_TYPE(battlerDef, GetBattlerType(battlerAtk, 1))
|
||||
|| IS_BATTLER_OF_TYPE(battlerDef, GetBattlerType(battlerAtk, 2)))
|
||||
break;
|
||||
else
|
||||
score -= 10;
|
||||
@ -3025,9 +3025,9 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
break;
|
||||
case EFFECT_SOAK:
|
||||
if (atkPartnerAbility == ABILITY_WONDER_GUARD
|
||||
&& (gBattleMons[battlerAtkPartner].type1 != TYPE_WATER
|
||||
|| gBattleMons[battlerAtkPartner].type2 != TYPE_WATER
|
||||
|| gBattleMons[battlerAtkPartner].type3 != TYPE_WATER))
|
||||
&& (GetBattlerType(battlerAtkPartner, 0) != TYPE_WATER
|
||||
|| GetBattlerType(battlerAtkPartner, 1) != TYPE_WATER
|
||||
|| GetBattlerType(battlerAtkPartner, 2) != TYPE_WATER))
|
||||
{
|
||||
RETURN_SCORE_PLUS(1);
|
||||
}
|
||||
|
@ -2126,12 +2126,12 @@ END:
|
||||
// of a move that is Super Effective against a Flying-type Pokémon.
|
||||
if (gBattleWeather & B_WEATHER_STRONG_WINDS)
|
||||
{
|
||||
if ((gBattleMons[gBattlerTarget].type1 == TYPE_FLYING
|
||||
&& GetTypeModifier(moveType, gBattleMons[gBattlerTarget].type1) >= UQ_4_12(2.0))
|
||||
|| (gBattleMons[gBattlerTarget].type2 == TYPE_FLYING
|
||||
&& GetTypeModifier(moveType, gBattleMons[gBattlerTarget].type2) >= UQ_4_12(2.0))
|
||||
|| (gBattleMons[gBattlerTarget].type3 == TYPE_FLYING
|
||||
&& GetTypeModifier(moveType, gBattleMons[gBattlerTarget].type3) >= UQ_4_12(2.0)))
|
||||
if ((GetBattlerType(gBattlerTarget, 0) == TYPE_FLYING
|
||||
&& GetTypeModifier(moveType, GetBattlerType(gBattlerTarget, 0)) >= UQ_4_12(2.0))
|
||||
|| (GetBattlerType(gBattlerTarget, 1) == TYPE_FLYING
|
||||
&& GetTypeModifier(moveType, GetBattlerType(gBattlerTarget, 1)) >= UQ_4_12(2.0))
|
||||
|| (GetBattlerType(gBattlerTarget, 2) == TYPE_FLYING
|
||||
&& GetTypeModifier(moveType, GetBattlerType(gBattlerTarget, 2)) >= UQ_4_12(2.0)))
|
||||
{
|
||||
gBattlerAbility = gBattlerTarget;
|
||||
BattleScriptPushCursor();
|
||||
@ -4909,34 +4909,8 @@ static void Cmd_setroost(void)
|
||||
CMD_ARGS();
|
||||
|
||||
gBattleResources->flags->flags[gBattlerAttacker] |= RESOURCE_FLAG_ROOST;
|
||||
|
||||
// Pure flying type.
|
||||
if (gBattleMons[gBattlerAttacker].type1 == TYPE_FLYING && gBattleMons[gBattlerAttacker].type2 == TYPE_FLYING)
|
||||
{
|
||||
gBattleStruct->roostTypes[gBattlerAttacker][0] = TYPE_FLYING;
|
||||
gBattleStruct->roostTypes[gBattlerAttacker][1] = TYPE_FLYING;
|
||||
#if B_ROOST_PURE_FLYING >= GEN_5
|
||||
SET_BATTLER_TYPE(gBattlerAttacker, TYPE_NORMAL);
|
||||
#else
|
||||
SET_BATTLER_TYPE(gBattlerAttacker, TYPE_MYSTERY);
|
||||
#endif
|
||||
}
|
||||
// Dual type with flying type.
|
||||
else if (gBattleMons[gBattlerAttacker].type1 == TYPE_FLYING || gBattleMons[gBattlerAttacker].type2 == TYPE_FLYING)
|
||||
{
|
||||
gBattleStruct->roostTypes[gBattlerAttacker][0] = gBattleMons[gBattlerAttacker].type1;
|
||||
gBattleStruct->roostTypes[gBattlerAttacker][1] = gBattleMons[gBattlerAttacker].type2;
|
||||
if (gBattleMons[gBattlerAttacker].type1 == TYPE_FLYING)
|
||||
gBattleMons[gBattlerAttacker].type1 = TYPE_MYSTERY;
|
||||
else if (gBattleMons[gBattlerAttacker].type2 == TYPE_FLYING)
|
||||
gBattleMons[gBattlerAttacker].type2 = TYPE_MYSTERY;
|
||||
}
|
||||
// Non-flying type.
|
||||
else
|
||||
{
|
||||
gBattleStruct->roostTypes[gBattlerAttacker][0] = gBattleMons[gBattlerAttacker].type1;
|
||||
gBattleStruct->roostTypes[gBattlerAttacker][1] = gBattleMons[gBattlerAttacker].type2;
|
||||
}
|
||||
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
@ -9442,26 +9416,26 @@ static void Cmd_various(void)
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
}
|
||||
else if (gBattleMons[gBattlerTarget].type1 == TYPE_MYSTERY && gBattleMons[gBattlerTarget].type2 != TYPE_MYSTERY)
|
||||
else if (GetBattlerType(gBattlerTarget, 0) == TYPE_MYSTERY && GetBattlerType(gBattlerTarget, 1) != TYPE_MYSTERY)
|
||||
{
|
||||
gBattleMons[gBattlerAttacker].type1 = gBattleMons[gBattlerTarget].type2;
|
||||
gBattleMons[gBattlerAttacker].type2 = gBattleMons[gBattlerTarget].type2;
|
||||
gBattleMons[gBattlerAttacker].type1 = GetBattlerType(gBattlerTarget, 1);
|
||||
gBattleMons[gBattlerAttacker].type2 = GetBattlerType(gBattlerTarget, 1);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
else if (gBattleMons[gBattlerTarget].type1 != TYPE_MYSTERY && gBattleMons[gBattlerTarget].type2 == TYPE_MYSTERY)
|
||||
else if (GetBattlerType(gBattlerTarget, 0) != TYPE_MYSTERY && GetBattlerType(gBattlerTarget, 1) == TYPE_MYSTERY)
|
||||
{
|
||||
gBattleMons[gBattlerAttacker].type1 = gBattleMons[gBattlerTarget].type1;
|
||||
gBattleMons[gBattlerAttacker].type2 = gBattleMons[gBattlerTarget].type1;
|
||||
gBattleMons[gBattlerAttacker].type1 = GetBattlerType(gBattlerTarget, 0);
|
||||
gBattleMons[gBattlerAttacker].type2 = GetBattlerType(gBattlerTarget, 0);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
else if (gBattleMons[gBattlerTarget].type1 == TYPE_MYSTERY && gBattleMons[gBattlerTarget].type2 == TYPE_MYSTERY)
|
||||
else if (GetBattlerType(gBattlerTarget, 0) == TYPE_MYSTERY && GetBattlerType(gBattlerTarget, 1) == TYPE_MYSTERY)
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
}
|
||||
else
|
||||
{
|
||||
gBattleMons[gBattlerAttacker].type1 = gBattleMons[gBattlerTarget].type1;
|
||||
gBattleMons[gBattlerAttacker].type2 = gBattleMons[gBattlerTarget].type2;
|
||||
gBattleMons[gBattlerAttacker].type1 = GetBattlerType(gBattlerTarget, 0);
|
||||
gBattleMons[gBattlerAttacker].type2 = GetBattlerType(gBattlerTarget, 1);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
return;
|
||||
@ -9469,8 +9443,8 @@ static void Cmd_various(void)
|
||||
case VARIOUS_TRY_SOAK:
|
||||
{
|
||||
VARIOUS_ARGS(const u8 *failInstr);
|
||||
if (gBattleMons[gBattlerTarget].type1 == gBattleMoves[gCurrentMove].type
|
||||
&& gBattleMons[gBattlerTarget].type2 == gBattleMoves[gCurrentMove].type)
|
||||
if (GetBattlerType(gBattlerTarget, 0) == gBattleMoves[gCurrentMove].type
|
||||
&& GetBattlerType(gBattlerTarget, 1) == gBattleMoves[gCurrentMove].type)
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
}
|
||||
|
@ -3065,11 +3065,7 @@ u8 DoBattlerEndTurnEffects(void)
|
||||
break;
|
||||
case ENDTURN_ROOST: // Return flying type.
|
||||
if (gBattleResources->flags->flags[battler] & RESOURCE_FLAG_ROOST)
|
||||
{
|
||||
gBattleResources->flags->flags[battler] &= ~RESOURCE_FLAG_ROOST;
|
||||
gBattleMons[battler].type1 = gBattleStruct->roostTypes[battler][0];
|
||||
gBattleMons[battler].type2 = gBattleStruct->roostTypes[battler][1];
|
||||
}
|
||||
gBattleStruct->turnEffectsTracker++;
|
||||
break;
|
||||
case ENDTURN_ELECTRIFY:
|
||||
@ -9990,12 +9986,12 @@ static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(u32 move, u32 mov
|
||||
{
|
||||
u32 illusionSpecies;
|
||||
|
||||
MulByTypeEffectiveness(&modifier, move, moveType, battlerDef, gBattleMons[battlerDef].type1, battlerAtk, recordAbilities);
|
||||
if (gBattleMons[battlerDef].type2 != gBattleMons[battlerDef].type1)
|
||||
MulByTypeEffectiveness(&modifier, move, moveType, battlerDef, gBattleMons[battlerDef].type2, battlerAtk, recordAbilities);
|
||||
if (gBattleMons[battlerDef].type3 != TYPE_MYSTERY && gBattleMons[battlerDef].type3 != gBattleMons[battlerDef].type2
|
||||
&& gBattleMons[battlerDef].type3 != gBattleMons[battlerDef].type1)
|
||||
MulByTypeEffectiveness(&modifier, move, moveType, battlerDef, gBattleMons[battlerDef].type3, battlerAtk, recordAbilities);
|
||||
MulByTypeEffectiveness(&modifier, move, moveType, battlerDef, GetBattlerType(battlerDef, 0), battlerAtk, recordAbilities);
|
||||
if (GetBattlerType(battlerDef, 1) != GetBattlerType(battlerDef, 0))
|
||||
MulByTypeEffectiveness(&modifier, move, moveType, battlerDef, GetBattlerType(battlerDef, 1), battlerAtk, recordAbilities);
|
||||
if (GetBattlerType(battlerDef, 2) != TYPE_MYSTERY && GetBattlerType(battlerDef, 2) != GetBattlerType(battlerDef, 1)
|
||||
&& GetBattlerType(battlerDef, 2) != GetBattlerType(battlerDef, 0))
|
||||
MulByTypeEffectiveness(&modifier, move, moveType, battlerDef, GetBattlerType(battlerDef, 2), battlerAtk, recordAbilities);
|
||||
|
||||
if (recordAbilities && (illusionSpecies = GetIllusionMonSpecies(battlerDef)))
|
||||
TryNoticeIllusionInTypeEffectiveness(move, moveType, battlerAtk, battlerDef, modifier, illusionSpecies);
|
||||
@ -10506,8 +10502,8 @@ bool32 TryBattleFormChange(u32 battler, u16 method)
|
||||
bool32 DoBattlersShareType(u32 battler1, u32 battler2)
|
||||
{
|
||||
s32 i;
|
||||
u8 types1[3] = {gBattleMons[battler1].type1, gBattleMons[battler1].type2, gBattleMons[battler1].type3};
|
||||
u8 types2[3] = {gBattleMons[battler2].type1, gBattleMons[battler2].type2, gBattleMons[battler2].type3};
|
||||
u8 types1[3] = {GetBattlerType(battler1, 0), GetBattlerType(battler1, 1), GetBattlerType(battler1, 2)};
|
||||
u8 types2[3] = {GetBattlerType(battler2, 0), GetBattlerType(battler2, 1), GetBattlerType(battler2, 2)};
|
||||
|
||||
if (types1[2] == TYPE_MYSTERY)
|
||||
types1[2] = types1[0];
|
||||
@ -11199,3 +11195,31 @@ bool32 IsGen6ExpShareEnabled(void)
|
||||
return FlagGet(I_EXP_SHARE_FLAG);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
u8 GetBattlerType(u32 battler, u8 typeIndex)
|
||||
{
|
||||
u16 types[3] = {0};
|
||||
types[0] = gBattleMons[battler].type1;
|
||||
types[1] = gBattleMons[battler].type2;
|
||||
types[2] = gBattleMons[battler].type3;
|
||||
|
||||
// Handle Roost's Flying-type suppression
|
||||
if (typeIndex == 0 || typeIndex == 1)
|
||||
{
|
||||
if (gBattleResources->flags->flags[battler] & RESOURCE_FLAG_ROOST)
|
||||
{
|
||||
if (types[0] == TYPE_FLYING && types[1] == TYPE_FLYING)
|
||||
#if B_ROOST_PURE_FLYING >= GEN_5
|
||||
return TYPE_NORMAL;
|
||||
#else
|
||||
return TYPE_MYSTERY;
|
||||
#endif
|
||||
else
|
||||
return types[typeIndex] == TYPE_FLYING ? TYPE_MYSTERY : types[typeIndex];
|
||||
}
|
||||
}
|
||||
|
||||
return types[typeIndex];
|
||||
}
|
||||
|
||||
|
432
test/battle/move_effect/roost.c
Normal file
432
test/battle/move_effect/roost.c
Normal file
@ -0,0 +1,432 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(gBattleMoves[MOVE_ROOST].effect == EFFECT_ROOST);
|
||||
ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_FLYING);
|
||||
ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_FLYING);
|
||||
// One attack of each type to verify typelessness
|
||||
ASSUME(gBattleMoves[MOVE_POUND].type == TYPE_NORMAL);
|
||||
ASSUME(gBattleMoves[MOVE_KARATE_CHOP].type == TYPE_FIGHTING);
|
||||
ASSUME(gBattleMoves[MOVE_GUST].type == TYPE_FLYING);
|
||||
ASSUME(gBattleMoves[MOVE_POISON_STING].type == TYPE_POISON);
|
||||
ASSUME(gBattleMoves[MOVE_EARTHQUAKE].type == TYPE_GROUND);
|
||||
ASSUME(gBattleMoves[MOVE_ROCK_THROW].type == TYPE_ROCK);
|
||||
ASSUME(gBattleMoves[MOVE_LEECH_LIFE].type == TYPE_BUG);
|
||||
ASSUME(gBattleMoves[MOVE_LICK].type == TYPE_GHOST);
|
||||
ASSUME(gBattleMoves[MOVE_STEEL_WING].type == TYPE_STEEL);
|
||||
ASSUME(gBattleMoves[MOVE_EMBER].type == TYPE_FIRE);
|
||||
ASSUME(gBattleMoves[MOVE_WATER_GUN].type == TYPE_WATER);
|
||||
ASSUME(gBattleMoves[MOVE_VINE_WHIP].type == TYPE_GRASS);
|
||||
ASSUME(gBattleMoves[MOVE_THUNDER_SHOCK].type == TYPE_ELECTRIC);
|
||||
ASSUME(gBattleMoves[MOVE_CONFUSION].type == TYPE_PSYCHIC);
|
||||
ASSUME(gBattleMoves[MOVE_ICE_BEAM].type == TYPE_ICE);
|
||||
ASSUME(gBattleMoves[MOVE_DRAGON_BREATH].type == TYPE_DRAGON);
|
||||
ASSUME(gBattleMoves[MOVE_BITE].type == TYPE_DARK);
|
||||
ASSUME(gBattleMoves[MOVE_DISARMING_VOICE].type == TYPE_FAIRY);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Roost fails when user is at full HP")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_ROOST); }
|
||||
} SCENE {
|
||||
MESSAGE("Wobbuffet's HP is full!");
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_ROOST, player);
|
||||
NOT HP_BAR(player);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Roost fails if the user is under the effects of Heal Block")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(100); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_HEAL_BLOCK); MOVE(player, MOVE_ROOST); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_HEAL_BLOCK, opponent);
|
||||
MESSAGE("Wobbuffet was prevented from healing!"); // Message when Heal Block is applied
|
||||
MESSAGE("Wobbuffet was prevented from healing!"); // Message when trying to heal under Heal Block
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_ROOST, player);
|
||||
NOT HP_BAR(player);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Roost recovers 50% of the user's Max HP")
|
||||
{
|
||||
s16 hp;
|
||||
|
||||
KNOWN_FAILING; // All healing is currently rounded down
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(1); MaxHP(99); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_ROOST); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ROOST, player);
|
||||
HP_BAR(player, captureHP: &hp);
|
||||
} THEN {
|
||||
//if (B_UPDATED_MOVE_DATA >= GEN_5)
|
||||
EXPECT(hp == 51); // Rounds up
|
||||
//else
|
||||
// EXPECT(hp == 50); // Rounds down
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Roost suppresses the user's Flying-typing this turn, then restores it at the end of the turn")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_SKARMORY].types[0] == TYPE_STEEL);
|
||||
ASSUME(gSpeciesInfo[SPECIES_SKARMORY].types[1] == TYPE_FLYING);
|
||||
PLAYER(SPECIES_SKARMORY) { HP(50); MaxHP(100); Ability(ABILITY_STURDY); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_ROOST); MOVE(opponent, MOVE_EARTHQUAKE); }
|
||||
TURN { MOVE(opponent, MOVE_EARTHQUAKE); }
|
||||
} SCENE {
|
||||
// Turn 1: EQ hits when Roosted
|
||||
MESSAGE("Skarmory used Roost!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ROOST, player);
|
||||
MESSAGE("Skarmory regained health!");
|
||||
MESSAGE("Foe Wobbuffet used Earthquake!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EARTHQUAKE, opponent);
|
||||
MESSAGE("It's super effective!");
|
||||
// Turn 2: EQ has no effect because Roost expired
|
||||
MESSAGE("Foe Wobbuffet used Earthquake!");
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_EARTHQUAKE, opponent);
|
||||
MESSAGE("It doesn't affect Skarmory…");
|
||||
NOT HP_BAR(player);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Roost, if used by a Flying/Flying type, treats the user as a Normal-type (or Typeless in Gen. 4) until the end of the turn")
|
||||
{
|
||||
u32 damagingMove;
|
||||
PARAMETRIZE{ damagingMove = MOVE_POUND; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_KARATE_CHOP; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_GUST; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_POISON_STING; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_EARTHQUAKE; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_ROCK_THROW; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_LEECH_LIFE; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_LICK; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_STEEL_WING; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_EMBER; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_WATER_GUN; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_VINE_WHIP; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_THUNDER_SHOCK; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_CONFUSION; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_ICE_BEAM; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_DRAGON_BREATH; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_BITE; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_DISARMING_VOICE; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(P_GEN_5_POKEMON == TRUE);
|
||||
ASSUME(gSpeciesInfo[SPECIES_TORNADUS].types[0] == TYPE_FLYING);
|
||||
ASSUME(gSpeciesInfo[SPECIES_TORNADUS].types[1] == TYPE_FLYING);
|
||||
PLAYER(SPECIES_TORNADUS) { HP(50); MaxHP(100); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_ROOST); MOVE(opponent, damagingMove); }
|
||||
} SCENE {
|
||||
MESSAGE("Tornadus used Roost!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ROOST, player);
|
||||
MESSAGE("Tornadus regained health!");
|
||||
|
||||
if (B_ROOST_PURE_FLYING >= GEN_5) // >= Gen. 5, Pokemon becomes pure Normal-type
|
||||
{
|
||||
if (damagingMove == MOVE_KARATE_CHOP)
|
||||
{
|
||||
ANIMATION(ANIM_TYPE_MOVE, damagingMove, opponent);
|
||||
MESSAGE("It's super effective!");
|
||||
}
|
||||
else if (damagingMove == MOVE_LICK)
|
||||
{
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, damagingMove, opponent);
|
||||
MESSAGE("It doesn't affect Tornadus…");
|
||||
}
|
||||
else
|
||||
{
|
||||
ANIMATION(ANIM_TYPE_MOVE, damagingMove, opponent);
|
||||
NONE_OF {
|
||||
MESSAGE("It's super effective!");
|
||||
MESSAGE("It's not very effective…");
|
||||
MESSAGE("It doesn't affect Tornadus…");
|
||||
}
|
||||
}
|
||||
}
|
||||
else // <= Gen. 4, Pokemon becomes Typeless
|
||||
{
|
||||
// Should not see any effectiveness messages
|
||||
NONE_OF {
|
||||
MESSAGE("It's super effective!");
|
||||
MESSAGE("It's not very effective…");
|
||||
MESSAGE("It doesn't affect Tornadus…");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Roost, if used by a Mystery/Flying type, treats the user as a Mystery/Mystery type until the end of the turn")
|
||||
{
|
||||
u32 damagingMove;
|
||||
PARAMETRIZE{ damagingMove = MOVE_POUND; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_KARATE_CHOP; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_GUST; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_POISON_STING; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_EARTHQUAKE; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_ROCK_THROW; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_LEECH_LIFE; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_LICK; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_STEEL_WING; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_EMBER; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_WATER_GUN; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_VINE_WHIP; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_THUNDER_SHOCK; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_CONFUSION; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_ICE_BEAM; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_DRAGON_BREATH; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_BITE; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_DISARMING_VOICE; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_MOLTRES].types[0] == TYPE_FIRE);
|
||||
ASSUME(gSpeciesInfo[SPECIES_MOLTRES].types[1] == TYPE_FLYING);
|
||||
PLAYER(SPECIES_MOLTRES) { HP(300); MaxHP(400); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_BURN_UP); }
|
||||
TURN { MOVE(player, MOVE_ROOST); MOVE(opponent, damagingMove); }
|
||||
} SCENE {
|
||||
// Turn 1: Use Burn Up to change from Fire/Flying to Mystery/Flying
|
||||
MESSAGE("Moltres used Burn Up!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_BURN_UP, player);
|
||||
MESSAGE("Moltres burned itself out!");
|
||||
// Turn 2: Use Roost to now be treated as a Mystery/Mystery type
|
||||
MESSAGE("Moltres used Roost!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ROOST, player);
|
||||
MESSAGE("Moltres regained health!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, damagingMove, opponent);
|
||||
NONE_OF {
|
||||
MESSAGE("It's super effective!");
|
||||
MESSAGE("It's not very effective…");
|
||||
MESSAGE("It doesn't affect Moltres…");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tested in ORAS
|
||||
DOUBLE_BATTLE_TEST("Roost suppresses the user's not-yet-aquired Flying-type this turn")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_KECLEON].types[0] != TYPE_FLYING);
|
||||
ASSUME(gSpeciesInfo[SPECIES_KECLEON].types[1] != TYPE_FLYING);
|
||||
PLAYER(SPECIES_KECLEON) { Speed(40); HP(150); Ability(ABILITY_COLOR_CHANGE); }
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(10); }
|
||||
OPPONENT(SPECIES_PIDGEY) { Speed(30); }
|
||||
OPPONENT(SPECIES_SANDSHREW) { Speed(20); }
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_ROOST);
|
||||
MOVE(opponentLeft, MOVE_GUST, target: playerLeft);
|
||||
MOVE(opponentRight, MOVE_EARTHQUAKE, target: playerLeft); }
|
||||
} SCENE {
|
||||
MESSAGE("Kecleon used Roost!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ROOST, playerLeft);
|
||||
MESSAGE("Kecleon regained health!");
|
||||
MESSAGE("Foe Pidgey used Gust!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_GUST, opponentLeft);
|
||||
MESSAGE("Kecleon's Color Change made it the Flying type!");
|
||||
MESSAGE("Foe Sandshrew used Earthquake!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EARTHQUAKE, opponentRight);
|
||||
MESSAGE("Kecleon's Color Change made it the Ground type!");
|
||||
}
|
||||
}
|
||||
|
||||
// Tested in ORAS
|
||||
SINGLE_BATTLE_TEST("Roost prevents a Flying-type user from being protected by Delta Stream")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_RAYQUAZA].types[1] == TYPE_FLYING);
|
||||
PLAYER(SPECIES_RAYQUAZA) { HP(1); Ability(ABILITY_DELTA_STREAM); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_ROOST); MOVE(opponent, MOVE_ICE_BEAM); }
|
||||
} SCENE {
|
||||
MESSAGE("Rayquaza used Roost!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ROOST, player);
|
||||
MESSAGE("Rayquaza regained health!");
|
||||
MESSAGE("Foe Wobbuffet used Ice Beam!");
|
||||
NOT MESSAGE("The mysterious strong winds weakened the attack!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Roost does not undo other type-changing effects at the end of the turn")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_SWELLOW].types[0] == TYPE_NORMAL);
|
||||
ASSUME(gSpeciesInfo[SPECIES_SWELLOW].types[1] == TYPE_FLYING);
|
||||
PLAYER(SPECIES_SWELLOW) { HP(1); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_ROOST); MOVE(opponent, MOVE_SOAK); }
|
||||
TURN { MOVE(opponent, MOVE_VINE_WHIP); }
|
||||
} SCENE {
|
||||
MESSAGE("Swellow used Roost!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ROOST, player);
|
||||
MESSAGE("Swellow regained health!");
|
||||
MESSAGE("Foe Wobbuffet used Soak!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SOAK, opponent);
|
||||
MESSAGE("Swellow transformed into the Water type!");
|
||||
MESSAGE("Foe Wobbuffet used Vine Whip!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_VINE_WHIP, opponent);
|
||||
MESSAGE("It's super effective!");
|
||||
}
|
||||
}
|
||||
|
||||
// https://www.smogon.com/forums/threads/sword-shield-battle-mechanics-research.3655528/page-64#post-9244179
|
||||
SINGLE_BATTLE_TEST("Roost's effect is lifted after Grassy Terrain's healing")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_SWELLOW].types[0] == TYPE_NORMAL);
|
||||
ASSUME(gSpeciesInfo[SPECIES_SWELLOW].types[1] == TYPE_FLYING);
|
||||
PLAYER(SPECIES_SWELLOW) { HP(1); Ability(ABILITY_GRASSY_SURGE); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_ROOST); }
|
||||
} SCENE {
|
||||
MESSAGE("Swellow used Roost!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ROOST, player);
|
||||
MESSAGE("Swellow regained health!");
|
||||
MESSAGE("Swellow is healed by the grassy terrain!");
|
||||
HP_BAR(player);
|
||||
}
|
||||
}
|
||||
|
||||
// Tested in USUM
|
||||
SINGLE_BATTLE_TEST("Roost's suppression prevents Reflect Type from copying any Flying typing")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_SWELLOW].types[0] == TYPE_NORMAL);
|
||||
ASSUME(gSpeciesInfo[SPECIES_SWELLOW].types[1] == TYPE_FLYING);
|
||||
ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] == TYPE_PSYCHIC);
|
||||
ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[1] == TYPE_PSYCHIC);
|
||||
PLAYER(SPECIES_SWELLOW) { HP(1); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_ROOST); MOVE(opponent, MOVE_REFLECT_TYPE); }
|
||||
TURN { MOVE(player, MOVE_EARTHQUAKE); MOVE(opponent, MOVE_REFLECT_TYPE); }
|
||||
TURN { MOVE(player, MOVE_EARTHQUAKE); }
|
||||
} SCENE {
|
||||
// Turn 1: Reflect Type on Roosted Normal/Flying
|
||||
MESSAGE("Swellow used Roost!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ROOST, player);
|
||||
MESSAGE("Swellow regained health!");
|
||||
MESSAGE("Foe Wobbuffet used Reflect Type!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_REFLECT_TYPE, opponent);
|
||||
MESSAGE("Foe Wobbuffet's type changed to match the Swellow's!");
|
||||
// Turn 2: EQ hits, Reflect Type on non-Roosted Normal/Flying
|
||||
MESSAGE("Swellow used Earthquake!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EARTHQUAKE, player);
|
||||
HP_BAR(opponent);
|
||||
MESSAGE("Foe Wobbuffet used Reflect Type!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_REFLECT_TYPE, opponent);
|
||||
MESSAGE("Foe Wobbuffet's type changed to match the Swellow's!");
|
||||
// Turn 3: EQ has no effect
|
||||
MESSAGE("Swellow used Earthquake!");
|
||||
MESSAGE("It doesn't affect Foe Wobbuffet…");
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_EARTHQUAKE, player);
|
||||
NOT HP_BAR(opponent);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Roost does not suppress the ungrounded effect of Levitate")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_FLYGON) { HP(1); Ability(ABILITY_LEVITATE); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_ROOST); MOVE(opponent, MOVE_EARTHQUAKE); }
|
||||
} SCENE {
|
||||
MESSAGE("Flygon used Roost!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ROOST, player);
|
||||
MESSAGE("Flygon regained health!");
|
||||
MESSAGE("Foe Wobbuffet used Earthquake!");
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_EARTHQUAKE, opponent);
|
||||
NOT HP_BAR(player);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Roost does not suppress the ungrounded effect of Air Balloon")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(1); Item(ITEM_AIR_BALLOON); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_ROOST); MOVE(opponent, MOVE_EARTHQUAKE); }
|
||||
} SCENE {
|
||||
MESSAGE("Wobbuffet used Roost!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ROOST, player);
|
||||
MESSAGE("Wobbuffet regained health!");
|
||||
MESSAGE("Foe Wobbuffet used Earthquake!");
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_EARTHQUAKE, opponent);
|
||||
NOT HP_BAR(player);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Roost does not suppress the ungrounded effect of Magnet Rise")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(1); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_MAGNET_RISE); }
|
||||
TURN { MOVE(player, MOVE_ROOST); MOVE(opponent, MOVE_EARTHQUAKE); }
|
||||
} SCENE {
|
||||
// Turn 1: Magnet Rise
|
||||
MESSAGE("Wobbuffet used Magnet Rise!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_MAGNET_RISE, player);
|
||||
MESSAGE("Wobbuffet levitated on electromagnetism!");
|
||||
// Turn 2
|
||||
MESSAGE("Wobbuffet used Roost!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ROOST, player);
|
||||
MESSAGE("Wobbuffet regained health!");
|
||||
MESSAGE("Foe Wobbuffet used Earthquake!");
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_EARTHQUAKE, opponent);
|
||||
NOT HP_BAR(player);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Roost does not suppress the ungrounded effect of Telekinesis")
|
||||
{
|
||||
KNOWN_FAILING; // Telekinesis currently says the pokemon was identified
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(1); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_TELEKINESIS); }
|
||||
TURN { MOVE(player, MOVE_ROOST); MOVE(opponent, MOVE_EARTHQUAKE); }
|
||||
} SCENE {
|
||||
// Turn 1: Telekinesis
|
||||
MESSAGE("Foe Wobbuffet used Telekinesis!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TELEKINESIS, opponent);
|
||||
MESSAGE("Wobbuffet was hurled into the air!");
|
||||
// Turn 2
|
||||
MESSAGE("Wobbuffet used Roost!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ROOST, player);
|
||||
MESSAGE("Wobbuffet regained health!");
|
||||
MESSAGE("Foe Wobbuffet used Earthquake!");
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_EARTHQUAKE, opponent);
|
||||
NOT HP_BAR(player);
|
||||
}
|
||||
}
|
||||
|
||||
// Tested in ORAS
|
||||
// Transform does not copy the Roost "status" either.
|
||||
// Probably better as a Transform test.
|
||||
TO_DO_BATTLE_TEST("Roost's suppression does not prevent others who are Transforming into the user from copying its Flying-type");
|
Loading…
Reference in New Issue
Block a user