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](../blob/master/include/pokemon.h): ```c u16 MonTryLearningNewMoveEvolution(struct Pokemon *mon, bool8 firstMove); ``` Next, we will write the function itself. Add a new function in [src/pokemon.c](../blob/master/src/pokemon.c): ```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](../blob/master/src/evolution_scene.c). Edit `Task_EvolutionScene` of [src/evolution_scene.c](../blob/master/src/evolution_scene.c): ```diff 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](../blob/master/src/evolution_scene.c): ```diff 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](../blob/master/src/pokemon.c): ```diff 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](../blob/master/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: ```c 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!