Merge branch 'rh-hideout:master' into master

This commit is contained in:
RoamerX 2026-02-23 13:06:57 +08:00 committed by GitHub
commit ff4163d1f6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 250 additions and 10 deletions

View File

@ -651,6 +651,15 @@
"contributions": [
"bug"
]
},
{
"login": "KnightGallade",
"name": "KnightGallade",
"avatar_url": "https://avatars.githubusercontent.com/u/189022270?v=4",
"profile": "https://github.com/KnightGallade",
"contributions": [
"bug"
]
}
],
"contributorsPerLine": 7,

View File

@ -93,6 +93,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<td align="center" valign="top" width="14.28%"><a href="https://github.com/PacFire"><img src="https://avatars.githubusercontent.com/u/108960850?v=4?s=100" width="100px;" alt="PacFire"/><br /><sub><b>PacFire</b></sub></a><br /><a href="#design-PacFire" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ChrispyChris27"><img src="https://avatars.githubusercontent.com/u/173648816?v=4?s=100" width="100px;" alt="ChrispyChris27"/><br /><sub><b>ChrispyChris27</b></sub></a><br /><a href="https://github.com/rh-hideout/pokeemerald-expansion/commits?author=ChrispyChris27" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LogicalLlama"><img src="https://avatars.githubusercontent.com/u/248230900?v=4?s=100" width="100px;" alt="LogicalLlama"/><br /><sub><b>LogicalLlama</b></sub></a><br /><a href="https://github.com/rh-hideout/pokeemerald-expansion/issues?q=author%3ALogicalLlama" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/KnightGallade"><img src="https://avatars.githubusercontent.com/u/189022270?v=4?s=100" width="100px;" alt="KnightGallade"/><br /><sub><b>KnightGallade</b></sub></a><br /><a href="https://github.com/rh-hideout/pokeemerald-expansion/issues?q=author%3AKnightGallade" title="Bug reports">🐛</a></td>
</tr>
</tbody>
<tfoot>

View File

@ -1652,6 +1652,7 @@ BattleScript_ToxicThreadTryPsn::
BattleScript_EffectVenomDrench::
attackcanceler
jumpifsubstituteblocks BattleScript_ButItFailed
jumpifstatus BS_TARGET, STATUS1_PSN_ANY, BattleScript_EffectVenomDrenchCanBeUsed
goto BattleScript_ButItFailed
BattleScript_EffectVenomDrenchCanBeUsed:
@ -4319,6 +4320,7 @@ BattleScript_EffectWaterSport::
BattleScript_EffectTickle::
attackcanceler
jumpifsubstituteblocks BattleScript_ButItFailed
jumpifstat BS_TARGET, CMP_GREATER_THAN, STAT_ATK, MIN_STAT_STAGE, BattleScript_TickleDoMoveAnim
jumpifstat BS_TARGET, CMP_EQUAL, STAT_DEF, MIN_STAT_STAGE, BattleScript_CantLowerMultipleStats
BattleScript_TickleDoMoveAnim::

View File

@ -137,6 +137,8 @@ enum FormChanges
FORM_CHANGE_OVERWORLD_WEATHER,
// Form change that activates when the Pokémon is deposited into the PC or Daycare.
FORM_CHANGE_DEPOSIT,
// Form change for Minior, which appears unchanged when encountered in the wild
FORM_CHANGE_BEGIN_WILD_ENCOUNTER,
};
#endif // GUARD_CONSTANTS_FORM_CHANGE_TYPES_H

View File

