• This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn more.
  • Announcement - March 5th 12:17 PM GMT

    Hi there Guest!
    Thanks for checking out Silph Co.! Right now things are very much still in development with things like themes, guidelines, rules and most importantly content, still being a WIP. The staff and our members are actively working to make the community more homey for you. In the mean time, we are welcoming feedback and suggestions if you have them in the Feedback section.
    Please read the forum rules before posting.

Tutorial Making Ruby Recognize Foreign Met Locations (pokeruby)

Compatible Base ROMs
PKMN Ruby, PKMN Sapphire

Deokishisu

Active member
#1
Has it ever annoyed you that when you trade your Pokemon back to Ruby, their met locations are the generic, "obtained in a trade," message? Do you wish Game Freak was more forward-thinking when putting the met locations in? Then look no further!


Yes, this is Ruby, and yes those are foreign met locations!

This is a bit more complicated than a quick couple of edits, as we will be messing with some code in addition to adding to existing files. Don't worry though, it's pretty simple!

But before you start, did you know that there is a Part 2 to this post that allows you to show specific Orre met locations? No longer will your Pokemon show, "met at a distant land," instead showing exactly where they're from in the summary screen! It builds off of the information presented in this post, so I'll remind you again at the bottom for hardcore met location enthusiasts.

Our First Challenge: the Summary Screen

It's not much use to add all of the other map names in without first making sure the game knows to print them on the Summary Screen! The file we are going to edit in this step is in pokeruby/src/pokemon_summary_screen.c.

Scroll down to the function named "PokemonSummaryScreen_PrintTrainerMemo" on line 3031, as this is the function that we need to edit specifically. It should look like this:
Code:
static void PokemonSummaryScreen_PrintTrainerMemo(struct Pokemon *mon, u8 left, u8 top)
{
    u8 locationMet;
    u8 gameMet;
    u8 *ptr = gStringVar4;
    u8 nature = GetNature(mon);

#if ENGLISH
    ptr = sub_80A1E9C(ptr, gNatureNames[nature], 14);
    if (nature != NATURE_BOLD && nature != NATURE_GENTLE)
        ptr = StringCopy(ptr, gOtherText_Terminator4);
    ptr = StringCopy(ptr, gOtherText_Nature);
#elif GERMAN
    ptr = StringCopy(gStringVar4, gOtherText_Nature);
    ptr = sub_80A1E9C(ptr, gNatureNames[nature], 14);
    ptr = StringCopy(ptr, gOtherText_Terminator4);
#endif

    if (PokemonSummaryScreen_CheckOT(mon) == TRUE)
    {
        locationMet = GetMonData(mon, MON_DATA_MET_LOCATION);

        if (GetMonData(mon, MON_DATA_MET_LEVEL) == 0)
        {
            ptr = PokemonSummaryScreen_CopyPokemonLevel(ptr, 5);
            *ptr = CHAR_NEWLINE;
            ptr++;

            CopyLocationName(gStringVar1, locationMet);
            ptr = sub_80A1E9C(ptr, gStringVar1, 14);
            StringCopy(ptr, gOtherText_Egg2);
        }
        else if (locationMet >= 88)
        {
            *ptr = CHAR_NEWLINE;
            ptr++;

            StringCopy(ptr, gOtherText_ObtainedInTrade);
        }
        else
        {
            u8 levelMet = GetMonData(mon, MON_DATA_MET_LEVEL);

            ptr = PokemonSummaryScreen_CopyPokemonLevel(ptr, levelMet);
            *ptr = CHAR_NEWLINE;
            ptr++;

            CopyLocationName(gStringVar1, locationMet);
            ptr = sub_80A1E9C(ptr, gStringVar1, 14);
            StringCopy(ptr, gOtherText_Met);
        }
    }
    else
    {
        gameMet = GetMonData(mon, MON_DATA_MET_GAME);

        if (!(gameMet == VERSION_RUBY || gameMet == VERSION_SAPPHIRE || gameMet == VERSION_EMERALD))
        {
            *ptr = CHAR_NEWLINE;
            ptr++;

            StringCopy(ptr, gOtherText_ObtainedInTrade);
        }
        else
        {
            locationMet = GetMonData(mon, MON_DATA_MET_LOCATION);
            if (locationMet == 0xFF)
            {
                u8 levelMet = GetMonData(mon, MON_DATA_MET_LEVEL);

                ptr = PokemonSummaryScreen_CopyPokemonLevel(ptr, levelMet);
                *ptr = CHAR_NEWLINE;
                ptr++;

                StringCopy(ptr, gOtherText_FatefulEncounter);
            }
            else if (locationMet >= 88)
            {
                *ptr = CHAR_NEWLINE;
                ptr++;

                StringCopy(ptr, gOtherText_ObtainedInTrade);
            }
            else
            {
                u8 levelMet = GetMonData(mon, MON_DATA_MET_LEVEL);

                ptr = PokemonSummaryScreen_CopyPokemonLevel(ptr, levelMet);
                *ptr = CHAR_NEWLINE;
                ptr++;

                CopyLocationName(gStringVar1, locationMet);
                ptr = sub_80A1E9C(ptr, gStringVar1, 14);
                StringCopy(ptr, gOtherText_Met2);
            }
        }
    }

    Menu_PrintText(gStringVar4, left++, top++);
}
The first and easiest thing we have to do is edit those if statements that check if locationMet is >=88. Those statements will automatically force the summary screen to print, "obtained in a trade." for location indices that are not in vanilla Ruby and Sapphire. We only want the summary screen to print "obtained in a trade." for values higher than what is in Emerald. Emerald's last location name is Trainer Hill, which is number 212 (or 0xD4 if you prefer hex). So, change the if statements on lines 3063 and 3107 to read
Code:
else if (locationMet >= 213)
Now, there is another check on line 3087 that looks like this:
Code:
        if (!(gameMet == VERSION_RUBY || gameMet == VERSION_SAPPHIRE || gameMet == VERSION_EMERALD))
        {
            *ptr = CHAR_NEWLINE;
            ptr++;

            StringCopy(ptr, gOtherText_ObtainedInTrade);
        }
Can you read what this code is saying? It's forcing the game to print "obtained in a trade." for Pokemon that were not caught in Ruby, Sapphire, or Emerald! For our purposes, this check needs to go. But, we have an opportunity here to repurpose it to handle Pokemon from Orre, and that's what I did. Remember this function, as we will come back to it.

Hitting a Snag: Pokemon from Orre

If we were to just null out that version check, Pokemon from Orre would show up incorrectly in the summary screen. Instead, we'll be specifically checking if the Pokemon is from Colosseum or XD: Gale of Darkness and printing a custom string in the summary screen if that is the case.

First, we have to add in our custom string. Open up pokeruby/data/strings2.s to line 432. It should look something like this:
Code:
...
gOtherText_Egg2:: @ 842D0FB
.string " (EGG).$"

gOtherText_ObtainedInTrade:: @ 842D103
.string "obtained in a trade.$"

gOtherText_FatefulEncounter:: @ 842D118
.string "fateful encounter.$"
...

Here is where we need to add in our custom string for handling Pokemon from Orre. I placed it right after gOtherText_ObtainedInTrade. This is what my file looks like:
Code:
...
gOtherText_Egg2:: @ 842D0FB
    .string " (EGG).$"

gOtherText_ObtainedInTrade:: @ 842D103
    .string "obtained in a trade.$"

gOtherText_MetDistantLand::
    .string "met in a distant land.$"

gOtherText_FatefulEncounter:: @ 842D118
    .string "fateful encounter.$"
...
See how easy it was to add in text for the summary screen? I stuck my new string in and followed the same format as the others. So, the text is in the game, but we still need to include this new string in the header file. Open up pokeruby/include/string2.h to line 268. This section of the file should look like this:
Code:
// pokemon_summary_screen
extern const u8 gOtherText_Terminator4[];
extern const u8 gOtherText_Nature[];
extern const u8 gOtherText_Comma[];
extern const u8 gOtherText_Met[];
extern const u8 gOtherText_Egg2[];
extern const u8 gOtherText_ObtainedInTrade[];
extern const u8 gOtherText_FatefulEncounter[];
extern const u8 gOtherText_Met2[];
extern const u8 gOtherText_EggDayCare[];
extern const u8 gOtherText_EggNicePlace[];
extern const u8 gOtherText_EggObtainedInTrade[];
extern const u8 gOtherText_EggHotSprings[];

Similarly to the last step, all we need to do is add in our custom string. Since we're editing this header file, and this file is #included at the top of pokemon_summary_screen.c, the summary screen will be able to reference our new string. I named my custom string "gOtherText_MetDistantLand", so that is what I'll use here. This is what my file looks like:
Code:
// pokemon_summary_screen
extern const u8 gOtherText_Terminator4[];
extern const u8 gOtherText_Nature[];
extern const u8 gOtherText_Comma[];
extern const u8 gOtherText_Met[];
extern const u8 gOtherText_Egg2[];
extern const u8 gOtherText_ObtainedInTrade[];
extern const u8 gOtherText_MetDistantLand[];
extern const u8 gOtherText_FatefulEncounter[];
extern const u8 gOtherText_Met2[];
extern const u8 gOtherText_EggDayCare[];
extern const u8 gOtherText_EggNicePlace[];
extern const u8 gOtherText_EggObtainedInTrade[];
extern const u8 gOtherText_EggHotSprings[];
Now we have to head back to that check in pokemon_summary_screen.c from earlier. Our string is prepared, so we just have to rewrite the check!
Code:
        if (!(gameMet == VERSION_RUBY || gameMet == VERSION_SAPPHIRE || gameMet == VERSION_EMERALD))
        {
            *ptr = CHAR_NEWLINE;
            ptr++;

            StringCopy(ptr, gOtherText_ObtainedInTrade);
        }
Instead of checking if the version is not Ruby, not Sapphire, or not Emerald, we need to check specifically if the version is Colosseum or XD. When a Pokemon is generated, the game it is generated in is saved to its data structure. Two lines up from this check, the gameMet variable loads this data from the Pokemon being considered. We know from research that Colosseum and XD's identifier is 15. For reference, the others are:
0 - Colosseum Bonus Disc
1 - Sapphire
2 - Ruby
3 - Emerald
4 - Firered
5 - Leafgreen
15 - Colosseum or XD: Gale of Darkness
The other change we need to make here is at the end of this if statement. StringCopy gets gOtherText_ObtainedInTrade as an argument. We need to pass in our custom string instead. Again, I called my custom string "gOtherText_MetDistantLand", so that is what I'll use here. So, with our changes made, here is what this check should look like:
Code:
if (gameMet == 15) //generated by Colosseum or XD: Gale of Darkness
        {
            *ptr = CHAR_NEWLINE;
            ptr++;

            StringCopy(ptr, gOtherText_MetDistantLand);
        }
