mirror of
https://github.com/pret/pokefirered.git
synced 2026-09-30 12:59:43 -05:00
update tests/test framework + failed test
This commit is contained in:
@@ -99,7 +99,7 @@ void *AllocInternal(void *heapStart, u32 size, const char *location)
|
||||
block = block->next;
|
||||
}
|
||||
while (block != head);
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, "%s: OOM allocating %d bytes", location, size);
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":L%s:%d, %s: OOM allocating %d bytes", gTestRunnerState.test->filename, SourceLine(0), location, size);
|
||||
#endif
|
||||
AGB_ASSERT_EX(0, ABSPATH("gflib/malloc.c"), 174);
|
||||
return NULL;
|
||||
|
||||
@@ -48,11 +48,12 @@ struct TrainerMon
|
||||
u8 nature:5;
|
||||
bool8 gender:2;
|
||||
bool8 isShiny:1;
|
||||
u8 useGimmick:4;
|
||||
u8 dynamaxLevel:4;
|
||||
u8 teraType:5;
|
||||
bool8 gigantamaxFactor:1;
|
||||
u8 padding:2;
|
||||
u8 shouldUseDynamax:1;
|
||||
u8 padding1:1;
|
||||
u8 dynamaxLevel:4;
|
||||
u8 padding2:4;
|
||||
};
|
||||
|
||||
#define TRAINER_PARTY(partyArray) partyArray, .partySize = ARRAY_COUNT(partyArray)
|
||||
|
||||
@@ -507,7 +507,7 @@
|
||||
// or loop.
|
||||
#define BATTLE_TEST_STACK_SIZE 1024
|
||||
#define MAX_TURNS 16
|
||||
#define MAX_QUEUED_EVENTS 25
|
||||
#define MAX_QUEUED_EVENTS 30
|
||||
#define MAX_EXPECTED_ACTIONS 10
|
||||
|
||||
enum { BATTLE_TEST_SINGLES, BATTLE_TEST_DOUBLES, BATTLE_TEST_WILD, BATTLE_TEST_AI_SINGLES, BATTLE_TEST_AI_DOUBLES };
|
||||
@@ -518,7 +518,6 @@ typedef void (*DoubleBattleTestFunction)(void *, const u32, struct BattlePokemon
|
||||
struct BattleTest
|
||||
{
|
||||
u8 type;
|
||||
u16 sourceLine;
|
||||
union
|
||||
{
|
||||
SingleBattleTestFunction singles;
|
||||
@@ -744,10 +743,10 @@ extern struct BattleTestRunnerState *const gBattleTestRunnerState;
|
||||
.name = _name, \
|
||||
.filename = __FILE__, \
|
||||
.runner = &gBattleTestRunner, \
|
||||
.sourceLine = __LINE__, \
|
||||
.data = (void *)&(const struct BattleTest) \
|
||||
{ \
|
||||
.type = _type, \
|
||||
.sourceLine = __LINE__, \
|
||||
.function = { .singles = (SingleBattleTestFunction)CAT(Test, __LINE__) }, \
|
||||
.resultsSize = sizeof(struct CAT(Result, __LINE__)), \
|
||||
}, \
|
||||
@@ -762,10 +761,10 @@ extern struct BattleTestRunnerState *const gBattleTestRunnerState;
|
||||
.name = _name, \
|
||||
.filename = __FILE__, \
|
||||
.runner = &gBattleTestRunner, \
|
||||
.sourceLine = __LINE__, \
|
||||
.data = (void *)&(const struct BattleTest) \
|
||||
{ \
|
||||
.type = _type, \
|
||||
.sourceLine = __LINE__, \
|
||||
.function = { .doubles = (DoubleBattleTestFunction)CAT(Test, __LINE__) }, \
|
||||
.resultsSize = sizeof(struct CAT(Result, __LINE__)), \
|
||||
}, \
|
||||
@@ -995,6 +994,8 @@ void SendOut(u32 sourceLine, struct BattlePokemon *, u32 partyIndex);
|
||||
// Static const is needed to make the modern compiler put the pattern variable in the .rodata section, instead of putting it on stack(which can break the game).
|
||||
#define MESSAGE(pattern) do {static const u8 msg[] = _(pattern); QueueMessage(__LINE__, msg);} while (0)
|
||||
#define STATUS_ICON(battler, status) QueueStatus(__LINE__, battler, (struct StatusEventContext) { status })
|
||||
#define FREEZE_OR_FROSTBURN_STATUS(battler, isFrostbite) \
|
||||
(B_USE_FROSTBITE ? STATUS_ICON(battler, frostbite: isFrostbite) : STATUS_ICON(battler, freeze: isFrostbite))
|
||||
|
||||
#define SWITCH_OUT_MESSAGE(name) ONE_OF { \
|
||||
MESSAGE(name ", that's enough! Come back!"); \
|
||||
@@ -1092,7 +1093,7 @@ void ValidateFinally(u32 sourceLine);
|
||||
s32 _am = Q_4_12_TO_INT(_a * _m); \
|
||||
s32 _t = max(Q_4_12_TO_INT(abs(_m) + Q_4_12_ROUND), 1); \
|
||||
if (abs(_am-_b) > _t) \
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: EXPECT_MUL_EQ(%d, %q, %d) failed: %d not in [%d..%d]", gTestRunnerState.test->filename, __LINE__, _a, _m, _b, _am, _b-_t, _b+_t); \
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_MUL_EQ(%d, %q, %d) failed: %d not in [%d..%d]", gTestRunnerState.test->filename, __LINE__, _a, _m, _b, _am, _b-_t, _b+_t); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -33,6 +33,7 @@ struct Test
|
||||
const char *filename;
|
||||
const struct TestRunner *runner;
|
||||
void *data;
|
||||
u16 sourceLine;
|
||||
};
|
||||
|
||||
struct TestRunnerState
|
||||
@@ -40,6 +41,7 @@ struct TestRunnerState
|
||||
u8 state;
|
||||
u8 exitCode;
|
||||
const char *skipFilename;
|
||||
u32 failedAssumptionsBlockLine;
|
||||
const struct Test *test;
|
||||
u32 processCosts[MAX_PROCESSES];
|
||||
|
||||
@@ -73,7 +75,9 @@ void CB2_TestRunner(void);
|
||||
|
||||
void Test_ExpectedResult(enum TestResult);
|
||||
void Test_ExpectLeaks(bool32);
|
||||
void Test_ExitWithResult(enum TestResult, const char *fmt, ...);
|
||||
void Test_ExitWithResult(enum TestResult, u32 stopLine, const char *fmt, ...);
|
||||
u32 SourceLine(u32 sourceLineOffset);
|
||||
u32 SourceLineOffset(u32 sourceLine);
|
||||
|
||||
s32 Test_MgbaPrintf(const char *fmt, ...);
|
||||
|
||||
@@ -84,6 +88,7 @@ s32 Test_MgbaPrintf(const char *fmt, ...);
|
||||
.name = _name, \
|
||||
.filename = __FILE__, \
|
||||
.runner = &gFunctionTestRunner, \
|
||||
.sourceLine = __LINE__, \
|
||||
.data = (void *)CAT(Test, __LINE__), \
|
||||
}; \
|
||||
static void CAT(Test, __LINE__)(void)
|
||||
@@ -95,6 +100,7 @@ s32 Test_MgbaPrintf(const char *fmt, ...);
|
||||
.name = "ASSUMPTIONS: " __FILE__, \
|
||||
.filename = __FILE__, \
|
||||
.runner = &gAssumptionsRunner, \
|
||||
.sourceLine = __LINE__, \
|
||||
.data = Assumptions, \
|
||||
}; \
|
||||
static void Assumptions(void)
|
||||
@@ -103,14 +109,14 @@ s32 Test_MgbaPrintf(const char *fmt, ...);
|
||||
do \
|
||||
{ \
|
||||
if (!(c)) \
|
||||
Test_ExitWithResult(TEST_RESULT_ASSUMPTION_FAIL, "%s:%d: ASSUME failed", gTestRunnerState.test->filename, __LINE__); \
|
||||
Test_ExitWithResult(TEST_RESULT_ASSUMPTION_FAIL, __LINE__, ":L%s:%d: ASSUME failed", gTestRunnerState.test->filename, __LINE__); \
|
||||
} while (0)
|
||||
|
||||
#define EXPECT(c) \
|
||||
do \
|
||||
{ \
|
||||
if (!(c)) \
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: EXPECT failed", gTestRunnerState.test->filename, __LINE__); \
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT failed", gTestRunnerState.test->filename, __LINE__); \
|
||||
} while (0)
|
||||
|
||||
#define EXPECT_EQ(a, b) \
|
||||
@@ -118,7 +124,7 @@ s32 Test_MgbaPrintf(const char *fmt, ...);
|
||||
{ \
|
||||
typeof(a) _a = (a), _b = (b); \
|
||||
if (_a != _b) \
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: EXPECT_EQ(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_EQ(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \
|
||||
} while (0)
|
||||
|
||||
#define EXPECT_NE(a, b) \
|
||||
@@ -126,7 +132,7 @@ s32 Test_MgbaPrintf(const char *fmt, ...);
|
||||
{ \
|
||||
typeof(a) _a = (a), _b = (b); \
|
||||
if (_a == _b) \
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: EXPECT_NE(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_NE(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \
|
||||
} while (0)
|
||||
|
||||
#define EXPECT_LT(a, b) \
|
||||
@@ -134,7 +140,7 @@ s32 Test_MgbaPrintf(const char *fmt, ...);
|
||||
{ \
|
||||
typeof(a) _a = (a), _b = (b); \
|
||||
if (_a >= _b) \
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: EXPECT_LT(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_LT(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \
|
||||
} while (0)
|
||||
|
||||
#define EXPECT_LE(a, b) \
|
||||
@@ -142,7 +148,7 @@ s32 Test_MgbaPrintf(const char *fmt, ...);
|
||||
{ \
|
||||
typeof(a) _a = (a), _b = (b); \
|
||||
if (_a > _b) \
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: EXPECT_LE(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_LE(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \
|
||||
} while (0)
|
||||
|
||||
#define EXPECT_GT(a, b) \
|
||||
@@ -150,7 +156,7 @@ s32 Test_MgbaPrintf(const char *fmt, ...);
|
||||
{ \
|
||||
typeof(a) _a = (a), _b = (b); \
|
||||
if (_a <= _b) \
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: EXPECT_GT(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_GT(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \
|
||||
} while (0)
|
||||
|
||||
#define EXPECT_GE(a, b) \
|
||||
@@ -158,7 +164,7 @@ s32 Test_MgbaPrintf(const char *fmt, ...);
|
||||
{ \
|
||||
typeof(a) _a = (a), _b = (b); \
|
||||
if (_a < _b) \
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: EXPECT_GE(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_GE(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \
|
||||
} while (0)
|
||||
|
||||
struct Benchmark { s32 ticks; };
|
||||
@@ -195,7 +201,7 @@ static inline struct Benchmark BenchmarkStop(void)
|
||||
u32 a_ = (a).ticks; u32 b_ = (b).ticks; \
|
||||
Test_MgbaPrintf(#a ": %d ticks, " #b ": %d ticks", a_, b_); \
|
||||
if (((a_ - BENCHMARK_ABS) * BENCHMARK_REL) >= (b_ * 100)) \
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: EXPECT_FASTER(" #a ", " #b ") failed", gTestRunnerState.test->filename, __LINE__); \
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_FASTER(" #a ", " #b ") failed", gTestRunnerState.test->filename, __LINE__); \
|
||||
} while (0)
|
||||
|
||||
#define EXPECT_SLOWER(a, b) \
|
||||
@@ -204,7 +210,7 @@ static inline struct Benchmark BenchmarkStop(void)
|
||||
u32 a_ = (a).ticks; u32 b_ = (b).ticks; \
|
||||
Test_MgbaPrintf(#a ": %d ticks, " #b ": %d ticks", a_, b_); \
|
||||
if ((a_ * 100) <= ((b_ - BENCHMARK_ABS) * BENCHMARK_REL)) \
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: EXPECT_SLOWER(" #a ", " #b ") failed", gTestRunnerState.test->filename, __LINE__); \
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_SLOWER(" #a ", " #b ") failed", gTestRunnerState.test->filename, __LINE__); \
|
||||
} while (0)
|
||||
|
||||
#define KNOWN_FAILING \
|
||||
@@ -220,7 +226,7 @@ static inline struct Benchmark BenchmarkStop(void)
|
||||
#define TO_DO \
|
||||
do { \
|
||||
Test_ExpectedResult(TEST_RESULT_TODO); \
|
||||
Test_ExitWithResult(TEST_RESULT_TODO, "%s:%d: EXPECT_TO_DO", gTestRunnerState.test->filename, __LINE__); \
|
||||
Test_ExitWithResult(TEST_RESULT_TODO, __LINE__, ":L%s:%d: EXPECT_TO_DO", gTestRunnerState.test->filename, __LINE__); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -82,8 +82,14 @@ bool32 ShouldTrainerBattlerUseGimmick(u32 battler, enum Gimmick gimmick)
|
||||
bool32 isSecondTrainer = (GetBattlerPosition(battler) == B_POSITION_OPPONENT_RIGHT) && (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) && !BATTLE_TWO_VS_ONE_OPPONENT;
|
||||
u16 trainerId = isSecondTrainer ? gTrainerBattleOpponent_B : gTrainerBattleOpponent_A;
|
||||
const struct TrainerMon *mon = &GetTrainerPartyFromId(trainerId)[isSecondTrainer ? gBattlerPartyIndexes[battler] - MULTI_PARTY_SIZE : gBattlerPartyIndexes[battler]];
|
||||
return mon->useGimmick == gimmick;
|
||||
|
||||
if (gimmick == GIMMICK_TERA && mon->teraType != TYPE_NONE)
|
||||
return TRUE;
|
||||
if (gimmick == GIMMICK_DYNAMAX && mon->shouldUseDynamax)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Returns whether a trainer has used a gimmick during a battle.
|
||||
@@ -290,7 +296,7 @@ static inline u32 GetIndicatorSpriteId(u32 healthboxId)
|
||||
u32 GetIndicatorTileTag(u32 battler)
|
||||
{
|
||||
u32 gimmick = GetActiveGimmick(battler);
|
||||
|
||||
|
||||
if (IsBattlerPrimalReverted(battler))
|
||||
{
|
||||
if (gBattleMons[battler].species == SPECIES_GROUDON_PRIMAL)
|
||||
@@ -330,6 +336,9 @@ void UpdateIndicatorVisibilityAndType(u32 healthboxId, bool32 invisible)
|
||||
u32 palTag = GetIndicatorPalTag(battler);
|
||||
struct Sprite *sprite = &gSprites[GetIndicatorSpriteId(healthboxId)];
|
||||
|
||||
if (GetIndicatorSpriteId(healthboxId) == 0) // safari zone means the player doesn't have an indicator sprite id
|
||||
return;
|
||||
|
||||
if (tileTag != TAG_NONE && palTag != TAG_NONE)
|
||||
{
|
||||
sprite->oam.tileNum = GetSpriteTileStartByTag(tileTag);
|
||||
|
||||
@@ -34,7 +34,7 @@ void ActivateTera(u32 battler)
|
||||
{
|
||||
FlagClear(B_FLAG_TERA_ORB_CHARGED);
|
||||
}
|
||||
|
||||
|
||||
// Execute battle script.
|
||||
PREPARE_TYPE_BUFFER(gBattleTextBuff1, GetBattlerTeraType(battler));
|
||||
if (TryBattleFormChange(gBattlerAttacker, FORM_CHANGE_BATTLE_TERASTALLIZATION))
|
||||
@@ -63,16 +63,21 @@ bool32 CanTerastallize(u32 battler)
|
||||
{
|
||||
u32 holdEffect = GetBattlerHoldEffect(battler, FALSE);
|
||||
|
||||
// Check if Player has Tera Orb and has charge.
|
||||
if (!TESTING && !CheckBagHasItem(ITEM_TERA_ORB, 1))
|
||||
return FALSE;
|
||||
|
||||
if (!TESTING
|
||||
&& !(B_FLAG_TERA_ORB_NO_COST != 0 && FlagGet(B_FLAG_TERA_ORB_NO_COST))
|
||||
&& (battler == B_POSITION_PLAYER_LEFT || (!(gBattleTypeFlags & BATTLE_TYPE_MULTI) && battler == B_POSITION_PLAYER_RIGHT)))
|
||||
if (TESTING || GetBattlerSide(battler) == B_SIDE_OPPONENT)
|
||||
{
|
||||
if (B_FLAG_TERA_ORB_CHARGED != 0 && !FlagGet(B_FLAG_TERA_ORB_CHARGED))
|
||||
return FALSE;
|
||||
// Skip all other checks in this block, go to HasTrainerUsedGimmick
|
||||
}
|
||||
else if (!CheckBagHasItem(ITEM_TERA_ORB, 1))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
else if (FlagGet(B_FLAG_TERA_ORB_NO_COST))
|
||||
{
|
||||
// Tera Orb is not depleted, go to HasTrainerUsedGimmick
|
||||
}
|
||||
else if (!FlagGet(B_FLAG_TERA_ORB_CHARGED))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Check if Trainer has already Terastallized.
|
||||
@@ -104,7 +109,7 @@ u32 GetBattlerTeraType(u32 battler)
|
||||
// Uses up a type's Stellar boost.
|
||||
void ExpendTypeStellarBoost(u32 battler, u32 type)
|
||||
{
|
||||
if (type < 32) // avoid OOB access
|
||||
if (type < 32 && gBattleMons[battler].species != SPECIES_TERAPAGOS_STELLAR) // avoid OOB access
|
||||
gBattleStruct->stellarBoostFlags[GetBattlerSide(battler)] |= gBitTable[type];
|
||||
}
|
||||
|
||||
|
||||
@@ -76,11 +76,7 @@ const struct SpeciesInfo gSpeciesInfo[] =
|
||||
.categoryName = _("Unknown"),
|
||||
.height = 0,
|
||||
.weight = 0,
|
||||
.description = COMPOUND_STRING(
|
||||
"This is a newly discovered Pokémon.\n"
|
||||
"It is currently under investigation.\n"
|
||||
"No detailed information is available\n"
|
||||
"at this time."),
|
||||
.description = gFallbackPokedexText,
|
||||
.pokemonScale = 256,
|
||||
.pokemonOffset = 0,
|
||||
.trainerScale = 256,
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
// fallback
|
||||
const u8 gFallbackPokedexText[] = _(
|
||||
"This is a newly discovered Pokémon.\n"
|
||||
"It is currently under investigation.\n"
|
||||
"No detailed information is available\n"
|
||||
"at this time.");
|
||||
|
||||
// Gen 1 families
|
||||
const u8 gRaticateAlolanPokedexText[] = _(
|
||||
"It forms a group of Rattata, which it \n"
|
||||
@@ -279,4 +286,4 @@ const u8 gOgerponCornerstoneMaskPokedexText[] = _(
|
||||
"In this form, it draws on the power\n"
|
||||
"of stone. Its body is rock-solid,\n"
|
||||
"protecting it from all manner of\n"
|
||||
"attacks.");
|
||||
"attacks.");
|
||||
|
||||
@@ -46,9 +46,9 @@ SINGLE_BATTLE_TEST("Beads of Ruin's message displays correctly after all battler
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, opponent);
|
||||
// Everyone faints.
|
||||
MESSAGE("Go! Chi-Yu!");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
ABILITY_POPUP(player, ABILITY_BEADS_OF_RUIN);
|
||||
MESSAGE("Chi-Yu's Beads of Ruin weakened the Sp. Def of all surrounding Pokémon!");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
54
test/battle/ability/comatose.c
Normal file
54
test/battle/ability/comatose.c
Normal file
@@ -0,0 +1,54 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Comatose prevents status-inducing moves")
|
||||
{
|
||||
u32 move;
|
||||
|
||||
PARAMETRIZE { move = MOVE_TOXIC; }
|
||||
PARAMETRIZE { move = MOVE_POISONPOWDER; }
|
||||
PARAMETRIZE { move = MOVE_SLEEP_POWDER; }
|
||||
PARAMETRIZE { move = MOVE_THUNDER_WAVE; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_KOMALA) { Ability(ABILITY_COMATOSE); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, move); }
|
||||
} SCENE {
|
||||
MESSAGE("Komala is drowsing!");
|
||||
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
ABILITY_POPUP(player, ABILITY_COMATOSE);
|
||||
MESSAGE("It doesn't affect Komala…");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Comatose may be suppressed if pokemon transformed into a pokemon with Comatose ability and was under the effects of Gastro Acid")
|
||||
{
|
||||
u32 move;
|
||||
|
||||
PARAMETRIZE { move = MOVE_TOXIC; }
|
||||
PARAMETRIZE { move = MOVE_POISONPOWDER; }
|
||||
PARAMETRIZE { move = MOVE_SLEEP_POWDER; }
|
||||
PARAMETRIZE { move = MOVE_THUNDER_WAVE; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_KOMALA) { Ability(ABILITY_COMATOSE); Speed(30); }
|
||||
OPPONENT(SPECIES_DITTO) { Speed(20); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_GASTRO_ACID); MOVE(opponent, MOVE_TRANSFORM); }
|
||||
TURN { MOVE(player, move); }
|
||||
} SCENE {
|
||||
MESSAGE("Komala is drowsing!");
|
||||
MESSAGE("Komala used Gastro Acid!");
|
||||
MESSAGE("Foe Ditto used Transform!");
|
||||
MESSAGE("Foe Ditto transformed into Komala!");
|
||||
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, player);
|
||||
if (move == MOVE_POISONPOWDER) { STATUS_ICON(opponent, poison: TRUE); }
|
||||
else if (move == MOVE_TOXIC) { STATUS_ICON(opponent, badPoison: TRUE); }
|
||||
else if (move == MOVE_THUNDER_WAVE) { STATUS_ICON(opponent, paralysis: TRUE); }
|
||||
else if (move == MOVE_SLEEP_POWDER) { STATUS_ICON(opponent, sleep: TRUE); }
|
||||
}
|
||||
}
|
||||
@@ -106,23 +106,122 @@ SINGLE_BATTLE_TEST("If a Poison- or Steel-type Pokémon with Corrosion holds a T
|
||||
|
||||
SINGLE_BATTLE_TEST("If a Poison- or Steel-type Pokémon with Corrosion poisons a target with Synchronize, Synchronize will not poison Poison- or Steel-type Pokémon")
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE { move = MOVE_TOXIC; }
|
||||
PARAMETRIZE { move = MOVE_POISON_POWDER; }
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC);
|
||||
ASSUME(gMovesInfo[MOVE_POISON_POWDER].effect == EFFECT_POISON);
|
||||
PLAYER(SPECIES_SALANDIT) { Ability(ABILITY_CORROSION); }
|
||||
OPPONENT(SPECIES_ABRA) { Ability(ABILITY_SYNCHRONIZE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TOXIC); }
|
||||
TURN { MOVE(player, move); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, player);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent);
|
||||
STATUS_ICON(opponent, badPoison: TRUE);
|
||||
if (move == MOVE_TOXIC)
|
||||
STATUS_ICON(opponent, badPoison: TRUE);
|
||||
else
|
||||
STATUS_ICON(opponent, poison: TRUE);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, player);
|
||||
STATUS_ICON(player, badPoison: TRUE);
|
||||
STATUS_ICON(player, poison: TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Corrosion cannot bypass moves or Abilities that prevent poisoning, such as Safeguard or Immunity");
|
||||
TO_DO_BATTLE_TEST("If the Pokémon with this Ability uses Magic Coat to reflect a status move that inflicts poison, the reflected move will be able to poison Poison- or Steel-type Pokémon.");
|
||||
TO_DO_BATTLE_TEST("Moves used by a Pokémon with Corrosion that are reflected by Magic Coat or Magic Bounce do not retain the ability to poison Poison- or Steel-type Pokémon.")
|
||||
SINGLE_BATTLE_TEST("Corrosion cannot bypass moves that prevent poisoning such as Safeguard")
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE { move = MOVE_TOXIC; }
|
||||
PARAMETRIZE { move = MOVE_POISON_POWDER; }
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC);
|
||||
ASSUME(gMovesInfo[MOVE_POISON_POWDER].effect == EFFECT_POISON);
|
||||
PLAYER(SPECIES_SALANDIT) { Ability(ABILITY_CORROSION); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_SAFEGUARD); MOVE(player, move); }
|
||||
} SCENE {
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC, player);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent);
|
||||
STATUS_ICON(opponent, badPoison: TRUE);
|
||||
STATUS_ICON(opponent, poison: TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Corrosion cannot bypass abilities that prevent poisoning such as Immunity")
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE { move = MOVE_TOXIC; }
|
||||
PARAMETRIZE { move = MOVE_POISON_POWDER; }
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC);
|
||||
ASSUME(gMovesInfo[MOVE_POISON_POWDER].effect == EFFECT_POISON);
|
||||
PLAYER(SPECIES_SALANDIT) { Ability(ABILITY_CORROSION); }
|
||||
OPPONENT(SPECIES_SNORLAX) { Ability(ABILITY_IMMUNITY); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, move); }
|
||||
} SCENE {
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC, player);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent);
|
||||
STATUS_ICON(opponent, badPoison: TRUE);
|
||||
STATUS_ICON(opponent, poison: TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Corrosion allows the Pokémon with the ability to poison a Steel or Poison-type opponent by using Magic Coat")
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE { move = MOVE_TOXIC; }
|
||||
PARAMETRIZE { move = MOVE_POISON_POWDER; }
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC);
|
||||
ASSUME(gMovesInfo[MOVE_POISON_POWDER].effect == EFFECT_POISON);
|
||||
ASSUME(gMovesInfo[MOVE_MAGIC_COAT].effect == EFFECT_MAGIC_COAT);
|
||||
PLAYER(SPECIES_SALANDIT) { Ability(ABILITY_CORROSION); }
|
||||
OPPONENT(SPECIES_BELDUM);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_MAGIC_COAT); MOVE(opponent, move); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_MAGIC_COAT, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, player); // Bounced by Magic Coat
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent);
|
||||
if (move == MOVE_TOXIC)
|
||||
STATUS_ICON(opponent, badPoison: TRUE);
|
||||
else
|
||||
STATUS_ICON(opponent, poison: TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Corrosion's effect is lost if the move used by the Pokémon with the ability is reflected by Magic Coat")
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE { move = MOVE_TOXIC; }
|
||||
PARAMETRIZE { move = MOVE_POISON_POWDER; }
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC);
|
||||
ASSUME(gMovesInfo[MOVE_POISON_POWDER].effect == EFFECT_POISON);
|
||||
ASSUME(gMovesInfo[MOVE_MAGIC_COAT].effect == EFFECT_MAGIC_COAT);
|
||||
PLAYER(SPECIES_SALANDIT) { Ability(ABILITY_CORROSION); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_MAGIC_COAT); MOVE(player, move); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_MAGIC_COAT, opponent);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, player);
|
||||
if (move == MOVE_TOXIC)
|
||||
STATUS_ICON(opponent, badPoison: TRUE);
|
||||
else
|
||||
STATUS_ICON(opponent, poison: TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
17
test/battle/ability/cursed_body.c
Normal file
17
test/battle/ability/cursed_body.c
Normal file
@@ -0,0 +1,17 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Cursed Body triggers 30% of the time")
|
||||
{
|
||||
PASSES_RANDOMLY(3, 10, RNG_CURSED_BODY);
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_FRILLISH) { Ability(ABILITY_CURSED_BODY); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_AQUA_JET); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_AQUA_JET, player);
|
||||
ABILITY_POPUP(opponent, ABILITY_CURSED_BODY);
|
||||
MESSAGE("Wobbuffet's Aqua Jet was disabled by Foe Frillish's Cursed Body!");
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,7 @@ SINGLE_BATTLE_TEST("Download raises Sp.Attack if enemy has lower Sp. Def than De
|
||||
SINGLE_BATTLE_TEST("Download doesn't activate if target hasn't been sent out yet", s16 damagePhysical, s16 damageSpecial)
|
||||
{
|
||||
u32 ability;
|
||||
|
||||
PARAMETRIZE { ability = ABILITY_TRACE; }
|
||||
PARAMETRIZE { ability = ABILITY_DOWNLOAD; }
|
||||
GIVEN {
|
||||
@@ -73,13 +74,13 @@ SINGLE_BATTLE_TEST("Download doesn't activate if target hasn't been sent out yet
|
||||
// Everyone faints.
|
||||
|
||||
SEND_IN_MESSAGE("Porygon");
|
||||
MESSAGE("2 sent out Porygon2!");
|
||||
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(player, ABILITY_DOWNLOAD);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
MESSAGE("Porygon's Download raised its Attack!");
|
||||
}
|
||||
MESSAGE("2 sent out Porygon2!");
|
||||
|
||||
if (ability == ABILITY_DOWNLOAD)
|
||||
{
|
||||
ABILITY_POPUP(opponent, ABILITY_DOWNLOAD);
|
||||
|
||||
4
test/battle/ability/full_metal_body.c
Normal file
4
test/battle/ability/full_metal_body.c
Normal file
@@ -0,0 +1,4 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
// Tests for Full Metal Body are handled in test/battle/ability/clear_body.c
|
||||
@@ -22,7 +22,7 @@ SINGLE_BATTLE_TEST("Ice Body recovers 1/16th of Max HP in hail.")
|
||||
TURN { MOVE(opponent, MOVE_HAIL); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(player, ABILITY_ICE_BODY);
|
||||
MESSAGE("Glalie's Ice Body healed it a little bit!");
|
||||
HP_BAR(player, damage: -(100 / 16));
|
||||
MESSAGE("Glalie's Ice Body healed it a little bit!");
|
||||
}
|
||||
}
|
||||
|
||||
24
test/battle/ability/illusion.c
Normal file
24
test/battle/ability/illusion.c
Normal file
@@ -0,0 +1,24 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
// This test is eyes on only
|
||||
SINGLE_BATTLE_TEST("Illusion can only imitate Normal Form terapagos")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_ZOROARK) { Moves(MOVE_CELEBRATE); }
|
||||
PLAYER(SPECIES_TERAPAGOS) { Moves(MOVE_CELEBRATE); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
// Zoroark is out, should be normal form Terapagos
|
||||
// Switch to Terapagos which enters Terastal Form
|
||||
TURN { SWITCH(player, 1); }
|
||||
// Switch back to Zoroark, should not be Terastal Terapagos
|
||||
TURN { SWITCH(player, 0); MOVE(opponent, MOVE_TACKLE);}
|
||||
// Switch back to Terapagos
|
||||
TURN { SWITCH(player, 1); }
|
||||
// Terapagos Stellar, Zoroark gets Roared in, should not be Stellar Terapagos
|
||||
TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_TERA); MOVE(opponent, MOVE_ROAR); }
|
||||
// Reveal the Zoroark
|
||||
TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_TACKLE); }
|
||||
}
|
||||
}
|
||||
@@ -78,23 +78,29 @@ DOUBLE_BATTLE_TEST("Intimidate doesn't activate on an empty field in a double ba
|
||||
// Everyone faints.
|
||||
|
||||
SEND_IN_MESSAGE("Ekans");
|
||||
MESSAGE("2 sent out Arbok!");
|
||||
SEND_IN_MESSAGE("Abra");
|
||||
MESSAGE("2 sent out Wynaut!");
|
||||
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(playerLeft, ABILITY_INTIMIDATE);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
MESSAGE("Ekans's Intimidate cuts Foe Arbok's attack!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
|
||||
MESSAGE("Ekans's Intimidate cuts Foe Wynaut's attack!");
|
||||
|
||||
}
|
||||
MESSAGE("2 sent out Arbok!");
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_INTIMIDATE);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
|
||||
MESSAGE("Foe Arbok's Intimidate cuts Ekans's attack!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
|
||||
MESSAGE("Foe Arbok's Intimidate cuts Abra's attack!");
|
||||
}
|
||||
SEND_IN_MESSAGE("Abra");
|
||||
MESSAGE("2 sent out Wynaut!");
|
||||
// Intimidate activates after all battlers have been brought out
|
||||
ABILITY_POPUP(playerLeft, ABILITY_INTIMIDATE);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
MESSAGE("Ekans's Intimidate cuts Foe Arbok's attack!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
|
||||
MESSAGE("Ekans's Intimidate cuts Foe Wynaut's attack!");
|
||||
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_INTIMIDATE);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
|
||||
MESSAGE("Foe Arbok's Intimidate cuts Ekans's attack!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
|
||||
MESSAGE("Foe Arbok's Intimidate cuts Abra's attack!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,6 +217,35 @@ SINGLE_BATTLE_TEST("Intimidate can not further lower opponents Atk stat if it is
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Intimidate is not going to trigger if a mon switches out through u-turn and the opposing field is empty")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); }
|
||||
OPPONENT(SPECIES_WYNAUT) { HP(1); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_TREECKO);
|
||||
OPPONENT(SPECIES_TORCHIC);
|
||||
} WHEN {
|
||||
TURN {
|
||||
MOVE(opponentRight, MOVE_HEALING_WISH);
|
||||
MOVE(playerLeft, MOVE_U_TURN, target: opponentLeft);
|
||||
SEND_OUT(playerLeft, 2);
|
||||
SEND_OUT(opponentLeft, 2);
|
||||
SEND_OUT(opponentRight, 3);
|
||||
}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, playerRight);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_HEALING_WISH, opponentRight);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_U_TURN, playerLeft);
|
||||
HP_BAR(opponentLeft);
|
||||
MESSAGE("2 sent out Treecko!");
|
||||
MESSAGE("2 sent out Torchic!");
|
||||
NOT ABILITY_POPUP(playerLeft, ABILITY_INTIMIDATE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Intimidate activates when it's no longer effected by Neutralizing Gas")
|
||||
{
|
||||
GIVEN {
|
||||
|
||||
73
test/battle/ability/lightning_rod.c
Normal file
73
test/battle/ability/lightning_rod.c
Normal file
@@ -0,0 +1,73 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Lightning Rod absorbs Electric-type moves and increases the Sp. Attack [Gen5+]")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_THUNDERBOLT].type == TYPE_ELECTRIC);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_RAICHU) { Ability(ABILITY_LIGHTNING_ROD); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_THUNDERBOLT); MOVE(opponent, MOVE_CELEBRATE); }
|
||||
} SCENE {
|
||||
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5) {
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDERBOLT, player);
|
||||
HP_BAR(opponent);
|
||||
};
|
||||
ABILITY_POPUP(opponent, ABILITY_LIGHTNING_ROD);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
MESSAGE("Foe Raichu's Sp. Atk rose!");
|
||||
} else {
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(opponent, ABILITY_LIGHTNING_ROD);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
MESSAGE("Foe Raichu's Sp. Atk rose!");
|
||||
};
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDERBOLT, player);
|
||||
HP_BAR(opponent);
|
||||
}
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Lightning Rod forces single-target Electric-type moves to target the Pokémon with this Ability.")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_THUNDERBOLT].type == TYPE_ELECTRIC);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_RAICHU) { Ability(ABILITY_LIGHTNING_ROD); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN {
|
||||
MOVE(playerLeft, MOVE_THUNDERBOLT, target: opponentRight);
|
||||
MOVE(playerRight, MOVE_THUNDERBOLT, target: opponentRight);
|
||||
MOVE(opponentLeft, MOVE_CELEBRATE);
|
||||
MOVE(opponentRight, MOVE_CELEBRATE);
|
||||
}
|
||||
} SCENE {
|
||||
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5) {
|
||||
NONE_OF {
|
||||
HP_BAR(opponentLeft);
|
||||
HP_BAR(opponentRight);
|
||||
};
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_LIGHTNING_ROD);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
MESSAGE("Foe Raichu's Sp. Atk rose!");
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_LIGHTNING_ROD);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
MESSAGE("Foe Raichu's Sp. Atk rose!");
|
||||
} else {
|
||||
NONE_OF {
|
||||
HP_BAR(opponentRight);
|
||||
};
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDERBOLT, playerLeft);
|
||||
HP_BAR(opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDERBOLT, playerRight);
|
||||
HP_BAR(opponentLeft);
|
||||
}
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentRight);
|
||||
}
|
||||
}
|
||||
@@ -49,8 +49,8 @@ AI_SINGLE_BATTLE_TEST("AI doesn't use accuracy-lowering moves if it knows that t
|
||||
for (j = MOVE_NONE + 1; j < MOVES_COUNT; j++)
|
||||
{
|
||||
if (gMovesInfo[j].effect == EFFECT_ACCURACY_DOWN || gMovesInfo[j].effect == EFFECT_ACCURACY_DOWN_2) {
|
||||
PARAMETRIZE{ moveAI = j; abilityAI = ABILITY_SWIFT_SWIM; }
|
||||
PARAMETRIZE{ moveAI = j; abilityAI = ABILITY_MOLD_BREAKER; }
|
||||
PARAMETRIZE { moveAI = j; abilityAI = ABILITY_SWIFT_SWIM; }
|
||||
PARAMETRIZE { moveAI = j; abilityAI = ABILITY_MOLD_BREAKER; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,16 +16,16 @@ SINGLE_BATTLE_TEST("Opportunist only copies foe's positive stat changes in a tur
|
||||
OPPONENT(SPECIES_ESPATHRA) { Speed(5); Ability(ability); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SHELL_SMASH); }
|
||||
TURN { MOVE(player, MOVE_TACKLE); MOVE(opponent, MOVE_TACKLE); }
|
||||
TURN { MOVE(opponent, MOVE_TACKLE); }
|
||||
} SCENE {
|
||||
if (ability == ABILITY_FRISK) {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SHELL_SMASH, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
|
||||
HP_BAR(player, captureDamage: &results[i].damage);
|
||||
} else {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SHELL_SMASH, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
|
||||
HP_BAR(player, captureDamage: &results[i].damage);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
|
||||
}
|
||||
} FINALLY {
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12(2.0), results[1].damage);
|
||||
@@ -78,12 +78,10 @@ DOUBLE_BATTLE_TEST("Opportunist raises Attack only once when partner has Intimid
|
||||
if ((abilityLeft == ABILITY_CONTRARY && abilityRight != ABILITY_CONTRARY)
|
||||
|| (abilityLeft != ABILITY_CONTRARY && abilityRight == ABILITY_CONTRARY)) {
|
||||
ABILITY_POPUP(playerRight, ABILITY_OPPORTUNIST);
|
||||
MESSAGE("Espathra copied its opponent's stat changes!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
|
||||
MESSAGE("Espathra's Attack rose!");
|
||||
} else if (abilityLeft == ABILITY_CONTRARY && abilityRight == ABILITY_CONTRARY) {
|
||||
ABILITY_POPUP(playerRight, ABILITY_OPPORTUNIST);
|
||||
MESSAGE("Espathra copied its opponent's stat changes!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
|
||||
MESSAGE("Espathra's Attack sharply rose!");
|
||||
}
|
||||
@@ -124,6 +122,177 @@ SINGLE_BATTLE_TEST("Opportunist does not accumulate opposing mon's stat changes"
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Opportunist doesn't copy ally stat increases");
|
||||
TO_DO_BATTLE_TEST("Opportunist doesn't copy foe stat increases gained via Opportunist");
|
||||
TO_DO_BATTLE_TEST("Opportunist copies foe stat increased gained via Swagger and Flatter");
|
||||
SINGLE_BATTLE_TEST("Opportunist copies each stat increase individually from ability and move")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_ZACIAN) { Ability(ABILITY_INTREPID_SWORD); }
|
||||
OPPONENT(SPECIES_ESPATHRA) { Ability(ABILITY_OPPORTUNIST); }
|
||||
} WHEN {
|
||||
TURN { SWITCH(player, 1); }
|
||||
TURN { MOVE(player, MOVE_SWORDS_DANCE); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(player, ABILITY_INTREPID_SWORD);
|
||||
ABILITY_POPUP(opponent, ABILITY_OPPORTUNIST);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, player);
|
||||
ABILITY_POPUP(opponent, ABILITY_OPPORTUNIST);
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 3);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Opportunist doesn't copy foe stat increases gained via Opportunist")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_ESPATHRA) { Ability(ABILITY_OPPORTUNIST); }
|
||||
OPPONENT(SPECIES_ESPATHRA) { Ability(ABILITY_OPPORTUNIST); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SWORDS_DANCE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, player);
|
||||
ABILITY_POPUP(opponent, ABILITY_OPPORTUNIST);
|
||||
NOT ABILITY_POPUP(player, ABILITY_OPPORTUNIST);
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->statStages[STAT_ATK], player->statStages[STAT_ATK]);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Opportunist copies foe stat increase gained via Swagger and Flatter")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_ESPATHRA) { Ability(ABILITY_OPPORTUNIST); }
|
||||
OPPONENT(SPECIES_ESPATHRA) { Ability(ABILITY_OPPORTUNIST); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_FLATTER); }
|
||||
TURN { MOVE(opponent, MOVE_SWAGGER); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FLATTER, opponent);
|
||||
ABILITY_POPUP(opponent, ABILITY_OPPORTUNIST);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SWAGGER, opponent);
|
||||
ABILITY_POPUP(opponent, ABILITY_OPPORTUNIST);
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPATK], DEFAULT_STAT_STAGE + 1);
|
||||
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 2);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Opportunist doesn't copy ally stat increases")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_ESPATHRA) { Ability(ABILITY_OPPORTUNIST); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_SWORDS_DANCE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, playerLeft);
|
||||
NOT ABILITY_POPUP(playerRight, ABILITY_OPPORTUNIST);
|
||||
} THEN {
|
||||
EXPECT_EQ(playerRight->statStages[STAT_SPATK], DEFAULT_STAT_STAGE );
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Opportunist copies the stat increase of each opposing mon")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_ESPATHRA) { Ability(ABILITY_OPPORTUNIST); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentRight, MOVE_SWORDS_DANCE); MOVE(opponentLeft, MOVE_SWORDS_DANCE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, opponentRight);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, opponentLeft);
|
||||
ABILITY_POPUP(playerRight, ABILITY_OPPORTUNIST);
|
||||
} THEN {
|
||||
EXPECT_EQ(playerRight->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DOUBLE_BATTLE_TEST("Opportunist copies the stat of each pokemon that were raised at the same time")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_ESPATHRA) { Ability(ABILITY_OPPORTUNIST); }
|
||||
OPPONENT(SPECIES_ZACIAN) { Ability(ABILITY_INTREPID_SWORD); }
|
||||
OPPONENT(SPECIES_ZACIAN) { Ability(ABILITY_INTREPID_SWORD); }
|
||||
} WHEN {
|
||||
TURN { }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_INTREPID_SWORD);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
ABILITY_POPUP(opponentRight, ABILITY_INTREPID_SWORD);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
|
||||
ABILITY_POPUP(playerRight, ABILITY_OPPORTUNIST);
|
||||
MESSAGE("Espathra's Attack sharply rose!");
|
||||
} THEN {
|
||||
EXPECT_EQ(playerRight->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 2);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Opportunist copies the increase not the stages")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_ESPATHRA) { Ability(ABILITY_OPPORTUNIST); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_CHARM); MOVE(opponent, MOVE_CHARM); }
|
||||
TURN { MOVE(player, MOVE_CHARM); MOVE(opponent, MOVE_CHARM); }
|
||||
TURN { MOVE(player, MOVE_CHARM); MOVE(opponent, MOVE_GROWL); }
|
||||
TURN { MOVE(player, MOVE_BELLY_DRUM); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_CHARM, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_CHARM, opponent);
|
||||
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_CHARM, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_CHARM, opponent);
|
||||
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_CHARM, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_GROWL, opponent);
|
||||
|
||||
ABILITY_POPUP(opponent, ABILITY_OPPORTUNIST);
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 5); // + 11
|
||||
EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 6); // + 11
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Opportunist copies the stat increase from the incoming mon")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_ESPATHRA) { Ability(ABILITY_OPPORTUNIST); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { HP(1); }
|
||||
OPPONENT(SPECIES_ZACIAN) { Ability(ABILITY_INTREPID_SWORD); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TACKLE); SEND_OUT(opponent, 1); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
|
||||
ABILITY_POPUP(opponent, ABILITY_INTREPID_SWORD);
|
||||
ABILITY_POPUP(player, ABILITY_OPPORTUNIST);
|
||||
} THEN {
|
||||
EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Opportunist and Mirror Herb stack stat increases")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_ZACIAN) { Ability(ABILITY_INTREPID_SWORD); }
|
||||
OPPONENT(SPECIES_ESPATHRA) { Ability(ABILITY_OPPORTUNIST); Item(ITEM_MIRROR_HERB); }
|
||||
} WHEN {
|
||||
TURN { }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(player, ABILITY_INTREPID_SWORD);
|
||||
ABILITY_POPUP(opponent, ABILITY_OPPORTUNIST);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 2);
|
||||
EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPEED], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPATK], DEFAULT_STAT_STAGE);
|
||||
EXPECT_EQ(opponent->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,23 @@ SINGLE_BATTLE_TEST("Own Tempo prevents confusion from moves by the user")
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Own Tempo is ignored by Mold Breaker")
|
||||
{
|
||||
KNOWN_FAILING; // Ideally the func CanBeConfused should be split into AttackerCanBeConfused and TargetCanBeConfused or we do it in the same func but have a check for when battlerAtk == battlerDef
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_CONFUSE_RAY].effect == EFFECT_CONFUSE);
|
||||
PLAYER(SPECIES_PINSIR) { Ability(ABILITY_MOLD_BREAKER); }
|
||||
OPPONENT(SPECIES_SLOWPOKE) { Ability(ABILITY_OWN_TEMPO); };
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_CONFUSE_RAY); }
|
||||
} SCENE {
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(opponent, ABILITY_OWN_TEMPO);
|
||||
MESSAGE("Foe Slowpoke's Own Tempo prevents confusion!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Own Tempo cures confusion obtained from an opponent with Mold Breaker")
|
||||
{
|
||||
KNOWN_FAILING;
|
||||
|
||||
@@ -239,6 +239,30 @@ SINGLE_BATTLE_TEST("Parental Bond has no affect on multi hit moves and they stil
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Parental Bond Smack Down effect triggers after 2nd hit")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_SMACK_DOWN].category != DAMAGE_CATEGORY_STATUS);
|
||||
ASSUME(gMovesInfo[MOVE_SMACK_DOWN].strikeCount < 2);
|
||||
ASSUME(MoveHasAdditionalEffect(MOVE_SMACK_DOWN, MOVE_EFFECT_SMACK_DOWN));
|
||||
PLAYER(SPECIES_KANGASKHAN) { Item(ITEM_KANGASKHANITE); }
|
||||
OPPONENT(SPECIES_SKARMORY);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SMACK_DOWN, gimmick: GIMMICK_MEGA); }
|
||||
} SCENE {
|
||||
MESSAGE("Kangaskhan's Kangaskhanite is reacting to 1's Mega Ring!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_MEGA_EVOLUTION, player);
|
||||
MESSAGE("Kangaskhan has Mega Evolved into Mega Kangaskhan!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SMACK_DOWN, player);
|
||||
HP_BAR(opponent);
|
||||
NOT MESSAGE("Foe Skarmory fell straight down!");
|
||||
HP_BAR(opponent);
|
||||
MESSAGE("Foe Skarmory fell straight down!");
|
||||
} THEN {
|
||||
EXPECT_EQ(player->species, SPECIES_KANGASKHAN_MEGA);
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Parental Bond tests");
|
||||
|
||||
// Temporary TODO: Convert Bulbapedia description into tests.
|
||||
|
||||
77
test/battle/ability/poison_touch.c
Normal file
77
test/battle/ability/poison_touch.c
Normal file
@@ -0,0 +1,77 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Poison Touch has a 30% chance to poison when attacking with contact moves")
|
||||
{
|
||||
PASSES_RANDOMLY(3, 10, RNG_POISON_TOUCH);
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_TACKLE].power > 0);
|
||||
ASSUME(gMovesInfo[MOVE_TACKLE].makesContact);
|
||||
PLAYER(SPECIES_GRIMER) { Ability(ABILITY_POISON_TOUCH); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TACKLE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
|
||||
ABILITY_POPUP(player, ABILITY_POISON_TOUCH);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent);
|
||||
MESSAGE("Foe Wobbuffet was poisoned by Grimer's Poison Touch!");
|
||||
STATUS_ICON(opponent, poison: TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Poison Touch only applies when using contact moves")
|
||||
{
|
||||
u32 move;
|
||||
|
||||
PARAMETRIZE { move = MOVE_TACKLE; }
|
||||
PARAMETRIZE { move = MOVE_SWIFT; }
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_TACKLE].makesContact);
|
||||
ASSUME(!gMovesInfo[MOVE_SWIFT].makesContact);
|
||||
PLAYER(SPECIES_GRIMER) { Ability(ABILITY_POISON_TOUCH); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, move); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, player);
|
||||
if (gMovesInfo[move].makesContact) {
|
||||
ABILITY_POPUP(player, ABILITY_POISON_TOUCH);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent);
|
||||
MESSAGE("Foe Wobbuffet was poisoned by Grimer's Poison Touch!");
|
||||
STATUS_ICON(opponent, poison: TRUE);
|
||||
} else {
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(player, ABILITY_POISON_TOUCH);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent);
|
||||
MESSAGE("Foe Wobbuffet was poisoned by Grimer's Poison Touch!");
|
||||
STATUS_ICON(opponent, poison: TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Poison Touch applies between multi-hit move hits")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_ARM_THRUST].effect == EFFECT_MULTI_HIT);
|
||||
ASSUME(gMovesInfo[MOVE_ARM_THRUST].makesContact);
|
||||
ASSUME(gItemsInfo[ITEM_PECHA_BERRY].holdEffect == HOLD_EFFECT_CURE_PSN);
|
||||
PLAYER(SPECIES_GRIMER) { Ability(ABILITY_POISON_TOUCH); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_PECHA_BERRY); };
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_ARM_THRUST); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ARM_THRUST, player);
|
||||
ABILITY_POPUP(player, ABILITY_POISON_TOUCH);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent);
|
||||
MESSAGE("Foe Wobbuffet was poisoned by Grimer's Poison Touch!");
|
||||
STATUS_ICON(opponent, poison: TRUE);
|
||||
MESSAGE("Foe Wobbuffet's Pecha Berry cured poison!");
|
||||
STATUS_ICON(opponent, poison: FALSE);
|
||||
ABILITY_POPUP(player, ABILITY_POISON_TOUCH);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent);
|
||||
MESSAGE("Foe Wobbuffet was poisoned by Grimer's Poison Touch!");
|
||||
STATUS_ICON(opponent, poison: TRUE);
|
||||
}
|
||||
}
|
||||
18
test/battle/ability/sticky_hold.c
Normal file
18
test/battle/ability/sticky_hold.c
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Sticky Hold prevents item theft")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(MoveHasAdditionalEffect(MOVE_THIEF, MOVE_EFFECT_STEAL_ITEM));
|
||||
PLAYER(SPECIES_URSALUNA) { Item(ITEM_NONE); }
|
||||
OPPONENT(SPECIES_GASTRODON) { Ability(ABILITY_STICKY_HOLD); Item(ITEM_LIFE_ORB); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_THIEF); }
|
||||
} SCENE {
|
||||
MESSAGE("Ursaluna used Thief!");
|
||||
ABILITY_POPUP(opponent, ABILITY_STICKY_HOLD);
|
||||
MESSAGE("Foe Gastrodon's Sticky Hold made Thief ineffective!");
|
||||
}
|
||||
}
|
||||
|
||||
73
test/battle/ability/storm_drain.c
Normal file
73
test/battle/ability/storm_drain.c
Normal file
@@ -0,0 +1,73 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Storm Drain absorbs Water-type moves and increases the Sp. Attack [Gen5+]")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_WATER_GUN].type == TYPE_WATER);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_GASTRODON_EAST_SEA) { Ability(ABILITY_STORM_DRAIN); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_WATER_GUN); MOVE(opponent, MOVE_CELEBRATE); }
|
||||
} SCENE {
|
||||
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5) {
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, player);
|
||||
HP_BAR(opponent);
|
||||
};
|
||||
ABILITY_POPUP(opponent, ABILITY_STORM_DRAIN);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
MESSAGE("Foe Gastrodon's Sp. Atk rose!");
|
||||
} else {
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(opponent, ABILITY_STORM_DRAIN);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
MESSAGE("Foe Gastrodon's Sp. Atk rose!");
|
||||
};
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, player);
|
||||
HP_BAR(opponent);
|
||||
}
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Storm Drain forces single-target Water-type moves to target the Pokémon with this Ability.")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_WATER_GUN].type == TYPE_WATER);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_GASTRODON_EAST_SEA) { Ability(ABILITY_STORM_DRAIN); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN {
|
||||
MOVE(playerLeft, MOVE_WATER_GUN, target: opponentRight);
|
||||
MOVE(playerRight, MOVE_WATER_GUN, target: opponentRight);
|
||||
MOVE(opponentLeft, MOVE_CELEBRATE);
|
||||
MOVE(opponentRight, MOVE_CELEBRATE);
|
||||
}
|
||||
} SCENE {
|
||||
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5) {
|
||||
NONE_OF {
|
||||
HP_BAR(opponentLeft);
|
||||
HP_BAR(opponentRight);
|
||||
};
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_STORM_DRAIN);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
MESSAGE("Foe Gastrodon's Sp. Atk rose!");
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_STORM_DRAIN);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
MESSAGE("Foe Gastrodon's Sp. Atk rose!");
|
||||
} else {
|
||||
NONE_OF {
|
||||
HP_BAR(opponentRight);
|
||||
};
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, playerLeft);
|
||||
HP_BAR(opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, playerRight);
|
||||
HP_BAR(opponentLeft);
|
||||
}
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentRight);
|
||||
}
|
||||
}
|
||||
@@ -107,9 +107,9 @@ SINGLE_BATTLE_TEST("Supreme Overlord's message displays correctly after all batt
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, opponent);
|
||||
// Everyone faints.
|
||||
SEND_IN_MESSAGE("Kingambit");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
ABILITY_POPUP(player, ABILITY_SUPREME_OVERLORD);
|
||||
MESSAGE("Kingambit gained strength from the fallen!");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
128
test/battle/ability/switch_in_abilities.c
Normal file
128
test/battle/ability/switch_in_abilities.c
Normal file
@@ -0,0 +1,128 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Switch-in abilities trigger in Speed Order at the battle's start - Single Battle")
|
||||
{
|
||||
u32 spdPlayer, spdOpponent;
|
||||
|
||||
PARAMETRIZE { spdPlayer = 5; spdOpponent = 1; }
|
||||
PARAMETRIZE { spdOpponent = 5; spdPlayer = 1; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_EKANS) { Speed(spdPlayer); Ability(ABILITY_INTIMIDATE); }
|
||||
OPPONENT(SPECIES_NINETALES) { Speed(spdOpponent); Ability(ABILITY_DROUGHT); }
|
||||
} WHEN {
|
||||
TURN { ; }
|
||||
} SCENE {
|
||||
if (spdPlayer > spdOpponent) {
|
||||
ABILITY_POPUP(player, ABILITY_INTIMIDATE);
|
||||
ABILITY_POPUP(opponent, ABILITY_DROUGHT);
|
||||
} else {
|
||||
ABILITY_POPUP(opponent, ABILITY_DROUGHT);
|
||||
ABILITY_POPUP(player, ABILITY_INTIMIDATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Switch-in abilities trigger in Speed Order at the battle's start - Double Battle")
|
||||
{
|
||||
u32 spdPlayer1, spdPlayer2, spdOpponent1, spdOpponent2;
|
||||
|
||||
PARAMETRIZE { spdPlayer1 = 5; spdPlayer2 = 4; spdOpponent1 = 3; spdOpponent2 = 2; }
|
||||
PARAMETRIZE { spdPlayer1 = 2; spdPlayer2 = 3; spdOpponent1 = 4; spdOpponent2 = 5; }
|
||||
PARAMETRIZE { spdPlayer1 = 4; spdPlayer2 = 3; spdOpponent1 = 5; spdOpponent2 = 2; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_KYOGRE) { Speed(spdPlayer1); Ability(ABILITY_DRIZZLE); }
|
||||
PLAYER(SPECIES_GYARADOS) { Speed(spdPlayer2); Ability(ABILITY_INTIMIDATE); }
|
||||
OPPONENT(SPECIES_PORYGON2) { Speed(spdOpponent1); Ability(ABILITY_DOWNLOAD); }
|
||||
OPPONENT(SPECIES_PINSIR) { Speed(spdOpponent2); Ability(ABILITY_MOLD_BREAKER); }
|
||||
} WHEN {
|
||||
TURN { ; }
|
||||
} SCENE {
|
||||
if (spdPlayer1 == 5) {
|
||||
ABILITY_POPUP(playerLeft, ABILITY_DRIZZLE);
|
||||
ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE);
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_DOWNLOAD);
|
||||
ABILITY_POPUP(opponentRight, ABILITY_MOLD_BREAKER);
|
||||
} else if (spdOpponent2 == 5) {
|
||||
ABILITY_POPUP(opponentRight, ABILITY_MOLD_BREAKER);
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_DOWNLOAD);
|
||||
ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE);
|
||||
ABILITY_POPUP(playerLeft, ABILITY_DRIZZLE);
|
||||
} else {
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_DOWNLOAD);
|
||||
ABILITY_POPUP(playerLeft, ABILITY_DRIZZLE);
|
||||
ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE);
|
||||
ABILITY_POPUP(opponentRight, ABILITY_MOLD_BREAKER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Switch-in abilities trigger in Speed Order after post-KO switch - Single Battle")
|
||||
{
|
||||
u32 spdPlayer, spdOpponent;
|
||||
|
||||
PARAMETRIZE { spdPlayer = 5; spdOpponent = 1; }
|
||||
PARAMETRIZE { spdOpponent = 5; spdPlayer = 1; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(1); Speed(1); }
|
||||
PLAYER(SPECIES_EKANS) { Speed(spdPlayer); Ability(ABILITY_INTIMIDATE); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { HP(1); Speed(1); }
|
||||
OPPONENT(SPECIES_PORYGON2) { Speed(spdOpponent); Ability(ABILITY_DOWNLOAD); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_EXPLOSION); SEND_OUT(player, 1); SEND_OUT(opponent, 1); }
|
||||
TURN { ; }
|
||||
} SCENE {
|
||||
MESSAGE("Wobbuffet used Explosion!");
|
||||
if (spdPlayer > spdOpponent) {
|
||||
ABILITY_POPUP(player, ABILITY_INTIMIDATE);
|
||||
ABILITY_POPUP(opponent, ABILITY_DOWNLOAD);
|
||||
} else {
|
||||
ABILITY_POPUP(opponent, ABILITY_DOWNLOAD);
|
||||
ABILITY_POPUP(player, ABILITY_INTIMIDATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Switch-in abilities trigger in Speed Order after post-KO switch - Double Battle")
|
||||
{
|
||||
u32 spdPlayer1, spdPlayer2, spdOpponent1, spdOpponent2;
|
||||
|
||||
PARAMETRIZE { spdPlayer1 = 5; spdPlayer2 = 4; spdOpponent1 = 3; spdOpponent2 = 2; }
|
||||
PARAMETRIZE { spdPlayer1 = 2; spdPlayer2 = 3; spdOpponent1 = 4; spdOpponent2 = 5; }
|
||||
PARAMETRIZE { spdPlayer1 = 4; spdPlayer2 = 3; spdOpponent1 = 5; spdOpponent2 = 2; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(1); Speed(1); }
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(1); Speed(1); }
|
||||
PLAYER(SPECIES_TYRANITAR) { Speed(spdPlayer1); Ability(ABILITY_SAND_STREAM); }
|
||||
PLAYER(SPECIES_GYARADOS) { Speed(spdPlayer2); Ability(ABILITY_INTIMIDATE); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { HP(1); Speed(1); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { HP(1); Speed(1); }
|
||||
OPPONENT(SPECIES_WEEZING_GALARIAN) { Speed(spdOpponent1); Ability(ABILITY_MISTY_SURGE); }
|
||||
OPPONENT(SPECIES_VULPIX_ALOLAN) { Speed(spdOpponent2); Ability(ABILITY_SNOW_WARNING); }
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_EXPLOSION); SEND_OUT(playerLeft, 2); SEND_OUT(opponentLeft, 2); SEND_OUT(playerRight, 3); SEND_OUT(opponentRight, 3); }
|
||||
TURN { ; }
|
||||
} SCENE {
|
||||
MESSAGE("Wobbuffet used Explosion!");
|
||||
if (spdPlayer1 == 5) {
|
||||
ABILITY_POPUP(playerLeft, ABILITY_SAND_STREAM);
|
||||
ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE);
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_MISTY_SURGE);
|
||||
ABILITY_POPUP(opponentRight, ABILITY_SNOW_WARNING);
|
||||
} else if (spdOpponent2 == 5) {
|
||||
ABILITY_POPUP(opponentRight, ABILITY_SNOW_WARNING);
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_MISTY_SURGE);
|
||||
ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE);
|
||||
ABILITY_POPUP(playerLeft, ABILITY_SAND_STREAM);
|
||||
} else {
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_MISTY_SURGE);
|
||||
ABILITY_POPUP(playerLeft, ABILITY_SAND_STREAM);
|
||||
ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE);
|
||||
ABILITY_POPUP(opponentRight, ABILITY_SNOW_WARNING);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,9 +46,9 @@ SINGLE_BATTLE_TEST("Sword of Ruin's message displays correctly after all battler
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, opponent);
|
||||
// Everyone faints.
|
||||
MESSAGE("Go! Chien-Pao!");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
ABILITY_POPUP(player, ABILITY_SWORD_OF_RUIN);
|
||||
MESSAGE("Chien-Pao's Sword of Ruin weakened the Defense of all surrounding Pokémon!");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,9 +46,9 @@ SINGLE_BATTLE_TEST("Tablets of Ruin's message displays correctly after all battl
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, opponent);
|
||||
// Everyone faints.
|
||||
MESSAGE("Go! Wo-Chien!");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
ABILITY_POPUP(player, ABILITY_TABLETS_OF_RUIN);
|
||||
MESSAGE("Wo-Chien's Tablets of Ruin weakened the Attack of all surrounding Pokémon!");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
102
test/battle/ability/teraform_zero.c
Normal file
102
test/battle/ability/teraform_zero.c
Normal file
@@ -0,0 +1,102 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
DOUBLE_BATTLE_TEST("Teraform Zero clears weather and terrain upon activation")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_TERAPAGOS_TERASTAL);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_KYOGRE) {Ability(ABILITY_DRIZZLE); }
|
||||
OPPONENT(SPECIES_TAPU_KOKO) {Ability(ABILITY_ELECTRIC_SURGE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_CELEBRATE, gimmick: GIMMICK_TERA); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(playerLeft, ABILITY_TERAFORM_ZERO);
|
||||
MESSAGE("The rain stopped.");
|
||||
MESSAGE("The electricity disappeared from the battlefield.");
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Teraform Zero can be supressed")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_TERAPAGOS_TERASTAL);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WEEZING) {Ability(ABILITY_NEUTRALIZING_GAS); }
|
||||
OPPONENT(SPECIES_KYOGRE) {Ability(ABILITY_DRIZZLE); }
|
||||
OPPONENT(SPECIES_TAPU_KOKO) {Ability(ABILITY_ELECTRIC_SURGE); }
|
||||
} WHEN {
|
||||
TURN { SWITCH(playerRight, 2); MOVE(playerLeft, MOVE_CELEBRATE, gimmick: GIMMICK_TERA); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(playerRight, ABILITY_NEUTRALIZING_GAS);
|
||||
NONE_OF {
|
||||
MESSAGE("The rain stopped.");
|
||||
MESSAGE("The electricity disappeared from the battlefield.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Teraform Zero can be replaced")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_WORRY_SEED].effect == EFFECT_WORRY_SEED);
|
||||
ASSUME(gMovesInfo[MOVE_REST].effect == EFFECT_REST);
|
||||
PLAYER(SPECIES_TERAPAGOS);
|
||||
OPPONENT(SPECIES_WHIMSICOTT) { Ability(ABILITY_PRANKSTER); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_WORRY_SEED); MOVE(player, MOVE_REST, gimmick: GIMMICK_TERA); }
|
||||
} SCENE {
|
||||
MESSAGE("Foe Whimsicott used Worry Seed!");
|
||||
MESSAGE("Terapagos acquired Insomnia!");
|
||||
MESSAGE("Terapagos used Rest!");
|
||||
ABILITY_POPUP(player, ABILITY_INSOMNIA);
|
||||
MESSAGE("Terapagos stayed awake using its Insomnia!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Teraform Zero cannot be swapped")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_SKILL_SWAP].effect == EFFECT_SKILL_SWAP);
|
||||
PLAYER(SPECIES_TERAPAGOS);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_TERA); MOVE(opponent, MOVE_SKILL_SWAP); }
|
||||
} SCENE {
|
||||
MESSAGE("Foe Wobbuffet used Skill Swap!");
|
||||
MESSAGE("But it failed!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Teraform Zero cannot be copied")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_ROLE_PLAY].effect == EFFECT_ROLE_PLAY);
|
||||
PLAYER(SPECIES_TERAPAGOS);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_TERA); MOVE(opponent, MOVE_ROLE_PLAY); }
|
||||
} SCENE {
|
||||
MESSAGE("Foe Wobbuffet used Role Play!");
|
||||
MESSAGE("But it failed!");
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Teraform Zero shouldn't cause Neutralizing Gas to show it's popup when trying to activate")
|
||||
{
|
||||
KNOWN_FAILING; // #5010
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_TERAPAGOS_TERASTAL);
|
||||
PLAYER(SPECIES_ABSOL) {Ability(ABILITY_PRESSURE); }
|
||||
PLAYER(SPECIES_WEEZING) {Ability(ABILITY_NEUTRALIZING_GAS); }
|
||||
OPPONENT(SPECIES_KYOGRE) {Ability(ABILITY_DRIZZLE); }
|
||||
OPPONENT(SPECIES_TAPU_KOKO) {Ability(ABILITY_ELECTRIC_SURGE); }
|
||||
} WHEN {
|
||||
TURN { SWITCH(playerRight, 2); MOVE(playerLeft, MOVE_CELEBRATE, gimmick: GIMMICK_TERA); }
|
||||
} SCENE {
|
||||
MESSAGE("Terapagos is storing energy!");
|
||||
MESSAGE("Terapagos terastalized into the Stellar type!");
|
||||
NOT ABILITY_POPUP(playerRight, ABILITY_NEUTRALIZING_GAS);
|
||||
MESSAGE("Terapagos used Celebreate!");
|
||||
}
|
||||
}
|
||||
@@ -79,3 +79,20 @@ SINGLE_BATTLE_TEST("Trace will copy an opponent's ability whenever it has the ch
|
||||
MESSAGE("Ralts TRACED Foe Torchic's Blaze!");
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Trace respects the turn order")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_DEOXYS_SPEED) { Speed(40); Ability(ABILITY_PRESSURE); }
|
||||
PLAYER(SPECIES_GARDEVOIR) { Speed(20); Ability(ABILITY_TRACE); }
|
||||
OPPONENT(SPECIES_HIPPOWDON) { Speed(10); Ability(ABILITY_SAND_STREAM); }
|
||||
OPPONENT(SPECIES_DEOXYS_SPEED) { Speed(30); Ability(ABILITY_PRESSURE); }
|
||||
} WHEN {
|
||||
TURN { }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(playerLeft, ABILITY_PRESSURE);
|
||||
ABILITY_POPUP(opponentRight, ABILITY_PRESSURE);
|
||||
ABILITY_POPUP(playerRight, ABILITY_TRACE);
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_SAND_STREAM);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,9 +46,9 @@ SINGLE_BATTLE_TEST("Vessel of Ruin's message displays correctly after all battle
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, opponent);
|
||||
// Everyone faints.
|
||||
MESSAGE("Go! Ting-Lu!");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
ABILITY_POPUP(player, ABILITY_VESSEL_OF_RUIN);
|
||||
MESSAGE("Ting-Lu's Vessel of Ruin weakened the Sp. Atk of all surrounding Pokémon!");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
4
test/battle/ability/white_smoke.c
Normal file
4
test/battle/ability/white_smoke.c
Normal file
@@ -0,0 +1,4 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
// Tests for White Smoke are handled in test/battle/ability/clear_body.c
|
||||
@@ -153,9 +153,9 @@ SINGLE_BATTLE_TEST("Zero to Hero's message displays correctly after all battlers
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, opponent);
|
||||
// Everyone faints.
|
||||
SEND_IN_MESSAGE("Palafin");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
ABILITY_POPUP(player, ABILITY_ZERO_TO_HERO);
|
||||
MESSAGE("Palafin underwent a heroic transformation!");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -402,9 +402,9 @@ AI_DOUBLE_BATTLE_TEST("AI will not use Helping Hand if partner does not have any
|
||||
{
|
||||
u16 move1 = MOVE_NONE, move2 = MOVE_NONE, move3 = MOVE_NONE, move4 = MOVE_NONE;
|
||||
|
||||
PARAMETRIZE{ move1 = MOVE_LEER; move2 = MOVE_TOXIC; }
|
||||
PARAMETRIZE{ move1 = MOVE_HELPING_HAND; move2 = MOVE_PROTECT; }
|
||||
PARAMETRIZE{ move1 = MOVE_ACUPRESSURE; move2 = MOVE_DOUBLE_TEAM; move3 = MOVE_TOXIC; move4 = MOVE_PROTECT; }
|
||||
PARAMETRIZE { move1 = MOVE_LEER; move2 = MOVE_TOXIC; }
|
||||
PARAMETRIZE { move1 = MOVE_HELPING_HAND; move2 = MOVE_PROTECT; }
|
||||
PARAMETRIZE { move1 = MOVE_ACUPRESSURE; move2 = MOVE_DOUBLE_TEAM; move3 = MOVE_TOXIC; move4 = MOVE_PROTECT; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
|
||||
@@ -431,7 +431,7 @@ AI_DOUBLE_BATTLE_TEST("AI will not use a status move if partner already chose He
|
||||
for (j = MOVE_NONE + 1; j < MOVES_COUNT; j++)
|
||||
{
|
||||
if (gMovesInfo[j].category == DAMAGE_CATEGORY_STATUS) {
|
||||
PARAMETRIZE{ statusMove = j; }
|
||||
PARAMETRIZE { statusMove = j; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ AI_SINGLE_BATTLE_TEST("Choiced Pokémon switch out after using a status move onc
|
||||
|
||||
for (j = 0; j < ARRAY_COUNT(choiceItems); j++)
|
||||
{
|
||||
PARAMETRIZE{ ability = ABILITY_NONE; heldItem = choiceItems[j]; }
|
||||
PARAMETRIZE{ ability = ABILITY_KLUTZ; heldItem = choiceItems[j]; }
|
||||
PARAMETRIZE { ability = ABILITY_NONE; heldItem = choiceItems[j]; }
|
||||
PARAMETRIZE { ability = ABILITY_KLUTZ; heldItem = choiceItems[j]; }
|
||||
}
|
||||
|
||||
GIVEN {
|
||||
@@ -55,8 +55,8 @@ AI_SINGLE_BATTLE_TEST("Choiced Pokémon won't use stat boosting moves")
|
||||
|
||||
for (j = 0; j < ARRAY_COUNT(choiceItems); j++)
|
||||
{
|
||||
PARAMETRIZE{ ability = ABILITY_NONE; heldItem = choiceItems[j]; }
|
||||
PARAMETRIZE{ ability = ABILITY_KLUTZ; heldItem = choiceItems[j]; }
|
||||
PARAMETRIZE { ability = ABILITY_NONE; heldItem = choiceItems[j]; }
|
||||
PARAMETRIZE { ability = ABILITY_KLUTZ; heldItem = choiceItems[j]; }
|
||||
}
|
||||
|
||||
GIVEN {
|
||||
@@ -87,10 +87,10 @@ AI_SINGLE_BATTLE_TEST("Choiced Pokémon won't use status move if they are the on
|
||||
|
||||
for (j = 0; j < ARRAY_COUNT(choiceItems); j++)
|
||||
{
|
||||
PARAMETRIZE{ ability = ABILITY_NONE; heldItem = choiceItems[j]; isAlive = 0; }
|
||||
PARAMETRIZE{ ability = ABILITY_KLUTZ; heldItem = choiceItems[j]; isAlive = 0; }
|
||||
PARAMETRIZE{ ability = ABILITY_NONE; heldItem = choiceItems[j]; isAlive = 1; }
|
||||
PARAMETRIZE{ ability = ABILITY_KLUTZ; heldItem = choiceItems[j]; isAlive = 1; }
|
||||
PARAMETRIZE { ability = ABILITY_NONE; heldItem = choiceItems[j]; isAlive = 0; }
|
||||
PARAMETRIZE { ability = ABILITY_KLUTZ; heldItem = choiceItems[j]; isAlive = 0; }
|
||||
PARAMETRIZE { ability = ABILITY_NONE; heldItem = choiceItems[j]; isAlive = 1; }
|
||||
PARAMETRIZE { ability = ABILITY_KLUTZ; heldItem = choiceItems[j]; isAlive = 1; }
|
||||
}
|
||||
|
||||
GIVEN {
|
||||
@@ -122,10 +122,10 @@ AI_SINGLE_BATTLE_TEST("Choiced Pokémon won't use status move if they don't have
|
||||
|
||||
for (j = 0; j < ARRAY_COUNT(choiceItems); j++)
|
||||
{
|
||||
PARAMETRIZE{ ability = ABILITY_NONE; heldItem = choiceItems[j]; species = SPECIES_SWAMPERT; move = MOVE_WATERFALL; }
|
||||
PARAMETRIZE{ ability = ABILITY_KLUTZ; heldItem = choiceItems[j]; species = SPECIES_SWAMPERT; move = MOVE_WATERFALL; }
|
||||
PARAMETRIZE{ ability = ABILITY_NONE; heldItem = choiceItems[j]; species = SPECIES_ELEKID; move = MOVE_THUNDER_WAVE; }
|
||||
PARAMETRIZE{ ability = ABILITY_KLUTZ; heldItem = choiceItems[j]; species = SPECIES_ELEKID; move = MOVE_THUNDER_WAVE; }
|
||||
PARAMETRIZE { ability = ABILITY_NONE; heldItem = choiceItems[j]; species = SPECIES_SWAMPERT; move = MOVE_WATERFALL; }
|
||||
PARAMETRIZE { ability = ABILITY_KLUTZ; heldItem = choiceItems[j]; species = SPECIES_SWAMPERT; move = MOVE_WATERFALL; }
|
||||
PARAMETRIZE { ability = ABILITY_NONE; heldItem = choiceItems[j]; species = SPECIES_ELEKID; move = MOVE_THUNDER_WAVE; }
|
||||
PARAMETRIZE { ability = ABILITY_KLUTZ; heldItem = choiceItems[j]; species = SPECIES_ELEKID; move = MOVE_THUNDER_WAVE; }
|
||||
}
|
||||
|
||||
GIVEN {
|
||||
@@ -157,10 +157,10 @@ AI_SINGLE_BATTLE_TEST("Choiced Pokémon won't use status move if they are trappe
|
||||
|
||||
for (j = 0; j < ARRAY_COUNT(choiceItems); j++)
|
||||
{
|
||||
PARAMETRIZE{ aiAbility = ABILITY_NONE; heldItem = choiceItems[j]; species = SPECIES_RHYDON; playerAbility = ABILITY_LIGHTNING_ROD; }
|
||||
PARAMETRIZE{ aiAbility = ABILITY_KLUTZ; heldItem = choiceItems[j]; species = SPECIES_RHYDON; playerAbility = ABILITY_LIGHTNING_ROD; }
|
||||
PARAMETRIZE{ aiAbility = ABILITY_NONE; heldItem = choiceItems[j]; species = SPECIES_DUGTRIO; playerAbility = ABILITY_ARENA_TRAP; }
|
||||
PARAMETRIZE{ aiAbility = ABILITY_KLUTZ; heldItem = choiceItems[j]; species = SPECIES_DUGTRIO; playerAbility = ABILITY_ARENA_TRAP; }
|
||||
PARAMETRIZE { aiAbility = ABILITY_NONE; heldItem = choiceItems[j]; species = SPECIES_RHYDON; playerAbility = ABILITY_LIGHTNING_ROD; }
|
||||
PARAMETRIZE { aiAbility = ABILITY_KLUTZ; heldItem = choiceItems[j]; species = SPECIES_RHYDON; playerAbility = ABILITY_LIGHTNING_ROD; }
|
||||
PARAMETRIZE { aiAbility = ABILITY_NONE; heldItem = choiceItems[j]; species = SPECIES_DUGTRIO; playerAbility = ABILITY_ARENA_TRAP; }
|
||||
PARAMETRIZE { aiAbility = ABILITY_KLUTZ; heldItem = choiceItems[j]; species = SPECIES_DUGTRIO; playerAbility = ABILITY_ARENA_TRAP; }
|
||||
}
|
||||
|
||||
GIVEN {
|
||||
@@ -5,8 +5,8 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_RISKY: AI will blindly Mirror Coat against specia
|
||||
{
|
||||
u32 aiRiskyFlag = 0;
|
||||
|
||||
PARAMETRIZE{ aiRiskyFlag = 0; }
|
||||
PARAMETRIZE{ aiRiskyFlag = AI_FLAG_RISKY; }
|
||||
PARAMETRIZE { aiRiskyFlag = 0; }
|
||||
PARAMETRIZE { aiRiskyFlag = AI_FLAG_RISKY; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_MIRROR_COAT].effect == EFFECT_MIRROR_COAT);
|
||||
@@ -24,8 +24,8 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_RISKY: AI will blindly Counter against physical a
|
||||
{
|
||||
u32 aiRiskyFlag = 0;
|
||||
|
||||
PARAMETRIZE{ aiRiskyFlag = 0; }
|
||||
PARAMETRIZE{ aiRiskyFlag = AI_FLAG_RISKY; }
|
||||
PARAMETRIZE { aiRiskyFlag = 0; }
|
||||
PARAMETRIZE { aiRiskyFlag = AI_FLAG_RISKY; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_COUNTER].effect == EFFECT_COUNTER);
|
||||
@@ -43,8 +43,8 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_RISKY: AI will prioritize Revenge if slower")
|
||||
{
|
||||
u32 aiRiskyFlag = 0;
|
||||
|
||||
PARAMETRIZE{ aiRiskyFlag = 0; }
|
||||
PARAMETRIZE{ aiRiskyFlag = AI_FLAG_RISKY; }
|
||||
PARAMETRIZE { aiRiskyFlag = 0; }
|
||||
PARAMETRIZE { aiRiskyFlag = AI_FLAG_RISKY; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_REVENGE].effect == EFFECT_REVENGE);
|
||||
@@ -60,8 +60,8 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_RISKY: Mid-battle switches prioritize offensive o
|
||||
{
|
||||
u32 aiRiskyFlag = 0;
|
||||
|
||||
PARAMETRIZE{ aiRiskyFlag = 0; }
|
||||
PARAMETRIZE{ aiRiskyFlag = AI_FLAG_RISKY; }
|
||||
PARAMETRIZE { aiRiskyFlag = 0; }
|
||||
PARAMETRIZE { aiRiskyFlag = AI_FLAG_RISKY; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_MON_CHOICES | aiRiskyFlag);
|
||||
@@ -78,8 +78,8 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_RISKY: AI prefers high damage moves at the expens
|
||||
{
|
||||
u32 aiRiskyFlag = 0;
|
||||
|
||||
PARAMETRIZE{ aiRiskyFlag = 0; }
|
||||
PARAMETRIZE{ aiRiskyFlag = AI_FLAG_RISKY; }
|
||||
PARAMETRIZE { aiRiskyFlag = 0; }
|
||||
PARAMETRIZE { aiRiskyFlag = AI_FLAG_RISKY; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiRiskyFlag);
|
||||
129
test/battle/ai/ai_flag_sequence_switching.c
Normal file
129
test/battle/ai/ai_flag_sequence_switching.c
Normal file
@@ -0,0 +1,129 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SEQUENCE_SWITCHING: AI will always switch after a KO in exactly party order")
|
||||
{
|
||||
u32 aiSequenceSwitchingFlag = 0;
|
||||
|
||||
PARAMETRIZE { aiSequenceSwitchingFlag = 0; }
|
||||
PARAMETRIZE { aiSequenceSwitchingFlag = AI_FLAG_SEQUENCE_SWITCHING; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiSequenceSwitchingFlag);
|
||||
PLAYER(SPECIES_SWELLOW) { Level (50); }
|
||||
OPPONENT(SPECIES_MACHOP) { Level(5); }
|
||||
OPPONENT(SPECIES_MACHOKE) { Level(5); }
|
||||
OPPONENT(SPECIES_MACHAMP) { Level(5); }
|
||||
OPPONENT(SPECIES_MANKEY) { Level(5); }
|
||||
OPPONENT(SPECIES_PRIMEAPE) { Level(5); }
|
||||
OPPONENT(SPECIES_MAGNEZONE) { Level(100); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_WING_ATTACK); }
|
||||
if (aiSequenceSwitchingFlag) {
|
||||
TURN { MOVE(player, MOVE_WING_ATTACK); }
|
||||
TURN { MOVE(player, MOVE_WING_ATTACK); }
|
||||
TURN { MOVE(player, MOVE_WING_ATTACK); }
|
||||
TURN { MOVE(player, MOVE_WING_ATTACK); }
|
||||
}
|
||||
} SCENE {
|
||||
if (aiSequenceSwitchingFlag) {
|
||||
MESSAGE("{PKMN} TRAINER LEAF sent out Machoke!");
|
||||
MESSAGE("{PKMN} TRAINER LEAF sent out Machamp!");
|
||||
MESSAGE("{PKMN} TRAINER LEAF sent out Mankey!");
|
||||
MESSAGE("{PKMN} TRAINER LEAF sent out Primeape!");
|
||||
MESSAGE("{PKMN} TRAINER LEAF sent out Magnezone!");
|
||||
}
|
||||
else {
|
||||
MESSAGE("{PKMN} TRAINER LEAF sent out Magnezone!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SEQUENCE_SWITCHING: Roar and Dragon Tail still force switch to random party member")
|
||||
{
|
||||
u32 move;
|
||||
|
||||
PARAMETRIZE { move = MOVE_ROAR; }
|
||||
PARAMETRIZE {move = MOVE_DRAGON_TAIL; }
|
||||
|
||||
PASSES_RANDOMLY(1, 2, RNG_FORCE_RANDOM_SWITCH);
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_ROAR].effect == EFFECT_ROAR);
|
||||
ASSUME(gMovesInfo[MOVE_DRAGON_TAIL].effect == EFFECT_HIT_SWITCH_TARGET);
|
||||
AI_FLAGS(AI_FLAG_SEQUENCE_SWITCHING);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_BULBASAUR);
|
||||
OPPONENT(SPECIES_CHARMANDER);
|
||||
OPPONENT(SPECIES_SQUIRTLE) { HP(0); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, move); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, player);
|
||||
MESSAGE("Foe Bulbasaur was dragged out!");
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SEQUENCE_SWITCHING: AI will always switch into lowest party index after U-Turn, Parting Shot, and Baton Pass")
|
||||
{
|
||||
u32 j, aiSequenceSwitchingFlag = 0, move = MOVE_NONE;
|
||||
|
||||
static const u32 switchMoves[] = {
|
||||
MOVE_U_TURN,
|
||||
MOVE_PARTING_SHOT,
|
||||
MOVE_BATON_PASS,
|
||||
};
|
||||
|
||||
for (j = 0; j < ARRAY_COUNT(switchMoves); j++)
|
||||
{
|
||||
PARAMETRIZE { aiSequenceSwitchingFlag = 0; move = switchMoves[j]; }
|
||||
PARAMETRIZE { aiSequenceSwitchingFlag = AI_FLAG_SEQUENCE_SWITCHING; move = switchMoves[j]; }
|
||||
}
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_U_TURN].effect == EFFECT_HIT_ESCAPE);
|
||||
ASSUME(gMovesInfo[MOVE_PARTING_SHOT].effect == EFFECT_PARTING_SHOT);
|
||||
ASSUME(gMovesInfo[MOVE_BATON_PASS].effect == EFFECT_BATON_PASS);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiSequenceSwitchingFlag);
|
||||
PLAYER(SPECIES_SWELLOW) { Level (50); }
|
||||
OPPONENT(SPECIES_MACHOP) { Level(1); Moves(move); }
|
||||
OPPONENT(SPECIES_MACHOP) { Level(2); Moves(move); }
|
||||
OPPONENT(SPECIES_MACHOP) { Level(3); Moves(move); }
|
||||
OPPONENT(SPECIES_MACHOP) { Level(4); Moves(move); }
|
||||
OPPONENT(SPECIES_MACHOP) { Level(5); Moves(move); }
|
||||
OPPONENT(SPECIES_MAGNEZONE) { Level(100); Moves(move); }
|
||||
} WHEN {
|
||||
if (aiSequenceSwitchingFlag) {
|
||||
TURN { EXPECT_MOVE(opponent, move) ; EXPECT_SEND_OUT(opponent, 1); }
|
||||
TURN { EXPECT_MOVE(opponent, move) ; EXPECT_SEND_OUT(opponent, 0); }
|
||||
TURN { EXPECT_MOVE(opponent, move) ; EXPECT_SEND_OUT(opponent, 1); }
|
||||
TURN { EXPECT_MOVE(opponent, move) ; EXPECT_SEND_OUT(opponent, 0); }
|
||||
TURN { EXPECT_MOVE(opponent, move) ; EXPECT_SEND_OUT(opponent, 1); }
|
||||
}
|
||||
else {
|
||||
TURN { EXPECT_MOVE(opponent, move) ; EXPECT_SEND_OUT(opponent, 5); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SEQUENCE_SWITCHING: AI will not switch mid-battle")
|
||||
{
|
||||
u32 aiSequenceSwitchingFlag = 0;
|
||||
|
||||
PARAMETRIZE { aiSequenceSwitchingFlag = 0; }
|
||||
PARAMETRIZE { aiSequenceSwitchingFlag = AI_FLAG_SEQUENCE_SWITCHING; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiSequenceSwitchingFlag);
|
||||
PLAYER(SPECIES_ZIGZAGOON) { Moves(MOVE_LICK); }
|
||||
OPPONENT(SPECIES_GASTLY) { Moves(MOVE_SHADOW_BALL); }
|
||||
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_KARATE_CHOP); }
|
||||
} WHEN {
|
||||
if (aiSequenceSwitchingFlag == AI_FLAG_SEQUENCE_SWITCHING) {
|
||||
TURN { MOVE(player, MOVE_LICK) ; EXPECT_MOVE(opponent, MOVE_SHADOW_BALL); }
|
||||
}
|
||||
else {
|
||||
TURN { MOVE(player, MOVE_LICK) ; EXPECT_SWITCH(opponent, 1); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,6 +67,19 @@ AI_DOUBLE_BATTLE_TEST("AI will not try to switch for the same pokemon for 2 spot
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: U-Turn will send out Ace Mon if it's the only one remaining")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_U_TURN].effect == EFFECT_HIT_ESCAPE);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_ACE_POKEMON);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_U_TURN); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { EXPECT_MOVE(opponent, MOVE_U_TURN); EXPECT_SEND_OUT(opponent, 1); }
|
||||
}
|
||||
}
|
||||
|
||||
// General AI_FLAG_SMART_MON_CHOICES behaviour
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Number of hits to KO calculation checks whether incoming damage is less than recurring healing to avoid an infinite loop")
|
||||
{
|
||||
@@ -127,9 +140,9 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: AI will not switch in a Pokemo
|
||||
u32 speedAlakazm;
|
||||
u32 aiSmartSwitchFlags = 0;
|
||||
|
||||
PARAMETRIZE{ speedAlakazm = 200; alakazamFirst = TRUE; } // AI will always send out Alakazan as it sees a KO with Focus Blast, even if Alakazam dies before it can get it off
|
||||
PARAMETRIZE{ speedAlakazm = 200; alakazamFirst = FALSE; aiSmartSwitchFlags = AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES; } // AI_FLAG_SMART_MON_CHOICES lets AI see that Alakazam would be KO'd before it can KO, and won't switch it in
|
||||
PARAMETRIZE{ speedAlakazm = 400; alakazamFirst = TRUE; aiSmartSwitchFlags = AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES; } // AI_FLAG_SMART_MON_CHOICES recognizes that Alakazam is faster and can KO, and will switch it in
|
||||
PARAMETRIZE { speedAlakazm = 200; alakazamFirst = TRUE; } // AI will always send out Alakazan as it sees a KO with Focus Blast, even if Alakazam dies before it can get it off
|
||||
PARAMETRIZE { speedAlakazm = 200; alakazamFirst = FALSE; aiSmartSwitchFlags = AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES; } // AI_FLAG_SMART_MON_CHOICES lets AI see that Alakazam would be KO'd before it can KO, and won't switch it in
|
||||
PARAMETRIZE { speedAlakazm = 400; alakazamFirst = TRUE; aiSmartSwitchFlags = AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES; } // AI_FLAG_SMART_MON_CHOICES recognizes that Alakazam is faster and can KO, and will switch it in
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_PSYCHIC].category == DAMAGE_CATEGORY_SPECIAL);
|
||||
@@ -159,8 +172,8 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: AI considers hazard damage whe
|
||||
u32 aiIsSmart = 0;
|
||||
u32 aiSmartSwitchFlags = 0;
|
||||
|
||||
PARAMETRIZE{ aiIsSmart = 0; aiSmartSwitchFlags = 0; } // AI doesn't care about hazard damage resulting in Pokemon being KO'd
|
||||
PARAMETRIZE{ aiIsSmart = 1; aiSmartSwitchFlags = AI_FLAG_SMART_MON_CHOICES; } // AI_FLAG_SMART_MON_CHOICES avoids being KO'd as a result of hazards damage
|
||||
PARAMETRIZE { aiIsSmart = 0; aiSmartSwitchFlags = 0; } // AI doesn't care about hazard damage resulting in Pokemon being KO'd
|
||||
PARAMETRIZE { aiIsSmart = 1; aiSmartSwitchFlags = AI_FLAG_SMART_MON_CHOICES; } // AI_FLAG_SMART_MON_CHOICES avoids being KO'd as a result of hazards damage
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiSmartSwitchFlags);
|
||||
@@ -181,10 +194,10 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Mid-battle switches prioritize
|
||||
u32 move2;
|
||||
u32 expectedIndex;
|
||||
|
||||
PARAMETRIZE{ expectedIndex = 3; move1 = MOVE_TACKLE; move2 = MOVE_TACKLE; aiSmartSwitchFlags = 0; } // When not smart, AI will only switch in a defensive mon if it has a SE move, otherwise will just default to damage
|
||||
PARAMETRIZE{ expectedIndex = 1; move1 = MOVE_GIGA_DRAIN; move2 = MOVE_TACKLE; aiSmartSwitchFlags = 0; }
|
||||
PARAMETRIZE{ expectedIndex = 2; move1 = MOVE_TACKLE; move2 = MOVE_TACKLE; aiSmartSwitchFlags = AI_FLAG_SMART_MON_CHOICES; } // When smart, AI will prioritize SE move, but still switch in good type matchup without SE move
|
||||
PARAMETRIZE{ expectedIndex = 1; move1 = MOVE_GIGA_DRAIN; move2 = MOVE_TACKLE; aiSmartSwitchFlags = AI_FLAG_SMART_MON_CHOICES; }
|
||||
PARAMETRIZE { expectedIndex = 3; move1 = MOVE_TACKLE; move2 = MOVE_TACKLE; aiSmartSwitchFlags = 0; } // When not smart, AI will only switch in a defensive mon if it has a SE move, otherwise will just default to damage
|
||||
PARAMETRIZE { expectedIndex = 1; move1 = MOVE_GIGA_DRAIN; move2 = MOVE_TACKLE; aiSmartSwitchFlags = 0; }
|
||||
PARAMETRIZE { expectedIndex = 2; move1 = MOVE_TACKLE; move2 = MOVE_TACKLE; aiSmartSwitchFlags = AI_FLAG_SMART_MON_CHOICES; } // When smart, AI will prioritize SE move, but still switch in good type matchup without SE move
|
||||
PARAMETRIZE { expectedIndex = 1; move1 = MOVE_GIGA_DRAIN; move2 = MOVE_TACKLE; aiSmartSwitchFlags = AI_FLAG_SMART_MON_CHOICES; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiSmartSwitchFlags);
|
||||
@@ -257,8 +270,8 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will not switch out if Pokemo
|
||||
{
|
||||
u32 move1;
|
||||
|
||||
PARAMETRIZE{ move1 = MOVE_TACKLE; }
|
||||
PARAMETRIZE{ move1 = MOVE_RAPID_SPIN; }
|
||||
PARAMETRIZE { move1 = MOVE_TACKLE; }
|
||||
PARAMETRIZE { move1 = MOVE_RAPID_SPIN; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL);
|
||||
@@ -153,3 +153,26 @@ SINGLE_BATTLE_TEST("Regular Mega Evolution and Fervent Wish Mega Evolution can h
|
||||
EXPECT_EQ(opponent->species, SPECIES_GARDEVOIR_MEGA);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Mega Evolved Pokemon do not change abilities after fainting")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_CRUNCH].makesContact == TRUE);
|
||||
ASSUME(gSpeciesInfo[SPECIES_GARCHOMP_MEGA].abilities[0] != ABILITY_ROUGH_SKIN);
|
||||
ASSUME(gSpeciesInfo[SPECIES_GARCHOMP_MEGA].abilities[1] != ABILITY_ROUGH_SKIN);
|
||||
ASSUME(gSpeciesInfo[SPECIES_GARCHOMP_MEGA].abilities[2] != ABILITY_ROUGH_SKIN);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_GARCHOMP) { Ability(ABILITY_ROUGH_SKIN); Item(ITEM_GARCHOMPITE); HP(1); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_CRUNCH); MOVE(opponent, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_MEGA_EVOLUTION, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_CRUNCH, player);
|
||||
MESSAGE("Foe Garchomp fainted!");
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(opponent, ABILITY_ROUGH_SKIN);
|
||||
MESSAGE("Wobbuffet was hurt by Foe Garchomp's Rough Skin!");
|
||||
HP_BAR(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ SINGLE_BATTLE_TEST("Shaymin-Sky reverts to Shaymin-Land when frozen or frostbitt
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
if (move == MOVE_POWDER_SNOW) {
|
||||
STATUS_ICON(player, freeze: TRUE);
|
||||
FREEZE_OR_FROSTBURN_STATUS(player, TRUE);
|
||||
NOT HP_BAR(player); // Regression caused by Mimikyu form change
|
||||
MESSAGE("Shaymin transformed!");
|
||||
} else {
|
||||
|
||||
@@ -762,6 +762,89 @@ SINGLE_BATTLE_TEST("(TERA) Stellar type's one-time boost factors in dynamically-
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("(TERA) Terapagos retains the Stellar type boost at all times")
|
||||
{
|
||||
s16 damage[2];
|
||||
u32 move;
|
||||
PARAMETRIZE { move = MOVE_TACKLE; }
|
||||
PARAMETRIZE { move = MOVE_MACH_PUNCH; }
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_TACKLE].type == TYPE_NORMAL);
|
||||
ASSUME(gMovesInfo[MOVE_MACH_PUNCH].type != TYPE_NORMAL);
|
||||
PLAYER(SPECIES_TERAPAGOS);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, move, gimmick: GIMMICK_TERA); }
|
||||
TURN { MOVE(player, move); }
|
||||
} SCENE {
|
||||
HP_BAR(opponent, captureDamage: &damage[0]);
|
||||
HP_BAR(opponent, captureDamage: &damage[1]);
|
||||
} THEN {
|
||||
EXPECT_EQ(damage[0], damage[1]);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("(TERA) Terapagos retains its base defensive profile when Terastalizing")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_TERAPAGOS);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_TERA); MOVE(opponent, MOVE_BRICK_BREAK); }
|
||||
} SCENE {
|
||||
MESSAGE("It's super effective!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("(TERA) Illusion breaks if the pokemon Terastalizes")
|
||||
{
|
||||
KNOWN_FAILING; // #5015
|
||||
u32 species;
|
||||
PARAMETRIZE { species = SPECIES_TERAPAGOS; }
|
||||
PARAMETRIZE { species = SPECIES_WOBBUFFET; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_ZOROARK) { TeraType(TYPE_DARK); }
|
||||
PLAYER(species);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_TERA); }
|
||||
} SCENE {
|
||||
MESSAGE("Zoroark's Illusion wore off!");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// This test freezes the emulator
|
||||
SINGLE_BATTLE_TEST("(TERA) Transformed pokemon can't Terastalize")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_DITTO);
|
||||
OPPONENT(SPECIES_TERAPAGOS) { Moves(MOVE_CELEBRATE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TRANSFORM); }
|
||||
TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_TERA); }
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
SINGLE_BATTLE_TEST("(TERA) Pokemon with Tera forms change upon Terastallizing")
|
||||
{
|
||||
u32 species, targetSpecies;
|
||||
PARAMETRIZE { species = SPECIES_OGERPON_TEAL_MASK; targetSpecies = SPECIES_OGERPON_TEAL_MASK_TERA; }
|
||||
PARAMETRIZE { species = SPECIES_OGERPON_WELLSPRING_MASK; targetSpecies = SPECIES_OGERPON_WELLSPRING_MASK_TERA; }
|
||||
PARAMETRIZE { species = SPECIES_OGERPON_HEARTHFLAME_MASK; targetSpecies = SPECIES_OGERPON_HEARTHFLAME_MASK_TERA; }
|
||||
PARAMETRIZE { species = SPECIES_OGERPON_CORNERSTONE_MASK; targetSpecies = SPECIES_OGERPON_CORNERSTONE_MASK_TERA; }
|
||||
PARAMETRIZE { species = SPECIES_TERAPAGOS_TERASTAL; targetSpecies = SPECIES_TERAPAGOS_STELLAR; }
|
||||
GIVEN {
|
||||
PLAYER(species);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_TERA); }
|
||||
} THEN {
|
||||
EXPECT_EQ(player->species, targetSpecies);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("(TERA) All type indicators function correctly")
|
||||
{
|
||||
u32 type;
|
||||
@@ -794,20 +877,34 @@ SINGLE_BATTLE_TEST("(TERA) All type indicators function correctly")
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("(TERA) Pokemon with Tera forms change upon Terastallizing")
|
||||
SINGLE_BATTLE_TEST("(TERA) All type indicators function correctly - Opponent")
|
||||
{
|
||||
u32 species, targetSpecies;
|
||||
PARAMETRIZE { species = SPECIES_OGERPON_TEAL_MASK; targetSpecies = SPECIES_OGERPON_TEAL_MASK_TERA; }
|
||||
PARAMETRIZE { species = SPECIES_OGERPON_WELLSPRING_MASK; targetSpecies = SPECIES_OGERPON_WELLSPRING_MASK_TERA; }
|
||||
PARAMETRIZE { species = SPECIES_OGERPON_HEARTHFLAME_MASK; targetSpecies = SPECIES_OGERPON_HEARTHFLAME_MASK_TERA; }
|
||||
PARAMETRIZE { species = SPECIES_OGERPON_CORNERSTONE_MASK; targetSpecies = SPECIES_OGERPON_CORNERSTONE_MASK_TERA; }
|
||||
PARAMETRIZE { species = SPECIES_TERAPAGOS_TERASTAL; targetSpecies = SPECIES_TERAPAGOS_STELLAR; }
|
||||
u32 type;
|
||||
PARAMETRIZE { type = TYPE_NONE; }
|
||||
PARAMETRIZE { type = TYPE_NORMAL; }
|
||||
PARAMETRIZE { type = TYPE_FIGHTING; }
|
||||
PARAMETRIZE { type = TYPE_FLYING; }
|
||||
PARAMETRIZE { type = TYPE_POISON; }
|
||||
PARAMETRIZE { type = TYPE_GROUND; }
|
||||
PARAMETRIZE { type = TYPE_ROCK; }
|
||||
PARAMETRIZE { type = TYPE_BUG; }
|
||||
PARAMETRIZE { type = TYPE_GHOST; }
|
||||
PARAMETRIZE { type = TYPE_STEEL; }
|
||||
PARAMETRIZE { type = TYPE_MYSTERY; }
|
||||
PARAMETRIZE { type = TYPE_FIRE; }
|
||||
PARAMETRIZE { type = TYPE_WATER; }
|
||||
PARAMETRIZE { type = TYPE_GRASS; }
|
||||
PARAMETRIZE { type = TYPE_ELECTRIC; }
|
||||
PARAMETRIZE { type = TYPE_PSYCHIC; }
|
||||
PARAMETRIZE { type = TYPE_ICE; }
|
||||
PARAMETRIZE { type = TYPE_DRAGON; }
|
||||
PARAMETRIZE { type = TYPE_DARK; }
|
||||
PARAMETRIZE { type = TYPE_FAIRY; }
|
||||
PARAMETRIZE { type = TYPE_STELLAR; }
|
||||
GIVEN {
|
||||
PLAYER(species);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { TeraType(type); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_TERA); }
|
||||
} THEN {
|
||||
EXPECT_EQ(player->species, targetSpecies);
|
||||
TURN { MOVE(opponent, MOVE_CELEBRATE, gimmick: GIMMICK_TERA); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ SINGLE_BATTLE_TEST("Rawst and Lum Berries cure burn")
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Aspear and Lum Berries cure freeze")
|
||||
SINGLE_BATTLE_TEST("Aspear and Lum Berries cure freeze or frostbite")
|
||||
{
|
||||
u16 item;
|
||||
|
||||
@@ -88,9 +88,9 @@ SINGLE_BATTLE_TEST("Aspear and Lum Berries cure freeze")
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ICE_PUNCH, player);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_FRZ, opponent);
|
||||
STATUS_ICON(opponent, freeze: TRUE);
|
||||
FREEZE_OR_FROSTBURN_STATUS(opponent, TRUE);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
|
||||
STATUS_ICON(opponent, freeze: FALSE);
|
||||
FREEZE_OR_FROSTBURN_STATUS(opponent, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,12 +163,12 @@ SINGLE_BATTLE_TEST("Berry hold effect cures status if a pokemon enters a battle"
|
||||
u16 status;
|
||||
u16 item;
|
||||
|
||||
PARAMETRIZE{ status = STATUS1_BURN; item = ITEM_RAWST_BERRY; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; item = ITEM_ASPEAR_BERRY; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; item = ITEM_CHERI_BERRY; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; item = ITEM_PECHA_BERRY; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; item = ITEM_PECHA_BERRY; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; item = ITEM_CHESTO_BERRY; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; item = ITEM_RAWST_BERRY; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; item = ITEM_ASPEAR_BERRY; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; item = ITEM_CHERI_BERRY; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; item = ITEM_PECHA_BERRY; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; item = ITEM_PECHA_BERRY; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; item = ITEM_CHESTO_BERRY; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_RAWST_BERRY].holdEffect == HOLD_EFFECT_CURE_BRN);
|
||||
|
||||
@@ -73,3 +73,18 @@ DOUBLE_BATTLE_TEST("Mirror Herb does not trigger for Ally's Soul Heart's stat ra
|
||||
EXPECT_EQ(playerLeft->statStages[STAT_SPATK], DEFAULT_STAT_STAGE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Mirror Herb copies the boost gained by an ability")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_ZACIAN) { Ability(ABILITY_INTREPID_SWORD); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_MIRROR_HERB); }
|
||||
} WHEN {
|
||||
TURN { }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(player, ABILITY_INTREPID_SWORD);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,12 +112,12 @@ SINGLE_BATTLE_TEST("Ice Heal heals a battler from being frozen")
|
||||
SINGLE_BATTLE_TEST("Full Heal heals a battler from any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_FULL_HEAL].battleUsage == EFFECT_ITEM_CURE_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(status); }
|
||||
@@ -134,12 +134,12 @@ SINGLE_BATTLE_TEST("Full Heal heals a battler from any primary status")
|
||||
SINGLE_BATTLE_TEST("Heal Powder heals a battler from any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_HEAL_POWDER].battleUsage == EFFECT_ITEM_CURE_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(status); }
|
||||
@@ -156,12 +156,12 @@ SINGLE_BATTLE_TEST("Heal Powder heals a battler from any primary status")
|
||||
SINGLE_BATTLE_TEST("Pewter Crunchies heals a battler from any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_PEWTER_CRUNCHIES].battleUsage == EFFECT_ITEM_CURE_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(status); }
|
||||
@@ -178,12 +178,12 @@ SINGLE_BATTLE_TEST("Pewter Crunchies heals a battler from any primary status")
|
||||
SINGLE_BATTLE_TEST("Lava Cookies heals a battler from any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_LAVA_COOKIE].battleUsage == EFFECT_ITEM_CURE_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(status); }
|
||||
@@ -200,12 +200,12 @@ SINGLE_BATTLE_TEST("Lava Cookies heals a battler from any primary status")
|
||||
SINGLE_BATTLE_TEST("Rage Candy Bar heals a battler from any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_RAGE_CANDY_BAR].battleUsage == EFFECT_ITEM_CURE_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(status); }
|
||||
@@ -222,12 +222,12 @@ SINGLE_BATTLE_TEST("Rage Candy Bar heals a battler from any primary status")
|
||||
SINGLE_BATTLE_TEST("Old Gateu heals a battler from any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_OLD_GATEAU].battleUsage == EFFECT_ITEM_CURE_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(status); }
|
||||
@@ -244,12 +244,12 @@ SINGLE_BATTLE_TEST("Old Gateu heals a battler from any primary status")
|
||||
SINGLE_BATTLE_TEST("Casteliacone heals a battler from any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_CASTELIACONE].battleUsage == EFFECT_ITEM_CURE_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(status); }
|
||||
@@ -266,12 +266,12 @@ SINGLE_BATTLE_TEST("Casteliacone heals a battler from any primary status")
|
||||
SINGLE_BATTLE_TEST("Lumiose Galette heals a battler from any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_LUMIOSE_GALETTE].battleUsage == EFFECT_ITEM_CURE_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(status); }
|
||||
@@ -288,12 +288,12 @@ SINGLE_BATTLE_TEST("Lumiose Galette heals a battler from any primary status")
|
||||
SINGLE_BATTLE_TEST("Shalour Sable heals a battler from any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_SHALOUR_SABLE].battleUsage == EFFECT_ITEM_CURE_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(status); }
|
||||
@@ -310,12 +310,12 @@ SINGLE_BATTLE_TEST("Shalour Sable heals a battler from any primary status")
|
||||
SINGLE_BATTLE_TEST("Big Malasada heals a battler from any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_BIG_MALASADA].battleUsage == EFFECT_ITEM_CURE_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(status); }
|
||||
|
||||
@@ -9,13 +9,13 @@ ASSUMPTIONS
|
||||
SINGLE_BATTLE_TEST("Full Restore restores a battler's HP and cures any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE{ status = STATUS1_NONE; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_NONE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(1); MaxHP(300); Status1(status); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
@@ -35,13 +35,13 @@ SINGLE_BATTLE_TEST("Full Restore restores a battler's HP and cures any primary s
|
||||
SINGLE_BATTLE_TEST("Full Restore restores a party members HP and cures any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE{ status = STATUS1_NONE; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_NONE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(1); MaxHP(300); Status1(status); }
|
||||
PLAYER(SPECIES_WYNAUT) { HP(1); MaxHP(300); Status1(status); }
|
||||
@@ -64,12 +64,12 @@ SINGLE_BATTLE_TEST("Full Restore restores a party members HP and cures any prima
|
||||
SINGLE_BATTLE_TEST("Full Restore heals a battler from any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(status); }
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
@@ -86,12 +86,12 @@ SINGLE_BATTLE_TEST("Full Restore heals a battler from any primary status")
|
||||
SINGLE_BATTLE_TEST("Full Restore heals a party member from any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WYNAUT) { Status1(status); }
|
||||
|
||||
@@ -1,5 +1,48 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("Acrobatics doubles in power if the user has no held item");
|
||||
TO_DO_BATTLE_TEST("Acrobatics still doubles in power when Flying Gem is consumed");
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(gMovesInfo[MOVE_ACROBATICS].effect == EFFECT_ACROBATICS);
|
||||
ASSUME(gMovesInfo[MOVE_ACROBATICS].type == TYPE_FLYING);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Acrobatics doubles in power if the user has no held item", s16 damage)
|
||||
{
|
||||
u16 heldItem;
|
||||
PARAMETRIZE { heldItem = ITEM_POTION; }
|
||||
PARAMETRIZE { heldItem = ITEM_NONE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Item(heldItem); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_ACROBATICS); }
|
||||
} SCENE {
|
||||
HP_BAR(player, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12(2), results[1].damage);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Acrobatics still doubles in power when Flying Gem is consumed", s16 damage)
|
||||
{
|
||||
u16 heldItem;
|
||||
PARAMETRIZE { heldItem = ITEM_NONE; }
|
||||
PARAMETRIZE { heldItem = ITEM_FLYING_GEM; }
|
||||
GIVEN {
|
||||
ASSUME(I_GEM_BOOST_POWER >= GEN_6);
|
||||
ASSUME(gItemsInfo[ITEM_FLYING_GEM].holdEffect == HOLD_EFFECT_GEMS);
|
||||
ASSUME(gItemsInfo[ITEM_FLYING_GEM].secondaryId == TYPE_FLYING);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Item(heldItem); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_ACROBATICS); }
|
||||
} SCENE {
|
||||
HP_BAR(player, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
if (I_GEM_BOOST_POWER >= GEN_6)
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.3), (results[1].damage));
|
||||
else
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), (results[1].damage));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,18 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("Hone Claws increases Attack and Accuracy by one stage each");
|
||||
SINGLE_BATTLE_TEST("Hone Claws increases Attack and Accuracy by one stage each")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_HONE_CLAWS].effect == EFFECT_ATTACK_ACCURACY_UP);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_HONE_CLAWS); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_HONE_CLAWS, player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
MESSAGE("Wobbuffet's Attack rose!");
|
||||
MESSAGE("Wobbuffet's accuracy rose!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@ ASSUMPTIONS
|
||||
SINGLE_BATTLE_TEST("Aura Wheel raises Speed; fails if the user is not Morpeko")
|
||||
{
|
||||
u16 species;
|
||||
PARAMETRIZE{ species = SPECIES_WOBBUFFET; }
|
||||
PARAMETRIZE{ species = SPECIES_MORPEKO; }
|
||||
PARAMETRIZE { species = SPECIES_WOBBUFFET; }
|
||||
PARAMETRIZE { species = SPECIES_MORPEKO; }
|
||||
GIVEN {
|
||||
PLAYER(species);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
|
||||
@@ -253,8 +253,8 @@ SINGLE_BATTLE_TEST("Embargo disables the effect of the Plate items on the move J
|
||||
{
|
||||
u32 heldItem;
|
||||
|
||||
PARAMETRIZE{ heldItem = ITEM_NONE; }
|
||||
PARAMETRIZE{ heldItem = ITEM_PIXIE_PLATE; }
|
||||
PARAMETRIZE { heldItem = ITEM_NONE; }
|
||||
PARAMETRIZE { heldItem = ITEM_PIXIE_PLATE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_ARCEUS) { Item(heldItem); };
|
||||
OPPONENT(SPECIES_DRAGONITE);
|
||||
@@ -274,8 +274,8 @@ SINGLE_BATTLE_TEST("Embargo disables the effect of the Drive items on the move T
|
||||
{
|
||||
u32 heldItem;
|
||||
|
||||
PARAMETRIZE{ heldItem = ITEM_NONE; }
|
||||
PARAMETRIZE{ heldItem = ITEM_SHOCK_DRIVE; }
|
||||
PARAMETRIZE { heldItem = ITEM_NONE; }
|
||||
PARAMETRIZE { heldItem = ITEM_SHOCK_DRIVE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_GENESECT) { Item(heldItem); };
|
||||
OPPONENT(SPECIES_GYARADOS);
|
||||
@@ -295,8 +295,8 @@ SINGLE_BATTLE_TEST("Embargo disables the effect of the Memory items on the move
|
||||
{
|
||||
u32 heldItem;
|
||||
|
||||
PARAMETRIZE{ heldItem = ITEM_NONE; }
|
||||
PARAMETRIZE{ heldItem = ITEM_FIRE_MEMORY; }
|
||||
PARAMETRIZE { heldItem = ITEM_NONE; }
|
||||
PARAMETRIZE { heldItem = ITEM_FIRE_MEMORY; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_SILVALLY) { Item(heldItem); };
|
||||
OPPONENT(SPECIES_VENUSAUR);
|
||||
|
||||
24
test/battle/move_effect/flame_burst.c
Normal file
24
test/battle/move_effect/flame_burst.c
Normal file
@@ -0,0 +1,24 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(gMovesInfo[MOVE_FLAME_BURST].additionalEffects->moveEffect == MOVE_EFFECT_FLAME_BURST);
|
||||
}
|
||||
|
||||
// Flame Burst AoE is supposed to hit through Substitute
|
||||
DOUBLE_BATTLE_TEST("Flame Burst Substitute")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_SUBSTITUTE].effect == EFFECT_SUBSTITUTE);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentLeft, MOVE_SUBSTITUTE); MOVE(playerRight, MOVE_FLAME_BURST, target: opponentRight); }
|
||||
} SCENE {
|
||||
MESSAGE("The bursting flames hit Foe Wynaut!");
|
||||
NOT MESSAGE("The SUBSTITUTE took damage for Foe Wynaut!");
|
||||
}
|
||||
}
|
||||
@@ -74,3 +74,28 @@ DOUBLE_BATTLE_TEST("Focus Punch activation is based on Speed")
|
||||
MESSAGE("Foe Wobbuffet lost its focus and couldn't move!");
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI won't use Focus Punch if it predicts a damaging move")
|
||||
{
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
|
||||
PLAYER(SPECIES_MAGNEZONE) { Moves(MOVE_THUNDER_WAVE, MOVE_FLASH_CANNON, MOVE_DISCHARGE, MOVE_TRI_ATTACK); }
|
||||
OPPONENT(SPECIES_BRELOOM) { Moves(MOVE_FOCUS_PUNCH, MOVE_SEED_BOMB); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_DISCHARGE); EXPECT_MOVE(opponent, MOVE_FOCUS_PUNCH); }
|
||||
TURN { MOVE(player, MOVE_DISCHARGE); EXPECT_MOVE(opponent, MOVE_SEED_BOMB); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI will Incapacitate -> Substitute -> Focus Punch if able")
|
||||
{
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
|
||||
PLAYER(SPECIES_MAGNEZONE) { Moves(MOVE_THUNDER_WAVE, MOVE_FLASH_CANNON, MOVE_DISCHARGE, MOVE_TRI_ATTACK); }
|
||||
OPPONENT(SPECIES_BRELOOM) { Moves(MOVE_SPORE, MOVE_FOCUS_PUNCH, MOVE_SUBSTITUTE, MOVE_SEED_BOMB); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_DISCHARGE); EXPECT_MOVE(opponent, MOVE_SPORE); }
|
||||
TURN { MOVE(player, MOVE_DISCHARGE); EXPECT_MOVE(opponent, MOVE_SUBSTITUTE); }
|
||||
TURN { MOVE(player, MOVE_DISCHARGE); EXPECT_MOVE(opponent, MOVE_FOCUS_PUNCH); }
|
||||
}
|
||||
}
|
||||
|
||||
38
test/battle/move_effect/fury_cutter.c
Normal file
38
test/battle/move_effect/fury_cutter.c
Normal file
@@ -0,0 +1,38 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(gMovesInfo[MOVE_FURY_CUTTER].effect == EFFECT_FURY_CUTTER);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Fury Cutter power doubles with each use, up to 160 power")
|
||||
{
|
||||
s16 damage[6];
|
||||
int turn;
|
||||
int maxTurns;
|
||||
|
||||
if (B_UPDATED_MOVE_DATA >= GEN_6)
|
||||
maxTurns = 4;
|
||||
else if (B_UPDATED_MOVE_DATA == GEN_5)
|
||||
maxTurns = 5;
|
||||
else
|
||||
maxTurns = 6;
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_CROBAT);
|
||||
OPPONENT(SPECIES_LINOONE) { HP(900); }
|
||||
} WHEN {
|
||||
for (turn = 0; turn < maxTurns; turn++)
|
||||
TURN { MOVE(player, MOVE_FURY_CUTTER); }
|
||||
} SCENE {
|
||||
for (turn = 0; turn < maxTurns; turn++) {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FURY_CUTTER, player);
|
||||
HP_BAR(opponent, captureDamage: &damage[turn]);
|
||||
}
|
||||
} THEN {
|
||||
for (turn = 1; turn < maxTurns - 1; turn++)
|
||||
EXPECT_MUL_EQ(damage[turn - 1], UQ_4_12(2.0), damage[turn]);
|
||||
EXPECT_EQ(damage[maxTurns - 2], damage[maxTurns - 1]);
|
||||
}
|
||||
}
|
||||
@@ -126,6 +126,7 @@ SINGLE_BATTLE_TEST("Held items are consumed immediately after a mon switched in
|
||||
ABILITY_POPUP(player, ABILITY_ELECTRIC_SURGE);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_U_TURN, player);
|
||||
HP_BAR(opponent);
|
||||
ABILITY_POPUP(player, ABILITY_INTIMIDATE);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
MESSAGE("2 sent out Wynaut!");
|
||||
@@ -137,7 +138,6 @@ SINGLE_BATTLE_TEST("Held items are consumed immediately after a mon switched in
|
||||
|
||||
SINGLE_BATTLE_TEST("Held items are consumed immediately after a mon switched in by U-turn and Intimidate activates after it: opposing side")
|
||||
{
|
||||
KNOWN_FAILING;
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); };
|
||||
PLAYER(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); }
|
||||
@@ -149,7 +149,7 @@ SINGLE_BATTLE_TEST("Held items are consumed immediately after a mon switched in
|
||||
ABILITY_POPUP(player, ABILITY_ELECTRIC_SURGE);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_U_TURN, player);
|
||||
HP_BAR(opponent);
|
||||
NOT ABILITY_POPUP(player, ABILITY_INTIMIDATE);
|
||||
ABILITY_POPUP(player, ABILITY_INTIMIDATE);
|
||||
MESSAGE("2 sent out Wynaut!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
|
||||
@@ -41,7 +41,7 @@ WILD_BATTLE_TEST("Ion Deluge works the same way as always when used by a mon wit
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(opponent, ability);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
MESSAGE("Wild Zebstrika's Sp.Atk rose!");
|
||||
MESSAGE("Wild Zebstrika's Sp. Atk rose!");
|
||||
MESSAGE("Wild Zebstrika's Speed rose!");
|
||||
}
|
||||
MESSAGE("A deluge of ions showers the battlefield!");
|
||||
|
||||
@@ -23,7 +23,7 @@ SINGLE_BATTLE_TEST("Photon Geyser can be mirror coated if it is a special move")
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Photon Geyser can be countered if it is a physcal move")
|
||||
SINGLE_BATTLE_TEST("Photon Geyser can be countered if it is a physical move")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Attack(110); SpAttack(100); }
|
||||
|
||||
@@ -47,20 +47,19 @@ SINGLE_BATTLE_TEST("Plasma Fists turns normal moves into electric for the remain
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Plasma Fists type-changing effect is applied after Pixilate")
|
||||
SINGLE_BATTLE_TEST("Plasma Fists type-changing effect does not override Pixilate")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_KRABBY) { Speed(300); };
|
||||
OPPONENT(SPECIES_ALTARIA) { Speed(1); Item(ITEM_ALTARIANITE); }
|
||||
OPPONENT(SPECIES_SYLVEON) { Speed(1); Ability(ABILITY_PIXILATE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_PLASMA_FISTS); MOVE(opponent, MOVE_EMBER, gimmick: GIMMICK_MEGA); }
|
||||
TURN { MOVE(player, MOVE_PLASMA_FISTS); MOVE(opponent, MOVE_TACKLE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_MEGA_EVOLUTION, opponent);
|
||||
MESSAGE("Krabby used Plasma Fists!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_PLASMA_FISTS, player);
|
||||
MESSAGE("A deluge of ions showers the battlefield!");
|
||||
MESSAGE("Foe Altaria used Ember!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, opponent);
|
||||
MESSAGE("Foe Sylveon used Tackle!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
|
||||
NOT MESSAGE("It's super effective!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,24 +111,24 @@ SINGLE_BATTLE_TEST("Roost suppresses the user's Flying-typing this turn, then re
|
||||
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; }
|
||||
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_TORNADUS].types[0] == TYPE_FLYING);
|
||||
@@ -179,24 +179,24 @@ SINGLE_BATTLE_TEST("Roost, if used by a Flying/Flying type, treats the user as a
|
||||
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; }
|
||||
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);
|
||||
|
||||
@@ -31,7 +31,7 @@ SINGLE_BATTLE_TEST("Shell Side Arm can be mirror coated if it is special")
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Shell Side Arm does not change catogory mid-turn")
|
||||
SINGLE_BATTLE_TEST("Shell Side Arm does not change category mid-turn")
|
||||
{
|
||||
s16 damage[3];
|
||||
|
||||
@@ -56,7 +56,7 @@ SINGLE_BATTLE_TEST("Shell Side Arm does not change catogory mid-turn")
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Shell Side Arm is choosing it's type for each battler on the field")
|
||||
DOUBLE_BATTLE_TEST("Shell Side Arm chooses its category for each battler on the field")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(10); Moves(MOVE_SHELL_SIDE_ARM); }
|
||||
|
||||
@@ -170,7 +170,6 @@ AI_DOUBLE_BATTLE_TEST("Spicy Extract user will use it if partner holds Clear Amu
|
||||
PARAMETRIZE { move = MOVE_TACKLE; }
|
||||
PARAMETRIZE { move = MOVE_SWIFT;}
|
||||
|
||||
AI_LOG;
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(10); }
|
||||
|
||||
@@ -56,7 +56,7 @@ DOUBLE_BATTLE_TEST("Sticky Web lowers Speed by 1 in a double battle after Explos
|
||||
OPPONENT(SPECIES_WOBBUFFET) {HP(1); Speed(1);}
|
||||
OPPONENT(SPECIES_WOBBUFFET) {HP(1); Speed(1);}
|
||||
OPPONENT(SPECIES_WYNAUT) {Speed(10);}
|
||||
OPPONENT(SPECIES_WYNAUT) {Speed(10);}
|
||||
OPPONENT(SPECIES_ALAKAZAM) {Speed(100);}
|
||||
} WHEN {
|
||||
TURN { MOVE(playerRight, MOVE_STICKY_WEB); MOVE(playerLeft, MOVE_EXPLOSION); SEND_OUT(playerLeft, 2); SEND_OUT(opponentLeft, 2); SEND_OUT(opponentRight, 3); }
|
||||
TURN {}
|
||||
@@ -65,13 +65,13 @@ DOUBLE_BATTLE_TEST("Sticky Web lowers Speed by 1 in a double battle after Explos
|
||||
MESSAGE("A sticky web spreads out on the ground around the opposing team!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, playerLeft);
|
||||
MESSAGE("2 sent out Wynaut!");
|
||||
MESSAGE("2 sent out Alakazam!");
|
||||
MESSAGE("Foe Alakazam was caught in a Sticky Web!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
|
||||
MESSAGE("Foe Alakazam's Speed fell!");
|
||||
MESSAGE("Foe Wynaut was caught in a Sticky Web!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
MESSAGE("Foe Wynaut's Speed fell!");
|
||||
MESSAGE("2 sent out Wynaut!");
|
||||
MESSAGE("Foe Wynaut was caught in a Sticky Web!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
|
||||
MESSAGE("Foe Wynaut's Speed fell!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ SINGLE_BATTLE_TEST("Strength Sap lowers Attack by 1 and restores HP based on tar
|
||||
{
|
||||
u32 atkStat = 0;
|
||||
|
||||
PARAMETRIZE{ atkStat = 100; }
|
||||
PARAMETRIZE{ atkStat = 50; }
|
||||
PARAMETRIZE { atkStat = 100; }
|
||||
PARAMETRIZE { atkStat = 50; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(200); }
|
||||
@@ -35,8 +35,8 @@ SINGLE_BATTLE_TEST("Strength Sap works exactly the same when attacker is behind
|
||||
{
|
||||
u32 atkStat = 0;
|
||||
|
||||
PARAMETRIZE{ atkStat = 100; }
|
||||
PARAMETRIZE{ atkStat = 50; }
|
||||
PARAMETRIZE { atkStat = 100; }
|
||||
PARAMETRIZE { atkStat = 50; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(200); }
|
||||
@@ -65,7 +65,7 @@ SINGLE_BATTLE_TEST("Strength Sap lowers Attack by 1 and restores HP based on tar
|
||||
|
||||
for (j = 0; j <= MAX_STAT_STAGE; j++) {
|
||||
if (j == DEFAULT_STAT_STAGE - 1) { continue; } // Ignore -6, because Strength Sap won't work otherwise
|
||||
PARAMETRIZE{ statStage = j; }
|
||||
PARAMETRIZE { statStage = j; }
|
||||
}
|
||||
|
||||
GIVEN {
|
||||
|
||||
@@ -59,3 +59,18 @@ SINGLE_BATTLE_TEST("Tera Starstorm becomes a physical move if the user is Terapa
|
||||
EXPECT_MUL_EQ(results[0].damage, UQ_4_12(2.5), results[1].damage);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Tera Starstorm remains Normal-type if used by Pokemon other than Terapagos")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_TERA_STARSTORM].type == TYPE_NORMAL);
|
||||
ASSUME(gSpeciesInfo[SPECIES_MISDREAVUS].types[0] == TYPE_GHOST);
|
||||
PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_STELLAR); }
|
||||
OPPONENT(SPECIES_MISDREAVUS);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TERA_STARSTORM, gimmick: GIMMICK_TERA); }
|
||||
} SCENE {
|
||||
MESSAGE("Wobbuffet used Tera Starstorm!");
|
||||
MESSAGE("It doesn't affect Foe Misdreavus…");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,13 +74,14 @@ SINGLE_BATTLE_TEST("Tidy Up removes Substitute")
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI prefers to keep it's substitute over removing hazards if target is slower")
|
||||
AI_SINGLE_BATTLE_TEST("AI prefers to keep its substitute over removing hazards if target is slower")
|
||||
{
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(50); Status1(STATUS1_PARALYSIS); Moves(MOVE_SLEEP_POWDER, MOVE_STEALTH_ROCK, MOVE_CELEBRATE); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(100); Moves(MOVE_BITE, MOVE_TACKLE, MOVE_SUBSTITUTE, MOVE_TIDY_UP); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_STEALTH_ROCK); EXPECT_MOVE(opponent, MOVE_TIDY_UP); }
|
||||
TURN { MOVE(player, MOVE_STEALTH_ROCK); EXPECT_MOVE(opponent, MOVE_SUBSTITUTE); }
|
||||
TURN { EXPECT_MOVE(opponent, MOVE_BITE); }
|
||||
}
|
||||
@@ -93,6 +94,7 @@ AI_SINGLE_BATTLE_TEST("AI will try to remove hazards if slower then target even
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(100); Status1(STATUS1_BURN); Moves(MOVE_SLEEP_POWDER, MOVE_STEALTH_ROCK, MOVE_CELEBRATE); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(50); Moves(MOVE_BITE, MOVE_TACKLE, MOVE_SUBSTITUTE, MOVE_TIDY_UP); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_STEALTH_ROCK); EXPECT_MOVE(opponent, MOVE_TIDY_UP); }
|
||||
TURN { MOVE(player, MOVE_STEALTH_ROCK); EXPECT_MOVE(opponent, MOVE_SUBSTITUTE); }
|
||||
TURN { EXPECT_MOVE(opponent, MOVE_TIDY_UP); }
|
||||
}
|
||||
|
||||
@@ -48,3 +48,21 @@ SINGLE_BATTLE_TEST("Toxic cannot miss if used by a Poison-type")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI avoids toxic when it can not poison target")
|
||||
{
|
||||
u32 species, ability;
|
||||
|
||||
PARAMETRIZE { species = SPECIES_SNORLAX; ability = ABILITY_IMMUNITY; }
|
||||
PARAMETRIZE { species = SPECIES_KOMALA; ability = ABILITY_COMATOSE; }
|
||||
PARAMETRIZE { species = SPECIES_NACLI; ability = ABILITY_PURIFYING_SALT; }
|
||||
PARAMETRIZE { species = SPECIES_BULBASAUR; ability = ABILITY_OVERGROW; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT);
|
||||
PLAYER(species) { Ability(ability); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_TOXIC); }
|
||||
} WHEN {
|
||||
TURN { SCORE_EQ(opponent, MOVE_CELEBRATE, MOVE_TOXIC); } // Both get -10
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,8 +243,8 @@ SINGLE_BATTLE_TEST("Solar Beam and Solar Blade can be used instantly in Sunlight
|
||||
SINGLE_BATTLE_TEST("Solar Beam's power is halved in Rain", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE{ move = MOVE_RAIN_DANCE; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_RAIN_DANCE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
@@ -261,8 +261,8 @@ SINGLE_BATTLE_TEST("Solar Beam's power is halved in Rain", s16 damage)
|
||||
SINGLE_BATTLE_TEST("Solar Blade's power is halved in Rain", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE{ move = MOVE_RAIN_DANCE; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_RAIN_DANCE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
@@ -279,8 +279,8 @@ SINGLE_BATTLE_TEST("Solar Blade's power is halved in Rain", s16 damage)
|
||||
SINGLE_BATTLE_TEST("Solar Beam's power is halved in a Sandstorm", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE{ move = MOVE_SANDSTORM; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_SANDSTORM; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_SAFETY_GOGGLES); };
|
||||
@@ -297,8 +297,8 @@ SINGLE_BATTLE_TEST("Solar Beam's power is halved in a Sandstorm", s16 damage)
|
||||
SINGLE_BATTLE_TEST("Solar Blade's power is halved in a Sandstorm", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE{ move = MOVE_SANDSTORM; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_SANDSTORM; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_SAFETY_GOGGLES); };
|
||||
@@ -315,8 +315,8 @@ SINGLE_BATTLE_TEST("Solar Blade's power is halved in a Sandstorm", s16 damage)
|
||||
SINGLE_BATTLE_TEST("Solar Beam's power is halved in Hail", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE{ move = MOVE_HAIL; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_HAIL; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_SAFETY_GOGGLES); };
|
||||
@@ -333,8 +333,8 @@ SINGLE_BATTLE_TEST("Solar Beam's power is halved in Hail", s16 damage)
|
||||
SINGLE_BATTLE_TEST("Solar Blade's power is halved in Hail", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE{ move = MOVE_HAIL; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_HAIL; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_SAFETY_GOGGLES); };
|
||||
@@ -351,8 +351,8 @@ SINGLE_BATTLE_TEST("Solar Blade's power is halved in Hail", s16 damage)
|
||||
SINGLE_BATTLE_TEST("Solar Beam's power is halved in Snow", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE{ move = MOVE_SNOWSCAPE; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_SNOWSCAPE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
@@ -369,8 +369,8 @@ SINGLE_BATTLE_TEST("Solar Beam's power is halved in Snow", s16 damage)
|
||||
SINGLE_BATTLE_TEST("Solar Blade's power is halved in Snow", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE{ move = MOVE_SNOWSCAPE; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_SNOWSCAPE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
|
||||
@@ -116,3 +116,19 @@ SINGLE_BATTLE_TEST("Upper Hand is boosted by Sheer Force")
|
||||
HP_BAR(player);
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI won't use Upper Hand unless it has seen a priority move")
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE { move = MOVE_TACKLE; }
|
||||
PARAMETRIZE { move = MOVE_QUICK_ATTACK; }
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
|
||||
ASSUME(gMovesInfo[MOVE_QUICK_ATTACK].priority == 1);
|
||||
PLAYER(SPECIES_WOBBUFFET) {Moves(move); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_UPPER_HAND, MOVE_KARATE_CHOP); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, move); EXPECT_MOVE(opponent, MOVE_KARATE_CHOP); }
|
||||
TURN { MOVE(player, move); EXPECT_MOVE(opponent, move == MOVE_QUICK_ATTACK ? MOVE_UPPER_HAND : MOVE_KARATE_CHOP); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ ASSUMPTIONS
|
||||
SINGLE_BATTLE_TEST("Weather Ball doubles its power and turns to a Fire-type move in Sunlight", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE{ move = MOVE_SUNNY_DAY; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_SUNNY_DAY; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_MEGANIUM);
|
||||
@@ -27,8 +27,8 @@ SINGLE_BATTLE_TEST("Weather Ball doubles its power and turns to a Fire-type move
|
||||
SINGLE_BATTLE_TEST("Weather Ball doubles its power and turns to a Water-type move in Rain", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE{ move = MOVE_RAIN_DANCE; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_RAIN_DANCE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_ARCANINE);
|
||||
@@ -45,8 +45,8 @@ SINGLE_BATTLE_TEST("Weather Ball doubles its power and turns to a Water-type mov
|
||||
SINGLE_BATTLE_TEST("Weather Ball doubles its power and turns to a Rock-type move in a Sandstorm", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE{ move = MOVE_SANDSTORM; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_SANDSTORM; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_MAGMAR) { Item(ITEM_SAFETY_GOGGLES); };
|
||||
@@ -63,9 +63,9 @@ SINGLE_BATTLE_TEST("Weather Ball doubles its power and turns to a Rock-type move
|
||||
SINGLE_BATTLE_TEST("Weather Ball doubles its power and turns to an Ice-type move in Hail and Snow", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE{ move = MOVE_HAIL; }
|
||||
PARAMETRIZE{ move = MOVE_SNOWSCAPE; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_HAIL; }
|
||||
PARAMETRIZE { move = MOVE_SNOWSCAPE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_DRAGONAIR) { Item(ITEM_SAFETY_GOGGLES); };
|
||||
|
||||
@@ -67,7 +67,8 @@ SINGLE_BATTLE_TEST("Dire Claw cannot poison/paralyze/cause to fall asleep pokemo
|
||||
u8 statusAnim;
|
||||
u16 species, ability;
|
||||
u32 rng;
|
||||
PARAMETRIZE { statusAnim = B_ANIM_STATUS_PRZ; rng = MOVE_EFFECT_PARALYSIS; species = SPECIES_RAICHU; ability = ABILITY_LIGHTNING_ROD; }
|
||||
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5)
|
||||
PARAMETRIZE { statusAnim = B_ANIM_STATUS_PRZ; rng = MOVE_EFFECT_PARALYSIS; species = SPECIES_RAICHU; ability = ABILITY_LIGHTNING_ROD; }
|
||||
PARAMETRIZE { statusAnim = B_ANIM_STATUS_PRZ; rng = MOVE_EFFECT_PARALYSIS; species = SPECIES_JOLTEON; ability = ABILITY_VOLT_ABSORB; }
|
||||
PARAMETRIZE { statusAnim = B_ANIM_STATUS_PRZ; rng = MOVE_EFFECT_PARALYSIS; species = SPECIES_ELECTIVIRE; ability = ABILITY_MOTOR_DRIVE; }
|
||||
PARAMETRIZE { statusAnim = B_ANIM_STATUS_PSN; rng = MOVE_EFFECT_POISON; species = SPECIES_ZANGOOSE; ability = ABILITY_IMMUNITY; }
|
||||
|
||||
@@ -7,7 +7,11 @@ ASSUMPTIONS
|
||||
ASSUME(gMovesInfo[MOVE_BLIZZARD].accuracy == 70);
|
||||
}
|
||||
|
||||
#if B_USE_FROSTBITE == TRUE
|
||||
SINGLE_BATTLE_TEST("Powder Snow inflicts frostbite")
|
||||
#else
|
||||
SINGLE_BATTLE_TEST("Powder Snow inflicts freeze")
|
||||
#endif
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
@@ -18,11 +22,15 @@ SINGLE_BATTLE_TEST("Powder Snow inflicts freeze")
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_POWDER_SNOW, player);
|
||||
HP_BAR(opponent);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_FRZ, opponent);
|
||||
STATUS_ICON(opponent, freeze: TRUE);
|
||||
FREEZE_OR_FROSTBURN_STATUS(opponent, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
#if B_USE_FROSTBITE == TRUE
|
||||
SINGLE_BATTLE_TEST("Powder Snow cannot frostbite an Ice-type Pokémon")
|
||||
#else
|
||||
SINGLE_BATTLE_TEST("Powder Snow cannot freeze an Ice-type Pokémon")
|
||||
#endif
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_SNORUNT].types[0] == TYPE_ICE);
|
||||
@@ -35,7 +43,7 @@ SINGLE_BATTLE_TEST("Powder Snow cannot freeze an Ice-type Pokémon")
|
||||
HP_BAR(opponent);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_FRZ, opponent);
|
||||
STATUS_ICON(opponent, freeze: TRUE);
|
||||
FREEZE_OR_FROSTBURN_STATUS(opponent, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,10 +76,18 @@ SINGLE_BATTLE_TEST("Blizzard bypasses accuracy checks in Hail and Snow")
|
||||
}
|
||||
|
||||
#if B_STATUS_TYPE_IMMUNITY > GEN_1
|
||||
#if B_USE_FROSTBITE == TRUE
|
||||
SINGLE_BATTLE_TEST("Freezing Glare should frostbite Psychic-types")
|
||||
#else
|
||||
SINGLE_BATTLE_TEST("Freezing Glare should freeze Psychic-types")
|
||||
#endif
|
||||
#else
|
||||
#if B_USE_FROSTBITE == TRUE
|
||||
SINGLE_BATTLE_TEST("Freezing Glare shouldn't freeze Psychic-types")
|
||||
#else
|
||||
SINGLE_BATTLE_TEST("Freezing Glare shouldn't freeze Psychic-types")
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_ARTICUNO_GALARIAN].types[0] == TYPE_PSYCHIC);
|
||||
@@ -86,11 +102,11 @@ SINGLE_BATTLE_TEST("Freezing Glare shouldn't freeze Psychic-types")
|
||||
HP_BAR(opponent);
|
||||
#if B_STATUS_TYPE_IMMUNITY > GEN_1
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_FRZ, opponent);
|
||||
STATUS_ICON(opponent, freeze: TRUE);
|
||||
FREEZE_OR_FROSTBURN_STATUS(opponent, TRUE);
|
||||
#else
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_FRZ, opponent);
|
||||
STATUS_ICON(opponent, freeze: TRUE);
|
||||
FREEZE_OR_FROSTBURN_STATUS(opponent, TRUE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -6,7 +6,11 @@ ASSUMPTIONS
|
||||
ASSUME(MoveHasAdditionalEffect(MOVE_TRI_ATTACK, MOVE_EFFECT_TRI_ATTACK) == TRUE);
|
||||
}
|
||||
|
||||
#if B_USE_FROSTBITE == TRUE
|
||||
SINGLE_BATTLE_TEST("Tri Attack can inflict paralysis, burn or frostbite")
|
||||
#else
|
||||
SINGLE_BATTLE_TEST("Tri Attack can inflict paralysis, burn or freeze")
|
||||
#endif
|
||||
{
|
||||
u8 statusAnim;
|
||||
PARAMETRIZE { statusAnim = B_ANIM_STATUS_PRZ; }
|
||||
@@ -26,14 +30,18 @@ SINGLE_BATTLE_TEST("Tri Attack can inflict paralysis, burn or freeze")
|
||||
if (statusAnim == B_ANIM_STATUS_BRN) {
|
||||
STATUS_ICON(opponent, burn: TRUE);
|
||||
} else if (statusAnim == B_ANIM_STATUS_FRZ) {
|
||||
STATUS_ICON(opponent, freeze: TRUE);
|
||||
FREEZE_OR_FROSTBURN_STATUS(opponent, TRUE);
|
||||
} else if (statusAnim == B_ANIM_STATUS_PRZ) {
|
||||
STATUS_ICON(opponent, paralysis: TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if B_USE_FROSTBITE == TRUE
|
||||
SINGLE_BATTLE_TEST("Tri Attack cannot paralyze/burn/frostbite electric/fire/ice types respectively")
|
||||
#else
|
||||
SINGLE_BATTLE_TEST("Tri Attack cannot paralyze/burn/freeze electric/fire/ice types respectively")
|
||||
#endif
|
||||
{
|
||||
u8 statusAnim;
|
||||
u16 species;
|
||||
@@ -42,7 +50,7 @@ SINGLE_BATTLE_TEST("Tri Attack cannot paralyze/burn/freeze electric/fire/ice typ
|
||||
PARAMETRIZE { statusAnim = B_ANIM_STATUS_PRZ; rng = MOVE_EFFECT_PARALYSIS; species = SPECIES_RAICHU; }
|
||||
#endif // B_PARALYZE_ELECTRIC
|
||||
PARAMETRIZE { statusAnim = B_ANIM_STATUS_BRN; rng = MOVE_EFFECT_BURN; species = SPECIES_ARCANINE; }
|
||||
PARAMETRIZE { statusAnim = B_ANIM_STATUS_FRZ; rng = MOVE_EFFECT_FREEZE; species = SPECIES_GLALIE; }
|
||||
PARAMETRIZE { statusAnim = B_ANIM_STATUS_FRZ; rng = MOVE_EFFECT_FREEZE_OR_FROSTBITE; species = SPECIES_GLALIE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(species);
|
||||
@@ -57,7 +65,7 @@ SINGLE_BATTLE_TEST("Tri Attack cannot paralyze/burn/freeze electric/fire/ice typ
|
||||
if (statusAnim == B_ANIM_STATUS_BRN) {
|
||||
STATUS_ICON(opponent, burn: TRUE);
|
||||
} else if (statusAnim == B_ANIM_STATUS_FRZ) {
|
||||
STATUS_ICON(opponent, freeze: TRUE);
|
||||
FREEZE_OR_FROSTBURN_STATUS(opponent, TRUE);
|
||||
} else if (statusAnim == B_ANIM_STATUS_PRZ) {
|
||||
STATUS_ICON(opponent, paralysis: TRUE);
|
||||
}
|
||||
@@ -65,7 +73,11 @@ SINGLE_BATTLE_TEST("Tri Attack cannot paralyze/burn/freeze electric/fire/ice typ
|
||||
}
|
||||
}
|
||||
|
||||
#if B_USE_FROSTBITE == TRUE
|
||||
SINGLE_BATTLE_TEST("Tri Attack cannot paralyze/burn/frostbite pokemon with abilities preventing respective statuses")
|
||||
#else
|
||||
SINGLE_BATTLE_TEST("Tri Attack cannot paralyze/burn/freeze pokemon with abilities preventing respective statuses")
|
||||
#endif
|
||||
{
|
||||
u8 statusAnim;
|
||||
u16 species, ability;
|
||||
@@ -75,8 +87,8 @@ SINGLE_BATTLE_TEST("Tri Attack cannot paralyze/burn/freeze pokemon with abilitie
|
||||
PARAMETRIZE { statusAnim = B_ANIM_STATUS_BRN; rng = MOVE_EFFECT_BURN; species = SPECIES_DEWPIDER; ability = ABILITY_WATER_BUBBLE; }
|
||||
PARAMETRIZE { statusAnim = B_ANIM_STATUS_BRN; rng = MOVE_EFFECT_BURN; species = SPECIES_SEAKING; ability = ABILITY_WATER_VEIL; }
|
||||
PARAMETRIZE { statusAnim = B_ANIM_STATUS_BRN; rng = MOVE_EFFECT_BURN; species = SPECIES_KOMALA; ability = ABILITY_COMATOSE; }
|
||||
PARAMETRIZE { statusAnim = B_ANIM_STATUS_FRZ; rng = MOVE_EFFECT_FREEZE; species = SPECIES_CAMERUPT; ability = ABILITY_MAGMA_ARMOR; }
|
||||
PARAMETRIZE { statusAnim = B_ANIM_STATUS_FRZ; rng = MOVE_EFFECT_FREEZE; species = SPECIES_KOMALA; ability = ABILITY_COMATOSE; }
|
||||
PARAMETRIZE { statusAnim = B_ANIM_STATUS_FRZ; rng = MOVE_EFFECT_FREEZE_OR_FROSTBITE; species = SPECIES_CAMERUPT; ability = ABILITY_MAGMA_ARMOR; }
|
||||
PARAMETRIZE { statusAnim = B_ANIM_STATUS_FRZ; rng = MOVE_EFFECT_FREEZE_OR_FROSTBITE; species = SPECIES_KOMALA; ability = ABILITY_COMATOSE; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
@@ -92,7 +104,7 @@ SINGLE_BATTLE_TEST("Tri Attack cannot paralyze/burn/freeze pokemon with abilitie
|
||||
if (statusAnim == B_ANIM_STATUS_BRN) {
|
||||
STATUS_ICON(opponent, burn: TRUE);
|
||||
} else if (statusAnim == B_ANIM_STATUS_FRZ) {
|
||||
STATUS_ICON(opponent, freeze: TRUE);
|
||||
FREEZE_OR_FROSTBURN_STATUS(opponent, TRUE);
|
||||
} else if (statusAnim == B_ANIM_STATUS_PRZ) {
|
||||
STATUS_ICON(opponent, paralysis: TRUE);
|
||||
}
|
||||
@@ -100,13 +112,17 @@ SINGLE_BATTLE_TEST("Tri Attack cannot paralyze/burn/freeze pokemon with abilitie
|
||||
}
|
||||
}
|
||||
|
||||
#if B_USE_FROSTBITE == TRUE
|
||||
SINGLE_BATTLE_TEST("Tri Attack cannot paralyze/burn/frostbite a mon which is already statused")
|
||||
#else
|
||||
SINGLE_BATTLE_TEST("Tri Attack cannot paralyze/burn/freeze a mon which is already statused")
|
||||
#endif
|
||||
{
|
||||
u8 statusAnim;
|
||||
u32 rng;
|
||||
PARAMETRIZE { statusAnim = B_ANIM_STATUS_PRZ; rng = MOVE_EFFECT_PARALYSIS; }
|
||||
PARAMETRIZE { statusAnim = B_ANIM_STATUS_BRN; rng = MOVE_EFFECT_BURN; }
|
||||
PARAMETRIZE { statusAnim = B_ANIM_STATUS_FRZ; rng = MOVE_EFFECT_FREEZE; }
|
||||
PARAMETRIZE { statusAnim = B_ANIM_STATUS_FRZ; rng = MOVE_EFFECT_FREEZE_OR_FROSTBITE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); }
|
||||
@@ -121,7 +137,7 @@ SINGLE_BATTLE_TEST("Tri Attack cannot paralyze/burn/freeze a mon which is alread
|
||||
if (statusAnim == B_ANIM_STATUS_BRN) {
|
||||
STATUS_ICON(opponent, burn: TRUE);
|
||||
} else if (statusAnim == B_ANIM_STATUS_FRZ) {
|
||||
STATUS_ICON(opponent, freeze: TRUE);
|
||||
FREEZE_OR_FROSTBURN_STATUS(opponent, TRUE);
|
||||
} else if (statusAnim == B_ANIM_STATUS_PRZ) {
|
||||
STATUS_ICON(opponent, paralysis: TRUE);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ ASSUMPTIONS
|
||||
{
|
||||
ASSUME(MoveHasAdditionalEffect(MOVE_THUNDER_FANG, MOVE_EFFECT_PARALYSIS) == TRUE);
|
||||
ASSUME(MoveHasAdditionalEffect(MOVE_THUNDER_FANG, MOVE_EFFECT_FLINCH) == TRUE);
|
||||
ASSUME(MoveHasAdditionalEffect(MOVE_ICE_FANG, MOVE_EFFECT_FREEZE) == TRUE);
|
||||
ASSUME(MoveHasAdditionalEffect(MOVE_ICE_FANG, MOVE_EFFECT_FREEZE_OR_FROSTBITE) == TRUE);
|
||||
ASSUME(MoveHasAdditionalEffect(MOVE_ICE_FANG, MOVE_EFFECT_FLINCH) == TRUE);
|
||||
ASSUME(MoveHasAdditionalEffect(MOVE_FIRE_FANG, MOVE_EFFECT_BURN) == TRUE);
|
||||
ASSUME(MoveHasAdditionalEffect(MOVE_FIRE_FANG, MOVE_EFFECT_FLINCH) == TRUE);
|
||||
@@ -33,7 +33,7 @@ SINGLE_BATTLE_TEST("Thunder, Ice and Fire Fang inflict status 10% of the time")
|
||||
STATUS_ICON(opponent, paralysis: TRUE);
|
||||
} if (move == MOVE_ICE_FANG) {
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_FRZ, opponent);
|
||||
STATUS_ICON(opponent, freeze: TRUE);
|
||||
FREEZE_OR_FROSTBURN_STATUS(opponent, TRUE);
|
||||
} if (move == MOVE_FIRE_FANG) {
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_BRN, opponent);
|
||||
STATUS_ICON(opponent, burn: TRUE);
|
||||
|
||||
@@ -32,4 +32,42 @@ SINGLE_BATTLE_TEST("Hurricane bypasses accuracy checks in Rain")
|
||||
NONE_OF { MESSAGE("Wobbuffet's attack missed!"); }
|
||||
}
|
||||
}
|
||||
TO_DO_BATTLE_TEST("Hurricane Veil can hit airborne targets") // Fly, Bounce, Sky Drop
|
||||
|
||||
SINGLE_BATTLE_TEST("Hurricane can hit airborne targets (Fly, Bounce)")
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE { move = MOVE_FLY; }
|
||||
PARAMETRIZE { move = MOVE_BOUNCE; }
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_FLY].effect == EFFECT_SEMI_INVULNERABLE);
|
||||
ASSUME(UNCOMPRESS_BITS(HIHALF(gMovesInfo[MOVE_FLY].argument)) == STATUS3_ON_AIR);
|
||||
ASSUME(gMovesInfo[MOVE_BOUNCE].effect == EFFECT_SEMI_INVULNERABLE);
|
||||
ASSUME(UNCOMPRESS_BITS(HIHALF(gMovesInfo[MOVE_BOUNCE].argument)) == STATUS3_ON_AIR);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(move); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, move); MOVE(player, MOVE_HURRICANE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_HURRICANE, player);
|
||||
NONE_OF { MESSAGE("Wobbuffet's attack missed!"); }
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Hurricane can hit airborne targets (Sky Drop)")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_SKY_DROP].effect == EFFECT_SKY_DROP);
|
||||
ASSUME(UNCOMPRESS_BITS(HIHALF(gMovesInfo[MOVE_SKY_DROP].argument)) == STATUS3_ON_AIR);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_SKY_DROP, target: opponentLeft); MOVE(playerRight, MOVE_HURRICANE, target: playerLeft); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SKY_DROP, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_HURRICANE, playerRight);
|
||||
NONE_OF { MESSAGE("Wobbuffet's attack missed!"); }
|
||||
}
|
||||
}
|
||||
|
||||
74
test/battle/move_flags/ignores_target_ability.c
Normal file
74
test/battle/move_flags/ignores_target_ability.c
Normal file
@@ -0,0 +1,74 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(gMovesInfo[MOVE_SUNSTEEL_STRIKE].ignoresTargetAbility);
|
||||
ASSUME(gMovesInfo[MOVE_MOONGEIST_BEAM].ignoresTargetAbility);
|
||||
ASSUME(gMovesInfo[MOVE_PHOTON_GEYSER].ignoresTargetAbility);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("ignoresTargetAbility moves do not ignore the attacker's own ability", s16 damage)
|
||||
{
|
||||
u32 ability, move;
|
||||
|
||||
PARAMETRIZE { move = MOVE_SUNSTEEL_STRIKE; ability = ABILITY_MAGIC_GUARD; }
|
||||
PARAMETRIZE { move = MOVE_SUNSTEEL_STRIKE; ability = ABILITY_UNAWARE; }
|
||||
PARAMETRIZE { move = MOVE_MOONGEIST_BEAM; ability = ABILITY_MAGIC_GUARD; }
|
||||
PARAMETRIZE { move = MOVE_MOONGEIST_BEAM; ability = ABILITY_UNAWARE; }
|
||||
PARAMETRIZE { move = MOVE_PHOTON_GEYSER; ability = ABILITY_MAGIC_GUARD; }
|
||||
PARAMETRIZE { move = MOVE_PHOTON_GEYSER; ability = ABILITY_UNAWARE; }
|
||||
|
||||
ASSUME(gAbilitiesInfo[ABILITY_UNAWARE].breakable);
|
||||
ASSUME(gMovesInfo[MOVE_IRON_DEFENSE].effect == EFFECT_DEFENSE_UP_2);
|
||||
ASSUME(gMovesInfo[MOVE_AMNESIA].effect == EFFECT_SPECIAL_DEFENSE_UP_2);
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_CLEFABLE) { Speed(1); Ability(ability); }
|
||||
OPPONENT(SPECIES_ARON) { Speed(2); }
|
||||
} WHEN {
|
||||
if (gMovesInfo[move].category == DAMAGE_CATEGORY_PHYSICAL)
|
||||
TURN { MOVE(opponent, MOVE_IRON_DEFENSE); MOVE(player, move); }
|
||||
else
|
||||
TURN { MOVE(opponent, MOVE_AMNESIA); MOVE(player, move); }
|
||||
} SCENE {
|
||||
if (gMovesInfo[move].category == DAMAGE_CATEGORY_PHYSICAL)
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_IRON_DEFENSE, opponent);
|
||||
else
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_AMNESIA, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, player);
|
||||
HP_BAR(opponent, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_MUL_EQ(results[0].damage, UQ_4_12(2.0), results[1].damage);
|
||||
EXPECT_MUL_EQ(results[2].damage, UQ_4_12(2.0), results[3].damage);
|
||||
EXPECT_MUL_EQ(results[4].damage, UQ_4_12(2.0), results[5].damage);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("ignoresTargetAbility moves do ignore target's abilities", s16 damage)
|
||||
{
|
||||
u32 ability, move;
|
||||
|
||||
PARAMETRIZE { move = MOVE_SUNSTEEL_STRIKE; ability = ABILITY_INNER_FOCUS; }
|
||||
PARAMETRIZE { move = MOVE_SUNSTEEL_STRIKE; ability = ABILITY_MULTISCALE; }
|
||||
PARAMETRIZE { move = MOVE_MOONGEIST_BEAM; ability = ABILITY_INNER_FOCUS; }
|
||||
PARAMETRIZE { move = MOVE_MOONGEIST_BEAM; ability = ABILITY_MULTISCALE; }
|
||||
PARAMETRIZE { move = MOVE_PHOTON_GEYSER; ability = ABILITY_INNER_FOCUS; }
|
||||
PARAMETRIZE { move = MOVE_PHOTON_GEYSER; ability = ABILITY_MULTISCALE; }
|
||||
|
||||
ASSUME(gAbilitiesInfo[ABILITY_MULTISCALE].breakable);
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_AZUMARILL);
|
||||
OPPONENT(SPECIES_DRAGONITE) { Ability(ability); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, move); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, player);
|
||||
HP_BAR(opponent, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_EQ(results[0].damage, results[1].damage);
|
||||
EXPECT_EQ(results[2].damage, results[3].damage);
|
||||
EXPECT_EQ(results[4].damage, results[5].damage);
|
||||
}
|
||||
}
|
||||
@@ -35,3 +35,23 @@ SINGLE_BATTLE_TEST("Burn reduces Attack by 50%", s16 damage)
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage);
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI avoids Will-o-Wisp when it can not burn target")
|
||||
{
|
||||
u32 species, ability;
|
||||
|
||||
PARAMETRIZE { species = SPECIES_BUIZEL; ability = ABILITY_WATER_VEIL; }
|
||||
PARAMETRIZE { species = SPECIES_DEWPIDER; ability = ABILITY_WATER_BUBBLE; }
|
||||
PARAMETRIZE { species = SPECIES_KOMALA; ability = ABILITY_COMATOSE; }
|
||||
PARAMETRIZE { species = SPECIES_ARCTIBAX; ability = ABILITY_THERMAL_EXCHANGE; }
|
||||
PARAMETRIZE { species = SPECIES_NACLI; ability = ABILITY_PURIFYING_SALT; }
|
||||
PARAMETRIZE { species = SPECIES_CHARMANDER; ability = ABILITY_BLAZE; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT);
|
||||
PLAYER(species) { Ability(ability); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_WILL_O_WISP); }
|
||||
} WHEN {
|
||||
TURN { SCORE_EQ(opponent, MOVE_CELEBRATE, MOVE_WILL_O_WISP); } // Both get -10
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,3 +42,21 @@ SINGLE_BATTLE_TEST("Paralysis has a 25% chance of skipping the turn")
|
||||
MESSAGE("Wobbuffet is paralyzed! It can't move!");
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI avoids Thunder Wave when it can not paralyse target")
|
||||
{
|
||||
u32 species, ability;
|
||||
|
||||
PARAMETRIZE { species = SPECIES_HITMONLEE; ability = ABILITY_LIMBER; }
|
||||
PARAMETRIZE { species = SPECIES_KOMALA; ability = ABILITY_COMATOSE; }
|
||||
PARAMETRIZE { species = SPECIES_NACLI; ability = ABILITY_PURIFYING_SALT; }
|
||||
PARAMETRIZE { species = SPECIES_PIKACHU; ability = ABILITY_STATIC; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT);
|
||||
PLAYER(species) { Ability(ability); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_THUNDER_WAVE); }
|
||||
} WHEN {
|
||||
TURN { SCORE_EQ(opponent, MOVE_CELEBRATE, MOVE_THUNDER_WAVE); } // Both get -10
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,3 +21,21 @@ SINGLE_BATTLE_TEST("Sleep prevents the battler from using a move")
|
||||
MESSAGE("Wobbuffet used Celebrate!");
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI avoids hypnosis when it can not put target to sleep")
|
||||
{
|
||||
u32 species, ability;
|
||||
|
||||
PARAMETRIZE { species = SPECIES_HOOTHOOT; ability = ABILITY_INSOMNIA; }
|
||||
PARAMETRIZE { species = SPECIES_MANKEY; ability = ABILITY_VITAL_SPIRIT; }
|
||||
PARAMETRIZE { species = SPECIES_KOMALA; ability = ABILITY_COMATOSE; }
|
||||
PARAMETRIZE { species = SPECIES_NACLI; ability = ABILITY_PURIFYING_SALT; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT);
|
||||
PLAYER(species) { Ability(ability); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_HYPNOSIS); }
|
||||
} WHEN {
|
||||
TURN { SCORE_EQ(opponent, MOVE_CELEBRATE, MOVE_HYPNOSIS); } // Both get -10
|
||||
}
|
||||
}
|
||||
|
||||
28
test/battle/status2/confusion.c
Normal file
28
test/battle/status2/confusion.c
Normal file
@@ -0,0 +1,28 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Confusion adds a 50/33% chance to hit self with 40 power")
|
||||
{
|
||||
s16 damage[2];
|
||||
|
||||
ASSUME(gMovesInfo[MOVE_TACKLE].power == 40);
|
||||
|
||||
PASSES_RANDOMLY(B_CONFUSION_SELF_DMG_CHANCE >= GEN_7 ? 33 : 50, 100, RNG_CONFUSION);
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(1); };
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(2); };
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_TACKLE, WITH_RNG(RNG_DAMAGE_MODIFIER, 0)); MOVE(player, MOVE_CONFUSE_RAY); }
|
||||
TURN;
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
|
||||
HP_BAR(player, captureDamage: &damage[0]);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_CONFUSE_RAY, player);
|
||||
MESSAGE("Foe Wobbuffet became confused!");
|
||||
MESSAGE("Foe Wobbuffet is confused!");
|
||||
MESSAGE("It hurt itself in its confusion!");
|
||||
HP_BAR(opponent, captureDamage: &damage[1]);
|
||||
} THEN {
|
||||
EXPECT_EQ(damage[0], damage[1]);
|
||||
}
|
||||
}
|
||||
@@ -85,3 +85,27 @@ SINGLE_BATTLE_TEST("Grassy Terrain lasts for 5 turns")
|
||||
MESSAGE("The grass disappeared from the battlefield.");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Grassy Terrain heals the pokemon on the field for the duration of the terrain, including last turn")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { HP(1); };
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_GRASSY_TERRAIN); }
|
||||
TURN {}
|
||||
TURN {}
|
||||
TURN {}
|
||||
TURN {}
|
||||
} SCENE {
|
||||
MESSAGE("Foe Wobbuffet used Celebrate!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_GRASSY_TERRAIN, player);
|
||||
MESSAGE("Grass grew to cover the battlefield!");
|
||||
MESSAGE("Foe Wobbuffet is healed by the grassy terrain!");
|
||||
MESSAGE("Foe Wobbuffet is healed by the grassy terrain!");
|
||||
MESSAGE("Foe Wobbuffet is healed by the grassy terrain!");
|
||||
MESSAGE("Foe Wobbuffet is healed by the grassy terrain!");
|
||||
MESSAGE("Foe Wobbuffet is healed by the grassy terrain!");
|
||||
MESSAGE("The grass disappeared from the battlefield.");
|
||||
}
|
||||
}
|
||||
|
||||
27
test/battle/test_runner_features.c
Normal file
27
test/battle/test_runner_features.c
Normal file
@@ -0,0 +1,27 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
ASSUMPTIONS {
|
||||
int i;
|
||||
for (i = 0; i < NUM_ABILITY_SLOTS; i++) {
|
||||
ASSUME(gSpeciesInfo[SPECIES_KADABRA].abilities[i] != ABILITY_QUARK_DRIVE);
|
||||
ASSUME(gSpeciesInfo[SPECIES_ALAKAZAM].abilities[i] != ABILITY_ELECTRIC_SURGE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Forced abilities activate on switch-in")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_ALAKAZAM);
|
||||
PLAYER(SPECIES_KADABRA) { Ability(ABILITY_QUARK_DRIVE); SpAttack(400);}
|
||||
OPPONENT(SPECIES_ARON);
|
||||
OPPONENT(SPECIES_ALAKAZAM) { Ability(ABILITY_ELECTRIC_SURGE); };
|
||||
} WHEN {
|
||||
TURN { SWITCH(player, 1); SWITCH(opponent, 1);}
|
||||
} SCENE {
|
||||
ABILITY_POPUP(opponent, ABILITY_ELECTRIC_SURGE);
|
||||
ABILITY_POPUP(player, ABILITY_QUARK_DRIVE);
|
||||
MESSAGE("The Electric Terrain activated Kadabra's Quark Drive!");
|
||||
MESSAGE("Kadabra's Sp. Atk was heightened!");
|
||||
}
|
||||
}
|
||||
@@ -113,3 +113,50 @@ TEST("ModifyPersonalityForNature can set any nature")
|
||||
ModifyPersonalityForNature(&personality, nature);
|
||||
EXPECT_EQ(GetNatureFromPersonality(personality), nature);
|
||||
}
|
||||
|
||||
static const struct TrainerMon sTestParty2[] =
|
||||
{
|
||||
{
|
||||
.species = SPECIES_WYNAUT,
|
||||
.lvl = 5,
|
||||
},
|
||||
{
|
||||
.species = SPECIES_WYNAUT,
|
||||
.lvl = 5,
|
||||
},
|
||||
{
|
||||
.species = SPECIES_WYNAUT,
|
||||
.lvl = 5,
|
||||
},
|
||||
{
|
||||
.species = SPECIES_WYNAUT,
|
||||
.lvl = 5,
|
||||
},
|
||||
{
|
||||
.species = SPECIES_WYNAUT,
|
||||
.lvl = 5,
|
||||
},
|
||||
{
|
||||
.species = SPECIES_WYNAUT,
|
||||
.lvl = 5,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct Trainer sTestTrainer2 =
|
||||
{
|
||||
.trainerName = _("Test2"),
|
||||
.trainerClass = TRAINER_CLASS_BLACK_BELT,
|
||||
.party = TRAINER_PARTY(sTestParty2),
|
||||
};
|
||||
|
||||
TEST("Trainer Class Balls apply to the entire party")
|
||||
{
|
||||
u32 j;
|
||||
struct Pokemon *testParty = Alloc(6 * sizeof(struct Pokemon));
|
||||
CreateNPCTrainerPartyFromTrainer(testParty, &sTestTrainer2, TRUE, BATTLE_TYPE_TRAINER);
|
||||
for(j = 0; j < 6; j++)
|
||||
{
|
||||
EXPECT(GetMonData(&testParty[j], MON_DATA_POKEBALL, 0) == gTrainerClasses[sTestTrainer2.trainerClass].ball);
|
||||
}
|
||||
Free(testParty);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
.isShiny = TRUE,
|
||||
#line 18
|
||||
.dynamaxLevel = 5,
|
||||
.useGimmick = GIMMICK_DYNAMAX,
|
||||
.shouldUseDynamax = TRUE,
|
||||
.moves = {
|
||||
#line 19
|
||||
MOVE_AIR_SLASH,
|
||||
|
||||
@@ -53,3 +53,20 @@ SINGLE_BATTLE_TEST("Hail fails if Desolate Land or Primordial Sea are active")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Hail deals damage based on turn order")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_GLALIE);
|
||||
PLAYER(SPECIES_WYNAUT) { Speed(1); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(2); }
|
||||
OPPONENT(SPECIES_WYNAUT) { Speed(3); }
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_HAIL); }
|
||||
} SCENE {
|
||||
NOT HP_BAR(playerLeft);
|
||||
HP_BAR(opponentRight);
|
||||
HP_BAR(opponentLeft);
|
||||
HP_BAR(playerRight);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ SINGLE_BATTLE_TEST("Sandstorm deals 1/16 damage per turn")
|
||||
SINGLE_BATTLE_TEST("Sandstorm multiplies the special defense of Rock-types by 1.5x", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_SANDSTORM; }
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_SANDSTORM; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_SWIFT].category == DAMAGE_CATEGORY_SPECIAL);
|
||||
PLAYER(SPECIES_WOBBUFFET) ;
|
||||
@@ -65,3 +65,20 @@ SINGLE_BATTLE_TEST("Sandstorm damage does not hurt Ground, Rock, and Steel-type
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Sandstorm deals damage based on turn order")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_PHANPY);
|
||||
PLAYER(SPECIES_WYNAUT) { Speed(1); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(2); }
|
||||
OPPONENT(SPECIES_WYNAUT) { Speed(3); }
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_SANDSTORM); }
|
||||
} SCENE {
|
||||
NOT HP_BAR(playerLeft);
|
||||
HP_BAR(opponentRight);
|
||||
HP_BAR(opponentLeft);
|
||||
HP_BAR(playerRight);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@ ASSUMPTIONS
|
||||
SINGLE_BATTLE_TEST("Snow multiplies the defense of Ice-types by 1.5x", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_SNOWSCAPE; }
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_SNOWSCAPE; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_GLALIE);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "global.h"
|
||||
#include "string_util.h"
|
||||
#include "test/test.h"
|
||||
#include "constants/form_change_types.h"
|
||||
|
||||
@@ -138,3 +139,18 @@ TEST("No species has two evolutions that use the evolution tracker")
|
||||
|
||||
EXPECT(evolutionTrackerEvolutions < 2);
|
||||
}
|
||||
|
||||
extern const u8 gFallbackPokedexText[];
|
||||
|
||||
TEST("Every species has a description")
|
||||
{
|
||||
u32 i;
|
||||
u32 species = SPECIES_NONE;
|
||||
for (i = 1; i < NUM_SPECIES; i++)
|
||||
{
|
||||
if (IsSpeciesEnabled(i))
|
||||
PARAMETRIZE { species = i; }
|
||||
}
|
||||
|
||||
EXPECT_NE(StringCompare(GetSpeciesPokedexDescription(species), gFallbackPokedexText), 0);
|
||||
}
|
||||
|
||||
@@ -120,7 +120,6 @@ top:
|
||||
MoveSaveBlocks_ResetHeap();
|
||||
ClearSav1();
|
||||
ClearSav2();
|
||||
// ClearSav3();
|
||||
|
||||
gIntrTable[7] = Intr_Timer2;
|
||||
|
||||
@@ -181,6 +180,7 @@ top:
|
||||
}
|
||||
|
||||
Test_MgbaPrintf(":N%s", gTestRunnerState.test->name);
|
||||
Test_MgbaPrintf(":L%s:%d", gTestRunnerState.test->filename);
|
||||
gTestRunnerState.result = TEST_RESULT_PASS;
|
||||
gTestRunnerState.expectedResult = TEST_RESULT_PASS;
|
||||
gTestRunnerState.expectLeaks = FALSE;
|
||||
@@ -218,6 +218,7 @@ top:
|
||||
// NOTE: Assumes that the compiler interns __FILE__.
|
||||
if (gTestRunnerState.skipFilename == gTestRunnerState.test->filename) // Assumption fails for tests in this file.
|
||||
{
|
||||
Test_MgbaPrintf(":L%s:%d", gTestRunnerState.test->filename, gTestRunnerState.failedAssumptionsBlockLine);
|
||||
gTestRunnerState.result = TEST_RESULT_ASSUMPTION_FAIL;
|
||||
return;
|
||||
}
|
||||
@@ -482,9 +483,10 @@ static void Intr_Timer2(void)
|
||||
}
|
||||
}
|
||||
|
||||
void Test_ExitWithResult(enum TestResult result, const char *fmt, ...)
|
||||
void Test_ExitWithResult(enum TestResult result, u32 stopLine, const char *fmt, ...)
|
||||
{
|
||||
gTestRunnerState.result = result;
|
||||
gTestRunnerState.failedAssumptionsBlockLine = stopLine;
|
||||
ReinitCallbacks();
|
||||
if (gTestRunnerState.state == STATE_REPORT_RESULT
|
||||
&& gTestRunnerState.result != gTestRunnerState.expectedResult)
|
||||
@@ -692,3 +694,24 @@ void DACSHandle(void)
|
||||
ReinitCallbacks();
|
||||
DACS_LR = ((uintptr_t)JumpToAgbMainLoop & ~1) + 4;
|
||||
}
|
||||
|
||||
static const struct Test *GetTest(void)
|
||||
{
|
||||
const struct Test *test = gTestRunnerState.test;
|
||||
return test;
|
||||
}
|
||||
|
||||
u32 SourceLine(u32 sourceLineOffset)
|
||||
{
|
||||
const struct Test *test = GetTest();
|
||||
return test->sourceLine + sourceLineOffset;
|
||||
}
|
||||
|
||||
u32 SourceLineOffset(u32 sourceLine)
|
||||
{
|
||||
const struct Test *test = GetTest();
|
||||
if (sourceLine - test->sourceLine > 0xFF)
|
||||
return 0;
|
||||
else
|
||||
return sourceLine - test->sourceLine;
|
||||
}
|
||||
|
||||
@@ -27,10 +27,10 @@
|
||||
#undef TestRunner_Battle_GetForcedAbility
|
||||
#endif
|
||||
|
||||
#define INVALID(fmt, ...) Test_ExitWithResult(TEST_RESULT_INVALID, "%s:%d: " fmt, gTestRunnerState.test->filename, sourceLine, ##__VA_ARGS__)
|
||||
#define INVALID_IF(c, fmt, ...) do { if (c) Test_ExitWithResult(TEST_RESULT_INVALID, "%s:%d: " fmt, gTestRunnerState.test->filename, sourceLine, ##__VA_ARGS__); } while (0)
|
||||
#define INVALID(fmt, ...) Test_ExitWithResult(TEST_RESULT_INVALID, sourceLine, ":L%s:%d: " fmt, gTestRunnerState.test->filename, sourceLine, ##__VA_ARGS__)
|
||||
#define INVALID_IF(c, fmt, ...) do { if (c) Test_ExitWithResult(TEST_RESULT_INVALID, sourceLine, ":L%s:%d: " fmt, gTestRunnerState.test->filename, sourceLine, ##__VA_ARGS__); } while (0)
|
||||
|
||||
#define ASSUMPTION_FAIL_IF(c, fmt, ...) do { if (c) Test_ExitWithResult(TEST_RESULT_ASSUMPTION_FAIL, "%s:%d: " fmt, gTestRunnerState.test->filename, sourceLine, ##__VA_ARGS__); } while (0)
|
||||
#define ASSUMPTION_FAIL_IF(c, fmt, ...) do { if (c) Test_ExitWithResult(TEST_RESULT_ASSUMPTION_FAIL, sourceLine, ":L%s:%d: " fmt, gTestRunnerState.test->filename, sourceLine, ##__VA_ARGS__); } while (0)
|
||||
|
||||
#define STATE gBattleTestRunnerState
|
||||
#define DATA gBattleTestRunnerState->data
|
||||
@@ -147,21 +147,6 @@ static bool32 IsAITest(void)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static u32 SourceLine(u32 sourceLineOffset)
|
||||
{
|
||||
const struct BattleTest *test = GetBattleTest();
|
||||
return test->sourceLine + sourceLineOffset;
|
||||
}
|
||||
|
||||
static u32 SourceLineOffset(u32 sourceLine)
|
||||
{
|
||||
const struct BattleTest *test = GetBattleTest();
|
||||
if (sourceLine - test->sourceLine > 0xFF)
|
||||
return 0;
|
||||
else
|
||||
return sourceLine - test->sourceLine;
|
||||
}
|
||||
|
||||
static u32 BattleTest_EstimateCost(void *data)
|
||||
{
|
||||
u32 cost;
|
||||
@@ -186,9 +171,9 @@ static void BattleTest_SetUp(void *data)
|
||||
InvokeTestFunction(test);
|
||||
STATE->parameters = STATE->parametersCount;
|
||||
if (STATE->parametersCount == 0 && test->resultsSize > 0)
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, "results without PARAMETRIZE");
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":Lresults without PARAMETRIZE");
|
||||
if (sizeof(*STATE) + test->resultsSize * STATE->parameters > sizeof(sBackupMapData))
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, "OOM: STATE (%d) + STATE->results (%d) too big for sBackupMapData (%d)", sizeof(*STATE), test->resultsSize * STATE->parameters, sizeof(sBackupMapData));
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LOOM: STATE (%d) + STATE->results (%d) too big for sBackupMapData (%d)", sizeof(*STATE), test->resultsSize * STATE->parameters, sizeof(sBackupMapData));
|
||||
STATE->results = (void *)((char *)sBackupMapData + sizeof(struct BattleTestRunnerState));
|
||||
memset(STATE->results, 0, test->resultsSize * STATE->parameters);
|
||||
switch (test->type)
|
||||
@@ -262,7 +247,7 @@ static void SetImplicitSpeeds(void)
|
||||
}
|
||||
}
|
||||
if (!madeProgress)
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, "TURNs have contradictory speeds");
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":LTURNs have contradictory speeds");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,9 +321,9 @@ static void BattleTest_Run(void *data)
|
||||
requiredOpponentPartySize = DATA.currentMonIndexes[i] + 1;
|
||||
}
|
||||
if (DATA.playerPartySize < requiredPlayerPartySize)
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, "%d PLAYER Pokemon required", requiredPlayerPartySize);
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":L%d PLAYER Pokemon required", requiredPlayerPartySize);
|
||||
if (DATA.opponentPartySize < requiredOpponentPartySize)
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, "%d OPPONENT Pokemon required", requiredOpponentPartySize);
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":L%d OPPONENT Pokemon required", requiredOpponentPartySize);
|
||||
|
||||
for (i = 0; i < STATE->battlersCount; i++)
|
||||
PushBattlerAction(0, i, RECORDED_BYTE, 0xFF);
|
||||
@@ -348,7 +333,7 @@ static void BattleTest_Run(void *data)
|
||||
if (DATA.explicitSpeeds[B_SIDE_PLAYER] != (1 << DATA.playerPartySize) - 1
|
||||
&& DATA.explicitSpeeds[B_SIDE_OPPONENT] != (1 << DATA.opponentPartySize) - 1)
|
||||
{
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, "Speed required for all PLAYERs and OPPONENTs");
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":LSpeed required for all PLAYERs and OPPONENTs");
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -394,7 +379,7 @@ u32 RandomUniform(enum RandomTag tag, u32 lo, u32 hi)
|
||||
}
|
||||
else if (STATE->trials != n)
|
||||
{
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, "RandomUniform called with inconsistent trials %d and %d", STATE->trials, n);
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomUniform called with inconsistent trials %d and %d", STATE->trials, n);
|
||||
}
|
||||
STATE->trialRatio = Q_4_12(1) / STATE->trials;
|
||||
return STATE->runTrial + lo;
|
||||
@@ -415,7 +400,7 @@ u32 RandomUniformExcept(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32
|
||||
if (turn && turn->rng.tag == tag)
|
||||
{
|
||||
if (reject(turn->rng.value))
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, "WITH_RNG specified a rejected value (%d)", turn->rng.value);
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":LWITH_RNG specified a rejected value (%d)", turn->rng.value);
|
||||
return turn->rng.value;
|
||||
}
|
||||
}
|
||||
@@ -436,7 +421,7 @@ u32 RandomUniformExcept(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32
|
||||
while (reject(STATE->runTrial + lo + STATE->rngTrialOffset))
|
||||
{
|
||||
if (STATE->runTrial + lo + STATE->rngTrialOffset > hi)
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, "RandomUniformExcept called with inconsistent reject");
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":LRandomUniformExcept called with inconsistent reject");
|
||||
STATE->rngTrialOffset++;
|
||||
}
|
||||
|
||||
@@ -447,7 +432,7 @@ u32 RandomUniformExcept(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32
|
||||
while (reject(default_))
|
||||
{
|
||||
if (default_ == lo)
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, "RandomUniformExcept rejected all values");
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":LRandomUniformExcept rejected all values");
|
||||
default_--;
|
||||
}
|
||||
return default_;
|
||||
@@ -458,7 +443,7 @@ u32 RandomWeightedArray(enum RandomTag tag, u32 sum, u32 n, const u8 *weights)
|
||||
const struct BattlerTurn *turn = NULL;
|
||||
|
||||
if (sum == 0)
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, "RandomWeightedArray called with zero sum");
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomWeightedArray called with zero sum");
|
||||
|
||||
if (gCurrentTurnActionNumber < gBattlersCount)
|
||||
{
|
||||
@@ -477,7 +462,7 @@ u32 RandomWeightedArray(enum RandomTag tag, u32 sum, u32 n, const u8 *weights)
|
||||
}
|
||||
else if (STATE->trials != n)
|
||||
{
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, "RandomWeighted called with inconsistent trials %d and %d", STATE->trials, n);
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomWeighted called with inconsistent trials %d and %d", STATE->trials, n);
|
||||
}
|
||||
// TODO: Detect inconsistent sum.
|
||||
STATE->trialRatio = Q_4_12(weights[STATE->runTrial]) / sum;
|
||||
@@ -511,7 +496,7 @@ u32 RandomWeightedArray(enum RandomTag tag, u32 sum, u32 n, const u8 *weights)
|
||||
while (weights[n-1] == 0)
|
||||
{
|
||||
if (n == 1)
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, "RandomWeightedArray called with all zero weights");
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomWeightedArray called with all zero weights");
|
||||
n--;
|
||||
}
|
||||
return n-1;
|
||||
@@ -537,7 +522,7 @@ const void *RandomElementArray(enum RandomTag tag, const void *array, size_t siz
|
||||
return (const u8 *)array + size * index;
|
||||
}
|
||||
// TODO: Incorporate the line number.
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, "%s: RandomElement illegal value requested: %d", gTestRunnerState.test->filename, turn->rng.value);
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":L%s: RandomElement illegal value requested: %d", gTestRunnerState.test->filename, turn->rng.value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -550,7 +535,7 @@ const void *RandomElementArray(enum RandomTag tag, const void *array, size_t siz
|
||||
}
|
||||
else if (STATE->trials != count)
|
||||
{
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, "RandomElement called with inconsistent trials %d and %d", STATE->trials, count);
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomElement called with inconsistent trials %d and %d", STATE->trials, count);
|
||||
}
|
||||
STATE->trialRatio = Q_4_12(1) / count;
|
||||
return (const u8 *)array + size * STATE->runTrial;
|
||||
@@ -601,7 +586,7 @@ void TestRunner_Battle_RecordAbilityPopUp(u32 battlerId, u32 ability)
|
||||
{
|
||||
const char *filename = gTestRunnerState.test->filename;
|
||||
u32 line = SourceLine(DATA.queuedEvents[match].sourceLineOffset);
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Matched ABILITY_POPUP", filename, line);
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, line, ":L%s:%d: Matched ABILITY_POPUP", filename, line);
|
||||
}
|
||||
|
||||
queuedEvent += event->groupSize;
|
||||
@@ -664,7 +649,7 @@ void TestRunner_Battle_RecordAnimation(u32 animType, u32 animId)
|
||||
{
|
||||
const char *filename = gTestRunnerState.test->filename;
|
||||
u32 line = SourceLine(DATA.queuedEvents[match].sourceLineOffset);
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Matched ANIMATION", filename, line);
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, line, ":L%s:%d: Matched ANIMATION", filename, line);
|
||||
}
|
||||
|
||||
queuedEvent += event->groupSize;
|
||||
@@ -754,7 +739,7 @@ void TestRunner_Battle_RecordHP(u32 battlerId, u32 oldHP, u32 newHP)
|
||||
{
|
||||
const char *filename = gTestRunnerState.test->filename;
|
||||
u32 line = SourceLine(DATA.queuedEvents[match].sourceLineOffset);
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Matched HP_BAR", filename, line);
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, line, ":L%s:%d: Matched HP_BAR", filename, line);
|
||||
}
|
||||
|
||||
queuedEvent += event->groupSize;
|
||||
@@ -809,10 +794,10 @@ void TestRunner_Battle_CheckChosenMove(u32 battlerId, u32 moveId, u32 target)
|
||||
bool32 movePasses = FALSE;
|
||||
|
||||
if (expectedAction->type != B_ACTION_USE_MOVE)
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Expected %s, got MOVE", filename, expectedAction->sourceLine, sBattleActionNames[expectedAction->type]);
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Expected %s, got MOVE", filename, expectedAction->sourceLine, sBattleActionNames[expectedAction->type]);
|
||||
|
||||
if (expectedAction->explicitTarget && expectedAction->target != target)
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Expected target %s, got %s", filename, expectedAction->sourceLine, BattlerIdentifier(expectedAction->target), BattlerIdentifier(target));
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Expected target %s, got %s", filename, expectedAction->sourceLine, BattlerIdentifier(expectedAction->target), BattlerIdentifier(target));
|
||||
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
@@ -846,16 +831,16 @@ void TestRunner_Battle_CheckChosenMove(u32 battlerId, u32 moveId, u32 target)
|
||||
u32 moveSlot = GetMoveSlot(gBattleMons[battlerId].moves, moveId);
|
||||
PrintAiMoveLog(battlerId, moveSlot, moveId, gBattleStruct->aiFinalScore[battlerId][expectedAction->target][moveSlot]);
|
||||
if (countExpected > 1)
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Unmatched EXPECT_MOVES %S, got %S", filename, expectedAction->sourceLine, GetMoveName(expectedMoveId), GetMoveName(moveId));
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Unmatched EXPECT_MOVES %S, got %S", filename, expectedAction->sourceLine, GetMoveName(expectedMoveId), GetMoveName(moveId));
|
||||
else
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Unmatched EXPECT_MOVE %S, got %S", filename, expectedAction->sourceLine, GetMoveName(expectedMoveId), GetMoveName(moveId));
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Unmatched EXPECT_MOVE %S, got %S", filename, expectedAction->sourceLine, GetMoveName(expectedMoveId), GetMoveName(moveId));
|
||||
}
|
||||
if (expectedAction->notMove && !movePasses)
|
||||
{
|
||||
if (countExpected > 1)
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Unmatched NOT_EXPECT_MOVES %S", filename, expectedAction->sourceLine, GetMoveName(expectedMoveId));
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Unmatched NOT_EXPECT_MOVES %S", filename, expectedAction->sourceLine, GetMoveName(expectedMoveId));
|
||||
else
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Unmatched NOT_EXPECT_MOVE %S", filename, expectedAction->sourceLine, GetMoveName(expectedMoveId));
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Unmatched NOT_EXPECT_MOVE %S", filename, expectedAction->sourceLine, GetMoveName(expectedMoveId));
|
||||
}
|
||||
}
|
||||
// Turn passed, clear logs from the turn
|
||||
@@ -875,17 +860,17 @@ void TestRunner_Battle_CheckSwitch(u32 battlerId, u32 partyIndex)
|
||||
if (!expectedAction->pass)
|
||||
{
|
||||
if (expectedAction->type != B_ACTION_SWITCH)
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Expected %s, got SWITCH/SEND_OUT", filename, expectedAction->sourceLine, sBattleActionNames[expectedAction->type]);
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Expected %s, got SWITCH/SEND_OUT", filename, expectedAction->sourceLine, sBattleActionNames[expectedAction->type]);
|
||||
|
||||
if (expectedAction->target != partyIndex)
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Expected partyIndex %d, got %d", filename, expectedAction->sourceLine, expectedAction->target, partyIndex);
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Expected partyIndex %d, got %d", filename, expectedAction->sourceLine, expectedAction->target, partyIndex);
|
||||
}
|
||||
DATA.aiActionsPlayed[battlerId]++;
|
||||
}
|
||||
|
||||
void TestRunner_Battle_InvalidNoHPMon(u32 battlerId, u32 partyIndex)
|
||||
{
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, "%s: INVALID: %s trying to send out a mon(id: %d) with 0 HP.",
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":L%s: INVALID: %s trying to send out a mon(id: %d) with 0 HP.",
|
||||
gTestRunnerState.test->filename, BattlerIdentifier(battlerId), gBattlerPartyIndexes[battlerId]);
|
||||
}
|
||||
|
||||
@@ -935,7 +920,7 @@ static void CheckIfMaxScoreEqualExpectMove(u32 battlerId, s32 target, struct Exp
|
||||
&& (aiAction->moveSlots & gBitTable[i])
|
||||
&& !(aiAction->moveSlots & gBitTable[bestScoreId]))
|
||||
{
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: EXPECT_MOVE %S has the same best score(%d) as not expected MOVE %S", filename,
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: EXPECT_MOVE %S has the same best score(%d) as not expected MOVE %S", filename,
|
||||
aiAction->sourceLine, GetMoveName(moves[i]), scores[i], GetMoveName(moves[bestScoreId]));
|
||||
}
|
||||
// We DO NOT expect move 'i', but it has the same best score as another move.
|
||||
@@ -944,7 +929,7 @@ static void CheckIfMaxScoreEqualExpectMove(u32 battlerId, s32 target, struct Exp
|
||||
&& (aiAction->moveSlots & gBitTable[i])
|
||||
&& !(aiAction->moveSlots & gBitTable[bestScoreId]))
|
||||
{
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: NOT_EXPECT_MOVE %S has the same best score(%d) as MOVE %S", filename,
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: NOT_EXPECT_MOVE %S has the same best score(%d) as MOVE %S", filename,
|
||||
aiAction->sourceLine, GetMoveName(moves[i]), scores[i], GetMoveName(moves[bestScoreId]));
|
||||
}
|
||||
}
|
||||
@@ -987,7 +972,7 @@ static void PrintAiMoveLog(u32 battlerId, u32 moveSlot, u32 moveId, s32 totalSco
|
||||
}
|
||||
if (scoreFromLogs != totalScore)
|
||||
{
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, "Warning! Score from logs(%d) is different than actual score(%d). Make sure all of the score adjustments use the ADJUST_SCORE macro\n", scoreFromLogs, totalScore);
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LWarning! Score from logs(%d) is different than actual score(%d). Make sure all of the score adjustments use the ADJUST_SCORE macro\n", scoreFromLogs, totalScore);
|
||||
}
|
||||
Test_MgbaPrintf("Total: %d\n", totalScore);
|
||||
}
|
||||
@@ -1025,7 +1010,7 @@ void TestRunner_Battle_CheckAiMoveScores(u32 battlerId)
|
||||
PrintAiMoveLog(battlerId, scoreCtx->moveSlot1, moveId1, scores[scoreCtx->moveSlot1]);
|
||||
if (!CheckComparision(scores[scoreCtx->moveSlot1], scoreCtx->value, scoreCtx->cmp))
|
||||
{
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Unmatched SCORE_%s_VAL %S %d, got %d",
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Unmatched SCORE_%s_VAL %S %d, got %d",
|
||||
filename, scoreCtx->sourceLine, sCmpToStringTable[scoreCtx->cmp], GetMoveName(moveId1), scoreCtx->value, scores[scoreCtx->moveSlot1]);
|
||||
}
|
||||
}
|
||||
@@ -1036,7 +1021,7 @@ void TestRunner_Battle_CheckAiMoveScores(u32 battlerId)
|
||||
PrintAiMoveLog(battlerId, scoreCtx->moveSlot2, moveId2, scores[scoreCtx->moveSlot2]);
|
||||
if (!CheckComparision(scores[scoreCtx->moveSlot1], scores[scoreCtx->moveSlot2], scoreCtx->cmp))
|
||||
{
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Unmatched SCORE_%s, got %S: %d, %S: %d",
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Unmatched SCORE_%s, got %S: %d, %S: %d",
|
||||
filename, scoreCtx->sourceLine, sCmpToStringTable[scoreCtx->cmp], GetMoveName(moveId1), scores[scoreCtx->moveSlot1], GetMoveName(moveId2), scores[scoreCtx->moveSlot2]);
|
||||
}
|
||||
}
|
||||
@@ -1136,7 +1121,7 @@ void TestRunner_Battle_RecordExp(u32 battlerId, u32 oldExp, u32 newExp)
|
||||
{
|
||||
const char *filename = gTestRunnerState.test->filename;
|
||||
u32 line = SourceLine(DATA.queuedEvents[match].sourceLineOffset);
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Matched EXPERIENCE_BAR", filename, line);
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, line, ":L%s:%d: Matched EXPERIENCE_BAR", filename, line);
|
||||
}
|
||||
|
||||
queuedEvent += event->groupSize;
|
||||
@@ -1225,7 +1210,7 @@ void TestRunner_Battle_RecordMessage(const u8 *string)
|
||||
{
|
||||
const char *filename = gTestRunnerState.test->filename;
|
||||
u32 line = SourceLine(DATA.queuedEvents[match].sourceLineOffset);
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Matched MESSAGE", filename, line);
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, line, ":L%s:%d: Matched MESSAGE", filename, line);
|
||||
}
|
||||
|
||||
queuedEvent += event->groupSize;
|
||||
@@ -1290,7 +1275,7 @@ void TestRunner_Battle_RecordStatus1(u32 battlerId, u32 status1)
|
||||
{
|
||||
const char *filename = gTestRunnerState.test->filename;
|
||||
u32 line = SourceLine(DATA.queuedEvents[match].sourceLineOffset);
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Matched STATUS_ICON", filename, line);
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, line, ":L%s:%d: Matched STATUS_ICON", filename, line);
|
||||
}
|
||||
|
||||
queuedEvent += event->groupSize;
|
||||
@@ -1325,7 +1310,7 @@ void TestRunner_Battle_AfterLastTurn(void)
|
||||
if (DATA.turns - 1 != DATA.lastActionTurn)
|
||||
{
|
||||
const char *filename = gTestRunnerState.test->filename;
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: %d TURNs specified, but %d ran", filename, SourceLine(0), DATA.turns, DATA.lastActionTurn + 1);
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: %d TURNs specified, but %d ran", filename, SourceLine(0), DATA.turns, DATA.lastActionTurn + 1);
|
||||
}
|
||||
|
||||
while (DATA.queuedEvent < DATA.queuedEventsCount
|
||||
@@ -1338,7 +1323,7 @@ void TestRunner_Battle_AfterLastTurn(void)
|
||||
const char *filename = gTestRunnerState.test->filename;
|
||||
u32 line = SourceLine(DATA.queuedEvents[DATA.queuedEvent].sourceLineOffset);
|
||||
const char *macro = sEventTypeMacros[DATA.queuedEvents[DATA.queuedEvent].type];
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Unmatched %s", filename, line, macro);
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, line, ":L%s:%d: Unmatched %s", filename, line, macro);
|
||||
}
|
||||
|
||||
STATE->runThen = TRUE;
|
||||
@@ -1420,7 +1405,7 @@ static void CB2_BattleTest_NextTrial(void)
|
||||
if (abs(STATE->observedRatio - STATE->expectedRatio) <= Q_4_12(0.02))
|
||||
gTestRunnerState.result = TEST_RESULT_PASS;
|
||||
else
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "Expected %q passes/successes, observed %q", STATE->expectedRatio, STATE->observedRatio);
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Expected %q passes/successes, observed %q", gTestRunnerState.test->filename, SourceLine(0), STATE->expectedRatio, STATE->observedRatio);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1639,6 +1624,7 @@ void Ability_(u32 sourceLine, u32 ability)
|
||||
u32 species;
|
||||
const struct SpeciesInfo *info;
|
||||
INVALID_IF(!DATA.currentMon, "Ability outside of PLAYER/OPPONENT");
|
||||
INVALID_IF(ability >= ABILITIES_COUNT, "Illegal ability id: %d", ability);
|
||||
species = GetMonData(DATA.currentMon, MON_DATA_SPECIES);
|
||||
info = &gSpeciesInfo[species];
|
||||
for (i = 0; i < NUM_ABILITY_SLOTS; i++)
|
||||
@@ -1875,7 +1861,7 @@ static void PushBattlerAction(u32 sourceLine, s32 battlerId, u32 actionType, u32
|
||||
{
|
||||
u32 recordIndex = DATA.recordIndexes[battlerId]++;
|
||||
if (recordIndex >= BATTLER_RECORD_SIZE)
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, "Too many actions");
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":LToo many actions");
|
||||
DATA.battleRecordTypes[battlerId][recordIndex] = actionType;
|
||||
DATA.battleRecordSourceLineOffsets[battlerId][recordIndex] = SourceLineOffset(sourceLine);
|
||||
DATA.recordedBattle.battleRecord[battlerId][recordIndex] = byte;
|
||||
@@ -1897,10 +1883,10 @@ void TestRunner_Battle_CheckBattleRecordActionType(u32 battlerId, u32 recordInde
|
||||
&& DATA.recordedBattle.battleRecord[battlerId][i-1] == B_ACTION_USE_MOVE)
|
||||
{
|
||||
u32 line = SourceLine(DATA.battleRecordSourceLineOffsets[battlerId][i-1]);
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, "%s:%d: Illegal MOVE", filename, line);
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, line, ":L%s:%d: Illegal MOVE", filename, line);
|
||||
}
|
||||
}
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, "%s:%d: Illegal MOVE", filename, SourceLine(0));
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":L%s:%d: Illegal MOVE", filename, SourceLine(0));
|
||||
}
|
||||
|
||||
if (DATA.battleRecordTypes[battlerId][recordIndex] != RECORDED_BYTE)
|
||||
@@ -1928,13 +1914,13 @@ void TestRunner_Battle_CheckBattleRecordActionType(u32 battlerId, u32 recordInde
|
||||
switch (actionType)
|
||||
{
|
||||
case RECORDED_ACTION_TYPE:
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, "%s:%d: Expected MOVE/SWITCH, got %s", filename, line, actualMacro);
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, line, ":L%s:%d: Expected MOVE/SWITCH, got %s", filename, line, actualMacro);
|
||||
case RECORDED_PARTY_INDEX:
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, "%s:%d: Expected SEND_OUT, got %s", filename, line, actualMacro);
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, line, ":L%s:%d: Expected SEND_OUT, got %s", filename, line, actualMacro);
|
||||
}
|
||||
}
|
||||
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, "%s:%d: Illegal battle record", filename, line);
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, line, ":L%s:%d: Illegal battle record", filename, line);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1942,7 +1928,7 @@ void TestRunner_Battle_CheckBattleRecordActionType(u32 battlerId, u32 recordInde
|
||||
if (DATA.lastActionTurn == gBattleResults.battleTurnCounter)
|
||||
{
|
||||
const char *filename = gTestRunnerState.test->filename;
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: TURN %d incomplete", filename, SourceLine(0), gBattleResults.battleTurnCounter + 1);
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: TURN %d incomplete", filename, SourceLine(0), gBattleResults.battleTurnCounter + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1951,7 +1937,7 @@ void OpenTurn(u32 sourceLine)
|
||||
{
|
||||
INVALID_IF(DATA.turnState != TURN_CLOSED, "Nested TURN");
|
||||
if (DATA.turns == MAX_TURNS)
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, "%s:%d: TURN exceeds MAX_TURNS", gTestRunnerState.test->filename, sourceLine);
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, sourceLine, ":L%s:%d: TURN exceeds MAX_TURNS", gTestRunnerState.test->filename, sourceLine);
|
||||
DATA.turnState = TURN_OPEN;
|
||||
DATA.actionBattlers = 0x00;
|
||||
DATA.moveBattlers = 0x00;
|
||||
@@ -2483,7 +2469,7 @@ void QueueAbility(u32 sourceLine, struct BattlePokemon *battler, struct AbilityE
|
||||
s32 battlerId = battler - gBattleMons;
|
||||
INVALID_IF(!STATE->runScene, "ABILITY_POPUP outside of SCENE");
|
||||
if (DATA.queuedEventsCount == MAX_QUEUED_EVENTS)
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, "%s:%d: ABILITY exceeds MAX_QUEUED_EVENTS", gTestRunnerState.test->filename, sourceLine);
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, sourceLine, ":L%s:%d: ABILITY exceeds MAX_QUEUED_EVENTS", gTestRunnerState.test->filename, sourceLine);
|
||||
DATA.queuedEvents[DATA.queuedEventsCount++] = (struct QueuedEvent) {
|
||||
.type = QUEUED_ABILITY_POPUP_EVENT,
|
||||
.sourceLineOffset = SourceLineOffset(sourceLine),
|
||||
@@ -2503,7 +2489,7 @@ void QueueAnimation(u32 sourceLine, u32 type, u32 id, struct AnimationEventConte
|
||||
|
||||
INVALID_IF(!STATE->runScene, "ANIMATION outside of SCENE");
|
||||
if (DATA.queuedEventsCount == MAX_QUEUED_EVENTS)
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, "%s:%d: ANIMATION exceeds MAX_QUEUED_EVENTS", gTestRunnerState.test->filename, sourceLine);
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, sourceLine, ":L%s:%d: ANIMATION exceeds MAX_QUEUED_EVENTS", gTestRunnerState.test->filename, sourceLine);
|
||||
|
||||
attackerId = ctx.attacker ? ctx.attacker - gBattleMons : 0xF;
|
||||
if (type == ANIM_TYPE_MOVE)
|
||||
@@ -2538,7 +2524,7 @@ void QueueHP(u32 sourceLine, struct BattlePokemon *battler, struct HPEventContex
|
||||
|
||||
INVALID_IF(!STATE->runScene, "HP_BAR outside of SCENE");
|
||||
if (DATA.queuedEventsCount == MAX_QUEUED_EVENTS)
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, "%s:%d: HP_BAR exceeds MAX_QUEUED_EVENTS", gTestRunnerState.test->filename, sourceLine);
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, sourceLine, ":L%s:%d: HP_BAR exceeds MAX_QUEUED_EVENTS", gTestRunnerState.test->filename, sourceLine);
|
||||
|
||||
if (ctx.explicitHP)
|
||||
{
|
||||
@@ -2591,7 +2577,7 @@ void QueueExp(u32 sourceLine, struct BattlePokemon *battler, struct ExpEventCont
|
||||
|
||||
INVALID_IF(!STATE->runScene, "EXPERIENCE_BAR outside of SCENE");
|
||||
if (DATA.queuedEventsCount == MAX_QUEUED_EVENTS)
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, "%s:%d: EXPERIENCE_BAR exceeds MAX_QUEUED_EVENTS", gTestRunnerState.test->filename, sourceLine);
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, sourceLine, ":L%s:%d: EXPERIENCE_BAR exceeds MAX_QUEUED_EVENTS", gTestRunnerState.test->filename, sourceLine);
|
||||
|
||||
if (ctx.explicitExp)
|
||||
{
|
||||
@@ -2628,7 +2614,7 @@ void QueueMessage(u32 sourceLine, const u8 *pattern)
|
||||
{
|
||||
INVALID_IF(!STATE->runScene, "MESSAGE outside of SCENE");
|
||||
if (DATA.queuedEventsCount == MAX_QUEUED_EVENTS)
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, "%s:%d: MESSAGE exceeds MAX_QUEUED_EVENTS", gTestRunnerState.test->filename, sourceLine);
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, sourceLine, ":L%s:%d: MESSAGE exceeds MAX_QUEUED_EVENTS", gTestRunnerState.test->filename, sourceLine);
|
||||
DATA.queuedEvents[DATA.queuedEventsCount++] = (struct QueuedEvent) {
|
||||
.type = QUEUED_MESSAGE_EVENT,
|
||||
.sourceLineOffset = SourceLineOffset(sourceLine),
|
||||
@@ -2647,7 +2633,7 @@ void QueueStatus(u32 sourceLine, struct BattlePokemon *battler, struct StatusEve
|
||||
|
||||
INVALID_IF(!STATE->runScene, "STATUS_ICON outside of SCENE");
|
||||
if (DATA.queuedEventsCount == MAX_QUEUED_EVENTS)
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, "%s:%d: STATUS_ICON exceeds MAX_QUEUED_EVENTS", gTestRunnerState.test->filename, sourceLine);
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, sourceLine, ":L%s:%d: STATUS_ICON exceeds MAX_QUEUED_EVENTS", gTestRunnerState.test->filename, sourceLine);
|
||||
|
||||
if (ctx.none)
|
||||
mask = 0;
|
||||
@@ -2711,7 +2697,7 @@ struct AILogLine *GetLogLine(u32 battlerId, u32 moveIndex)
|
||||
}
|
||||
}
|
||||
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, "Too many AI log lines");
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LToo many AI log lines");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
21
test/text.c
21
test/text.c
@@ -275,7 +275,7 @@ TEST("Item names fit on Shop Screen")
|
||||
TEST("Species names fit on Battle Screen HP box")
|
||||
{
|
||||
u32 i, genderWidthPx;
|
||||
const u32 fontId = FONT_SMALL_NARROWER, widthPx = 54;
|
||||
const u32 fontId = FONT_SMALL_NARROWER, widthPx = 55;
|
||||
u32 species = SPECIES_NONE;
|
||||
genderWidthPx = GetStringWidth(fontId, COMPOUND_STRING("♂"), 0);
|
||||
for (i = 1; i < NUM_SPECIES; i++)
|
||||
@@ -501,6 +501,25 @@ TEST("Species names fit on PokeNav Ribbon List Screen")
|
||||
EXPECT_LE(GetStringWidth(fontId, gSpeciesInfo[species].speciesName, 0), widthPx);
|
||||
}
|
||||
|
||||
TEST("Species names fit on Battle Screen HP box for vanilla mons with the default font")
|
||||
{
|
||||
u32 i, genderWidthPx;
|
||||
const u32 fontId = FONT_SMALL, widthPx = 55;
|
||||
u32 species = SPECIES_NONE;
|
||||
genderWidthPx = GetStringWidth(fontId, COMPOUND_STRING("♂"), 0);
|
||||
for (i = 1; i < SPECIES_TURTWIG; i++)
|
||||
{
|
||||
if (IsSpeciesEnabled(i))
|
||||
{
|
||||
PARAMETRIZE_LABEL("%S", gSpeciesInfo[i].speciesName) { species = i; }
|
||||
}
|
||||
}
|
||||
if (gSpeciesInfo[i].genderRatio != MON_GENDERLESS)
|
||||
EXPECT_LE(GetStringWidth(fontId, gSpeciesInfo[species].speciesName, 0) - genderWidthPx, widthPx);
|
||||
else
|
||||
EXPECT_LE(GetStringWidth(fontId, gSpeciesInfo[species].speciesName, 0), widthPx);
|
||||
}
|
||||
|
||||
TEST("Ability names fit on Pokemon Summary Screen")
|
||||
{
|
||||
u32 i;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
*
|
||||
* COMMANDS
|
||||
* N: Sets the test name to the remainder of the line.
|
||||
* L: Sets the filename to the remainder of the line.
|
||||
* R: Sets the result to the remainder of the line, and flushes any
|
||||
* output buffered since the previous R.
|
||||
* P/K/F/A: Sets the result to the remaining of the line, flushes any
|
||||
@@ -46,6 +47,7 @@ struct Runner
|
||||
int outfd;
|
||||
char rom_path[FILENAME_MAX];
|
||||
char test_name[256];
|
||||
char filename_line[256];
|
||||
size_t input_buffer_size;
|
||||
size_t input_buffer_capacity;
|
||||
char *input_buffer;
|
||||
@@ -59,8 +61,12 @@ struct Runner
|
||||
int assumptionFails;
|
||||
int fails;
|
||||
int results;
|
||||
char failedTestNames[MAX_SUMMARY_TESTS_TO_LIST][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
char knownFailingPassedTestNames[MAX_SUMMARY_TESTS_TO_LIST][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
char failed_TestNames[MAX_SUMMARY_TESTS_TO_LIST][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
char failed_TestFilenameLine[MAX_SUMMARY_TESTS_TO_LIST][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
char knownFailingPassed_TestNames[MAX_SUMMARY_TESTS_TO_LIST][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
char knownFailingPassed_FilenameLine[MAX_SUMMARY_TESTS_TO_LIST][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
char assumeFailed_TestNames[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
char assumeFailed_FilenameLine[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
};
|
||||
|
||||
static unsigned nrunners = 0;
|
||||
@@ -102,6 +108,16 @@ static void handle_read(int i, struct Runner *runner)
|
||||
strncpy(runner->test_name, soc, eol - soc - 1);
|
||||
runner->test_name[eol - soc - 1] = '\0';
|
||||
break;
|
||||
case 'L':
|
||||
soc += 2;
|
||||
if (sizeof(runner->filename_line) <= eol - soc - 1)
|
||||
{
|
||||
fprintf(stderr, "filename_line too long\n");
|
||||
exit(2);
|
||||
}
|
||||
strncpy(runner->filename_line, soc, eol - soc - 1);
|
||||
runner->filename_line[eol - soc - 1] = '\0';
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
runner->passes++;
|
||||
@@ -111,18 +127,29 @@ static void handle_read(int i, struct Runner *runner)
|
||||
goto add_to_results;
|
||||
case 'U':
|
||||
if (runner->knownFailsPassing < MAX_SUMMARY_TESTS_TO_LIST)
|
||||
strcpy(runner->knownFailingPassedTestNames[runner->knownFailsPassing], runner->test_name);
|
||||
{
|
||||
strcpy(runner->knownFailingPassed_TestNames[runner->knownFailsPassing], runner->test_name);
|
||||
strcpy(runner->knownFailingPassed_FilenameLine[runner->knownFailsPassing], runner->filename_line);
|
||||
}
|
||||
runner->knownFailsPassing++;
|
||||
goto add_to_results;
|
||||
case 'T':
|
||||
runner->todos++;
|
||||
goto add_to_results;
|
||||
case 'A':
|
||||
if (runner->assumptionFails < MAX_SUMMARY_TESTS_TO_LIST)
|
||||
{
|
||||
strcpy(runner->assumeFailed_TestNames[runner->assumptionFails], runner->test_name);
|
||||
strcpy(runner->assumeFailed_FilenameLine[runner->assumptionFails], runner->filename_line);
|
||||
}
|
||||
runner->assumptionFails++;
|
||||
goto add_to_results;
|
||||
case 'F':
|
||||
if (runner->fails < MAX_SUMMARY_TESTS_TO_LIST)
|
||||
strcpy(runner->failedTestNames[runner->fails], runner->test_name);
|
||||
{
|
||||
strcpy(runner->failed_TestNames[runner->fails], runner->test_name);
|
||||
strcpy(runner->failed_TestFilenameLine[runner->fails], runner->filename_line);
|
||||
}
|
||||
runner->fails++;
|
||||
add_to_results:
|
||||
runner->results++;
|
||||
@@ -532,8 +559,14 @@ int main(int argc, char *argv[])
|
||||
int fails = 0;
|
||||
int results = 0;
|
||||
|
||||
char failedTestNames[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
char knownFailingPassedTestNames[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
char failed_TestNames[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
char failed_TestFilenameLine[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
|
||||
char knownFailingPassed_TestNames[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
char knownFailingPassed_FilenameLine[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
|
||||
char assumeFailed_TestNames[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
char assumeFailed_FilenameLine[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
|
||||
for (int i = 0; i < nrunners; i++)
|
||||
{
|
||||
@@ -552,33 +585,43 @@ int main(int argc, char *argv[])
|
||||
for (int j = 0; j < runners[i].knownFailsPassing; j++)
|
||||
{
|
||||
if (j < MAX_SUMMARY_TESTS_TO_LIST)
|
||||
strcpy(knownFailingPassedTestNames[fails], runners[i].knownFailingPassedTestNames[j]);
|
||||
{
|
||||
strcpy(knownFailingPassed_TestNames[knownFailsPassing], runners[i].knownFailingPassed_TestNames[j]);
|
||||
strcpy(knownFailingPassed_FilenameLine[knownFailsPassing], runners[i].knownFailingPassed_FilenameLine[j]);
|
||||
}
|
||||
knownFailsPassing++;
|
||||
}
|
||||
todos += runners[i].todos;
|
||||
assumptionFails += runners[i].assumptionFails;
|
||||
for (int j = 0; j < runners[i].assumptionFails; j++)
|
||||
{
|
||||
if (j < MAX_SUMMARY_TESTS_TO_LIST)
|
||||
{
|
||||
strcpy(assumeFailed_TestNames[assumptionFails], runners[i].assumeFailed_TestNames[j]);
|
||||
strcpy(assumeFailed_FilenameLine[assumptionFails], runners[i].assumeFailed_FilenameLine[j]);
|
||||
}
|
||||
assumptionFails++;
|
||||
}
|
||||
for (int j = 0; j < runners[i].fails; j++)
|
||||
{
|
||||
if (j < MAX_SUMMARY_TESTS_TO_LIST)
|
||||
strcpy(failedTestNames[fails], runners[i].failedTestNames[j]);
|
||||
{
|
||||
strcpy(failed_TestNames[fails], runners[i].failed_TestNames[j]);
|
||||
strcpy(failed_TestFilenameLine[fails], runners[i].failed_TestFilenameLine[j]);
|
||||
}
|
||||
fails++;
|
||||
}
|
||||
results += runners[i].results;
|
||||
}
|
||||
|
||||
qsort(failedTestNames, min(fails, MAX_SUMMARY_TESTS_TO_LIST), sizeof(char) * MAX_TEST_LIST_BUFFER_LENGTH, compare_strings);
|
||||
qsort(knownFailingPassedTestNames, min(fails, MAX_SUMMARY_TESTS_TO_LIST), sizeof(char) * MAX_TEST_LIST_BUFFER_LENGTH, compare_strings);
|
||||
|
||||
if (results == 0)
|
||||
{
|
||||
fprintf(stdout, "\nNo tests found.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stdout, "\n");
|
||||
if (fails > 0)
|
||||
{
|
||||
fprintf(stdout, "- Tests \e[31mFAILED\e[0m : %d Add TESTS='X' to run tests with the defined prefix.\n", fails);
|
||||
fprintf(stdout, "\n \e[31mFAILED\e[0m tests:\n");
|
||||
for (int i = 0; i < fails; i++)
|
||||
{
|
||||
if (i >= MAX_SUMMARY_TESTS_TO_LIST)
|
||||
@@ -586,31 +629,51 @@ int main(int argc, char *argv[])
|
||||
fprintf(stdout, " - \e[31mand %d more...\e[0m\n", fails - MAX_SUMMARY_TESTS_TO_LIST);
|
||||
break;
|
||||
}
|
||||
fprintf(stdout, " - \e[31m%s\e[0m.\n", failedTestNames[i]);
|
||||
fprintf(stdout, " - \e[31m%s\e[0m - %s.\n", failed_TestFilenameLine[i], failed_TestNames[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (assumptionFails > 0)
|
||||
{
|
||||
fprintf(stdout, "\n Tests with \e[33mASSUMPTIONS_FAILED\e[0m:\n");
|
||||
for (int i = 0; i < assumptionFails; i++)
|
||||
{
|
||||
if (i >= MAX_SUMMARY_TESTS_TO_LIST)
|
||||
{
|
||||
fprintf(stdout, " - \e[33mand %d more...\e[0m\n", assumptionFails - MAX_SUMMARY_TESTS_TO_LIST);
|
||||
break;
|
||||
}
|
||||
fprintf(stdout, " - \e[33m%s\e[0m - %s.\n", assumeFailed_FilenameLine[i], assumeFailed_TestNames[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (knownFailsPassing > 0)
|
||||
{
|
||||
fprintf(stdout, "- \e[31mKNOWN_FAILING_PASSED\e[0m: %d \e[31mPlease remove KNOWN_FAILING if these tests intentionally PASS\e[0m\n", knownFailsPassing);
|
||||
fprintf(stdout, "\n \e[33mKNOWN_FAILING\e[0m tests \e[32mPASSING\e[0m:\n");
|
||||
for (int i = 0; i < knownFailsPassing; i++)
|
||||
{
|
||||
if (i >= MAX_SUMMARY_TESTS_TO_LIST)
|
||||
{
|
||||
fprintf(stdout, " - \e[31mand %d more...\e[0m\n", knownFailsPassing - MAX_SUMMARY_TESTS_TO_LIST);
|
||||
fprintf(stdout, " - \e[32mand %d more...\e[0m\n", knownFailsPassing - MAX_SUMMARY_TESTS_TO_LIST);
|
||||
break;
|
||||
}
|
||||
fprintf(stdout, " - \e[31m%s\e[0m.\n", knownFailingPassedTestNames[i]);
|
||||
fprintf(stdout, " - \e[32m%s\e[0m - %s.\n", knownFailingPassed_FilenameLine[i], knownFailingPassed_TestNames[i]);
|
||||
}
|
||||
}
|
||||
fprintf(stdout, "- Tests \e[32mPASSED\e[0m: %d\n", passes);
|
||||
if (knownFails > 0)
|
||||
fprintf(stdout, "- Tests \e[33mKNOWN_FAILING\e[0m: %d\n", knownFails);
|
||||
if (todos > 0)
|
||||
fprintf(stdout, "- Tests \e[33mTO_DO\e[0m: %d\n", todos);
|
||||
if (assumptionFails > 0)
|
||||
fprintf(stdout, "- \e[33mASSUMPTIONS_FAILED\e[0m: %d\n", assumptionFails);
|
||||
|
||||
fprintf(stdout, "- Tests \e[34mTOTAL\e[0m: %d\n", results);
|
||||
fprintf(stdout, "\n");
|
||||
if (fails > 0)
|
||||
fprintf(stdout, "- Tests \e[31mFAILED\e[0m : %d Add TESTS='X' to run tests with the defined prefix.\n", fails);
|
||||
if (knownFails > 0)
|
||||
fprintf(stdout, "- Tests \e[33mKNOWN_FAILING\e[0m: %d\n", knownFails);
|
||||
if (assumptionFails > 0)
|
||||
fprintf(stdout, "- \e[33mASSUMPTIONS_FAILED\e[0m: %d\n", assumptionFails);
|
||||
if (todos > 0)
|
||||
fprintf(stdout, "- Tests \e[33mTO_DO\e[0m: %d\n", todos);
|
||||
if (knownFailsPassing > 0)
|
||||
fprintf(stdout, "- \e[32mKNOWN_FAILING_PASSING\e[0m: %d \e[33mPlease remove KNOWN_FAILING if these tests intentionally PASS\e[0m\n", knownFailsPassing);
|
||||
fprintf(stdout, "- Tests \e[32mPASSED\e[0m: %d\n", passes);
|
||||
fprintf(stdout, "- Tests \e[34mTOTAL\e[0m: %d\n", results);
|
||||
}
|
||||
fprintf(stdout, "\n");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user