@ -582,7 +582,11 @@ static void CB2_InitBattleInternal(void)
TryFormChange(i, B_SIDE_PLAYER, FORM_CHANGE_BEGIN_BATTLE);
TryFormChange(i, B_SIDE_OPPONENT, FORM_CHANGE_BEGIN_BATTLE);
}
if (!(gBattleTypeFlags & BATTLE_TYPE_TRAINER))
{
TryFormChange(0, B_SIDE_OPPONENT, FORM_CHANGE_BEGIN_WILD_ENCOUNTER);
TryFormChange(1, B_SIDE_OPPONENT, FORM_CHANGE_BEGIN_WILD_ENCOUNTER);// Only tries to change the first two opposing slots, assuming these are the only ones occupied in a wild battle.
}
if (TESTING)
{
gPlayerPartyCount = CalculatePartyCount(gPlayerParty);

View File

@ -5538,6 +5538,7 @@ static void PlayAnimation(u32 battler, u8 animId, const u16 *argPtr, const u8 *n
|| animId == B_ANIM_FORM_CHANGE
|| animId == B_ANIM_SUBSTITUTE_FADE
|| animId == B_ANIM_PRIMAL_REVERSION
|| animId == B_ANIM_POWER_CONSTRUCT
|| animId == B_ANIM_ULTRA_BURST
|| animId == B_ANIM_TERA_CHARGE
|| animId == B_ANIM_TERA_ACTIVATE)
@ -16560,6 +16561,12 @@ void BS_JumpIfAbilityCantBeReactivated(void)
u32 battler = GetBattlerForBattleScript(cmd->battler);
u32 ability = gBattleMons[battler].ability;
if (GetBattlerHoldEffectIgnoreAbility(battler) == HOLD_EFFECT_ABILITY_SHIELD)
{
gBattlescriptCurrInstr = cmd->jumpInstr;
return;
}
switch (ability)
{
case ABILITY_IMPOSTER:

View File

@ -163,15 +163,19 @@ uq4_12_t GetTeraMultiplier(struct DamageContext *ctx)
else
return UQ_4_12(2.0);
}
// Base or Tera type only.
else if ((ctx->moveType == teraType && !IS_BATTLER_OF_BASE_TYPE(ctx->battlerAtk, ctx->moveType))
|| (ctx->moveType != teraType && IS_BATTLER_OF_BASE_TYPE(ctx->battlerAtk, ctx->moveType)))
// Tera type only (Adaptability applies).
else if (ctx->moveType == teraType && !IS_BATTLER_OF_BASE_TYPE(ctx->battlerAtk, ctx->moveType))
{
if (ctx->abilityAtk == ABILITY_ADAPTABILITY)
return UQ_4_12(2.0);
else
return UQ_4_12(1.5);
}
// Base type only (Adaptability does not apply while Terastallized).
else if (ctx->moveType != teraType && IS_BATTLER_OF_BASE_TYPE(ctx->battlerAtk, ctx->moveType))
{
return UQ_4_12(1.5);
}
// Neither base or Tera type.
else
{

View File

@ -11215,11 +11215,21 @@ static u32 GetAssistMove(void)
u32 move = MOVE_NONE;
s32 chooseableMovesNo = 0;
struct Pokemon *party;
u8 battlerByPartyId[PARTY_SIZE];
u16 *validMoves = Alloc(sizeof(u16) * PARTY_SIZE * MAX_MON_MOVES);
if (validMoves != NULL)
{
party = GetBattlerParty(gBattlerAttacker);
for (u32 i = 0; i < PARTY_SIZE; i++)
battlerByPartyId[i] = MAX_BATTLERS_COUNT;
for (u32 battler = 0; battler < gBattlersCount; battler++)
{
if (GetBattlerSide(battler) != GetBattlerSide(gBattlerAttacker))
continue;
if (gBattlerPartyIndexes[battler] < PARTY_SIZE)
battlerByPartyId[gBattlerPartyIndexes[battler]] = battler;
}
for (u32 monId = 0; monId < PARTY_SIZE; monId++)
{
@ -11232,7 +11242,12 @@ static u32 GetAssistMove(void)
for (u32 moveId = 0; moveId < MAX_MON_MOVES; moveId++)
{
u16 move = GetMonData(&party[monId], MON_DATA_MOVE1 + moveId);
u16 move;
if (battlerByPartyId[monId] != MAX_BATTLERS_COUNT)
move = gBattleMons[battlerByPartyId[monId]].moves[moveId];
else
move = GetMonData(&party[monId], MON_DATA_MOVE1 + moveId);
if (IsMoveAssistBanned(move))
continue;

View File

@ -1316,10 +1316,10 @@ static const struct FormChange sSilvallyFormChangeTable[] =
{FORM_CHANGE_TERMINATOR},
};
#endif //P_FAMILY_TYPE_NULL
#if P_FAMILY_MINIOR
static const struct FormChange sMiniorRedFormChangeTable[] =
{
{FORM_CHANGE_BEGIN_WILD_ENCOUNTER, SPECIES_MINIOR_METEOR_RED},
{FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_RED},
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_METEOR_RED, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_RED, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},
@ -1330,6 +1330,7 @@ static const struct FormChange sMiniorRedFormChangeTable[] =
};
static const struct FormChange sMiniorBlueFormChangeTable[] =
{
{FORM_CHANGE_BEGIN_WILD_ENCOUNTER, SPECIES_MINIOR_METEOR_BLUE},
{FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_BLUE},
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_METEOR_BLUE, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_BLUE, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},
@ -1340,6 +1341,7 @@ static const struct FormChange sMiniorBlueFormChangeTable[] =
};
static const struct FormChange sMiniorGreenFormChangeTable[] =
{
{FORM_CHANGE_BEGIN_WILD_ENCOUNTER, SPECIES_MINIOR_METEOR_GREEN},
{FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_GREEN},
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_METEOR_GREEN, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_GREEN, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},
@ -1350,6 +1352,7 @@ static const struct FormChange sMiniorGreenFormChangeTable[] =
};
static const struct FormChange sMiniorIndigoFormChangeTable[] =
{
{FORM_CHANGE_BEGIN_WILD_ENCOUNTER, SPECIES_MINIOR_METEOR_INDIGO},
{FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_INDIGO},
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_METEOR_INDIGO, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_INDIGO, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},
@ -1360,6 +1363,7 @@ static const struct FormChange sMiniorIndigoFormChangeTable[] =
};
static const struct FormChange sMiniorOrangeFormChangeTable[] =
{
{FORM_CHANGE_BEGIN_WILD_ENCOUNTER, SPECIES_MINIOR_METEOR_ORANGE},
{FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_ORANGE},
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_METEOR_ORANGE, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_ORANGE, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},
@ -1370,6 +1374,7 @@ static const struct FormChange sMiniorOrangeFormChangeTable[] =
};
static const struct FormChange sMiniorVioletFormChangeTable[] =
{
{FORM_CHANGE_BEGIN_WILD_ENCOUNTER, SPECIES_MINIOR_METEOR_VIOLET},
{FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_VIOLET},
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_METEOR_VIOLET, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_VIOLET, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},
@ -1379,6 +1384,7 @@ static const struct FormChange sMiniorVioletFormChangeTable[] =
{FORM_CHANGE_TERMINATOR},
};
static const struct FormChange sMiniorYellowFormChangeTable[] = {
{FORM_CHANGE_BEGIN_WILD_ENCOUNTER, SPECIES_MINIOR_METEOR_YELLOW},
{FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_YELLOW},
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_METEOR_YELLOW, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
{FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_YELLOW, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},

View File

@ -50,6 +50,9 @@ void FakeRtc_TickTimeForward(void)
void FakeRtc_AdvanceTimeBy(u32 days, u32 hours, u32 minutes, u32 seconds)
{
if (!OW_USE_FAKE_RTC)
return;
struct DateTime dateTime;
struct SiiRtcInfo *rtc = FakeRtc_GetCurrentTime();
@ -63,6 +66,9 @@ void FakeRtc_AdvanceTimeBy(u32 days, u32 hours, u32 minutes, u32 seconds)
void FakeRtc_ForwardTimeTo(u32 hour, u32 minute, u32 second)
{
if (!OW_USE_FAKE_RTC)
return;
Script_PauseFakeRtc();
struct Time diff, target;
struct SiiRtcInfo *fakeRtc = FakeRtc_GetCurrentTime();

View File

@ -6970,6 +6970,7 @@ u32 GetFormChangeTargetSpeciesBoxMon(struct BoxPokemon *boxMon, enum FormChanges
case FORM_CHANGE_DEPOSIT:
case FORM_CHANGE_FAINT:
case FORM_CHANGE_DAYS_PASSED:
case FORM_CHANGE_BEGIN_WILD_ENCOUNTER:
targetSpecies = formChanges[i].targetSpecies;
break;
case FORM_CHANGE_STATUS:

View File

@ -349,7 +349,8 @@ void RtcCalcLocalTimeOffset(s32 days, s32 hours, s32 minutes, s32 seconds)
gLocalTime.hours = hours;
gLocalTime.minutes = minutes;
gLocalTime.seconds = seconds;
FakeRtc_ManuallySetTime(gLocalTime.days, gLocalTime.hours, gLocalTime.minutes, seconds);
if (!OW_USE_FAKE_RTC)
FakeRtc_ManuallySetTime(gLocalTime.days, gLocalTime.hours, gLocalTime.minutes, seconds);
RtcGetInfo(&sRtc);
RtcCalcTimeDifference(&sRtc, &gSaveBlock2Ptr->localTimeOffset, &gLocalTime);
}

View File

@ -3239,6 +3239,9 @@ bool8 ScrCmd_fwdtime(struct ScriptContext *ctx)
bool8 ScrCmd_fwdweekday(struct ScriptContext *ctx)
{
if (!OW_USE_FAKE_RTC)
return FALSE;
struct SiiRtcInfo *rtc = FakeRtc_GetCurrentTime();
u32 weekdayTarget = ScriptReadWord(ctx);

View File

@ -61,4 +61,39 @@ SINGLE_BATTLE_TEST("(TERA) Terastallizing into the same type with Adaptability g
}
}
TO_DO_BATTLE_TEST("Adaptability does not affect Stellar-type moves");
SINGLE_BATTLE_TEST("(TERA) Adaptability does not increase non-Tera base STAB beyond 1.5x", s16 damage)
{
u32 move;
PARAMETRIZE { move = MOVE_GUST; }
PARAMETRIZE { move = MOVE_WATER_GUN; }
GIVEN {
PLAYER(SPECIES_CRAWDAUNT) { Ability(ABILITY_ADAPTABILITY); TeraType(TYPE_NORMAL); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, move, gimmick: GIMMICK_TERA); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, move, player);
HP_BAR(opponent, captureDamage: &results[i].damage);
} FINALLY {
// With Adaptability, non-Tera base type should still be 1.5x STAB (not 2.0x).
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage);
}
}
SINGLE_BATTLE_TEST("(TERA) Adaptability does not affect Stellar-type moves", s16 damage)
{
u32 ability;
PARAMETRIZE { ability = ABILITY_HYPER_CUTTER; }
PARAMETRIZE { ability = ABILITY_ADAPTABILITY; }
GIVEN {
PLAYER(SPECIES_CRAWDAUNT) { Ability(ability); TeraType(TYPE_STELLAR); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_TERA_BLAST, gimmick: GIMMICK_TERA); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TERA_BLAST, player);
HP_BAR(opponent, captureDamage: &results[i].damage);
} FINALLY {
EXPECT_EQ(results[0].damage, results[1].damage);
}
}

