Skip to content

New Evolution Methods

judicornadamsfoster edited this page Jun 21, 2026 · 10 revisions

New Evolution Methods

updates:

  • 7th June - EVO_LEVEL_RAIN
  • 17th June - EVO_LEVEL_NATURE_AMPED & EVO_LEVEL_NATURE_LOW_KEY
  • 21st June - EVO_BY_ITEM_COUNT

-- part of this guide comes from The Law's PokeCommunity post
-- for scripted evolution, see Anon822's PokeCommunity post
(example: Eevee evolves into Leafeon when you interact with a Moss Stone object in Petalburg Woods)
-- for AsparagusEduardo's Branched Alolan Evolution, see here or exact commit here

Want to add different ways for Pokemon to evolve from later gens?
Want to change the times of the day that evolution can happen?
Want to evolve Pikachu into Alolan Raichu but still have the option for it evolve into Kantonian Raichu?

Bulbasaur evolving when holding a Potion Bulbasaur not evolving when not holding a Potion Charmander evolving if leveled up in Littleroot Town

New Evolution Methods

  • Evolving when it knows a specific move (like Lickitung into Lickililly) or move type (Eevee into Sylveon)
  • Reach a specific level if male or female (like Salandit only evolving if its female)
  • Reach a specified level at a specific time of day (all day, morning, night or dusk)
  • Level up while holding a specific item at day or night
  • Reaching a specified level or using an evo stone while holding a specific item
  • Level up with a specific Pokemon in the party (like Mantyke and Remoraid)
  • Use an evo stone on a specific gender
  • Pokemon evolve into their Alolan form by leveling up or using an evo stone while holding the Strange Souvenir item
  • Location-based evolution (like Magneton evolving into Magnezone at Mt Coronet)

Times of the day for specific evolutions to take place can be adjusted using the #defines in src/pokemon.c

note: you will need to manually add the ITEM_STRANGE_SOUVENIR item into your hack
or see AsparagusEduardo's Branched Alolan Evolution here or exact commit here


Block Evolution From Happening

  • Bulbasaur not evolving on level up

If you want to block evolution (for example as part of an event or challenge):

in file include/constants/flags.h

replace an existing unused flag with

#define FLAG_BLOCK_EVOLUTION

in file src/pokemon.c, in section u16 GetEvolutionTargetSpecies(struct Pokemon *mon, u8 mode, u16 evolutionItem) after section

     if (heldItem == ITEM_ENIGMA_BERRY)
         holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect;
     else
         holdEffect = GetItemHoldEffect(heldItem);

add

	#ifdef FLAG_BLOCK_EVOLUTION
		// prevent evolution with a flag
        if(FlagGet(FLAG_BLOCK_EVOLUTION))
            return SPECIES_NONE;
	#else
	#endif

Now when the flag is set, no Pokemon can evolve.

note: this is already included in the code below


include/constants/pokemon.h

note: if you already have any new evolution modes, increase the numbers below to +1 higher than the last #define

in evolution method section, add after #define EVO_BEAUTY

// new evo methods
#define EVO_LEVEL_MALE           16 // reach specified level, is male
#define EVO_LEVEL_FEMALE         17 // reach specified level, is female
#define EVO_LEVEL_MALE_MORNING   18 // reach specified level, is male, is morning
#define EVO_LEVEL_FEMALE_MORNING 19 // reach specified level, is female, is morning
#define EVO_LEVEL_DAY            20 // reach specified level, is day
#define EVO_LEVEL_NIGHT          21 // reach specified level, is night
#define EVO_LEVEL_MORNING        22 // reach specified level, is morning
#define EVO_LEVEL_DUSK           23 // reach specified level, is dusk
#define EVO_HOLD_ITEM            24 // level up, hold specified item
#define EVO_HOLD_ITEM_DAY        25 // level up, hold specified item at day
#define EVO_HOLD_ITEM_NIGHT      26 // level up, hold specified item at night
#define EVO_MOVE                 27 // level up, knows specific move
#define EVO_MOVE_TYPE            28 // level up, knows move of specific type
#define EVO_LEVEL_HOLD_ITEM      29 // reach specified level, hold specified item, DEFINE_LEVEL_HOLD_ITEM must be defined in src/pokemon.c
#define EVO_MON_IN_PARTY         30 // level up, has specific mon in party
#define EVO_ITEM_MALE            31 // use evo stone, is male
#define EVO_ITEM_FEMALE          32 // use evo stone, is female
#define EVO_STONE_HOLD_ITEM      33 // use evo stone, hold specified item, DEFINE_STONE_HOLD_ITEM must be defined in src/pokemon.c
#define EVO_ALOLA_LEVEL          34 // reach specified level, hold ITEM_STRANGE_SOUVENIR
#define EVO_ALOLA_LEVEL_NIGHT    35 // reach specified level, is night, hold ITEM_STRANGE_SOUVENIR
#define EVO_ALOLA_STONE          36 // use evo stone, hold ITEM_STRANGE_SOUVENIR
#define EVO_LEVEL_LOCATION       37 // Pokémon levels up in a specific location
#define EVO_LEVEL_RAIN           38 // reach specified level in the rain
#define EVO_LEVEL_NATURE_AMPED   39 // reach specific level with nature
#define EVO_LEVEL_NATURE_LOW_KEY 40 // reach specific level with nature
#define EVO_BY_ITEM_COUNT        41 // level up and have number of specific items in bag, items then removed, DEFINE_ITEM_COUNT_FOR_EVO must be defined in src/pokemon.c