Great! Now Pokemon traded in from Colosseum or XD will display "met in a distant land." on their summary screens! But, we're not done yet.


What's in a Name? Adding in the New Location Names and Making Them Work

We have the summary screen all set up to show the new location names, and we even have Pokemon from Orre handled. Now, we need to get the new names set up, defined, and usable by the game. There are a few files we'll be editing for this. Most of the work involves copy and pasting here, and I will provide the things you need to copy in.

First, the game needs the strings themselves. The strings for the location names are in pokeruby/src/data/region_map_names_en.h and the new location names need to be added to this file. In the spoiler below is what my file looks like, and includes all the location names from the GBA Gen 3 games. You can copy and paste this into your file, replacing everything that is there.
Code:
const u8 gMapName_LittlerootTown[] = _("LITTLEROOT{NAME_END} TOWN");
const u8 gMapName_OldaleTown[] = _("OLDALE{NAME_END} TOWN");
const u8 gMapName_DewfordTown[] = _("DEWFORD{NAME_END} TOWN");
const u8 gMapName_LavaridgeTown[] = _("LAVARIDGE{NAME_END} TOWN");
const u8 gMapName_FallarborTown[] = _("FALLARBOR{NAME_END} TOWN");
const u8 gMapName_VerdanturfTown[] = _("VERDANTURF{NAME_END} TOWN");
const u8 gMapName_PacifidlogTown[] = _("PACIFIDLOG{NAME_END} TOWN");
const u8 gMapName_PetalburgCity[] = _("PETALBURG{NAME_END} CITY");
const u8 gMapName_SlateportCity[] = _("SLATEPORT{NAME_END} CITY");
const u8 gMapName_MauvilleCity[] = _("MAUVILLE{NAME_END} CITY");
const u8 gMapName_RustboroCity[] = _("RUSTBORO{NAME_END} CITY");
const u8 gMapName_FortreeCity[] = _("FORTREE{NAME_END} CITY");
const u8 gMapName_LilycoveCity[] = _("LILYCOVE{NAME_END} CITY");
const u8 gMapName_MossdeepCity[] = _("MOSSDEEP{NAME_END} CITY");
const u8 gMapName_SootopolisCity[] = _("SOOTOPOLIS{NAME_END} CITY");
const u8 gMapName_EverGrandeCity[] = _("EVER GRANDE{NAME_END} CITY");
const u8 gMapName_Route101[] = _("ROUTE 101");
const u8 gMapName_Route102[] = _("ROUTE 102");
const u8 gMapName_Route103[] = _("ROUTE 103");
const u8 gMapName_Route104[] = _("ROUTE 104");
const u8 gMapName_Route105[] = _("ROUTE 105");
const u8 gMapName_Route106[] = _("ROUTE 106");
const u8 gMapName_Route107[] = _("ROUTE 107");
const u8 gMapName_Route108[] = _("ROUTE 108");
const u8 gMapName_Route109[] = _("ROUTE 109");
const u8 gMapName_Route110[] = _("ROUTE 110");
const u8 gMapName_Route111[] = _("ROUTE 111");
const u8 gMapName_Route112[] = _("ROUTE 112");
const u8 gMapName_Route113[] = _("ROUTE 113");
const u8 gMapName_Route114[] = _("ROUTE 114");
const u8 gMapName_Route115[] = _("ROUTE 115");
const u8 gMapName_Route116[] = _("ROUTE 116");
const u8 gMapName_Route117[] = _("ROUTE 117");
const u8 gMapName_Route118[] = _("ROUTE 118");
const u8 gMapName_Route119[] = _("ROUTE 119");
const u8 gMapName_Route120[] = _("ROUTE 120");
const u8 gMapName_Route121[] = _("ROUTE 121");
const u8 gMapName_Route122[] = _("ROUTE 122");
const u8 gMapName_Route123[] = _("ROUTE 123");
const u8 gMapName_Route124[] = _("ROUTE 124");
const u8 gMapName_Route125[] = _("ROUTE 125");
const u8 gMapName_Route126[] = _("ROUTE 126");
const u8 gMapName_Route127[] = _("ROUTE 127");
const u8 gMapName_Route128[] = _("ROUTE 128");
const u8 gMapName_Route129[] = _("ROUTE 129");
const u8 gMapName_Route130[] = _("ROUTE 130");
const u8 gMapName_Route131[] = _("ROUTE 131");
const u8 gMapName_Route132[] = _("ROUTE 132");
const u8 gMapName_Route133[] = _("ROUTE 133");
const u8 gMapName_Route134[] = _("ROUTE 134");
const u8 gMapName_Underwater[] = _("UNDERWATER");
const u8 gMapName_GraniteCave[] = _("GRANITE CAVE");
const u8 gMapName_MtChimney[] = _("MT. CHIMNEY");
const u8 gMapName_SafariZone[] = _("SAFARI ZONE");
const u8 gMapName_BattleTower[] = _("BATTLE TOWER");
const u8 gMapName_PetalburgWoods[] = _("PETALBURG WOODS");
const u8 gMapName_RusturfTunnel[] = _("RUSTURF TUNNEL");
const u8 gMapName_AbandonedShip[] = _("ABANDONED SHIP");
const u8 gMapName_NewMauville[] = _("NEW MAUVILLE");
const u8 gMapName_MeteorFalls[] = _("METEOR FALLS");
const u8 gMapName_MtPyre[] = _("MT. PYRE");
const u8 gMapName_EvilTeamHideout[] = _("{EVIL_TEAM} HIDEOUT");
const u8 gMapName_ShoalCave[] = _("SHOAL CAVE");
const u8 gMapName_SeafloorCavern[] = _("SEAFLOOR CAVERN");
const u8 gMapName_VictoryRoad[] = _("VICTORY ROAD");
const u8 gMapName_MirageIsland[] = _("MIRAGE ISLAND");
const u8 gMapName_CaveOfOrigin[] = _("CAVE OF ORIGIN");
const u8 gMapName_SouthernIsland[] = _("SOUTHERN ISLAND");
const u8 gMapName_FieryPath[] = _("FIERY PATH");
const u8 gMapName_JaggedPass[] = _("JAGGED PASS");
const u8 gMapName_SealedChamber[] = _("SEALED CHAMBER");
const u8 gMapName_ScorchedSlab[] = _("SCORCHED SLAB");
const u8 gMapName_IslandCave[] = _("ISLAND CAVE");
const u8 gMapName_DesertRuins[] = _("DESERT RUINS");
const u8 gMapName_AncientTomb[] = _("ANCIENT TOMB");
const u8 gMapName_InsideOfTruck[] = _("INSIDE OF TRUCK");
const u8 gMapName_SkyPillar[] = _("SKY PILLAR");
const u8 gMapName_SecretBase[] = _("SECRET BASE");
const u8 gMapName_None[] = _("");
const u8 gMapName_PalletTown[] = _("PALLET TOWN");
const u8 gMapName_ViridianCity[] = _("VIRIDIAN CITY");
const u8 gMapName_PewterCity[] = _("PEWTER CITY");
const u8 gMapName_CeruleanCity[] = _("CERULEAN CITY");
const u8 gMapName_LavenderTown[] = _("LAVENDER TOWN");
const u8 gMapName_VermilionCity[] = _("VERMILION CITY");
const u8 gMapName_CeladonCity[] = _("CELADON CITY");
const u8 gMapName_FuchsiaCity[] = _("FUCHSIA CITY");
const u8 gMapName_CinnabarIsland[] = _("CINNABAR ISLAND");
const u8 gMapName_IndigoPlateau[] = _("INDIGO PLATEAU");
const u8 gMapName_SaffronCity[] = _("SAFFRON CITY");
const u8 gMapName_Route4[] = _("ROUTE 4");
const u8 gMapName_Route10[] = _("ROUTE 10");
const u8 gMapName_Route1[] = _("ROUTE 1");
const u8 gMapName_Route2[] = _("ROUTE 2");
const u8 gMapName_Route3[] = _("ROUTE 3");
const u8 gMapName_Route4_2[] = _("ROUTE 4");
const u8 gMapName_Route5[] = _("ROUTE 5");
const u8 gMapName_Route6[] = _("ROUTE 6");
const u8 gMapName_Route7[] = _("ROUTE 7");
const u8 gMapName_Route8[] = _("ROUTE 8");
const u8 gMapName_Route9[] = _("ROUTE 9");
const u8 gMapName_Route10_2[] = _("ROUTE 10");
const u8 gMapName_Route11[] = _("ROUTE 11");
const u8 gMapName_Route12[] = _("ROUTE 12");
const u8 gMapName_Route13[] = _("ROUTE 13");
const u8 gMapName_Route14[] = _("ROUTE 14");
const u8 gMapName_Route15[] = _("ROUTE 15");
const u8 gMapName_Route16[] = _("ROUTE 16");
const u8 gMapName_Route17[] = _("ROUTE 17");
const u8 gMapName_Route18[] = _("ROUTE 18");
const u8 gMapName_Route19[] = _("ROUTE 19");
const u8 gMapName_Route20[] = _("ROUTE 20");
const u8 gMapName_Route21[] = _("ROUTE 21");
const u8 gMapName_Route22[] = _("ROUTE 22");
const u8 gMapName_Route23[] = _("ROUTE 23");
const u8 gMapName_Route24[] = _("ROUTE 24");
const u8 gMapName_Route25[] = _("ROUTE 25");
const u8 gMapName_ViridianForest[] = _("VIRIDIAN FOREST");
const u8 gMapName_MtMoon[] = _("MT. MOON");
const u8 gMapName_SSAnne[] = _("S.S. ANNE");
const u8 gMapName_UndergroundPath[] = _("UNDERGROUND PATH");
const u8 gMapName_UndergroundPath2[] = _("UNDERGROUND PATH");
const u8 gMapName_DiglettsCave[] = _("DIGLETT’S CAVE");
const u8 gMapName_KantoVictoryRoad[] = _("VICTORY ROAD");
const u8 gMapName_RocketHideout[] = _("ROCKET HIDEOUT");
const u8 gMapName_SilphCo[] = _("SILPH CO.");
const u8 gMapName_PokemonMansion[] = _("POKéMON MANSION");
const u8 gMapName_KantoSafariZone[] = _("SAFARI ZONE");
const u8 gMapName_PokemonLeague[] = _("POKéMON LEAGUE");
const u8 gMapName_RockTunnel[] = _("ROCK TUNNEL");
const u8 gMapName_SeafoamIslands[] = _("SEAFOAM ISLANDS");
const u8 gMapName_PokemonTower[] = _("POKéMON TOWER");
const u8 gMapName_CeruleanCave[] = _("CERULEAN CAVE");
const u8 gMapName_PowerPlant[] = _("POWER PLANT");
const u8 gMapName_OneIsland[] = _("ONE ISLAND");
const u8 gMapName_TwoIsland[] = _("TWO ISLAND");
const u8 gMapName_ThreeIsland[] = _("THREE ISLAND");
const u8 gMapName_FourIsland[] = _("FOUR ISLAND");
const u8 gMapName_FiveIsland[] = _("FIVE ISLAND");
const u8 gMapName_SevenIsland[] = _("SEVEN ISLAND");
const u8 gMapName_SixIsland[] = _("SIX ISLAND");
const u8 gMapName_KindleRoad[] = _("KINDLE ROAD");
const u8 gMapName_TreasureBeach[] = _("TREASURE BEACH");
const u8 gMapName_CapeBrink[] = _("CAPE BRINK");
const u8 gMapName_BondBridge[] = _("BOND BRIDGE");
const u8 gMapName_ThreeIslePort[] = _("THREE ISLE PORT");
const u8 gMapName_SeviiIsle6[] = _("SEVII ISLE 6");
const u8 gMapName_SeviiIsle7[] = _("SEVII ISLE 7");
const u8 gMapName_SeviiIsle8[] = _("SEVII ISLE 8");
const u8 gMapName_SeviiIsle9[] = _("SEVII ISLE 9");
const u8 gMapName_ResortGorgeous[] = _("RESORT GORGEOUS");
const u8 gMapName_WaterLabyrinth[] = _("WATER LABYRINTH");
const u8 gMapName_FiveIsleMeadow[] = _("FIVE ISLE MEADOW");
const u8 gMapName_MemorialPillar[] = _("MEMORIAL PILLAR");
const u8 gMapName_OutcastIsland[] = _("OUTCAST ISLAND");
const u8 gMapName_GreenPath[] = _("GREEN PATH");
const u8 gMapName_WaterPath[] = _("WATER PATH");
const u8 gMapName_RuinValley[] = _("RUIN VALLEY");
const u8 gMapName_TrainerTower[] = _("TRAINER TOWER");
const u8 gMapName_CanyonEntrance[] = _("CANYON ENTRANCE");
const u8 gMapName_SevaultCanyon[] = _("SEVAULT CANYON");
const u8 gMapName_TanobyRuins[] = _("TANOBY RUINS");
const u8 gMapName_SeviiIsle22[] = _("SEVII ISLE 22");
const u8 gMapName_SeviiIsle23[] = _("SEVII ISLE 23");
const u8 gMapName_SeviiIsle24[] = _("SEVII ISLE 24");
const u8 gMapName_NavelRock[] = _("NAVEL ROCK");
const u8 gMapName_MtEmber[] = _("MT. EMBER");
const u8 gMapName_BerryForest[] = _("BERRY FOREST");
const u8 gMapName_IcefallCave[] = _("ICEFALL CAVE");
const u8 gMapName_RocketWarehouse[] = _("ROCKET WAREHOUSE");
const u8 gMapName_TrainerTower2[] = _("TRAINER TOWER");
const u8 gMapName_DottedHole[] = _("DOTTED HOLE");
const u8 gMapName_LostCave[] = _("LOST CAVE");
const u8 gMapName_PatternBush[] = _("PATTERN BUSH");
const u8 gMapName_AlteringCave[] = _("ALTERING CAVE");
const u8 gMapName_TanobyChambers[] = _("TANOBY CHAMBERS");
const u8 gMapName_ThreeIslePath[] = _("THREE ISLE PATH");
const u8 gMapName_TanobyKey[] = _("TANOBY KEY");
const u8 gMapName_BirthIsland[] = _("BIRTH ISLAND");
const u8 gMapName_MoneanChamber[] = _("MONEAN CHAMBER");
const u8 gMapName_LiptooChamber[] = _("LIPTOO CHAMBER");
const u8 gMapName_WeepthChamber[] = _("WEEPTH CHAMBER");
const u8 gMapName_DilfordChamber[] = _("DILFORD CHAMBER");
const u8 gMapName_ScufibChamber[] = _("SCUFIB CHAMBER");
const u8 gMapName_RixyChamber[] = _("RIXY CHAMBER");
const u8 gMapName_ViapoisChamber[] = _("VIAPOIS CHAMBER");
const u8 gMapName_EmberSpa[] = _("EMBER SPA");
const u8 gMapName_SpecialArea[] = _("SPECIAL AREA");
const u8 gMapName_AquaHideout[] = _("AQUA HIDEOUT");
const u8 gMapName_MagmaHideout[] = _("MAGMA HIDEOUT");
const u8 gMapName_MirageTower[] = _("MIRAGE TOWER");
const u8 gMapName_FarawayIsland[] = _("FARAWAY ISLAND");
const u8 gMapName_ArtisanCave[] = _("ARTISAN CAVE");
const u8 gMapName_MarineCave[] = _("MARINE CAVE");
const u8 gMapName_TerraCave[] = _("TERRA CAVE");
const u8 gMapName_DesertUnderpass[] = _("DESERT UNDERPASS");
const u8 gMapName_TrainerHill[] = _("TRAINER HILL");