View File

@ -75,3 +75,39 @@ SINGLE_BATTLE_TEST("Shields Down protects Minior Meteor from status conditions")
EXPECT(opponent->status1 & STATUS1_BURN);
}
}
WILD_BATTLE_TEST("Wild Minior appear in Meteor form without transforming")// To be replaced with WILD_DOUBLE_BATTLE_TEST when that is made possible.
{
GIVEN {
PLAYER(SPECIES_MINIOR_CORE) { Ability(ABILITY_SHIELDS_DOWN); }
OPPONENT(SPECIES_MINIOR_CORE) { Ability(ABILITY_SHIELDS_DOWN); }
} WHEN {
TURN {}
} SCENE {
ABILITY_POPUP(player, ABILITY_SHIELDS_DOWN);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player);
NONE_OF {
ABILITY_POPUP(opponent, ABILITY_SHIELDS_DOWN);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, opponent);
}
} THEN {
EXPECT_EQ(opponent->species, SPECIES_MINIOR_METEOR);
EXPECT_EQ(player->species, SPECIES_MINIOR_METEOR);
}
}
SINGLE_BATTLE_TEST("Trainers' Minior appear in Core form")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET)
OPPONENT(SPECIES_MINIOR_METEOR) { Ability(ABILITY_SHIELDS_DOWN); }
} WHEN {
TURN {}
} SCENE {
ABILITY_POPUP(opponent, ABILITY_SHIELDS_DOWN);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, opponent);
} THEN {
EXPECT_EQ(opponent->species, SPECIES_MINIOR_METEOR);
}
}