// end of new evo methods

just underneath the // Evolution types section change

#define EVOS_PER_MON 5 to

#define EVOS_PER_MON 8 // 8 allows Eevee to evolve to all Eeveelutions if Leafeon/Glaceon/Sylveon are added

src/pokemon.c

add to the end of the #include section at the top of the file:

#include "constants/region_map_sections.h"
#include "field_weather.h"
#include "constants/weather.h"

add to the #define section at the top after #define FRIENDSHIP_EVO_THRESHOLD 220

note: the evo methods EVO_LEVEL_HOLD_ITEM, EVO_STONE_HOLD_ITEM and EVO_BY_ITEM_COUNT must have a define for each item or amount you want as a condition, without these it won't compile properly. (Potion and Super Potion used here as an example)

//custom evo times
#define CUSTOM_EVO_MORNING_START  6
#define CUSTOM_EVO_MORNING_END    12
#define CUSTOM_EVO_DAY_START      7
#define CUSTOM_EVO_DAY_END        19

#define CUSTOM_EVO_NIGHT_START    CUSTOM_EVO_DAY_END
#define CUSTOM_EVO_NIGHT_END      CUSTOM_EVO_DAY_START

#define CUSTOM_EVO_MIDNIGHT_PM    24
#define CUSTOM_EVO_MIDNIGHT_AM     0

#define CUSTOM_EVO_DUSK_START     19
#define CUSTOM_EVO_DUSK_END       22

// uncomment to use the above times as new evolution times, else default times will be used
//#define CUSTOM_EVO_TIMES

// required for `EVO_LEVEL_HOLD_ITEM` / `EVO_STONE_HOLD_ITEM` / `EVO_BY_ITEM_COUNT`
#define DEFINE_LEVEL_HOLD_ITEM      ITEM_POTION
#define DEFINE_STONE_HOLD_ITEM      ITEM_SUPER_POTION
#define DEFINE_ITEM_COUNT_FOR_EVO   999

in section u16 GetEvolutionTargetSpecies(struct Pokemon *mon, u8 mode, u16 evolutionItem) replace everything with:

