Merge branch '_RHH/master' into _RHH/upcoming

This commit is contained in:
Eduardo Quezada 2024-10-04 14:28:13 -03:00
commit a7fca616b0
10 changed files with 576 additions and 71 deletions

View file

@ -1094,6 +1094,7 @@ extern u16 gLastPrintedMoves[MAX_BATTLERS_COUNT];
extern u16 gLastMoves[MAX_BATTLERS_COUNT];
extern u16 gLastLandedMoves[MAX_BATTLERS_COUNT];
extern u16 gLastHitByType[MAX_BATTLERS_COUNT];
extern u16 gLastUsedMoveType[MAX_BATTLERS_COUNT];
extern u16 gLastResultingMoves[MAX_BATTLERS_COUNT];
extern u16 gLockedMoves[MAX_BATTLERS_COUNT];
extern u16 gLastUsedMove;

View file

@ -69,6 +69,7 @@
#define B_RECOIL_IF_MISS_DMG GEN_LATEST // In Gen5+, Jump Kick and High Jump Kick will always do half of the user's max HP when missing.
#define B_KLUTZ_FLING_INTERACTION GEN_LATEST // In Gen5+, Pokémon with the Klutz ability can't use Fling.
#define B_UPDATED_CONVERSION GEN_LATEST // In Gen6+, Conversion changes the user's type to match their first move's. Before, it would choose a move at random.
#define B_UPDATED_CONVERSION_2 GEN_LATEST // In Gen5+, Conversion 2 changes the user's type to a type that resists the last move used by the selected target. Before, it would consider the last move being successfully hit by. Additionally, Struggle is considered Normal type before Gen 5.
#define B_PP_REDUCED_BY_SPITE GEN_LATEST // In Gen4+, Spite reduces the foe's last move's PP by 4, instead of 2 to 5.
#define B_EXTRAPOLATED_MOVE_FLAGS TRUE // Adds move flags to moves that they don't officially have but would likely have if they were in the latest core series game.

View file

