silphscope 1.2.31 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/main.js +2 -2
- package/move-data/moveData.json +5940 -0
- package/move-data/moveStructData.json +3802 -0
- package/move-data/unusedTags.json +986 -0
- package/package.json +7 -2
- package/rom-configs/firered.js +2 -0
- package/src/graphics/graphics-extractor-main.js +25 -3
- package/src/graphics/icons/render-icons.js +1 -1
- package/src/graphics/moves/render-moves.js +85 -0
- package/src/graphics/moves/resolvers/move-pal-resolver.js +10 -0
- package/src/graphics/moves/resolvers/move-pic-resolver.js +10 -0
- package/src/icon-data-parser.js +0 -30
- package/src/mon-data-parser.js +0 -118
- package/src/trainer-data-parser.js +0 -29
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "silphscope",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "A firered/leafgreen ROM asset extractor for use in web applications",
|
|
5
5
|
"main": "main.js",
|
|
6
6
|
"exports": {
|
|
@@ -17,7 +17,12 @@
|
|
|
17
17
|
"rom-maps/",
|
|
18
18
|
"item-data/",
|
|
19
19
|
"trainer-data",
|
|
20
|
-
"rom-configs/"
|
|
20
|
+
"rom-configs/",
|
|
21
|
+
"move-data/",
|
|
22
|
+
"!src/icon-data-parser.js",
|
|
23
|
+
"!src/mon-data-parser.js",
|
|
24
|
+
"!src/trainer-data-parser.js",
|
|
25
|
+
"!src/move-data-parser.js"
|
|
21
26
|
],
|
|
22
27
|
"keywords": [],
|
|
23
28
|
"author": "chickenPoo",
|
package/rom-configs/firered.js
CHANGED
|
@@ -19,5 +19,7 @@ export const firered = {
|
|
|
19
19
|
trainerBackPicTable: 0x239FA4,
|
|
20
20
|
trainerBackPicPaletteTable: 0x239FD4,
|
|
21
21
|
itemIconTable: 0x3D4294, // newer update: (so turns out this old value was the pointer to the table lol however this new one is the actual table... for real this time!) rest of the old message: so this was very hard to find since it isn't labeled in the .map of ROMs... luckily Ghidra and the ROM decomps exist so that helped a ton... issue is I believe this contains both the palette and gfx in each listing (should probably double check pokefirered to confirm...) so it will be interesting to extract assets I suppose...
|
|
22
|
+
moveAnimPicTable: 0x3ACC08,
|
|
23
|
+
moveAnimPaletteTable: 0x3AD510,
|
|
22
24
|
} // if this works out... well hehe... :D
|
|
23
25
|
}
|
|
@@ -9,6 +9,7 @@ import { renderIcon } from "./icons/render-icons.js";
|
|
|
9
9
|
import { renderTrainer } from "./trainers/render-trainers.js";
|
|
10
10
|
import { RomReader } from "../rom-reader.js";
|
|
11
11
|
import { getRomConfig } from "../get-rom-config.js";
|
|
12
|
+
import { renderMove } from "./moves/render-moves.js";
|
|
12
13
|
|
|
13
14
|
const currentDir = path.dirname(fileURLToPath(import.meta.url));
|
|
14
15
|
|
|
@@ -17,11 +18,11 @@ function loadDefaultJson(relativePath) {
|
|
|
17
18
|
return JSON.parse(fs.readFileSync(absolutePath, "utf-8"));
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
const assets = loadDefaultJson("../graphics-maps/fr-graphic-map.json");
|
|
21
21
|
const mons = loadDefaultJson("../mon-data/monData.json");
|
|
22
22
|
const icons = loadDefaultJson("../item-data/itemData.json");
|
|
23
23
|
const trainers = loadDefaultJson("../trainer-data/trainerData.json");
|
|
24
24
|
const trainersBack = loadDefaultJson("../trainer-data/trainerBackData.json");
|
|
25
|
+
const moves = loadDefaultJson("../move-data/moveData.json");
|
|
25
26
|
|
|
26
27
|
export async function renderAllMons(rom, options = {}) {
|
|
27
28
|
if (!rom || !(rom instanceof Uint8Array || Buffer.isBuffer(rom))) {
|
|
@@ -58,7 +59,6 @@ export async function renderAllIcons(rom, options = {}) {
|
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
const {
|
|
61
|
-
assets: providedAssets = assets,
|
|
62
62
|
icons: providedIcons = icons,
|
|
63
63
|
outputDir = "./out",
|
|
64
64
|
} = options;
|
|
@@ -69,7 +69,7 @@ export async function renderAllIcons(rom, options = {}) {
|
|
|
69
69
|
const reader = new RomReader(rom, config);
|
|
70
70
|
|
|
71
71
|
for (const itemName of Object.keys(providedIcons)) {
|
|
72
|
-
await renderIcon(itemName, providedIcons,
|
|
72
|
+
await renderIcon(itemName, providedIcons, reader, rom, { outputDir });
|
|
73
73
|
console.log(`Done: ${itemName}`);
|
|
74
74
|
}
|
|
75
75
|
}
|
|
@@ -100,6 +100,23 @@ export async function renderAllTrainers(rom, options = {}) {
|
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
+
export async function renderAllMoves(rom, options = {}) {
|
|
104
|
+
const {
|
|
105
|
+
moves: providedMoves = moves,
|
|
106
|
+
outputDir = "./out",
|
|
107
|
+
} = options;
|
|
108
|
+
|
|
109
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
110
|
+
|
|
111
|
+
const config = getRomConfig(rom);
|
|
112
|
+
const reader = new RomReader(rom, config);
|
|
113
|
+
|
|
114
|
+
for (const moveName of Object.keys(providedMoves)) {
|
|
115
|
+
await renderMove(moveName, providedMoves, reader, rom, { outputDir });
|
|
116
|
+
console.log(`Done: ${moveName}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
103
120
|
export async function renderAllGraphics(rom, options = {}) { // eventually I will speed this up instead of doing it sequentially :p but for now its fine I guess
|
|
104
121
|
if (!rom || !(rom instanceof Uint8Array || Buffer.isBuffer(rom))) {
|
|
105
122
|
throw new TypeError("renderAllGraphics(rom, options) requires rom Buffer/Uint8Array as first argument");
|
|
@@ -109,6 +126,7 @@ export async function renderAllGraphics(rom, options = {}) { // eventually I wil
|
|
|
109
126
|
outputMonDir = "./out/mons",
|
|
110
127
|
outputIconDir = "./out/icons",
|
|
111
128
|
outputTrainerDir = "./out/trainers",
|
|
129
|
+
outputMoveDir = "./out/moves"
|
|
112
130
|
} = options;
|
|
113
131
|
|
|
114
132
|
await renderAllMons(rom, {
|
|
@@ -125,6 +143,10 @@ export async function renderAllGraphics(rom, options = {}) { // eventually I wil
|
|
|
125
143
|
outputDir: outputTrainerDir,
|
|
126
144
|
trainerBackPics: true,
|
|
127
145
|
});
|
|
146
|
+
|
|
147
|
+
await renderAllMoves(rom, {
|
|
148
|
+
outputDir: outputMoveDir,
|
|
149
|
+
})
|
|
128
150
|
}
|
|
129
151
|
|
|
130
152
|
export function loadDefaultRom() {
|
|
@@ -14,7 +14,7 @@ const streamToBuffer = (stream) => new Promise((resolve, reject) => {
|
|
|
14
14
|
stream.on("error", reject);
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
-
export async function renderIcon(itemName, items,
|
|
17
|
+
export async function renderIcon(itemName, items, reader, rom, options = {}) {
|
|
18
18
|
const { outputDir = null } = options;
|
|
19
19
|
|
|
20
20
|
if (!rom || !(rom instanceof Uint8Array || Buffer.isBuffer(rom))) {
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Copyright (c) 2026 chickenPoo
|
|
2
|
+
// Licensed under the MIT License. See LICENSE file in project root.
|
|
3
|
+
|
|
4
|
+
import { extract } from "../extract.js";
|
|
5
|
+
import { render4bppImage } from "../render-4bpp-image.js";
|
|
6
|
+
import { resolveMovePic } from "./resolvers/move-pic-resolver.js";
|
|
7
|
+
import { resolveMovePal } from "./resolvers/move-pal-resolver.js";
|
|
8
|
+
import fs from "fs";
|
|
9
|
+
import { PNG } from "pngjs";
|
|
10
|
+
|
|
11
|
+
// let's see if I remember how to throw one of these together...
|
|
12
|
+
|
|
13
|
+
const streamToBuffer = (stream) => new Promise((resolve, reject) => {
|
|
14
|
+
const chunks = [];
|
|
15
|
+
stream.on("data", chunk => chunks.push(chunk));
|
|
16
|
+
stream.on("end", () => resolve(Buffer.concat(chunks)));
|
|
17
|
+
stream.on("error", reject);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const extractFrameFromImage = (imageData, fullWidth, frameData) => { // in theory should work...
|
|
21
|
+
const { x, y, width, height } = frameData;
|
|
22
|
+
const frameImage = new Uint8ClampedArray(width * height * 4);
|
|
23
|
+
|
|
24
|
+
for (let row = 0; row < height; row++) {
|
|
25
|
+
for (let col = 0; col < width; col++) {
|
|
26
|
+
const srcIndex = ((y + row) * fullWidth + (x + col)) * 4;
|
|
27
|
+
const dstIndex = (row * width + col) * 4;
|
|
28
|
+
frameImage[dstIndex] = imageData[srcIndex];
|
|
29
|
+
frameImage[dstIndex + 1] = imageData[srcIndex + 1];
|
|
30
|
+
frameImage[dstIndex + 2] = imageData[srcIndex + 2];
|
|
31
|
+
frameImage[dstIndex + 3] = imageData[srcIndex + 3];
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return frameImage;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export async function renderMove(moveName, moves, reader, rom, options = {}) {
|
|
39
|
+
const {
|
|
40
|
+
outputDir = null
|
|
41
|
+
} = options;
|
|
42
|
+
if (!rom || !(rom instanceof Uint8Array || Buffer.isBuffer(rom))) {
|
|
43
|
+
throw new TypeError("renderMove(..., rom) requires a ROM Buffer/Uint8Array");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const move = moves[moveName];
|
|
47
|
+
if (!move) {
|
|
48
|
+
throw new Error(`Missing move: ${moveName}`)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const movePic = resolveMovePic(move, reader, moveName);
|
|
52
|
+
const movePal = resolveMovePal(move, reader, moveName);
|
|
53
|
+
if (!movePal || !movePic) {
|
|
54
|
+
throw new Error(`Missing assets for: ${moveName}`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const moveImageData = extract(movePic, rom);
|
|
58
|
+
const rawMovePalData = extract(movePal, rom);
|
|
59
|
+
const width = move.imageWidth;
|
|
60
|
+
const height = move.imageHeight;
|
|
61
|
+
|
|
62
|
+
const image = render4bppImage({
|
|
63
|
+
tileData: moveImageData.data,
|
|
64
|
+
paletteData: rawMovePalData.data,
|
|
65
|
+
width,
|
|
66
|
+
height,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
if (outputDir) { // I will update this later but in theory it should also work... eventually though it will need a split inside to handle full image generation :p
|
|
70
|
+
const dir = `${outputDir}/${moveName}`;
|
|
71
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
72
|
+
|
|
73
|
+
for (let i = 0; i < move.frames.length; i++) {
|
|
74
|
+
const frame = move.frames[i];
|
|
75
|
+
const frameImageData = extractFrameFromImage(image, width, frame);
|
|
76
|
+
|
|
77
|
+
const png = new PNG({ width: frame.width, height: frame.height });
|
|
78
|
+
png.data = frameImageData;
|
|
79
|
+
const pngBuffer = await streamToBuffer(png.pack());
|
|
80
|
+
|
|
81
|
+
const fileName = `${dir}/frame-${i}.png`;
|
|
82
|
+
fs.writeFileSync(fileName, pngBuffer);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function resolveMovePal(move, reader, moveName) {
|
|
2
|
+
const table = reader.getTable("moveAnimPaletteTable");
|
|
3
|
+
const entryOffset = table + move.index * 8;
|
|
4
|
+
const ptr = reader.readPointer(entryOffset);
|
|
5
|
+
return {
|
|
6
|
+
name: `move_${moveName}_pal`,
|
|
7
|
+
offset: ptr,
|
|
8
|
+
size: 40 // maybe this will continue working? perhaps? please?
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function resolveMovePic(move, reader, moveName) {
|
|
2
|
+
const table = reader.getTable("moveAnimPicTable");
|
|
3
|
+
const entryOffset = table + move.index * 8;
|
|
4
|
+
const ptr = reader.readPointer(entryOffset);
|
|
5
|
+
return {
|
|
6
|
+
name: `move_${moveName}_pic`,
|
|
7
|
+
offset: ptr
|
|
8
|
+
// I don't think this needs a size... since I think most of these are all lz77 compressed... if not more JSON time :/
|
|
9
|
+
}
|
|
10
|
+
}
|
package/src/icon-data-parser.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
|
|
4
|
-
const itemIconDataMap = path.resolve("../item_graphics/item_icon_table.h");
|
|
5
|
-
const iconDataLines = fs.readFileSync(itemIconDataMap, "utf-8").split("\n");
|
|
6
|
-
|
|
7
|
-
const itemData = {};
|
|
8
|
-
let itemIndex = 0;
|
|
9
|
-
|
|
10
|
-
for (let i = 0; i < iconDataLines.length; i++) {
|
|
11
|
-
const match = iconDataLines[i].match(/\[(ITEMS?_[A-Z0-9_]+)\]\s*=\s*\{\s*([^,]+),\s*([^}]+)\}/);
|
|
12
|
-
if (match) {
|
|
13
|
-
let itemName = match[1]
|
|
14
|
-
.replace("ITEM_", "")
|
|
15
|
-
.replace("ITEMS_", "");
|
|
16
|
-
const icon = match[2].trim();
|
|
17
|
-
const palette = match[3].trim();
|
|
18
|
-
if (!itemData[itemName]) {
|
|
19
|
-
itemData[itemName] = {};
|
|
20
|
-
}
|
|
21
|
-
if (!itemData[itemName]["index"]) {
|
|
22
|
-
itemData[itemName]["index"] = itemIndex;
|
|
23
|
-
itemIndex++;
|
|
24
|
-
}
|
|
25
|
-
itemData[itemName]["icon"] = icon;
|
|
26
|
-
itemData[itemName]["palette"] = palette;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
fs.writeFileSync("../item-data/itemData.json", JSON.stringify(itemData, null, 2));
|
package/src/mon-data-parser.js
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
|
|
4
|
-
const monFrontPicMap = path.resolve("../pokemon_graphics/front_pic_table.h");
|
|
5
|
-
const monBackPicMap = path.resolve("../pokemon_graphics/back_pic_table.h");
|
|
6
|
-
const monFootprintMap = path.resolve("../pokemon_graphics/footprint_table.h");
|
|
7
|
-
const monPaletteMap = path.resolve("../pokemon_graphics/palette_table.h");
|
|
8
|
-
const monShinyPaletteMap = path.resolve("../pokemon_graphics/shiny_palette_table.h");
|
|
9
|
-
const monImageDimensionMap = path.resolve("../pokemon_graphics/front_pic_coordinates.h");
|
|
10
|
-
const monIconPaletteIdxMap = path.resolve("../pokemon_icon.c");
|
|
11
|
-
const frontPicLines = fs.readFileSync(monFrontPicMap, "utf-8").split("\n");
|
|
12
|
-
const backPicLines = fs.readFileSync(monBackPicMap, "utf-8").split("\n");
|
|
13
|
-
const footprintLines = fs.readFileSync(monFootprintMap, "utf8").split("\n");
|
|
14
|
-
const paletteLines = fs.readFileSync(monPaletteMap, "utf-8").split("\n");
|
|
15
|
-
const shinyPaletteLines = fs.readFileSync(monShinyPaletteMap, "utf-8").split("\n");
|
|
16
|
-
const imageDimLines = fs.readFileSync(monImageDimensionMap, "utf-8").split("\n");
|
|
17
|
-
const iconPalIdxLines = fs.readFileSync(monIconPaletteIdxMap, "utf-8").split("\n");
|
|
18
|
-
const monData = {};
|
|
19
|
-
|
|
20
|
-
function extractMonData(lines, category) {
|
|
21
|
-
let monIndex = 0;
|
|
22
|
-
for (let i = 0; i < lines.length; i++) {
|
|
23
|
-
let match;
|
|
24
|
-
let monName;
|
|
25
|
-
let secondArgument;
|
|
26
|
-
if (category !== "footprintPics" && category !== "imageDimensions" && category !== "iconPalIndex") {
|
|
27
|
-
match = lines[i].match(/\(([^,]+),\s*([^,]+)\)/);
|
|
28
|
-
if (match) {
|
|
29
|
-
monName = match[1];
|
|
30
|
-
secondArgument = match[2];
|
|
31
|
-
}
|
|
32
|
-
} else if (category === "footprintPics") {
|
|
33
|
-
match = lines[i].match(/\[(SPECIES_\w+)\]\s*=\s*(gMonFootprint_\w+)/);
|
|
34
|
-
if (match) {
|
|
35
|
-
monName = match[1].replace("SPECIES_", "");
|
|
36
|
-
secondArgument = match[2];
|
|
37
|
-
}
|
|
38
|
-
} else if (category === "imageDimensions" && lines[i].includes(".size = MON_COORDS_SIZE")) {
|
|
39
|
-
const prevLine = lines[i - 2];
|
|
40
|
-
match = lines[i].match(/MON_COORDS_SIZE\((\d+),\s*(\d+)\)/);
|
|
41
|
-
if (match) {
|
|
42
|
-
monName = prevLine.match(/\[(SPECIES_\w+)\]/)[1].replace("SPECIES_", "");
|
|
43
|
-
const width = match[1];
|
|
44
|
-
const height = match[2];
|
|
45
|
-
if (!monData[monName]) {
|
|
46
|
-
monData[monName] = {};
|
|
47
|
-
}
|
|
48
|
-
monData[monName]["width"] = width;
|
|
49
|
-
monData[monName]["height"] = height;
|
|
50
|
-
}
|
|
51
|
-
} else if (category === "iconPalIndex") {
|
|
52
|
-
match = lines[i].match(/\[(SPECIES_\w+)\]\s*=\s*(\d+)\s*,?/);
|
|
53
|
-
if (match) {
|
|
54
|
-
monName = match[1].replace("SPECIES_", "");
|
|
55
|
-
secondArgument = match[2];
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
if (monName && secondArgument) {
|
|
59
|
-
if (!monData[monName]) {
|
|
60
|
-
monData[monName] = {};
|
|
61
|
-
}
|
|
62
|
-
if (!monData[monName][category]) {
|
|
63
|
-
monData[monName][category] = secondArgument;
|
|
64
|
-
}
|
|
65
|
-
if (!monData[monName]["index"]) {
|
|
66
|
-
monData[monName]["index"] = monIndex;
|
|
67
|
-
monIndex++
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
extractMonData(frontPicLines, "frontPics");
|
|
74
|
-
extractMonData(backPicLines, "backPics");
|
|
75
|
-
extractMonData(paletteLines, "normPalette");
|
|
76
|
-
extractMonData(shinyPaletteLines, "shinyPalette");
|
|
77
|
-
extractMonData(footprintLines, "footprintPics");
|
|
78
|
-
extractMonData(imageDimLines, "imageDimensions");
|
|
79
|
-
extractMonData(iconPalIdxLines, "iconPalIndex");
|
|
80
|
-
function uncapitalize(string) {
|
|
81
|
-
return string.charAt(0) + string.slice(1).toLowerCase();
|
|
82
|
-
}
|
|
83
|
-
Object.entries(monData).forEach(([monName]) => {
|
|
84
|
-
let monName2 = uncapitalize(monName);
|
|
85
|
-
if (monName2.includes("Old_unown_") || monName2.includes("None")) {
|
|
86
|
-
monName2 = "QuestionMark";
|
|
87
|
-
}
|
|
88
|
-
if (monName2.includes("Unown_")) {
|
|
89
|
-
monName2 = monName2.slice(0, 5) + monName2[6].toUpperCase() + monName2.slice(7);
|
|
90
|
-
if (monName2 === "UnownEmark") {
|
|
91
|
-
monName2 = "UnownExclamationMark";
|
|
92
|
-
} else if (monName2 === "UnownQmark") {
|
|
93
|
-
monName2 = "UnownQuestionMark";
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
if (monName2.includes("Nidoran")) {
|
|
97
|
-
if (monName2.includes("Nidoran_f")) {
|
|
98
|
-
monName2 = "NidoranF";
|
|
99
|
-
}
|
|
100
|
-
if (monName2.includes("Nidoran_m")) {
|
|
101
|
-
monName2 = "NidoranM";
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
if (monName2.includes("Mr_mime")) {
|
|
105
|
-
monName2 = "Mrmime";
|
|
106
|
-
}
|
|
107
|
-
if (monName2 === "Unown") {
|
|
108
|
-
monName2 = "UnownA";
|
|
109
|
-
}
|
|
110
|
-
if (monName2 === "Ho_oh") {
|
|
111
|
-
monName2 = "HoOh";
|
|
112
|
-
}
|
|
113
|
-
console.log(monName2);
|
|
114
|
-
const iconName = `gMonIcon_${monName2}`
|
|
115
|
-
monData[monName]["Icon"] = iconName;
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
fs.writeFileSync("../mon-data/monData.json", JSON.stringify(monData, null, 2));
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
|
|
4
|
-
const trainerFrontPicMap = path.resolve("../trainer_graphics/front_pic_tables.h");
|
|
5
|
-
const frontPicLines = fs.readFileSync(trainerFrontPicMap, "utf-8").split("\n");
|
|
6
|
-
|
|
7
|
-
const trainerData = {};
|
|
8
|
-
let trainerIndex = 0;
|
|
9
|
-
|
|
10
|
-
for (let i = 0; i < frontPicLines.length; i++) {
|
|
11
|
-
const match = frontPicLines[i].match(/TRAINER_(SPRITE|PAL)\(\s*([A-Z0-9_]+)\s*,\s*(gTrainer(?:FrontPic|Palette)_[A-Za-z0-9_]+)/);
|
|
12
|
-
if (match) {
|
|
13
|
-
let trainerName = match[2];
|
|
14
|
-
if (!trainerData[trainerName]) {
|
|
15
|
-
trainerData[trainerName] = {};
|
|
16
|
-
}
|
|
17
|
-
if (match[1] === "SPRITE") {
|
|
18
|
-
trainerData[trainerName]["Pic"] = match[3];
|
|
19
|
-
} else {
|
|
20
|
-
trainerData[trainerName]["Palette"] = match[3];
|
|
21
|
-
}
|
|
22
|
-
if (trainerData[trainerName]["index"] === undefined) {
|
|
23
|
-
trainerData[trainerName]["index"] = trainerIndex;
|
|
24
|
-
trainerIndex++;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
fs.writeFileSync("../trainer-data/trainerData.json", JSON.stringify(trainerData, null, 2));
|