Forms: keep formes that differ only by ability (Basculin, Toxtricity)

The cosmetic-form filter now also requires identical abilities before
dropping a variety, so gameplay-relevant look-alike formes (Basculin
Blue/White-Striped, Toxtricity Low Key) are no longer discarded.
274 forms across the snapshot (+10 'other').

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
chris 2026-08-28 11:14:35 -04:00
parent 40667cbdb6
commit f9f2b8f1e8

View File

@ -192,9 +192,8 @@ async function main() {
};
};
const bstOf = (st) => st.hp + st.atk + st.def + st.spa + st.spd + st.spe;
const sameShape = (a, b) =>
a.types.join() === b.types.join() && a.bst === b.bst &&
a.stats.hp === b.stats.hp && a.stats.spe === b.stats.spe && a.stats.atk === b.stats.atk;
const abilKey = (pk) => pk.abilities.map((a) => a.ability.name).sort().join(',');
const statKey = (st) => `${st.hp}/${st.atk}/${st.def}/${st.spa}/${st.spd}/${st.spe}`;
console.log(`Fetching ${ids.length} species (stats, typings, flags, forms) …`);
const species = await mapLimit(ids, CONCURRENCY, async (id) => {
@ -204,6 +203,8 @@ async function main() {
]);
const stats = statMap(pk);
const baseTypes = pk.types.slice().sort((a, b) => a.slot - b.slot).map((t) => t.type.name);
const baseAbil = abilKey(pk);
const baseStatKey = statKey(stats);
// Non-default varieties = forms (megas, G-max, regional, alt formes).
const variantSlugs = (sp.varieties || [])
@ -231,10 +232,14 @@ async function main() {
height: fp.height,
weight: fp.weight,
};
// Drop purely-cosmetic forms (identical stats & typing, no named category).
if (cat === 'other' && sameShape(entry, { types: baseTypes, bst: bstOf(stats), stats })) {
continue;
}
// Drop purely-cosmetic forms: same typing, stats AND abilities as the
// base, and not a named category (mega/gmax/regional/primal).
const cosmetic =
cat === 'other' &&
ftypes.join() === baseTypes.join() &&
statKey(fstats) === baseStatKey &&
abilKey(fp) === baseAbil;
if (cosmetic) continue;
forms.push(entry);
}