• Our software update is now concluded. You will need to reset your password to log in. In order to do this, you will have to click "Log in" in the top right corner and then "Forgot your password?".
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

Expanding Pokénav/post-game rematches in Ruby/Sapphire

4
Posts
6
Years
  • Age 27
  • Seen Nov 30, 2023
Hiya, made a thread about this in the Binary section but having done more research, decomp seems to be the way to go. I've been thinking of getting more into ROM hacking, and wanted to start fairly simple with a hack that adds rematches to the non-Pokénav trainers in Ruby/Sapphire. Apparently it's easier with Emerald.

Looking into it, this seems to be as simple as adding new entries to the 'gTrainerEyeTrainers' table, adding more trainers/teams/scripts/Pokénav entries and so on. I've been assured this will also affect the structure of the save file, but I sort of expected that. If I'm going wrong here or if there's more to it, do let me know.

What I'd like some help with is the possibility of bumping all of the trainers up to a final post-champion rematch team once you've cleared the Elite Four. So, for example, each trainer bar Wally (and I guess Gabby & Ty) has 4 rematch teams defined. I'd like for them to have a sixth team that isn't accessible until you've entered the Hall of Fame - once you have, all of them get pushed forward to that sixth team from then on.

Thanks in advance for any help you can provide, and major props for all the work you guys have been doing with these decomps and the hacks that come from them. It's fascinating to see what you can make these old games do. :D
 
Last edited:

Lunos

Random Uruguayan User
3,114
Posts
15
Years
What I'd like some help with is the possibility of bumping all of the trainers up to a final post-champion rematch team once you've cleared the Elite Four. So, for example, each trainer bar Wally (and I guess Gabby & Ty) has 4 rematch teams defined. I'd like for them to have a sixth team that isn't accessible until you've entered the Hall of Fame - once you have, all of them get pushed forward to that sixth team from then on.
I mean, you can go ahead and do that.
Add your trainers opponents like you'd add any other. That means you'll be modifying src/data/trainers_en.h, src/data/trainer_parties.h, include/constants/flags.h and src/battle_setup.c.

Now, once you have everything set up, you need to dive into the usages of the gTrainerEyeTrainers which is the table that links rematch trainer Ids with the basic trainer's party, and read the code in order to understand how it all works.

If you Ctrl+F it in the same file where it's located, you'll notice there's a good number of functions that make use of it.
One of them is called GetRematchTrainerId.
This function calls another one called GetRematchTrainerIdFromTable which is the one that gets a rematch trainer Id based on the number of rematches the Player has had with that trainer InGame.

In order to do that, and if I'm not misunderstanding, it loops through all the entries in the gTrainerEyeTrainers table using a for loop with a local variable i, starting with the 2nd ID for each entry in the table, TRAINER_CALVIN_2, TRAINER_SHELBY_2, et cetera.
It's important to remember here that the entries in an array are index from 0 to 4, and not from 1 to 5, so the i variable starting at 1 means that the scan begins on the 2nd trainer on a list of 5, where the 1st element would be 0.

Once you've fought a trainer with rematch parties 4 times, the function will always return the 5th party index for each trainer present in gTrainerEyeTrainers, as you can see by its return trainer->opponentIDs[4];.

That's where you'll want to throw in a check using FlagGet.

Ex:
Code:
u16 GetRematchTrainerIdFromTable(const struct TrainerEyeTrainer *trainers, u16 opponentId)
{
    int i;
    const struct TrainerEyeTrainer *trainer;
    s32 trainerEyeIndex = FirstBattleTrainerIdToRematchTableId(trainers, opponentId);

    if (trainerEyeIndex == -1)
        return 0;
    trainer = &trainers[trainerEyeIndex];
    for (i = 1; i < 5; i++)
    {
        if (!trainer->opponentIDs[i])
            return trainer->opponentIDs[i - 1];
        if (!HasTrainerAlreadyBeenFought(trainer->opponentIDs[i]))
            return trainer->opponentIDs[i];
    }

[COLOR="Red"]-   return trainer->opponentIDs[4];[/COLOR]
[COLOR="SeaGreen"]+   if (FlagGet(FLAG_SYS_GAME_CLEAR) && trainer->opponentIDs[5])
+       return trainer->opponentIDs[5]
+   else
+       return trainer->opponentIDs[4];[/COLOR]
}
This would tell the function to return the 6th rematch trainer Id (which again, you need to add for whatever trainers you want at gTrainerEyeTrainers) if the trainer has an actual 6th trainer Id set in the array and if the FLAG_SYS_GAME_CLEAR is set.
That flag is only set after you defeat Steven and become the new champion of Hoenn, set by the special GameClear in one of the scripts activated when you reach the Hall of Fame.

I basically told you everything you need to know by now, so without nothing else to add, I wish you good luck.
 
Last edited:
Back
Top