silphscope 1.2.2 → 1.2.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "silphscope",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "description": "A firered/leafgreen ROM asset extractor for use in web applications",
5
5
  "main": "main.js",
6
6
  "exports": {
@@ -95,13 +95,17 @@ export async function renderAllTrainers(rom, options = {}) {
95
95
  const {
96
96
  assets: providedAssets = assets,
97
97
  trainers: providedTrainers = trainers,
98
+ trainerBackPics = true,
98
99
  outputDir = "./out",
99
100
  } = options;
100
101
 
101
102
  fs.mkdirSync(outputDir, { recursive: true });
102
103
 
103
104
  for (const trainerName of Object.keys(providedTrainers)) {
104
- await renderTrainer(trainerName, providedTrainers, providedAssets, rom, { outputDir });
105
+ await renderTrainer(trainerName, providedTrainers, providedAssets, rom, {
106
+ trainerBackPics,
107
+ outputDir
108
+ });
105
109
  console.log(`Done: ${trainerName}`);
106
110
  }
107
111
  }
@@ -129,6 +133,7 @@ export async function renderAllGraphics(rom, options = {}) { // eventually I wil
129
133
 
130
134
  await renderAllTrainers(rom, {
131
135
  outputDir: outputTrainerDir,
136
+ trainerBackPics: true,
132
137
  });
133
138
  }
134
139
 
@@ -0,0 +1,75 @@
1
+ // Copyright (c) 2026 chickenPoo
2
+ // Licensed under the MIT License. See LICENSE file in project root.
3
+
4
+ import { PNG } from "pngjs";
5
+ import fs from "fs";
6
+ import { extract } from "../extract.js";
7
+ import { render4bppImage } from "../render-4bpp-image.js";
8
+
9
+ const streamToBuffer = (stream) => new Promise((resolve, reject) => {
10
+ const chunks = [];
11
+ stream.on("data", chunk => chunks.push(chunk));
12
+ stream.on("end", () => resolve(Buffer.concat(chunks)));
13
+ stream.on("error", reject);
14
+ });
15
+
16
+ export async function renderTrainerBackPic(trainerName, trainers, assets, rom, options = {}) {
17
+ const { outputDir = null } = options;
18
+
19
+ if (!rom || !(rom instanceof Uint8Array || Buffer.isBuffer(rom))) {
20
+ throw new TypeError("renderTrainerBackPic(..., rom) requires a ROM Buffer/Uint8Array");
21
+ }
22
+
23
+ const trainer = trainers[trainerName];
24
+ if (!trainer) {
25
+ throw new Error(`Missing trainer entry for ${trainerName}`);
26
+ }
27
+
28
+ if (trainerName !== "OLDMAN" &&
29
+ trainerName !== "POKEDUDE" &&
30
+ trainerName !== "RS_BRENDAN_1" &&
31
+ trainerName !== "RS_BRENDAN_2" &&
32
+ trainerName !== "RS_MAY_1" &&
33
+ trainerName !== "RS_MAY_2" && // I wonder if there is a more compact way to write this without using a array and `.includes`
34
+ trainerName !== "RED" &&
35
+ trainerName !== "LEAF"
36
+ ) {
37
+ return;
38
+ }
39
+
40
+ const trainerBackPic = assets.find(a => a.name === trainer.BackPic);
41
+ const trainerBackPal = assets.find(a => a.name === trainer.BackPal);
42
+ if (!trainerBackPic || !trainerBackPal) {
43
+ throw new Error(`Missing assets for: ${trainerName}`);
44
+ }
45
+
46
+ const trainerBackImageData = extract(trainerBackPic, rom);
47
+ const rawTrainerBackPalData = extract(trainerBackPal, rom);
48
+ const width = 64;
49
+ let height;
50
+ if (trainer === "RED" || trainer === "LEAF") {
51
+ height = 320;
52
+ } else {
53
+ height = 256;
54
+ }
55
+
56
+ const image = render4bppImage({
57
+ tileData: trainerBackImageData.data,
58
+ paletteData: rawTrainerBackPalData.data,
59
+ width,
60
+ height,
61
+ });
62
+
63
+ const png = new PNG({ width, height });
64
+ png.data = image;
65
+ const pngBuffer = await streamToBuffer(png.pack());
66
+
67
+ if (outputDir) {
68
+ const dir = `${outputDir}/${trainerName}`;
69
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
70
+ const fileName = `${dir}/trainer_back.png`;
71
+ fs.writeFileSync(fileName, pngBuffer);
72
+ }
73
+
74
+ return pngBuffer;
75
+ }
@@ -5,6 +5,7 @@ import { extract } from "../extract.js";
5
5
  import { render4bppImage } from "../render-4bpp-image.js";
6
6
  import { PNG } from "pngjs";
7
7
  import fs from "fs";
8
+ import { renderTrainerBackPic } from "./render-trainer-back-pics.js";
8
9
 
9
10
  const streamToBuffer = (stream) => new Promise((resolve, reject) => {
10
11
  const chunks = [];
@@ -14,7 +15,10 @@ const streamToBuffer = (stream) => new Promise((resolve, reject) => {
14
15
  });
15
16
 
16
17
  export async function renderTrainer(trainerName, trainers, assets, rom, options = {}) {
17
- const { outputDir = null } = options;
18
+ const {
19
+ trainerBackPics = false,
20
+ outputDir = null,
21
+ } = options;
18
22
  if (!rom || !(rom instanceof Uint8Array || Buffer.isBuffer(rom))) {
19
23
  throw new TypeError("renderTrainer(..., rom) requires a ROM Buffer/Uint8Array");
20
24
  }
@@ -23,7 +27,12 @@ export async function renderTrainer(trainerName, trainers, assets, rom, options
23
27
  if (!trainer) {
24
28
  throw new Error(`Missing Trainer: ${trainerName}`);
25
29
  }
26
-
30
+ if (trainerBackPics) {
31
+ renderTrainerBackPic(trainerName, trainers, assets, rom, { outputDir });
32
+ }
33
+ if (trainerName === "OLDMAN" || trainerName === "POKEDUDE") {
34
+ return;
35
+ }
27
36
  const trainerPal = assets.find(a => a.name === trainer.Palette);
28
37
  const trainerPic = assets.find(a => a.name === trainer.Pic);
29
38
 
@@ -225,11 +225,15 @@
225
225
  },
226
226
  "RS_BRENDAN_1": {
227
227
  "Pic": "gTrainerFrontPic_RSBrendan1",
228
- "Palette": "gTrainerPalette_RSBrendan1"
228
+ "Palette": "gTrainerPalette_RSBrendan1",
229
+ "BackPic": "gTrainerBackPic_RSBrendan",
230
+ "BackPal": "gTrainerPalette_RSBrendan1"
229
231
  },
230
232
  "RS_MAY_1": {
231
233
  "Pic": "gTrainerFrontPic_RSMay1",
232
- "Palette": "gTrainerPalette_RSMay1"
234
+ "Palette": "gTrainerPalette_RSMay1",
235
+ "BackPic": "gTrainerBackPic_RSMay",
236
+ "BackPal": "gTrainerPalette_RSMay1"
233
237
  },
234
238
  "RS_POKEMON_BREEDER_M": {
235
239
  "Pic": "gTrainerFrontPic_RSPokemonBreederM",
@@ -533,19 +537,27 @@
533
537
  },
534
538
  "RS_BRENDAN_2": {
535
539
  "Pic": "gTrainerFrontPic_RSBrendan2",
536
- "Palette": "gTrainerPalette_RSBrendan2"
540
+ "Palette": "gTrainerPalette_RSBrendan2",
541
+ "BackPic": "gTrainerBackPic_RSBrendan",
542
+ "BackPal": "gTrainerPalette_RSBrendan2"
537
543
  },
538
544
  "RS_MAY_2": {
539
545
  "Pic": "gTrainerFrontPic_RSMay2",
540
- "Palette": "gTrainerPalette_RSMay2"
546
+ "Palette": "gTrainerPalette_RSMay2",
547
+ "BackPic": "gTrainerBackPic_RSMay",
548
+ "BackPal": "gTrainerPalette_RSMay2"
541
549
  },
542
550
  "RED": {
543
551
  "Pic": "gTrainerFrontPic_Red",
544
- "Palette": "gTrainerPalette_Red"
552
+ "Palette": "gTrainerPalette_Red",
553
+ "BackPic": "gTrainerBackPic_Red",
554
+ "BackPal": "gTrainerPalette_RedBackPic"
545
555
  },
546
556
  "LEAF": {
547
557
  "Pic": "gTrainerFrontPic_Leaf",
548
- "Palette": "gTrainerPalette_Leaf"
558
+ "Palette": "gTrainerPalette_Leaf",
559
+ "BackPic": "gTrainerBackPic_Leaf",
560
+ "BackPal": "gTrainerPalette_LeafBackPic"
549
561
  },
550
562
  "ROCKET_GRUNT_F": {
551
563
  "Pic": "gTrainerFrontPic_RocketGruntF",
@@ -590,5 +602,13 @@
590
602
  "PAINTER": {
591
603
  "Pic": "gTrainerFrontPic_Painter",
592
604
  "Palette": "gTrainerPalette_Painter"
605
+ },
606
+ "POKEDUDE": {
607
+ "BackPic": "gTrainerBackPic_Pokedude",
608
+ "BackPal": "gTrainerPalette_PokedudeBackPic"
609
+ },
610
+ "OLDMAN": {
611
+ "BackPic": "gTrainerBackPic_OldMan",
612
+ "BackPal": "gTrainerPalette_OldManBackPic"
593
613
  }
594
614
  }