mirror of
https://github.com/smogon/sprites.git
synced 2026-09-27 19:57:47 -05:00
Build the forum's auto avatars, and publish them as a slot table
The forum has carried its default avatars as 702 committed gifs since its initial commit in 2019: bytes in the wrong repo, and the last sprite collection it hadn't moved onto a manifest. The sources are all here, so build them. They are gen 5 animations on a uniform 96x96 box. The box is not decorative: XenForo scales an <img> to fill its avatar container, so a sprite published at its own aspect would arrive stretched. It is also the games' own sprite size, so nothing is scaled up, and the 45 animations that overflow it are cropped to it, which is what the 2019 set did too. The pool is an index, not a set. The forum picks a slot with crc32(username) % count, so a name added, removed or respelled reassigns every user's avatar -- which is why rules/avatars.ts spells the pool out instead of globbing src/sprites/gen5, and why these publish under the PS ids the 2019 set used (`hooh`, not `ho-oh`) rather than the smogon names every other set here publishes. publishedName(sn, psid) spells all but two of them; Arceus-Normal and Swanna-2 were second copies of a picture the pool already carries, and now share its file. What ships is that index rather than a name -> url manifest, because nothing looks an avatar up: __meta/avatars/manifest.json is the directory listing scandir() used to return, as an array of urls. Two things about that listing are the index and so are reproduced rather than tidied away. It sorted filenames with the extension attached, which orders arceus-bug.gif ahead of arceus.gif where the bare names sort the other way, and disagrees with the manifest order at 68 of the 702 slots. And it led with `.` and `..`, which counted toward the divisor and named no avatar: those two rendered a broken image for two of every 704 usernames, and now get Substitute, which the pool already carries, so they cost nothing but the slot. The animations themselves change, unavoidably. The 2019 files came from an earlier generation of these sources: 649 of the 693 that still resolve have a different frame count, and no coalesced frame survives. Same Pokemon, same slot, same framing, re-animated. Manifest grows url(), which write() already composed inline, so a set can publish another projection of the same mapping. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
737
rules/avatars.ts
Normal file
737
rules/avatars.ts
Normal file
@@ -0,0 +1,737 @@
|
||||
|
||||
// The forum's auto avatars: a frozen pool of pictures it assigns to users who
|
||||
// have uploaded none. It picks one with crc32(username) % count, so the pool is
|
||||
// an index and not a set -- a name added, removed or respelled reassigns every
|
||||
// user's avatar. That is why this is a list and not a glob over the gen 5
|
||||
// sources: a sprite landing in src/ must not join the pool on its own.
|
||||
//
|
||||
// The names are the ones the 2019 set was built under, which are PS ids rather
|
||||
// than the smogon names every other set here publishes: `hooh`, not `ho-oh`.
|
||||
// publishedName(sn, psid) spells all but two of them.
|
||||
|
||||
export let AVATARS: string[] = [
|
||||
'abomasnow',
|
||||
'abra',
|
||||
'absol',
|
||||
'accelgor',
|
||||
'aerodactyl',
|
||||
'aggron',
|
||||
'aipom',
|
||||
'alakazam',
|
||||
'alomomola',
|
||||
'altaria',
|
||||
'ambipom',
|
||||
'amoonguss',
|
||||
'ampharos',
|
||||
'anorith',
|
||||
'arbok',
|
||||
'arcanine',
|
||||
'arceus',
|
||||
'arceus-bug',
|
||||
'arceus-dark',
|
||||
'arceus-dragon',
|
||||
'arceus-electric',
|
||||
'arceus-ghost',
|
||||
'arceus-grass',
|
||||
'arceus-ground',
|
||||
'arceus-ice',
|
||||
'arceus-normal',
|
||||
'arceus-poison',
|
||||
'arceus-psychic',
|
||||
'arceus-rock',
|
||||
'arceus-steel',
|
||||
'arceus-water',
|
||||
'archen',
|
||||
'archeops',
|
||||
'ariados',
|
||||
'armaldo',
|
||||
'aron',
|
||||
'articuno',
|
||||
'audino',
|
||||
'aurumoth',
|
||||
'axew',
|
||||
'azelf',
|
||||
'azumarill',
|
||||
'azurill',
|
||||
'bagon',
|
||||
'baltoy',
|
||||
'banette',
|
||||
'barboach',
|
||||
'basculin',
|
||||
'bastiodon',
|
||||
'bayleef',
|
||||
'beartic',
|
||||
'beautifly',
|
||||
'beedrill',
|
||||
'beheeyem',
|
||||
'beldum',
|
||||
'bellossom',
|
||||
'bellsprout',
|
||||
'bibarel',
|
||||
'bidoof',
|
||||
'bisharp',
|
||||
'blastoise',
|
||||
'blaziken',
|
||||
'blissey',
|
||||
'blitzle',
|
||||
'boldore',
|
||||
'bonsly',
|
||||
'bouffalant',
|
||||
'braviary',
|
||||
'breloom',
|
||||
'bronzong',
|
||||
'bronzor',
|
||||
'budew',
|
||||
'buizel',
|
||||
'bulbasaur',
|
||||
'buneary',
|
||||
'burmy',
|
||||
'burmy-sandy',
|
||||
'burmy-trash',
|
||||
'butterfree',
|
||||
'cacnea',
|
||||
'cacturne',
|
||||
'camerupt',
|
||||
'carnivine',
|
||||
'carracosta',
|
||||
'carvanha',
|
||||
'cascoon',
|
||||
'castform',
|
||||
'castform-rainy',
|
||||
'castform-snowy',
|
||||
'castform-sunny',
|
||||
'caterpie',
|
||||
'celebi',
|
||||
'chandelure',
|
||||
'chansey',
|
||||
'charizard',
|
||||
'charmander',
|
||||
'charmeleon',
|
||||
'chatot',
|
||||
'cherrim',
|
||||
'cherrim-sunshine',
|
||||
'cherubi',
|
||||
'chikorita',
|
||||
'chimchar',
|
||||
'chimecho',
|
||||
'chinchou',
|
||||
'chingling',
|
||||
'cinccino',
|
||||
'clamperl',
|
||||
'claydol',
|
||||
'clefable',
|
||||
'clefairy',
|
||||
'cleffa',
|
||||
'cloyster',
|
||||
'cobalion',
|
||||
'cofagrigus',
|
||||
'combee',
|
||||
'combusken',
|
||||
'conkeldurr',
|
||||
'corphish',
|
||||
'corsola',
|
||||
'cottonee',
|
||||
'cradily',
|
||||
'cranidos',
|
||||
'crawdaunt',
|
||||
'cresselia',
|
||||
'croagunk',
|
||||
'crobat',
|
||||
'croconaw',
|
||||
'crustle',
|
||||
'cryogonal',
|
||||
'cubchoo',
|
||||
'cubone',
|
||||
'cyndaquil',
|
||||
'darkrai',
|
||||
'darmanitan',
|
||||
'darmanitan-zen',
|
||||
'darumaka',
|
||||
'deerling',
|
||||
'deerling-autumn',
|
||||
'deerling-summer',
|
||||
'deerling-winter',
|
||||
'deino',
|
||||
'delcatty',
|
||||
'delibird',
|
||||
'deoxys',
|
||||
'deoxys-attack',
|
||||
'deoxys-defense',
|
||||
'deoxys-speed',
|
||||
'dewgong',
|
||||
'dewott',
|
||||
'dialga',
|
||||
'diglett',
|
||||
'ditto',
|
||||
'dodrio',
|
||||
'doduo',
|
||||
'donphan',
|
||||
'dragonair',
|
||||
'dragonite',
|
||||
'drapion',
|
||||
'dratini',
|
||||
'drifblim',
|
||||
'drifloon',
|
||||
'drilbur',
|
||||
'drowzee',
|
||||
'druddigon',
|
||||
'ducklett',
|
||||
'dugtrio',
|
||||
'dunsparce',
|
||||
'duosion',
|
||||
'durant',
|
||||
'dusclops',
|
||||
'dusknoir',
|
||||
'duskull',
|
||||
'dustox',
|
||||
'dwebble',
|
||||
'eelektrik',
|
||||
'eelektross',
|
||||
'eevee',
|
||||
'ekans',
|
||||
'electabuzz',
|
||||
'electivire',
|
||||
'electrike',
|
||||
'electrode',
|
||||
'elekid',
|
||||
'elgyem',
|
||||
'emboar',
|
||||
'emolga',
|
||||
'empoleon',
|
||||
'entei',
|
||||
'escavalier',
|
||||
'espeon',
|
||||
'excadrill',
|
||||
'exeggcute',
|
||||
'exeggutor',
|
||||
'exploud',
|
||||
'farfetchd',
|
||||
'fearow',
|
||||
'feebas',
|
||||
'feraligatr',
|
||||
'ferroseed',
|
||||
'ferrothorn',
|
||||
'finneon',
|
||||
'flaaffy',
|
||||
'flareon',
|
||||
'floatzel',
|
||||
'flygon',
|
||||
'foongus',
|
||||
'forretress',
|
||||
'fraxure',
|
||||
'frillish',
|
||||
'froslass',
|
||||
'furret',
|
||||
'gabite',
|
||||
'gallade',
|
||||
'galvantula',
|
||||
'garbodor',
|
||||
'garchomp',
|
||||
'gardevoir',
|
||||
'gastly',
|
||||
'gastrodon',
|
||||
'gastrodon-east',
|
||||
'genesect',
|
||||
'gengar',
|
||||
'geodude',
|
||||
'gible',
|
||||
'gigalith',
|
||||
'girafarig',
|
||||
'giratina',
|
||||
'giratina-origin',
|
||||
'glaceon',
|
||||
'glalie',
|
||||
'glameow',
|
||||
'gligar',
|
||||
'gliscor',
|
||||
'gloom',
|
||||
'golbat',
|
||||
'goldeen',
|
||||
'golduck',
|
||||
'golem',
|
||||
'golett',
|
||||
'golurk',
|
||||
'gorebyss',
|
||||
'gothita',
|
||||
'gothitelle',
|
||||
'gothorita',
|
||||
'granbull',
|
||||
'graveler',
|
||||
'grimer',
|
||||
'grotle',
|
||||
'groudon',
|
||||
'grovyle',
|
||||
'growlithe',
|
||||
'grumpig',
|
||||
'gulpin',
|
||||
'gurdurr',
|
||||
'gyarados',
|
||||
'happiny',
|
||||
'hariyama',
|
||||
'haunter',
|
||||
'haxorus',
|
||||
'heatmor',
|
||||
'heatran',
|
||||
'heracross',
|
||||
'herdier',
|
||||
'hippopotas',
|
||||
'hippowdon',
|
||||
'hitmonchan',
|
||||
'hitmonlee',
|
||||
'hitmontop',
|
||||
'honchkrow',
|
||||
'hooh',
|
||||
'hoothoot',
|
||||
'hoppip',
|
||||
'horsea',
|
||||
'houndoom',
|
||||
'houndour',
|
||||
'huntail',
|
||||
'hydreigon',
|
||||
'hypno',
|
||||
'igglybuff',
|
||||
'illumise',
|
||||
'infernape',
|
||||
'ivysaur',
|
||||
'jellicent',
|
||||
'jigglypuff',
|
||||
'jirachi',
|
||||
'jolteon',
|
||||
'joltik',
|
||||
'jumpluff',
|
||||
'jynx',
|
||||
'kabuto',
|
||||
'kabutops',
|
||||
'kadabra',
|
||||
'kakuna',
|
||||
'kangaskhan',
|
||||
'karrablast',
|
||||
'kecleon',
|
||||
'keldeo',
|
||||
'keldeo-resolute',
|
||||
'kingdra',
|
||||
'kingler',
|
||||
'kirlia',
|
||||
'klang',
|
||||
'klink',
|
||||
'klinklang',
|
||||
'koffing',
|
||||
'krabby',
|
||||
'kricketot',
|
||||
'kricketune',
|
||||
'krokorok',
|
||||
'krookodile',
|
||||
'kyogre',
|
||||
'kyurem',
|
||||
'kyurem-black',
|
||||
'kyurem-white',
|
||||
'lairon',
|
||||
'lampent',
|
||||
'landorus',
|
||||
'landorus-therian',
|
||||
'lanturn',
|
||||
'lapras',
|
||||
'larvesta',
|
||||
'larvitar',
|
||||
'latias',
|
||||
'latios',
|
||||
'leafeon',
|
||||
'leavanny',
|
||||
'ledian',
|
||||
'ledyba',
|
||||
'lickilicky',
|
||||
'lickitung',
|
||||
'liepard',
|
||||
'lileep',
|
||||
'lilligant',
|
||||
'lillipup',
|
||||
'linoone',
|
||||
'litwick',
|
||||
'lombre',
|
||||
'lopunny',
|
||||
'lotad',
|
||||
'loudred',
|
||||
'lucario',
|
||||
'ludicolo',
|
||||
'lugia',
|
||||
'lumineon',
|
||||
'lunatone',
|
||||
'luvdisc',
|
||||
'luxio',
|
||||
'luxray',
|
||||
'machamp',
|
||||
'machoke',
|
||||
'machop',
|
||||
'magby',
|
||||
'magcargo',
|
||||
'magikarp',
|
||||
'magmar',
|
||||
'magmortar',
|
||||
'magnemite',
|
||||
'magneton',
|
||||
'magnezone',
|
||||
'makuhita',
|
||||
'malaconda',
|
||||
'mamoswine',
|
||||
'manaphy',
|
||||
'mandibuzz',
|
||||
'manectric',
|
||||
'mankey',
|
||||
'mantine',
|
||||
'mantyke',
|
||||
'maractus',
|
||||
'mareep',
|
||||
'marill',
|
||||
'marowak',
|
||||
'marshtomp',
|
||||
'masquerain',
|
||||
'mawile',
|
||||
'medicham',
|
||||
'meditite',
|
||||
'meganium',
|
||||
'meloetta',
|
||||
'meloetta-pirouette',
|
||||
'meowth',
|
||||
'mesprit',
|
||||
'metagross',
|
||||
'metang',
|
||||
'metapod',
|
||||
'mew',
|
||||
'mewtwo',
|
||||
'mienfoo',
|
||||
'mienshao',
|
||||
'mightyena',
|
||||
'milotic',
|
||||
'miltank',
|
||||
'mimejr',
|
||||
'minccino',
|
||||
'minun',
|
||||
'misdreavus',
|
||||
'mismagius',
|
||||
'mollux',
|
||||
'moltres',
|
||||
'monferno',
|
||||
'mothim',
|
||||
'mrmime',
|
||||
'mudkip',
|
||||
'muk',
|
||||
'munchlax',
|
||||
'munna',
|
||||
'murkrow',
|
||||
'musharna',
|
||||
'natu',
|
||||
'necturna',
|
||||
'nidoking',
|
||||
'nidoqueen',
|
||||
'nidoranf',
|
||||
'nidoranm',
|
||||
'nidorina',
|
||||
'nidorino',
|
||||
'nincada',
|
||||
'ninetales',
|
||||
'ninjask',
|
||||
'noctowl',
|
||||
'nosepass',
|
||||
'numel',
|
||||
'nuzleaf',
|
||||
'octillery',
|
||||
'oddish',
|
||||
'omanyte',
|
||||
'omastar',
|
||||
'onix',
|
||||
'oshawott',
|
||||
'pachirisu',
|
||||
'palkia',
|
||||
'palpitoad',
|
||||
'panpour',
|
||||
'pansage',
|
||||
'pansear',
|
||||
'paras',
|
||||
'parasect',
|
||||
'patrat',
|
||||
'pawniard',
|
||||
'pelipper',
|
||||
'persian',
|
||||
'petilil',
|
||||
'phanpy',
|
||||
'phione',
|
||||
'pichu',
|
||||
'pidgeot',
|
||||
'pidgeotto',
|
||||
'pidgey',
|
||||
'pidove',
|
||||
'pignite',
|
||||
'pikachu',
|
||||
'piloswine',
|
||||
'pineco',
|
||||
'pinsir',
|
||||
'piplup',
|
||||
'plusle',
|
||||
'politoed',
|
||||
'poliwag',
|
||||
'poliwhirl',
|
||||
'poliwrath',
|
||||
'ponyta',
|
||||
'poochyena',
|
||||
'porygon',
|
||||
'porygon2',
|
||||
'porygonz',
|
||||
'primeape',
|
||||
'prinplup',
|
||||
'probopass',
|
||||
'psyduck',
|
||||
'pupitar',
|
||||
'purrloin',
|
||||
'purugly',
|
||||
'quagsire',
|
||||
'quilava',
|
||||
'qwilfish',
|
||||
'raichu',
|
||||
'raikou',
|
||||
'ralts',
|
||||
'rampardos',
|
||||
'rapidash',
|
||||
'raticate',
|
||||
'rattata',
|
||||
'rayquaza',
|
||||
'regice',
|
||||
'regigigas',
|
||||
'regirock',
|
||||
'registeel',
|
||||
'relicanth',
|
||||
'remoraid',
|
||||
'reshiram',
|
||||
'reuniclus',
|
||||
'rhydon',
|
||||
'rhyhorn',
|
||||
'rhyperior',
|
||||
'riolu',
|
||||
'roggenrola',
|
||||
'roselia',
|
||||
'roserade',
|
||||
'rotom',
|
||||
'rotom-heat',
|
||||
'rotom-mow',
|
||||
'rotom-wash',
|
||||
'rufflet',
|
||||
'sableye',
|
||||
'salamence',
|
||||
'samurott',
|
||||
'sandile',
|
||||
'sandshrew',
|
||||
'sandslash',
|
||||
'sawk',
|
||||
'sawsbuck',
|
||||
'sawsbuck-autumn',
|
||||
'sawsbuck-summer',
|
||||
'sawsbuck-winter',
|
||||
'sceptile',
|
||||
'scizor',
|
||||
'scolipede',
|
||||
'scrafty',
|
||||
'scraggy',
|
||||
'scyther',
|
||||
'seadra',
|
||||
'seaking',
|
||||
'sealeo',
|
||||
'seedot',
|
||||
'seel',
|
||||
'seismitoad',
|
||||
'sentret',
|
||||
'serperior',
|
||||
'servine',
|
||||
'seviper',
|
||||
'sewaddle',
|
||||
'sharpedo',
|
||||
'shaymin',
|
||||
'shaymin-sky',
|
||||
'shedinja',
|
||||
'shelgon',
|
||||
'shellder',
|
||||
'shellos',
|
||||
'shellos-east',
|
||||
'shelmet',
|
||||
'shieldon',
|
||||
'shiftry',
|
||||
'shinx',
|
||||
'shroomish',
|
||||
'shuckle',
|
||||
'shuppet',
|
||||
'sigilyph',
|
||||
'silcoon',
|
||||
'simipour',
|
||||
'simisage',
|
||||
'simisear',
|
||||
'skarmory',
|
||||
'skiploom',
|
||||
'skitty',
|
||||
'skorupi',
|
||||
'skuntank',
|
||||
'slaking',
|
||||
'slakoth',
|
||||
'slowbro',
|
||||
'slowking',
|
||||
'slowpoke',
|
||||
'slugma',
|
||||
'smeargle',
|
||||
'smoochum',
|
||||
'sneasel',
|
||||
'snivy',
|
||||
'snorlax',
|
||||
'snorunt',
|
||||
'snover',
|
||||
'snubbull',
|
||||
'solosis',
|
||||
'solrock',
|
||||
'spearow',
|
||||
'spheal',
|
||||
'spinarak',
|
||||
'spinda',
|
||||
'spiritomb',
|
||||
'spoink',
|
||||
'squirtle',
|
||||
'stantler',
|
||||
'staraptor',
|
||||
'staravia',
|
||||
'starly',
|
||||
'starmie',
|
||||
'staryu',
|
||||
'steelix',
|
||||
'stoutland',
|
||||
'stunfisk',
|
||||
'stunky',
|
||||
'substitute',
|
||||
'sudowoodo',
|
||||
'suicune',
|
||||
'sunflora',
|
||||
'sunkern',
|
||||
'surskit',
|
||||
'swablu',
|
||||
'swadloon',
|
||||
'swalot',
|
||||
'swampert',
|
||||
'swanna',
|
||||
'swanna-2',
|
||||
'swellow',
|
||||
'swinub',
|
||||
'swoobat',
|
||||
'taillow',
|
||||
'tangela',
|
||||
'tangrowth',
|
||||
'tauros',
|
||||
'teddiursa',
|
||||
'tentacool',
|
||||
'tentacruel',
|
||||
'tepig',
|
||||
'terrakion',
|
||||
'throh',
|
||||
'thundurus',
|
||||
'thundurus-therian',
|
||||
'timburr',
|
||||
'tirtouga',
|
||||
'togekiss',
|
||||
'togepi',
|
||||
'togetic',
|
||||
'tomohawk',
|
||||
'torchic',
|
||||
'torkoal',
|
||||
'tornadus',
|
||||
'tornadus-therian',
|
||||
'torterra',
|
||||
'totodile',
|
||||
'toxicroak',
|
||||
'tranquill',
|
||||
'trapinch',
|
||||
'treecko',
|
||||
'tropius',
|
||||
'trubbish',
|
||||
'turtwig',
|
||||
'tympole',
|
||||
'tynamo',
|
||||
'typhlosion',
|
||||
'tyranitar',
|
||||
'tyrogue',
|
||||
'umbreon',
|
||||
'unfezant',
|
||||
'unown',
|
||||
'ursaring',
|
||||
'uxie',
|
||||
'vanillish',
|
||||
'vanillite',
|
||||
'vanilluxe',
|
||||
'vaporeon',
|
||||
'venipede',
|
||||
'venomoth',
|
||||
'venonat',
|
||||
'venusaur',
|
||||
'vespiquen',
|
||||
'vibrava',
|
||||
'victini',
|
||||
'victreebel',
|
||||
'vigoroth',
|
||||
'vileplume',
|
||||
'virizion',
|
||||
'volbeat',
|
||||
'volcarona',
|
||||
'voltorb',
|
||||
'vullaby',
|
||||
'vulpix',
|
||||
'wailmer',
|
||||
'wailord',
|
||||
'walrein',
|
||||
'wartortle',
|
||||
'watchog',
|
||||
'weavile',
|
||||
'weedle',
|
||||
'weepinbell',
|
||||
'weezing',
|
||||
'whimsicott',
|
||||
'whirlipede',
|
||||
'whiscash',
|
||||
'whismur',
|
||||
'wigglytuff',
|
||||
'wingull',
|
||||
'wobbuffet',
|
||||
'woobat',
|
||||
'wooper',
|
||||
'wormadam',
|
||||
'wormadam-sandy',
|
||||
'wormadam-trash',
|
||||
'wurmple',
|
||||
'wynaut',
|
||||
'xatu',
|
||||
'yamask',
|
||||
'yanma',
|
||||
'yanmega',
|
||||
'zangoose',
|
||||
'zapdos',
|
||||
'zebstrika',
|
||||
'zekrom',
|
||||
'zigzagoon',
|
||||
'zoroark',
|
||||
'zorua',
|
||||
'zubat',
|
||||
'zweilous',
|
||||
];
|
||||
|
||||
// Two names the 2019 tree carried a second copy of. Swanna's two files were
|
||||
// byte for byte the same picture; Arceus and Arceus-Normal were two palettes of
|
||||
// one pose, and only the one is drawn today. Both spend their slot on the
|
||||
// picture already in the pool.
|
||||
export let AVATAR_ALIASES: Record<string, string> = {
|
||||
'arceus-normal': 'arceus',
|
||||
'swanna-2': 'swanna',
|
||||
};
|
||||
|
||||
// The pool in the order the forum indexes it, which is the directory listing
|
||||
// scandir() used to return. Two things about that listing are the index and so
|
||||
// are reproduced rather than tidied away: it sorted filenames with the
|
||||
// extension attached, which orders `arceus-bug.gif` ahead of `arceus.gif` where
|
||||
// the bare names sort the other way round, and it led with `.` and `..`, which
|
||||
// named no avatar but counted toward the divisor. Those two slots rendered a
|
||||
// broken image; they get Substitute, which the pool already carries, so they
|
||||
// cost nothing but the slot.
|
||||
export function avatarSlots(): string[] {
|
||||
let files = [...AVATARS].sort((a, b) => `${a}.gif` < `${b}.gif` ? -1 : 1);
|
||||
return ['substitute', 'substitute', ...files];
|
||||
}
|
||||
@@ -55,10 +55,20 @@ export class Manifest {
|
||||
this.#ctx.copy(f, `${this.#tree.root}/${dir}/${stamped}`);
|
||||
}
|
||||
|
||||
// The whole url the copy `name` answers to. Exposed on its own for a set
|
||||
// that publishes some other projection of this mapping than write()'s.
|
||||
url(name: string): string {
|
||||
let e = this.#entries.get(name);
|
||||
if (e === undefined) {
|
||||
throw new Error(`no sprite named ${name}`);
|
||||
}
|
||||
return `${this.#tree.served}/${e.dir}/${e.stamped}`;
|
||||
}
|
||||
|
||||
write(dst: string): void {
|
||||
let sorted: Record<string, string> = {};
|
||||
for (let [k, e] of this.#sorted()) {
|
||||
sorted[k] = `${this.#tree.served}/${e.dir}/${e.stamped}`;
|
||||
for (let [k] of this.#sorted()) {
|
||||
sorted[k] = this.url(k);
|
||||
}
|
||||
this.#ctx.write(dst, JSON.stringify(sorted, null, 4) + '\n');
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
|
||||
import * as spritedata from '@smogon/sprite-data/index.ts';
|
||||
|
||||
import {AVATARS, AVATAR_ALIASES, avatarSlots} from './rules/avatars.ts';
|
||||
import {gen10Modelslike} from './rules/modelslike.ts';
|
||||
import {GEN4_CAPS, forEachFront, fronts, named} from './rules/oldgen.ts';
|
||||
import {Manifest, type Sprite, type Tree, firstWins, itemspritecopy, spritecopy} from './rules/publish.ts';
|
||||
import {type CmdSpec, forEachRule, rule} from './tools/build/artifact.ts';
|
||||
import {compresspng, pad, spriteglob, trimimg} from './tools/build/helpers.ts';
|
||||
import {type Artifact, type CmdSpec, forEachRule, rule} from './tools/build/artifact.ts';
|
||||
import {base, compresspng, pad, spriteglob, trimimg} from './tools/build/helpers.ts';
|
||||
import {type DeployCtx, deploy} from './tools/deploy/api.ts';
|
||||
|
||||
// The tar root maps onto the served tree: sprites/x is served at
|
||||
@@ -220,6 +223,60 @@ deploy(async ctx => {
|
||||
manifest.write('__meta/forumsprites/manifest.json');
|
||||
});
|
||||
|
||||
// Forum auto avatars: the gen 5 animations on a uniform 96x96 box, which is
|
||||
// what XenForo's avatar container is. It scales an <img> to fill, so a sprite
|
||||
// published at its own aspect would arrive stretched; the box is the games' own
|
||||
// sprite size, so nothing is scaled up, and the few animations that overflow it
|
||||
// are cropped to it, which is what the set the forum used to carry did too.
|
||||
|
||||
// The pool with its two second slots resolved, which is the set of pictures to
|
||||
// build. See rules/avatars.ts for why it is a list and not a glob.
|
||||
let avatarPool = new Set(AVATARS.map(name => AVATAR_ALIASES[name] ?? name));
|
||||
|
||||
let avatarArt = new Map<string, Artifact>();
|
||||
for (let f of spriteglob(['src/sprites/gen5/*.gif', 'src/sprites/gen5/xsubstitute.png'],
|
||||
{b: false, s: false})) {
|
||||
// publishedNames() is no use here: it resolves smogon names where the pool
|
||||
// is spelled in PS ids, and it refuses the one x-kind sprite the pool
|
||||
// carries. Backs and shinies are filtered above rather than here, since
|
||||
// publishedName spells them exactly as it spells their front.
|
||||
let name = spritedata.publishedName(spritedata.parseFilename(base(f)), spritedata.psid);
|
||||
if (!avatarPool.has(name)) {
|
||||
continue;
|
||||
}
|
||||
if (avatarArt.has(name)) {
|
||||
throw new Error(`avatar ${name}: two gen 5 sources publish it`);
|
||||
}
|
||||
avatarArt.set(name, rule(f, {
|
||||
display: 'avatar %f',
|
||||
cmds: [
|
||||
'magick convert %f -coalesce -background none -gravity center -extent 96x96 %o',
|
||||
'gifsicle -O3 -b %o',
|
||||
],
|
||||
}, `${name}.gif`));
|
||||
}
|
||||
|
||||
// A pool member with no source would leave the forum a shorter list and
|
||||
// reassign every user, so a source renamed out from under one fails the build
|
||||
// rather than the deploy.
|
||||
for (let name of avatarPool) {
|
||||
if (!avatarArt.has(name)) {
|
||||
throw new Error(`avatar ${name}: no gen 5 source`);
|
||||
}
|
||||
}
|
||||
|
||||
deploy(async ctx => {
|
||||
let manifest = new Manifest(ctx, TREE);
|
||||
for (let [name, art] of avatarArt) {
|
||||
await manifest.copy(art, {dir: 'avatars'}, name);
|
||||
}
|
||||
// Published by slot rather than by name: nothing looks an avatar up, the
|
||||
// forum picks one with crc32(username) % count, so the order is the whole
|
||||
// mapping and the length is the divisor.
|
||||
let slots = avatarSlots().map(name => manifest.url(AVATAR_ALIASES[name] ?? name));
|
||||
ctx.write('__meta/avatars/manifest.json', JSON.stringify(slots, null, 4) + '\n');
|
||||
});
|
||||
|
||||
// PMD sprites ship as-is, stamped.
|
||||
|
||||
deploy(async ctx => {
|
||||
|
||||
Reference in New Issue
Block a user