@ -183,6 +183,7 @@ EWRAM_DATA u16 gLastPrintedMoves[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gLastMoves[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gLastLandedMoves[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gLastHitByType[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gLastUsedMoveType[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gLastResultingMoves[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gLockedMoves[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gLastUsedMove = 0;
@ -3021,6 +3022,7 @@ static void BattleStartClearSetData(void)
gLastMoves[i] = MOVE_NONE;
gLastLandedMoves[i] = MOVE_NONE;
gLastHitByType[i] = 0;
gLastUsedMoveType[i] = 0;
gLastResultingMoves[i] = MOVE_NONE;
gLastHitBy[i] = 0xFF;
gLockedMoves[i] = MOVE_NONE;
@ -3199,6 +3201,7 @@ void SwitchInClearSetData(u32 battler)
gLastMoves[battler] = MOVE_NONE;
gLastLandedMoves[battler] = MOVE_NONE;
gLastHitByType[battler] = 0;
gLastUsedMoveType[battler] = 0;
gLastResultingMoves[battler] = MOVE_NONE;
gLastPrintedMoves[battler] = MOVE_NONE;
gLastHitBy[battler] = 0xFF;
@ -3332,6 +3335,7 @@ const u8* FaintClearSetData(u32 battler)
gLastMoves[battler] = MOVE_NONE;
gLastLandedMoves[battler] = MOVE_NONE;
gLastHitByType[battler] = 0;
gLastUsedMoveType[battler] = 0;
gLastResultingMoves[battler] = MOVE_NONE;
gLastPrintedMoves[battler] = MOVE_NONE;
gLastHitBy[battler] = 0xFF;
@ -4748,9 +4752,9 @@ u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, u32 holdEffect)
speed *= 2;
else if (ability == ABILITY_SLOW_START && gDisableStructs[battler].slowStartTimer != 0)
speed /= 2;
else if (ability == ABILITY_PROTOSYNTHESIS && (gBattleWeather & B_WEATHER_SUN || gBattleStruct->boosterEnergyActivates & (1u << battler)))
else if (ability == ABILITY_PROTOSYNTHESIS && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) && ((gBattleWeather & B_WEATHER_SUN && WEATHER_HAS_EFFECT) || gBattleStruct->boosterEnergyActivates & (1u << battler)))
speed = (GetHighestStatId(battler) == STAT_SPEED) ? (speed * 150) / 100 : speed;
else if (ability == ABILITY_QUARK_DRIVE && (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gBattleStruct->boosterEnergyActivates & (1u << battler)))
else if (ability == ABILITY_QUARK_DRIVE && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) && (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gBattleStruct->boosterEnergyActivates & (1u << battler)))
speed = (GetHighestStatId(battler) == STAT_SPEED) ? (speed * 150) / 100 : speed;
// stat stages

View file

@ -6042,12 +6042,14 @@ static void Cmd_moveend(void)
gLastMoves[gBattlerAttacker] = gChosenMove;
RecordKnownMove(gBattlerAttacker, gChosenMove);
gLastResultingMoves[gBattlerAttacker] = gCurrentMove;
gLastUsedMoveType[gBattlerAttacker] = GetMoveType(gCurrentMove);
}
}
else
{
gLastMoves[gBattlerAttacker] = MOVE_UNAVAILABLE;
gLastResultingMoves[gBattlerAttacker] = MOVE_UNAVAILABLE;
gLastUsedMoveType[gBattlerAttacker] = 0;
}
if (!(gHitMarker & HITMARKER_FAINTED(gBattlerTarget)))
@ -8932,12 +8934,15 @@ u32 GetHighestStatId(u32 battler)
for (i = STAT_DEF; i < NUM_STATS; i++)
{
u16 *statVal = &gBattleMons[battler].attack + (i - 1);
if (*statVal > highestStat)
if (*statVal > highestStat && i != STAT_SPEED)
{
highestStat = *statVal;
highestId = i;
}
}
if (gBattleMons[battler].speed > highestStat)
highestId = STAT_SPEED;
return highestId;
}
@ -12996,60 +13001,122 @@ static void Cmd_settypetorandomresistance(void)
{
CMD_ARGS(const u8 *failInstr);
if (gLastLandedMoves[gBattlerAttacker] == MOVE_NONE
|| gLastLandedMoves[gBattlerAttacker] == MOVE_UNAVAILABLE)
// Before Gen 5 Conversion 2 only worked on a move the attacker was actually hit by.
// This changed later to the last move used by the selected target.
if (B_UPDATED_CONVERSION_2 < GEN_5)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (gBattleMoveEffects[gMovesInfo[gLastLandedMoves[gBattlerAttacker]].effect].twoTurnEffect
&& gBattleMons[gLastHitBy[gBattlerAttacker]].status2 & STATUS2_MULTIPLETURNS)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_TERA)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (gLastHitByType[gBattlerAttacker] == TYPE_STELLAR || gLastHitByType[gBattlerAttacker] == TYPE_MYSTERY)
{
gBattlescriptCurrInstr = cmd->failInstr;
if (gLastLandedMoves[gBattlerAttacker] == MOVE_NONE
|| gLastLandedMoves[gBattlerAttacker] == MOVE_UNAVAILABLE)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (gBattleMoveEffects[gMovesInfo[gLastLandedMoves[gBattlerAttacker]].effect].twoTurnEffect
&& gBattleMons[gLastHitBy[gBattlerAttacker]].status2 & STATUS2_MULTIPLETURNS)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_TERA)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (gLastHitByType[gBattlerAttacker] == TYPE_STELLAR || gLastHitByType[gBattlerAttacker] == TYPE_MYSTERY)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else
{
u32 i, resistTypes = 0;
u32 hitByType = gLastHitByType[gBattlerAttacker];
for (i = 0; i < NUMBER_OF_MON_TYPES; i++) // Find all types that resist.
{
switch (GetTypeModifier(hitByType, i))
{
case UQ_4_12(0):
case UQ_4_12(0.5):
resistTypes |= 1u << i;
break;
}
}
while (resistTypes != 0)
{
i = Random() % NUMBER_OF_MON_TYPES;
if (resistTypes & 1u << i)
{
if (IS_BATTLER_OF_TYPE(gBattlerAttacker, i))
{
resistTypes &= ~(1u << i); // Type resists, but the user is already of this type.
}
else
{
SET_BATTLER_TYPE(gBattlerAttacker, i);
PREPARE_TYPE_BUFFER(gBattleTextBuff1, i);
gBattlescriptCurrInstr = cmd->nextInstr;
return;
}
}
}
gBattlescriptCurrInstr = cmd->failInstr;
}
}
else
{
u32 i, resistTypes = 0;
u32 hitByType = gLastHitByType[gBattlerAttacker];
for (i = 0; i < NUMBER_OF_MON_TYPES; i++) // Find all types that resist.
if (gLastResultingMoves[gBattlerTarget] == MOVE_NONE
|| gLastResultingMoves[gBattlerTarget] == MOVE_UNAVAILABLE
|| gLastResultingMoves[gBattlerTarget] == MOVE_STRUGGLE)
{
switch (GetTypeModifier(hitByType, i))
{
case UQ_4_12(0):
case UQ_4_12(0.5):
resistTypes |= 1u << i;
break;
}
gBattlescriptCurrInstr = cmd->failInstr;
}
while (resistTypes != 0)
else if (IsSemiInvulnerable(gBattlerTarget, gCurrentMove))
{
i = Random() % NUMBER_OF_MON_TYPES;
if (resistTypes & (1u << i))
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (gLastUsedMoveType[gBattlerTarget] == TYPE_NONE || gLastUsedMoveType[gBattlerTarget] == TYPE_STELLAR || gLastUsedMoveType[gBattlerTarget] == TYPE_MYSTERY)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_TERA)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else
{
u32 i, resistTypes = 0;
for (i = 0; i < NUMBER_OF_MON_TYPES; i++) // Find all types that resist.
{
if (IS_BATTLER_OF_TYPE(gBattlerAttacker, i))
switch (GetTypeModifier(gLastUsedMoveType[gBattlerTarget], i))
{
resistTypes &= ~(1u << i); // Type resists, but the user is already of this type.
}
else
{
SET_BATTLER_TYPE(gBattlerAttacker, i);
PREPARE_TYPE_BUFFER(gBattleTextBuff1, i);
gBattlescriptCurrInstr = cmd->nextInstr;
return;
case UQ_4_12(0):
case UQ_4_12(0.5):
resistTypes |= 1u << i;
break;
}
}
}
gBattlescriptCurrInstr = cmd->failInstr;
while (resistTypes != 0)
{
i = Random() % NUMBER_OF_MON_TYPES;
if (resistTypes & 1u << i)
{
if (IS_BATTLER_OF_TYPE(gBattlerAttacker, i))
{
resistTypes &= ~(1u << i); // Type resists, but the user is already of this type.
}
else
{
SET_BATTLER_TYPE(gBattlerAttacker, i);
PREPARE_TYPE_BUFFER(gBattleTextBuff1, i);
gBattlescriptCurrInstr = cmd->nextInstr;
return;
}
}
}
gBattlescriptCurrInstr = cmd->failInstr;
}
}
}

