diff --git a/rules/publish.ts b/rules/publish.ts index f1383bad..984b92dd 100644 --- a/rules/publish.ts +++ b/rules/publish.ts @@ -64,25 +64,34 @@ function extOf(f: Sprite, ext?: string): string { return result; } -export async function spritecopy(manifest: Manifest, f: Sprite, dest: Dest, - allowUnknown = false): Promise { +// The names a sprite publishes under on the smogon side, or none where it +// isn't published at all. A set that backfills another needs this before it +// copies, since the mapping isn't one name per filename in either direction: +// Meowstic answers to two, and the forme slots the games gave one sprite (the +// six Minior meteors, Zygarde's Power Construct pair) answer to the same one. +export function publishedNames(f: Sprite, allowUnknown = false): string[] { let sn = spritedata.parseFilename(f.name); // Skip asymmetrical for now if (sn.extra.has('a') || sn.extra.has('b') || sn.extra.has('s')) { - return; + return []; } if (sn.kind === 'x') { // Skip these, we don't use Unknown/Substitute if (!allowUnknown || sn.name !== 'unknown') { - return; + return []; } } else if (sn.kind !== 's') { throw new Error(`Not a specie sprite: ${f.name}`); } - for (let name of spritedata.smogonNames(sn)) { + return spritedata.smogonNames(sn); +} + +export async function spritecopy(manifest: Manifest, f: Sprite, dest: Dest, + allowUnknown = false): Promise { + for (let name of publishedNames(f, allowUnknown)) { await manifest.copy(f, dest, name); } } diff --git a/smogon.build.ts b/smogon.build.ts index aeb06b35..013329f1 100644 --- a/smogon.build.ts +++ b/smogon.build.ts @@ -1,6 +1,6 @@ import {gen10Modelslike} from './rules/modelslike.ts'; -import {Manifest, type Sprite, spritecopy} from './rules/publish.ts'; +import {Manifest, type Sprite, publishedNames, spritecopy} from './rules/publish.ts'; import {forEachRule} from './tools/build/artifact.ts'; import {compresspng, trimimg} from './tools/build/helpers.ts'; import {deploy} from './tools/deploy/api.ts'; @@ -19,7 +19,9 @@ let xyModels = forEachRule('src/gen9species/*.png', { let xyChampions = gen10Modelslike(); -// Non-model gen 5 CAPs. +// Whatever the models don't cover, in gen 5 style: the CAPs that never got a +// model, and, since the Smogon Sprite Project's batch landed, the Gigantamax +// formes and a few others. let xyGen5 = forEachRule('src/sprites/gen5/*.png', [ // TODO, add customizable compression for gif @@ -29,14 +31,22 @@ let xyGen5 = forEachRule('src/sprites/gen5/*.png', [ ], '%B.gif'); deploy(async ctx => { - let seenModels = new Set(); + let seen = new Set(); let manifest = new Manifest(ctx); + // First source wins per published name rather than per filename, because + // the later sources are backfills and a name can be spelled more than one + // way. gen 5 carries a sprite per forme slot, so its six Minior meteors + // and two Zygarde Power Construct slots all want the name the models + // already publish, which the manifest would reject as a duplicate. let xycopy = async (f: Sprite) => { - if (seenModels.has(f.name)) { + let names = publishedNames(f); + if (names.some(n => seen.has(n))) { return; } - seenModels.add(f.name); - await spritecopy(manifest, f, {dir: 'xy'}); + for (let name of names) { + seen.add(name); + await manifest.copy(f, {dir: 'xy'}, name); + } }; for (let f of await ctx.list('src/models')) { @@ -48,7 +58,6 @@ deploy(async ctx => { for (let f of xyChampions) { await xycopy(f); } - // Non-model CAPs for (let f of await ctx.list('src/sprites/gen5')) { if (f.ext === 'gif') { await xycopy(f);