From 21f0eb15835edf162af7a753d726877d32c74ae2 Mon Sep 17 00:00:00 2001 From: Philipp AUER Date: Tue, 3 Jun 2025 17:21:17 -0400 Subject: [PATCH] Debug parties and battles (#6884) Co-authored-by: sbird --- include/data.h | 56 +++++---------- include/debug.h | 1 + src/data/debug_trainers.h | 132 ++++++++++++++++++++++++++++++++++ src/data/debug_trainers.party | 68 ++++++++++++++++++ src/debug.c | 63 ++++++++++++++-- 5 files changed, 276 insertions(+), 44 deletions(-) create mode 100644 src/data/debug_trainers.h create mode 100644 src/data/debug_trainers.party diff --git a/include/data.h b/include/data.h index 93b9e1fb1b..87b485b7d9 100644 --- a/include/data.h +++ b/include/data.h @@ -5,6 +5,7 @@ #include "constants/trainers.h" #include "constants/battle.h" #include "difficulty.h" +#include "debug.h" #define MAX_TRAINER_ITEMS 4 @@ -205,7 +206,9 @@ static inline u16 SanitizeTrainerId(u16 trainerId) static inline const struct Trainer *GetTrainerStructFromId(u16 trainerId) { - u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); + u32 sanitizedTrainerId = 0; + if (gIsDebugBattle) return GetDebugAiTrainer(); + sanitizedTrainerId = SanitizeTrainerId(trainerId); enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); return &gTrainers[difficulty][sanitizedTrainerId]; @@ -213,10 +216,9 @@ static inline const struct Trainer *GetTrainerStructFromId(u16 trainerId) static inline const enum TrainerClassID GetTrainerClassFromId(u16 trainerId) { - u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); - enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); + const struct Trainer *trainer = GetTrainerStructFromId(trainerId); - return gTrainers[difficulty][sanitizedTrainerId].trainerClass; + return trainer->trainerClass; } static inline const u8 *GetTrainerClassNameFromId(u16 trainerId) @@ -230,82 +232,62 @@ static inline const u8 *GetTrainerClassNameFromId(u16 trainerId) static inline const u8 *GetTrainerNameFromId(u16 trainerId) { - u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); - - enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); - - enum DifficultyLevel partnerDifficulty = GetBattlePartnerDifficultyLevel(trainerId); - if (trainerId > TRAINER_PARTNER(PARTNER_NONE)) + { + enum DifficultyLevel partnerDifficulty = GetBattlePartnerDifficultyLevel(trainerId); return gBattlePartners[partnerDifficulty][trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerName; - return gTrainers[difficulty][sanitizedTrainerId].trainerName; + } + return GetTrainerStructFromId(trainerId)->trainerName; } static inline const u8 GetTrainerPicFromId(u16 trainerId) { - u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); - enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); enum DifficultyLevel partnerDifficulty = GetBattlePartnerDifficultyLevel(trainerId); if (trainerId > TRAINER_PARTNER(PARTNER_NONE)) return gBattlePartners[partnerDifficulty][trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerPic; - return gTrainers[difficulty][sanitizedTrainerId].trainerPic; + return GetTrainerStructFromId(trainerId)->trainerPic; } static inline const u8 GetTrainerStartingStatusFromId(u16 trainerId) { - return gTrainers[GetCurrentDifficultyLevel()][SanitizeTrainerId(trainerId)].startingStatus; + return GetTrainerStructFromId(trainerId)->startingStatus; } static inline const enum TrainerBattleType GetTrainerBattleType(u16 trainerId) { - u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); - enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); - - return gTrainers[difficulty][sanitizedTrainerId].battleType; + return GetTrainerStructFromId(trainerId)->battleType; } static inline const u8 GetTrainerPartySizeFromId(u16 trainerId) { - u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); - enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); - - return gTrainers[difficulty][sanitizedTrainerId].partySize; + return GetTrainerStructFromId(trainerId)->partySize; } static inline const bool32 DoesTrainerHaveMugshot(u16 trainerId) { - return gTrainers[GetCurrentDifficultyLevel()][SanitizeTrainerId(trainerId)].mugshotColor; + return GetTrainerStructFromId(trainerId)->mugshotColor; } static inline const u8 GetTrainerMugshotColorFromId(u16 trainerId) { - return gTrainers[GetCurrentDifficultyLevel()][SanitizeTrainerId(trainerId)].mugshotColor; + return GetTrainerStructFromId(trainerId)->mugshotColor; } static inline const u16 *GetTrainerItemsFromId(u16 trainerId) { - u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); - enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); - - return gTrainers[difficulty][sanitizedTrainerId].items; + return GetTrainerStructFromId(trainerId)->items; } static inline const struct TrainerMon *GetTrainerPartyFromId(u16 trainerId) { - u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); - enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); - - return gTrainers[difficulty][sanitizedTrainerId].party; + return GetTrainerStructFromId(trainerId)->party; } static inline const u64 GetTrainerAIFlagsFromId(u16 trainerId) { - u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); - enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); - - return gTrainers[difficulty][sanitizedTrainerId].aiFlags; + return GetTrainerStructFromId(trainerId)->aiFlags; } #endif // GUARD_DATA_H diff --git a/include/debug.h b/include/debug.h index 1a48e9f6cd..11212ce97f 100644 --- a/include/debug.h +++ b/include/debug.h @@ -4,6 +4,7 @@ void Debug_ShowMainMenu(void); extern const u8 Debug_FlagsAndVarNotSetBattleConfigMessage[]; const u8 *GetWeatherName(u32 weatherId); +const struct Trainer* GetDebugAiTrainer(void); extern EWRAM_DATA bool8 gIsDebugBattle; extern EWRAM_DATA u64 gDebugAIFlags; diff --git a/src/data/debug_trainers.h b/src/data/debug_trainers.h new file mode 100644 index 0000000000..0ec683e296 --- /dev/null +++ b/src/data/debug_trainers.h @@ -0,0 +1,132 @@ +// +// DO NOT MODIFY THIS FILE! It is auto-generated from src/data/debug_trainers.party +// +// If you want to modify this file set COMPETITIVE_PARTY_SYNTAX to FALSE +// in include/config/general.h and remove this notice. +// Use sed -i '/^#line/d' 'src/data/debug_trainers.h' to remove #line markers. +// + +#line 1 "src/data/debug_trainers.party" + +#line 14 + [DIFFICULTY_NORMAL][DEBUG_TRAINER_PLAYER] = + { +#line 15 + .trainerName = _("Player"), +#line 16 + .trainerClass = TRAINER_CLASS_PKMN_TRAINER_1, +#line 17 + .trainerPic = TRAINER_PIC_BRENDAN, + .encounterMusic_gender = +#line 19 + TRAINER_ENCOUNTER_MUSIC_MALE, + .partySize = 1, + .party = (const struct TrainerMon[]) + { + { +#line 21 + .nickname = COMPOUND_STRING("Buffie"), +#line 21 + .species = SPECIES_WOBBUFFET, + .gender = TRAINER_MON_RANDOM_GENDER, +#line 25 + .ev = TRAINER_PARTY_EVS(0, 252, 252, 0, 6, 0), +#line 24 + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), +#line 23 + .lvl = 100, +#line 22 + .nature = NATURE_BRAVE, + .dynamaxLevel = MAX_DYNAMAX_LEVEL, + .moves = { +#line 26 + MOVE_EARTHQUAKE, + MOVE_FLAMETHROWER, + MOVE_CELEBRATE, + MOVE_CELEBRATE, + }, + }, + }, + }, +#line 31 + [DIFFICULTY_NORMAL][DEBUG_TRAINER_AI] = + { +#line 32 + .trainerName = _("Debugger"), +#line 33 + .trainerClass = TRAINER_CLASS_RIVAL, +#line 35 + .trainerPic = TRAINER_PIC_STEVEN, + .encounterMusic_gender = +#line 37 + TRAINER_ENCOUNTER_MUSIC_MALE, +#line 34 + .battleType = TRAINER_BATTLE_TYPE_SINGLES, + .partySize = 3, + .party = (const struct TrainerMon[]) + { + { +#line 39 + .species = SPECIES_METANG, + .gender = TRAINER_MON_RANDOM_GENDER, +#line 43 + .ev = TRAINER_PARTY_EVS(0, 252, 252, 0, 6, 0), +#line 42 + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), +#line 41 + .lvl = 42, +#line 40 + .nature = NATURE_BRAVE, + .dynamaxLevel = MAX_DYNAMAX_LEVEL, + .moves = { +#line 44 + MOVE_LIGHT_SCREEN, + MOVE_PSYCHIC, + MOVE_REFLECT, + MOVE_METAL_CLAW, + }, + }, + { +#line 49 + .species = SPECIES_SKARMORY, + .gender = TRAINER_MON_RANDOM_GENDER, +#line 53 + .ev = TRAINER_PARTY_EVS(252, 0, 0, 0, 6, 252), +#line 52 + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), +#line 51 + .lvl = 43, +#line 50 + .nature = NATURE_IMPISH, + .dynamaxLevel = MAX_DYNAMAX_LEVEL, + .moves = { +#line 54 + MOVE_TOXIC, + MOVE_AERIAL_ACE, + MOVE_PROTECT, + MOVE_STEEL_WING, + }, + }, + { +#line 59 + .species = SPECIES_AGGRON, + .gender = TRAINER_MON_RANDOM_GENDER, +#line 63 + .ev = TRAINER_PARTY_EVS(0, 252, 0, 0, 252, 6), +#line 62 + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), +#line 61 + .lvl = 44, +#line 60 + .nature = NATURE_ADAMANT, + .dynamaxLevel = MAX_DYNAMAX_LEVEL, + .moves = { +#line 64 + MOVE_THUNDER, + MOVE_PROTECT, + MOVE_SOLAR_BEAM, + MOVE_DRAGON_CLAW, + }, + }, + }, + }, diff --git a/src/data/debug_trainers.party b/src/data/debug_trainers.party new file mode 100644 index 0000000000..4a57d2c35e --- /dev/null +++ b/src/data/debug_trainers.party @@ -0,0 +1,68 @@ +/* + +Parties for the debug menu. + +The trainer description for DEBUG_TRAINER_PLAYER is not used, +its party is given to the player whenever the Set Party action is selected, +or the Start Debug Battle action is selected. + +The debug menu will start a battle against DEBUG_TRAINER_AI when the +Start Debug Battle action is selected. + +*/ + +=== DEBUG_TRAINER_PLAYER === +Name: Player +Class: Pkmn Trainer 1 +Pic: Brendan +Gender: Male +Music: Male + +Buffie (Wobbuffet) +Brave Nature +Level: 100 +IVs: 31 HP / 31 Atk / 31 Def / 31 SpA / 31 SpD / 31 Spe +EVs: 252 Atk / 252 Def / 6 SpA +- Earthquake +- Flamethrower +- Celebrate +- Celebrate + +=== DEBUG_TRAINER_AI === +Name: Debugger +AI: Basic Trainer +Class: Rival +Battle Type: Singles +Pic: Steven +Gender: Male +Music: Male + +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 diff --git a/src/debug.c b/src/debug.c index cbf90dc567..0b018b275f 100644 --- a/src/debug.c +++ b/src/debug.c @@ -159,6 +159,8 @@ enum PartyDebugMenu DEBUG_PARTY_MENU_ITEM_CHECK_EVS, DEBUG_PARTY_MENU_ITEM_CHECK_IVS, DEBUG_PARTY_MENU_ITEM_CLEAR_PARTY, + DEBUG_PARTY_MENU_ITEM_SET_PARTY, + DEBUG_PARTY_MENU_ITEM_BATTLE_SINGLE, }; enum ScriptDebugMenu @@ -437,6 +439,8 @@ static void DebugAction_Party_InflictStatus1(u8 taskId); static void DebugAction_Party_CheckEVs(u8 taskId); static void DebugAction_Party_CheckIVs(u8 taskId); static void DebugAction_Party_ClearParty(u8 taskId); +static void DebugAction_Party_SetParty(u8 taskId); +static void DebugAction_Party_BattleSingle(u8 taskId); static void DebugAction_FlagsVars_Flags(u8 taskId); static void DebugAction_FlagsVars_FlagsSelect(u8 taskId); @@ -708,13 +712,15 @@ static const struct ListMenuItem sDebugMenu_Items_PCBag_Fill[] = static const struct ListMenuItem sDebugMenu_Items_Party[] = { - [DEBUG_PARTY_MENU_ITEM_MOVE_REMINDER] = {COMPOUND_STRING("Move Reminder"), DEBUG_PARTY_MENU_ITEM_MOVE_REMINDER}, - [DEBUG_PARTY_MENU_ITEM_HATCH_AN_EGG] = {COMPOUND_STRING("Hatch an Egg"), DEBUG_PARTY_MENU_ITEM_HATCH_AN_EGG}, - [DEBUG_PARTY_MENU_ITEM_HEAL_PARTY] = {COMPOUND_STRING("Heal party"), DEBUG_PARTY_MENU_ITEM_HEAL_PARTY}, - [DEBUG_PARTY_MENU_ITEM_INFLICT_STATUS1] = {COMPOUND_STRING("Inflict Status1"), DEBUG_PARTY_MENU_ITEM_INFLICT_STATUS1}, - [DEBUG_PARTY_MENU_ITEM_CHECK_EVS] = {COMPOUND_STRING("Check EVs"), DEBUG_PARTY_MENU_ITEM_CHECK_EVS}, - [DEBUG_PARTY_MENU_ITEM_CHECK_IVS] = {COMPOUND_STRING("Check IVs"), DEBUG_PARTY_MENU_ITEM_CHECK_IVS}, - [DEBUG_PARTY_MENU_ITEM_CLEAR_PARTY] = {COMPOUND_STRING("Clear Party"), DEBUG_PARTY_MENU_ITEM_CLEAR_PARTY}, + [DEBUG_PARTY_MENU_ITEM_MOVE_REMINDER] = {COMPOUND_STRING("Move Reminder"), DEBUG_PARTY_MENU_ITEM_MOVE_REMINDER}, + [DEBUG_PARTY_MENU_ITEM_HATCH_AN_EGG] = {COMPOUND_STRING("Hatch an Egg"), DEBUG_PARTY_MENU_ITEM_HATCH_AN_EGG}, + [DEBUG_PARTY_MENU_ITEM_HEAL_PARTY] = {COMPOUND_STRING("Heal party"), DEBUG_PARTY_MENU_ITEM_HEAL_PARTY}, + [DEBUG_PARTY_MENU_ITEM_INFLICT_STATUS1] = {COMPOUND_STRING("Inflict Status1"), DEBUG_PARTY_MENU_ITEM_INFLICT_STATUS1}, + [DEBUG_PARTY_MENU_ITEM_CHECK_EVS] = {COMPOUND_STRING("Check EVs"), DEBUG_PARTY_MENU_ITEM_CHECK_EVS}, + [DEBUG_PARTY_MENU_ITEM_CHECK_IVS] = {COMPOUND_STRING("Check IVs"), DEBUG_PARTY_MENU_ITEM_CHECK_IVS}, + [DEBUG_PARTY_MENU_ITEM_CLEAR_PARTY] = {COMPOUND_STRING("Clear Party"), DEBUG_PARTY_MENU_ITEM_CLEAR_PARTY}, + [DEBUG_PARTY_MENU_ITEM_SET_PARTY] = {COMPOUND_STRING("Set Party"), DEBUG_PARTY_MENU_ITEM_SET_PARTY}, + [DEBUG_PARTY_MENU_ITEM_BATTLE_SINGLE] = {COMPOUND_STRING("Start Debug Battle"), DEBUG_PARTY_MENU_ITEM_BATTLE_SINGLE}, }; static const struct ListMenuItem sDebugMenu_Items_Scripts[] = @@ -897,6 +903,8 @@ static void (*const sDebugMenu_Actions_Party[])(u8) = [DEBUG_PARTY_MENU_ITEM_CHECK_EVS] = DebugAction_Party_CheckEVs, [DEBUG_PARTY_MENU_ITEM_CHECK_IVS] = DebugAction_Party_CheckIVs, [DEBUG_PARTY_MENU_ITEM_CLEAR_PARTY] = DebugAction_Party_ClearParty, + [DEBUG_PARTY_MENU_ITEM_SET_PARTY] = DebugAction_Party_SetParty, + [DEBUG_PARTY_MENU_ITEM_BATTLE_SINGLE] = DebugAction_Party_BattleSingle, }; static void (*const sDebugMenu_Actions_Scripts[])(u8) = @@ -4893,6 +4901,47 @@ static void DebugAction_Party_ClearParty(u8 taskId) Debug_DestroyMenu_Full(taskId); } +enum DebugTrainerIds +{ + DEBUG_TRAINER_PLAYER, + DEBUG_TRAINER_AI, + DEBUG_TRAINERS_COUNT +}; + +const struct Trainer sDebugTrainers[DIFFICULTY_COUNT][DEBUG_TRAINERS_COUNT] = +{ +#include "data/debug_trainers.h" +}; + +const struct Trainer* GetDebugAiTrainer(void) +{ + return &sDebugTrainers[DIFFICULTY_NORMAL][DEBUG_TRAINER_AI]; +} + +static void DebugAction_Party_SetParty(u8 taskId) +{ + ZeroPlayerPartyMons(); + CreateNPCTrainerPartyFromTrainer(gPlayerParty, &sDebugTrainers[DIFFICULTY_NORMAL][DEBUG_TRAINER_PLAYER], TRUE, BATTLE_TYPE_TRAINER); + ScriptContext_Enable(); + Debug_DestroyMenu_Full(taskId); +} + +static void DebugAction_Party_BattleSingle(u8 taskId) +{ + ZeroPlayerPartyMons(); + ZeroEnemyPartyMons(); + CreateNPCTrainerPartyFromTrainer(gPlayerParty, &sDebugTrainers[DIFFICULTY_NORMAL][DEBUG_TRAINER_PLAYER], TRUE, BATTLE_TYPE_TRAINER); + CreateNPCTrainerPartyFromTrainer(gEnemyParty, GetDebugAiTrainer(), FALSE, BATTLE_TYPE_TRAINER); + + gBattleTypeFlags = BATTLE_TYPE_TRAINER; + gDebugAIFlags = sDebugTrainers[DIFFICULTY_NORMAL][DEBUG_TRAINER_AI].aiFlags; + gIsDebugBattle = TRUE; + gBattleEnvironment = BattleSetup_GetEnvironmentId(); + CalculateEnemyPartyCount(); + BattleSetup_StartTrainerBattle_Debug(); + Debug_DestroyMenu_Full(taskId); +} + void CheckEWRAMCounters(struct ScriptContext *ctx) { ConvertIntToDecimalStringN(gStringVar1, gFollowerSteps, STR_CONV_MODE_LEFT_ALIGN, 5);