From 976e642137d9d31b15beecb509bd10f1b36dd0d5 Mon Sep 17 00:00:00 2001 From: FosterProgramming Date: Fri, 13 Mar 2026 15:49:23 +0100 Subject: [PATCH] Fix partner difficulty and rework tests (#9419) --- .gitignore | 1 + include/battle_partner.h | 2 - include/constants/battle_partner.h | 4 +- include/data.h | 9 +- src/battle_partner.c | 2 + src/data.c | 2 + src/data/battle_partners.party | 12 ++ src/trainer_slide.c | 4 + test/battle/partner_control.party | 84 ++++++++++++++ test/battle/trainer_control.c | 171 +++++++++++++++-------------- test/battle/trainer_control.party | 61 +++++++--- test/battle/trainer_slides.h | 6 +- test/test_runner_battle.c | 37 +++++-- trainer_rules.mk | 1 + 14 files changed, 279 insertions(+), 117 deletions(-) create mode 100644 test/battle/partner_control.party diff --git a/.gitignore b/.gitignore index c586b32b19..c64c73c980 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,7 @@ src/data/trainers_frlg.h src/data/debug_trainers.h src/data/tutor_moves.h test/battle/trainer_control.h +test/battle/partner_control.h tools/compresSmol/compresSmol tools/compresSmol/compresSmolTilemap tools/aif2pcm/aif2pcm diff --git a/include/battle_partner.h b/include/battle_partner.h index 75e97a667f..042d18dcba 100644 --- a/include/battle_partner.h +++ b/include/battle_partner.h @@ -4,8 +4,6 @@ #include "difficulty.h" #include "constants/battle_partner.h" -extern const struct Trainer gBattlePartners[DIFFICULTY_COUNT][PARTNER_COUNT]; - void FillPartnerParty(u16 trainerId); #endif // BATTLE_PARTNER_H diff --git a/include/constants/battle_partner.h b/include/constants/battle_partner.h index c609ee5aa2..04292c6c74 100644 --- a/include/constants/battle_partner.h +++ b/include/constants/battle_partner.h @@ -4,6 +4,8 @@ #define PARTNER_NONE 0 #define PARTNER_STEVEN 1 -#define PARTNER_COUNT 2 +#define PARTNER_DUMMY 2 +#define PARTNER_COUNT 3 +//Tests need PARTNER_COUNT to be at least 3 so we add a dummy partner #endif // GUARD_CONSTANTS_BATTLE_PARTNERS_H diff --git a/include/data.h b/include/data.h index 8ff8945879..7847f1fbe3 100644 --- a/include/data.h +++ b/include/data.h @@ -227,7 +227,7 @@ extern const struct FollowerMsgInfo gFollowerPoisonedMessages[]; static inline bool8 IsPartnerTrainerId(u16 trainerId) { - if (trainerId >= TRAINER_PARTNER(PARTNER_NONE) && trainerId < TRAINER_PARTNER(PARTNER_COUNT)) + if (trainerId > TRAINER_PARTNER(PARTNER_NONE) && trainerId < TRAINER_PARTNER(PARTNER_COUNT)) return TRUE; return FALSE; } @@ -255,12 +255,17 @@ static inline const struct Trainer *GetTrainerStructFromId(u16 trainerId) u32 sanitizedTrainerId = 0; if (gIsDebugBattle) return GetDebugAiTrainer(); sanitizedTrainerId = SanitizeTrainerId(trainerId); - enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); if (IsPartnerTrainerId(trainerId)) + { + enum DifficultyLevel difficulty = GetBattlePartnerDifficultyLevel(sanitizedTrainerId); return &gBattlePartners[difficulty][sanitizedTrainerId - TRAINER_PARTNER(PARTNER_NONE)]; + } else + { + enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); return &gTrainers[difficulty][sanitizedTrainerId]; + } } static inline const enum TrainerClassID GetTrainerClassFromId(u16 trainerId) diff --git a/src/battle_partner.c b/src/battle_partner.c index f99ab86c7e..6207683bba 100644 --- a/src/battle_partner.c +++ b/src/battle_partner.c @@ -13,10 +13,12 @@ #include "constants/battle_ai.h" #include "data/partner_parties.h" +#if !TESTING const struct Trainer gBattlePartners[DIFFICULTY_COUNT][PARTNER_COUNT] = { #include "data/battle_partners.h" }; +#endif #define STEVEN_OTID 61226 diff --git a/src/data.c b/src/data.c index d861496f01..cf2b3f1eec 100644 --- a/src/data.c +++ b/src/data.c @@ -228,6 +228,7 @@ const union AnimCmd *const gAnims_Trainer[] ={ #include "data/trainer_parties.h" +#if !TESTING const struct Trainer gTrainers[DIFFICULTY_COUNT][TRAINERS_COUNT] = { #if IS_FRLG @@ -236,5 +237,6 @@ const struct Trainer gTrainers[DIFFICULTY_COUNT][TRAINERS_COUNT] = #include "data/trainers.h" #endif }; +#endif #include "data/text/follower_messages.h" diff --git a/src/data/battle_partners.party b/src/data/battle_partners.party index 8de1dc0f2b..95b7861678 100644 --- a/src/data/battle_partners.party +++ b/src/data/battle_partners.party @@ -44,3 +44,15 @@ EVs: 252 Atk / 252 SpA / 6 SpD - Protect - Solar Beam - Dragon Claw + +=== PARTNER_DUMMY === +Name: +Class: Pkmn Trainer 1 +Pic: Brendan +Gender: Male +Music: Male +Back Pic: Brendan +Party Size: 0 + +Wynaut + diff --git a/src/trainer_slide.c b/src/trainer_slide.c index 7e4db155da..e03c72647e 100644 --- a/src/trainer_slide.c +++ b/src/trainer_slide.c @@ -70,6 +70,10 @@ static const u8* const sFrontierTrainerSlides[DIFFICULTY_COUNT][FRONTIER_TRAINER }, }; +#define TRAINER_RED_TEST 1 +#define TRAINER_LEAF_TEST 2 +#define PARTNER_STEVEN_TEST 1 + static const u8* const sTestTrainerSlides[DIFFICULTY_COUNT][MAX_TRAINERS_COUNT_EMERALD + PARTNER_COUNT][TRAINER_SLIDE_COUNT] = { #include "../test/battle/trainer_slides.h" diff --git a/test/battle/partner_control.party b/test/battle/partner_control.party new file mode 100644 index 0000000000..5d77e47b27 --- /dev/null +++ b/test/battle/partner_control.party @@ -0,0 +1,84 @@ +=== PARTNER_NONE === +Name: +Class: Pkmn Trainer 1 +Pic: Brendan +Gender: Male +Music: Male +Back Pic: Brendan + +=== PARTNER_STEVEN_TEST === +Name: STEVEN +Class: Rival +Pic: Steven +Gender: Male +Music: Male +Back Pic: Steven +AI: Basic Trainer + +Metang +Brave Nature +Level: 42 +IVs: 31 HP / 31 Atk / 31 Def / 31 SpA / 31 SpD / 31 Spe +EVs: 252 Atk / 252 Def / 6 SpA +- Light Screen +- Psychic +- Reflect +- Metal Claw + +Skarmory +Impish Nature +Level: 43 +IVs: 31 HP / 31 Atk / 31 Def / 31 SpA / 31 SpD / 31 Spe +EVs: 252 HP / 6 SpA / 252 SpD +- Toxic +- Aerial Ace +- Protect +- Steel Wing + +Aggron +Adamant Nature +Level: 44 +IVs: 31 HP / 31 Atk / 31 Def / 31 SpA / 31 SpD / 31 Spe +EVs: 252 Atk / 252 SpA / 6 SpD +- Thunder +- Protect +- Solar Beam +- Dragon Claw + +=== 2 === +Name: Test2 +Class: Rival +Pic: Steven +Gender: Male +Music: Male +Back Pic: Steven +Difficulty: Normal + +Mewtwo +Level: 50 + +=== 2 === +Name: Test2 +Class: Rival +Pic: Steven +Gender: Male +Music: Male +Back Pic: Steven +Battle Type: Singles +Difficulty: Easy + +Metapod +Level: 1 + +=== 2 === +Name: Test2 +Class: Rival +Pic: Steven +Gender: Male +Music: Male +Back Pic: Steven +Battle Type: Singles +Difficulty: Hard + +Arceus +Level: 99 diff --git a/test/battle/trainer_control.c b/test/battle/trainer_control.c index 6a0925d762..596a63071f 100644 --- a/test/battle/trainer_control.c +++ b/test/battle/trainer_control.c @@ -11,33 +11,14 @@ #include "constants/abilities.h" #include "constants/trainers.h" #include "constants/battle.h" - -#define NUM_TEST_TRAINERS 12 - -static const struct Trainer sTestTrainers[DIFFICULTY_COUNT][NUM_TEST_TRAINERS] = -{ -#include "trainer_control.h" -}; - -enum DifficultyLevel GetTrainerDifficultyLevelTest(u16 trainerId) -{ - enum DifficultyLevel difficulty = GetCurrentDifficultyLevel(); - - if (difficulty == DIFFICULTY_NORMAL) - return DIFFICULTY_NORMAL; - - if (sTestTrainers[difficulty][trainerId].party == NULL) - return DIFFICULTY_NORMAL; - - return difficulty; -} +#include "constants/battle_ai.h" TEST("CreateNPCTrainerPartyForTrainer generates customized Pokémon") { struct Pokemon *testParty = Alloc(6 * sizeof(struct Pokemon)); - u32 currTrainer = 0; + u32 currTrainer = 3; u8 nickBuffer[20]; - CreateNPCTrainerPartyFromTrainer(testParty, &sTestTrainers[GetTrainerDifficultyLevelTest(currTrainer)][currTrainer], TRUE, BATTLE_TYPE_TRAINER); + CreateNPCTrainerPartyFromTrainer(testParty, GetTrainerStructFromId(currTrainer), TRUE, BATTLE_TYPE_TRAINER); EXPECT(IsMonShiny(&testParty[0])); EXPECT(!IsMonShiny(&testParty[1])); @@ -111,9 +92,9 @@ TEST("CreateNPCTrainerPartyForTrainer generates customized Pokémon") TEST("CreateNPCTrainerPartyForTrainer generates different personalities for different mons") { - enum DifficultyLevel difficulty = GetTrainerDifficultyLevelTest(0); struct Pokemon *testParty = Alloc(6 * sizeof(struct Pokemon)); - CreateNPCTrainerPartyFromTrainer(testParty, &sTestTrainers[difficulty][0], TRUE, BATTLE_TYPE_TRAINER); + u32 currTrainer = 3; + CreateNPCTrainerPartyFromTrainer(testParty, GetTrainerStructFromId(currTrainer), TRUE, BATTLE_TYPE_TRAINER); EXPECT(testParty[0].box.personality != testParty[1].box.personality); Free(testParty); } @@ -132,88 +113,108 @@ TEST("ModifyPersonalityForNature can set any 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, - }, -}; - TEST("Trainer Class Balls apply to the entire party") { ASSUME(B_TRAINER_CLASS_POKE_BALLS >= GEN_8); struct Pokemon *testParty = Alloc(6 * sizeof(struct Pokemon)); u32 j; - CreateNPCTrainerPartyFromTrainer(testParty, &sTestTrainers[DIFFICULTY_NORMAL][11], TRUE, BATTLE_TYPE_TRAINER); + u32 currTrainer = 14; + const struct Trainer *trainer = GetTrainerStructFromId(currTrainer); + CreateNPCTrainerPartyFromTrainer(testParty, trainer, TRUE, BATTLE_TYPE_TRAINER); for(j = 0; j < 6; j++) { - EXPECT(GetMonData(&testParty[j], MON_DATA_POKEBALL, 0) == gTrainerClasses[sTestTrainers[DIFFICULTY_NORMAL][11].trainerClass].ball); + EXPECT(GetMonData(&testParty[j], MON_DATA_POKEBALL, 0) == gTrainerClasses[trainer->trainerClass].ball); } Free(testParty); } -TEST("Difficulty default to Normal is the trainer doesn't have a member for the current diffuculty") +TEST("Difficulty default to Normal if the trainer doesn't have a member for the current difficulty") { SetCurrentDifficultyLevel(DIFFICULTY_EASY); struct Pokemon *testParty = Alloc(6 * sizeof(struct Pokemon)); - u32 currTrainer = 1; - CreateNPCTrainerPartyFromTrainer(testParty, &sTestTrainers[GetTrainerDifficultyLevelTest(currTrainer)][currTrainer], TRUE, BATTLE_TYPE_TRAINER); + u32 currTrainer = 4; + CreateNPCTrainerPartyFromTrainer(testParty, GetTrainerStructFromId(currTrainer), TRUE, BATTLE_TYPE_TRAINER); EXPECT(GetMonData(&testParty[0], MON_DATA_SPECIES) == SPECIES_MEWTWO); Free(testParty); SetCurrentDifficultyLevel(DIFFICULTY_NORMAL); } -TEST("Difficulty changes which party if used for NPCs if defined for the difficulty (EASY)") +TEST("Difficulty changes which party is used for enemy trainer if defined for the difficulty (EASY)") { SetCurrentDifficultyLevel(DIFFICULTY_EASY); struct Pokemon *testParty = Alloc(6 * sizeof(struct Pokemon)); - u32 currTrainer = 2; - CreateNPCTrainerPartyFromTrainer(testParty, &sTestTrainers[GetTrainerDifficultyLevelTest(currTrainer)][currTrainer], TRUE, BATTLE_TYPE_TRAINER); + u32 currTrainer = 5; + CreateNPCTrainerPartyFromTrainer(testParty, GetTrainerStructFromId(currTrainer), TRUE, BATTLE_TYPE_TRAINER); EXPECT(GetMonData(&testParty[0], MON_DATA_SPECIES) == SPECIES_METAPOD); EXPECT(GetMonData(&testParty[0], MON_DATA_LEVEL) == 1); Free(testParty); SetCurrentDifficultyLevel(DIFFICULTY_NORMAL); } -TEST("Difficulty changes which party if used for NPCs if defined for the difficulty (HARD)") +TEST("Difficulty changes which party is used for enemy trainer if defined for the difficulty (HARD)") { SetCurrentDifficultyLevel(DIFFICULTY_HARD); struct Pokemon *testParty = Alloc(6 * sizeof(struct Pokemon)); - u32 currTrainer = 2; - CreateNPCTrainerPartyFromTrainer(testParty, &sTestTrainers[GetTrainerDifficultyLevelTest(currTrainer)][currTrainer], TRUE, BATTLE_TYPE_TRAINER); + u32 currTrainer = 5; + CreateNPCTrainerPartyFromTrainer(testParty, GetTrainerStructFromId(currTrainer), TRUE, BATTLE_TYPE_TRAINER); EXPECT(GetMonData(&testParty[0], MON_DATA_SPECIES) == SPECIES_ARCEUS); EXPECT(GetMonData(&testParty[0], MON_DATA_LEVEL) == 99); Free(testParty); SetCurrentDifficultyLevel(DIFFICULTY_NORMAL); } -TEST("Difficulty changes which party if used for NPCs if defined for the difficulty (NORMAL)") +TEST("Difficulty changes which party is used for enemy trainer if defined for the difficulty (NORMAL)") { SetCurrentDifficultyLevel(DIFFICULTY_NORMAL); struct Pokemon *testParty = Alloc(6 * sizeof(struct Pokemon)); - u32 currTrainer = 2; - CreateNPCTrainerPartyFromTrainer(testParty, &sTestTrainers[GetTrainerDifficultyLevelTest(currTrainer)][currTrainer], TRUE, BATTLE_TYPE_TRAINER); + u32 currTrainer = 5; + CreateNPCTrainerPartyFromTrainer(testParty, GetTrainerStructFromId(currTrainer), TRUE, BATTLE_TYPE_TRAINER); + EXPECT(GetMonData(&testParty[0], MON_DATA_SPECIES) == SPECIES_MEWTWO); + EXPECT(GetMonData(&testParty[0], MON_DATA_LEVEL) == 50); + Free(testParty); +} + +TEST("Difficulty default to Normal if the partner doesn't have a member for the current difficulty") +{ + SetCurrentDifficultyLevel(DIFFICULTY_EASY); + struct Pokemon *testParty = Alloc(6 * sizeof(struct Pokemon)); + u32 currTrainer = TRAINER_PARTNER(1); + CreateNPCTrainerPartyFromTrainer(testParty, GetTrainerStructFromId(currTrainer), TRUE, BATTLE_TYPE_TRAINER); + EXPECT(GetMonData(&testParty[0], MON_DATA_SPECIES) == SPECIES_METANG); + Free(testParty); + SetCurrentDifficultyLevel(DIFFICULTY_NORMAL); +} + +TEST("Difficulty changes which party is used for partner if defined for the difficulty (EASY)") +{ + SetCurrentDifficultyLevel(DIFFICULTY_EASY); + struct Pokemon *testParty = Alloc(6 * sizeof(struct Pokemon)); + u32 currTrainer = TRAINER_PARTNER(2); + CreateNPCTrainerPartyFromTrainer(testParty, GetTrainerStructFromId(currTrainer), TRUE, BATTLE_TYPE_TRAINER); + EXPECT(GetMonData(&testParty[0], MON_DATA_SPECIES) == SPECIES_METAPOD); + EXPECT(GetMonData(&testParty[0], MON_DATA_LEVEL) == 1); + Free(testParty); + SetCurrentDifficultyLevel(DIFFICULTY_NORMAL); +} + +TEST("Difficulty changes which party is used for partner if defined for the difficulty (HARD)") +{ + SetCurrentDifficultyLevel(DIFFICULTY_HARD); + struct Pokemon *testParty = Alloc(6 * sizeof(struct Pokemon)); + u32 currTrainer = TRAINER_PARTNER(2); + CreateNPCTrainerPartyFromTrainer(testParty, GetTrainerStructFromId(currTrainer), TRUE, BATTLE_TYPE_TRAINER); + EXPECT(GetMonData(&testParty[0], MON_DATA_SPECIES) == SPECIES_ARCEUS); + EXPECT(GetMonData(&testParty[0], MON_DATA_LEVEL) == 99); + Free(testParty); + SetCurrentDifficultyLevel(DIFFICULTY_NORMAL); +} + +TEST("Difficulty changes which party is used for partner if defined for the difficulty (NORMAL)") +{ + SetCurrentDifficultyLevel(DIFFICULTY_NORMAL); + struct Pokemon *testParty = Alloc(6 * sizeof(struct Pokemon)); + u32 currTrainer = TRAINER_PARTNER(2); + CreateNPCTrainerPartyFromTrainer(testParty, GetTrainerStructFromId(currTrainer), TRUE, BATTLE_TYPE_TRAINER); EXPECT(GetMonData(&testParty[0], MON_DATA_SPECIES) == SPECIES_MEWTWO); EXPECT(GetMonData(&testParty[0], MON_DATA_LEVEL) == 50); Free(testParty); @@ -222,8 +223,8 @@ TEST("Difficulty changes which party if used for NPCs if defined for the difficu TEST("Trainer Party Pool generates a party from the trainer pool") { struct Pokemon *testParty = Alloc(6 * sizeof(struct Pokemon)); - u32 currTrainer = 3; - CreateNPCTrainerPartyFromTrainer(testParty, &sTestTrainers[GetTrainerDifficultyLevelTest(currTrainer)][currTrainer], TRUE, BATTLE_TYPE_TRAINER); + u32 currTrainer = 6; + CreateNPCTrainerPartyFromTrainer(testParty, GetTrainerStructFromId(currTrainer), TRUE, BATTLE_TYPE_TRAINER); EXPECT(GetMonData(&testParty[0], MON_DATA_SPECIES) == SPECIES_EEVEE); Free(testParty); } @@ -231,8 +232,8 @@ TEST("Trainer Party Pool generates a party from the trainer pool") TEST("Trainer Party Pool picks a random lead and a random ace if tags exist in the pool") { struct Pokemon *testParty = Alloc(6 * sizeof(struct Pokemon)); - u32 currTrainer = 4; - CreateNPCTrainerPartyFromTrainer(testParty, &sTestTrainers[GetTrainerDifficultyLevelTest(currTrainer)][currTrainer], TRUE, BATTLE_TYPE_TRAINER); + u32 currTrainer = 7; + CreateNPCTrainerPartyFromTrainer(testParty, GetTrainerStructFromId(currTrainer), TRUE, BATTLE_TYPE_TRAINER); EXPECT(GetMonData(&testParty[0], MON_DATA_SPECIES) == SPECIES_ARON); // Lead EXPECT(GetMonData(&testParty[1], MON_DATA_SPECIES) == SPECIES_WYNAUT); // Not Lead or Ace EXPECT(GetMonData(&testParty[2], MON_DATA_SPECIES) == SPECIES_EEVEE); // Ace @@ -242,8 +243,8 @@ TEST("Trainer Party Pool picks a random lead and a random ace if tags exist in t TEST("Trainer Party Pool picks according to custom rules") { struct Pokemon *testParty = Alloc(6 * sizeof(struct Pokemon)); - u32 currTrainer = 5; - CreateNPCTrainerPartyFromTrainer(testParty, &sTestTrainers[GetTrainerDifficultyLevelTest(currTrainer)][currTrainer], TRUE, BATTLE_TYPE_TRAINER | BATTLE_TYPE_DOUBLE); + u32 currTrainer = 8; + CreateNPCTrainerPartyFromTrainer(testParty, GetTrainerStructFromId(currTrainer), TRUE, BATTLE_TYPE_TRAINER | BATTLE_TYPE_DOUBLE); EXPECT(GetMonData(&testParty[0], MON_DATA_SPECIES) == SPECIES_TORKOAL); // Lead + Weather Setter EXPECT(GetMonData(&testParty[1], MON_DATA_SPECIES) == SPECIES_BULBASAUR); // Lead + Weather Abuser EXPECT(GetMonData(&testParty[2], MON_DATA_SPECIES) == SPECIES_EEVEE); // Anything else @@ -253,8 +254,8 @@ TEST("Trainer Party Pool picks according to custom rules") TEST("Trainer Party Pool uses standard party creation if pool is illegal") { struct Pokemon *testParty = Alloc(6 * sizeof(struct Pokemon)); - u32 currTrainer = 6; - CreateNPCTrainerPartyFromTrainer(testParty, &sTestTrainers[GetTrainerDifficultyLevelTest(currTrainer)][currTrainer], TRUE, BATTLE_TYPE_TRAINER); + u32 currTrainer = 9; + CreateNPCTrainerPartyFromTrainer(testParty, GetTrainerStructFromId(currTrainer), TRUE, BATTLE_TYPE_TRAINER); EXPECT(GetMonData(&testParty[0], MON_DATA_SPECIES) == SPECIES_WYNAUT); EXPECT(GetMonData(&testParty[1], MON_DATA_SPECIES) == SPECIES_WOBBUFFET); Free(testParty); @@ -263,8 +264,8 @@ TEST("Trainer Party Pool uses standard party creation if pool is illegal") TEST("Trainer Party Pool can be pruned before picking") { struct Pokemon *testParty = Alloc(6 * sizeof(struct Pokemon)); - u32 currTrainer = 7; - CreateNPCTrainerPartyFromTrainer(testParty, &sTestTrainers[GetTrainerDifficultyLevelTest(currTrainer)][currTrainer], TRUE, BATTLE_TYPE_TRAINER); + u32 currTrainer = 10; + CreateNPCTrainerPartyFromTrainer(testParty, GetTrainerStructFromId(currTrainer), TRUE, BATTLE_TYPE_TRAINER); EXPECT(GetMonData(&testParty[0], MON_DATA_SPECIES) == SPECIES_EEVEE); EXPECT(GetMonData(&testParty[1], MON_DATA_SPECIES) == SPECIES_WYNAUT); Free(testParty); @@ -273,8 +274,8 @@ TEST("Trainer Party Pool can be pruned before picking") TEST("Trainer Party Pool can choose which functions to use for picking mons") { struct Pokemon *testParty = Alloc(6 * sizeof(struct Pokemon)); - u32 currTrainer = 8; - CreateNPCTrainerPartyFromTrainer(testParty, &sTestTrainers[GetTrainerDifficultyLevelTest(currTrainer)][currTrainer], TRUE, BATTLE_TYPE_TRAINER); + u32 currTrainer = 11; + CreateNPCTrainerPartyFromTrainer(testParty, GetTrainerStructFromId(currTrainer), TRUE, BATTLE_TYPE_TRAINER); EXPECT(GetMonData(&testParty[0], MON_DATA_SPECIES) == SPECIES_WYNAUT); EXPECT(GetMonData(&testParty[1], MON_DATA_SPECIES) == SPECIES_WOBBUFFET); Free(testParty); @@ -283,17 +284,19 @@ TEST("Trainer Party Pool can choose which functions to use for picking mons") TEST("trainerproc supports both Double Battle: Yes and Battle Type: Doubles") { u32 currTrainer; - PARAMETRIZE { currTrainer = 9; } - PARAMETRIZE { currTrainer = 10; } - const struct Trainer trainer = sTestTrainers[GetTrainerDifficultyLevelTest(currTrainer)][currTrainer]; - EXPECT(trainer.battleType == TRAINER_BATTLE_TYPE_DOUBLES); + PARAMETRIZE { currTrainer = 12; } + PARAMETRIZE { currTrainer = 13; } + const struct Trainer *trainer = GetTrainerStructFromId(currTrainer); + EXPECT(trainer->battleType == TRAINER_BATTLE_TYPE_DOUBLES); } TEST("CreateNPCTrainerPartyForTrainer generates default moves if no moves are specified") { - ASSUME(sTestTrainers[GetTrainerDifficultyLevelTest(1)][1].party[0].moves[0] == MOVE_NONE); + u32 currTrainer = 1; + const struct Trainer *trainer = GetTrainerStructFromId(currTrainer); + ASSUME(trainer->party[0].moves[0] == MOVE_NONE); struct Pokemon *testParty = Alloc(6 * sizeof(struct Pokemon)); - CreateNPCTrainerPartyFromTrainer(testParty, &sTestTrainers[GetTrainerDifficultyLevelTest(1)][1], TRUE, BATTLE_TYPE_TRAINER); + CreateNPCTrainerPartyFromTrainer(testParty, trainer, TRUE, BATTLE_TYPE_TRAINER); EXPECT(GetMonData(&testParty[0], MON_DATA_MOVE1) != MOVE_NONE); Free(testParty); } diff --git a/test/battle/trainer_control.party b/test/battle/trainer_control.party index 436bbb5db6..8ca261b855 100644 --- a/test/battle/trainer_control.party +++ b/test/battle/trainer_control.party @@ -1,4 +1,37 @@ -=== 0 === +=== TRAINER_NONE === +Name: +Class: Pkmn Trainer 1 +Pic: Hiker +Gender: Male +Music: Male +Double Battle: No + +=== 1 === +Name: RED +Class: Rival +Pic: Red +Gender: Male +Music: Male +Double Battle: No + +Charmander +Level: 5 +IVs: 0 HP / 0 Atk / 0 Def / 0 SpA / 0 SpD / 0 Spe + +=== 2 === +Name: LEAF +Class: Rival +Pic: Leaf +Gender: Female +Music: Male +Double Battle: No + +Bulbasaur +Level: 5 +IVs: 0 HP / 0 Atk / 0 Def / 0 SpA / 0 SpD / 0 Spe + + +=== 3 === Name: Test1 Class: Pkmn Trainer 1 Pic: Red @@ -30,7 +63,7 @@ Wynaut Level: 5 IVs: 0 HP / 0 Atk / 0 Def / 0 SpA / 0 SpD / 0 Spe -=== 1 === +=== 4 === Name: Test2 Class: Pkmn Trainer 1 Pic: Red @@ -42,7 +75,7 @@ Difficulty: Normal Mewtwo Level: 5 -=== 2 === +=== 5 === Name: Test2 Class: Pkmn Trainer 1 Pic: Red @@ -54,7 +87,7 @@ Difficulty: Normal Mewtwo Level: 50 -=== 2 === +=== 5 === Name: Test2 Class: Pkmn Trainer 1 Pic: Red @@ -66,7 +99,7 @@ Difficulty: Easy Metapod Level: 1 -=== 2 === +=== 5 === Name: Test2 Class: Pkmn Trainer 1 Pic: Red @@ -78,7 +111,7 @@ Difficulty: Hard Arceus Level: 99 -=== 3 === +=== 6 === Name: Test3 Class: Pkmn Trainer 1 Pic: Red @@ -95,7 +128,7 @@ Eevee Mew -=== 4 === +=== 7 === Name: Test4 Class: Pkmn Trainer 1 Pic: Red @@ -120,7 +153,7 @@ Tags: Ace Aron Tags: Lead -=== 5 === +=== 8 === Name: Test5 Class: Pkmn Trainer 1 Pic: Red @@ -158,7 +191,7 @@ Oddish Eevee -=== 6 === +=== 9 === Name: Test6 Class: Pkmn Trainer 1 Pic: Red @@ -177,7 +210,7 @@ Tags: Lead Eevee Tags: Lead -=== 7 === +=== 10 === Name: Test1 Class: Pkmn Trainer 1 Pic: Red @@ -195,7 +228,7 @@ Tags: Lead Eevee -=== 8 === +=== 11 === Name: Test1 Class: Pkmn Trainer 1 Pic: Red @@ -214,7 +247,7 @@ Wobbuffet Eevee Tags: Lead -=== 9 === +=== 12 === Name: Test9 Class: Pkmn Trainer 1 Pic: Red @@ -227,7 +260,7 @@ Wynaut Wobbuffet -=== 10 === +=== 13 === Name: Test10 Class: Pkmn Trainer 1 Pic: Red @@ -240,7 +273,7 @@ Wynaut Wobbuffet -=== 11 === +=== 14 === Name: Test11 Class: Black Belt Pic: Red diff --git a/test/battle/trainer_slides.h b/test/battle/trainer_slides.h index eb2b67328a..d7ef6ab1dd 100644 --- a/test/battle/trainer_slides.h +++ b/test/battle/trainer_slides.h @@ -1,6 +1,6 @@ [DIFFICULTY_NORMAL] = { - [TRAINER_LEAF] = + [TRAINER_LEAF_TEST] = { [TRAINER_SLIDE_BEFORE_FIRST_TURN] = COMPOUND_STRING("Trainer A: This message plays before the first turn.{PAUSE_UNTIL_PRESS}"), [TRAINER_SLIDE_PLAYER_LANDS_FIRST_CRITICAL_HIT] = COMPOUND_STRING("Trainer A: This message plays after the player lands their first critical hit.{PAUSE_UNTIL_PRESS}"), @@ -16,7 +16,7 @@ [TRAINER_SLIDE_Z_MOVE] = COMPOUND_STRING("Trainer A: This message plays before the enemy activates the Z-Move gimmick.{PAUSE_UNTIL_PRESS}"), [TRAINER_SLIDE_DYNAMAX] = COMPOUND_STRING("Trainer A: This message plays before the enemy activates the Dynamax gimmick.{PAUSE_UNTIL_PRESS}"), }, - [TRAINER_RED] = + [TRAINER_RED_TEST] = { [TRAINER_SLIDE_BEFORE_FIRST_TURN] = COMPOUND_STRING("Trainer B: This message plays before the first turn.{PAUSE_UNTIL_PRESS}"), [TRAINER_SLIDE_PLAYER_LANDS_FIRST_CRITICAL_HIT] = COMPOUND_STRING("Trainer B: This message plays after the player lands their first critical hit.{PAUSE_UNTIL_PRESS}"), @@ -32,7 +32,7 @@ [TRAINER_SLIDE_Z_MOVE] = COMPOUND_STRING("Trainer B: This message plays before the enemy activates the Z-Move gimmick.{PAUSE_UNTIL_PRESS}"), [TRAINER_SLIDE_DYNAMAX] = COMPOUND_STRING("Trainer B: This message plays before the enemy activates the Dynamax gimmick.{PAUSE_UNTIL_PRESS}"), }, - [TRAINER_PARTNER(PARTNER_STEVEN)] = + [TRAINER_PARTNER(PARTNER_STEVEN_TEST)] = { [TRAINER_SLIDE_BEFORE_FIRST_TURN] = COMPOUND_STRING("Trainer Partner: This message plays before the first turn.{PAUSE_UNTIL_PRESS}"), [TRAINER_SLIDE_PLAYER_LANDS_FIRST_CRITICAL_HIT] = COMPOUND_STRING("Trainer Partner: This message plays after the player lands their first critical hit.{PAUSE_UNTIL_PRESS}"), diff --git a/test/test_runner_battle.c b/test/test_runner_battle.c index f20b34b176..e144549b13 100644 --- a/test/test_runner_battle.c +++ b/test/test_runner_battle.c @@ -14,6 +14,7 @@ #include "party_menu.h" #include "random.h" #include "test/battle.h" +#include "trainer_pools.h" #include "window.h" #include "constants/characters.h" #include "constants/trainers.h" @@ -48,6 +49,20 @@ static inline bool32 RngSeedNotDefault(const rng_value_t *seed) #undef Q_4_12 #define Q_4_12(n) (s32)((n) * 4096) +#define TRAINER_RED_TEST 1 +#define TRAINER_LEAF_TEST 2 +#define PARTNER_STEVEN_TEST 1 + +const struct Trainer gTrainers[DIFFICULTY_COUNT][TRAINERS_COUNT] = +{ + #include "battle/trainer_control.h" +}; + +const struct Trainer gBattlePartners[DIFFICULTY_COUNT][PARTNER_COUNT] = +{ + #include "battle/partner_control.h" +}; + // Alias sBackupMapData to avoid using heap. struct BattleTestRunnerState *const gBattleTestRunnerState = (void *)sBackupMapData; STATIC_ASSERT(sizeof(struct BattleTestRunnerState) <= sizeof(sBackupMapData), sBackupMapDataSpace); @@ -365,14 +380,14 @@ static void BattleTest_Run(void *data) break; case BATTLE_TEST_AI_SINGLES: DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_TRAINER; - DATA.recordedBattle.opponentA = TRAINER_LEAF; + DATA.recordedBattle.opponentA = TRAINER_LEAF_TEST; DATA.hasAI = TRUE; for (i = 0; i < STATE->battlersCount; i++) DATA.currentMonIndexes[i] = i / 2; break; case BATTLE_TEST_AI_DOUBLES: DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_TRAINER | BATTLE_TYPE_DOUBLE; - DATA.recordedBattle.opponentA = TRAINER_LEAF; + DATA.recordedBattle.opponentA = TRAINER_LEAF_TEST; DATA.recordedBattle.opponentB = TRAINER_NONE; DATA.hasAI = TRUE; for (i = 0; i < STATE->battlersCount; i++) @@ -380,9 +395,9 @@ static void BattleTest_Run(void *data) break; case BATTLE_TEST_AI_MULTI: DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_TRAINER | BATTLE_TYPE_DOUBLE | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS; - DATA.recordedBattle.partnerId = TRAINER_PARTNER(PARTNER_STEVEN); - DATA.recordedBattle.opponentA = TRAINER_LEAF; - DATA.recordedBattle.opponentB = TRAINER_RED; + DATA.recordedBattle.partnerId = TRAINER_PARTNER(PARTNER_STEVEN_TEST); + DATA.recordedBattle.opponentA = TRAINER_LEAF_TEST; + DATA.recordedBattle.opponentB = TRAINER_RED_TEST; DATA.hasAI = TRUE; DATA.currentMonIndexes[0] = 0; // Player first mon DATA.currentMonIndexes[1] = 0; // Opponent A first mon @@ -391,8 +406,8 @@ static void BattleTest_Run(void *data) break; case BATTLE_TEST_AI_TWO_VS_ONE: DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_TRAINER | BATTLE_TYPE_DOUBLE | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_MULTI; - DATA.recordedBattle.partnerId = TRAINER_PARTNER(PARTNER_STEVEN); - DATA.recordedBattle.opponentA = TRAINER_LEAF; + DATA.recordedBattle.partnerId = TRAINER_PARTNER(PARTNER_STEVEN_TEST); + DATA.recordedBattle.opponentA = TRAINER_LEAF_TEST; DATA.recordedBattle.opponentB = 0xFFFF; DATA.currentMonIndexes[0] = 0; // Player first mon DATA.currentMonIndexes[1] = 0; // Opponent first mon @@ -402,8 +417,8 @@ static void BattleTest_Run(void *data) break; case BATTLE_TEST_AI_ONE_VS_TWO: DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_TRAINER | BATTLE_TYPE_DOUBLE | BATTLE_TYPE_TWO_OPPONENTS; - DATA.recordedBattle.opponentA = TRAINER_LEAF; - DATA.recordedBattle.opponentB = TRAINER_RED; + DATA.recordedBattle.opponentA = TRAINER_LEAF_TEST; + DATA.recordedBattle.opponentB = TRAINER_RED_TEST; DATA.currentMonIndexes[0] = 0; // Player first mon DATA.currentMonIndexes[1] = 0; // Opponent A first mon DATA.currentMonIndexes[2] = 1; // Player second mon @@ -425,7 +440,7 @@ static void BattleTest_Run(void *data) break; case BATTLE_TEST_MULTI: DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_RECORDED_IS_MASTER | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_TRAINER | BATTLE_TYPE_DOUBLE | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS; - DATA.recordedBattle.partnerId = TRAINER_PARTNER(PARTNER_STEVEN); + DATA.recordedBattle.partnerId = TRAINER_PARTNER(PARTNER_STEVEN_TEST); DATA.recordedBattle.opponentA = TRAINER_LINK_OPPONENT; DATA.recordedBattle.opponentB = TRAINER_LINK_OPPONENT; DATA.currentMonIndexes[0] = 0; // Player first mon @@ -435,7 +450,7 @@ static void BattleTest_Run(void *data) break; case BATTLE_TEST_TWO_VS_ONE: DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_RECORDED_IS_MASTER | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_TRAINER | BATTLE_TYPE_DOUBLE | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_MULTI; - DATA.recordedBattle.partnerId = TRAINER_PARTNER(PARTNER_STEVEN); + DATA.recordedBattle.partnerId = TRAINER_PARTNER(PARTNER_STEVEN_TEST); DATA.recordedBattle.opponentA = TRAINER_LINK_OPPONENT; DATA.recordedBattle.opponentB = 0xFFFF; DATA.currentMonIndexes[0] = 0; // Player first mon diff --git a/trainer_rules.mk b/trainer_rules.mk index 95e754abf4..06ab77ba0d 100644 --- a/trainer_rules.mk +++ b/trainer_rules.mk @@ -5,6 +5,7 @@ AUTO_GEN_TARGETS += src/data/trainers.h AUTO_GEN_TARGETS += src/data/trainers_frlg.h AUTO_GEN_TARGETS += src/data/battle_partners.h AUTO_GEN_TARGETS += test/battle/trainer_control.h +AUTO_GEN_TARGETS += test/battle/partner_control.h AUTO_GEN_TARGETS += src/data/debug_trainers.h %.h: %.party $(TRAINERPROC)