View File

@ -35,6 +35,38 @@ SINGLE_BATTLE_TEST("Ability Shield protects against Neutralizing Gas")
}
}
DOUBLE_BATTLE_TEST("Ability Shield prevents Intimidate from reactivating after Neutralizing Gas ends")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Speed(5); }
PLAYER(SPECIES_WYNAUT) { Speed(4); }
OPPONENT(SPECIES_KOFFING) { Ability(ABILITY_NEUTRALIZING_GAS); HP(1); Speed(1); }
OPPONENT(SPECIES_GYARADOS) { Ability(ABILITY_INTIMIDATE); Item(ITEM_ABILITY_SHIELD); Speed(3); }
} WHEN {
TURN { MOVE(playerLeft, MOVE_SCRATCH, target: opponentLeft); }
} SCENE {
ABILITY_POPUP(opponentLeft, ABILITY_NEUTRALIZING_GAS);
MESSAGE("Neutralizing gas filled the area!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponentRight);
MESSAGE("The opposing Gyarados's Ability is protected by the effects of its Ability Shield!");
ABILITY_POPUP(opponentRight, ABILITY_INTIMIDATE);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, playerLeft);
HP_BAR(opponentLeft);
MESSAGE("The effects of the neutralizing gas wore off!");
NONE_OF {
ABILITY_POPUP(opponentRight, ABILITY_INTIMIDATE);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
}
MESSAGE("The opposing Koffing fainted!");
} THEN {
EXPECT_EQ(playerLeft->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 1);
EXPECT_EQ(playerRight->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 1);
}
}
SINGLE_BATTLE_TEST("Ability Shield protects against Mold Breaker (no message)")
{
u32 item;

View File

@ -12,7 +12,6 @@ TO_DO_BATTLE_TEST("Assist can call moves with no PP left");
TO_DO_BATTLE_TEST("Assist can call moves from a fainted party member");
TO_DO_BATTLE_TEST("Assist can call moves that are blocked to its partners"); // Eg. double battle parter blocked by Disable
TO_DO_BATTLE_TEST("Assist can only call the original moves of a Transformed partner (Gen4 only)");
TO_DO_BATTLE_TEST("Assist can only call the current moves of a Transformed partner (Gen5+)");
TO_DO_BATTLE_TEST("Assist cannot call a Mimicked move (Gen4 only)");
TO_DO_BATTLE_TEST("Assist can call a Mimicked move but not the original Mimic (Gen5+)");
TO_DO_BATTLE_TEST("Assist can call moves in unhatched Eggs (Gen5 only)");
@ -57,3 +56,25 @@ SINGLE_BATTLE_TEST("Assisted move triggers correct weakness berry")
ANIMATION(ANIM_TYPE_MOVE, MOVE_SURF, player);
}
}
DOUBLE_BATTLE_TEST("Assist can only call the current moves of a Transformed partner (Gen5+)")
{
GIVEN {
ASSUME(GetMoveEffect(MOVE_TRANSFORM) == EFFECT_TRANSFORM);
PLAYER(SPECIES_WOBBUFFET) { Speed(3); Moves(MOVE_ASSIST); }
PLAYER(SPECIES_DITTO) { Speed(4); Moves(MOVE_TRANSFORM); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(2); Moves(MOVE_SCRATCH); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(1); }
} WHEN {
TURN {
MOVE(playerRight, MOVE_TRANSFORM, target: opponentLeft);
MOVE(playerLeft, MOVE_ASSIST);
MOVE(opponentLeft, MOVE_SCRATCH, target: playerRight);
}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TRANSFORM, playerRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_ASSIST, playerLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, playerLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponentLeft);
}
}