The strings are in! Now, we need to associate them with the indices for the met location. A Pokemon's met location is a byte that is read to determine which map name to show, but Ruby doesn't have any names associated with bytes higher than the locations in vanilla Ruby. We're about to change that. Open up pokeruby/include/constants/region_map_sections.h. Here, we need to define new map names. This is where linking our new location strings to their respective indices happen. Copy what is in the spoiler below and replace the entire content of the file with it.
Code:
#ifndef GUARD_REGIONMAPSEC_H
#define GUARD_REGIONMAPSEC_H

enum
{
    MAPSEC_LITTLEROOT_TOWN,              // 0x00
    MAPSEC_OLDALE_TOWN,                  // 0x01
    MAPSEC_DEWFORD_TOWN,                 // 0x02
    MAPSEC_LAVARIDGE_TOWN,               // 0x03
    MAPSEC_FALLARBOR_TOWN,               // 0x04
    MAPSEC_VERDANTURF_TOWN,              // 0x05
    MAPSEC_PACIFIDLOG_TOWN,              // 0x06
    MAPSEC_PETALBURG_CITY,               // 0x07
    MAPSEC_SLATEPORT_CITY,               // 0x08
    MAPSEC_MAUVILLE_CITY,                // 0x09
    MAPSEC_RUSTBORO_CITY,                // 0x0A
    MAPSEC_FORTREE_CITY,                 // 0x0B
    MAPSEC_LILYCOVE_CITY,                // 0x0C
    MAPSEC_MOSSDEEP_CITY,                // 0x0D
    MAPSEC_SOOTOPOLIS_CITY,              // 0x0E
    MAPSEC_EVER_GRANDE_CITY,             // 0x0F
    MAPSEC_ROUTE_101,                    // 0x10
    MAPSEC_ROUTE_102,                    // 0x11
    MAPSEC_ROUTE_103,                    // 0x12
    MAPSEC_ROUTE_104,                    // 0x13
    MAPSEC_ROUTE_105,                    // 0x14
    MAPSEC_ROUTE_106,                    // 0x15
    MAPSEC_ROUTE_107,                    // 0x16
    MAPSEC_ROUTE_108,                    // 0x17
    MAPSEC_ROUTE_109,                    // 0x18
    MAPSEC_ROUTE_110,                    // 0x19
    MAPSEC_ROUTE_111,                    // 0x1A
    MAPSEC_ROUTE_112,                    // 0x1B
    MAPSEC_ROUTE_113,                    // 0x1C
    MAPSEC_ROUTE_114,                    // 0x1D
    MAPSEC_ROUTE_115,                    // 0x1E
    MAPSEC_ROUTE_116,                    // 0x1F
    MAPSEC_ROUTE_117,                    // 0x20
    MAPSEC_ROUTE_118,                    // 0x21
    MAPSEC_ROUTE_119,                    // 0x22
    MAPSEC_ROUTE_120,                    // 0x23
    MAPSEC_ROUTE_121,                    // 0x24
    MAPSEC_ROUTE_122,                    // 0x25
    MAPSEC_ROUTE_123,                    // 0x26
    MAPSEC_ROUTE_124,                    // 0x27
    MAPSEC_ROUTE_125,                    // 0x28
    MAPSEC_ROUTE_126,                    // 0x29
    MAPSEC_ROUTE_127,                    // 0x2A
    MAPSEC_ROUTE_128,                    // 0x2B
    MAPSEC_ROUTE_129,                    // 0x2C
    MAPSEC_ROUTE_130,                    // 0x2D
    MAPSEC_ROUTE_131,                    // 0x2E
    MAPSEC_ROUTE_132,                    // 0x2F
    MAPSEC_ROUTE_133,                    // 0x30
    MAPSEC_ROUTE_134,                    // 0x31
    MAPSEC_UNDERWATER_124,               // 0x32
    MAPSEC_UNDERWATER_125,               // 0x33
    MAPSEC_UNDERWATER_126,               // 0x34
    MAPSEC_UNDERWATER_127,               // 0x35
    MAPSEC_UNDERWATER_SOOTOPOLIS,        // 0x36
    MAPSEC_GRANITE_CAVE,                 // 0x37
    MAPSEC_MT_CHIMNEY,                   // 0x38
    MAPSEC_SAFARI_ZONE,                  // 0x39
    MAPSEC_BATTLE_TOWER,                   // 0x3A
    MAPSEC_PETALBURG_WOODS,              // 0x3B
    MAPSEC_RUSTURF_TUNNEL,               // 0x3C
    MAPSEC_ABANDONED_SHIP,               // 0x3D
    MAPSEC_NEW_MAUVILLE,                 // 0x3E
    MAPSEC_METEOR_FALLS,                 // 0x3F
    MAPSEC_METEOR_FALLS2,                // 0x40
    MAPSEC_MT_PYRE,                      // 0x41
    MAPSEC_EVIL_TEAM_HIDEOUT,            // 0x42
    MAPSEC_SHOAL_CAVE,                   // 0x43
    MAPSEC_SEAFLOOR_CAVERN,              // 0x44
    MAPSEC_UNDERWATER_128,               // 0x45
    MAPSEC_VICTORY_ROAD,                 // 0x46
    MAPSEC_MIRAGE_ISLAND,                // 0x47
    MAPSEC_CAVE_OF_ORIGIN,               // 0x48
    MAPSEC_SOUTHERN_ISLAND,              // 0x49
    MAPSEC_FIERY_PATH,                   // 0x4A
    MAPSEC_FIERY_PATH2,                  // 0x4B
    MAPSEC_JAGGED_PASS,                  // 0x4C
    MAPSEC_JAGGED_PASS2,                 // 0x4D
    MAPSEC_SEALED_CHAMBER,               // 0x4E
    MAPSEC_UNDERWATER_SEALED_CHAMBER,    // 0x4F
    MAPSEC_SCORCHED_SLAB,                // 0x50
    MAPSEC_ISLAND_CAVE,                  // 0x51
    MAPSEC_DESERT_RUINS,                 // 0x52
    MAPSEC_ANCIENT_TOMB,                 // 0x53
    MAPSEC_INSIDE_OF_TRUCK,              // 0x54
    MAPSEC_SKY_PILLAR,                   // 0x55
    MAPSEC_SECRET_BASE,                  // 0x56
    MAPSEC_DYNAMIC,                      // 0x57
    MAPSEC_PALLET_TOWN,                  // 0x58
    MAPSEC_VIRIDIAN_CITY,                // 0x59
    MAPSEC_PEWTER_CITY,                  // 0x5A
    MAPSEC_CERULEAN_CITY,                // 0x5B
    MAPSEC_LAVENDER_TOWN,                // 0x5C
    MAPSEC_VERMILION_CITY,               // 0x5D
    MAPSEC_CELADON_CITY,                 // 0x5E
    MAPSEC_FUCHSIA_CITY,                 // 0x5F
    MAPSEC_CINNABAR_ISLAND,              // 0x60
    MAPSEC_INDIGO_PLATEAU,               // 0x61
    MAPSEC_SAFFRON_CITY,                 // 0x62
    MAPSEC_ROUTE_4_FLYDUP,               // 0x63
    MAPSEC_ROUTE_10_FLYDUP,              // 0x64
    MAPSEC_ROUTE_1,                      // 0x65
    MAPSEC_ROUTE_2,                      // 0x66
    MAPSEC_ROUTE_3,                      // 0x67
    MAPSEC_ROUTE_4,                      // 0x68
    MAPSEC_ROUTE_5,                      // 0x69
    MAPSEC_ROUTE_6,                      // 0x6A
    MAPSEC_ROUTE_7,                      // 0x6B
    MAPSEC_ROUTE_8,                      // 0x6C
    MAPSEC_ROUTE_9,                      // 0x6D
    MAPSEC_ROUTE_10,                     // 0x6E
    MAPSEC_ROUTE_11,                     // 0x6F
    MAPSEC_ROUTE_12,                     // 0x70
    MAPSEC_ROUTE_13,                     // 0x71
    MAPSEC_ROUTE_14,                     // 0x72
    MAPSEC_ROUTE_15,                     // 0x73
    MAPSEC_ROUTE_16,                     // 0x74
    MAPSEC_ROUTE_17,                     // 0x75
    MAPSEC_ROUTE_18,                     // 0x76
    MAPSEC_ROUTE_19,                     // 0x77
    MAPSEC_ROUTE_20,                     // 0x78
    MAPSEC_ROUTE_21,                     // 0x79
    MAPSEC_ROUTE_22,                     // 0x7A
    MAPSEC_ROUTE_23,                     // 0x7B
    MAPSEC_ROUTE_24,                     // 0x7C
    MAPSEC_ROUTE_25,                     // 0x7D
    MAPSEC_VIRIDIAN_FOREST,              // 0x7E
    MAPSEC_MT_MOON,                      // 0x7F
    MAPSEC_S_S_ANNE,                     // 0x80
    MAPSEC_UNDERGROUND_PATH,             // 0x81
    MAPSEC_UNDERGROUND_PATH_2,           // 0x82
    MAPSEC_DIGLETTS_CAVE,                // 0x83
    MAPSEC_KANTO_VICTORY_ROAD,           // 0x84
    MAPSEC_ROCKET_HIDEOUT,               // 0x85
    MAPSEC_SILPH_CO,                     // 0x86
    MAPSEC_POKEMON_MANSION,              // 0x87
    MAPSEC_KANTO_SAFARI_ZONE,            // 0x88
    MAPSEC_POKEMON_LEAGUE,               // 0x89
    MAPSEC_ROCK_TUNNEL,                  // 0x8A
    MAPSEC_SEAFOAM_ISLANDS,              // 0x8B
    MAPSEC_POKEMON_TOWER,                // 0x8C
    MAPSEC_CERULEAN_CAVE,                // 0x8D
    MAPSEC_POWER_PLANT,                  // 0x8E
    MAPSEC_ONE_ISLAND,                   // 0x8F
    MAPSEC_TWO_ISLAND,                   // 0x90
    MAPSEC_THREE_ISLAND,                 // 0x91
    MAPSEC_FOUR_ISLAND,                  // 0x92
    MAPSEC_FIVE_ISLAND,                  // 0x93
    MAPSEC_SEVEN_ISLAND,                 // 0x94
    MAPSEC_SIX_ISLAND,                   // 0x95
    MAPSEC_KINDLE_ROAD,                  // 0x96
    MAPSEC_TREASURE_BEACH,               // 0x97
    MAPSEC_CAPE_BRINK,                   // 0x98
    MAPSEC_BOND_BRIDGE,                  // 0x99
    MAPSEC_THREE_ISLE_PORT,              // 0x9A
    MAPSEC_SEVII_ISLE_6,                 // 0x9B
    MAPSEC_SEVII_ISLE_7,                 // 0x9C
    MAPSEC_SEVII_ISLE_8,                 // 0x9D
    MAPSEC_SEVII_ISLE_9,                 // 0x9E
    MAPSEC_RESORT_GORGEOUS,              // 0x9F
    MAPSEC_WATER_LABYRINTH,              // 0xA0
    MAPSEC_FIVE_ISLE_MEADOW,             // 0xA1
    MAPSEC_MEMORIAL_PILLAR,              // 0xA2
    MAPSEC_OUTCAST_ISLAND,               // 0xA3
    MAPSEC_GREEN_PATH,                   // 0xA4
    MAPSEC_WATER_PATH,                   // 0xA5
    MAPSEC_RUIN_VALLEY,                  // 0xA6
    MAPSEC_TRAINER_TOWER,                // 0xA7
    MAPSEC_CANYON_ENTRANCE,              // 0xA8
    MAPSEC_SEVAULT_CANYON,               // 0xA9
    MAPSEC_TANOBY_RUINS,                 // 0xAA
    MAPSEC_SEVII_ISLE_22,                // 0xAB
    MAPSEC_SEVII_ISLE_23,                // 0xAC
    MAPSEC_SEVII_ISLE_24,                // 0xAD
    MAPSEC_NAVEL_ROCK,                   // 0xAE
    MAPSEC_MT_EMBER,                     // 0xAF
    MAPSEC_BERRY_FOREST,                 // 0xB0
    MAPSEC_ICEFALL_CAVE,                 // 0xB1
    MAPSEC_ROCKET_WAREHOUSE,             // 0xB2
    MAPSEC_TRAINER_TOWER_2,              // 0xB3
    MAPSEC_DOTTED_HOLE,                  // 0xB4
    MAPSEC_LOST_CAVE,                    // 0xB5
    MAPSEC_PATTERN_BUSH,                 // 0xB6
    MAPSEC_ALTERING_CAVE,                // 0xB7
    MAPSEC_TANOBY_CHAMBERS,              // 0xB8
    MAPSEC_THREE_ISLE_PATH,              // 0xB9
    MAPSEC_TANOBY_KEY,                   // 0xBA
    MAPSEC_BIRTH_ISLAND,                 // 0xBB
    MAPSEC_MONEAN_CHAMBER,               // 0xBC
    MAPSEC_LIPTOO_CHAMBER,               // 0xBD
    MAPSEC_WEEPTH_CHAMBER,               // 0xBE
    MAPSEC_DILFORD_CHAMBER,              // 0xBF
    MAPSEC_SCUFIB_CHAMBER,               // 0xC0
    MAPSEC_RIXY_CHAMBER,                 // 0xC1
    MAPSEC_VIAPOIS_CHAMBER,              // 0xC2
    MAPSEC_EMBER_SPA,                    // 0xC3
    MAPSEC_SPECIAL_AREA,                 // 0xC4
    MAPSEC_AQUA_HIDEOUT,                 // 0xC5
    MAPSEC_MAGMA_HIDEOUT,                // 0xC6
    MAPSEC_MIRAGE_TOWER,                 // 0xC7
    MAPSEC_BIRTH_ISLAND_2,               // 0xC8
    MAPSEC_FARAWAY_ISLAND,               // 0xC9
    MAPSEC_ARTISAN_CAVE,                 // 0xCA
    MAPSEC_MARINE_CAVE,                  // 0xCB
    MAPSEC_UNDERWATER_MARINE_CAVE,       // 0xCC
    MAPSEC_TERRA_CAVE,                   // 0xCD
    MAPSEC_UNDERWATER_TERRA_CAVE,        // 0xCE
    MAPSEC_UNDERWATER_UNK1,              // 0xCF
    MAPSEC_UNDERWATER_129,               // 0xD0
    MAPSEC_DESERT_UNDERPASS,             // 0xD1
    MAPSEC_ALTERING_CAVE_2,              // 0xD2
    MAPSEC_NAVEL_ROCK2,                  // 0xD3
    MAPSEC_TRAINER_HILL,                 // 0xD4
    MAPSEC_NOTHING,                      // 0xD5
};

