Skip to content

feat: Audit and add all divergent/regional evolution lines - #1656

Open
FallenDeity wants to merge 7 commits into
PokeAPI:masterfrom
FallenDeity:branched-evolutions
Open

feat: Audit and add all divergent/regional evolution lines#1656
FallenDeity wants to merge 7 commits into
PokeAPI:masterfrom
FallenDeity:branched-evolutions

Conversation

@FallenDeity

@FallenDeity FallenDeity commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Change description

Went through a list of complicated/branched evolutions and regional ones to make sure everything being served by pokeapi is accurate and information regarding it is complete

This adds some new evolution information

  • condition_expression: for some formulaic ones like tandmaus form, dundunsparce, wurmple etc which rely on encryption constant/individual values
  • needs_one_of_natures: for toxel -> amped/low-key (this is 25-bit bitmask field for the natures)
  • 2 new triggers one rename for tandemause it used other renamed it to level up in battle, and for meltan which needs meltan candies
  • the main change is migration of base_form and evolved_form from pokemon to pokemon-form rationale behind this is pokemon form is the complete store of all variants and some specialized ones which evolutions depend on like burmy, sinistea etc which are more cosmetic variants with no stat changes or differences other than look but they are canon for required evolution base and next forms so moving everything to pokemon form helps with cosmetic evolution dependencies and also acts the same for ones with technical differences since they point to the respective pokemon entry for stats/moves etc without introducing new form specific fields for this use case and future proofs use for more such evo lines

cases are some pre forms might be cosmetic like burmy but permanent when wormadam, or both pre and post like sinstea line where they have the fake one and the legit one

  • few other minor changes include adding some data for gender splits like espurr, lechonk, basculin etc

References:

Context

Fixes: #1199 #1315 #966 #1037

#1086 partially my understanding goes like this pokemon-species is the biological species in the pokedex its concept and lore, then pokemon further adds the mechanical context like stats, movepools, game timeline etc, followed by form which finally adds the cosmetic layer and points back to pokemon if there is a mechanical change so fallback is in order from that abstraction layer

I dont think species should be removed since some regional variants like paldean wooper etc still use the national dex 174 id and not some 1000+ they share similar egg cycles, hatch rate and pokedex based stuff I am of the opinion we can specialize based on the abstraction layer as mentioned above with some minor details we can move around like mentioned below. going with a unified model destroys all abstraction and generates tons of dups of stuff with only cosmetic changes or visual like vivillon, alcremie etc

#1026 partially again since some points do make sense but species should still exist since thats the lore or universal stuff it holds like pokedex has only one entry for rotom and then it differs bw diff mechanical forms removing species would be duplicating all of that, same for gmax, megas etc or any variant pokemon like deoxys, the evo chain changes rn currently solves both of above issues pertaining to this

some arguments such as gender diffs is not technically valid since there is no stat diff and there is visual diffs which is already present as sprites in pokemon form and pokemon

partial because color_id is valid that changes for regional it should go under pokemon-form since its cosmetic imo

prolly a few others since evo chain linking has been a pain point bought up multiple times this should solve that but I agree current pokemon evolution chains are now no longer linear so if anyone is working with similar to what i linked as a tree below they WOULD have to use something like a tree or a graph with trigger conditions as edges if they want a robust solution.

AI coding assistance disclosure

Used AI to review/summarize some of the bulbapedia and pokeapi.fr site pages for proses and info, locate some csv records and flows etc

Contributor check list

  • I have written a description of the contribution and explained its motivation.
  • I have written tests for my code changes (if applicable).
  • I have read and understood the AI Assisted Contribution guidelines.
  • I will own this change in production, and I am prepared to fix any bugs caused by my code change.

A cli tree constructed from our evolution chain data for some of the complicated lines for review

Details
$ uv run python .\playground\evos.py
[2026-08-31 00:15:42] | ~\pokelance\client\_base.py:119 | INFO | Using cache size: 100
[2026-08-31 00:15:42] | ~\pokelance\client\_base.py:128 | INFO | Setup complete
Loading Pokémon species, version groups, and evolution chains in parallel...

========================= GENERATION I (Generation 1) =========================