{
    int i, j;
    u16 targetSpecies = 0;
    u16 species = GetMonData(mon, MON_DATA_SPECIES, 0);
    u16 heldItem = GetMonData(mon, MON_DATA_HELD_ITEM, 0);
    u32 personality = GetMonData(mon, MON_DATA_PERSONALITY, 0);
    u8 level;
    u16 friendship;
    u8 beauty = GetMonData(mon, MON_DATA_BEAUTY, 0);
    u16 upperPersonality = personality >> 16;
    u8 holdEffect;

    if (heldItem == ITEM_ENIGMA_BERRY)
        holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect;
    else
        holdEffect = GetItemHoldEffect(heldItem);

	#ifdef FLAG_BLOCK_EVOLUTION
		// prevent evolution with a flag (to use, rename a flag in flags.h)
        if(FlagGet(FLAG_BLOCK_EVOLUTION))
            return SPECIES_NONE;
	#else
	#endif

    // Prevent evolution with Everstone, unless we're just viewing the party menu with an evolution item
    if (holdEffect == HOLD_EFFECT_PREVENT_EVOLVE && mode != EVO_MODE_ITEM_CHECK)
        return SPECIES_NONE;

    switch (mode)
    {
    case EVO_MODE_NORMAL:
        level = GetMonData(mon, MON_DATA_LEVEL, 0);
        friendship = GetMonData(mon, MON_DATA_FRIENDSHIP, 0);

        for (i = 0; i < EVOS_PER_MON; i++)
        {
            switch (gEvolutionTable[species][i].method)
            {
            case EVO_FRIENDSHIP:
                if (friendship >= FRIENDSHIP_EVO_THRESHOLD)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
            case EVO_FRIENDSHIP_DAY:
                #ifndef CUSTOM_EVO_TIMES
                    RtcCalcLocalTime();
                    if (gLocalTime.hours >= DAY_EVO_HOUR_BEGIN && gLocalTime.hours < DAY_EVO_HOUR_END && friendship >= FRIENDSHIP_EVO_THRESHOLD)
                        targetSpecies = gEvolutionTable[species][i].targetSpecies;
                    break;
                #else
                    RtcCalcLocalTime();
                    if (gLocalTime.hours >= CUSTOM_EVO_DAY_START && gLocalTime.hours < CUSTOM_EVO_DAY_END && friendship >= FRIENDSHIP_EVO_THRESHOLD)
                        targetSpecies = gEvolutionTable[species][i].targetSpecies;
                    break;
				#endif
            case EVO_FRIENDSHIP_NIGHT:
			    #ifndef CUSTOM_EVO_TIMES
			        RtcCalcLocalTime();
                    if (gLocalTime.hours >= NIGHT_EVO_HOUR_BEGIN && gLocalTime.hours < NIGHT_EVO_HOUR_END && friendship >= FRIENDSHIP_EVO_THRESHOLD)
                        targetSpecies = gEvolutionTable[species][i].targetSpecies;
                    break;
                #else
                    RtcCalcLocalTime();
                if (gLocalTime.hours >= CUSTOM_EVO_MIDNIGHT_AM && gLocalTime.hours < CUSTOM_EVO_DAY_START && friendship >= FRIENDSHIP_EVO_THRESHOLD)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                if (gLocalTime.hours >= CUSTOM_EVO_NIGHT_START && gLocalTime.hours < CUSTOM_EVO_MIDNIGHT_PM && friendship >= FRIENDSHIP_EVO_THRESHOLD)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
                #endif
            case EVO_LEVEL:
                if (gEvolutionTable[species][i].param <= level)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
            case EVO_LEVEL_ATK_GT_DEF:
                if (gEvolutionTable[species][i].param <= level)
                    if (GetMonData(mon, MON_DATA_ATK, 0) > GetMonData(mon, MON_DATA_DEF, 0))
                        targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
            case EVO_LEVEL_ATK_EQ_DEF:
                if (gEvolutionTable[species][i].param <= level)
                    if (GetMonData(mon, MON_DATA_ATK, 0) == GetMonData(mon, MON_DATA_DEF, 0))
                        targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
            case EVO_LEVEL_ATK_LT_DEF:
                if (gEvolutionTable[species][i].param <= level)
                    if (GetMonData(mon, MON_DATA_ATK, 0) < GetMonData(mon, MON_DATA_DEF, 0))
                        targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
            case EVO_LEVEL_SILCOON:
                if (gEvolutionTable[species][i].param <= level && (upperPersonality % 10) <= 4)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
            case EVO_LEVEL_CASCOON:
                if (gEvolutionTable[species][i].param <= level && (upperPersonality % 10) > 4)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
            case EVO_LEVEL_NINJASK:
                if (gEvolutionTable[species][i].param <= level)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
            case EVO_BEAUTY:
                if (gEvolutionTable[species][i].param <= beauty)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
            case EVO_LEVEL_MALE:
                if (gEvolutionTable[species][i].param <= level && GetMonGender(mon) == MON_MALE)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
            case EVO_LEVEL_FEMALE:
                if (gEvolutionTable[species][i].param <= level && GetMonGender(mon) == MON_FEMALE)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
            case EVO_LEVEL_MALE_MORNING:
                    RtcCalcLocalTime();
                if (gEvolutionTable[species][i].param <= level && GetMonGender(mon) == MON_MALE && gLocalTime.hours >= CUSTOM_EVO_MORNING_START && gLocalTime.hours < CUSTOM_EVO_MORNING_END && gEvolutionTable[species][i].param <= level)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
            case EVO_LEVEL_FEMALE_MORNING:
                    RtcCalcLocalTime();
                if (gEvolutionTable[species][i].param <= level && GetMonGender(mon) == MON_FEMALE && gLocalTime.hours >= CUSTOM_EVO_MORNING_START && gLocalTime.hours < CUSTOM_EVO_MORNING_END && gEvolutionTable[species][i].param <= level)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
            case EVO_LEVEL_DAY:
			#ifndef CUSTOM_EVO_TIMES
                    RtcCalcLocalTime();
                if (gLocalTime.hours >= DAY_EVO_HOUR_BEGIN && gLocalTime.hours < DAY_EVO_HOUR_END && gEvolutionTable[species][i].param <= level)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
            #else
                    RtcCalcLocalTime();
                if (gLocalTime.hours >= CUSTOM_EVO_DAY_START && gLocalTime.hours < CUSTOM_EVO_DAY_END && gEvolutionTable[species][i].param <= level)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
			#endif
            case EVO_LEVEL_NIGHT:
			#ifndef CUSTOM_EVO_TIMES
                    RtcCalcLocalTime();
                if (gLocalTime.hours >= NIGHT_EVO_HOUR_BEGIN && gLocalTime.hours < NIGHT_EVO_HOUR_END && gEvolutionTable[species][i].param <= level)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
			#else
                    RtcCalcLocalTime();
                if (gLocalTime.hours >= CUSTOM_EVO_MIDNIGHT_AM && gLocalTime.hours < CUSTOM_EVO_NIGHT_END && gEvolutionTable[species][i].param <= level)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                if (gLocalTime.hours >= CUSTOM_EVO_NIGHT_START && gLocalTime.hours < CUSTOM_EVO_MIDNIGHT_PM && gEvolutionTable[species][i].param <= level)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
			#endif
            case EVO_LEVEL_MORNING:
                    RtcCalcLocalTime();
                if (gLocalTime.hours >= CUSTOM_EVO_MORNING_START && gLocalTime.hours < CUSTOM_EVO_MORNING_END && gEvolutionTable[species][i].param <= level)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
            case EVO_LEVEL_DUSK:
                    RtcCalcLocalTime();
                if (gLocalTime.hours >= CUSTOM_EVO_DUSK_START && gLocalTime.hours < CUSTOM_EVO_DUSK_END && gEvolutionTable[species][i].param <= level)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
            case EVO_HOLD_ITEM:
                if (heldItem == gEvolutionTable[species][i].param)
                {
                    heldItem = 0;
                    SetMonData(mon, MON_DATA_HELD_ITEM, &heldItem);
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                }
                break;
            case EVO_HOLD_ITEM_DAY:
            #ifndef CUSTOM_EVO_TIMES
                    RtcCalcLocalTime();
                if (gLocalTime.hours >= DAY_EVO_HOUR_BEGIN && gLocalTime.hours < DAY_EVO_HOUR_END && heldItem == gEvolutionTable[species][i].param)
                {
                    heldItem = 0;
                    SetMonData(mon, MON_DATA_HELD_ITEM, &heldItem);
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                }
                break;
			#else
                    RtcCalcLocalTime();
                if (gLocalTime.hours >= CUSTOM_EVO_DAY_START && gLocalTime.hours < CUSTOM_EVO_DAY_END && heldItem == gEvolutionTable[species][i].param)
                {
                    heldItem = 0;
                    SetMonData(mon, MON_DATA_HELD_ITEM, &heldItem);
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                }
                break;
            #endif
            case EVO_HOLD_ITEM_NIGHT:
			#ifndef CUSTOM_EVO_TIMES
                    RtcCalcLocalTime();
                if (gLocalTime.hours >= NIGHT_EVO_HOUR_BEGIN && gLocalTime.hours < NIGHT_EVO_HOUR_END && heldItem == gEvolutionTable[species][i].param)
                {
                    heldItem = 0;
                    SetMonData(mon, MON_DATA_HELD_ITEM, &heldItem);
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                }
                break;			
            #else
                    RtcCalcLocalTime();
                if (gLocalTime.hours >= CUSTOM_EVO_MIDNIGHT_AM && gLocalTime.hours < CUSTOM_EVO_NIGHT_END && heldItem == gEvolutionTable[species][i].param)
                {
                    heldItem = 0;
                    SetMonData(mon, MON_DATA_HELD_ITEM, &heldItem);
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                }
                if (gLocalTime.hours >= CUSTOM_EVO_NIGHT_START && gLocalTime.hours < CUSTOM_EVO_MIDNIGHT_PM && heldItem == gEvolutionTable[species][i].param)
                {
                    heldItem = 0;
                    SetMonData(mon, MON_DATA_HELD_ITEM, &heldItem);
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                }
                break;
            #endif
            case EVO_MOVE:
                if (MonKnowsMove(mon, gEvolutionTable[species][i].param))
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
            case EVO_MOVE_TYPE:
                for (j = 0; j < 4; j++)
                {
                    if (gBattleMoves[GetMonData(mon, MON_DATA_MOVE1 + j, NULL)].type == gEvolutionTable[species][i].param)
                    {
                        targetSpecies = gEvolutionTable[species][i].targetSpecies;
                        break;
                    }
                }
                break;
            case EVO_LEVEL_HOLD_ITEM:
                if (gEvolutionTable[species][i].param <= level && heldItem == DEFINE_LEVEL_HOLD_ITEM)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
            case EVO_MON_IN_PARTY:
                for (j = 0; j < PARTY_SIZE; j++)
                {
                    if (GetMonData(&gPlayerParty[j], MON_DATA_SPECIES, NULL) == gEvolutionTable[species][i].param)
                    {
                        targetSpecies = gEvolutionTable[species][i].targetSpecies;
                        break;
                    }
                }
                break;
            case EVO_ALOLA_LEVEL:
				#ifdef ITEM_STRANGE_SOUVENIR
                if (gEvolutionTable[species][i].param <= level && heldItem == ITEM_STRANGE_SOUVENIR)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
				#else
				#endif
            case EVO_ALOLA_LEVEL_NIGHT:
                #ifdef ITEM_STRANGE_SOUVENIR
                #ifndef CUSTOM_EVO_TIMES
                RtcCalcLocalTime();
                if (gLocalTime.hours >= NIGHT_EVO_HOUR_BEGIN && gLocalTime.hours < NIGHT_EVO_HOUR_END && gEvolutionTable[species][i].param <= level && heldItem == ITEM_STRANGE_SOUVENIR)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
                #else
                RtcCalcLocalTime();
                if (gLocalTime.hours >= CUSTOM_EVO_MIDNIGHT_AM && gLocalTime.hours < CUSTOM_EVO_NIGHT_END && gEvolutionTable[species][i].param <= level && heldItem == ITEM_STRANGE_SOUVENIR)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                if (gLocalTime.hours >= CUSTOM_EVO_NIGHT_START && gLocalTime.hours < CUSTOM_EVO_MIDNIGHT_PM && gEvolutionTable[species][i].param <= level && heldItem == ITEM_STRANGE_SOUVENIR)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
                #endif // CUSTOM_EVO_TIMES
                #else
                #endif // ITEM_STRANGE_SOUVENIR
            case EVO_LEVEL_LOCATION:
                {
                    u16 requiredMapsec = gEvolutionTable[species][i].param;
                    if (GetCurrentRegionMapSectionId() == requiredMapsec)
                        targetSpecies = gEvolutionTable[species][i].targetSpecies;
                }
                break;
            case EVO_LEVEL_RAIN:
                j = GetCurrentWeather();
                if ((j == WEATHER_RAIN || j == WEATHER_RAIN_THUNDERSTORM || j == WEATHER_DOWNPOUR) && gEvolutionTable[species][i].param <= level)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
            case EVO_LEVEL_NATURE_AMPED:
                if (gEvolutionTable[species][i].param <= level)
                {
                    u8 nature = GetNature(mon);
                    switch (nature)
                    {
                    case NATURE_HARDY:
                    case NATURE_BRAVE:
                    case NATURE_ADAMANT:
                    case NATURE_NAUGHTY:
                    case NATURE_DOCILE:
                    case NATURE_IMPISH:
                    case NATURE_LAX:
                    case NATURE_HASTY:
                    case NATURE_JOLLY:
                    case NATURE_NAIVE:
                    case NATURE_RASH:
                    case NATURE_SASSY:
                    case NATURE_QUIRKY:
                        targetSpecies = gEvolutionTable[species][i].targetSpecies;
                        break;
                    }
                }
                break;
            case EVO_LEVEL_NATURE_LOW_KEY:
                if (gEvolutionTable[species][i].param <= level)
                {
                    u8 nature = GetNature(mon);
                    switch (nature)
                    {
                    case NATURE_LONELY:
                    case NATURE_BOLD:
                    case NATURE_RELAXED:
                    case NATURE_TIMID:
                    case NATURE_SERIOUS:
                    case NATURE_MODEST:
                    case NATURE_MILD:
                    case NATURE_QUIET:
                    case NATURE_BASHFUL:
                    case NATURE_CALM:
                    case NATURE_GENTLE:
                    case NATURE_CAREFUL:
                        targetSpecies = gEvolutionTable[species][i].targetSpecies;
                        break;
                    }
                }
                break;
            case EVO_BY_ITEM_COUNT:
                if (CheckBagHasItem(gEvolutionTable[species][i].param, DEFINE_ITEM_COUNT_FOR_EVO))
                {
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                    RemoveBagItem(gEvolutionTable[species][i].param, DEFINE_ITEM_COUNT_FOR_EVO);
                }
                break;
            }
        }
        break;
    case EVO_MODE_TRADE:
        for (i = 0; i < EVOS_PER_MON; i++)
        {
            switch (gEvolutionTable[species][i].method)
            {
            case EVO_TRADE:
                targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
            case EVO_TRADE_ITEM:
                if (gEvolutionTable[species][i].param == heldItem)
                {
                    heldItem = ITEM_NONE;
                    SetMonData(mon, MON_DATA_HELD_ITEM, &heldItem);
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                }
                break;
            }
        }
        break;
    case EVO_MODE_ITEM_USE:
    case EVO_MODE_ITEM_CHECK:

        for (i = 0; i < EVOS_PER_MON; i++)
        {
            switch (gEvolutionTable[species][i].method)
            {
            case EVO_ITEM:
                if (gEvolutionTable[species][i].param == evolutionItem)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
            case EVO_STONE_MALE:
                if (GetMonGender(mon) == MON_FEMALE && gEvolutionTable[species][i].param == evolutionItem)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
            case EVO_STONE_FEMALE:
                if (GetMonGender(mon) == MON_MALE && gEvolutionTable[species][i].param == evolutionItem)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
            case EVO_STONE_HOLD_ITEM:
                if (gEvolutionTable[species][i].param == evolutionItem && heldItem == DEFINE_STONE_HOLD_ITEM)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
            case EVO_ALOLA_STONE:
			#ifdef ITEM_STRANGE_SOUVENIR
                if (gEvolutionTable[species][i].param == evolutionItem && heldItem == ITEM_STRANGE_SOUVENIR)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;
			#else
			#endif
            }
        }
        break;
    }

    return targetSpecies;
}
//end of evolution methods

