Merge branch 'RHH/master' into RHH/upcoming
# Conflicts: # asm/macros/battle_script.inc # src/battle_script_commands.c
This commit is contained in:
commit
1137d54b61
4
Makefile
4
Makefile
@ -85,7 +85,11 @@ ELF = $(ROM:.gba=.elf)
|
||||
MAP = $(ROM:.gba=.map)
|
||||
SYM = $(ROM:.gba=.sym)
|
||||
|
||||
ifeq ($(MODERN),0)
|
||||
TEST_OBJ_DIR_NAME := build/test
|
||||
else
|
||||
TEST_OBJ_DIR_NAME := build/modern-test
|
||||
endif
|
||||
TESTELF = $(ROM:.gba=-test.elf)
|
||||
HEADLESSELF = $(ROM:.gba=-test-headless.elf)
|
||||
|
||||
|
||||
@ -1456,6 +1456,11 @@
|
||||
.4byte \jumpInstr
|
||||
.endm
|
||||
|
||||
.macro tryreflecttype failInstr:req
|
||||
callnative BS_TryReflectType
|
||||
.4byte \failInstr
|
||||
.endm
|
||||
|
||||
@ Used to active a different Max Move effects.
|
||||
.macro setmaxmoveeffect
|
||||
callnative BS_SetMaxMoveEffect
|
||||
@ -1729,11 +1734,6 @@
|
||||
.4byte \failInstr
|
||||
.endm
|
||||
|
||||
.macro tryreflecttype failInstr:req
|
||||
various BS_ATTACKER, VARIOUS_TRY_REFLECT_TYPE
|
||||
.4byte \failInstr
|
||||
.endm
|
||||
|
||||
.macro trysoak failInstr:req
|
||||
various BS_ATTACKER, VARIOUS_TRY_SOAK
|
||||
.4byte \failInstr
|
||||
|
||||
@ -753,12 +753,16 @@ STATIC_ASSERT(sizeof(((struct BattleStruct *)0)->palaceFlags) * 8 >= MAX_BATTLER
|
||||
#define BATTLER_DAMAGED(battlerId) ((gSpecialStatuses[battlerId].physicalDmg != 0 || gSpecialStatuses[battlerId].specialDmg != 0))
|
||||
|
||||
#define IS_BATTLER_OF_TYPE(battlerId, type)((GetBattlerType(battlerId, 0) == type || GetBattlerType(battlerId, 1) == type || (GetBattlerType(battlerId, 2) != TYPE_MYSTERY && GetBattlerType(battlerId, 2) == type)))
|
||||
|
||||
#define IS_BATTLER_TYPELESS(battlerId)(GetBattlerType(battlerId, 0) == TYPE_MYSTERY && GetBattlerType(battlerId, 1) == TYPE_MYSTERY && GetBattlerType(battlerId, 2) == TYPE_MYSTERY)
|
||||
|
||||
#define SET_BATTLER_TYPE(battlerId, type) \
|
||||
{ \
|
||||
gBattleMons[battlerId].type1 = type; \
|
||||
gBattleMons[battlerId].type2 = type; \
|
||||
gBattleMons[battlerId].type3 = TYPE_MYSTERY; \
|
||||
}
|
||||
|
||||
#define RESTORE_BATTLER_TYPE(battlerId) \
|
||||
{ \
|
||||
gBattleMons[battlerId].type1 = gSpeciesInfo[gBattleMons[battlerId].species].types[0]; \
|
||||
|
||||
@ -117,7 +117,7 @@
|
||||
#define B_SHADOW_TAG_ESCAPE GEN_LATEST // In Gen4+, if both sides have a Pokémon with Shadow Tag, all battlers can escape. Before, neither side could escape this situation.
|
||||
#define B_MOODY_ACC_EVASION GEN_LATEST // In Gen8, Moody CANNOT raise Accuracy and Evasion anymore.
|
||||
#define B_FLASH_FIRE_FROZEN GEN_LATEST // In Gen5+, Flash Fire can trigger even when frozen, when it couldn't before.
|
||||
#define B_SYNCHRONIZE_NATURE GEN_LATEST // In Gen8, if a Pokémon with Synchronize is leading the party, it's 100% guaranteed that wild Pokémon will have the same ability, as opposed to 50% previously.
|
||||
#define B_SYNCHRONIZE_NATURE GEN_LATEST // In Gen8, if a Pokémon with Synchronize is leading the party, it's 100% guaranteed that wild Pokémon will have the same Nature, as opposed to 50% previously. In Gen9, it has no out-of-battle effect.
|
||||
#define B_SYNCHRONIZE_TOXIC GEN_LATEST // In Gen5+, if a Pokémon with Synchronize is badly poisoned, the opponent will also become badly poisoned. Previously, the opponent would become regular poisoned.
|
||||
#define B_UPDATED_INTIMIDATE GEN_LATEST // In Gen8, Intimidate doesn't work on opponents with the Inner Focus, Scrappy, Own Tempo or Oblivious abilities. It also activates Rattled.
|
||||
#define B_OBLIVIOUS_TAUNT GEN_LATEST // In Gen6+, Pokémon with Oblivious can't be taunted.
|
||||
|
||||
@ -47,6 +47,7 @@ struct TestRunnerState
|
||||
u8 expectedResult;
|
||||
bool8 expectLeaks:1;
|
||||
bool8 inBenchmark:1;
|
||||
bool8 tearDown:1;
|
||||
u32 timeoutSeconds;
|
||||
};
|
||||
|
||||
|
||||
@ -1883,7 +1883,7 @@ static u32 GeneratePartyHash(const struct Trainer *trainer, u32 i)
|
||||
void ModifyPersonalityForNature(u32 *personality, u32 newNature)
|
||||
{
|
||||
u32 nature = GetNatureFromPersonality(*personality);
|
||||
s32 diff = abs(nature - newNature);
|
||||
s32 diff = abs((s32)nature - (s32)newNature);
|
||||
s32 sign = (nature > newNature) ? 1 : -1;
|
||||
if (diff > NUM_NATURES / 2)
|
||||
{
|
||||
|
||||
@ -9398,38 +9398,6 @@ static void Cmd_various(void)
|
||||
}
|
||||
return;
|
||||
}
|
||||
case VARIOUS_TRY_REFLECT_TYPE:
|
||||
{
|
||||
VARIOUS_ARGS(const u8 *failInstr);
|
||||
if (GET_BASE_SPECIES_ID(gBattleMons[gBattlerTarget].species) == SPECIES_ARCEUS
|
||||
|| GET_BASE_SPECIES_ID(gBattleMons[gBattlerTarget].species) == SPECIES_SILVALLY)
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
}
|
||||
else if (GetBattlerType(gBattlerTarget, 0) == TYPE_MYSTERY && GetBattlerType(gBattlerTarget, 1) != TYPE_MYSTERY)
|
||||
{
|
||||
gBattleMons[gBattlerAttacker].type1 = GetBattlerType(gBattlerTarget, 1);
|
||||
gBattleMons[gBattlerAttacker].type2 = GetBattlerType(gBattlerTarget, 1);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
else if (GetBattlerType(gBattlerTarget, 0) != TYPE_MYSTERY && GetBattlerType(gBattlerTarget, 1) == TYPE_MYSTERY)
|
||||
{
|
||||
gBattleMons[gBattlerAttacker].type1 = GetBattlerType(gBattlerTarget, 0);
|
||||
gBattleMons[gBattlerAttacker].type2 = GetBattlerType(gBattlerTarget, 0);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
else if (GetBattlerType(gBattlerTarget, 0) == TYPE_MYSTERY && GetBattlerType(gBattlerTarget, 1) == TYPE_MYSTERY)
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
}
|
||||
else
|
||||
{
|
||||
gBattleMons[gBattlerAttacker].type1 = GetBattlerType(gBattlerTarget, 0);
|
||||
gBattleMons[gBattlerAttacker].type2 = GetBattlerType(gBattlerTarget, 1);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
case VARIOUS_TRY_SOAK:
|
||||
{
|
||||
VARIOUS_ARGS(const u8 *failInstr);
|
||||
@ -16250,3 +16218,49 @@ void BS_JumpIfTerrainAffected(void)
|
||||
else
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
void BS_TryReflectType(void)
|
||||
{
|
||||
NATIVE_ARGS(const u8 *failInstr);
|
||||
u16 targetBaseSpecies = GET_BASE_SPECIES_ID(gBattleMons[gBattlerTarget].species);
|
||||
u8 targetType1 = GetBattlerType(gBattlerTarget, 0);
|
||||
u8 targetType2 = GetBattlerType(gBattlerTarget, 1);
|
||||
u8 targetType3 = GetBattlerType(gBattlerTarget, 2);
|
||||
|
||||
if (targetBaseSpecies == SPECIES_ARCEUS || targetBaseSpecies == SPECIES_SILVALLY)
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
}
|
||||
else if (IS_BATTLER_TYPELESS(gBattlerTarget))
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
}
|
||||
else if (targetType1 == TYPE_MYSTERY && targetType2 == TYPE_MYSTERY && targetType3 != TYPE_MYSTERY)
|
||||
{
|
||||
gBattleMons[gBattlerAttacker].type1 = TYPE_NORMAL;
|
||||
gBattleMons[gBattlerAttacker].type2 = TYPE_NORMAL;
|
||||
gBattleMons[gBattlerAttacker].type3 = targetType3;
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
else if (targetType1 == TYPE_MYSTERY && targetType2 != TYPE_MYSTERY)
|
||||
{
|
||||
gBattleMons[gBattlerAttacker].type1 = targetType2;
|
||||
gBattleMons[gBattlerAttacker].type2 = targetType2;
|
||||
gBattleMons[gBattlerAttacker].type3 = targetType3;
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
else if (targetType1 != TYPE_MYSTERY && targetType2 == TYPE_MYSTERY)
|
||||
{
|
||||
gBattleMons[gBattlerAttacker].type1 = targetType1;
|
||||
gBattleMons[gBattlerAttacker].type2 = targetType1;
|
||||
gBattleMons[gBattlerAttacker].type3 = targetType3;
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
else
|
||||
{
|
||||
gBattleMons[gBattlerAttacker].type1 = targetType1;
|
||||
gBattleMons[gBattlerAttacker].type2 = targetType2;
|
||||
gBattleMons[gBattlerAttacker].type3 = targetType3;
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -6041,8 +6041,8 @@ const struct Item gItems[] =
|
||||
.holdEffectParam = 10,
|
||||
.description = sRazorFangDesc,
|
||||
.pocket = POCKET_ITEMS,
|
||||
.type = ITEM_USE_BAG_MENU,
|
||||
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
|
||||
.type = EVO_HELD_ITEM_TYPE,
|
||||
.fieldUseFunc = EVO_HELD_ITEM_FIELD_FUNC,
|
||||
.flingPower = 30,
|
||||
},
|
||||
|
||||
|
||||
@ -618,6 +618,7 @@ const u8 *const gItemEffectTable[ITEMS_COUNT] =
|
||||
[ITEM_METAL_COAT] = gItemEffect_EvoItem,
|
||||
[ITEM_KINGS_ROCK] = gItemEffect_EvoItem,
|
||||
[ITEM_RAZOR_CLAW] = gItemEffect_EvoItem,
|
||||
[ITEM_RAZOR_FANG] = gItemEffect_EvoItem,
|
||||
[ITEM_AUSPICIOUS_ARMOR] = gItemEffect_EvoItem,
|
||||
[ITEM_MALICIOUS_ARMOR] = gItemEffect_EvoItem,
|
||||
[ITEM_SCROLL_OF_DARKNESS] = gItemEffect_EvoItem,
|
||||
|
||||
@ -415,6 +415,7 @@ static u8 PickWildMonNature(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
#if B_SYNCHRONIZE_NATURE < GEN_9
|
||||
// check synchronize for a pokemon with the same ability
|
||||
if (!GetMonData(&gPlayerParty[0], MON_DATA_SANITY_IS_EGG)
|
||||
&& GetMonAbility(&gPlayerParty[0]) == ABILITY_SYNCHRONIZE
|
||||
@ -422,6 +423,7 @@ static u8 PickWildMonNature(void)
|
||||
{
|
||||
return GetMonData(&gPlayerParty[0], MON_DATA_PERSONALITY) % NUM_NATURES;
|
||||
}
|
||||
#endif
|
||||
|
||||
// random nature
|
||||
return Random() % NUM_NATURES;
|
||||
|
||||
186
test/battle/move_effect/reflect_type.c
Normal file
186
test/battle/move_effect/reflect_type.c
Normal file
@ -0,0 +1,186 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("Reflect Type fails if the user is Terastallized");
|
||||
TO_DO_BATTLE_TEST("Reflect Type succeeds against a Terastallized target and copies its Tera type");
|
||||
|
||||
SINGLE_BATTLE_TEST("Reflect Type does not affect any of Arceus' forms")
|
||||
{
|
||||
u32 j;
|
||||
static const u16 sArceusFormSpeciesIdTable[] = {
|
||||
SPECIES_ARCEUS,
|
||||
SPECIES_ARCEUS_FIGHTING,
|
||||
SPECIES_ARCEUS_FLYING,
|
||||
SPECIES_ARCEUS_POISON,
|
||||
SPECIES_ARCEUS_GROUND,
|
||||
SPECIES_ARCEUS_ROCK,
|
||||
SPECIES_ARCEUS_BUG,
|
||||
SPECIES_ARCEUS_GHOST,
|
||||
SPECIES_ARCEUS_STEEL,
|
||||
SPECIES_ARCEUS_FIRE,
|
||||
SPECIES_ARCEUS_WATER,
|
||||
SPECIES_ARCEUS_GRASS,
|
||||
SPECIES_ARCEUS_ELECTRIC,
|
||||
SPECIES_ARCEUS_PSYCHIC,
|
||||
SPECIES_ARCEUS_ICE,
|
||||
SPECIES_ARCEUS_DRAGON,
|
||||
SPECIES_ARCEUS_DARK,
|
||||
SPECIES_ARCEUS_FAIRY,
|
||||
};
|
||||
u16 species = SPECIES_NONE;
|
||||
|
||||
for (j = 0; j < ARRAY_COUNT(sArceusFormSpeciesIdTable); j++)
|
||||
{
|
||||
PARAMETRIZE { species = sArceusFormSpeciesIdTable[j]; }
|
||||
}
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(species);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_REFLECT_TYPE); }
|
||||
} SCENE {
|
||||
MESSAGE("Wobbuffet used Reflect Type!");
|
||||
MESSAGE("But it failed!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Reflect Type does not affect any of Silvally's forms")
|
||||
{
|
||||
u32 j;
|
||||
static const u16 sSilvallyFormSpeciesIdTable[] = {
|
||||
SPECIES_SILVALLY,
|
||||
SPECIES_SILVALLY_FIGHTING,
|
||||
SPECIES_SILVALLY_FLYING,
|
||||
SPECIES_SILVALLY_POISON,
|
||||
SPECIES_SILVALLY_GROUND,
|
||||
SPECIES_SILVALLY_ROCK,
|
||||
SPECIES_SILVALLY_BUG,
|
||||
SPECIES_SILVALLY_GHOST,
|
||||
SPECIES_SILVALLY_STEEL,
|
||||
SPECIES_SILVALLY_FIRE,
|
||||
SPECIES_SILVALLY_WATER,
|
||||
SPECIES_SILVALLY_GRASS,
|
||||
SPECIES_SILVALLY_ELECTRIC,
|
||||
SPECIES_SILVALLY_PSYCHIC,
|
||||
SPECIES_SILVALLY_ICE,
|
||||
SPECIES_SILVALLY_DRAGON,
|
||||
SPECIES_SILVALLY_DARK,
|
||||
SPECIES_SILVALLY_FAIRY,
|
||||
};
|
||||
u16 species = SPECIES_NONE;
|
||||
|
||||
for (j = 0; j < ARRAY_COUNT(sSilvallyFormSpeciesIdTable); j++)
|
||||
{
|
||||
PARAMETRIZE { species = sSilvallyFormSpeciesIdTable[j]; }
|
||||
}
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(species);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_REFLECT_TYPE); }
|
||||
} SCENE {
|
||||
MESSAGE("Wobbuffet used Reflect Type!");
|
||||
MESSAGE("But it failed!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Reflect Type does not affect Pokémon with no types")
|
||||
{
|
||||
ASSUME(gSpeciesInfo[SPECIES_ARCANINE].types[0] == TYPE_FIRE);
|
||||
ASSUME(gSpeciesInfo[SPECIES_ARCANINE].types[1] == TYPE_FIRE);
|
||||
ASSUME(gSpeciesInfo[SPECIES_POLIWRATH].types[0] == TYPE_WATER);
|
||||
ASSUME(gSpeciesInfo[SPECIES_POLIWRATH].types[1] == TYPE_FIGHTING);
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_ARCANINE);
|
||||
OPPONENT(SPECIES_POLIWRATH);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_BURN_UP); MOVE(opponent, MOVE_REFLECT_TYPE); }
|
||||
} SCENE {
|
||||
MESSAGE("Arcanine used Burn Up!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_BURN_UP, player);
|
||||
HP_BAR(opponent);
|
||||
MESSAGE("Arcanine burned itself out!");
|
||||
MESSAGE("Foe Poliwrath used Reflect Type!");
|
||||
MESSAGE("But it failed!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Reflect Type copies a target's dual types")
|
||||
{
|
||||
ASSUME(gSpeciesInfo[SPECIES_ARCANINE].types[0] == TYPE_FIRE);
|
||||
ASSUME(gSpeciesInfo[SPECIES_ARCANINE].types[1] == TYPE_FIRE);
|
||||
ASSUME(gSpeciesInfo[SPECIES_POLIWRATH].types[0] == TYPE_WATER);
|
||||
ASSUME(gSpeciesInfo[SPECIES_POLIWRATH].types[1] == TYPE_FIGHTING);
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_ARCANINE);
|
||||
OPPONENT(SPECIES_POLIWRATH);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_REFLECT_TYPE); }
|
||||
} SCENE {
|
||||
MESSAGE("Arcanine used Reflect Type!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_REFLECT_TYPE, player);
|
||||
MESSAGE("Arcanine's type changed to match the Foe Poliwrath's!");
|
||||
} THEN {
|
||||
EXPECT_EQ(player->type1, TYPE_WATER);
|
||||
EXPECT_EQ(player->type2, TYPE_FIGHTING);
|
||||
EXPECT_EQ(player->type3, TYPE_MYSTERY);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Reflect Type copies a target's pure type")
|
||||
{
|
||||
ASSUME(gSpeciesInfo[SPECIES_ARCANINE].types[0] == TYPE_FIRE);
|
||||
ASSUME(gSpeciesInfo[SPECIES_ARCANINE].types[1] == TYPE_FIRE);
|
||||
ASSUME(gSpeciesInfo[SPECIES_SUDOWOODO].types[0] == TYPE_ROCK);
|
||||
ASSUME(gSpeciesInfo[SPECIES_SUDOWOODO].types[1] == TYPE_ROCK);
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_ARCANINE);
|
||||
OPPONENT(SPECIES_SUDOWOODO);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_REFLECT_TYPE); }
|
||||
} SCENE {
|
||||
MESSAGE("Arcanine used Reflect Type!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_REFLECT_TYPE, player);
|
||||
MESSAGE("Arcanine's type changed to match the Foe Sudowoodo's!");
|
||||
} THEN {
|
||||
EXPECT_EQ(player->type1, TYPE_ROCK);
|
||||
EXPECT_EQ(player->type2, TYPE_ROCK);
|
||||
EXPECT_EQ(player->type3, TYPE_MYSTERY);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Reflect Type defaults to Normal type for the user's type1 and type2 if the target only has a 3rd type")
|
||||
{
|
||||
ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] == TYPE_PSYCHIC);
|
||||
ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[1] == TYPE_PSYCHIC);
|
||||
ASSUME(gSpeciesInfo[SPECIES_ARCANINE].types[0] == TYPE_FIRE);
|
||||
ASSUME(gSpeciesInfo[SPECIES_ARCANINE].types[1] == TYPE_FIRE);
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_ARCANINE);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_BURN_UP); }
|
||||
TURN { MOVE(player, MOVE_FORESTS_CURSE); }
|
||||
TURN { MOVE(player, MOVE_REFLECT_TYPE); }
|
||||
} SCENE {
|
||||
// Turn 1
|
||||
MESSAGE("Foe Arcanine used Burn Up!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_BURN_UP, opponent);
|
||||
HP_BAR(player);
|
||||
MESSAGE("Foe Arcanine burned itself out!");
|
||||
// Turn 2
|
||||
MESSAGE("Wobbuffet used Forest'sCurs!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FORESTS_CURSE, player);
|
||||
MESSAGE("Grass type was added to Foe Arcanine!");
|
||||
// Turn 3
|
||||
MESSAGE("Wobbuffet used Reflect Type!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_REFLECT_TYPE, player);
|
||||
MESSAGE("Wobbuffet's type changed to match the Foe Arcanine's!");
|
||||
} THEN {
|
||||
EXPECT_EQ(player->type1, TYPE_NORMAL);
|
||||
EXPECT_EQ(player->type2, TYPE_NORMAL);
|
||||
EXPECT_EQ(player->type3, TYPE_GRASS);
|
||||
}
|
||||
}
|
||||
@ -4,6 +4,7 @@
|
||||
#include "battle_main.h"
|
||||
#include "data.h"
|
||||
#include "malloc.h"
|
||||
#include "random.h"
|
||||
#include "string_util.h"
|
||||
#include "constants/item.h"
|
||||
#include "constants/abilities.h"
|
||||
@ -119,3 +120,17 @@ TEST("CreateNPCTrainerPartyForTrainer generates different personalities for diff
|
||||
EXPECT(testParty[0].box.personality != testParty[1].box.personality);
|
||||
Free(testParty);
|
||||
}
|
||||
|
||||
TEST("ModifyPersonalityForNature can set any nature")
|
||||
{
|
||||
u32 personality, nature, j, k;
|
||||
for (j = 0; j < 64; j++)
|
||||
{
|
||||
for (k = 0; k < NUM_NATURES; k++)
|
||||
{
|
||||
PARAMETRIZE { personality = Random32(); nature = k; }
|
||||
}
|
||||
}
|
||||
ModifyPersonalityForNature(&personality, nature);
|
||||
EXPECT_EQ(GetNatureFromPersonality(personality), nature);
|
||||
}
|
||||
|
||||
@ -56,9 +56,10 @@ static bool32 PrefixMatch(const char *pattern, const char *string)
|
||||
enum
|
||||
{
|
||||
STATE_INIT,
|
||||
STATE_NEXT_TEST,
|
||||
STATE_ASSIGN_TEST,
|
||||
STATE_RUN_TEST,
|
||||
STATE_REPORT_RESULT,
|
||||
STATE_NEXT_TEST,
|
||||
STATE_EXIT,
|
||||
};
|
||||
|
||||
@ -152,17 +153,15 @@ void CB2_TestRunner(void)
|
||||
}
|
||||
else
|
||||
{
|
||||
gTestRunnerState.state = STATE_NEXT_TEST;
|
||||
gTestRunnerState.test = __start_tests - 1;
|
||||
gTestRunnerState.state = STATE_ASSIGN_TEST;
|
||||
gTestRunnerState.test = __start_tests;
|
||||
}
|
||||
gTestRunnerState.exitCode = 0;
|
||||
gTestRunnerState.skipFilename = NULL;
|
||||
|
||||
break;
|
||||
|
||||
case STATE_NEXT_TEST:
|
||||
gTestRunnerState.test++;
|
||||
|
||||
case STATE_ASSIGN_TEST:
|
||||
if (gTestRunnerState.test == __stop_tests)
|
||||
{
|
||||
gTestRunnerState.state = STATE_EXIT;
|
||||
@ -172,6 +171,7 @@ void CB2_TestRunner(void)
|
||||
if (gTestRunnerState.test->runner != &gAssumptionsRunner
|
||||
&& !PrefixMatch(gTestRunnerArgv, gTestRunnerState.test->name))
|
||||
{
|
||||
gTestRunnerState.state = STATE_NEXT_TEST;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -191,6 +191,8 @@ void CB2_TestRunner(void)
|
||||
sCurrentTest.address = (uintptr_t)gTestRunnerState.test;
|
||||
sCurrentTest.state = CURRENT_TEST_STATE_ESTIMATE;
|
||||
|
||||
// If AssignCostToRunner fails, we want to report the failure.
|
||||
gTestRunnerState.state = STATE_REPORT_RESULT;
|
||||
if (AssignCostToRunner() == gTestRunnerI)
|
||||
gTestRunnerState.state = STATE_RUN_TEST;
|
||||
else
|
||||
@ -204,7 +206,10 @@ void CB2_TestRunner(void)
|
||||
SeedRng(0);
|
||||
SeedRng2(0);
|
||||
if (gTestRunnerState.test->runner->setUp)
|
||||
{
|
||||
gTestRunnerState.test->runner->setUp(gTestRunnerState.test->data);
|
||||
gTestRunnerState.tearDown = TRUE;
|
||||
}
|
||||
// NOTE: Assumes that the compiler interns __FILE__.
|
||||
if (gTestRunnerState.skipFilename == gTestRunnerState.test->filename) // Assumption fails for tests in this file.
|
||||
{
|
||||
@ -216,13 +221,17 @@ void CB2_TestRunner(void)
|
||||
gTestRunnerState.test->runner->run(gTestRunnerState.test->data);
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_REPORT_RESULT:
|
||||
REG_TM2CNT_H = 0;
|
||||
|
||||
gTestRunnerState.state = STATE_NEXT_TEST;
|
||||
|
||||
if (gTestRunnerState.test->runner->tearDown)
|
||||
if (gTestRunnerState.tearDown && gTestRunnerState.test->runner->tearDown)
|
||||
{
|
||||
gTestRunnerState.test->runner->tearDown(gTestRunnerState.test->data);
|
||||
gTestRunnerState.tearDown = FALSE;
|
||||
}
|
||||
|
||||
if (gTestRunnerState.result == TEST_RESULT_PASS
|
||||
&& !gTestRunnerState.expectLeaks)
|
||||
@ -342,6 +351,11 @@ void CB2_TestRunner(void)
|
||||
|
||||
break;
|
||||
|
||||
case STATE_NEXT_TEST:
|
||||
gTestRunnerState.state = STATE_ASSIGN_TEST;
|
||||
gTestRunnerState.test++;
|
||||
break;
|
||||
|
||||
case STATE_EXIT:
|
||||
MgbaExit_(gTestRunnerState.exitCode);
|
||||
break;
|
||||
|
||||
@ -2,9 +2,9 @@
|
||||
* parses the output to display human-readable progress.
|
||||
*
|
||||
* Output lines starting with "GBA Debug: :" are parsed as commands to
|
||||
* Hydra, other output lines starting with "GBA Debug: " are parsed as
|
||||
* output from the current test, and any other lines are parsed as
|
||||
* output from the mgba-rom-test process itself.
|
||||
* Hydra, other output lines starting with "GBA Debug: " or with "GBA: "
|
||||
* are parsed as output from the current test, and any other lines are
|
||||
* parsed as output from the mgba-rom-test process itself.
|
||||
*
|
||||
* COMMANDS
|
||||
* N: Sets the test name to the remainder of the line.
|
||||
@ -75,10 +75,17 @@ static void handle_read(int i, struct Runner *runner)
|
||||
{
|
||||
eol++;
|
||||
size_t n = eol - sol;
|
||||
if (runner->input_buffer_size >= strlen("GBA Debug: ")
|
||||
&& !strncmp(sol, "GBA Debug: ", strlen("GBA Debug: ")))
|
||||
char *soc;
|
||||
if (runner->input_buffer_size >= strlen("GBA: ")
|
||||
&& !strncmp(sol, "GBA: ", strlen("GBA: ")))
|
||||
{
|
||||
char *soc = sol + strlen("GBA Debug: ");
|
||||
soc = sol + strlen("GBA: ");
|
||||
goto buffer_output;
|
||||
}
|
||||
else if (runner->input_buffer_size >= strlen("GBA Debug: ")
|
||||
&& !strncmp(sol, "GBA Debug: ", strlen("GBA Debug: ")))
|
||||
{
|
||||
soc = sol + strlen("GBA Debug: ");
|
||||
if (soc[0] == ':')
|
||||
{
|
||||
switch (soc[1])
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user