View file

@ -6350,7 +6350,10 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
}
break;
case ABILITY_PROTOSYNTHESIS:
if (!gDisableStructs[battler].weatherAbilityDone && IsBattlerWeatherAffected(battler, B_WEATHER_SUN))
if (!gDisableStructs[battler].weatherAbilityDone
&& (gBattleWeather & B_WEATHER_SUN) && WEATHER_HAS_EFFECT
&& !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED)
&& !(gBattleStruct->boosterEnergyActivates & (1u << battler)))
{
gDisableStructs[battler].weatherAbilityDone = TRUE;
PREPARE_STAT_BUFFER(gBattleTextBuff1, GetHighestStatId(battler));
@ -6376,7 +6379,10 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
}
break;
case ABILITY_QUARK_DRIVE:
if (!gDisableStructs[battler].terrainAbilityDone && IsBattlerTerrainAffected(battler, STATUS_FIELD_ELECTRIC_TERRAIN))
if (!gDisableStructs[battler].terrainAbilityDone
&& gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN
&& !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED)
&& !(gBattleStruct->boosterEnergyActivates & (1u << battler)))
{
gDisableStructs[battler].terrainAbilityDone = TRUE;
PREPARE_STAT_BUFFER(gBattleTextBuff1, GetHighestStatId(battler));
@ -7617,7 +7623,8 @@ u8 ItemBattleEffects(u8 caseID, u32 battler, bool32 moveTurn)
break;
case HOLD_EFFECT_BOOSTER_ENERGY:
if (!(gBattleStruct->boosterEnergyActivates & (1u << battler))
&& (((GetBattlerAbility(battler) == ABILITY_PROTOSYNTHESIS) && !(gBattleWeather & B_WEATHER_SUN))
&& !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED)
&& (((GetBattlerAbility(battler) == ABILITY_PROTOSYNTHESIS) && !((gBattleWeather & B_WEATHER_SUN) && WEATHER_HAS_EFFECT))
|| ((GetBattlerAbility(battler) == ABILITY_QUARK_DRIVE) && !(gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN))))
{
PREPARE_STAT_BUFFER(gBattleTextBuff1, GetHighestStatId(battler));
@ -7884,7 +7891,8 @@ u8 ItemBattleEffects(u8 caseID, u32 battler, bool32 moveTurn)
break;
case HOLD_EFFECT_BOOSTER_ENERGY:
if (!(gBattleStruct->boosterEnergyActivates & (1u << battler))
&& (((GetBattlerAbility(battler) == ABILITY_PROTOSYNTHESIS) && !(gBattleWeather & B_WEATHER_SUN))
&& !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED)
&& (((GetBattlerAbility(battler) == ABILITY_PROTOSYNTHESIS) && !((gBattleWeather & B_WEATHER_SUN) && WEATHER_HAS_EFFECT))
|| ((GetBattlerAbility(battler) == ABILITY_QUARK_DRIVE) && !(gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN))))
{
PREPARE_STAT_BUFFER(gBattleTextBuff1, GetHighestStatId(battler));
@ -9303,8 +9311,9 @@ static inline u32 CalcMoveBasePowerAfterModifiers(u32 move, u32 battlerAtk, u32
case ABILITY_PROTOSYNTHESIS:
{
u8 atkHighestStat = GetHighestStatId(battlerAtk);
if ((weather & B_WEATHER_SUN || gBattleStruct->boosterEnergyActivates & (1u << battlerAtk))
&& ((IS_MOVE_PHYSICAL(move) && atkHighestStat == STAT_ATK) || (IS_MOVE_SPECIAL(move) && atkHighestStat == STAT_SPATK)))
if (((weather & B_WEATHER_SUN && WEATHER_HAS_EFFECT) || gBattleStruct->boosterEnergyActivates & (1u << battlerAtk))
&& ((IS_MOVE_PHYSICAL(move) && atkHighestStat == STAT_ATK) || (IS_MOVE_SPECIAL(move) && atkHighestStat == STAT_SPATK))
&& !(gBattleMons[battlerAtk].status2 & STATUS2_TRANSFORMED))
modifier = uq4_12_multiply(modifier, UQ_4_12(1.3));
}
break;
@ -9312,16 +9321,17 @@ static inline u32 CalcMoveBasePowerAfterModifiers(u32 move, u32 battlerAtk, u32
{
u8 atkHighestStat = GetHighestStatId(battlerAtk);
if ((gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gBattleStruct->boosterEnergyActivates & (1u << battlerAtk))
&& ((IS_MOVE_PHYSICAL(move) && atkHighestStat == STAT_ATK) || (IS_MOVE_SPECIAL(move) && atkHighestStat == STAT_SPATK)))
&& ((IS_MOVE_PHYSICAL(move) && atkHighestStat == STAT_ATK) || (IS_MOVE_SPECIAL(move) && atkHighestStat == STAT_SPATK))
&& !(gBattleMons[battlerAtk].status2 & STATUS2_TRANSFORMED))
modifier = uq4_12_multiply(modifier, UQ_4_12(1.3));
}
break;
case ABILITY_ORICHALCUM_PULSE:
if (weather & B_WEATHER_SUN)
if (weather & B_WEATHER_SUN && WEATHER_HAS_EFFECT && IS_MOVE_PHYSICAL(move))
modifier = uq4_12_multiply(modifier, UQ_4_12(1.3));
break;
case ABILITY_HADRON_ENGINE:
if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN)
if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN && IS_MOVE_SPECIAL(move))
modifier = uq4_12_multiply(modifier, UQ_4_12(1.3));
break;
case ABILITY_SHARPNESS:
@ -9381,8 +9391,9 @@ static inline u32 CalcMoveBasePowerAfterModifiers(u32 move, u32 battlerAtk, u32
case ABILITY_PROTOSYNTHESIS:
{
u8 defHighestStat = GetHighestStatId(battlerDef);
if ((weather & B_WEATHER_SUN || gBattleStruct->boosterEnergyActivates & (1u << battlerDef))
&& ((IS_MOVE_PHYSICAL(move) && defHighestStat == STAT_DEF) || (IS_MOVE_SPECIAL(move) && defHighestStat == STAT_SPDEF)))
if (((weather & B_WEATHER_SUN && WEATHER_HAS_EFFECT) || gBattleStruct->boosterEnergyActivates & (1u << battlerDef))
&& ((IS_MOVE_PHYSICAL(move) && defHighestStat == STAT_DEF) || (IS_MOVE_SPECIAL(move) && defHighestStat == STAT_SPDEF))
&& !(gBattleMons[battlerDef].status2 & STATUS2_TRANSFORMED))
modifier = uq4_12_multiply(modifier, UQ_4_12(0.7));
}
break;
@ -9390,7 +9401,8 @@ static inline u32 CalcMoveBasePowerAfterModifiers(u32 move, u32 battlerAtk, u32
{
u8 defHighestStat = GetHighestStatId(battlerDef);
if ((gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gBattleStruct->boosterEnergyActivates & (1u << battlerDef))
&& ((IS_MOVE_PHYSICAL(move) && defHighestStat == STAT_DEF) || (IS_MOVE_SPECIAL(move) && defHighestStat == STAT_SPDEF)))
&& ((IS_MOVE_PHYSICAL(move) && defHighestStat == STAT_DEF) || (IS_MOVE_SPECIAL(move) && defHighestStat == STAT_SPDEF))
&& !(gBattleMons[battlerDef].status2 & STATUS2_TRANSFORMED))
modifier = uq4_12_multiply(modifier, UQ_4_12(0.7));
}
break;

View file

@ -4505,7 +4505,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
.type = TYPE_NORMAL,
.accuracy = 0,
.pp = 30,
.target = MOVE_TARGET_USER,
.target = B_UPDATED_MOVE_DATA >= GEN_5 ? MOVE_TARGET_SELECTED : MOVE_TARGET_USER,
.priority = 0,
.category = DAMAGE_CATEGORY_STATUS,
.zMove = { .effect = Z_EFFECT_RECOVER_HP },

View file

@ -100,6 +100,125 @@ SINGLE_BATTLE_TEST("Protosynthesis activates on switch-in")
}
}
TO_DO_BATTLE_TEST("Protosynthesis activates in sun before Booster Energy");
TO_DO_BATTLE_TEST("Protosynthesis activates even if the Pokémon is holding an Utility Umbrella");
TO_DO_BATTLE_TEST("Protosynthesis doesn't activate if Cloud Nine/Air Lock is on the field");
SINGLE_BATTLE_TEST("Protosynthesis boosts Attack 1st in case of a stat tie")
{
GIVEN {
PLAYER(SPECIES_GREAT_TUSK) { Ability(ABILITY_PROTOSYNTHESIS); Attack(5); Defense(5); SpAttack(5); SpDefense(5); Speed(5); }
OPPONENT(SPECIES_GROUDON) { Ability(ABILITY_DROUGHT); Speed(5); }
} WHEN {
TURN { }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_DROUGHT);
ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS);
MESSAGE("Great Tusk's Attack was heightened!");
}
}
SINGLE_BATTLE_TEST("Protosynthesis boosts Defense 2nd in case of a stat tie")
{
GIVEN {
PLAYER(SPECIES_GREAT_TUSK) { Ability(ABILITY_PROTOSYNTHESIS); Attack(4); Defense(5); SpAttack(5); SpDefense(5); Speed(5); }
OPPONENT(SPECIES_GROUDON) { Ability(ABILITY_DROUGHT); Speed(5); }
} WHEN {
TURN { }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_DROUGHT);
ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS);
MESSAGE("Great Tusk's Defense was heightened!");
}
}
SINGLE_BATTLE_TEST("Protosynthesis boosts Special Attack 3rd in case of a stat tie")
{
GIVEN {
PLAYER(SPECIES_GREAT_TUSK) { Ability(ABILITY_PROTOSYNTHESIS); Attack(4); Defense(4); SpAttack(5); SpDefense(5); Speed(5); }
OPPONENT(SPECIES_GROUDON) { Ability(ABILITY_DROUGHT); Speed(5); }
} WHEN {
TURN { }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_DROUGHT);
ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS);
MESSAGE("Great Tusk's Sp. Atk was heightened!");
}
}
SINGLE_BATTLE_TEST("Protosynthesis boosts Special Defense 4th in case of a stat tie")
{
GIVEN {
PLAYER(SPECIES_GREAT_TUSK) { Ability(ABILITY_PROTOSYNTHESIS); Attack(4); Defense(4); SpAttack(4); SpDefense(5); Speed(5); }
OPPONENT(SPECIES_GROUDON) { Ability(ABILITY_DROUGHT); Speed(5); }
} WHEN {
TURN { }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_DROUGHT);
ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS);
MESSAGE("Great Tusk's Sp. Def was heightened!");
}
}
SINGLE_BATTLE_TEST("Protosynthesis activates in Sun before Booster Energy")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_GREAT_TUSK) { Ability(ABILITY_PROTOSYNTHESIS); Item(ITEM_BOOSTER_ENERGY); }
OPPONENT(SPECIES_NINETALES) { Ability(ABILITY_DROUGHT); }
} WHEN {
TURN { SWITCH(player, 1); }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_DROUGHT);
ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS);
} THEN {
EXPECT_EQ(player->item, ITEM_BOOSTER_ENERGY);
}
}
SINGLE_BATTLE_TEST("Protosynthesis doesn't activate for a transformed battler")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_GREAT_TUSK) { Ability(ABILITY_PROTOSYNTHESIS); Item(ITEM_BOOSTER_ENERGY); }
OPPONENT(SPECIES_NINETALES) { Ability(ABILITY_DROUGHT); Item(ITEM_BOOSTER_ENERGY); }
} WHEN {
TURN { SWITCH(player, 1); MOVE(opponent, MOVE_TRANSFORM); }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_DROUGHT);
ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS);
ANIMATION(ANIM_TYPE_MOVE, MOVE_TRANSFORM, opponent);
NOT ABILITY_POPUP(opponent, ABILITY_PROTOSYNTHESIS);
} THEN {
EXPECT_EQ(player->item, ITEM_BOOSTER_ENERGY);
EXPECT_EQ(opponent->item, ITEM_BOOSTER_ENERGY);
EXPECT_EQ(opponent->ability, ABILITY_PROTOSYNTHESIS);
}
}
SINGLE_BATTLE_TEST("Protosynthesis activates even if the Pokémon is holding an Utility Umbrella")
{
GIVEN {
PLAYER(SPECIES_GREAT_TUSK) { Ability(ABILITY_PROTOSYNTHESIS); Item(ITEM_UTILITY_UMBRELLA); }
OPPONENT(SPECIES_NINETALES) { Ability(ABILITY_DROUGHT); }
} WHEN {
TURN { }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_DROUGHT);
ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS);
}
}
SINGLE_BATTLE_TEST("Protosynthesis doesn't activate if Cloud Nine/Air Lock is on the field")
{
u32 species, ability;
PARAMETRIZE { species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; }
PARAMETRIZE { species = SPECIES_GOLDUCK; ability = ABILITY_CLOUD_NINE; }
GIVEN {
PLAYER(SPECIES_GREAT_TUSK) { Ability(ABILITY_PROTOSYNTHESIS); }
OPPONENT(species) { Ability(ability); }
} WHEN {
TURN { MOVE(opponent, MOVE_SUNNY_DAY); }
} SCENE {
ABILITY_POPUP(opponent, ability);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, opponent);
NOT ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS);
}
}