src/data/pokemon/evolution.h

-- important note:
if adding another evolution method to a Pokemon, make sure the first entry has }, and the final entry has the closing }},
eg:

original
    [SPECIES_PIDGEY]     = {{EVO_LEVEL, 18, SPECIES_PIDGEOTTO}},
edited
    [SPECIES_PIDGEY]     = {{EVO_LEVEL, 18, SPECIES_PIDGEOTTO},
                            {EVO_LEVEL_HOLD_ITEM, 18, SPECIES_PIDGEOT}},

example evolutions using the new methods

[SPECIES_BULBASAUR] = {{EVO_LEVEL_MALE, 10, SPECIES_IVYSAUR},
                       {EVO_LEVEL, 16, SPECIES_IVYSAUR}},

[SPECIES_CHARMANDER] = {{EVO_LEVEL_LOCATION, MAPSEC_LITTLEROOT_TOWN, SPECIES_CHARMELEON}},

[SPECIES_SQUIRTLE]   = {{EVO_LEVEL_FEMALE, 10, SPECIES_WARTORTLE}},

[SPECIES_PSYDUCK]    = {{EVO_LEVEL_FEMALE_MORNING, 33, SPECIES_GOLDUCK}},

[SPECIES_MANKEY]     = {{EVO_LEVEL_MALE_MORNING, 28, SPECIES_PRIMEAPE}},