#endif // GUARD_REGIONMAPSEC_H

Great! Now we need to associate these map sections with the actual strings of our map names and the correct indices. Open up pokeruby/src/region_map.c to line 62. The structure we're looking at is called gRegionMapLocations, and it is what associates map names with certain IDs and links them to the world map. We need to add in our new map names here, but we need to be careful not to put them on the world map itself. The values directly before gMapName on each line are the x and y locations on the world map, as well as the width and height of the map in question. We don't1 want our new map names showing up on our Ruby Hoenn world map, so we will set our x and y locations to zero (which is out of bounds) and our height and width to 1. I have properly formatted the new locations for you so that you don't need to worry about it. Like before, highlight the entire structure up to the end curly brace and semicolon, and replace it by pasting what is in the spoiler below.
Code:
const struct RegionMapLocation gRegionMapLocations[] =
{
    { 4, 11, 1, 1, gMapName_LittlerootTown},
    { 4,  9, 1, 1, gMapName_OldaleTown},
    { 2, 14, 1, 1, gMapName_DewfordTown},
    { 5,  3, 1, 1, gMapName_LavaridgeTown},
    { 3,  0, 1, 1, gMapName_FallarborTown},
    { 4,  6, 1, 1, gMapName_VerdanturfTown},
    {17, 10, 1, 1, gMapName_PacifidlogTown},
    { 1,  9, 1, 1, gMapName_PetalburgCity},
    { 8, 10, 1, 2, gMapName_SlateportCity},
    { 8,  6, 2, 1, gMapName_MauvilleCity},
    { 0,  5, 1, 2, gMapName_RustboroCity},
    {12,  0, 1, 1, gMapName_FortreeCity},
    {18,  3, 2, 1, gMapName_LilycoveCity},
    {24,  5, 2, 1, gMapName_MossdeepCity},
    {21,  7, 1, 1, gMapName_SootopolisCity},
    {27,  8, 1, 2, gMapName_EverGrandeCity},
    { 4, 10, 1, 1, gMapName_Route101},
    { 2,  9, 2, 1, gMapName_Route102},
    { 4,  8, 4, 1, gMapName_Route103},
    { 0,  7, 1, 3, gMapName_Route104},
    { 0, 10, 1, 3, gMapName_Route105},
    { 0, 13, 2, 1, gMapName_Route106},
    { 3, 14, 3, 1, gMapName_Route107},
    { 6, 14, 2, 1, gMapName_Route108},
    { 8, 12, 1, 3, gMapName_Route109},
    { 8,  7, 1, 3, gMapName_Route110},
    { 8,  0, 1, 6, gMapName_Route111},
    { 6,  3, 2, 1, gMapName_Route112},
    { 4,  0, 4, 1, gMapName_Route113},
    { 1,  0, 2, 3, gMapName_Route114},
    { 0,  2, 1, 3, gMapName_Route115},
    { 1,  5, 4, 1, gMapName_Route116},
    { 5,  6, 3, 1, gMapName_Route117},
    {10,  6, 2, 1, gMapName_Route118},
    {11,  0, 1, 6, gMapName_Route119},
    {13,  0, 1, 4, gMapName_Route120},
    {14,  3, 4, 1, gMapName_Route121},
    {16,  4, 1, 2, gMapName_Route122},
    {12,  6, 5, 1, gMapName_Route123},
    {20,  3, 4, 3, gMapName_Route124},
    {24,  3, 2, 2, gMapName_Route125},
    {20,  6, 3, 3, gMapName_Route126},
    {23,  6, 3, 3, gMapName_Route127},
    {23,  9, 4, 1, gMapName_Route128},
    {24, 10, 2, 1, gMapName_Route129},
    {21, 10, 3, 1, gMapName_Route130},
    {18, 10, 3, 1, gMapName_Route131},
    {15, 10, 2, 1, gMapName_Route132},
    {12, 10, 3, 1, gMapName_Route133},
    { 9, 10, 3, 1, gMapName_Route134},
    {20,  3, 4, 3, gMapName_Underwater},
    {20,  6, 3, 3, gMapName_Underwater},
    {23,  6, 3, 3, gMapName_Underwater},
    {23,  9, 4, 1, gMapName_Underwater},
    {21,  7, 1, 1, gMapName_Underwater},
    { 1, 13, 1, 1, gMapName_GraniteCave},
    { 6,  2, 1, 1, gMapName_MtChimney},
    {16,  2, 1, 1, gMapName_SafariZone},
    {22, 12, 1, 1, gMapName_BattleTower},
    { 0,  8, 1, 1, gMapName_PetalburgWoods},
    { 2,  5, 1, 1, gMapName_RusturfTunnel},
    { 6, 14, 1, 1, gMapName_AbandonedShip},
    { 8,  7, 1, 1, gMapName_NewMauville},
    { 0,  3, 1, 1, gMapName_MeteorFalls},
    { 1,  2, 1, 1, gMapName_MeteorFalls},
    {16,  4, 1, 1, gMapName_MtPyre},
    {19,  3, 1, 1, gMapName_EvilTeamHideout},
    {24,  4, 1, 1, gMapName_ShoalCave},
    {24,  9, 1, 1, gMapName_SeafloorCavern},
    {24,  9, 1, 1, gMapName_Underwater},
    {27,  9, 1, 1, gMapName_VictoryRoad},
    {17, 10, 1, 1, gMapName_MirageIsland},
    {21,  7, 1, 1, gMapName_CaveOfOrigin},
    {12, 14, 1, 1, gMapName_SouthernIsland},
    { 6,  3, 1, 1, gMapName_FieryPath},
    { 7,  3, 1, 1, gMapName_FieryPath},
    { 6,  3, 1, 1, gMapName_JaggedPass},
    { 7,  2, 1, 1, gMapName_JaggedPass},
    {11, 10, 1, 1, gMapName_SealedChamber},
    {11, 10, 1, 1, gMapName_Underwater},
    {13,  0, 1, 1, gMapName_ScorchedSlab},
    {0,  10, 1, 1, gMapName_IslandCave},
    { 8,  3, 1, 1, gMapName_DesertRuins},
    {13,  2, 1, 1, gMapName_AncientTomb},
    { 0,  0, 1, 1, gMapName_InsideOfTruck},
    {19, 10, 1, 1, gMapName_SkyPillar},
    { 0,  0, 1, 1, gMapName_SecretBase},
    { 0,  0, 1, 1, gMapName_None},
    { 0,  0, 1, 1, gMapName_PalletTown},
    { 0,  0, 1, 1, gMapName_ViridianCity},
    { 0,  0, 1, 1, gMapName_PewterCity},
    { 0,  0, 1, 1, gMapName_CeruleanCity},
    { 0,  0, 1, 1, gMapName_LavenderTown},
    { 0,  0, 1, 1, gMapName_VermilionCity},
    { 0,  0, 1, 1, gMapName_CeladonCity},
    { 0,  0, 1, 1, gMapName_FuchsiaCity},
    { 0,  0, 1, 1, gMapName_CinnabarIsland},
    { 0,  0, 1, 1, gMapName_IndigoPlateau},
    { 0,  0, 1, 1, gMapName_SaffronCity},
    { 0,  0, 1, 1, gMapName_Route4},
    { 0,  0, 1, 1, gMapName_Route10},
    { 0,  0, 1, 1, gMapName_Route1},
    { 0,  0, 1, 1, gMapName_Route2},
    { 0,  0, 1, 1, gMapName_Route3},
    { 0,  0, 1, 1, gMapName_Route4_2},
    { 0,  0, 1, 1, gMapName_Route5},
    { 0,  0, 1, 1, gMapName_Route6},
    { 0,  0, 1, 1, gMapName_Route7},
    { 0,  0, 1, 1, gMapName_Route8},
    { 0,  0, 1, 1, gMapName_Route9},
    { 0,  0, 1, 1, gMapName_Route10_2},
    { 0,  0, 1, 1, gMapName_Route11},
    { 0,  0, 1, 1, gMapName_Route12},
    { 0,  0, 1, 1, gMapName_Route13},
    { 0,  0, 1, 1, gMapName_Route14},
    { 0,  0, 1, 1, gMapName_Route15},
    { 0,  0, 1, 1, gMapName_Route16},
    { 0,  0, 1, 1, gMapName_Route17},
    { 0,  0, 1, 1, gMapName_Route18},
    { 0,  0, 1, 1, gMapName_Route19},
    { 0,  0, 1, 1, gMapName_Route20},
    { 0,  0, 1, 1, gMapName_Route21},
    { 0,  0, 1, 1, gMapName_Route22},
    { 0,  0, 1, 1, gMapName_Route23},
    { 0,  0, 1, 1, gMapName_Route24},
    { 0,  0, 1, 1, gMapName_Route25},
    { 0,  0, 1, 1, gMapName_ViridianForest},
    { 0,  0, 1, 1, gMapName_MtMoon},
    { 0,  0, 1, 1, gMapName_SSAnne},
    { 0,  0, 1, 1, gMapName_UndergroundPath},
    { 0,  0, 1, 1, gMapName_UndergroundPath2},
    { 0,  0, 1, 1, gMapName_DiglettsCave},
    { 0,  0, 1, 1, gMapName_KantoVictoryRoad},
    { 0,  0, 1, 1, gMapName_RocketHideout},
    { 0,  0, 1, 1, gMapName_SilphCo},
    { 0,  0, 1, 1, gMapName_PokemonMansion},
    { 0,  0, 1, 1, gMapName_KantoSafariZone},
    { 0,  0, 1, 1, gMapName_PokemonLeague},
    { 0,  0, 1, 1, gMapName_RockTunnel},
    { 0,  0, 1, 1, gMapName_SeafoamIslands},
    { 0,  0, 1, 1, gMapName_PokemonTower},
    { 0,  0, 1, 1, gMapName_CeruleanCave},
    { 0,  0, 1, 1, gMapName_PowerPlant},
    { 0,  0, 1, 1, gMapName_OneIsland},
    { 0,  0, 1, 1, gMapName_TwoIsland},
    { 0,  0, 1, 1, gMapName_ThreeIsland},
    { 0,  0, 1, 1, gMapName_FourIsland},
    { 0,  0, 1, 1, gMapName_FiveIsland},
    { 0,  0, 1, 1, gMapName_SevenIsland},
    { 0,  0, 1, 1, gMapName_SixIsland},
    { 0,  0, 1, 1, gMapName_KindleRoad},
    { 0,  0, 1, 1, gMapName_TreasureBeach},
    { 0,  0, 1, 1, gMapName_CapeBrink},
    { 0,  0, 1, 1, gMapName_BondBridge},
    { 0,  0, 1, 1, gMapName_ThreeIslePort},
    { 0,  0, 1, 1, gMapName_SeviiIsle6},
    { 0,  0, 1, 1, gMapName_SeviiIsle7},
    { 0,  0, 1, 1, gMapName_SeviiIsle8},
    { 0,  0, 1, 1, gMapName_SeviiIsle9},
    { 0,  0, 1, 1, gMapName_ResortGorgeous},
    { 0,  0, 1, 1, gMapName_WaterLabyrinth},
    { 0,  0, 1, 1, gMapName_FiveIsleMeadow},
    { 0,  0, 1, 1, gMapName_MemorialPillar},
    { 0,  0, 1, 1, gMapName_OutcastIsland},
    { 0,  0, 1, 1, gMapName_GreenPath},
    { 0,  0, 1, 1, gMapName_WaterPath},
    { 0,  0, 1, 1, gMapName_RuinValley},
    { 0,  0, 1, 1, gMapName_TrainerTower},
    { 0,  0, 1, 1, gMapName_CanyonEntrance},
    { 0,  0, 1, 1, gMapName_SevaultCanyon},
    { 0,  0, 1, 1, gMapName_TanobyRuins},
    { 0,  0, 1, 1, gMapName_SeviiIsle22},
    { 0,  0, 1, 1, gMapName_SeviiIsle23},
    { 0,  0, 1, 1, gMapName_SeviiIsle24},
    { 0,  0, 1, 1, gMapName_NavelRock},
    { 0,  0, 1, 1, gMapName_MtEmber},
    { 0,  0, 1, 1, gMapName_BerryForest},
    { 0,  0, 1, 1, gMapName_IcefallCave},
    { 0,  0, 1, 1, gMapName_RocketWarehouse},
    { 0,  0, 1, 1, gMapName_TrainerTower2},
    { 0,  0, 1, 1, gMapName_DottedHole},
    { 0,  0, 1, 1, gMapName_LostCave},
    { 0,  0, 1, 1, gMapName_PatternBush},
    { 0,  0, 1, 1, gMapName_AlteringCave},
    { 0,  0, 1, 1, gMapName_TanobyChambers},
    { 0,  0, 1, 1, gMapName_ThreeIslePath},
    { 0,  0, 1, 1, gMapName_TanobyKey},
    { 0,  0, 1, 1, gMapName_BirthIsland},
    { 0,  0, 1, 1, gMapName_MoneanChamber},
    { 0,  0, 1, 1, gMapName_LiptooChamber},
    { 0,  0, 1, 1, gMapName_WeepthChamber},
    { 0,  0, 1, 1, gMapName_DilfordChamber},
    { 0,  0, 1, 1, gMapName_ScufibChamber},
    { 0,  0, 1, 1, gMapName_RixyChamber},
    { 0,  0, 1, 1, gMapName_ViapoisChamber},
    { 0,  0, 1, 1, gMapName_EmberSpa},
    { 0,  0, 1, 1, gMapName_SpecialArea},
    { 0,  0, 1, 1, gMapName_AquaHideout},
    { 0,  0, 1, 1, gMapName_MagmaHideout},
    { 0,  0, 1, 1, gMapName_MirageTower},
    { 0,  0, 1, 1, gMapName_BirthIsland},
    { 0,  0, 1, 1, gMapName_FarawayIsland},
    { 0,  0, 1, 1, gMapName_ArtisanCave},
    { 0,  0, 1, 1, gMapName_MarineCave},
    { 0,  0, 1, 1, gMapName_Underwater},
    { 0,  0, 1, 1, gMapName_TerraCave},
    { 0,  0, 1, 1, gMapName_Underwater},
    { 0,  0, 1, 1, gMapName_Underwater},
    { 0,  0, 1, 1, gMapName_Underwater},
    { 0,  0, 1, 1, gMapName_DesertUnderpass},
    { 0,  0, 1, 1, gMapName_AlteringCave},
    { 0,  0, 1, 1, gMapName_NavelRock},
    { 0,  0, 1, 1, gMapName_TrainerHill}
};

