arktosmos-pkmn-sav-editor
v1.0.1
Published
Pokemon save file editor library supporting Gen 1-3 (RGB/Y, GSC, RSE/FRLG)
Maintainers
Readme
arktosmos-pkmn-sav-editor
A TypeScript library for parsing and editing Pokemon save files from Generations 1-3.
Supported Games
| Generation | Games | Locales | |------------|-------|---------| | Gen 1 | Red, Blue, Yellow | English, Japanese | | Gen 2 | Gold, Silver, Crystal | English, Japanese | | Gen 3 | Ruby, Sapphire, FireRed, LeafGreen, Emerald | English, Japanese |
Installation
npm install arktosmos-pkmn-sav-editorUsage
Basic Example
import { parseSAV, flashSAV, isSAV1, isSAV2, isSAV3 } from 'arktosmos-pkmn-sav-editor';
import { readFileSync, writeFileSync } from 'fs';
// Load a save file
const buffer = new Uint8Array(readFileSync('Pokemon Red.sav'));
// Parse the save data
const sav = parseSAV(buffer);
console.log(sav.game); // ['RB', 'en']
console.log(sav.tid); // Trainer ID
console.log(sav.money); // Current money
console.log(sav.party); // Party Pokemon (up to 6)
console.log(sav.boxes); // PC box Pokemon
// Modify the save
sav.money = 999999;
// Write back to file
const newBuffer = flashSAV(sav, buffer);
writeFileSync('Pokemon Red.sav', newBuffer);Type Guards
Use type guards to access generation-specific fields:
import { parseSAV, isSAV1, isSAV2, isSAV3 } from 'arktosmos-pkmn-sav-editor';
const sav = parseSAV(buffer);
if (isSAV1(sav)) {
// Gen 1 specific fields
console.log(sav.rivalName); // Rival's name
console.log(sav.badges); // 8 Kanto badges
console.log(sav.coin); // Game Corner coins
}
if (isSAV2(sav)) {
// Gen 2 specific fields
console.log(sav.badges); // 16 badges (Johto + Kanto)
console.log(sav.playerColor); // Player sprite color
console.log(sav.bag.tmhm); // TM/HM pocket
}
if (isSAV3(sav)) {
// Gen 3 specific fields
console.log(sav.sid); // Secret ID
console.log(sav.pokedex.nationalDex); // National Dex unlocked?
console.log(sav.league?.hallOfFame); // Hall of Fame completed?
}Working with Pokemon
const sav = parseSAV(buffer);
// Access party Pokemon
for (const mon of sav.party) {
if (mon.id > 0) { // Valid Pokemon
console.log(`Species: ${mon.id}, Level: ${mon.lv}`);
console.log(`Moves: ${mon.moves.map(m => m.id)}`);
console.log(`EVs: HP=${mon.evs.hp}, ATK=${mon.evs.atk}`);
}
}
// Modify a Pokemon
sav.party[0].lv = 100;
// Access PC boxes
for (const box of sav.boxes) {
const pokemonCount = box.mons.filter(m => m.id > 0).length;
console.log(`Box has ${pokemonCount} Pokemon`);
}Experience Utilities
import { getLevel, getMinExp, getLv100Exp } from 'arktosmos-pkmn-sav-editor';
// Growth rates: 0=Medium Fast, 1=Erratic, 2=Fluctuating, 3=Medium Slow, 4=Fast, 5=Slow
// Get level from experience points
const level = getLevel(100000, 0); // Medium Fast growth
// Get minimum exp for a level
const expNeeded = getMinExp(50, 0); // Exp needed for level 50
// Get max exp (level 100)
const maxExp = getLv100Exp(0);API Reference
Core Functions
| Function | Description |
|----------|-------------|
| parseSAV(buffer) | Parse a save file buffer into a SAV object |
| flashSAV(sav, originalBuffer) | Encode a SAV object back to binary (with checksum) |
| getSAVType(buffer) | Detect game version and locale from buffer |
Type Guards
| Function | Description |
|----------|-------------|
| isSAV1(sav) | Check if save is Gen 1 (Red/Blue/Yellow) |
| isSAV2(sav) | Check if save is Gen 2 (Gold/Silver/Crystal) |
| isSAV3(sav) | Check if save is Gen 3 (Ruby/Sapphire/FRLG/Emerald) |
SAV Object Structure
type SAV = {
game: [GameVersion, Locale]; // e.g., ['RB', 'en']
name: number[]; // Trainer name (encoded)
tid: number; // Trainer ID
gender: 'male' | 'female'; // Trainer gender
money: number; // Current money
playtime: [hours, minutes, seconds, frames];
pokedex?: { seen: boolean[], owned: boolean[] };
events: Event[]; // Game event flags
bag: { [key: string]: Pouch };// Item storage
party: Party; // Party Pokemon (6 slots)
boxes: Box[]; // PC storage boxes
};Generation-Specific Fields
SAV1 (Gen 1):
rivalName: number[]- Rival's namebadges: boolean[]- 8 Kanto gym badgescoin: number- Game Corner coins
SAV2 (Gen 2):
badges: boolean[]- 16 badges (8 Johto + 8 Kanto)playerColor: number- Player sprite colorbag.items,bag.keyItems,bag.balls,bag.tmhm- Bag pockets
SAV3 (Gen 3):
sid: number- Secret IDpokedex.nationalDex: boolean- National Dex unlockedrivalName?: number[]- Rival name (FRLG only)league?: { eliteFourDefeated, championDefeated, hallOfFame }- League progress
Save File Sizes
| Generation | Size | |------------|------| | Gen 1 | 32,768 bytes | | Gen 2 | 32,816 bytes | | Gen 3 | 131,072 bytes |
License
MIT