[SPECIES_EKANS]      = {{EVO_LEVEL_DAY, 22, SPECIES_ARBOK}},

[SPECIES_ZUBAT]      = {{EVO_LEVEL_NIGHT, 22, SPECIES_GOLBAT}},

[SPECIES_SANDSHREW]  = {{EVO_LEVEL_MORNING, 22, SPECIES_SANDSLASH}},

[SPECIES_MEOWTH]     = {{EVO_LEVEL_DUSK, 28, SPECIES_PERSIAN}},

[SPECIES_CLEFFA]     = {{EVO_HOLD_ITEM, ITEM_HEART_STONE, SPECIES_CLEFAIRY}},

[SPECIES_GLOOM]      = {{EVO_HOLD_ITEM_NIGHT, ITEM_LEAF_STONE, SPECIES_VILEPLUME},
                        {EVO_HOLD_ITEM_DAY, ITEM_SUN_STONE, SPECIES_BELLOSSOM}},

[SPECIES_LICKITUNG]  = {{EVO_MOVE, MOVE_ROLLOUT, SPECIES_LICKILICKY}},

[SPECIES_EEVEE]      = {{EVO_ITEM, ITEM_THUNDER_STONE, SPECIES_JOLTEON},
                          [edited for brevity]
                        {EVO_MOVE_TYPE, TYPE_FAIRY, SPECIES_SYLVEON}},

