From 05b1db8cc64ca1fbef534511602e5f0e31062e97 Mon Sep 17 00:00:00 2001 From: hedara90 <90hedara@gmail.com> Date: Fri, 18 Jul 2025 16:57:57 +0200 Subject: [PATCH] `trainerproc` copy other trainer party (#7251) --- docs/tutorials/how_to_trainer_party_pool.md | 5 +++ include/data.h | 1 + src/battle_main.c | 19 ++++++++- tools/trainerproc/main.c | 43 +++++++++++++++++---- 4 files changed, 59 insertions(+), 9 deletions(-) diff --git a/docs/tutorials/how_to_trainer_party_pool.md b/docs/tutorials/how_to_trainer_party_pool.md index e0e7639de3..e111ba957e 100644 --- a/docs/tutorials/how_to_trainer_party_pool.md +++ b/docs/tutorials/how_to_trainer_party_pool.md @@ -52,6 +52,11 @@ By default, only `DefaultPickFunction` and `PickLowest` are implemente - `Pool Prune` (`.poolPruneIndex`) controls if members in the pool should be removed before party members are picked from the pool. By default, only `POOL_PRUNE_NONE`, which doesn't remove anything from the pool, and `POOL_PRUNE_TEST`, which removes Wobbuffet from the pool, are implemented. Must be an `enum` value in `enum PoolPruneOptions`. +## Pool copy +The `Copy Pool` option can be used to have the trainer use the party or pool from a different trainer. +If you for example want some other trainer to have the same team/pool as Tiana, you'd use `Copy Pool: TRAINER_TIANA`. +If `Party Size` isn't defined for the current trainer, it will inherit from the copied trainer. + ## Example pool ``` === TRAINER_TIANA === diff --git a/include/data.h b/include/data.h index 003d669f8e..ffa1a4cba0 100644 --- a/include/data.h +++ b/include/data.h @@ -105,6 +105,7 @@ struct Trainer /*0x22*/ u8 poolRuleIndex; /*0x23*/ u8 poolPickIndex; /*0x24*/ u8 poolPruneIndex; + /*0x25*/ u16 overrideTrainer; }; struct TrainerClass diff --git a/src/battle_main.c b/src/battle_main.c index 7ba11811f6..8c4ba46261 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -2026,7 +2026,24 @@ static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 fir u8 retVal; if (trainerNum == TRAINER_SECRET_BASE) return 0; - retVal = CreateNPCTrainerPartyFromTrainer(party, GetTrainerStructFromId(trainerNum), firstTrainer, gBattleTypeFlags); + if (GetTrainerStructFromId(trainerNum)->overrideTrainer) + { + struct Trainer tempTrainer; + memcpy(&tempTrainer, GetTrainerStructFromId(trainerNum), sizeof(struct Trainer)); + const struct Trainer *origTrainer = GetTrainerStructFromId(tempTrainer.overrideTrainer); + + tempTrainer.party = origTrainer->party; + + tempTrainer.poolSize = origTrainer->poolSize; + if (tempTrainer.partySize == 0) + tempTrainer.partySize = origTrainer->partySize; + + retVal = CreateNPCTrainerPartyFromTrainer(party, (const struct Trainer *)(&tempTrainer), firstTrainer, gBattleTypeFlags); + } + else + { + retVal = CreateNPCTrainerPartyFromTrainer(party, GetTrainerStructFromId(trainerNum), firstTrainer, gBattleTypeFlags); + } return retVal; } diff --git a/tools/trainerproc/main.c b/tools/trainerproc/main.c index 98ca8884fd..dc812cb153 100644 --- a/tools/trainerproc/main.c +++ b/tools/trainerproc/main.c @@ -150,6 +150,9 @@ struct Trainer struct String pool_prune; int pool_prune_line; + struct String copy_pool; + int copy_pool_line; + struct String macro; int macro_line; }; @@ -1283,6 +1286,13 @@ static bool parse_trainer(struct Parser *p, const struct Parsed *parsed, struct trainer->pool_prune_line = value.location.line; trainer->pool_prune = token_string(&value); } + else if (is_literal_token(&key, "Copy Pool")) + { + if (trainer->copy_pool_line) + any_error = !set_show_parse_error(p, key.location, "duplicate 'Copy Pool'"); + trainer->copy_pool_line = value.location.line; + trainer->copy_pool = token_string(&value); + } else if (is_literal_token(&key, "Macro")) { if (trainer->macro_line) @@ -1317,7 +1327,7 @@ static bool parse_trainer(struct Parser *p, const struct Parsed *parsed, struct while (match_empty_line(p)) {} if (!parse_pokemon_header(p, &nickname, &species, &gender, &item)) { - if (i > 0 || ends_with(trainer->id, "_NONE")) + if (i > 0 || ends_with(trainer->id, "_NONE") || !is_empty_string(trainer->copy_pool)) break; if (!p->error) set_parse_error(p, p->location, "expected nickname or species"); @@ -1331,6 +1341,12 @@ static bool parse_trainer(struct Parser *p, const struct Parsed *parsed, struct } trainer->pokemon_n++; + if (!is_empty_string(trainer->copy_pool)) + { + set_show_parse_error(p, p->location, "trainer is set to copy mons from other trainer, but defines their own party"); + } + + pokemon->nickname = token_string(&nickname); pokemon->species = token_string(&species); if (is_empty_token(&gender)) @@ -1529,7 +1545,7 @@ static bool parse_trainer(struct Parser *p, const struct Parsed *parsed, struct } } - if (trainer->party_size_line && trainer->party_size > trainer->pokemon_n) + if (trainer->party_size_line && trainer->party_size > trainer->pokemon_n && is_empty_string(trainer->copy_pool)) { set_show_parse_error(p, p->location, "partySize larger than supplied pool"); } @@ -1863,6 +1879,13 @@ static void fprint_trainers(const char *output_path, FILE *f, struct Parsed *par fprintf(f, ",\n"); } + if (!is_empty_string(trainer->copy_pool)) + { + fprintf(f, "#line %d\n", trainer->copy_pool_line); + fprintf(f, " .overrideTrainer = "); + fprint_string(f, trainer->copy_pool); + fprintf(f, ",\n"); + } if (trainer->macro_line) { fprintf(f, "#line %d\n", trainer->macro_line); @@ -1875,18 +1898,21 @@ static void fprint_trainers(const char *output_path, FILE *f, struct Parsed *par { fprintf(f, "#line %d\n", trainer->party_size_line); fprintf(f, " .partySize = %d,\n", trainer->party_size); - fprintf(f, " .poolSize = %d,\n", trainer->pokemon_n); - fprintf(f, " .party = (const struct TrainerMon[])\n"); - fprintf(f, " {\n"); + if (is_empty_string(trainer->copy_pool)) + { + fprintf(f, " .poolSize = %d,\n", trainer->pokemon_n); + fprintf(f, " .party = (const struct TrainerMon[])\n"); + fprintf(f, " {\n"); + } } - else + else if (is_empty_string(trainer->copy_pool)) { fprintf(f, " .partySize = %d,\n", trainer->pokemon_n); fprintf(f, " .party = (const struct TrainerMon[])\n"); fprintf(f, " {\n"); } - for (int j = 0; j < trainer->pokemon_n; j++) + for (int j = 0; j < trainer->pokemon_n && is_empty_string(trainer->copy_pool); j++) { struct Pokemon *pokemon = &trainer->pokemon[j]; fprintf(f, " {\n"); @@ -2049,7 +2075,8 @@ static void fprint_trainers(const char *output_path, FILE *f, struct Parsed *par fprintf(f, " },\n"); } - fprintf(f, " },\n"); + if (is_empty_string(trainer->copy_pool)) + fprintf(f, " },\n"); fprintf(f, " },\n"); } }