View file

@ -100,3 +100,109 @@ SINGLE_BATTLE_TEST("Quark Drive activates on switch-in")
MESSAGE("Iron Moth's Sp. Atk was heightened!");
}
}
SINGLE_BATTLE_TEST("Quark Drive activates on Electric Terrain even if not grounded")
{
GIVEN {
ASSUME(gSpeciesInfo[SPECIES_IRON_JUGULIS].types[0] == TYPE_FLYING || gSpeciesInfo[SPECIES_IRON_JUGULIS].types[1] == TYPE_FLYING);
PLAYER(SPECIES_IRON_JUGULIS) { Ability(ABILITY_QUARK_DRIVE); }
OPPONENT(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); };
} WHEN {
TURN { }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_ELECTRIC_SURGE);
ABILITY_POPUP(player, ABILITY_QUARK_DRIVE);
}
}
SINGLE_BATTLE_TEST("Quark Drive boosts Attack 1st in case of a stat tie")
{
GIVEN {
PLAYER(SPECIES_IRON_TREADS) { Ability(ABILITY_QUARK_DRIVE); Attack(5); Defense(5); SpAttack(5); SpDefense(5); Speed(5); }
OPPONENT(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); Speed(5); }
} WHEN {
TURN { }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_ELECTRIC_SURGE);
ABILITY_POPUP(player, ABILITY_QUARK_DRIVE);
MESSAGE("Iron Treads's Attack was heightened!");
}
}
SINGLE_BATTLE_TEST("Quark Drive boosts Defense 2nd in case of a stat tie")
{
GIVEN {
PLAYER(SPECIES_IRON_TREADS) { Ability(ABILITY_QUARK_DRIVE); Attack(4); Defense(5); SpAttack(5); SpDefense(5); Speed(5); }
OPPONENT(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); Speed(5); }
} WHEN {
TURN { }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_ELECTRIC_SURGE);
ABILITY_POPUP(player, ABILITY_QUARK_DRIVE);
MESSAGE("Iron Treads's Defense was heightened!");
}
}
SINGLE_BATTLE_TEST("Quark Drive boosts Special Attack 3rd in case of a stat tie")
{
GIVEN {
PLAYER(SPECIES_IRON_TREADS) { Ability(ABILITY_QUARK_DRIVE); Attack(4); Defense(4); SpAttack(5); SpDefense(5); Speed(5); }
OPPONENT(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); Speed(5); }
} WHEN {
TURN { }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_ELECTRIC_SURGE);
ABILITY_POPUP(player, ABILITY_QUARK_DRIVE);
MESSAGE("Iron Treads's Sp. Atk was heightened!");
}
}
SINGLE_BATTLE_TEST("Quark Drive boosts Special Defense 4th in case of a stat tie")
{
GIVEN {
PLAYER(SPECIES_IRON_TREADS) { Ability(ABILITY_QUARK_DRIVE); Attack(4); Defense(4); SpAttack(4); SpDefense(5); Speed(5); }
OPPONENT(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); Speed(5); }
} WHEN {
TURN { }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_ELECTRIC_SURGE);
ABILITY_POPUP(player, ABILITY_QUARK_DRIVE);
MESSAGE("Iron Treads's Sp. Def was heightened!");
}
}
SINGLE_BATTLE_TEST("Quark Drive activates in Electric Terrain before Booster Energy")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_IRON_TREADS) { Ability(ABILITY_QUARK_DRIVE); Item(ITEM_BOOSTER_ENERGY); }
OPPONENT(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); }
} WHEN {
TURN { SWITCH(player, 1); }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_ELECTRIC_SURGE);
ABILITY_POPUP(player, ABILITY_QUARK_DRIVE);
} THEN {
EXPECT_EQ(player->item, ITEM_BOOSTER_ENERGY);
}
}
SINGLE_BATTLE_TEST("Quark Drive doesn't activate for a transformed battler")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_IRON_TREADS) { Ability(ABILITY_QUARK_DRIVE); Item(ITEM_BOOSTER_ENERGY); }
OPPONENT(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); Item(ITEM_BOOSTER_ENERGY); }
} WHEN {
TURN { SWITCH(player, 1); MOVE(opponent, MOVE_TRANSFORM); }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_ELECTRIC_SURGE);
ABILITY_POPUP(player, ABILITY_QUARK_DRIVE);
ANIMATION(ANIM_TYPE_MOVE, MOVE_TRANSFORM, opponent);
NOT ABILITY_POPUP(opponent, ABILITY_QUARK_DRIVE);
} THEN {
EXPECT_EQ(player->item, ITEM_BOOSTER_ENERGY);
EXPECT_EQ(opponent->item, ITEM_BOOSTER_ENERGY);
EXPECT_EQ(opponent->ability, ABILITY_QUARK_DRIVE);
}
}