[SPECIES_MANTYKE]   = {{EVO_MON_IN_PARTY, SPECIES_REMORAID, SPECIES_GYARADOS}},

[SPECIES_STARYU]     = {{EVO_LEVEL_MON_IN_PARTY, SPECIES_, SPECIES_STARMIE}},

[SPECIES_VULPIX]     = {{EVO_ITEM_MALE, ITEM_FIRE_STONE, SPECIES_NINETALES}},

[SPECIES_JIGGLYPUFF] = {{EVO_ITEM_FEMALE, ITEM_MOON_STONE, SPECIES_WIGGLYTUFF}},

[SPECIES_ABRA]       = {{EVO_LEVEL_HOLD_ITEM, 16, SPECIES_KADABRA}},

[SPECIES_MACHOP]     = {{EVO_STONE_HOLD_ITEM, 28, SPECIES_MACHOKE}},

[SPECIES_GEODUDE]    = {{EVO_ALOLA_LEVEL, 225, SPECIES_GRAVELER_ALOLAN}},

[SPECIES_RATTATA]    = {{EVO_ALOLA_LEVEL_NIGHT, 20, SPECIES_RATICATE_ALOLAN}},

[SPECIES_PIKACHU]    = {{EVO_ALOLA_STONE, ITEM_THUNDER_STONE, SPECIES_RAICHU}},