We've done it! Our new map names are in the game, associated with the correct met location indices, and the code for the summary screen has been altered so that our newly added locations show. Ruby can now display map names from all other GBA games, and even has a special message for Pokemon from Orre!

Move on to Part 2, which shows you how to make your Orre Pokemon show where they're really from, and not just, "met in a distant land."
 
Last edited:

Lunos

Well-known member
#2
Woah, this is quite impressive. The amount of modifications that have to be done for such a small detail is slightly overwhelming but I suppose that as time progresses, people will start to make forks of Pokeruby/Pokeemerald with ROM Hacking development in mind, simplifying some tasks and such. Not to mention that Pokeruby/Pokeemerald itself are still in constant development so some files and documents could be simplified, maybe.

Incredible job Deokishisu, it's amazing to see that there's people that is finally starting to do stuff with the disassembly and decompilation projects, even going as far as writing tutorials and in such a detailed way too! <3
 
OP
OP
Deokishisu

Deokishisu

Active member
#4
Does this work for pokeemerald too?
As far as I can remember, Emerald does show Kanto locations in its summary screen, so there is no need to do the extensive modification that I did here. Pokemon from Orre in Emerald display the "obtained in a trade." string, but since the summary screen in pokeemerald isn't completely decompiled, I haven't bothered to look into changing that for Emerald. It does do a gameMet check, so you could hijack that and have it print a custom string for Orre Pokemon as well. But again, I haven't looked at doing it for pokeemerald. Once it's complete enough to do substantial work on it, I'll be switching over. Most of the stuff I'm playing with in pokeruby is stuff that I can easily port to pokeemerald when the time comes.
 
