Credit to Zeturic and UltimaSoul for this feature, and to ExpoSeed and Lunos for modifying it.
Note: this feature as written is not compatible with DizzyEgg's battle_engine_v2.
This tutorial will allow Pokemon to learn moves immediately after evolving, like in Gen 7. This is useful because it avoids a situation where a Pokemon (like Feebas) has no useful or damaging moves because it evolved slightly too late.
We will implement this by writing a new function to handle learning a new move on evolution. Declare a new function in include/pokemon.h:
u16 MonTryLearningNewMoveEvolution(struct Pokemon *mon, bool8 firstMove);
Next, we will write the function itself. Add a new function in src/pokemon.c:
u16 MonTryLearningNewMoveEvolution(struct Pokemon *mon, bool8 firstMove)
{
u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL);
u8 level = GetMonData(mon, MON_DATA_LEVEL, NULL);
// since you can learn more than one move per level
// the game needs to know whether you decided to
// learn it or keep the old set to avoid asking
// you to learn the same move over and over again
if (firstMove)
{
sLearningMoveTableID = 0;
}
while(gLevelUpLearnsets[species][sLearningMoveTableID] != LEVEL_UP_END)
{
u16 moveLevel;
moveLevel = (gLevelUpLearnsets[species][sLearningMoveTableID] & LEVEL_UP_MOVE_LV);
while (moveLevel == 0 || moveLevel == (level << 9))
{
gMoveToLearn = (gLevelUpLearnsets[species][sLearningMoveTableID] & LEVEL_UP_MOVE_ID);
sLearningMoveTableID++;
return GiveMoveToMon(mon, gMoveToLearn);
}
sLearningMoveTableID++;
}
return 0;
}
This iterates through the mon's level up learnset and attempts to teach all the moves that are either level 0 or the same level as the mon.
Next, we need to call our new function. The two times the normal MonTryLearningNewMove
function is called are in src/evolution_scene.c.
Edit Task_EvolutionScene
of src/evolution_scene.c:
case 15: // check if it wants to learn a new move
if (!IsTextPrinterActive(0))
{
- var = MonTryLearningNewMove(mon, gTasks[taskID].tLearnsFirstMove);
+ var = MonTryLearningNewMoveEvolution(mon, gTasks[taskID].tLearnsFirstMove);
if (var != 0 && !gTasks[taskID].tEvoWasStopped)
{
u8 text[20];
if (!(gTasks[taskID].tBits & TASK_BIT_LEARN_MOVE))
{
StopMapMusic();
Overworld_PlaySpecialMapMusic();
}
gTasks[taskID].tBits |= TASK_BIT_LEARN_MOVE;
gTasks[taskID].tLearnsFirstMove = FALSE;
gTasks[taskID].tLearnMoveState = 0;
GetMonData(mon, MON_DATA_NICKNAME, text);
StringCopy10(gBattleTextBuff1, text);
if (var == MON_HAS_MAX_MOVES)
gTasks[taskID].tState = 22;
else if (var == MON_ALREADY_KNOWS_MOVE)
break;
else
gTasks[taskID].tState = 20; // move has been learned
}
else // no move to learn
{
BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 0x10, RGB_BLACK);
gTasks[taskID].tState++;
}
}
break;
And edit Task_TradeEvolutionScene
of src/evolution_scene.c:
case 13:
if (!IsTextPrinterActive(0) && IsFanfareTaskInactive() == TRUE)
{
- var = MonTryLearningNewMove(mon, gTasks[taskID].tLearnsFirstMove);
+ var = MonTryLearningNewMoveEvolution(mon, gTasks[taskID].tLearnsFirstMove);
if (var != 0 && !gTasks[taskID].tEvoWasStopped)
{
u8 text[20];
gTasks[taskID].tBits |= TASK_BIT_LEARN_MOVE;
gTasks[taskID].tLearnsFirstMove = FALSE;
gTasks[taskID].tLearnMoveState = 0;
GetMonData(mon, MON_DATA_NICKNAME, text);
StringCopy10(gBattleTextBuff1, text);
if (var == MON_HAS_MAX_MOVES)
gTasks[taskID].tState = 20;
else if (var == MON_ALREADY_KNOWS_MOVE)
break;
else
gTasks[taskID].tState = 18;
}
else
{
PlayBGM(MUS_SHINKA);
DrawTextOnTradeWindow(0, gText_CommunicationStandby5, 1);
gTasks[taskID].tState++;
}
}
break;
We also need to fix the generation of moves when a mon is initially created. Otherwise, new mons will start with their level 0 moves learned. To fix this, edit src/pokemon.c:
void GiveBoxMonInitialMoveset(struct BoxPokemon *boxMon)
{
u16 species = GetBoxMonData(boxMon, MON_DATA_SPECIES, NULL);
s32 level = GetLevelFromBoxMonExp(boxMon);
s32 i;
for (i = 0; gLevelUpLearnsets[species][i] != LEVEL_UP_END; i++)
{
u16 moveLevel;
u16 move;
moveLevel = (gLevelUpLearnsets[species][i] & LEVEL_UP_MOVE_LV);
+ if (moveLevel == 0)
+ continue;
if (moveLevel > (level << 9))
break;
move = (gLevelUpLearnsets[species][i] & LEVEL_UP_MOVE_ID);
if (GiveMoveToBoxMon(boxMon, move) == MON_HAS_MAX_MOVES)
DeleteFirstMoveAndGiveMoveToBoxMon(boxMon, move);
}
}
Finally, we need to actually give our mons evolution moves. This info can be found in src/data/pokemon/level_up_learnsets.h. The moves need to be at the beginning of the list and at level 0. Here is an example of what this looks like:
static const u16 sMarshtompLevelUpLearnset[] = {
LEVEL_UP_MOVE( 0, MOVE_MUD_SHOT),
LEVEL_UP_MOVE( 1, MOVE_MUD_SHOT),
LEVEL_UP_MOVE( 1, MOVE_TACKLE),
LEVEL_UP_MOVE( 1, MOVE_GROWL),
LEVEL_UP_MOVE( 1, MOVE_WATER_GUN),
LEVEL_UP_MOVE( 1, MOVE_MUD_SLAP),
LEVEL_UP_MOVE( 4, MOVE_WATER_GUN),
LEVEL_UP_MOVE( 9, MOVE_MUD_SLAP),
LEVEL_UP_MOVE(12, MOVE_FORESIGHT),
LEVEL_UP_MOVE(18, MOVE_BIDE),
LEVEL_UP_MOVE(22, MOVE_MUD_BOMB),
LEVEL_UP_MOVE(28, MOVE_ROCK_SLIDE),
LEVEL_UP_MOVE(32, MOVE_PROTECT),
LEVEL_UP_MOVE(38, MOVE_MUDDY_WATER),
LEVEL_UP_MOVE(42, MOVE_TAKE_DOWN),
LEVEL_UP_MOVE(48, MOVE_EARTHQUAKE),
LEVEL_UP_MOVE(52, MOVE_ENDEAVOR),
LEVEL_UP_END
};
And that's it!