[SPECIES_TORCHIC]    = {{EVO_LEVEL_RAIN, 7, SPECIES_COMBUSKEN}},

[SPECIES_TOXEL]      = {{EVO_LEVEL_NATURE_AMPED, 30, SPECIES_TOXTRICITY_AMPED},
                        {EVO_LEVEL_NATURE_LOW_KEY, 30, SPECIES_TOXTRICITY_LOW_KEY}},

[SPECIES_GIMMIGHOUL] = {{EVO_BY_ITEM_COUNT, ITEM_GIMMIGHOUL_COIN, SPECIES_GHOLDENGO}},

Edits

  • 7th June - EVO_LEVEL_RAIN

in include/constants/pokemon.h
add

#define EVO_LEVEL_RAIN           38 // reach specified level in the rain

in src/pokemon.c
add

#include "field_weather.h"
#include "constants/weather.h"

in section u16 GetEvolutionTargetSpecies
add to EVO_NORMAL section:

            case EVO_LEVEL_RAIN:
                j = GetCurrentWeather();
                if ((j == WEATHER_RAIN || j == WEATHER_RAIN_THUNDERSTORM || j == WEATHER_DOWNPOUR) && gEvolutionTable[species][i].param <= level)
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                break;

in src/data/pokemon/evolution.c add the evolution

