silphscope 1.2.7 → 1.2.9

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.7",
3
+ "version": "1.2.9",
4
4
  "description": "A firered/leafgreen ROM asset extractor for use in web applications",
5
5
  "main": "main.js",
6
6
  "exports": {
@@ -16,7 +16,8 @@
16
16
  "mon-data/",
17
17
  "rom-maps/",
18
18
  "item-data/",
19
- "trainer-data"
19
+ "trainer-data",
20
+ "rom-configs/"
20
21
  ],
21
22
  "keywords": [],
22
23
  "author": "chickenPoo",
@@ -0,0 +1,11 @@
1
+ // I have an idea but it needs math D:
2
+
3
+ export const firered = {
4
+ code: "BPRE", // I find this weird... like what does BP stand for? is it: "Battle Pokemon"? no idea :o
5
+ tables: { // so the idea is essentially instead of a big JSON like we have now we instead just view the table graphics and build from that... it in theory could be slower because more lookups instead of direct references but it should be more maintainable...
6
+ monFrontSprites: 0x2350AC,
7
+ monBackSprites: 0x23654C,
8
+ monPalettes: 0x23730C,
9
+ monShinyPalettes: 0x2380CC
10
+ } // if this works out... well hehe... :D
11
+ }
@@ -0,0 +1,11 @@
1
+ import { firered } from "../rom-configs/firered.js";
2
+
3
+ function detectRomCode(rom) {
4
+ return new TextDecoder().decode(rom.slice(0xAC, 0xB0));
5
+ }
6
+
7
+ export function getRomConfig(rom) {
8
+ const code = detectRomCode(rom);
9
+ if (code === firered.code) return firered; // eventually will add more and so on :p (by more I mean leafgreen lol)
10
+ throw new Error(`Unsupported ROM: ${code}`);
11
+ }
@@ -4,9 +4,11 @@
4
4
  import fs from "fs";
5
5
  import path from "path";
6
6
  import { fileURLToPath } from "url";
7
- import { renderMon } from "./render-mons.js";
7
+ import { renderMon } from "./mons/render-mons.js";
8
8
  import { renderIcon } from "./icons/render-icons.js";
9
9
  import { renderTrainer } from "./trainers/render-trainers.js";
10
+ import { RomReader } from "../rom-reader.js";
11
+ import { getRomConfig } from "../get-rom-config.js";
10
12
 
11
13
  const currentDir = path.dirname(fileURLToPath(import.meta.url));
12
14
 