View file

@ -509,6 +509,7 @@ SINGLE_BATTLE_TEST("(TERA) Revelation Dance uses a Stellar-type Pokemon's base t
}
}
#if B_UPDATED_CONVERSION_2 < GEN_5
SINGLE_BATTLE_TEST("(TERA) Conversion2 fails if last hit by a Stellar-type move")
{
GIVEN {
@ -526,6 +527,7 @@ SINGLE_BATTLE_TEST("(TERA) Conversion2 fails if last hit by a Stellar-type move"
MESSAGE("But it failed!");
}
}
#endif
SINGLE_BATTLE_TEST("(TERA) Roost does not remove Flying-type ground immunity when Terastallized into the Stellar type")
{

View file

@ -1,14 +1,207 @@
#include "global.h"
#include "test/battle.h"
TO_DO_BATTLE_TEST("Conversion 2 randomly changes the type of the user to a type that resists the last move that hit the user (Gen 3-4)");
TO_DO_BATTLE_TEST("Conversion 2 randomly changes the type of the user to a type that resists the last move used by the target (Gen 5+)");
TO_DO_BATTLE_TEST("Conversion 2's type change considers the type of moves called by other moves");
TO_DO_BATTLE_TEST("Conversion 2's type change considers dynamic type moves"); // Eg. Weather Ball
TO_DO_BATTLE_TEST("Conversion 2's type change considers move types changed by Normalize and Electrify");
TO_DO_BATTLE_TEST("Conversion 2's type change considers move types changed by Normalize");
TO_DO_BATTLE_TEST("Conversion 2's type change considers Struggle to be Normal type (Gen 3-4)");
TO_DO_BATTLE_TEST("Conversion 2 fails if the move used is of typeless damage (Gen 5+)");
TO_DO_BATTLE_TEST("Conversion 2's type change considers status moves (Gen 5+)");
TO_DO_BATTLE_TEST("Conversion 2's type change considers Inverse Battles");
TO_DO_BATTLE_TEST("Conversion 2 fails if the move used is Stellar Type");
#if B_UPDATED_CONVERSION_2 < GEN_5
SINGLE_BATTLE_TEST("Conversion 2 randomly changes the type of the user to a type that resists the last move that hit the user (Gen 3-4)")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_OMINOUS_WIND); MOVE(opponent, MOVE_CONVERSION_2); }
} SCENE {
// turn 1
MESSAGE("Wobbuffet used Ominous Wind!");
// turn 1
ONE_OF {
MESSAGE("Foe Wobbuffet transformed into the Normal type!");
MESSAGE("Foe Wobbuffet transformed into the Dark type!");
}
}
}
SINGLE_BATTLE_TEST("Conversion 2's type change considers Struggle to be Normal type (Gen 3-4)")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_STRUGGLE); }
TURN { MOVE(player, MOVE_CONVERSION_2); }
} SCENE {
// turn 1
MESSAGE("Foe Wobbuffet used Struggle!");
// turn 2
ONE_OF {
MESSAGE("Wobbuffet transformed into the Steel type!");
MESSAGE("Wobbuffet transformed into the Rock type!");
MESSAGE("Wobbuffet transformed into the Ghost type!");
}
}
}
#endif
#if B_UPDATED_CONVERSION_2 >= GEN_5
SINGLE_BATTLE_TEST("Conversion 2 randomly changes the type of the user to a type that resists the last used target's move (Gen 5+)")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_OMINOUS_WIND); MOVE(opponent, MOVE_CONVERSION_2); }
} SCENE {
// turn 1
MESSAGE("Wobbuffet used Ominous Wind!");
// turn 1
ONE_OF {
MESSAGE("Foe Wobbuffet transformed into the Normal type!");
MESSAGE("Foe Wobbuffet transformed into the Dark type!");
}
}
}
SINGLE_BATTLE_TEST("Conversion 2's type change considers status moves (Gen 5+)")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_CURSE); }
TURN { MOVE(player, MOVE_CONVERSION_2); }
} SCENE {
// turn 1
MESSAGE("Foe Wobbuffet used Curse!");
// turn 2
ONE_OF {
MESSAGE("Wobbuffet transformed into the Normal type!");
MESSAGE("Wobbuffet transformed into the Dark type!");
}
}
}
SINGLE_BATTLE_TEST("Conversion 2's type change considers the type of moves called by other moves")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_OMINOUS_WIND); MOVE(opponent, MOVE_MIRROR_MOVE); }
TURN { MOVE(player, MOVE_CONVERSION_2); }
} SCENE {
// turn 1
MESSAGE("Foe Wobbuffet used Mirror Move!");
// turn 2
ONE_OF {
MESSAGE("Wobbuffet transformed into the Normal type!");
MESSAGE("Wobbuffet transformed into the Dark type!");
}
}
}
SINGLE_BATTLE_TEST("Conversion 2's type change considers dynamic type moves")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_HAIL); MOVE(opponent, MOVE_WEATHER_BALL); }
TURN { MOVE(player, MOVE_CONVERSION_2); }
} SCENE {
// turn 1
MESSAGE("Foe Wobbuffet used Weather Ball!");
// turn 2
ONE_OF {
MESSAGE("Wobbuffet transformed into the Steel type!");
MESSAGE("Wobbuffet transformed into the Fire type!");
MESSAGE("Wobbuffet transformed into the Water type!");
MESSAGE("Wobbuffet transformed into the Ice type!");
}
}
}
SINGLE_BATTLE_TEST("Conversion 2's type change considers move types changed by Normalize and Electrify")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_NORMALIZE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_ELECTRIFY); MOVE(opponent, MOVE_POUND); }
TURN { MOVE(player, MOVE_CONVERSION_2); }
TURN { MOVE(player, MOVE_WATER_GUN); MOVE(opponent, MOVE_CONVERSION_2); }
} SCENE {
// turn 1
MESSAGE("Wobbuffet used Electrify!");
MESSAGE("Foe Wobbuffet used Pound!");
// turn 2
ONE_OF {
MESSAGE("Wobbuffet transformed into the Ground type!");
MESSAGE("Wobbuffet transformed into the Dragon type!");
MESSAGE("Wobbuffet transformed into the Grass type!");
MESSAGE("Wobbuffet transformed into the Electric type!");
}
// turn 3
MESSAGE("Wobbuffet used Water Gun!");
ONE_OF {
MESSAGE("Foe Wobbuffet transformed into the Steel type!");
MESSAGE("Foe Wobbuffet transformed into the Rock type!");
MESSAGE("Foe Wobbuffet transformed into the Ghost type!");
}
}
}
SINGLE_BATTLE_TEST("Conversion 2's type change fails targeting Struggle (Gen 5+)")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_STRUGGLE); }
TURN { MOVE(player, MOVE_CONVERSION_2); }
} SCENE {
// turn 1
MESSAGE("Foe Wobbuffet used Struggle!");
// turn 2
MESSAGE("Wobbuffet used Conversion 2!");
MESSAGE("But it failed!");
}
}
SINGLE_BATTLE_TEST("Conversion 2 fails if the move used is of typeless damage (Gen 5+)")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_ENTEI);
} WHEN {
TURN { MOVE(opponent, MOVE_BURN_UP); }
TURN { MOVE(opponent, MOVE_REVELATION_DANCE); }
TURN { MOVE(player, MOVE_CONVERSION_2); }
} SCENE {
// turn 1
MESSAGE("Foe Entei used Burn Up!");
// turn 2
MESSAGE("Foe Entei used Revelation Dance!");
// turn 3
MESSAGE("Wobbuffet used Conversion 2!");
MESSAGE("But it failed!");
}
}
#endif
SINGLE_BATTLE_TEST("Conversion 2 fails if the targeted move is Stellar Type")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_STELLAR); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_TERA_BLAST, gimmick: GIMMICK_TERA); MOVE(opponent, MOVE_CONVERSION_2); }
} SCENE {
// turn 1
MESSAGE("Wobbuffet used Tera Blast!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_TERA_BLAST, player);
// turn 1
MESSAGE("Foe Wobbuffet used Conversion 2!");
MESSAGE("But it failed!");
}
}