silphscope 1.3.6 → 1.4.0
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/ball-data/ballData.json +38 -0
- package/main.js +2 -2
- package/package.json +6 -2
- package/rom-configs/firered.js +4 -0
- package/src/graphics/balls/render-ball-particle.js +59 -0
- package/src/graphics/balls/render-balls.js +65 -0
- package/src/graphics/balls/resolvers/ball-particle-palette-resolver.js +13 -0
- package/src/graphics/balls/resolvers/ball-particle-resolver.js +12 -0
- package/src/graphics/balls/resolvers/ball-sprite-palette-resolver.js +13 -0
- package/src/graphics/balls/resolvers/ball-sprite-resolver.js +12 -0
- package/src/graphics/graphics-extractor-main.js +27 -1
- package/graphics-maps/fr-graphic-map.json +0 -29080
- package/rom-maps/pokefirered.map +0 -35107
- package/src/rom-map-parser.js +0 -85
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"POKE": {
|
|
3
|
+
"index": 0
|
|
4
|
+
},
|
|
5
|
+
"GREAT": {
|
|
6
|
+
"index": 1
|
|
7
|
+
},
|
|
8
|
+
"SAFARI": {
|
|
9
|
+
"index": 2
|
|
10
|
+
},
|
|
11
|
+
"ULTRA": {
|
|
12
|
+
"index": 3
|
|
13
|
+
},
|
|
14
|
+
"MASTER": {
|
|
15
|
+
"index": 4
|
|
16
|
+
},
|
|
17
|
+
"NET": {
|
|
18
|
+
"index": 5
|
|
19
|
+
},
|
|
20
|
+
"DIVE": {
|
|
21
|
+
"index": 6
|
|
22
|
+
},
|
|
23
|
+
"NEST": {
|
|
24
|
+
"index": 7
|
|
25
|
+
},
|
|
26
|
+
"REPEAT": {
|
|
27
|
+
"index": 8
|
|
28
|
+
},
|
|
29
|
+
"TIMER": {
|
|
30
|
+
"index": 9
|
|
31
|
+
},
|
|
32
|
+
"LUXURY": {
|
|
33
|
+
"index": 10
|
|
34
|
+
},
|
|
35
|
+
"PREMIER": {
|
|
36
|
+
"index": 11
|
|
37
|
+
}
|
|
38
|
+
}
|
package/main.js
CHANGED
|
@@ -5,5 +5,5 @@ import { extract } from "./src/graphics/extract.js"; // random message for a com
|
|
|
5
5
|
|
|
6
6
|
export { renderMon, renderMonIcon, renderMonFoot, extract };
|
|
7
7
|
|
|
8
|
-
import { renderAllMons, renderAllIcons, renderAllTrainers, renderAllMoves, renderAllGraphics } from "./src/graphics/graphics-extractor-main.js";
|
|
9
|
-
export { renderAllMons, renderAllIcons, renderAllTrainers, renderAllMoves ,renderAllGraphics };
|
|
8
|
+
import { renderAllMons, renderAllIcons, renderAllTrainers, renderAllMoves, renderAllBalls, renderAllGraphics } from "./src/graphics/graphics-extractor-main.js";
|
|
9
|
+
export { renderAllMons, renderAllIcons, renderAllTrainers, renderAllMoves, renderAllBalls, renderAllGraphics };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "silphscope",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "A firered/leafgreen ROM asset extractor for use in web applications",
|
|
5
5
|
"main": "main.js",
|
|
6
6
|
"exports": {
|
|
@@ -22,7 +22,11 @@
|
|
|
22
22
|
"!src/icon-data-parser.js",
|
|
23
23
|
"!src/mon-data-parser.js",
|
|
24
24
|
"!src/trainer-data-parser.js",
|
|
25
|
-
"!src/move-data-parser.js"
|
|
25
|
+
"!src/move-data-parser.js",
|
|
26
|
+
"!src/rom-map-parser.js",
|
|
27
|
+
"!rom-maps/",
|
|
28
|
+
"!graphics-maps/",
|
|
29
|
+
"ball-data/"
|
|
26
30
|
],
|
|
27
31
|
"keywords": [],
|
|
28
32
|
"author": "chickenPoo",
|
package/rom-configs/firered.js
CHANGED
|
@@ -21,5 +21,9 @@ export const firered = {
|
|
|
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
22
|
moveAnimPicTable: 0x3ACC08,
|
|
23
23
|
moveAnimPaletteTable: 0x3AD510,
|
|
24
|
+
ballParticlePicTable: 0x40BF48,
|
|
25
|
+
ballParticlePalTable: 0x40BFA8,
|
|
26
|
+
ballAnimPicTable: 0x26056C,
|
|
27
|
+
ballAnimPalTable: 0x2605CC, // any idea what I am doing next?
|
|
24
28
|
} // if this works out... well hehe... :D
|
|
25
29
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// Copyright (c) 2026 chickenPoo
|
|
2
|
+
// Licensed under the MIT License. See LICENSE file in project root.
|
|
3
|
+
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
import { PNG } from "pngjs";
|
|
6
|
+
import { extract } from "../extract.js";
|
|
7
|
+
import { render4bppImage } from "../render-4bpp-image.js";
|
|
8
|
+
import { resolveBallParticlePic } from "./resolvers/ball-particle-resolver.js";
|
|
9
|
+
import { resolveBallParticlePal } from "./resolvers/ball-particle-palette-resolver.js";
|
|
10
|
+
|
|
11
|
+
const streamToBuffer = (stream) => new Promise((resolve, reject) => {
|
|
12
|
+
const chunks = [];
|
|
13
|
+
stream.on("data", chunk => chunks.push(chunk));
|
|
14
|
+
stream.on("end", () => resolve(Buffer.concat(chunks)));
|
|
15
|
+
stream.on("error", reject);
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
export async function renderBallParticle(ballName, balls, reader, rom, options = {}) {
|
|
19
|
+
const { outputDir = null } = options;
|
|
20
|
+
if (!rom || !(rom instanceof Uint8Array || Buffer.isBuffer(rom))) {
|
|
21
|
+
throw new TypeError("renderBallParticle(..., rom) requires a ROM Buffer/Uint8Array");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const ball = balls[ballName];
|
|
25
|
+
if (!ball) {
|
|
26
|
+
throw new Error(`Missing Ball: ${ballName}`);
|
|
27
|
+
}
|
|
28
|
+
const particlePic = resolveBallParticlePic(ball, reader, ballName);
|
|
29
|
+
const particlePal = resolveBallParticlePal(ball, reader, ballName);
|
|
30
|
+
|
|
31
|
+
if (!particlePic || !particlePal) {
|
|
32
|
+
throw new Error(`Missing assets for: ${ballName}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const particleImageData = extract(particlePic, rom);
|
|
36
|
+
const rawParticlePalData = extract(particlePal, rom);
|
|
37
|
+
const width = 8; // so actually the "particle image" is one image that just contains all of the particles used for the balls upon opening later on I will split the ones actually used by each ball so we aren't exporting a full redundant image :p
|
|
38
|
+
const height = 64;
|
|
39
|
+
|
|
40
|
+
const image = render4bppImage({
|
|
41
|
+
tileData: particleImageData.data,
|
|
42
|
+
paletteData: rawParticlePalData.data,
|
|
43
|
+
width,
|
|
44
|
+
height,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const png = new PNG({ width, height });
|
|
48
|
+
png.data = image;
|
|
49
|
+
const pngBuffer = streamToBuffer(png.pack());
|
|
50
|
+
|
|
51
|
+
if (outputDir) {
|
|
52
|
+
const dir = `${outputDir}/${ballName}`;
|
|
53
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
54
|
+
const fileName = `${dir}/particle.png`;
|
|
55
|
+
fs.writeFileSync(fileName, pngBuffer);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return pngBuffer;
|
|
59
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Copyright (c) 2026 chickenPoo
|
|
2
|
+
// Licensed under the MIT License. See LICENSE file in project root.
|
|
3
|
+
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
import { PNG } from "pngjs";
|
|
6
|
+
import { extract } from "../extract.js";
|
|
7
|
+
import { render4bppImage } from "../render-4bpp-image.js";
|
|
8
|
+
import { resolveBallSpritePal } from "./resolvers/ball-sprite-palette-resolver.js";
|
|
9
|
+
import { resolveBallSpritePic } from "./resolvers/ball-sprite-resolver.js";
|
|
10
|
+
import { renderBallParticle } from "./render-ball-particle.js";
|
|
11
|
+
|
|
12
|
+
const streamToBuffer = (stream) => new Promise((resolve, reject) => {
|
|
13
|
+
const chunks = [];
|
|
14
|
+
stream.on("data", chunk => chunks.push(chunk));
|
|
15
|
+
stream.on("end", () => resolve(Buffer.concat(chunks)));
|
|
16
|
+
stream.on("error", reject);
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
export async function renderBall(ballName, balls, reader, rom, options = {}) {
|
|
20
|
+
const {
|
|
21
|
+
outputDir = null,
|
|
22
|
+
ballParticles = false,
|
|
23
|
+
} = options;
|
|
24
|
+
if (!rom || !(rom instanceof Uint8Array || Buffer.isBuffer(rom))) {
|
|
25
|
+
throw new TypeError("renderBall(..., rom) requires a ROM Buffer/Uint8Array");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const ball = balls[ballName];
|
|
29
|
+
if (!ball) {
|
|
30
|
+
throw new Error(`Missing Ball: ${ballName}`);
|
|
31
|
+
}
|
|
32
|
+
if (ballParticles) {
|
|
33
|
+
renderBallParticle(ballName, balls, reader, rom, { outputDir });
|
|
34
|
+
}
|
|
35
|
+
const ballPal = resolveBallSpritePal(ball, reader, ballName);
|
|
36
|
+
const ballPic = resolveBallSpritePic(ball, reader, ballName);
|
|
37
|
+
if(!ballPal || !ballPic) {
|
|
38
|
+
throw new Error(`Missing assets for: ${ballName}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const ballImageData = extract(ballPic, rom);
|
|
42
|
+
const rawBallPalData = extract(ballPal, rom);
|
|
43
|
+
const width = 16;
|
|
44
|
+
const height = 48;
|
|
45
|
+
|
|
46
|
+
const image = render4bppImage({
|
|
47
|
+
tileData: ballImageData.data,
|
|
48
|
+
paletteData: rawBallPalData.data,
|
|
49
|
+
width,
|
|
50
|
+
height,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const png = new PNG({ width, height });
|
|
54
|
+
png.data = image;
|
|
55
|
+
const pngBuffer = streamToBuffer(png.pack());
|
|
56
|
+
|
|
57
|
+
if (outputDir) {
|
|
58
|
+
const dir = `${outputDir}/${ballName}`;
|
|
59
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
60
|
+
const fileName = `${dir}/ball.png`;
|
|
61
|
+
fs.writeFileSync(fileName, pngBuffer);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return pngBuffer;
|
|
65
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Copyright (c) 2026 chickenPoo
|
|
2
|
+
// Licensed under the MIT License. See LICENSE file in project root.
|
|
3
|
+
|
|
4
|
+
export function resolveBallParticlePal(ball, reader, ballName) {
|
|
5
|
+
const table = reader.getTable("ballParticlePalTable");
|
|
6
|
+
const entryOffset = table + ball.index * 8;
|
|
7
|
+
const ptr = reader.readPointer(entryOffset);
|
|
8
|
+
return {
|
|
9
|
+
name: `ball_${ballName}_particle_pal`,
|
|
10
|
+
offset: ptr,
|
|
11
|
+
size: 32,
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Copyright (c) 2026 chickenPoo
|
|
2
|
+
// Licensed under the MIT License. See LICENSE file in project root.
|
|
3
|
+
|
|
4
|
+
export function resolveBallParticlePic(ball, reader, ballName) {
|
|
5
|
+
const table = reader.getTable("ballParticlePicTable");
|
|
6
|
+
const entryOffset = table + ball.index * 8;
|
|
7
|
+
const ptr = reader.readPointer(entryOffset);
|
|
8
|
+
return {
|
|
9
|
+
name: `ball_${ballName}_particle_pic`,
|
|
10
|
+
offset: ptr,
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Copyright (c) 2026 chickenPoo
|
|
2
|
+
// Licensed under the MIT License. See LICENSE file in project root.
|
|
3
|
+
|
|
4
|
+
export function resolveBallSpritePal(ball, reader, ballName) {
|
|
5
|
+
const table = reader.getTable("ballAnimPalTable");
|
|
6
|
+
const entryOffset = table + ball.index * 8;
|
|
7
|
+
const ptr = reader.readPointer(entryOffset);
|
|
8
|
+
return {
|
|
9
|
+
name: `ball_${ballName}_pal`,
|
|
10
|
+
offset: ptr,
|
|
11
|
+
size: 32
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Copyright (c) 2026 chickenPoo
|
|
2
|
+
// Licensed under the MIT License. See LICENSE file in project root.
|
|
3
|
+
|
|
4
|
+
export function resolveBallSpritePic(ball, reader, ballName) {
|
|
5
|
+
const table = reader.getTable("ballAnimPicTable");
|
|
6
|
+
const entryOffset = table + ball.index * 8;
|
|
7
|
+
const ptr = reader.readPointer(entryOffset);
|
|
8
|
+
return {
|
|
9
|
+
name: `ball_${ballName}_pic`,
|
|
10
|
+
offset: ptr, // I think this is lz77 compressed so it doesn't need a size value...
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -10,6 +10,7 @@ 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
12
|
import { renderMove } from "./moves/render-moves.js";
|
|
13
|
+
import { renderBall } from "./balls/render-balls.js";
|
|
13
14
|
|
|
14
15
|
const currentDir = path.dirname(fileURLToPath(import.meta.url));
|
|
15
16
|
|
|
@@ -23,6 +24,7 @@ const icons = loadDefaultJson("../item-data/itemData.json");
|
|
|
23
24
|
const trainers = loadDefaultJson("../trainer-data/trainerData.json");
|
|
24
25
|
const trainersBack = loadDefaultJson("../trainer-data/trainerBackData.json");
|
|
25
26
|
const moves = loadDefaultJson("../move-data/moveData.json");
|
|
27
|
+
const balls = loadDefaultJson("../ball-data/ballData.json");
|
|
26
28
|
|
|
27
29
|
export async function renderAllMons(rom, options = {}) {
|
|
28
30
|
if (!rom || !(rom instanceof Uint8Array || Buffer.isBuffer(rom))) {
|
|
@@ -123,6 +125,24 @@ export async function renderAllMoves(rom, options = {}) {
|
|
|
123
125
|
}
|
|
124
126
|
}
|
|
125
127
|
|
|
128
|
+
export async function renderAllBalls(rom, options= {}) {
|
|
129
|
+
const {
|
|
130
|
+
balls: providedBalls = balls,
|
|
131
|
+
outputDir = "./out",
|
|
132
|
+
ballParticles = true,
|
|
133
|
+
} = options;
|
|
134
|
+
|
|
135
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
136
|
+
|
|
137
|
+
const config = getRomConfig(rom);
|
|
138
|
+
const reader = new RomReader(rom, config);
|
|
139
|
+
|
|
140
|
+
for (const ballName of Object.keys(providedBalls)) {
|
|
141
|
+
await renderBall(ballName, providedBalls, reader, rom, { outputDir });
|
|
142
|
+
console.log(`Done: ${ballName}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
126
146
|
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
|
|
127
147
|
if (!rom || !(rom instanceof Uint8Array || Buffer.isBuffer(rom))) {
|
|
128
148
|
throw new TypeError("renderAllGraphics(rom, options) requires rom Buffer/Uint8Array as first argument");
|
|
@@ -134,6 +154,7 @@ export async function renderAllGraphics(rom, options = {}) { // eventually I wil
|
|
|
134
154
|
outputTrainerDir = "./out/trainers",
|
|
135
155
|
outputMoveDir = "./out/moves",
|
|
136
156
|
sortUnusedMoves = true,
|
|
157
|
+
outputBallDir = "./out/balls",
|
|
137
158
|
} = options;
|
|
138
159
|
|
|
139
160
|
await renderAllMons(rom, {
|
|
@@ -155,7 +176,12 @@ export async function renderAllGraphics(rom, options = {}) { // eventually I wil
|
|
|
155
176
|
outputDir: outputMoveDir,
|
|
156
177
|
renderMasterImage: true,
|
|
157
178
|
sortUnused: sortUnusedMoves,
|
|
158
|
-
})
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
await renderAllBalls(rom, {
|
|
182
|
+
outputDir: outputBallDir,
|
|
183
|
+
ballParticles: true,
|
|
184
|
+
});
|
|
159
185
|
}
|
|
160
186
|
|
|
161
187
|
export function loadDefaultRom() {
|