View File

@ -21,3 +21,20 @@ SINGLE_BATTLE_TEST("Tickle reduces the target's Attack and Defense by 1 stage ea
EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE - 1);
}
}
SINGLE_BATTLE_TEST("Tickle is blocked by Substitute (Gen4+)")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_TICKLE, MOVE_CELEBRATE); Speed(5); }
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_SUBSTITUTE, MOVE_CELEBRATE); Speed(10); }
} WHEN {
TURN { MOVE(opponent, MOVE_SUBSTITUTE); MOVE(player, MOVE_CELEBRATE); }
TURN { MOVE(player, MOVE_TICKLE); MOVE(opponent, MOVE_CELEBRATE); }
} SCENE {
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_TICKLE, player);
MESSAGE("But it failed!");
} THEN {
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
}
}

View File

@ -1,4 +1,42 @@
#include "global.h"
#include "test/battle.h"
TO_DO_BATTLE_TEST("TODO: Write Venom Drench (Move Effect) test titles")
ASSUMPTIONS
{
ASSUME(GetMoveEffect(MOVE_VENOM_DRENCH) == EFFECT_VENOM_DRENCH);
}
SINGLE_BATTLE_TEST("Venom Drench lowers stats of a poisoned target")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_VENOM_DRENCH); }
OPPONENT(SPECIES_WOBBUFFET) { Status1(STATUS1_POISON); }
} WHEN {
TURN { MOVE(player, MOVE_VENOM_DRENCH); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_VENOM_DRENCH, player);
} THEN {
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 1);
EXPECT_EQ(opponent->statStages[STAT_SPATK], DEFAULT_STAT_STAGE - 1);
EXPECT_EQ(opponent->statStages[STAT_SPEED], DEFAULT_STAT_STAGE - 1);
}
}
SINGLE_BATTLE_TEST("Venom Drench is blocked by Substitute")
{
GIVEN {
ASSUME(GetMoveEffect(MOVE_SUBSTITUTE) == EFFECT_SUBSTITUTE);
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_VENOM_DRENCH, MOVE_CELEBRATE); }
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_SUBSTITUTE, MOVE_CELEBRATE); Status1(STATUS1_POISON); }
} WHEN {
TURN { MOVE(opponent, MOVE_SUBSTITUTE); MOVE(player, MOVE_CELEBRATE); }
TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_VENOM_DRENCH); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUBSTITUTE, opponent);
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_VENOM_DRENCH, player);
} THEN {
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
EXPECT_EQ(opponent->statStages[STAT_SPATK], DEFAULT_STAT_STAGE);
EXPECT_EQ(opponent->statStages[STAT_SPEED], DEFAULT_STAT_STAGE);
}
}