roomie 1.0.0 → 1.0.2
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/README.md +52 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/index.mjs +3 -0
- package/dist/roomie.d.ts +39 -0
- package/dist/roomie.js +171 -0
- package/dist/systems/snes.d.ts +3 -0
- package/dist/systems/snes.js +31 -0
- package/dist/tables/regions.d.ts +46 -0
- package/{lib → dist/tables}/regions.js +46 -47
- package/dist/tables/specs.d.ts +221 -0
- package/{lib → dist/tables}/specs.js +61 -61
- package/dist/types.d.ts +1 -0
- package/dist/types.js +1 -0
- package/dist/utils/stringHelper.d.ts +1 -0
- package/dist/utils/stringHelper.js +8 -0
- package/package.json +28 -29
- package/index.js +0 -1
- package/lib/roomie.js +0 -124
- package/lib/stringHelper.js +0 -13
- package/lib/system.js +0 -10
- package/lib/systems/snes.js +0 -10
package/README.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# roomie
|
|
2
|
+
|
|
3
|
+
Roomie is a library for analyzing basic metadata of ROM files from various classic consoles. It allows extracting relevant information such as the game name, region, code, ROM and RAM size, version, and other console-specific data.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install roomie
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import Roomie from "roomie";
|
|
15
|
+
|
|
16
|
+
const romPath = "/path/to/game.sfc";
|
|
17
|
+
const roomie = new Roomie(romPath);
|
|
18
|
+
|
|
19
|
+
roomie.on("loaded", (info) => {
|
|
20
|
+
console.log("ROM Information:", info);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
await roomie.load(romPath); // Load ROM from file path
|
|
24
|
+
|
|
25
|
+
const romBuffer = Buffer.from([...]); // Load ROM from a Buffer
|
|
26
|
+
await roomie.load(romBuffer);
|
|
27
|
+
|
|
28
|
+
console.log(roomie.info);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Supported Consoles
|
|
32
|
+
|
|
33
|
+
Roomie supports metadata extraction from the following systems:
|
|
34
|
+
|
|
35
|
+
- **Nintendo DS (NDS):** Retrieves data such as the game name, region, game code, ROM and RAM size, version, among others.
|
|
36
|
+
- **Game Boy Advance (GBA):** Extracts information about the title, game code, region, ROM and RAM size, version, etc.
|
|
37
|
+
- **Game Boy (GB):** Provides details about the title, cartridge type, ROM and RAM size, and other metadata.
|
|
38
|
+
- **Super Nintendo / Super Famicom (SNES/SFC):** Detects the ROM type (HiROM/LoROM), game name, region, code, ROM size, and other specific fields.
|
|
39
|
+
|
|
40
|
+
## API
|
|
41
|
+
|
|
42
|
+
- `new Roomie(path: string | Buffer)` – Creates an instance and immediately loads the specified ROM file or buffer. Emits the `'loaded'` event when the information is available.
|
|
43
|
+
- `await roomie.load(pathOrBuffer: string | Buffer)` – Loads or reloads a different ROM file from a file path or a Buffer.
|
|
44
|
+
- `roomie.info: RomInfo` – Object with the analyzed ROM metadata, including system, size, game code, region, and other specific fields.
|
|
45
|
+
- `roomie.rom: Buffer` – Contains the raw bytes of the loaded ROM file.
|
|
46
|
+
- `roomie.system: "nds" | "gba" | "gb" | "sfc"` – Detected system based on the file extension and content.
|
|
47
|
+
|
|
48
|
+
If the system cannot be identified, the library throws errors with codes `unknown_file` (when loading from a path) or `unknown_bytes` (when loading from a Buffer).
|
|
49
|
+
|
|
50
|
+
## License
|
|
51
|
+
|
|
52
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require("./index.mjs");
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
package/dist/index.mjs
ADDED
package/dist/roomie.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import type { SupportedSystem } from "./types";
|
|
3
|
+
export interface RomInfo {
|
|
4
|
+
path: string;
|
|
5
|
+
system: SupportedSystem;
|
|
6
|
+
size: number;
|
|
7
|
+
hash: {
|
|
8
|
+
sha1: string;
|
|
9
|
+
};
|
|
10
|
+
gameCode?: string;
|
|
11
|
+
region?: string;
|
|
12
|
+
sfc?: {
|
|
13
|
+
romSpeed?: string;
|
|
14
|
+
rom?: {
|
|
15
|
+
size?: number;
|
|
16
|
+
type?: string;
|
|
17
|
+
speed?: string;
|
|
18
|
+
};
|
|
19
|
+
ram?: number;
|
|
20
|
+
hardware?: Record<string, unknown>;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export declare class Roomie extends EventEmitter {
|
|
24
|
+
private _path;
|
|
25
|
+
private _rom;
|
|
26
|
+
private _system;
|
|
27
|
+
private _info;
|
|
28
|
+
constructor(path: string);
|
|
29
|
+
private detectSystemFromPath;
|
|
30
|
+
private readGameCode;
|
|
31
|
+
private computeRegion;
|
|
32
|
+
private computeSfcInfo;
|
|
33
|
+
load(pathOrBuffer: string | Buffer): Promise<void>;
|
|
34
|
+
get info(): RomInfo;
|
|
35
|
+
get system(): SupportedSystem;
|
|
36
|
+
get path(): string;
|
|
37
|
+
get rom(): Buffer;
|
|
38
|
+
}
|
|
39
|
+
export default Roomie;
|
package/dist/roomie.js
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { promises as fs } from "node:fs";
|
|
4
|
+
import { regions } from "./tables/regions";
|
|
5
|
+
import { specs } from "./tables/specs";
|
|
6
|
+
import { isHiRomBuffer } from "./systems/snes";
|
|
7
|
+
export class Roomie extends EventEmitter {
|
|
8
|
+
constructor(path) {
|
|
9
|
+
super();
|
|
10
|
+
this.load(path);
|
|
11
|
+
}
|
|
12
|
+
detectSystemFromPath(p) {
|
|
13
|
+
const ext = p.toLowerCase().split(".").pop();
|
|
14
|
+
if (ext === "nds")
|
|
15
|
+
return "nds";
|
|
16
|
+
if (ext === "gba")
|
|
17
|
+
return "gba";
|
|
18
|
+
if (ext === "gb" || ext === "gbc")
|
|
19
|
+
return "gb";
|
|
20
|
+
if (ext === "sfc" || ext === "smc")
|
|
21
|
+
return "sfc";
|
|
22
|
+
// Default to sfc to keep compatibility with original intent; could be improved.
|
|
23
|
+
return "sfc";
|
|
24
|
+
}
|
|
25
|
+
readGameCode(system) {
|
|
26
|
+
const b = this._rom;
|
|
27
|
+
try {
|
|
28
|
+
if (system === "nds" && b.length >= 0x10) {
|
|
29
|
+
return b.subarray(0x0C, 0x10).toString("ascii");
|
|
30
|
+
}
|
|
31
|
+
if (system === "gba" && b.length >= 0xB0) {
|
|
32
|
+
return b.subarray(0xAC, 0xB0).toString("ascii");
|
|
33
|
+
}
|
|
34
|
+
if (system === "gb" && b.length >= 0x0143) {
|
|
35
|
+
return b.subarray(0x013F, 0x0143).toString("ascii");
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch { }
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
computeRegion(system, gameCode) {
|
|
42
|
+
switch (system) {
|
|
43
|
+
case "nds":
|
|
44
|
+
if (gameCode && gameCode.length >= 4) {
|
|
45
|
+
const key = gameCode[3];
|
|
46
|
+
return regions.nds[key];
|
|
47
|
+
}
|
|
48
|
+
return undefined;
|
|
49
|
+
case "gba":
|
|
50
|
+
if (gameCode && gameCode.length >= 4) {
|
|
51
|
+
const key = gameCode[3];
|
|
52
|
+
return regions.gba[key];
|
|
53
|
+
}
|
|
54
|
+
return undefined;
|
|
55
|
+
case "gb":
|
|
56
|
+
if (this._rom.length > 0x14A) {
|
|
57
|
+
const v = this._rom[0x14A];
|
|
58
|
+
return regions.gb[v];
|
|
59
|
+
}
|
|
60
|
+
return undefined;
|
|
61
|
+
case "sfc":
|
|
62
|
+
const hi = isHiRomBuffer(this._rom);
|
|
63
|
+
const off = hi ? 0xFFD9 : 0x7FD9;
|
|
64
|
+
if (this._rom.length > off) {
|
|
65
|
+
const key = this._rom[off];
|
|
66
|
+
return regions.snes[key];
|
|
67
|
+
}
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
computeSfcInfo() {
|
|
72
|
+
if (this._system !== "sfc")
|
|
73
|
+
return undefined;
|
|
74
|
+
const hi = isHiRomBuffer(this._rom);
|
|
75
|
+
const base = hi ? 0xFFD0 : 0x7FD0; // region/speed map nearby
|
|
76
|
+
const romspeedOff = base + 0x09; // D9
|
|
77
|
+
const romTypeOff = base + 0x05; // D5
|
|
78
|
+
const romSizeOff = base + 0x07; // D7
|
|
79
|
+
const ramSizeOff = base + 0x08; // D8
|
|
80
|
+
const out = {};
|
|
81
|
+
if (this._rom.length > romspeedOff) {
|
|
82
|
+
const key = this._rom[romspeedOff].toString(16);
|
|
83
|
+
out.romSpeed = key;
|
|
84
|
+
const spec = specs.sfc?.romspeed?.[key];
|
|
85
|
+
if (spec)
|
|
86
|
+
out.rom = { ...(out.rom || {}), type: spec.type, speed: spec.speed };
|
|
87
|
+
}
|
|
88
|
+
if (this._rom.length > romTypeOff) {
|
|
89
|
+
const hwKey = this._rom[romTypeOff].toString(16);
|
|
90
|
+
const hw = specs.sfc?.hardware?.[hwKey];
|
|
91
|
+
if (hw)
|
|
92
|
+
out.hardware = hw;
|
|
93
|
+
}
|
|
94
|
+
if (this._rom.length > romSizeOff) {
|
|
95
|
+
const exp = this._rom[romSizeOff];
|
|
96
|
+
out.rom = { ...(out.rom || {}), size: Math.pow(2, exp) * 1024 };
|
|
97
|
+
}
|
|
98
|
+
if (this._rom.length > ramSizeOff) {
|
|
99
|
+
const exp = this._rom[ramSizeOff];
|
|
100
|
+
out.ram = Math.pow(2, exp) * 1024;
|
|
101
|
+
}
|
|
102
|
+
return out;
|
|
103
|
+
}
|
|
104
|
+
async load(pathOrBuffer) {
|
|
105
|
+
if (typeof pathOrBuffer === "string") {
|
|
106
|
+
this._path = pathOrBuffer;
|
|
107
|
+
this._rom = await fs.readFile(pathOrBuffer);
|
|
108
|
+
this._system = this.detectSystemFromPath(pathOrBuffer);
|
|
109
|
+
if (!this._system) {
|
|
110
|
+
throw new Error("unknown_file");
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
this._rom = pathOrBuffer;
|
|
115
|
+
this._path = "in-memory";
|
|
116
|
+
const b = this._rom;
|
|
117
|
+
let detected = undefined;
|
|
118
|
+
// Check NDS: game code at 0x0C-0x10 ASCII uppercase letters/digits
|
|
119
|
+
if (b.length >= 0x10) {
|
|
120
|
+
const code = b.subarray(0x0C, 0x10).toString("ascii");
|
|
121
|
+
if (/^[A-Z0-9]{4}$/.test(code)) {
|
|
122
|
+
detected = "nds";
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Check GBA: game code at 0xAC-0xB0 ASCII uppercase letters/digits
|
|
126
|
+
if (!detected && b.length >= 0xB0) {
|
|
127
|
+
const code = b.subarray(0xAC, 0xB0).toString("ascii");
|
|
128
|
+
if (/^[A-Z0-9]{4}$/.test(code)) {
|
|
129
|
+
detected = "gba";
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// Check GB: game code at 0x0134-0x0143 ASCII valid characters
|
|
133
|
+
if (!detected && b.length >= 0x0143) {
|
|
134
|
+
const code = b.subarray(0x0134, 0x0143).toString("ascii");
|
|
135
|
+
if (/^[A-Z0-9]{4,9}$/.test(code)) {
|
|
136
|
+
detected = "gb";
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// Check SFC: use isHiRomBuffer heuristic
|
|
140
|
+
if (!detected) {
|
|
141
|
+
if (b.length > 0x8000 && (isHiRomBuffer(b) || !isHiRomBuffer(b))) {
|
|
142
|
+
detected = "sfc";
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (!detected) {
|
|
146
|
+
throw new Error("unknown_bytes");
|
|
147
|
+
}
|
|
148
|
+
this._system = detected;
|
|
149
|
+
}
|
|
150
|
+
const sha1 = createHash("sha1").update(this._rom).digest("hex");
|
|
151
|
+
const gameCode = this.readGameCode(this._system);
|
|
152
|
+
const info = {
|
|
153
|
+
path: this._path,
|
|
154
|
+
system: this._system,
|
|
155
|
+
size: this._rom.length,
|
|
156
|
+
hash: { sha1 },
|
|
157
|
+
gameCode,
|
|
158
|
+
region: this.computeRegion(this._system, gameCode),
|
|
159
|
+
};
|
|
160
|
+
if (this._system === "sfc") {
|
|
161
|
+
info.sfc = this.computeSfcInfo();
|
|
162
|
+
}
|
|
163
|
+
this._info = info;
|
|
164
|
+
this.emit("loaded", info);
|
|
165
|
+
}
|
|
166
|
+
get info() { return this._info; }
|
|
167
|
+
get system() { return this._system; }
|
|
168
|
+
get path() { return this._path; }
|
|
169
|
+
get rom() { return this._rom; }
|
|
170
|
+
}
|
|
171
|
+
export default Roomie;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
function plausibleHeaderByte(b) {
|
|
3
|
+
return Number.isInteger(b) && b >= 0 && b <= 0xFF;
|
|
4
|
+
}
|
|
5
|
+
/** Heuristic detection. Defaults to LoROM (false) if unsure. */
|
|
6
|
+
export async function isHiRom(path) {
|
|
7
|
+
const buf = await fs.readFile(path);
|
|
8
|
+
return isHiRomBuffer(buf);
|
|
9
|
+
}
|
|
10
|
+
export function isHiRomBuffer(buf) {
|
|
11
|
+
const offLo = 0x7FD5;
|
|
12
|
+
const offHi = 0xFFD5;
|
|
13
|
+
if (buf.length > offHi) {
|
|
14
|
+
const lo = buf[offLo];
|
|
15
|
+
const hi = buf[offHi];
|
|
16
|
+
if (plausibleHeaderByte(lo) && plausibleHeaderByte(hi)) {
|
|
17
|
+
// Very simple heuristic: choose the one whose "map" nibble looks like HiROM (0x21, 0x31, 0x23, 0x32, 0x25)
|
|
18
|
+
const hiromCandidates = new Set([0x21, 0x31, 0x23, 0x32, 0x25]);
|
|
19
|
+
const loromCandidates = new Set([0x20, 0x30]);
|
|
20
|
+
const hiLikely = hiromCandidates.has(hi);
|
|
21
|
+
const loLikely = loromCandidates.has(lo);
|
|
22
|
+
if (hiLikely && !loLikely)
|
|
23
|
+
return true;
|
|
24
|
+
if (loLikely && !hiLikely)
|
|
25
|
+
return false;
|
|
26
|
+
// If both plausible, prefer the one with a valid checksum complement just as a tie-breaker (not implemented)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// Fallback: LoROM
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export declare const regions: {
|
|
2
|
+
readonly nds: {
|
|
3
|
+
readonly A: "asia";
|
|
4
|
+
readonly C: "china";
|
|
5
|
+
readonly P: "europe";
|
|
6
|
+
readonly E: "americas";
|
|
7
|
+
readonly J: "japan";
|
|
8
|
+
readonly F: "french";
|
|
9
|
+
readonly H: "dutch";
|
|
10
|
+
readonly I: "italian";
|
|
11
|
+
readonly K: "korean";
|
|
12
|
+
readonly L: "usa#2";
|
|
13
|
+
readonly M: "swedish";
|
|
14
|
+
readonly N: "norwegian";
|
|
15
|
+
readonly O: "international";
|
|
16
|
+
readonly Q: "danish";
|
|
17
|
+
readonly R: "russian";
|
|
18
|
+
readonly S: "spanish";
|
|
19
|
+
readonly T: "usa+aus";
|
|
20
|
+
readonly U: "australia";
|
|
21
|
+
readonly V: "eur+aus";
|
|
22
|
+
readonly W: "europe#3";
|
|
23
|
+
readonly X: "europe#4";
|
|
24
|
+
readonly Y: "europe#5";
|
|
25
|
+
readonly Z: "europe#5";
|
|
26
|
+
};
|
|
27
|
+
readonly gba: {
|
|
28
|
+
readonly J: "japan";
|
|
29
|
+
readonly E: "english";
|
|
30
|
+
readonly P: "europe";
|
|
31
|
+
readonly D: "german";
|
|
32
|
+
readonly F: "french";
|
|
33
|
+
readonly I: "italian";
|
|
34
|
+
readonly S: "spanish";
|
|
35
|
+
};
|
|
36
|
+
readonly gb: {
|
|
37
|
+
readonly 0: "japan";
|
|
38
|
+
readonly 1: "overseas";
|
|
39
|
+
};
|
|
40
|
+
readonly snes: {
|
|
41
|
+
readonly 0: "japan";
|
|
42
|
+
readonly 1: "americas";
|
|
43
|
+
readonly 2: "europe";
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
export type SupportedSystemsForRegions = keyof typeof regions;
|
|
@@ -1,47 +1,46 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"K": "korean",
|
|
13
|
-
"L": "usa#2",
|
|
14
|
-
"M": "swedish",
|
|
15
|
-
"N": "norwegian",
|
|
16
|
-
"O": "international",
|
|
17
|
-
"Q": "danish",
|
|
18
|
-
"R": "russian",
|
|
19
|
-
"S": "spanish",
|
|
20
|
-
"T": "usa+aus",
|
|
21
|
-
"U": "australia",
|
|
22
|
-
"V": "eur+aus",
|
|
23
|
-
"W": "europe#3",
|
|
24
|
-
"X": "europe#4",
|
|
25
|
-
"Y": "europe#5",
|
|
26
|
-
"Z": "europe#5"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
1
|
+
/* Auto-generated from original JS */
|
|
2
|
+
export const regions = {
|
|
3
|
+
nds: {
|
|
4
|
+
"A": "asia",
|
|
5
|
+
"C": "china",
|
|
6
|
+
"P": "europe",
|
|
7
|
+
"E": "americas",
|
|
8
|
+
"J": "japan",
|
|
9
|
+
"F": "french",
|
|
10
|
+
"H": "dutch",
|
|
11
|
+
"I": "italian",
|
|
12
|
+
"K": "korean",
|
|
13
|
+
"L": "usa#2",
|
|
14
|
+
"M": "swedish",
|
|
15
|
+
"N": "norwegian",
|
|
16
|
+
"O": "international",
|
|
17
|
+
"Q": "danish",
|
|
18
|
+
"R": "russian",
|
|
19
|
+
"S": "spanish",
|
|
20
|
+
"T": "usa+aus",
|
|
21
|
+
"U": "australia",
|
|
22
|
+
"V": "eur+aus",
|
|
23
|
+
"W": "europe#3",
|
|
24
|
+
"X": "europe#4",
|
|
25
|
+
"Y": "europe#5",
|
|
26
|
+
"Z": "europe#5"
|
|
27
|
+
},
|
|
28
|
+
gba: {
|
|
29
|
+
"J": "japan",
|
|
30
|
+
"E": "english",
|
|
31
|
+
"P": "europe",
|
|
32
|
+
"D": "german",
|
|
33
|
+
"F": "french",
|
|
34
|
+
"I": "italian",
|
|
35
|
+
"S": "spanish"
|
|
36
|
+
},
|
|
37
|
+
gb: {
|
|
38
|
+
0: "japan",
|
|
39
|
+
1: "overseas"
|
|
40
|
+
},
|
|
41
|
+
snes: {
|
|
42
|
+
0: "japan",
|
|
43
|
+
1: "americas",
|
|
44
|
+
2: "europe"
|
|
45
|
+
}
|
|
46
|
+
};
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
export declare const specs: {
|
|
2
|
+
readonly nds: {
|
|
3
|
+
readonly unitcode: {
|
|
4
|
+
readonly "0": "nds";
|
|
5
|
+
readonly "1": "nds/dsi";
|
|
6
|
+
readonly "2": "dsi";
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
readonly gb: {
|
|
10
|
+
readonly a: "";
|
|
11
|
+
};
|
|
12
|
+
readonly sfc: {
|
|
13
|
+
readonly hardware: {
|
|
14
|
+
readonly "0": {
|
|
15
|
+
readonly coprocessor: false;
|
|
16
|
+
readonly rom: true;
|
|
17
|
+
};
|
|
18
|
+
readonly "1": {
|
|
19
|
+
readonly coprocessor: false;
|
|
20
|
+
readonly rom: true;
|
|
21
|
+
readonly ram: true;
|
|
22
|
+
};
|
|
23
|
+
readonly "2": {
|
|
24
|
+
readonly coprocessor: false;
|
|
25
|
+
readonly rom: true;
|
|
26
|
+
readonly ram: true;
|
|
27
|
+
readonly battery: true;
|
|
28
|
+
};
|
|
29
|
+
readonly "3": {
|
|
30
|
+
readonly coprocessor: "dsp";
|
|
31
|
+
readonly rom: true;
|
|
32
|
+
};
|
|
33
|
+
readonly "4": {
|
|
34
|
+
readonly coprocessor: "dsp";
|
|
35
|
+
readonly rom: true;
|
|
36
|
+
readonly ram: true;
|
|
37
|
+
};
|
|
38
|
+
readonly "5": {
|
|
39
|
+
readonly coprocessor: "dsp";
|
|
40
|
+
readonly rom: true;
|
|
41
|
+
readonly ram: true;
|
|
42
|
+
readonly battery: true;
|
|
43
|
+
};
|
|
44
|
+
readonly "6": {
|
|
45
|
+
readonly coprocessor: "dsp";
|
|
46
|
+
readonly rom: true;
|
|
47
|
+
readonly battery: true;
|
|
48
|
+
};
|
|
49
|
+
readonly "13": {
|
|
50
|
+
readonly coprocessor: "gsu/superFX";
|
|
51
|
+
readonly rom: true;
|
|
52
|
+
};
|
|
53
|
+
readonly "14": {
|
|
54
|
+
readonly coprocessor: "gsu/superFX";
|
|
55
|
+
readonly rom: true;
|
|
56
|
+
readonly ram: true;
|
|
57
|
+
};
|
|
58
|
+
readonly "15": {
|
|
59
|
+
readonly coprocessor: "gsu/superFX";
|
|
60
|
+
readonly rom: true;
|
|
61
|
+
readonly ram: true;
|
|
62
|
+
readonly battery: true;
|
|
63
|
+
};
|
|
64
|
+
readonly "16": {
|
|
65
|
+
readonly coprocessor: "gsu/superFX";
|
|
66
|
+
readonly rom: true;
|
|
67
|
+
readonly battery: true;
|
|
68
|
+
};
|
|
69
|
+
readonly "23": {
|
|
70
|
+
readonly coprocessor: "obc1";
|
|
71
|
+
readonly rom: true;
|
|
72
|
+
};
|
|
73
|
+
readonly "24": {
|
|
74
|
+
readonly coprocessor: "obc1";
|
|
75
|
+
readonly rom: true;
|
|
76
|
+
readonly ram: true;
|
|
77
|
+
};
|
|
78
|
+
readonly "25": {
|
|
79
|
+
readonly coprocessor: "obc1";
|
|
80
|
+
readonly rom: true;
|
|
81
|
+
readonly ram: true;
|
|
82
|
+
readonly battery: true;
|
|
83
|
+
};
|
|
84
|
+
readonly "26": {
|
|
85
|
+
readonly coprocessor: "obc1";
|
|
86
|
+
readonly rom: true;
|
|
87
|
+
readonly battery: true;
|
|
88
|
+
};
|
|
89
|
+
readonly "33": {
|
|
90
|
+
readonly coprocessor: "sa-1";
|
|
91
|
+
readonly rom: true;
|
|
92
|
+
};
|
|
93
|
+
readonly "34": {
|
|
94
|
+
readonly coprocessor: "sa-1";
|
|
95
|
+
readonly rom: true;
|
|
96
|
+
readonly ram: true;
|
|
97
|
+
};
|
|
98
|
+
readonly "35": {
|
|
99
|
+
readonly coprocessor: "sa-1";
|
|
100
|
+
readonly rom: true;
|
|
101
|
+
readonly ram: true;
|
|
102
|
+
readonly battery: true;
|
|
103
|
+
};
|
|
104
|
+
readonly "36": {
|
|
105
|
+
readonly coprocessor: "sa-1";
|
|
106
|
+
readonly rom: true;
|
|
107
|
+
readonly battery: true;
|
|
108
|
+
};
|
|
109
|
+
readonly "43": {
|
|
110
|
+
readonly coprocessor: "s-dd1";
|
|
111
|
+
readonly rom: true;
|
|
112
|
+
};
|
|
113
|
+
readonly "44": {
|
|
114
|
+
readonly coprocessor: "s-dd1";
|
|
115
|
+
readonly rom: true;
|
|
116
|
+
readonly ram: true;
|
|
117
|
+
};
|
|
118
|
+
readonly "45": {
|
|
119
|
+
readonly coprocessor: "s-dd1";
|
|
120
|
+
readonly rom: true;
|
|
121
|
+
readonly ram: true;
|
|
122
|
+
readonly battery: true;
|
|
123
|
+
};
|
|
124
|
+
readonly "46": {
|
|
125
|
+
readonly coprocessor: "s-dd1";
|
|
126
|
+
readonly rom: true;
|
|
127
|
+
readonly battery: true;
|
|
128
|
+
};
|
|
129
|
+
readonly "53": {
|
|
130
|
+
readonly coprocessor: "s-rtc";
|
|
131
|
+
readonly rom: true;
|
|
132
|
+
};
|
|
133
|
+
readonly "54": {
|
|
134
|
+
readonly coprocessor: "s-rtc";
|
|
135
|
+
readonly rom: true;
|
|
136
|
+
readonly ram: true;
|
|
137
|
+
};
|
|
138
|
+
readonly "55": {
|
|
139
|
+
readonly coprocessor: "s-rtc";
|
|
140
|
+
readonly rom: true;
|
|
141
|
+
readonly ram: true;
|
|
142
|
+
readonly battery: true;
|
|
143
|
+
};
|
|
144
|
+
readonly "56": {
|
|
145
|
+
readonly coprocessor: "s-rtc";
|
|
146
|
+
readonly rom: true;
|
|
147
|
+
readonly battery: true;
|
|
148
|
+
};
|
|
149
|
+
readonly e3: {
|
|
150
|
+
readonly coprocessor: "other";
|
|
151
|
+
readonly rom: true;
|
|
152
|
+
};
|
|
153
|
+
readonly e4: {
|
|
154
|
+
readonly coprocessor: "other";
|
|
155
|
+
readonly rom: true;
|
|
156
|
+
readonly ram: true;
|
|
157
|
+
};
|
|
158
|
+
readonly e5: {
|
|
159
|
+
readonly coprocessor: "other";
|
|
160
|
+
readonly rom: true;
|
|
161
|
+
readonly ram: true;
|
|
162
|
+
readonly battery: true;
|
|
163
|
+
};
|
|
164
|
+
readonly e6: {
|
|
165
|
+
readonly coprocessor: "other";
|
|
166
|
+
readonly rom: true;
|
|
167
|
+
readonly battery: true;
|
|
168
|
+
};
|
|
169
|
+
readonly f3: {
|
|
170
|
+
readonly coprocessor: "custom";
|
|
171
|
+
readonly rom: true;
|
|
172
|
+
};
|
|
173
|
+
readonly f4: {
|
|
174
|
+
readonly coprocessor: "custom";
|
|
175
|
+
readonly rom: true;
|
|
176
|
+
readonly ram: true;
|
|
177
|
+
};
|
|
178
|
+
readonly f5: {
|
|
179
|
+
readonly coprocessor: "custom";
|
|
180
|
+
readonly rom: true;
|
|
181
|
+
readonly ram: true;
|
|
182
|
+
readonly battery: true;
|
|
183
|
+
};
|
|
184
|
+
readonly f6: {
|
|
185
|
+
readonly coprocessor: "custom";
|
|
186
|
+
readonly rom: true;
|
|
187
|
+
readonly battery: true;
|
|
188
|
+
};
|
|
189
|
+
};
|
|
190
|
+
readonly romspeed: {
|
|
191
|
+
readonly "20": {
|
|
192
|
+
readonly type: "LoROM";
|
|
193
|
+
readonly speed: "2.68MHz";
|
|
194
|
+
};
|
|
195
|
+
readonly "21": {
|
|
196
|
+
readonly type: "HiROM";
|
|
197
|
+
readonly speed: "2.68MHz";
|
|
198
|
+
};
|
|
199
|
+
readonly "23": {
|
|
200
|
+
readonly type: "SA-1";
|
|
201
|
+
};
|
|
202
|
+
readonly "25": {
|
|
203
|
+
readonly type: "ExHiROM";
|
|
204
|
+
readonly speed: "2.68MHz";
|
|
205
|
+
};
|
|
206
|
+
readonly "30": {
|
|
207
|
+
readonly type: "LoROM";
|
|
208
|
+
readonly speed: "3.58MHz";
|
|
209
|
+
};
|
|
210
|
+
readonly "31": {
|
|
211
|
+
readonly type: "HiROM";
|
|
212
|
+
readonly speed: "3.58MHz";
|
|
213
|
+
};
|
|
214
|
+
readonly "32": {
|
|
215
|
+
readonly type: "ExHiROM";
|
|
216
|
+
readonly speed: "3.58MHz";
|
|
217
|
+
};
|
|
218
|
+
};
|
|
219
|
+
};
|
|
220
|
+
};
|
|
221
|
+
export type SupportedSystemsForSpecs = keyof typeof specs;
|
|
@@ -1,61 +1,61 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"2": { coprocessor: false, rom: true, ram: true, battery: true },
|
|
18
|
-
"3": { coprocessor: "dsp", rom: true },
|
|
19
|
-
"4": { coprocessor: "dsp", rom: true, ram: true },
|
|
20
|
-
"5": { coprocessor: "dsp", rom: true, ram: true, battery: true },
|
|
21
|
-
"6": { coprocessor: "dsp", rom: true, battery: true },
|
|
22
|
-
"13": { coprocessor: "gsu/superFX", rom: true },
|
|
23
|
-
"14": { coprocessor: "gsu/superFX", rom: true, ram: true },
|
|
24
|
-
"15": { coprocessor: "gsu/superFX", rom: true, ram: true, battery: true },
|
|
25
|
-
"16": { coprocessor: "gsu/superFX", rom: true, battery: true },
|
|
26
|
-
"23": { coprocessor: "obc1", rom: true },
|
|
27
|
-
"24": { coprocessor: "obc1", rom: true, ram: true },
|
|
28
|
-
"25": { coprocessor: "obc1", rom: true, ram: true, battery: true },
|
|
29
|
-
"26": { coprocessor: "obc1", rom: true, battery: true },
|
|
30
|
-
"33": { coprocessor: "sa-1", rom: true },
|
|
31
|
-
"34": { coprocessor: "sa-1", rom: true, ram: true },
|
|
32
|
-
"35": { coprocessor: "sa-1", rom: true, ram: true, battery: true },
|
|
33
|
-
"36": { coprocessor: "sa-1", rom: true, battery: true },
|
|
34
|
-
"43": { coprocessor: "s-dd1", rom: true },
|
|
35
|
-
"44": { coprocessor: "s-dd1", rom: true, ram: true },
|
|
36
|
-
"45": { coprocessor: "s-dd1", rom: true, ram: true, battery: true },
|
|
37
|
-
"46": { coprocessor: "s-dd1", rom: true, battery: true },
|
|
38
|
-
"53": { coprocessor: "s-rtc", rom: true },
|
|
39
|
-
"54": { coprocessor: "s-rtc", rom: true, ram: true },
|
|
40
|
-
"55": { coprocessor: "s-rtc", rom: true, ram: true, battery: true },
|
|
41
|
-
"56": { coprocessor: "s-rtc", rom: true, battery: true },
|
|
42
|
-
"e3": { coprocessor: "other", rom: true },
|
|
43
|
-
"e4": { coprocessor: "other", rom: true, ram: true },
|
|
44
|
-
"e5": { coprocessor: "other", rom: true, ram: true, battery: true },
|
|
45
|
-
"e6": { coprocessor: "other", rom: true, battery: true },
|
|
46
|
-
"f3": { coprocessor: "custom", rom: true },
|
|
47
|
-
"f4": { coprocessor: "custom", rom: true, ram: true },
|
|
48
|
-
"f5": { coprocessor: "custom", rom: true, ram: true, battery: true },
|
|
49
|
-
"f6": { coprocessor: "custom", rom: true, battery: true },
|
|
50
|
-
},
|
|
51
|
-
romspeed: {
|
|
52
|
-
"20": { type: "LoROM", speed: "2.68MHz" },
|
|
53
|
-
"21": { type: "HiROM", speed: "2.68MHz" },
|
|
54
|
-
"23": { type: "SA-1"},
|
|
55
|
-
"25": { type: "ExHiROM", speed: "2.68MHz" },
|
|
56
|
-
"30": { type: "LoROM", speed: "3.58MHz" },
|
|
57
|
-
"31": { type: "HiROM", speed: "3.58MHz" },
|
|
58
|
-
"32": { type: "ExHiROM", speed: "3.58MHz" },
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
1
|
+
/* Auto-generated from original JS */
|
|
2
|
+
export const specs = {
|
|
3
|
+
nds: {
|
|
4
|
+
unitcode: {
|
|
5
|
+
"0": "nds",
|
|
6
|
+
"1": "nds/dsi",
|
|
7
|
+
"2": "dsi"
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
gb: {
|
|
11
|
+
"a": ""
|
|
12
|
+
},
|
|
13
|
+
sfc: {
|
|
14
|
+
hardware: {
|
|
15
|
+
"0": { coprocessor: false, rom: true },
|
|
16
|
+
"1": { coprocessor: false, rom: true, ram: true },
|
|
17
|
+
"2": { coprocessor: false, rom: true, ram: true, battery: true },
|
|
18
|
+
"3": { coprocessor: "dsp", rom: true },
|
|
19
|
+
"4": { coprocessor: "dsp", rom: true, ram: true },
|
|
20
|
+
"5": { coprocessor: "dsp", rom: true, ram: true, battery: true },
|
|
21
|
+
"6": { coprocessor: "dsp", rom: true, battery: true },
|
|
22
|
+
"13": { coprocessor: "gsu/superFX", rom: true },
|
|
23
|
+
"14": { coprocessor: "gsu/superFX", rom: true, ram: true },
|
|
24
|
+
"15": { coprocessor: "gsu/superFX", rom: true, ram: true, battery: true },
|
|
25
|
+
"16": { coprocessor: "gsu/superFX", rom: true, battery: true },
|
|
26
|
+
"23": { coprocessor: "obc1", rom: true },
|
|
27
|
+
"24": { coprocessor: "obc1", rom: true, ram: true },
|
|
28
|
+
"25": { coprocessor: "obc1", rom: true, ram: true, battery: true },
|
|
29
|
+
"26": { coprocessor: "obc1", rom: true, battery: true },
|
|
30
|
+
"33": { coprocessor: "sa-1", rom: true },
|
|
31
|
+
"34": { coprocessor: "sa-1", rom: true, ram: true },
|
|
32
|
+
"35": { coprocessor: "sa-1", rom: true, ram: true, battery: true },
|
|
33
|
+
"36": { coprocessor: "sa-1", rom: true, battery: true },
|
|
34
|
+
"43": { coprocessor: "s-dd1", rom: true },
|
|
35
|
+
"44": { coprocessor: "s-dd1", rom: true, ram: true },
|
|
36
|
+
"45": { coprocessor: "s-dd1", rom: true, ram: true, battery: true },
|
|
37
|
+
"46": { coprocessor: "s-dd1", rom: true, battery: true },
|
|
38
|
+
"53": { coprocessor: "s-rtc", rom: true },
|
|
39
|
+
"54": { coprocessor: "s-rtc", rom: true, ram: true },
|
|
40
|
+
"55": { coprocessor: "s-rtc", rom: true, ram: true, battery: true },
|
|
41
|
+
"56": { coprocessor: "s-rtc", rom: true, battery: true },
|
|
42
|
+
"e3": { coprocessor: "other", rom: true },
|
|
43
|
+
"e4": { coprocessor: "other", rom: true, ram: true },
|
|
44
|
+
"e5": { coprocessor: "other", rom: true, ram: true, battery: true },
|
|
45
|
+
"e6": { coprocessor: "other", rom: true, battery: true },
|
|
46
|
+
"f3": { coprocessor: "custom", rom: true },
|
|
47
|
+
"f4": { coprocessor: "custom", rom: true, ram: true },
|
|
48
|
+
"f5": { coprocessor: "custom", rom: true, ram: true, battery: true },
|
|
49
|
+
"f6": { coprocessor: "custom", rom: true, battery: true },
|
|
50
|
+
},
|
|
51
|
+
romspeed: {
|
|
52
|
+
"20": { type: "LoROM", speed: "2.68MHz" },
|
|
53
|
+
"21": { type: "HiROM", speed: "2.68MHz" },
|
|
54
|
+
"23": { type: "SA-1" },
|
|
55
|
+
"25": { type: "ExHiROM", speed: "2.68MHz" },
|
|
56
|
+
"30": { type: "LoROM", speed: "3.58MHz" },
|
|
57
|
+
"31": { type: "HiROM", speed: "3.58MHz" },
|
|
58
|
+
"32": { type: "ExHiROM", speed: "3.58MHz" },
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
};
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type SupportedSystem = "nds" | "gba" | "gb" | "sfc";
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function hexEncode(input: string): string;
|
package/package.json
CHANGED
|
@@ -1,36 +1,35 @@
|
|
|
1
1
|
{
|
|
2
|
-
"dependencies": {
|
|
3
|
-
"cryptography": "^1.2.3",
|
|
4
|
-
"path": "^0.12.7"
|
|
5
|
-
},
|
|
6
2
|
"name": "roomie",
|
|
7
|
-
"version": "1.0.
|
|
8
|
-
"description": "ROM
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "ROM metadata helper",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/index.cjs",
|
|
8
|
+
"module": "dist/index.mjs",
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"require": "./dist/index.cjs",
|
|
13
|
+
"import": "./dist/index.mjs",
|
|
14
|
+
"types": "./dist/index.d.ts"
|
|
15
|
+
}
|
|
16
16
|
},
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"url": "git+https://github.com/nikitacontreras/roomie.git"
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=18"
|
|
20
19
|
},
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"emulation",
|
|
24
|
-
"emurom",
|
|
25
|
-
"snes",
|
|
26
|
-
"gba",
|
|
27
|
-
"nds",
|
|
28
|
-
"nes"
|
|
20
|
+
"files": [
|
|
21
|
+
"dist"
|
|
29
22
|
],
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
"
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc && node scripts/emit-dual.js",
|
|
25
|
+
"clean": "rimraf dist",
|
|
26
|
+
"prepublishOnly": "npm run build",
|
|
27
|
+
"typecheck": "tsc --noEmit",
|
|
28
|
+
"prepare": "npm run clean && npm run build"
|
|
34
29
|
},
|
|
35
|
-
"
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/node": "^20.10.0",
|
|
32
|
+
"rimraf": "^5.0.0",
|
|
33
|
+
"typescript": "^5.6.0"
|
|
34
|
+
}
|
|
36
35
|
}
|
package/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
module.exports = require("./lib/roomie")
|
package/lib/roomie.js
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
const { createHash } = require("cryptography");
|
|
2
|
-
const { EventEmitter } = require('events');
|
|
3
|
-
const { regions } = require("./regions")
|
|
4
|
-
const { specs } = require("./specs")
|
|
5
|
-
const { stringHelper } = require("./stringHelper")
|
|
6
|
-
const fs = require('fs');
|
|
7
|
-
const { systems } = require('./system')
|
|
8
|
-
|
|
9
|
-
let rom, system;
|
|
10
|
-
|
|
11
|
-
class Roomie extends EventEmitter {
|
|
12
|
-
constructor(path) {
|
|
13
|
-
super()
|
|
14
|
-
this.load(path)
|
|
15
|
-
|
|
16
|
-
this.__rom, this.__system, this.__romInfo, this.__path
|
|
17
|
-
this.name = this._name()
|
|
18
|
-
this.gameid = this._gameid()
|
|
19
|
-
this.region = this._region()
|
|
20
|
-
this.gamecode = this._gamecode()
|
|
21
|
-
this.cartridge = this._cartridge()
|
|
22
|
-
}
|
|
23
|
-
get system() {
|
|
24
|
-
return this.__system
|
|
25
|
-
}
|
|
26
|
-
set system(extension) {
|
|
27
|
-
this.__system = extension
|
|
28
|
-
}
|
|
29
|
-
get rom() {
|
|
30
|
-
return this.__rom
|
|
31
|
-
}
|
|
32
|
-
set rom(buffer) {
|
|
33
|
-
this.__rom = buffer
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
load = (path) => {
|
|
37
|
-
this.__path = path
|
|
38
|
-
this.__rom = fs.readFileSync(path)
|
|
39
|
-
this.__romInfo = fs.statSync(path)
|
|
40
|
-
this.__system = path.split(".")[path.split().length]
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
_name() {
|
|
44
|
-
switch (this.system) {
|
|
45
|
-
case "nds":
|
|
46
|
-
return this.rom.slice(0x0, 0xB).toString().trim()
|
|
47
|
-
case "gba":
|
|
48
|
-
return this.rom.slice(0xA0, 0xA0 + 12).toString().trim()
|
|
49
|
-
case "gb":
|
|
50
|
-
return this.rom.slice(0x134, 0x134 + 9).toString().trim()
|
|
51
|
-
case "sfc":
|
|
52
|
-
return this.rom.slice(systems.snes.isHiRom(this.__path, 0x7FC0), systems.snes.isHiRom(this.__path, 0x7FC0) + 21).toString().trim()
|
|
53
|
-
case "n64":
|
|
54
|
-
return this.rom.slice(0x20, 0x20 + 14).toString().match(/.{1,2}/g).reverse().join('').split("").reverse().join("").trim()
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
_gamecode() {
|
|
59
|
-
switch (this.system) {
|
|
60
|
-
case "nds":
|
|
61
|
-
return this.rom.slice(0xD, 0xD + 2).toString()
|
|
62
|
-
case "gba":
|
|
63
|
-
return this.rom.slice(0xAD, 0xAD + 2).toString()
|
|
64
|
-
case "sfc":
|
|
65
|
-
return this.rom.slice(systems.snes.isHiRom(this.__path, 0x7FB2), systems.snes.isHiRom(this.__path, 0x7FB2) + 4).toString("ASCII").trim()
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
_gameid() {
|
|
70
|
-
switch (this.system) {
|
|
71
|
-
case "nds":
|
|
72
|
-
return "NTR-" + this.rom.slice(0xC, 0xC + 4).toString()
|
|
73
|
-
case "gba":
|
|
74
|
-
return "AGB-" + this.rom.slice(0xAC, 0xAC + 4).toString()
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
_cartridge() {
|
|
79
|
-
switch (this.system) {
|
|
80
|
-
case "nds":
|
|
81
|
-
return {
|
|
82
|
-
unit: specs.nds.unitcode[this.rom[0x012].toString(16)],
|
|
83
|
-
developer: this.rom[0x012].toString(16),
|
|
84
|
-
version: this.rom[0x01E],
|
|
85
|
-
title: this.rom.slice(0x265440, 0x265440 + 0x3B).toString().replace(/\x00/g, '').replace(/(\\n)/g, "\n")
|
|
86
|
-
}
|
|
87
|
-
case "gba":
|
|
88
|
-
return {
|
|
89
|
-
developer: this.rom.slice(0xB0, 0xB0 + 0x2).toString()
|
|
90
|
-
}
|
|
91
|
-
case "gb":
|
|
92
|
-
return {
|
|
93
|
-
rom: {
|
|
94
|
-
size: this.rom[0x148]
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
case "sfc":
|
|
98
|
-
return {
|
|
99
|
-
romSpeed: (systems.snes.isHiRom(this.__path) ? this.rom[0xFFD9] : this.rom[0x7FD9]).toString().trim(),
|
|
100
|
-
rom: {
|
|
101
|
-
size: 2 ** (2 ^ this.rom[systems.snes.isHiRom(this.__path, 0x7FD7)]) * 1000,
|
|
102
|
-
specs: specs.sfc.romspeed[this.rom[systems.snes.isHiRom(this.__path, 0x7FD5)].toString(16)]
|
|
103
|
-
},
|
|
104
|
-
ram: 2 ** (2 ^ (this.rom[systems.snes.isHiRom(this.__path, 0x7FD8)])) * 1000,
|
|
105
|
-
hardware: specs.sfc.hardware[this.rom[systems.snes.isHiRom(this.__path, 0x7FD6)].toString(16)],
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
_region() {
|
|
111
|
-
switch (this.system) {
|
|
112
|
-
case "nds":
|
|
113
|
-
return regions.nds[(this.gameid[this.gameid.length - 1])]
|
|
114
|
-
case "gba":
|
|
115
|
-
return regions.gba[(this.gameid[this.gameid.length - 1])]
|
|
116
|
-
case "gb":
|
|
117
|
-
return regions.gb[this.rom[0x14A].toString()]
|
|
118
|
-
case "sfc":
|
|
119
|
-
return regions.snes[this.rom[systems.snes.isHiRom(this.__path, 0x7FD9)].toString()]
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
module.exports = Roomie
|
package/lib/stringHelper.js
DELETED
package/lib/system.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
const fs = require("fs")
|
|
2
|
-
files = {}
|
|
3
|
-
fs.readdirSync(`${__dirname}/systems`)
|
|
4
|
-
.filter((module) => {
|
|
5
|
-
return module.slice(module.length - 3) === '.js';
|
|
6
|
-
})
|
|
7
|
-
.forEach((module) => {
|
|
8
|
-
files[module.split(".")[0]] = require(`${__dirname}/systems/` + module);
|
|
9
|
-
});
|
|
10
|
-
module.exports.systems = files
|