The French, German, Italian and Spanish releases store Magikarp's length in millimetres (and print a tenth of them), start the Magikarp house's record at their own length and holder, keep Pokédex heights in decimetres and weights in hectograms (printed in metres and kilograms), read the Heavy Ball's weight byte without converting it, and place the enemy's nickname before EnemyText (French, Italian) or the trainer's name before the class (French, Italian, Spanish). map-revision --symbols writes each release's symbol file, so the reference specs run against a release; specs that pin English data skip there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
58 lines
2.0 KiB
TypeScript
58 lines
2.0 KiB
TypeScript
import type { Page } from "@playwright/test";
|
|
import { readFileSync } from "node:fs";
|
|
import { resolve } from "node:path";
|
|
|
|
export const romPath = resolve(
|
|
process.env.CRYSTAL_ROM_PATH ??
|
|
"Pokemon - Crystal Version (UE) (V1.1) [C][!].gbc",
|
|
);
|
|
/** PRET's 1.1 symbols, or CRYSTAL_SYMBOLS_PATH for another cartridge (a
|
|
* release's symbols mapped from 1.1's, as scripts/map-revision.mjs finds
|
|
* its labels). */
|
|
export const symbolsPath = process.env.CRYSTAL_SYMBOLS_PATH ?? ".reference/pokecrystal/pokecrystal11.sym";
|
|
/** PRET's rebuilds of the other English cartridges (`make crystal
|
|
* crystal_au`), which keep 1.1's addresses for every label the port reads. */
|
|
export const revisionRoms = {
|
|
"1.0": resolve(".reference/pokecrystal/pokecrystal.gbc"),
|
|
au: resolve(".reference/pokecrystal/pokecrystal_au.gbc"),
|
|
} as const;
|
|
|
|
/** Banked addresses from the private PRET rebuild's symbol file. */
|
|
export function loadSymbols() {
|
|
const symbols = new Map(
|
|
readFileSync(symbolsPath, "utf8")
|
|
.split("\n")
|
|
.flatMap((line) => {
|
|
const match = /^([0-9a-f]{2}):([0-9a-f]{4}) (\S+)$/.exec(line);
|
|
return match
|
|
? [
|
|
[
|
|
match[3],
|
|
{
|
|
bank: parseInt(match[1], 16),
|
|
address: parseInt(match[2], 16),
|
|
},
|
|
] as const,
|
|
]
|
|
: [];
|
|
}),
|
|
);
|
|
return {
|
|
at: (name: string) => symbols.get(name)!.address,
|
|
routine: (name: string) => symbols.get(name)!,
|
|
};
|
|
}
|
|
|
|
/** Open the reference page and hand it the ROM (by default the user's 1.1)
|
|
* through an isolated file input, without an HTTP ROM endpoint. */
|
|
export async function openReference(page: Page, rom = romPath) {
|
|
await page.goto("/reference.html");
|
|
await page.evaluate(() => {
|
|
const input = document.createElement("input");
|
|
input.type = "file";
|
|
input.id = "reference-fixture";
|
|
document.body.append(input);
|
|
});
|
|
await page.locator("#reference-fixture").setInputFiles(rom);
|
|
}
|