=== Evolution Tree: Bulbasaur (Chain #1) ===
   Bulbasaur (#1)
└── [trigger: level-up, min_level: 16 (Gen 1 · Kanto)]
    └──    Ivysaur (#2)
        └── [trigger: level-up, min_level: 32 (Gen 1 · Kanto)]
            └──    Venusaur (#3)

=== Evolution Tree: Charmander (Chain #2) ===
   Charmander (#4)
└── [trigger: level-up, min_level: 16 (Gen 1 · Kanto)]
    └──    Charmeleon (#5)
        └── [trigger: level-up, min_level: 36 (Gen 1 · Kanto)]
            └──    Charizard (#6)

=== Evolution Tree: Squirtle (Chain #3) ===
   Squirtle (#7)
└── [trigger: level-up, min_level: 16 (Gen 1 · Kanto)]
    └──    Wartortle (#8)
        └── [trigger: level-up, min_level: 36 (Gen 1 · Kanto)]
            └──    Blastoise (#9)

=== Evolution Tree: Sandshrew (Chain #11) ===
   Sandshrew (#27)
└── [trigger: level-up, min_level: 22 (Gen 1 · Kanto)]
    └──    Sandslash (#28)

   Sandshrew Alola (#10203)
└── [trigger: use-item, item: ice-stone (Gen 7 · Alola)]
    └──    Sandslash Alola (#10204)

=== Evolution Tree: Nidoran F (Chain #12) ===
   Nidoran F (#29)
└── [trigger: level-up, min_level: 16 (Gen 1 · Kanto)]
    └──    Nidorina (#30)
        └── [trigger: use-item, item: moon-stone (Gen 1 · Kanto)]
            └──    Nidoqueen (#31)

=== Evolution Tree: Nidoran M (Chain #13) ===
   Nidoran M (#32)
└── [trigger: level-up, min_level: 16 (Gen 1 · Kanto)]
    └──    Nidorino (#33)
        └── [trigger: use-item, item: moon-stone (Gen 1 · Kanto)]
            └──    Nidoking (#34)

=== Evolution Tree: Vulpix (Chain #15) ===
   Vulpix (#37)
└── [trigger: use-item, item: fire-stone (Gen 1 · Kanto)]
    └──    Ninetales (#38)

   Vulpix Alola (#10205)
└── [trigger: use-item, item: ice-stone (Gen 7 · Alola)]
    └──    Ninetales Alola (#10206)

=== Evolution Tree: Oddish (Chain #18) ===
   Oddish (#43)
└── [trigger: level-up, min_level: 21 (Gen 1 · Kanto)]
    └──    Gloom (#44)
        ├── [trigger: use-item, item: leaf-stone (Gen 1 · Kanto)]
        │   └──    Vileplume (#45)
        └── [trigger: use-item, item: sun-stone (Gen 2 · Johto)]
            └──    Bellossom (#182)

=== Evolution Tree: Diglett (Chain #21) ===
   Diglett (#50)
└── [trigger: level-up, min_level: 26 (Gen 1 · Kanto)]
    └──    Dugtrio (#51)

   Diglett Alola (#10207)
└── [trigger: level-up, min_level: 26 (Gen 7 · Alola)]
    └──    Dugtrio Alola (#10208)

=== Evolution Tree: Meowth (Chain #22) ===
   Meowth (#52)
└── [trigger: level-up, min_level: 28 (Gen 1 · Kanto)]
    └──    Persian (#53)

   Meowth Alola (#10209)
└── [trigger: level-up, min_happiness: 160 (Gen 7 · Alola)]
    └──    Persian Alola (#10210)

   Meowth Galar (#10320)
└── [trigger: level-up, min_level: 28 (Gen 8 · Galar)]
    └──    Perrserker (#863)

=== Evolution Tree: Mankey (Chain #24) ===
   Mankey (#56)
└── [trigger: level-up, min_level: 28 (Gen 1 · Kanto)]
    └──    Primeape (#57)
        └── [trigger: use-move, used_move: rage-fist, min_move_count: 20 (Gen 9 · Paldea)]
            └──    Annihilape (#979)

=== Evolution Tree: Growlithe (Chain #25) ===
   Growlithe (#58)
└── [trigger: use-item, item: fire-stone (Gen 1 · Kanto)]
    └──    Arcanine (#59)

   Growlithe Hisui (#10398)
└── [trigger: use-item, item: fire-stone (Gen 8 · Hisui)]
    └──    Arcanine Hisui (#10399)

=== Evolution Tree: Poliwag (Chain #26) ===
   Poliwag (#60)
└── [trigger: level-up, min_level: 25 (Gen 1 · Kanto)]
    └──    Poliwhirl (#61)
        ├── [trigger: use-item, item: water-stone (Gen 1 · Kanto)]
        │   └──    Poliwrath (#62)
        └── [trigger: trade, held_item: kings-rock (Gen 2 · Johto)]
            └──    Politoed (#186)

=== Evolution Tree: Geodude (Chain #31) ===
   Geodude (#74)
└── [trigger: level-up, min_level: 25 (Gen 1 · Kanto)]
    └──    Graveler (#75)
        └── [trigger: trade (Gen 1 · Kanto)]
            └──    Golem (#76)

   Geodude Alola (#10211)
└── [trigger: level-up, min_level: 25 (Gen 7 · Alola)]
    └──    Graveler Alola (#10212)
        └── [trigger: trade (Gen 7 · Alola)]
            └──    Golem Alola (#10213)

=== Evolution Tree: Ponyta (Chain #32) ===
   Ponyta (#77)
└── [trigger: level-up, min_level: 40 (Gen 1 · Kanto)]
    └──    Rapidash (#78)

   Ponyta Galar (#10321)
└── [trigger: level-up, min_level: 40 (Gen 8 · Galar)]
    └──    Rapidash Galar (#10322)

=== Evolution Tree: Slowpoke (Chain #33) ===
   Slowpoke (#79)
├── [trigger: level-up, min_level: 37 (Gen 1 · Kanto)]
│   └──    Slowbro (#80)
└── [trigger: trade, held_item: kings-rock (Gen 2 · Johto)]
    └──    Slowking (#199)

   Slowpoke Galar (#10323)
├── [trigger: use-item, item: galarica-cuff (Gen 8 · Galar)]
│   └──    Slowbro Galar (#10324)
└── [trigger: use-item, item: galarica-wreath (Gen 8 · Galar)]
    └──    Slowking Galar (#10331)

=== Evolution Tree: Farfetchd (Chain #35) ===
   Farfetchd (#83) (No evolutions)

   Farfetchd Galar (#10325)
└── [trigger: three-critical-hits (Gen 8 · Galar)]
    └──    Sirfetchd (#865)

=== Evolution Tree: Grimer (Chain #38) ===
   Grimer (#88)
└── [trigger: level-up, min_level: 38 (Gen 1 · Kanto)]
    └──    Muk (#89)

   Grimer Alola (#10214)
└── [trigger: level-up, min_level: 38 (Gen 7 · Alola)]
    └──    Muk Alola (#10215)

=== Evolution Tree: Voltorb (Chain #44) ===
   Voltorb (#100)
└── [trigger: level-up, min_level: 30 (Gen 1 · Kanto)]
    └──    Electrode (#101)

   Voltorb Hisui (#10400)
└── [trigger: use-item, item: leaf-stone (Gen 8 · Hisui)]
    └──    Electrode Hisui (#10401)

=== Evolution Tree: Exeggcute (Chain #45) ===
   Exeggcute (#102)
├── [trigger: use-item, item: leaf-stone (Gen 1 · Kanto)]
│   └──    Exeggutor (#103)
└── [trigger: use-item, item: leaf-stone, region: alola (Gen 7 · Alola)]
    └──    Exeggutor Alola (#10216)

=== Evolution Tree: Cubone (Chain #46) ===
   Cubone (#104)
├── [trigger: level-up, min_level: 28 (Gen 1 · Kanto)]
│   └──    Marowak (#105)
└── [trigger: level-up, min_level: 28, time_of_day: night, region: alola (Gen 7 · Alola)]
    └──    Marowak Alola (#10217)

=== Evolution Tree: Koffing (Chain #49) ===
   Koffing (#109)
├── [trigger: level-up, min_level: 35 (Gen 1 · Kanto)]
│   └──    Weezing (#110)
└── [trigger: level-up, min_level: 35, region: galar (Gen 8 · Galar)]
    └──    Weezing Galar (#10326)

=== Evolution Tree: Scyther (Chain #58) ===
   Scyther (#123)
├── [trigger: trade, held_item: metal-coat (Gen 2 · Johto)]
│   └──    Scizor (#212)
└── [trigger: use-item, item: black-augurite (Gen 8 · Hisui)]
    └──    Kleavor (#900)

=== Evolution Tree: Tauros (Chain #63) ===
   Tauros (#128) (No evolutions)

=== Evolution Tree: Eevee (Chain #67) ===
   Eevee (#133)
├── [trigger: use-item, item: water-stone (Gen 1 · Kanto)]
│   └──    Vaporeon (#134)
├── [trigger: use-item, item: thunder-stone (Gen 1 · Kanto)]
│   └──    Jolteon (#135)
├── [trigger: use-item, item: fire-stone (Gen 1 · Kanto)]
│   └──    Flareon (#136)
├── [trigger: level-up, time_of_day: day, min_happiness: 160 (Gen 2 · Johto)]
│   └──    Espeon (#196)
├── [trigger: level-up, time_of_day: night, min_happiness: 160 (Gen 2 · Johto)]
│   └──    Umbreon (#197)
├── [trigger: level-up, location: eterna-forest, near_special_rock: True (Gen 4 · Sinnoh)]
├── [trigger: level-up, location: pinwheel-forest, near_special_rock: True (Gen 5 · Unova)]
├── [trigger: level-up, location: kalos-route-20, near_special_rock: True (Gen 6 · Kalos)]
├── [trigger: level-up, location: petalburg-woods, near_special_rock: True (Gen 6 · Hoenn)]
├── [trigger: level-up, location: lush-jungle, near_special_rock: True (Gen 7 · Alola)]
├── [trigger: use-item, item: leaf-stone (Gen 8 · Galar)]
│   └──    Leafeon (#470)
├── [trigger: level-up, location: sinnoh-route-217, near_special_rock: True (Gen 4 · Sinnoh)]
├── [trigger: level-up, location: twist-mountain, near_special_rock: True (Gen 5 · Unova)]
├── [trigger: level-up, location: frost-cavern, near_special_rock: True (Gen 6 · Kalos)]
├── [trigger: level-up, location: shoal-cave, near_special_rock: True (Gen 6 · Hoenn)]
├── [trigger: level-up, location: mount-lanakila, near_special_rock: True (Gen 7 · Alola)]
├── [trigger: use-item, item: ice-stone (Gen 8 · Galar)]
│   └──    Glaceon (#471)
├── [trigger: level-up, known_move_type: fairy, min_affection: 2 (Gen 6 · Kalos)]
└── [trigger: level-up, known_move_type: fairy, min_happiness: 160 (Gen 8 · Galar)]
    └──    Sylveon (#700)

=== Evolution Tree: Articuno (Chain #73) ===
   Articuno (#144) (No evolutions)

=== Evolution Tree: Zapdos (Chain #74) ===
   Zapdos (#145) (No evolutions)

=== Evolution Tree: Moltres (Chain #75) ===
   Moltres (#146) (No evolutions)

=== Evolution Tree: Mewtwo (Chain #77) ===
   Mewtwo (#150) (No evolutions)

========================= GENERATION II (Generation 2) =========================

=== Evolution Tree: Cyndaquil (Chain #80) ===
   Cyndaquil (#155)
├── [trigger: level-up, min_level: 14 (Gen 2 · Johto)]
└── [trigger: level-up, min_level: 17, region: hisui (Gen 8 · Hisui)]
    └──    Quilava (#156)
        ├── [trigger: level-up, min_level: 36 (Gen 2 · Johto)]
        │   └──    Typhlosion (#157)
        └── [trigger: level-up, min_level: 36, region: hisui (Gen 8 · Hisui)]
            └──    Typhlosion Hisui (#10402)

=== Evolution Tree: Pichu (Chain #10) ===
   Pichu (#172)
└── [trigger: level-up, min_happiness: 220 (Gen 1 · Kanto)]
    └──    Pikachu (#25)
        ├── [trigger: use-item, item: thunder-stone (Gen 1 · Kanto)]
        │   └──    Raichu (#26)
        └── [trigger: use-item, item: thunder-stone, region: alola (Gen 7 · Alola)]
            └──    Raichu Alola (#10202)

=== Evolution Tree: Wooper (Chain #96) ===
   Wooper (#194)
└── [trigger: level-up, min_level: 20 (Gen 2 · Johto)]
    └──    Quagsire (#195)

   Wooper Paldea (#10422)
└── [trigger: level-up, min_level: 20 (Gen 9 · Paldea)]
    └──    Clodsire (#980)

=== Evolution Tree: Dunsparce (Chain #103) ===
   Dunsparce (#206)
├── [trigger: level-up, known_move: hyper-drill, condition_expression: (EC % 100) != 0 (Gen 9 · Paldea)]
│   └──    Dudunsparce Two Segment (#982)
└── [trigger: level-up, known_move: hyper-drill, condition_expression: (EC % 100) == 0 (Gen 9 · Paldea)]
    └──    Dudunsparce Three Segment (#10424)

=== Evolution Tree: Qwilfish (Chain #106) ===
   Qwilfish (#211) (No evolutions)

   Qwilfish Hisui (#10403)
├── [trigger: strong-style-move, used_move: barb-barrage, min_move_count: 20 (Gen 8 · Hisui)]
├── [trigger: level-up, known_move: barb-barrage (Gen 9 · Paldea)]
└── [trigger: use-move, used_move: barb-barrage, min_move_count: 20 (Gen 9 · Paldea)]
    └──    Overqwil (#904)

=== Evolution Tree: Teddiursa (Chain #110) ===
   Teddiursa (#216)
└── [trigger: level-up, min_level: 30 (Gen 2 · Johto)]
    └──    Ursaring (#217)
        └── [trigger: use-item, item: peat-block, time_of_day: full-moon (Gen 8 · Hisui)]
            └──    Ursaluna (#901)

=== Evolution Tree: Corsola (Chain #113) ===
   Corsola (#222) (No evolutions)

   Corsola Galar (#10332)
└── [trigger: level-up, min_level: 38 (Gen 8 · Galar)]
    └──    Cursola (#864)

=== Evolution Tree: Stantler (Chain #120) ===
   Stantler (#234)
└── [trigger: agile-style-move, used_move: psyshield-bash, min_move_count: 20 (Gen 8 · Hisui)]
    └──    Wyrdeer (#899)

=== Evolution Tree: Tyrogue (Chain #47) ===
   Tyrogue (#236)
├── [trigger: level-up, min_level: 20, relative_physical_stats: 1 (Gen 1 · Kanto)]
│   └──    Hitmonlee (#106)
├── [trigger: level-up, min_level: 20, relative_physical_stats: -1 (Gen 1 · Kanto)]
│   └──    Hitmonchan (#107)
└── [trigger: level-up, min_level: 20, relative_physical_stats: 0 (Gen 2 · Johto)]
    └──    Hitmontop (#237)

========================= GENERATION III (Generation 3) =========================

=== Evolution Tree: Zigzagoon (Chain #134) ===
   Zigzagoon (#263)
└── [trigger: level-up, min_level: 20 (Gen 3 · Hoenn)]
    └──    Linoone (#264)

   Zigzagoon Galar (#10333)
└── [trigger: level-up, min_level: 20 (Gen 8 · Galar)]
    └──    Linoone Galar (#10334)
        └── [trigger: level-up, min_level: 35, time_of_day: night (Gen 8 · Galar)]
            └──    Obstagoon (#862)

=== Evolution Tree: Wurmple (Chain #135) ===
   Wurmple (#265)
├── [trigger: level-up, min_level: 7, condition_expression: ((PID >> 16) % 10) <= 4 (Gen 3 · Hoenn)]
├── [trigger: level-up, min_level: 7, condition_expression: ((EC >> 16) % 10) <= 4 (Gen 6 · Kalos)]
│   └──    Silcoon (#266)
│       └── [trigger: level-up, min_level: 10 (Gen 3 · Hoenn)]
│           └──    Beautifly (#267)
├── [trigger: level-up, min_level: 7, condition_expression: ((PID >> 16) % 10) >= 5 (Gen 3 · Hoenn)]
└── [trigger: level-up, min_level: 7, condition_expression: ((EC >> 16) % 10) >= 5 (Gen 6 · Kalos)]
    └──    Cascoon (#268)
        └── [trigger: level-up, min_level: 10 (Gen 3 · Hoenn)]
            └──    Dustox (#269)

=== Evolution Tree: Ralts (Chain #140) ===
   Ralts (#280)
└── [trigger: level-up, min_level: 20 (Gen 3 · Hoenn)]
    └──    Kirlia (#281)
        ├── [trigger: level-up, min_level: 30 (Gen 3 · Hoenn)]
        │   └──    Gardevoir (#282)
        └── [trigger: use-item, item: dawn-stone, gender: male (Gen 4 · Sinnoh)]
            └──    Gallade (#475)

=== Evolution Tree: Nincada (Chain #144) ===
   Nincada (#290)
├── [trigger: level-up, min_level: 20 (Gen 3 · Hoenn)]
│   └──    Ninjask (#291)
└── [trigger: shed (Gen 3 · Hoenn)]
    └──    Shedinja (#292)

=== Evolution Tree: Feebas (Chain #178) ===
   Feebas (#349)
├── [trigger: level-up, min_beauty: 170 (Gen 3 · Hoenn)]
└── [trigger: trade, held_item: prism-scale (Gen 5 · Unova)]
    └──    Milotic (#350)

=== Evolution Tree: Castform (Chain #179) ===
   Castform (#351) (No evolutions)

=== Evolution Tree: Snorunt (Chain #186) ===
   Snorunt (#361)
├── [trigger: level-up, min_level: 42 (Gen 3 · Hoenn)]
│   └──    Glalie (#362)
└── [trigger: use-item, item: dawn-stone, gender: female (Gen 4 · Sinnoh)]
    └──    Froslass (#478)

=== Evolution Tree: Clamperl (Chain #188) ===
   Clamperl (#366)
├── [trigger: trade, held_item: deep-sea-tooth (Gen 3 · Hoenn)]
│   └──    Huntail (#367)
└── [trigger: trade, held_item: deep-sea-scale (Gen 3 · Hoenn)]
    └──    Gorebyss (#368)

=== Evolution Tree: Groudon (Chain #199) ===
   Groudon (#383) (No evolutions)

=== Evolution Tree: Deoxys (Chain #202) ===
   Deoxys (#386) (No evolutions)

========================= GENERATION IV (Generation 4) =========================

=== Evolution Tree: Burmy (Chain #213) ===
   Burmy Plant (#412)
├── [trigger: level-up, min_level: 20, gender: female (Gen 4 · Sinnoh)]
│   └──    Wormadam Plant (#413)
└── [trigger: level-up, min_level: 20, gender: male (Gen 4 · Sinnoh)]
    └──    Mothim (#414)

   Burmy Sandy (#10034)
├── [trigger: level-up, min_level: 20, gender: male (Gen 4 · Sinnoh)]
│   └──    Mothim (#414)
└── [trigger: level-up, min_level: 20, gender: female (Gen 4 · Sinnoh)]
    └──    Wormadam Sandy (#10036)

   Burmy Trash (#10035)
├── [trigger: level-up, min_level: 20, gender: male (Gen 4 · Sinnoh)]
│   └──    Mothim (#414)
└── [trigger: level-up, min_level: 20, gender: female (Gen 4 · Sinnoh)]
    └──    Wormadam Trash (#10037)

=== Evolution Tree: Combee (Chain #214) ===
   Combee (#415)
└── [trigger: level-up, min_level: 21, gender: female (Gen 4 · Sinnoh)]
    └──    Vespiquen (#416)

=== Evolution Tree: Cherrim (Chain #217) ===
   Cherubi (#420)
└── [trigger: level-up, min_level: 25 (Gen 4 · Sinnoh)]
    └──    Cherrim (#421)

=== Evolution Tree: Mime Jr (Chain #57) ===
   Mime Jr (#439)
├── [trigger: level-up, known_move: mimic (Gen 4 · Sinnoh)]
│   └──    Mr Mime (#122)
└── [trigger: level-up, known_move: mimic, region: galar (Gen 8 · Galar)]
    └──    Mr Mime Galar (#10327)
        └── [trigger: level-up, min_level: 42 (Gen 8 · Galar)]
            └──    Mr Rime (#866)

=== Evolution Tree: Hippopotas (Chain #233) ===
   Hippopotas (#449)
└── [trigger: level-up, min_level: 34 (Gen 4 · Sinnoh)]
    └──    Hippowdon (#450)

=== Evolution Tree: Mantyke (Chain #116) ===
   Mantyke (#458)
└── [trigger: level-up, party_species: remoraid (Gen 4 · Sinnoh)]
    └──    Mantine (#226)

=== Evolution Tree: Weavile (Chain #109) ===
   Sneasel (#215)
└── [trigger: level-up, held_item: razor-claw, time_of_day: night (Gen 4 · Sinnoh)]
    └──    Weavile (#461)

   Sneasel Hisui (#10404)
└── [trigger: level-up, held_item: razor-claw, time_of_day: day (Gen 8 · Hisui)]
    └──    Sneasler (#903)

========================= GENERATION V (Generation 5) =========================

=== Evolution Tree: Oshawott (Chain #258) ===
   Oshawott (#501)
└── [trigger: level-up, min_level: 17 (Gen 5 · Unova)]
    └──    Dewott (#502)
        ├── [trigger: level-up, min_level: 36 (Gen 5 · Unova)]
        │   └──    Samurott (#503)
        └── [trigger: level-up, min_level: 36, region: hisui (Gen 8 · Hisui)]
            └──    Samurott Hisui (#10405)

=== Evolution Tree: Tranquill (Chain #266) ===
   Pidove (#519)
└── [trigger: level-up, min_level: 21 (Gen 5 · Unova)]
    └──    Tranquill (#520)
        └── [trigger: level-up, min_level: 32 (Gen 5 · Unova)]
            └──    Unfezant (#521)

=== Evolution Tree: Petilil (Chain #279) ===
   Petilil (#548)
├── [trigger: use-item, item: sun-stone (Gen 5 · Unova)]
│   └──    Lilligant (#549)
└── [trigger: use-item, item: sun-stone, region: hisui (Gen 8 · Hisui)]
    └──    Lilligant Hisui (#10406)

=== Evolution Tree: Basculin (Chain #280) ===
   Basculin (#550) (No evolutions)

   Basculin White Striped (#10416)
├── [trigger: recoil-damage, gender: male, min_damage_taken: 294 (Gen 8 · Hisui)]
│   └──    Basculegion Male (#902)
└── [trigger: recoil-damage, gender: female, min_damage_taken: 294 (Gen 8 · Hisui)]
    └──    Basculegion Female (#10417)

=== Evolution Tree: Darumaka (Chain #282) ===
   Darumaka (#554)
└── [trigger: level-up, min_level: 35 (Gen 5 · Unova)]
    └──    Darmanitan (#555)

   Darumaka Galar (#10335)
└── [trigger: use-item, item: ice-stone (Gen 8 · Galar)]
    └──    Darmanitan Galar Standard (#10336)

=== Evolution Tree: Yamask (Chain #287) ===
   Yamask (#562)
└── [trigger: level-up, min_level: 34 (Gen 5 · Unova)]
    └──    Cofagrigus (#563)

   Yamask Galar (#10338)
└── [trigger: take-damage, location: dusty-bowl, min_damage_taken: 49 (Gen 8 · Galar)]
    └──    Runerigus (#867)

=== Evolution Tree: Zorua (Chain #291) ===
   Zorua (#570)
└── [trigger: level-up, min_level: 30 (Gen 5 · Unova)]
    └──    Zoroark (#571)

   Zorua Hisui (#10407)
└── [trigger: level-up, min_level: 30 (Gen 8 · Hisui)]
    └──    Zoroark Hisui (#10408)

=== Evolution Tree: Karrablast (Chain #299) ===
   Karrablast (#588)
└── [trigger: trade, trade_species: shelmet (Gen 5 · Unova)]
    └──    Escavalier (#589)

=== Evolution Tree: Frillish (Chain #301) ===
   Frillish (#592)
└── [trigger: level-up, min_level: 40 (Gen 5 · Unova)]
    └──    Jellicent (#593)

=== Evolution Tree: Shelmet (Chain #312) ===
   Shelmet (#616)
└── [trigger: trade, trade_species: karrablast (Gen 5 · Unova)]
    └──    Accelgor (#617)

=== Evolution Tree: Stunfisk (Chain #313) ===
   Stunfisk (#618) (No evolutions)

=== Evolution Tree: Pawniard (Chain #317) ===
   Pawniard (#624)
└── [trigger: level-up, min_level: 52 (Gen 5 · Unova)]
    └──    Bisharp (#625)
        └── [trigger: three-defeated-bisharp (Gen 9 · Paldea)]
            └──    Kingambit (#983)

=== Evolution Tree: Rufflet (Chain #319) ===
   Rufflet (#627)
├── [trigger: level-up, min_level: 54 (Gen 5 · Unova)]
│   └──    Braviary (#628)
└── [trigger: level-up, min_level: 54, region: hisui (Gen 8 · Hisui)]
    └──    Braviary Hisui (#10409)

=== Evolution Tree: Meloetta (Chain #335) ===
   Meloetta (#648) (No evolutions)

========================= GENERATION VI (Generation 6) =========================

=== Evolution Tree: Greninja (Chain #339) ===
   Froakie (#656)
└── [trigger: level-up, min_level: 16 (Gen 6 · Kalos)]
    └──    Frogadier (#657)
        └── [trigger: level-up, min_level: 36 (Gen 6 · Kalos)]
            └──    Greninja (#658)

=== Evolution Tree: Litleo (Chain #343) ===
   Litleo (#667)
└── [trigger: level-up, min_level: 35 (Gen 6 · Kalos)]
    └──    Pyroar (#668)

=== Evolution Tree: Floette (Chain #344) ===
   Flabebe (#669)
└── [trigger: level-up, min_level: 19 (Gen 6 · Kalos)]
    └──    Floette (#670)
        └── [trigger: use-item, item: shiny-stone (Gen 6 · Kalos)]
            └──    Florges (#671)

=== Evolution Tree: Pancham (Chain #346) ===
   Pancham (#674)
└── [trigger: level-up, min_level: 32, party_type: dark (Gen 6 · Kalos)]
    └──    Pangoro (#675)

=== Evolution Tree: Espurr (Chain #348) ===
   Espurr (#677)
├── [trigger: level-up, min_level: 25, gender: male (Gen 6 · Kalos)]
│   └──    Meowstic Male (#678)
└── [trigger: level-up, min_level: 25, gender: female (Gen 6 · Kalos)]
    └──    Meowstic Female (#10124)

=== Evolution Tree: Aegislash (Chain #349) ===
   Honedge (#679)
└── [trigger: level-up, min_level: 35 (Gen 6 · Kalos)]
    └──    Doublade (#680)
        └── [trigger: use-item, item: dusk-stone (Gen 6 · Kalos)]
            └──    Aegislash (#681)

=== Evolution Tree: Inkay (Chain #352) ===
   Inkay (#686)
└── [trigger: level-up, min_level: 30, turn_upside_down: True (Gen 6 · Kalos)]
    └──    Malamar (#687)

=== Evolution Tree: Goomy (Chain #362) ===
   Goomy (#704)
├── [trigger: level-up, min_level: 40 (Gen 6 · Kalos)]
│   └──    Sliggoo (#705)
│       └── [trigger: level-up, min_level: 50, needs_overworld_rain: True (Gen 6 · Kalos)]
│           └──    Goodra (#706)
└── [trigger: level-up, min_level: 40, region: hisui (Gen 8 · Hisui)]
    └──    Sliggoo Hisui (#10410)
        └── [trigger: level-up, min_level: 50, needs_overworld_rain: True (Gen 8 · Hisui)]
            └──    Goodra Hisui (#10411)

=== Evolution Tree: Pumpkaboo (Chain #365) ===
   Pumpkaboo Average (#710)
└── [trigger: trade (Gen 6 · Kalos)]
    └──    Gourgeist Average (#711)

   Pumpkaboo Small (#10126)
└── [trigger: trade (Gen 6 · Kalos)]
    └──    Gourgeist Small (#10129)

   Pumpkaboo Large (#10127)
└── [trigger: trade (Gen 6 · Kalos)]
    └──    Gourgeist Large (#10130)

   Pumpkaboo Super (#10128)
└── [trigger: trade (Gen 6 · Kalos)]
    └──    Gourgeist Super (#10131)

=== Evolution Tree: Bergmite (Chain #366) ===
   Bergmite (#712)
├── [trigger: level-up, min_level: 37 (Gen 6 · Kalos)]
│   └──    Avalugg (#713)
└── [trigger: level-up, min_level: 37, region: hisui (Gen 8 · Hisui)]
    └──    Avalugg Hisui (#10412)

=== Evolution Tree: Zygarde (Chain #370) ===
   Zygarde (#718) (No evolutions)

=== Evolution Tree: Hoopa (Chain #372) ===
   Hoopa (#720) (No evolutions)

========================= GENERATION VII (Generation 7) =========================

=== Evolution Tree: Rowlet (Chain #374) ===
   Rowlet (#722)
└── [trigger: level-up, min_level: 17 (Gen 7 · Alola)]
    └──    Dartrix (#723)
        ├── [trigger: level-up, min_level: 34 (Gen 7 · Alola)]
        │   └──    Decidueye (#724)
        └── [trigger: level-up, min_level: 36, region: hisui (Gen 8 · Hisui)]
            └──    Decidueye Hisui (#10413)

=== Evolution Tree: Rockruff (Chain #383) ===
   Rockruff (#744)
├── [trigger: level-up, min_level: 25, time_of_day: day (Gen 7 · Alola)]
│   └──    Lycanroc Midday (#745)
└── [trigger: level-up, min_level: 25, time_of_day: night (Gen 7 · Alola)]
    └──    Lycanroc Midnight (#10228)

   Rockruff Own Tempo (#10310)
└── [trigger: level-up, min_level: 25, time_of_day: dusk (Gen 7 · Alola)]
    └──    Lycanroc Dusk (#10311)

=== Evolution Tree: Wishiwashi (Chain #384) ===
   Wishiwashi (#746) (No evolutions)

=== Evolution Tree: Salandit (Chain #390) ===
   Salandit (#757)
└── [trigger: level-up, min_level: 33, gender: female (Gen 7 · Alola)]
    └──    Salazzle (#758)

=== Evolution Tree: Minior (Chain #400) ===
   Minior (#774) (No evolutions)

=== Evolution Tree: Mimikyu (Chain #404) ===
   Mimikyu (#778) (No evolutions)

=== Evolution Tree: Cosmog (Chain #413) ===
   Cosmog (#789)
└── [trigger: level-up, min_level: 43 (Gen 7 · Alola)]
    └──    Cosmoem (#790)
        ├── [trigger: level-up, min_level: 53 (Gen 7 · Alola)]
        │   └──    Solgaleo (#791)
        └── [trigger: level-up, min_level: 53 (Gen 7 · Alola)]
            └──    Lunala (#792)

=== Evolution Tree: Necrozma (Chain #421) ===
   Necrozma (#800) (No evolutions)

=== Evolution Tree: Magearna (Chain #422) ===
   Magearna (#801) (No evolutions)

=== Evolution Tree: Meltan (Chain #428) ===
   Meltan (#808)
└── [trigger: meltan-candies (Gen 7 · Kanto)]
    └──    Melmetal (#809)

========================= GENERATION VIII (Generation 8) =========================

=== Evolution Tree: Applin (Chain #442) ===
   Applin (#840)
├── [trigger: use-item, item: tart-apple (Gen 8 · Galar)]
│   └──    Flapple (#841)
├── [trigger: use-item, item: sweet-apple (Gen 8 · Galar)]
│   └──    Appletun (#842)
└── [trigger: use-item, item: syrupy-apple (Gen 9 · Paldea)]
    └──    Dipplin (#1011)
        └── [trigger: level-up, known_move: dragon-cheer (Gen 9 · Paldea)]
            └──    Hydrapple (#1019)

=== Evolution Tree: Cramorant (Chain #444) ===
   Cramorant (#845) (No evolutions)

=== Evolution Tree: Toxel (Chain #446) ===
   Toxel (#848)
├── [trigger: level-up, min_level: 30, needs_one_of_natures: one of 13 natures (hardy, docile, hasty...) (Gen 8 · Galar)]
│   └──    Toxtricity Amped (#849)
└── [trigger: level-up, min_level: 30, needs_one_of_natures: one of 12 natures (bold, modest, calm...) (Gen 8 · Galar)]
    └──    Toxtricity Low Key (#10343)

=== Evolution Tree: Sinistea (Chain #449) ===
   Sinistea Phony (#854)
└── [trigger: use-item, item: cracked-pot (Gen 8 · Galar)]
    └──    Polteageist Phony (#855)

   Sinistea Antique (#10344)
└── [trigger: use-item, item: chipped-pot (Gen 8 · Galar)]
    └──    Polteageist Antique (#10345)

=== Evolution Tree: Milcery (Chain #452) ===
   Milcery (#868)
└── [trigger: spin (Gen 8 · Galar)]
    └──    Alcremie (#869)

=== Evolution Tree: Eiscue (Chain #457) ===
   Eiscue (#875) (No evolutions)

=== Evolution Tree: Indeedee (Chain #458) ===
   Indeedee (#876) (No evolutions)

=== Evolution Tree: Duraludon (Chain #465) ===
   Duraludon (#884)
└── [trigger: use-item, item: metal-alloy (Gen 9 · Paldea)]
    └──    Archaludon (#1018)

=== Evolution Tree: Zacian (Chain #467) ===
   Zacian (#888) (No evolutions)

=== Evolution Tree: Zamazenta (Chain #468) ===
   Zamazenta (#889) (No evolutions)

=== Evolution Tree: Eternatus (Chain #469) ===
   Eternatus (#890) (No evolutions)

=== Evolution Tree: Kubfu (Chain #470) ===
   Kubfu (#891)
├── [trigger: tower-of-darkness (Gen 8 · Galar)]
├── [trigger: use-item, item: scroll-of-darkness (Gen 9 · Paldea)]
│   └──    Urshifu Single Strike (#892)
├── [trigger: tower-of-waters (Gen 8 · Galar)]
└── [trigger: use-item, item: scroll-of-waters (Gen 9 · Paldea)]
    └──    Urshifu Rapid Strike (#10360)

=== Evolution Tree: Zarude (Chain #471) ===
   Zarude (#893) (No evolutions)

=== Evolution Tree: Calyrex (Chain #476) ===
   Calyrex (#898) (No evolutions)

========================= GENERATION IX (Generation 9) =========================

=== Evolution Tree: Lechonk (Chain #481) ===
   Lechonk (#915)
├── [trigger: level-up, min_level: 18, gender: male (Gen 9 · Paldea)]
│   └──    Oinkologne Male (#916)
└── [trigger: level-up, min_level: 18, gender: female (Gen 9 · Paldea)]
    └──    Oinkologne Female (#10423)

=== Evolution Tree: Pawmi (Chain #484) ===
   Pawmi (#921)
└── [trigger: level-up, min_level: 18 (Gen 9 · Paldea)]
    └──    Pawmo (#922)
        └── [trigger: level-up, min_steps: 1000 (Gen 9 · Paldea)]
            └──    Pawmot (#923)

=== Evolution Tree: Tandemaus (Chain #485) ===
   Tandemaus (#924)
├── [trigger: in-battle-level-up, min_level: 25, condition_expression: (EC % 100) != 0 (Gen 9 · Paldea)]
│   └──    Maushold Family Of Four (#925)
└── [trigger: in-battle-level-up, min_level: 25, condition_expression: (EC % 100) == 0 (Gen 9 · Paldea)]
    └──    Maushold Family Of Three (#10426)

=== Evolution Tree: Squawkabilly (Chain #488) ===
   Squawkabilly (#931) (No evolutions)

=== Evolution Tree: Charcadet (Chain #490) ===
   Charcadet (#935)
├── [trigger: use-item, item: auspicious-armor (Gen 9 · Paldea)]
│   └──    Armarouge (#936)
└── [trigger: use-item, item: malicious-armor (Gen 9 · Paldea)]
    └──    Ceruledge (#937)

=== Evolution Tree: Bramblin (Chain #495) ===
   Bramblin (#946)
└── [trigger: level-up, min_steps: 1000 (Gen 9 · Paldea)]
    └──    Brambleghast (#947)

=== Evolution Tree: Rellor (Chain #499) ===
   Rellor (#953)
└── [trigger: level-up, min_steps: 1000 (Gen 9 · Paldea)]
    └──    Rabsca (#954)

=== Evolution Tree: Palafin (Chain #504) ===
   Finizen (#963)
└── [trigger: level-up, min_level: 38, needs_multiplayer: True (Gen 9 · Paldea)]
    └──    Palafin (#964)

=== Evolution Tree: Tatsugiri (Chain #514) ===
   Tatsugiri (#978) (No evolutions)

=== Evolution Tree: Gimmighoul (Chain #528) ===
   Gimmighoul (#999)
└── [trigger: gimmighoul-coins (Gen 9 · Paldea)]
    └──    Gholdengo (#1000)

=== Evolution Tree: Poltchageist (Chain #539) ===
   Poltchageist Counterfeit (#1012)
└── [trigger: use-item, item: unremarkable-teacup (Gen 9 · Paldea)]
    └──    Sinistcha Unremarkable (#1013)

   Poltchageist Artisan (#10447)
└── [trigger: use-item, item: masterpiece-teacup (Gen 9 · Paldea)]
    └──    Sinistcha Masterpiece (#10448)

=== Evolution Tree: Terapagos (Chain #548) ===
   Terapagos (#1024) (No evolutions)

Comment thread data/v2/build.py

@jemarq04 jemarq04 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great! Whenever I've updated the evolutions I've left these "form" fields pointing to Pokemon as they were initially, but this is so much cleaner! Plus the solution for Toxtricity is very clean. I added a few comments and questions here.

As a separate thought, I'm not sure that I am loving the condition expression? It is difficult to read and we don't translate this in any way before it's served. Adding a single field that acts as an arbitrary expression seems too complicated and reads confusing. I know that these are odd conditions to the evolutions, but I feel like we can find a better way to model it. Maybe just additional unique evolution triggers?

Comment thread data/v2/build.py Outdated
Comment thread pokemon_v2/models.py Outdated
Comment thread pokemon_v2/serializers.py Outdated
Comment thread pokemon_v2/serializers.py
Comment thread pyproject.toml
Comment thread data/v2/csv/pokemon_evolution.csv Outdated
Comment thread data/v2/build.py Outdated
Comment thread data/v2/csv/evolution_triggers.csv
Comment thread data/v2/csv/pokemon_evolution.csv Outdated
Comment thread data/v2/csv/pokemon_evolution.csv Outdated
@FallenDeity

FallenDeity commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

a few thoughts of mine of the expression side

image

this is what an expression looks like in the evolution chain it is a postfix/rpn expression https://en.wikipedia.org/wiki/Reverse_Polish_notation parsing it to a human readable form is trivial and it gives quite a few benefits over an infix expression

the expression is actively evaluable by any client consumer programming language agnostic this is not a fixed trigger it depends on values and we can let consumers decide how they are going to display the expression hence variable information and data types are tagged under evolution-variable, they can either make it into human readable via stack operation or evaluate it based on conditions without unsafe elements like evals etc

also kind of another distinction is a trigger is a specific event to be met to lead to evolution while condition expression is like a baseline condition that has to be met its not guaranteed pokemon will not release a scenario where there is an expression as such and an event too like even rn a new trigger only would combine level-up + another condition

Comment thread data/v2/csv/evolution_triggers.csv
Comment thread data/v2/csv/pokemon_evolution.csv Outdated
Comment thread data/v2/csv/pokemon_evolution.csv Outdated
@MiquelRForgeFlow

Copy link
Copy Markdown
Contributor

Vivillon can be easily handled too, but with many lines.

The main issue would be Alcremie, awful case, which needs more columns in the trigger file (?)

@FallenDeity

FallenDeity commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

dont think we need to handle vivillon since any spewpa can evolve into any form based on real world region unless we want the real world mapping we can skip it evolved_form null should just be a catch all to any vivillon form, same for milcery again unless we want all permutation of which sweet + swirl/spin

found an exhaustive list for future reference if we ever need to come back to this: https://bulbapedia.bulbagarden.net/wiki/List_of_Pok%C3%A9mon_with_form_differences
but yeah think both would require new cols not worth it imo its just visual diff if someone needs that info we'll give it a look then

@MiquelRForgeFlow

Copy link
Copy Markdown
Contributor

Handling Scatterbug → Spewpa → Vivillon should be 40 rows.

The key question was whether the pattern is decided at evolution or earlier. Bulbapedia, on the Scatterbug page:

This determines the form of Vivillon they will eventually evolve into, and is determined when they are first generated; for Eggs, this means the game in which the Egg was created, regardless of parents.

So Scatterbug and Spewpa already carry the pattern from the moment they're generated, even though they look identical. These are 20 real internal forms, and the database already has all of them (20/20/20). A river Scatterbug always yields a river Vivillon. Structurally this is the same as Flabébé → Floette → Florges, where the branch didn't hesitate to add 5+5 rows.

Cost: 20 rows off row 342 (spewpa, lvl 9) + 20 off row 341 (vivillon, lvl 12).

Two warnings if you take it on:

  • Don't zip by position. The form_identifier values match 20/20, but the ordering doesn't: vivillon starts with meadow (it's the default form) while scatterbug/spewpa start with icy-snow. Match by identifier, not by index.
  • fancy and poke-ball: they exist as scatterbug/spewpa forms in the database, but in the core series they were only distributed as event Vivillon. Breeding a Fancy Vivillon produces a Scatterbug with the console's regional pattern. You need to decide whether to write 20 or 18. I'd do all 20 for consistency with what's already in pokemon_forms.csv; otherwise you're left with orphan forms that have no evolutionary path.

Comment thread data/v2/csv/pokemon_evolution.csv Outdated
@jemarq04

jemarq04 commented Sep 1, 2026

Copy link
Copy Markdown
Member

this is what an expression looks like in the evolution chain it is a postfix/rpn expression https://en.wikipedia.org/wiki/Reverse_Polish_notation parsing it to a human readable form is trivial and it gives quite a few benefits over an infix expression

the expression is actively evaluable by any client consumer programming language agnostic this is not a fixed trigger it depends on values and we can let consumers decide how they are going to display the expression hence variable information and data types are tagged under evolution-variable, they can either make it into human readable via stack operation or evaluate it based on conditions without unsafe elements like evals etc

also kind of another distinction is a trigger is a specific event to be met to lead to evolution while condition expression is like a baseline condition that has to be met its not guaranteed pokemon will not release a scenario where there is an expression as such and an event too like even rn a new trigger only would combine level-up + another condition

Ah ok, I had not heard of the postfix notation before now and coming from a math/physics background this was a very confusing expression haha! I suppose I now understand the reasoning behind this, but I'm not sure that I'm 100% onboard either. The data we serve is (at least I believe it is) human readable. For example, one could provide the allowed natures being proposed here as a bitmask assuming the user would parse it themselves, but its better to provide it in a human readable way as a list of nature resources as you've done.

On the suggestion to use triggers, they have also been used to describe very specific evolutions. For example, we could have stored Gimmighoul's evolution as level-up with a new condition needs_999_gimmighoul_coins, but that would be false for every other entry other than that one, so we opted to use an evolution trigger instead. Similar for kingambit. Though I do agree that making evolution triggers may not be the most elegant approach to this either, especially with the complex formulas for Silcoon/Cascoon.

I'm not totally against using the expression and variables, so if this is the best approach then we should go for it and explain things appropriately in the documentation. I just wanted to see if there were any other options. Maybe we can ping some others to see what they think on this? @Naramsim @notblisy

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

toxtricity-amped needs to be fixed

3 participants