Skip to content

Make Move Relearner Teach Egg Moves With A Flag

Scyrous edited this page Aug 11, 2024 · 9 revisions

Credits: Scyrous, Yak Attack, Kurausukun, Zatsu

In this guide, we will demonstrate how to modify the Move Relearner in Pokémon Emerald to teach egg moves instead of level-up moves. By setting a specific flag before executing the special command, we can temporarily alter the Move Relearner's functionality. This modification will allow egg moves to be taught to all Pokémon within the same evolution family, not just the base form. For instance, Charmander's egg moves can also be taught to Charmeleon and Charizard. Let's get started!

Contents

  1. Rename unused flag
  2. Change static function and GetEggMoves
  3. Declare GetEggMoves
  4. Edit move learner functionality
  5. Exclude invalid Pokémon from list

1. Rename unused flag

Edit include/constants/flags.h:

 #define FLAG_TEMP_1F     (TEMP_FLAGS_START + 0x1F)
 #define TEMP_FLAGS_END   FLAG_TEMP_1F
 #define NUM_TEMP_FLAGS   (TEMP_FLAGS_END - TEMP_FLAGS_START + 1)

-#define FLAG_UNUSED_0x020    0x20 // Unused Flag
+#define FLAG_EGG_MOVES_TUTOR 0x20 // Enable egg moves tutor
 #define FLAG_UNUSED_0x021    0x21 // Unused Flag
 #define FLAG_UNUSED_0x022    0x22 // Unused Flag

Naturally, you can use any flag you want here. Just make sure it's unused and you're good to go.


2. Change static function and GetEggMoves

We want to use GetEggMoves in an upcoming step, but the function is a static one. This means it's only accessible within the file it's defined in (src/daycare.c). We'll remove the static part so that it can be used anywhere, and also make it so that egg moves already learned are excluded from the list.

Edit src/daycare.c:

 // Counts the number of egg moves a Pokémon learns and stores the moves in
 // the given array.
-static u8 GetEggMoves(struct Pokemon *pokemon, u16 *eggMoves)
+u8 GetEggMoves(struct Pokemon *pokemon, u16 *eggMoves)
{
+    u16 learnedMoves[MAX_MON_MOVES];
     u16 eggMoveIdx;
     u16 numEggMoves;
     u16 species;
-    u16 i;
+    u16 i, j, k;

     numEggMoves = 0;
     eggMoveIdx = 0;
-    species = GetMonData(pokemon, MON_DATA_SPECIES);
+    species = GetEggSpecies(GetMonData(pokemon, MON_DATA_SPECIES));

     for (i = 0; i < ARRAY_COUNT(gEggMoves) - 1; i++)
     {
         if (gEggMoves[i] == species + EGG_MOVES_SPECIES_OFFSET)
         {
             eggMoveIdx = i + 1;
             break;
         }
     }

+    if (FlagGet(FLAG_EGG_MOVES_TUTOR))
+    {
+        for (i = 0; i < MAX_MON_MOVES; i++)
+            learnedMoves[i] = GetMonData(pokemon, MON_DATA_MOVE1 + i, 0);
+    }
+
     for (i = 0; i < EGG_MOVES_ARRAY_COUNT; i++)
     {
-        if (gEggMoves[eggMoveIdx + i] > EGG_MOVES_SPECIES_OFFSET)
+        u16 eggMoveId = gEggMoves[eggMoveIdx + i];
+
+        if (eggMoveId > EGG_MOVES_SPECIES_OFFSET)
            break;

-        eggMoves[i] = gEggMoves[eggMoveIdx + i];
-        numEggMoves++;
+        if (FlagGet(FLAG_EGG_MOVES_TUTOR))
+        {
+            for (j = 0; j < MAX_MON_MOVES && learnedMoves[j] != eggMoveId; j++);
+
+            if (j == MAX_MON_MOVES)
+            {
+                for (k = 0; k < numEggMoves && eggMoves[k] != eggMoveId; k++);
+
+                if (k == numEggMoves)
+                    eggMoves[numEggMoves++] = eggMoveId;
+            }
+        }
+        else
+        {
+            for (k = 0; k < numEggMoves && eggMoves[k] != eggMoveId; k++);
+
+            if (k == numEggMoves)
+                eggMoves[numEggMoves++] = eggMoveId;
+        }
     }
 
     return numEggMoves;
 }

