Skip to content

feat: expose form transformations in evolution chains - #1658

Open
MiquelRForgeFlow wants to merge 1 commit into
PokeAPI:masterfrom
MiquelRForgeFlow:feat/evolution-chain-transformations
Open

feat: expose form transformations in evolution chains#1658
MiquelRForgeFlow wants to merge 1 commit into
PokeAPI:masterfrom
MiquelRForgeFlow:feat/evolution-chain-transformations

Conversation

@MiquelRForgeFlow

Copy link
Copy Markdown
Contributor

Change description

/api/v2/evolution-chain/{id}/ only describes species-level evolution. The reversible form changes of those same species (mega evolution, primal reversion, gigantamax, in-battle transformations) live in pokemon_form_conditions.csv and are only reachable one variety at a time: pokemon-species/6varietiespokemon/6formspokemon-form/10134trigger_conditions, i.e. 4 hops to learn that Charizard has two megas and a gmax form.

This PR adds a transformations field next to chain, grouping those conditions by species:

"transformations": [
  { "species": {"name": "charizard"},
    "forms": [
      {"form": {"name": "charizard-mega-x"}, "trigger": "held-item",
       "item": {"name": "charizardite-x"}, "ability": null, "move": null, "base_form": null},
      {"form": {"name": "charizard-gmax"}, "trigger": "gigantamax-factor", ...}
    ]
  }
]

Design notes:

  • chain is untouched. Form changes are not evolutions, so they are not chain links (otherwise Arceus would "evolve" into 17 plates and Aegislash into aegislash-blade). Purely additive: no model or migration changes.
  • Keys stay explicit (item / ability / move), unlike pokemon-form's trigger_conditions, which merges the target's {name, url} into the trigger dict and loses which of the three it came from.
  • transformations is always present, [] when the chain has no form conditions (399 of the 541 chains).
  • Costs exactly 1 extra query per request regardless of chain size.

AI coding assistance disclosure

It wrote the serializer and the tests from my design decisions.

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.

Group the reversible form changes of a chain's species (mega evolution,
gigantamax, in-battle transformations) into a new `transformations` field,
instead of requiring one pokemon-form lookup per variety. `chain` is unchanged.
@FallenDeity

Copy link
Copy Markdown
Contributor

would adding a new field in pokemon-species > varieties itself not solve this problem?

{
 "is_default": false,
  "pokemon": {
    "name": "charizard-mega-x",
    "url": "https://pokeapi.co/api/v2/pokemon/10034/"
  },
  "pokemon_form": ...
}

I dont think reversible transformations should be added in whats considered the biological evolution chain

@MiquelRForgeFlow

MiquelRForgeFlow commented Aug 31, 2026

Copy link
Copy Markdown
Contributor Author

Agreed on the principle: reversible form changes aren't evolution, which is exactly why I kept them out of chain. You're taking that one step further, to the endpoint itself, and I'm fine with it. pokemon-species is the right home.

On putting it in varieties: it can't be a single pokemon_form object. A variety often holds more than one form, and that's where most of this data lives. arceus is one variety with 19 forms (18 plate conditions) and silvally one variety with 18 forms (17 memories). Six varieties also carry more than one condition on the same form (giratina-origin and zygarde-complete, with different triggers per generation). So it would have to be a list.

But once it's a list, nesting it under varieties still splits the data in a way that's awkward to read:

  • 26 of the 146 species that have conditions spread them across several varieties (zygarde across 6, plus aegislash, oricorio, wishiwashi), while arceus and silvally pile 18 into a single entry. The grouping doesn't track anything meaningful.
  • 37 conditions have a base_form pointing at a form that sits under a different variety. Reading a single pair (wishiwashi-solo to wishiwashi-school, darmanitan-zen to darmanitan-standard, greninja-ash to greninja-battle-bond) means hopping between entries of the same list.

So I'd rather put a flat list on the species itself:

"transformations": [
   {"form": {"name": "charizard-mega-x", "url": ".../pokemon-form/10134/"},
    "trigger": "held-item", "item": {"name": "charizardite-x", "url": "..."},
    "ability": null, "move": null, "base_form": null},
   {"form": {"name": "charizard-gmax", "url": ".../pokemon-form/10365/"},
    "trigger": "gigantamax-factor", "item": null, "ability": null, "move": null, "base_form": null}
 ]

Empty for 879 of the 1025 species, one extra query either way, and each pair stays readable in one place.

If you'd still prefer it under varieties, that's fine by me too. I'd just make it a list per variety instead of a single object. Let me know which one you want and I'll rework the PR.

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.

2 participants