From a282c8a643051ec32a0857d568c87a5672d19b8b Mon Sep 17 00:00:00 2001 From: Christopher Monsanto Date: Fri, 21 Aug 2026 02:28:14 -0400 Subject: [PATCH] Bring the data table generators into the repo data/species.json and data/items.json were generated by scripts that lived outside the tree, so nothing here recorded where the tables came from or how to refresh them. Port both into tools/spritedata/, taking the pokemon-showdown checkout as an argument instead of hardcoding an absolute path. Both reproduce the committed tables byte-identically against pokemon-showdown f2fe71c87. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01MQicnpaee6kQXGG7uVExLS --- pnpm-lock.yaml | 6 ++++ tools/spritedata/items.ts | 46 ++++++++++++++++++++++++++++ tools/spritedata/package.json | 6 ++++ tools/spritedata/species.ts | 56 ++++++++++++++++++++++++++++++++++ tools/spritedata/tsconfig.json | 3 ++ tsconfig-workspace.json | 1 + 6 files changed, 118 insertions(+) create mode 100644 tools/spritedata/items.ts create mode 100644 tools/spritedata/package.json create mode 100644 tools/spritedata/species.ts create mode 100644 tools/spritedata/tsconfig.json diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 54390aa2..3257f5d5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -82,6 +82,12 @@ importers: specifier: ^3.4.1 version: 3.5.1 + tools/spritedata: + dependencies: + '@types/node': + specifier: ^24.10.7 + version: 24.13.3 + tools/trim: dependencies: '@types/node': diff --git a/tools/spritedata/items.ts b/tools/spritedata/items.ts new file mode 100644 index 00000000..ea98d486 --- /dev/null +++ b/tools/spritedata/items.ts @@ -0,0 +1,46 @@ +import {createRequire} from 'node:module'; +import * as path from 'node:path'; + +// Regenerates data/items.json from a pokemon-showdown checkout: +// +// node tools/spritedata/items.ts ~/smogon/pokemon-showdown > data/items.json +// +// One sprite per item number, so items that share a number share a sprite and +// collect their names in one entry: Aspear Berry is also Burnt Berry. + +type ItemEntry = { + type: 'item', + names: string[], + sid: string +}; + +type ItemsEntry = { + num: number, + name: string +}; + +let ps = process.argv[2]; +if (!ps) { + throw new Error('usage: node tools/spritedata/items.ts '); +} + +let require = createRequire(import.meta.url); +let {Items} = require(path.resolve(ps, 'dist/data/items.js')) as + {Items: Record}; + +let output: Record = {}; + +for (let {num, name} of Object.values(Items)) { + let sid = Math.abs(num); + if (num < 0) sid |= 1 << 29; + + let key = `i${sid}`; + let entry = output[key]; + if (entry) { + entry.names.push(name); + } else { + output[key] = {type: 'item', names: [name], sid: key}; + } +} + +process.stdout.write(JSON.stringify(output, null, ' ')); diff --git a/tools/spritedata/package.json b/tools/spritedata/package.json new file mode 100644 index 00000000..5432c01b --- /dev/null +++ b/tools/spritedata/package.json @@ -0,0 +1,6 @@ +{ + "type": "module", + "dependencies": { + "@types/node": "^24.10.7" + } +} diff --git a/tools/spritedata/species.ts b/tools/spritedata/species.ts new file mode 100644 index 00000000..09b2fb85 --- /dev/null +++ b/tools/spritedata/species.ts @@ -0,0 +1,56 @@ +import {createRequire} from 'node:module'; +import * as path from 'node:path'; + +// Regenerates data/species.json from a pokemon-showdown checkout: +// +// node tools/spritedata/species.ts ~/smogon/pokemon-showdown > data/species.json +// +// A sprite id packs the dex number and the game's forme index into one number, +// with bit 29 marking the negative nums CAP and fakemon use. Gmax formes get no +// id of their own; they ride on the base forme's -g flag. + +type SpecieEntry = { + type: 'specie', + num: number, + formeNum: number, + base: string, + forme: string, + sid: string +}; + +type PokedexEntry = { + num: number, + name: string, + baseSpecies?: string, + formeOrder?: string[] +}; + +let ps = process.argv[2]; +if (!ps) { + throw new Error('usage: node tools/spritedata/species.ts '); +} + +let require = createRequire(import.meta.url); +let {Pokedex} = require(path.resolve(ps, 'dist/data/pokedex.js')) as + {Pokedex: Record}; + +let output: Record = {}; + +for (let {num, name, baseSpecies, formeOrder} of Object.values(Pokedex)) { + // Formes are enumerated from their base species, not on their own. + if (baseSpecies) continue; + for (let [formeNum, formeName] of (formeOrder ?? [name]).entries()) { + // Gmax is a flag, not a forme. + if (formeName.endsWith('-Gmax')) continue; + + let sid = (Math.abs(num) << 5) + formeNum; + if (num < 0) sid |= 1 << 29; + + let forme = formeName.slice(name.length + 1); + let key = `s${sid}`; + if (output[key]) throw new Error(`duplicate sid ${key} for ${name}`); + output[key] = {type: 'specie', num, formeNum, base: name, forme, sid: key}; + } +} + +process.stdout.write(JSON.stringify(output, null, ' ') + '\n'); diff --git a/tools/spritedata/tsconfig.json b/tools/spritedata/tsconfig.json new file mode 100644 index 00000000..3e88c180 --- /dev/null +++ b/tools/spritedata/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig-base" +} diff --git a/tsconfig-workspace.json b/tsconfig-workspace.json index 5b7e972a..d25a7ab4 100644 --- a/tsconfig-workspace.json +++ b/tsconfig-workspace.json @@ -6,6 +6,7 @@ {"path": "tools/deploy"}, {"path": "tools/sheet"}, {"path": "tools/smogdexspritesheet"}, + {"path": "tools/spritedata"}, {"path": "tools/trim"}, {"path": "lib/root"}, {"path": "data/lib"},