We have now made it so that species looks at the evolutionary family as a whole, rather than individual Pokémon. Additionally, egg moves already learned by the chosen Pokemon are now excluded from the list.


3. Declare GetEggMoves

Since we've just removed the static part from GetEggMoves in the previous step, we now need to declare this function in the appropriate header file.

Edit include/daycare.h:

 void ShowDaycareLevelMenu(void);
 void ChooseSendDaycareMon(void);
+u8 GetEggMoves(struct Pokemon *pokemon, u16 *eggMoves);

 #endif // GUARD_DAYCARE_H

4. Edit move learner functionality

To enable the use of GetEggMoves within src/move_relearner.c, we have to include the relevant header file somewhere at the top of src/move_relearner.c.

Edit src/move_relearner.c:

 #include "constants/rgb.h"
 #include "constants/songs.h"
+#include "daycare.h"

 /*
  * Move relearner state machine

We will also create an if/else statement that uses our renamed flag. If the flag is set, GetEggMoves is used to obtain the list of egg moves. If the flag is cleared, we stick to the original line that uses GetMoveRelearnerMoves.

 static void CreateLearnableMovesList(void)
 {
     s32 i;
     u8 nickname[POKEMON_NAME_LENGTH + 1];

-    sMoveRelearnerStruct->numMenuChoices = GetMoveRelearnerMoves(&gPlayerParty[sMoveRelearnerStruct->partyMon], sMoveRelearnerStruct->movesToLearn);
+    if (FlagGet(FLAG_EGG_MOVES_TUTOR))
+        sMoveRelearnerStruct->numMenuChoices = GetEggMoves(&gPlayerParty[sMoveRelearnerStruct->partyMon], sMoveRelearnerStruct->movesToLearn);
+    else
+        sMoveRelearnerStruct->numMenuChoices = GetMoveRelearnerMoves(&gPlayerParty[sMoveRelearnerStruct->partyMon], sMoveRelearnerStruct->movesToLearn);

     for (i = 0; i < sMoveRelearnerStruct->numMenuChoices; i++)

5. Exclude invalid Pokémon from list

Now for a little bit of extra polish! Plenty of Pokémon are unable to learn any egg moves. This applies to egg groups DITTO, NO_EGGS_DISCOVERED and genderless Pokémon. Furthermore, we need to ensure Pokémon who have already learned every available egg move are unable to be selected from the party screen, similar to how the original move tutor works.

Edit src\pokemon.c:

Since we want to use GetEggMoves for this edit, we'll need to include daycare.h.

 #include "constants/trainers.h"
 #include "constants/union_room.h"
+#include "daycare.h"

 #define DAY_EVO_HOUR_BEGIN       12
 #define DAY_EVO_HOUR_END         HOURS_PER_DAY

By checking for numEggMoves == 0, we target any Pokémon that meet the criteria mentioned earlier.

u8 GetNumberOfRelearnableMoves(struct Pokemon *mon)
{
     u16 learnedMoves[MAX_MON_MOVES];
     u16 moves[MAX_LEVEL_UP_MOVES];
+    u16 eggMoves[EGG_MOVES_ARRAY_COUNT];
     u8 numMoves = 0;
+    u8 numEggMoves;
     u16 species = GetMonData(mon, MON_DATA_SPECIES_OR_EGG, 0);
     u8 level = GetMonData(mon, MON_DATA_LEVEL, 0);
     int i, j, k;

+    if (FlagGet(FLAG_EGG_MOVES_TUTOR))
+    {
+        numEggMoves = GetEggMoves(mon, eggMoves);
+
+        if (numEggMoves == 0)
+            return 0;
+    }
+
     if (species == SPECIES_EGG)
         return 0;

Lastly, we need to include an additional check for low-level Pokémon at the end of the function. These Pokémon cannot yet learn any moves from the regular move tutor, but should have access to egg moves.

         }
     }
 
+    if (numMoves == 0 && numEggMoves > 0 && FlagGet(FLAG_EGG_MOVES_TUTOR))
+       return numEggMoves;
+
     return numMoves;
 }

If a Pokémon's egg move list is empty, the game will now correctly display "NOT ABLE!" in the party selection screen.


To enable this functionality in-game, simply use setflag FLAG_EGG_MOVES_TUTOR before the relevant special commands are used. Naturally, make sure to use clearflag FLAG_EGG_MOVES_TUTOR before the end of any move relearner scripts.

And that's it! Happy move learning.

Clone this wiki locally