#5
As far as I can remember, Emerald does show Kanto locations in its summary screen, so there is no need to do the extensive modification that I did here. Pokemon from Orre in Emerald display the "obtained in a trade." string, but since the summary screen in pokeemerald isn't completely decompiled, I haven't bothered to look into changing that for Emerald. It does do a gameMet check, so you could hijack that and have it print a custom string for Orre Pokemon as well. But again, I haven't looked at doing it for pokeemerald. Once it's complete enough to do substantial work on it, I'll be switching over. Most of the stuff I'm playing with in pokeruby is stuff that I can easily port to pokeemerald when the time comes.
Ah, okay. No worries. I’ll have a look into it myself based on what’s been spoke about on here.
 
OP
OP
Deokishisu

Deokishisu

Active member
#6
Part 2: Making Ruby Recognize Specific Orre Met Locations
Does, "met in a distant land," just not do it for you? Do you need to know exactly where you caught your Orre Pokemon? Then this is the Part 2 for you!


Yes, this is still Ruby, and yes those are actual Orre met locations!

Hey everyone! I did this a while ago but didn't have time for a writeup. I figured I'd post it while I have time now. This is going to be light on the explanation, as a lot of it is the same principles from the initial post.

Either Orre
Doing Orre met locations precisely can be an issue, because Colosseum and XD reused the same indices for locations, but had no regard for each other! A met location could mean Mt. Battle in one game, but Citadark Isle in another! This, unfortunately makes for some collisions where Pokemon have met locations that would be valid for both games. But don't worry! I've already sorted that out for you and hopefully caught all of the cases where a Pokemon could be from either Colosseum or XD from its met location.

For those curious, here are the indices which overlap, all in decimal:
67 - Laboratory in Colosseum/Cipher Key Lair in XD
69 - Laboratory in Colosseum/Cipher Key Lair in XD
76 - Mt. Battle in Colosseum/Citadark Isle in XD
109 - ReagamTwr Dome in Colosseum/Pyrite Town in XD
110 - ReagamTwr Dome in Colosseum/Pyrite Town in XD
111 - ReagamTwr Dome in Colosseum/Pyrite Town in XD
254 - Colosseum Starter Espeon and Umbreon/Colosseum Duking's Plusle
Another potential issue that needs to be worked around is the fact that Colosseum and XD both start their location indices from zero. This overlaps with the location indices from Gen 3 games, so we can't just add map names like we did in the last step and call it a day. I chose to hardcode the strings and write a few functions to make sure the correct ones were displayed and collisions were resolved.

Deciphering the Code
I will be attaching actual text files with my code in them to the end of this post so that you need not copy+paste from the post itself, but I figured I'd do a little bit of explanation. I created another .c file in pokeruby/src called orre_met_location_handler.c and wrote my three functions there, as I didn't want to clutter up pokemon_summary_screen.c. Here is the code:
Code:
#include "global.h"
#include "pokemon.h"
#include "strings2.h"
#include "constants/species.h"
#include "orre_met_location_strings.h"

u8* DetermineOrreMetLocation(struct Pokemon *);
u8* GetOrreMetLocationString(struct Pokemon *);
u8* ResolveOrreMetLocationCollision(struct Pokemon *);


u8* DetermineOrreMetLocation(struct Pokemon *mon)
{
    u8 *stringToUse;
    u8 locationMet = GetMonData(mon, MON_DATA_MET_LOCATION);
    if(locationMet == 76 || locationMet == 109 || locationMet == 110 || locationMet == 111 || locationMet == 67 || locationMet == 69 || locationMet == 0 || locationMet == 254)
    {
        stringToUse = ResolveOrreMetLocationCollision(mon);
    }
    else
    {
        stringToUse = GetOrreMetLocationString(mon);
    }
    return (u8 *)stringToUse;
}

