Add native Crystal exploration port and reference tooling
Checks / web (push) Canceled after 0s

This commit is contained in:
Sébastien QUEROL committed 2026-09-23 09:23:29 +02:00
1 parent 2127f5f459
commit 8b80d05ca2
56 files changed
+6910 -1

No files matched your search

+127
View File
@@ -0,0 +1,127 @@
import { RomReader } from "../rom/reader";
const CHARACTERS: Record<number, string> = {
0x1f: " ",
0x22: "\n",
0x25: "",
0x49: "MOM",
0x4a: "Pokémon",
0x4b: "\n",
0x4c: "\n",
0x4e: "\n",
0x4f: "\n",
0x51: "\n\n",
0x53: "???",
0x54: "POKé",
0x55: "\n",
0x56: "……",
0x5b: "PC",
0x5c: "TM",
0x5d: "TRAINER",
0x5e: "ROCKET",
0x70: "PO",
0x71: "Ké",
0x72: "“",
0x73: "”",
0x74: "·",
0x75: "…",
0x7f: " ",
0x9a: "(",
0x9b: ")",
0x9c: ":",
0x9d: ";",
0x9e: "[",
0x9f: "]",
0xc0: "Ä",
0xc1: "Ö",
0xc2: "Ü",
0xc3: "ä",
0xc4: "ö",
0xc5: "ü",
0xd0: "'d",
0xd1: "'l",
0xd2: "'m",
0xd3: "'r",
0xd4: "'s",
0xd5: "'t",
0xd6: "'v",
0xdf: "←",
0xe0: "'",
0xe1: "POKé",
0xe2: "MON",
0xe3: "-",
0xe6: "?",
0xe7: "!",
0xe8: ".",
0xe9: "&",
0xea: "é",
0xeb: "→",
0xec: "▷",
0xed: "▶",
0xee: "▼",
0xef: "♂",
0xf0: "¥",
0xf1: "×",
0xf2: ".",
0xf3: "/",
0xf4: ",",
0xf5: "♀",
};
export class UnsupportedText extends Error {
constructor(
readonly offset: number,
readonly opcode: number,
) {
super(
`Text command 0x${opcode.toString(16)} at 0x${offset.toString(16)} is not ported.`,
);
}
}
export function readText(
reader: RomReader,
start: number,
playerName: string,
depth = 0,
): string {
if (depth > 8) throw new Error("Text calls exceed the recursion limit.");
let p = start,
output = "";
for (let count = 0; count < 8192; count++) {
const commandOffset = p,
command = reader.byte(p++);
if (command === 0x50) return output.trim();
if (command === 0x16) {
output += readText(
reader,
reader.near(p, reader.byte(p + 2)),
playerName,
depth + 1,
);
p += 3;
continue;
}
if (command !== 0) throw new UnsupportedText(commandOffset, command);
let ended = false;
for (let length = 0; length < 8192; length++) {
const offset = p,
code = reader.byte(p++);
if (code === 0x57 || code === 0x58) return output.trim();
if (code === 0x50) {
ended = true;
break;
}
if (code === 0x52 || code === 0x14) output += playerName;
else if (code >= 0x80 && code <= 0x99)
output += String.fromCharCode(65 + code - 0x80);
else if (code >= 0xa0 && code <= 0xb9)
output += String.fromCharCode(97 + code - 0xa0);
else if (code >= 0xf6) output += String(code - 0xf6);
else if (CHARACTERS[code] !== undefined) output += CHARACTERS[code];
else throw new UnsupportedText(offset, code);
}
if (!ended) throw new Error("Unterminated text.");
}
throw new Error("Text command limit exceeded.");
}