-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Make Move Relearner Teach Egg Moves With A Flag
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!
- Rename unused flag
- Change static function and GetEggMoves
- Declare GetEggMoves
- Edit move learner functionality
- Exclude invalid Pokémon from list
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.
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.
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
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++)
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.