Fix partner difficulty and rework tests (#9419)

This commit is contained in:
FosterProgramming 2026-03-13 15:49:23 +01:00 committed by GitHub
parent 50cfe5847e
commit 976e642137
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 279 additions and 117 deletions

1
.gitignore vendored
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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}"),

View File

@ -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

View File

@ -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)