u8* GetOrreMetLocationString(struct Pokemon *mon)
{
    u8 locationMet = GetMonData(mon, MON_DATA_MET_LOCATION);
    const u8 *locationString;
    switch (locationMet)
    {
            //valid Colosseum locations
            case 39: //only valid Agate Village location
                locationString = Agate_Village;
                break;
            case 125: //only valid Deep Colosseum location
                locationString = Deep_Colosseum;
                break;
            case 68: //only valid Laboratory location
                locationString = Laboratory;
                break;
            case 5: //only valid Mayor's House location
                locationString = Mayors_House;
                break;
            case 30: //only valid Miror's Hideout location, Remoraid and Mantine 2nd chance here or Pyrite Cave?
                locationString = Mirors_Hideout;
                break;
            case 1: //only valid Outskirt Stand location
                locationString = Outskirt_Stand;
                break;
            case 3: //only normally valid Phenac City location
            case 128: //eReader Pokemon are from here in Phenac City
                locationString = Phenac_City;
                break;
            case 25:
            case 28: //only valid Pyrite Building locations
                locationString = Pyrite_Bldg;
                break;
            case 29:
            case 31:
            case 32: //only valid Pyrite Cave locations
                locationString = Pyrite_Cave;
                break;
            case 15: //only valid Pyrite Town location
                locationString = Pyrite_Town;
                break;
            case 115:
            case 117: //valid Realgam Tower locations; see below comment
                locationString = Realgam_Tower;
                break;
            case 104:
            case 106: //Do these three display as Realgam Tower instead in game?
            case 113: //only valid RealgamTwr Dome locations
                locationString = RealgamTwr_Dome;
                break;
            case 132:
            case 133:
            case 134: //only valid Snagem Hideout locations
                locationString = Snagem_Hideout;
                break;
            case 47:
            case 55: //only valid The Under locations
                locationString = The_Under;
                break;
            case 58: //only valid The Under Subway location
                locationString = The_Under_Subway;
                break;
            case 118: //only valid Tower Colosseum location
                locationString = Tower_Colosseum;
                break;
            //valid XD locations
            case 92: //only valid Cave Poke Spot location
                locationString = Cave;
                break;
            case 64:
            case 65:
            case 66:
            case 70:
            case 71: //only valid Cipher Key Lair locations
                locationString = Cipher_Key_Lair;
                break;
            case 8:
            case 9:
            case 10:
            case 11: //only valid Cipher Lab locations
                locationString = Cipher_Lab;
                break;
            case 73:
            case 74:
            case 75:
            case 77:
            case 80:
            case 81:
            case 84:
            case 85:
            case 87:
            case 88: //only valid Citadark Isle locations
                locationString = Citadark_Isle;
                break;
            case 153:
            case 162: //only valid Gateon Port locations
                locationString = Gateon_Port;
                break;
            case 16: //only valid Mt. Battle location; gift Johto Starters
                locationString = Mt_Battle;
                break;
            case 91: //only valid Oasis Poke Spot location
                locationString = Oasis;
                break;
            case 164: //only valid Outskirt Stand location
                locationString = Outskirt_Stand;
                break;
            case 94:
            case 96:
            case 97:
            case 100:
            case 107: //only valid Phenac City locations
                locationString = Phenac_City;
                break;
            case 143: //only valid Pokemon HQ Lab location
                locationString = Pokemon_HQ_Lab;
                break;
            case 116:
            case 119: //only valid Pyrite Town locations
                locationString = Pyrite_Town;
                break;
            case 59: //only valid Realgam Tower location
                locationString = Realgam_Tower;
                break;
            case 90: //only valid Rock Poke Spot location
                locationString = Rock;
                break;
            default: //if any other location index is present, use generic distant land text.
                locationString = gOtherText_MetDistantLand;
                break;
    }
    return (u8 *)locationString;
}

u8* ResolveOrreMetLocationCollision(struct Pokemon *mon)
{
    u16 species;
    u8 locationMet;
    const u8 *locationString;
    locationMet = GetMonData(mon, MON_DATA_MET_LOCATION);
    species = GetMonData(mon, MON_DATA_SPECIES);
    switch (locationMet)
    {
        case 67:
        case 69: //Colosseum: Laboratory; XD: Cipher Key Lair
            if(species == SPECIES_PRIMEAPE || species == SPECIES_HYPNO || species == SPECIES_TANGELA || species == SPECIES_BUTTERFREE || species == SPECIES_MAGNETON)
                locationString = Cipher_Key_Lair;
            else
                locationString = Laboratory;
            break;
        case 76: //Colosseum: Mt. Battle; XD: Citadark Isle
            if(species == SPECIES_ENTEI)
                locationString = Mt_Battle;
            else
                locationString = Citadark_Isle;
            break;
        case 109:
        case 110:
        case 111: //Colosseum: RealgamTwr Dome; XD: Pyrite Town
            if(species == SPECIES_SUNFLORA || species == SPECIES_DELIBIRD || species == SPECIES_SUICUNE || species == SPECIES_HERACROSS)
                locationString = RealgamTwr_Dome;
            else
                locationString = Pyrite_Town;
            break;
        case 0: //XD Starter Eevee
            if((species >= SPECIES_EEVEE && species <= SPECIES_FLAREON) || species == SPECIES_ESPEON || species == SPECIES_UMBREON)
                locationString = XD_Eevee_Met_Location;
            break;
        case 254: //Colosseum Starter Espeon and Umbreon and Duking's Plusle
            if(species == SPECIES_ESPEON || species == SPECIES_UMBREON)
                locationString = Colosseum_Starter_Met_Location;
            else
                locationString = Dukings_Plusle;
            break;
        default: //error handler; default to generic distant land text
            locationString = gOtherText_MetDistantLand;
            break;
    }
    return (u8 *)locationString;
}
I want to give a very brief overview of what it's doing for you all so that there's some basic understanding of what my code does.

The very first function, DetermineOrreMetLocation, is called by pokemon_summary_screen.c (whose changes I will also explain further down) once it sees that a Pokemon was from Colosseum or XD (that is, after it finds that gameMet == 15. Remember that change from Part 1?). DetermineOrreMetLocation sets up a pointer to a string and then specifically checks for the locationMet values that are valid for both Colosseum and XD. If it finds one, it calls ResolveOrreMetLocationCollision and gets the correct address for stringToUse from that function. If it's not a locationMet value that is valid for both games (that is, only one game uses that value for a valid met location), it calls GetOrreMetLocation and receives the correct address for stringToUse from that function instead. Then, DetermineOrreMetLocation returns the string pointer so that pokemon_summary_screen.c can use it to print the correct string on the summary screen.

GetOrreMetLocation is the function for non-collisions. It is literally a big switch statement that checks the met location value and assigns the corresponding string's address to a string pointer and then returns that pointer.

ResolveOrreMetLocationCollision is only slightly more complicated. It is a similar switch statement, but inside each case is an if statement that checks specific species that are only valid in one game or the other. For example, if the Pokemon in question is an Entei that has a value of 76 as its met location, then it must be from Mt. Battle (as 76 is the index for Mt. Battle in Colosseum), as it is the only valid Pokemon from Colosseum with that value. Any other Pokemon with the value of 76 would necessarily be an XD Pokemon, and thus be from Citadark Isle, which is what location index 76 corresponds to in XD. This function also handles the starter Eeveelutions and Duking's Plusle.

Both of the aforementioned functions will print "met in a distant land," as an error handler. As an aside, if you have a legal Colosseum or XD Pokemon that prints that, please let me know so I can fix it! I may not have caught all of the valid second chance locations in Colosseum, and actually fixed a few missing ones while testing.

Now you may be wondering, "we're referencing strings in this file, where are they?" I have added an extra file in pokeruby/data/ called orre_met_locations_strings.s as well as a corresponding header file in pokeruby/include/ called orre_met_locations_strings.h. They will be attached at the bottom of the post. They're literally just text, so there's no real need to explain the files themselves here. However, you will need to add these files to the ld_script.txt file so that the linker knows to put them in! I will not be providing my ld_script.txt in the attachments, so pay attention here!

Adding files to the ld_script.txt file is easy to do. First off, locate the file. It's in the root directory, so pokeruby/ld_script.txt. For this specific implementation, add the line
Code:
src/orre_met_location_handler.o(.text);
to the .text section. That starts on line 37 of the unmodified file I just threw mine at the end, after everything else. Great! Our new .c file can be found by the linker now! Now, we need to add in the strings we wrote. Strings and other read-only data goes into the aptly named .rodata section, which starts on line 483 of the unmodified file. Here's the line you would have to insert for my implementation:
Code:
data/orre_met_location_strings.o(.rodata);
Again, I appended mine to the end. That's all for the linker file! Now the linker knows to include our new files into the ROM when we compile. Anytime you add a new file to pokeruby, you will need to go through a similar process, so keep that in mind as you start your own C projects!

Returning to the Summary Screen
Now, all this is well and good, but we still haven't modified the pokemon_summary_screen.c file to do anything with our new functions or strings. We need to make a few changes and rewrite a part of a function to accommodate for our snazzy new functionality. I will not be including my entire pokemon_summary_screen.c file with the other attachments, because I don't want people blindly copy-pasting a huge, vital file and possibly messing up any of the changes they might have already made to it, so pay attention here! First off, add the line
Code:
#include "orre_met_location_strings.h"
to the very top of our file. Then, extern our DetermineOrreMetLocation function near the top of the file with the others. I put mine on line 157, as the last function declared as extern. The added line should look like this:
Code:
extern u8* DetermineOrreMetLocation(struct Pokemon *);
Then, at the top of the PokemonSummaryScreen_PrintTrainerMemo function which is on line 3031 in an unmodified file, we need to declare some new variables with the others. After the line where they declare and initialize the nature variable, add in
Code:
u8 nature = GetNature(mon); //this is already there, put your new variables after this
u8 *orreMetLocationString; //receives the string pointer returned from DetermineOrreMetLocation
u16 species; //needed to check for starter Eeveelutions and Plusle, which are special cases
Great! So now we need to head back to that check that we repurposed from Part 1 that now checks if a Pokemon is from Colosseum and XD. In an unmodified file, that check is on line 3087. This is where the magic happens. Here's the modified code, starting with that if statement that we changed to check for Orre Pokemon:
Code:
if (gameMet == 15) //generated by Colosseum or XD: Gales of Darkness
{
            u8 levelMet = GetMonData(mon, MON_DATA_MET_LEVEL);

            ptr = PokemonSummaryScreen_CopyPokemonLevel(ptr, levelMet);
            *ptr = CHAR_NEWLINE;
            ptr++;

            orreMetLocationString = DetermineOrreMetLocation(mon);
            GetMonData(mon, MON_DATA_OT_NAME, gStringVar2); //used for Eeveelution strings and Duking's Plusle
            species = GetMonData(mon, MON_DATA_SPECIES);
            if((species >= SPECIES_EEVEE && species <= SPECIES_FLAREON) || species == SPECIES_ESPEON || species == SPECIES_UMBREON || species == SPECIES_PLUSLE)
            {
                StringCopy(ptr, orreMetLocationString);
            }
            else
            {
                ptr = sub_80A1E9C(ptr, orreMetLocationString, 14);
                StringCopy(ptr, gOtherText_Met);
            }
}
Yes! We call our DetermineOrreMetLocation function, passing in the Pokemon we're looking at as an argument, and it returns the string to the orreMetLocationString variable that we declared higher up. Next, we grab the OT name of the Pokemon and put it in a string buffer, as we will need it for the starter Eeveelutions and Duking's Plusle. Next, we grab the Pokemon's species, as that will be used to check for the aforementioned starter Eeveelutions and Duking's Plusle. They are special-cased here so that their text is printed in black instead of red like for other met locations, and it doesn't include "(met)" at the end. Next (within the if and else statements), the strings are printed to the summary screen and viewable!

