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) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MQicnpaee6kQXGG7uVExLS
This commit is contained in:
Christopher Monsanto
2026-08-21 02:28:14 -04:00
parent 6591abd406
commit a282c8a643
6 changed files with 118 additions and 0 deletions

6
pnpm-lock.yaml generated
View File

@@ -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':

46
tools/spritedata/items.ts Normal file
View File

@@ -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 <pokemon-showdown checkout>');
}
let require = createRequire(import.meta.url);
let {Items} = require(path.resolve(ps, 'dist/data/items.js')) as
{Items: Record<string, ItemsEntry>};
let output: Record<string, ItemEntry> = {};
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, ' '));

View File

@@ -0,0 +1,6 @@
{
"type": "module",
"dependencies": {
"@types/node": "^24.10.7"
}
}

View File

@@ -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 <pokemon-showdown checkout>');
}
let require = createRequire(import.meta.url);
let {Pokedex} = require(path.resolve(ps, 'dist/data/pokedex.js')) as
{Pokedex: Record<string, PokedexEntry>};
let output: Record<string, SpecieEntry> = {};
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');

View File

@@ -0,0 +1,3 @@
{
"extends": "../../tsconfig-base"
}

View File

@@ -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"},