@@ -35,29 +37,32 @@ export async function renderAllMons(rom, options = {}) {
35
37
 
36
38
  fs.mkdirSync(outputDir, { recursive: true });
37
39
 
40
+ const config = getRomConfig(rom);
41
+ const reader = new RomReader(rom, config);
42
+
38
43
  for (const monName of Object.keys(providedMons)) {
39
- await renderMon(monName, providedMons, providedAssets, rom, {
44
+ await renderMon(monName, providedMons, providedAssets, reader, rom, {
40
45
  side: "front",
41
46
  variant: "normal",
42
47
  icon,
43
48
  footprint,
44
49
  outputDir,
45
50
  });
46
- await renderMon(monName, providedMons, providedAssets, rom, {
51
+ await renderMon(monName, providedMons, providedAssets, reader, rom, {
47
52
  side: "front",
48
53
  variant: "shiny",
49
54
  icon: false,
50
55
  footprint: false,
51
56
  outputDir,
52
57
  });
53
- await renderMon(monName, providedMons, providedAssets, rom, {
58
+ await renderMon(monName, providedMons, providedAssets, reader, rom, {
54
59
  side: "back",
55
60
  variant: "normal",
56
61
  icon: false,
57
62
  footprint: false,
58
63
  outputDir,
59
64
  });
60
- await renderMon(monName, providedMons, providedAssets, rom, {
65
+ await renderMon(monName, providedMons, providedAssets, reader, rom, {
61
66
  side: "back",
62
67
  variant: "shiny",
63
68
  icon: false,
@@ -2,8 +2,8 @@
2
2
  // Licensed under the MIT License. See LICENSE file in project root.
3
3
 
4
4
  import { PNG } from "pngjs";
5
- import { extract } from "./extract.js";
6
- import { decode1bppTile } from "./decode-1bpp.js";
5
+ import { extract } from "../extract.js";
6
+ import { decode1bppTile } from "../decode-1bpp.js";
7
7
  import fs from "fs";
8
8
 
9
9
  const streamToBuffer = (stream) => new Promise((resolve, reject) => {
@@ -1,10 +1,10 @@
1
1
  // Copyright (c) 2026 chickenPoo
2
2
  // Licensed under the MIT License. See LICENSE file in project root.
3
3
 
4
- import { extract } from "./extract.js";
4
+ import { extract } from "../extract.js";
5
5
  import { PNG } from "pngjs";
6
6
  import fs from "fs";
7
- import { render4bppImage } from "./render-4bpp-image.js";
7
+ import { render4bppImage } from "../render-4bpp-image.js";
8
8
 
9
9
  const streamToBuffer = (stream) => new Promise((resolve, reject) => {
10
10
  const chunks = [];
@@ -3,10 +3,11 @@
3
3
 
4
4
  import { PNG } from "pngjs";
5
5
  import fs from "fs";
6
- import { extract } from "./extract.js";
6
+ import { extract } from "../extract.js";
7
7
  import { renderMonIcon } from "./render-mon-icon.js";
8
8
  import { renderMonFoot } from "./render-mon-foot.js";
9
- import { render4bppImage } from "./render-4bpp-image.js";
9
+ import { render4bppImage } from "../render-4bpp-image.js";
10
+ import { resolveMonFrontSprite } from "./resolvers/mon-front-sprite-resolver.js";
10
11
 
11
12
  const streamToBuffer = (stream) => new Promise((resolve, reject) => {
12
13
  const chunks = [];
@@ -15,7 +16,7 @@ const streamToBuffer = (stream) => new Promise((resolve, reject) => {
15
16
  stream.on("error", reject);
16
17
  });
17
18
 
18
- export async function renderMon(monName, mons, assets, rom, options = {}) {
19
+ export async function renderMon(monName, mons, assets, reader, rom, options = {}) {
19
20
  const {
20
21
  side = "front",
21
22
  variant = "normal",
@@ -42,8 +43,13 @@ export async function renderMon(monName, mons, assets, rom, options = {}) {
42
43
  throw new Error(`Missing mon: ${monName}`);
43
44
  }
44
45
 
45
- const picName = side === "back" ? mon.backPics : mon.frontPics;
46
- const monPic = assets.find(a => a.name === picName);
46
+ let monPic;
47
+ if (side === "front") {
48
+ monPic = resolveMonFrontSprite(mon, reader); // I wonder if this will work :O
49
+ } else {
50
+ const picName = mon.backPics;
51
+ monPic = assets.find(a => a.name === picName);
52
+ }
47
53
  const palType = variant === "shiny" ? mon.shinyPalette : mon.normPalette;
48
54
  const monPal = assets.find(a => a.name === palType);
49
55
 
@@ -0,0 +1,15 @@
1
+ // so the idea of "resolvers" is to essentially replace this line in the asset extraction:
2
+ // const monPic = assets.find(a => a.name === picName);
3
+ // of course though thats for the mon stuff specifically however!
4
+ // this time instead of needing a giant lookup table we use this thingy
5
+ // plus our rom-config to just infer all of this from the table in the ROM itself... in theory..
6
+
7
+ export function resolveMonFrontSprite(mon, romReader) {
8
+ const table = romReader.getTable("monFrontSprites");
9
+ const entryOffset = table + mon.index * 8;
10
+ const ptr = romReader.readPointer(entryOffset);
11
+ return {
12
+ name: `mon_${mon.name}_front`,
13
+ offset: ptr
14
+ };
15
+ }
@@ -18,6 +18,7 @@ const iconPalIdxLines = fs.readFileSync(monIconPaletteIdxMap, "utf-8").split("\n
18
18
  const monData = {};
19
19
 
20
20
  function extractMonData(lines, category) {
21
+ let monIndex = 0;
21
22
  for (let i = 0; i < lines.length; i++) {
22
23
  let match;
23
24
  let monName;
@@ -61,6 +62,10 @@ function extractMonData(lines, category) {
61
62
  if (!monData[monName][category]) {
62
63
  monData[monName][category] = secondArgument;
63
64
  }
65
+ if (!monData[monName]["index"]) {
66
+ monData[monName]["index"] = monIndex;
67
+ monIndex++
68
+ }
64
69
  }
65
70
  }
66
71
  }
@@ -0,0 +1,21 @@
1
+ export class RomReader {
2
+ constructor(rom, mapConfig) {
3
+ this.rom = rom;
4
+ this.mapConfig = mapConfig;
5
+ }
6
+ readU32(offset) {
7
+ const rom = this.rom;
8
+ return(
9
+ rom[offset] |
10
+ (rom[offset + 1] << 8) |
11
+ (rom[offset + 2] << 16) |
12
+ (rom[offset + 3] << 24)
13
+ );
14
+ }
15
+ readPointer(offset) {
16
+ return this.readU32(offset) - 0x08000000;
17
+ }
18
+ getTable(name) {
19
+ return this.mapConfig.tables[name];
20
+ }
21
+ }