But, we're not done yet. For most situations, these strings print perfectly fine, but the string for the XD Starter Eeveelution is just a tad longer than what the game normally expects to be there because of the variable length of the player's OT name. By a tad, I mean that at the max OT name length, the string is literally two pixels too wide. You may be thinking that the string will stretch out past the box and look unsightly if this is the case, but it looks perfectly normal. In fact, you can check for yourself. Scroll up to the screenshot on the top of this post. That Jolteon's met location is actually at the maximum width of the string in the window! The summary screen doesn't clear the actual screen past a certain width, so we will have to do the tiniest bit of tinkering so that it does. This has no side effects, so don't worry about what we're doing here.

The name of this function will definitely change as the decomps get better documentation, but on line 2523 in an unmodified pokemon_summary_screen.c file is the function that is named (at the time of this writing) sub_809FE80. This is the function responsible for clearing the main page of the summary screen when switching between Pokemon. We just need to make it clear a few more pixels on the bottom. Here's the original function:
Code:
static void sub_809FE80(void)
{
    Menu_EraseWindowRect(14, 4, 18, 5);
    Menu_EraseWindowRect(25, 4, 30, 5);
    Menu_EraseWindowRect(11, 9, 28, 12);
    Menu_EraseWindowRect(11, 14, 28, 17);
}
You see that last line there? We need to change those values to make it clear out our slightly longer string. Change it from "Menu_EraseWindowRect(11, 14, 28, 17);" to "Menu_EraseWindowRect(11, 14, 29, 19);" and the summary screen will now erase those extra two pixels of width for us!

Do you feel accomplished? Because you should! We're all done and now Pokemon will correctly display their exact Orre met locations in the summary screen! If you've followed these two posts, your Pokemon Ruby ROM now supports all valid met locations from Generation III.

When you add these files into your own repositories, remember that the instructions here are name-sensitive. That is, if you rename anything in any of these, you will need to go through everything and make sure that all of the modified files are referencing that new name. This is just something to keep in mind if you plan on relabeling any of the files, functions, or strings.

And again, if you have a legal Colosseum or XD Pokemon that prints "met in a distant land," as its met location or prints an incorrect location in the summary screen , please let me know so I can fix it! I may not have caught all of the valid second chance locations in Colosseum. If you could send me the .sav file with the offending Pokemon in it and let me know which Pokemon you're talking about, I'll update this ASAP to include it. Thank you, and good luck!
 

Attachments

Last edited:
OP
OP
Deokishisu

Deokishisu

Active member
#8
You may also want to add a case where if a Pokémon is obtained from Emerald, the Battle Tower location gets read as Battle Frontier.
That's a great idea, but it's such a simple change (if you don't want to get fancy, check below) that I'd be okay leaving it out from the tutorial for now. People should be able to do that fairly easily with the information I've already provided.

However, there is an issue. gameMet is read from the game origin field of a Pokemon's data structure. Game origin is set when a Pokemon is initially generated and never changes. So yeah, Pokemon you fish up or surf to get in the Battle Frontier would benefit from this additional if statement, but what if I bred a Pokemon in RSFRLG, traded it to Emerald, and then hatched it in the Battle Frontier? Suddenly we have a Pokemon with game origin of RSFRLG with the Battle Frontier as its actual met location but it prints Battle Tower instead. It would be very difficult to make a check that is accurate because of this. You could specifically check the met level to see if it was hatched, but you can never know what game it was actually hatched in (which is the real issue here) because Game Origin is never overwritten. You can have an Emerald Pokemon from the Battle Tower, a Ruby Pokemon from the Battle Frontier, etc.

Basically, you could ensure that Pokemon encountered in Emerald in the Battle Frontier show the right location with a (not very) complicated if statement making sure that they weren't hatched, but you could never tell whether an Egg hatched in the Battle Tower or the Battle Frontier. In this case, I would probably just do what the official games do and have it print Battle Tower when viewed in RSFRLG and Battle Frontier when viewed in Emerald.

EDIT: Upon further inspection, the only Pokemon that one can catch in the actual Battle Frontier without cheating is the level 40 Sudowoodo. The water is empty. The if statement would check for that Sudowoodo specifically at that met level and location from Emerald. Eggs would still be impossible to determine. If you're thinking, "What about Smeargle and the trade Skitty?" Smeargle is actually in Artisan Cave, and the Skitty will always print that it's from an ingame trade.
 
Last edited:
#9
That's a great idea, but it's such a simple change (if you don't want to get fancy, check below) that I'd be okay leaving it out from the tutorial for now. People should be able to do that fairly easily with the information I've already provided.

However, there is an issue. gameMet is read from the Game Origin field of a Pokemon's data structure. Game Origin is set when a Pokemon is initially generated and never changes. So yeah, Pokemon you fish up or surf to get in the Battle Frontier would benefit from this additional if statement, but what if I bred a Pokemon in RSFRLG, traded it to Emerald, and then hatched it in the Battle Frontier? Suddenly we have a Pokemon with Game Origin of RSFRLG with the Battle Frontier as its actual met location but it prints Battle Tower instead. It would be very difficult to make a check that is accurate because of this. You could specifically check the met level to see if it was hatched, but you can never know what game it was actually hatched in (which is the real issue here) because Game Origin is never overwritten. You can have an Emerald Pokemon from the Battle Tower, a Ruby Pokemon from the Battle Frontier, etc.

Basically, you could ensure that Pokemon encountered in Emerald in the Battle Frontier show the right location with a (not very) complicated if statement making sure that they weren't hatched, but you could never tell whether an Egg hatched in the Battle Tower or the Battle Frontier. In this case, I would probably just do what the official games do and have it print Battle Tower when viewed in RSFRLG and Battle Frontier when viewed in Emerald.

EDIT: Upon further inspection, the only Pokemon that one can catch in the actual Battle Frontier without cheating is the level 40 Sudowoodo. The water is empty. The if statement would check for that Sudowoodo specifically at that met level and location from Emerald. Eggs would still be impossible to determine. If you're thinking, "What about Smeargle and the trade Skitty?" Smeargle is actually in Artisan Cave, and the Skitty will always print that it's from an ingame trade.
Actually, once the egg hatches, the origin game of the Pokémon will be that of the game it hatched in, not the game where the egg was obtained.
And when you trade the unhatched egg to another game, the game will display the message, 'egg obtained in a link trade' or something similar.
 
OP
OP
Deokishisu

Deokishisu

Active member
#10
Actually, once the egg hatches, the origin game of the Pokémon will be that of the game it hatched in, not the game where the egg was obtained.
And when you trade the unhatched egg to another game, the game will display the message, 'egg obtained in a link trade' or something similar.
Actually it doesn't. The met location will be written as the location it hatched in in the new game, but internally its game origin will be the game it was generated in. In normal gameplay, you can see this most prominently when migrating Pokemon to Gen IV. If you bred a Pokemon in FRLG, traded it to RSE to hatch it, and then migrated it up to Gen IV, it will say that it is from Kanto and not from Hoenn because it is reading the game origin and not the met location. The game origin is never changed once a Pokemon in generated.

Bulbapedia said:
A Pokémon whose Egg is created in a game based in one region and traded to another region before it was hatched will display the name of the region it was generated in, rather than the one it was hatched in; this means that a Pokémon generated in Emerald but hatched in FireRed will have the OT and ID of the FireRed player but list that it was met in Hoenn.
Go ahead and cheat in an egg whose game origin is set to some other game, hatch it, and check it again. You will see that it doesn't change.
 
#11
Actually it doesn't. The met location will be written as the location it hatched in in the new game, but internally its game origin will be the game it was generated in. In normal gameplay, you can see this most prominently when migrating Pokemon to Gen IV. If you bred a Pokemon in FRLG, traded it to RSE to hatch it, and then migrated it up to Gen IV, it will say that it is from Kanto and not from Hoenn because it is reading the game origin and not the met location. The game origin is never changed once a Pokemon in generated.



Go ahead and cheat in an egg whose game origin is set to some other game, hatch it, and check it again. You will see that it doesn't change.
Then couldn’t you do it so another check is in place for the player? So if the egg hatched at the Battle Frontier on a save generated from Emerald, it would read the location as Battle Frontier?
 
OP
OP
Deokishisu

Deokishisu

Active member
#12
Then couldn’t you do it so another check is in place for the player? So if the egg hatched at the Battle Frontier on a save generated from Emerald, it would read the location as Battle Frontier?
I could definitely check to see if the Pokemon has the Player's OT and other identifying information to help with printing the correct string for the correct game (obviously, if it has the player's OT and this is a Ruby game, the Pokemon was hatched at the Battle Tower regardless of its game origin), but again that only works for player owned Pokemon. Other Pokemon traded in from other OTs would be a tossup. There's nothing in the Pokemon data structure that shows "from an Emerald save," or "from a Firered save," only the game it was generated in. Similarly, nothing about the OT's game is saved in the Pokemon data structure either. There's simply no way to tell which string to print for Pokemon that are from the Battle Tower/Battle Frontier that will be 100% accurate for all Pokemon. The best that can be done is to special-case Sudowoodo and Pokemon matching the player's OT, and then guess for the rest.

A similar issue occurs in Gen 5. Pokemon from Cold Storage show up as being from the PWT when traded from BW to B2W2 and vice-versa, as they share the same location index. If they wanted to do something similar to what we're going for here and print the correct string, hatching a traded Egg in either location would create the same issue we're having in regards to game origin. There'd be no way to tell whether the Egg was actually hatched in the PWT or Cold Storage because they share the same index and game origin doesn't say anything about the game it was hatched in.