example:
    [SPECIES_TORCHIC]    = {{EVO_LEVEL_RAIN, 7, SPECIES_COMBUSKEN}},
  • 17th June - EVO_LEVEL_NATURE_AMPED & EVO_LEVEL_NATURE_LOW_KEY
    A pokemon can evolve into different evos based on their nature (like Toxel into Toxtricity)

Toxel evolves into "Amped Form" if its Nature is Hardy, Brave, Adamant, Naughty, Docile, Impish, Lax, Hasty, Jolly, Naive, Rash, Sassy, or Quirky.
Toxel evolves into "Low Key Form" if its Nature is Lonely, Bold, Relaxed, Timid, Serious, Modest, Mild, Quiet, Bashful, Calm, Gentle, or Careful.

-- Eevee is used for this example for fun. NATURE_AMPED evolves into Wigglytuff, NATURE_LOW_KEY evolves into Clefable
1emon 1evo 2emon 2evo

3emon 3evo 4emon 4evo 5emon 5evo

in include/constants/pokemon.h
add

#define EVO_LEVEL_NATURE_AMPED   39 // reach specific level with nature
#define EVO_LEVEL_NATURE_LOW_KEY 40 // reach specific level with nature

in src/pokemon.c

in section u16 GetEvolutionTargetSpecies
add to EVO_NORMAL section:

            case EVO_LEVEL_NATURE_AMPED:
                if (gEvolutionTable[species][i].param <= level)
                {
                    u8 nature = GetNature(mon);
                    switch (nature)
                    {
                    case NATURE_HARDY:
                    case NATURE_BRAVE:
                    case NATURE_ADAMANT:
                    case NATURE_NAUGHTY:
                    case NATURE_DOCILE:
                    case NATURE_IMPISH:
                    case NATURE_LAX:
                    case NATURE_HASTY:
                    case NATURE_JOLLY:
                    case NATURE_NAIVE:
                    case NATURE_RASH:
                    case NATURE_SASSY:
                    case NATURE_QUIRKY:
                        targetSpecies = gEvolutionTable[species][i].targetSpecies;
                        break;
                    }
                }
                break;
            case EVO_LEVEL_NATURE_LOW_KEY:
                if (gEvolutionTable[species][i].param <= level)
                {
                    u8 nature = GetNature(mon);
                    switch (nature)
                    {
                    case NATURE_LONELY:
                    case NATURE_BOLD:
                    case NATURE_RELAXED:
                    case NATURE_TIMID:
                    case NATURE_SERIOUS:
                    case NATURE_MODEST:
                    case NATURE_MILD:
                    case NATURE_QUIET:
                    case NATURE_BASHFUL:
                    case NATURE_CALM:
                    case NATURE_GENTLE:
                    case NATURE_CAREFUL:
                        targetSpecies = gEvolutionTable[species][i].targetSpecies;
                        break;
                    }
                }
                break;

in src/data/pokemon/evolution.c add the evolution

example:
    [SPECIES_TOXEL]      = {{EVO_LEVEL_NATURE_AMPED, 30, SPECIES_TOXTRICITY_AMPED},
                            {EVO_LEVEL_NATURE_LOW_KEY, 30, SPECIES_TOXTRICITY_LOW_KEY}},
  • 21st June 2026: Evolve by item count

in include/constants/pokemon.h
add

#define EVO_BY_ITEM_COUNT        41 // level up and have number of specific items in bag, items then removed, DEFINE_ITEM_COUNT_FOR_EVO must be defined in src/pokemon.c

in src/pokemon.c
add near the start of the file, with your custom evolution times (if used)
(this is how many items you need to have for the mon to evolve)

#define DEFINE_ITEM_COUNT_FOR_EVO   999

in section u16 GetEvolutionTargetSpecies
add to EVO_NORMAL section:

            case EVO_BY_ITEM_COUNT:
                if (CheckBagHasItem(gEvolutionTable[species][i].param, DEFINE_ITEM_COUNT_FOR_EVO))
                {
                    targetSpecies = gEvolutionTable[species][i].targetSpecies;
                    RemoveBagItem(gEvolutionTable[species][i].param, DEFINE_ITEM_COUNT_FOR_EVO);
                }
                break;

in src/data/pokemon/evolution.c add the evolution

example:
    [SPECIES_GIMMIGHOUL] = {{EVO_BY_ITEM_COUNT, ITEM_GIMMIGHOUL_COIN, SPECIES_GHOLDENGO}},

Clone this wiki locally