Files
sprites/rules/oldgen.ts
Christopher Monsanto d6082eedfc Give the gen 4 CAP prevos a dp sprite
The dex serves /dex/dp/pokemon/embirch/ and the sprite lookup logs a miss for
it, which is not a dex bug: Embirch is an NFE from a gen 4 CAP process, so it
belongs on a gen 4 page. It was drawn in BW's day, like the other twelve prevos
the gen 4 CAPs were given after the fact.

That is what GEN4_CAPS is already for. dp/ has no CAP art of its own -- gen 4
never drew any of it, and nothing in a gen 5 filename says a sprite is a CAP --
so the set names the eleven by hand and lifts them out of the gen 5 stills.
Name the prevos there too, and the same rule draws them: fifteen files, the
thirteen species plus the female slots on Flarelm and Protowatt, each trimmed
the way its evolution is.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 16:05:29 -04:00

80 lines
3.8 KiB
TypeScript

import * as spritedata from '@smogon/sprite-data/index.ts';
import {type Artifact, type CmdSpec, rule} from '../tools/build/artifact.ts';
import {base, glob} from '../tools/build/helpers.ts';
// A source picked for an older-gen collection, and what the sprite built from
// it is called. The two differ because the game is spent on choosing the
// collection: `rb` and `y` are the same Zubat under two palettes, and neither
// output has a game left in its name. Dropping it is not cosmetic. `-g` is
// Gigantamax everywhere the grammar isn't naming a gen 1-4 game, so a name
// that kept it would reach publishedName() as `zubat-gmax`.
export type Front = {
file: string,
name: string,
};
// The gen 1-4 sets are each named for one game and sourced from several. `-g`
// spells the games a picture is the copy for, a letter apiece, and a
// collection takes them in preference order: the game it is named for first,
// then whatever drew the formes that game never did. That is how rs/ comes to
// hold Deoxys-Attack, which only FireRed drew, and dp/ the Rotom appliances
// and Giratina-Origin, which only Platinum did. Which layer wins a name is
// settled at copy time, by whoever claims it first.
//
// Gen 5 has no such axis -- there its `-g` really is Gigantamax -- so its sets
// pass no order, and keep every flag they came with.
export function fronts(pats: string | string[], games?: string): Front[] {
let ranked = [];
for (let file of glob(pats)) {
let sn = spritedata.parseFilename(base(file));
// Backs and shinies go unpublished: the legacy tree kept them in
// subdirectories of their own, under national dex numbers, and
// nothing on the site has ever read one.
if (sn.extra.has('b') || sn.extra.has('s')) {
continue;
}
let rank = 0;
if (games !== undefined) {
let code = sn.extra.get('g') ?? '';
rank = [...games].findIndex(g => code.includes(g));
// Another generation's game, or no game at all: not this set's.
if (rank < 0) {
continue;
}
sn.extra.delete('g');
}
ranked.push({file, name: spritedata.formatFilename(sn), rank});
}
// Stable, so within one game the glob's own order survives.
return ranked.sort((a, b) => a.rank - b.rank).map(({file, name}) => ({file, name}));
}
// One rule per front, its output named for what it publishes. Several sources
// can land on one name -- Abra is the same drawing in Ruby and in Emerald --
// which is fine, since a nominal name is provenance and not identity.
export function forEachFront(files: Front[], spec: CmdSpec, ext: string): Artifact[] {
return files.map(f => rule(f.file, spec, `${f.name}.${ext}`));
}
// The gen 4 CAP families: the eleven CAPs a gen 4 process produced, and the
// prevos later processes gave them. None of it was drawn in gen 4's style --
// the CAPs were only ever drawn in gen 5's, and the prevos did not exist until
// BW -- so dp/ carries the lot from the gen 5 sources, as the legacy set did
// for the eleven. A prevo lands on a gen 4 dex page like its evolution does,
// which is why it is here too. The list is by hand, since nothing in a
// filename says a sprite is a CAP.
export let GEN4_CAPS = [
'arghonaut', 'breezi', 'colossoil', 'cyclohm', 'dorsoil', 'duohm',
'embirch', 'fidgit', 'flarelm', 'kitsunoh', 'krilowatt', 'monohm',
'nohface', 'privatyke', 'protowatt', 'pyroak', 'rebble', 'revenankh',
'stratagem', 'syclant', 'syclar', 'tactite', 'voodoll', 'voodoom',
];
// Every front of the given species, formes and female slots included.
export function named(files: Front[], names: readonly string[]): Front[] {
let want = new Set(names);
return files.filter(f => want.has(spritedata.parseFilename(f.name).name));
}