Utilities for Nintendo Entertainment System game hacking.
Warning: the test scripts under test/
delete files. They also need input
files listed in test-in-files.md5
.
Table of contents:
usage: ines_combine.py [-h] -p PRG_ROM [-c CHR_ROM] [-m MAPPER] [-n {h,v,f}]
[-x]
outputFile
Create an iNES ROM file (.nes).
positional arguments:
outputFile iNES ROM file (.nes) to write.
options:
-h, --help show this help message and exit
-p PRG_ROM, --prg-rom PRG_ROM
PRG ROM data file to read. Required. Size: 16-4096 KiB
and a multiple of 16 KiB.
-c CHR_ROM, --chr-rom CHR_ROM
CHR ROM data file to read. Size: 0-2040 KiB and a
multiple of 8 KiB.
-m MAPPER, --mapper MAPPER
iNES mapper number (0-255). Default=0 (NROM).
-n {h,v,f}, --mirroring {h,v,f}
Type of name table mirroring: h=horizontal (default),
v=vertical, f=four-screen.
-x, --extra-ram The game contains extra RAM at $6000-$7fff.
Print information of an iNES ROM file (.nes).
Example:
trainer size: 0
PRG ROM size: 32768
CHR ROM size: 8192
iNES mapper number: 0
name table mirroring: vertical
has extra RAM at $6000-$7fff: no
usage: ines_split.py [-h] [-p PRG] [-c CHR] input_file
Extract PRG ROM and/or CHR ROM data from an iNES ROM file (.nes).
positional arguments:
input_file iNES ROM file (.nes) to read.
options:
-h, --help show this help message and exit
-p PRG, --prg PRG File to write PRG ROM data to.
-c CHR, --chr CHR File to write CHR ROM data to. Not written if there is no
data.
Requires Pillow.
Convert NES CHR (graphics) data into a PNG file.
Arguments: inputFile outputFile palette
inputFile: File to read. An iNES ROM (.nes) or raw CHR data. Size of raw
CHR data must be a multiple of 256 bytes.
outputFile: PNG file to write. 16 tiles wide.
palette: Optional. Output palette or which colors will correspond to CHR
colors 0-3. Four hexadecimal RRGGBB codes (000000-ffffff) separated by
commas. Default: 000000,555555,aaaaaa,ffffff
Requires Pillow.
Convert an image file into an NES CHR (graphics) data file.
Arguments: inputFile outputFile palette
inputFile: Image file to read (e.g. PNG). Width must be
128 pixels (16 tiles). Height must
be a multiple of 8 pixels (1 tile). No more than 4 unique
colors.
outputFile: NES CHR data file to write. The size will be a multiple of
256 bytes (16 tiles).
palette: Optional. Input palette (which image colors correspond to CHR
colors 0-3). Four hexadecimal RRGGBB color codes (000000-ffffff)
separated by commas. All colors must be distinct. Palette must include
every unique color in input file. Palette may contain colors not
present in input file.
Default: 000000,555555,aaaaaa,ffffff
usage: nes_color_swap.py [-h] [-c {0,1,2,3} {0,1,2,3} {0,1,2,3} {0,1,2,3}]
[-f FIRST_TILE] [-n TILE_COUNT]
input_file output_file
Swap colors in the graphics data (CHR ROM) of an iNES ROM file (.nes).
positional arguments:
input_file iNES ROM file (.nes) to read.
output_file iNES ROM file (.nes) to write.
options:
-h, --help show this help message and exit
-c {0,1,2,3} {0,1,2,3} {0,1,2,3} {0,1,2,3},
--colors {0,1,2,3} {0,1,2,3} {0,1,2,3} {0,1,2,3}
Change original colors 0...3 to these colors. Four
colors (each 0...3) separated by spaces. Default: 0 2
3 1
-f FIRST_TILE, --first-tile FIRST_TILE
First tile to change (0 or greater, default=0).
-n TILE_COUNT, --tile-count TILE_COUNT
Number of tiles to change. 0 (default) = all starting
from --first-tile.
An example from Super Mario Bros. by Nintendo:
Requires qneslib.py (see below).
Convert an NES PRG ROM address into possible CPU addresses using the iNES ROM file (.nes). Args: file address_in_hexadecimal
Get byte value at specified PRG ROM address in an iNES ROM file (.nes). Arguments: file address-in-hexadecimal
Decode an NES Game Genie code. Argument: code (6 or 8 letters from AEGIKLNOPSTUVXYZ).
Example:
$ python3 nesgenie_dec.py yeuzugaa
CPU address = 0xacb3, replace value = 0x07, compare value = 0x00
Encode an NES Game Genie code. Arguments: AAAA RR or AAAA RR CC (AAAA = CPU address, RR = replacement value, CC = compare value; all in hexadecimal).
Example:
$ python3 nesgenie_enc.py acb3 07 00
YEUZUGAA
Requires qneslib.py (see below).
Convert a 6-letter NES Game Genie code into 8 letters using the iNES ROM file (.nes). Can be useful if the 6-letter code has unintended side effects. Args: file code
Requires qneslib.py (see below).
Find the PRG ROM addresses affected by an NES Game Genie code in an iNES ROM file (.nes). Args: file code
Requires qneslib.py (see below).
usage: nesgenie_verconv.py [-h] [-s SLICE_LENGTH] [-d MAX_DIFFERENT_BYTES]
[-v]
code file1 file2
Convert an NES Game Genie code from one version of a game to another using
both iNES ROM files (.nes). Technical explanation: decode the code; find out
PRG ROM addresses affected in file1; see what's in and around them; look for
similar bytestrings in file2's PRG ROM; convert the addresses back into CPU
addresses; encode them into codes.
positional arguments:
code An NES Game Genie code that is known to work with
file1. Six-letter codes are not allowed if file1 uses
PRG ROM bankswitching.
file1 An iNES ROM file (.nes) to read. The game your code is
known to work with.
file2 Another iNES ROM file (.nes) to read. The equivalent
code for this game will be searched for.
options:
-h, --help show this help message and exit
-s SLICE_LENGTH, --slice-length SLICE_LENGTH
How many PRG ROM bytes to compare both before and
after the relevant byte (that is, total number of
bytes compared is twice this value, plus one). Fewer
bytes will be compared if the relevant byte is too
close to start or end of PRG ROM. 1 to 20, default=4.
Decrease to get more results.
-d MAX_DIFFERENT_BYTES, --max-different-bytes MAX_DIFFERENT_BYTES
Maximum number of non-matching bytes allowed in each
pair of PRG ROM slices to compare. (The relevant byte
must always match.) Minimum=0, default=1,
maximum=twice --slice-length, minus one. Increase to
get more results.
-v, --verbose Print more information. Note: all printed numbers are
hexadecimal.
Does not do anything by itself but is needed by some other programs in this repo. Just copy this file to the same directory. Formerly known as neslib.py, ineslib.py and nesgenielib.py.
NAME
qneslib - qalle's NES library (Nintendo Entertainment System stuff).
FUNCTIONS
address_cpu_to_prg(cpuAddr, prgBankSize, prgSize)
Convert a CPU ROM address into possible PRG ROM addresses.
cpuAddr: CPU ROM address (0x8000-0xffff)
prgBankSize: PRG ROM bank size (8_192/16_384/32_768)
prgSize: PRG ROM size
generate: PRG ROM addresses
address_prg_to_cpu(prgAddr, prgBankSize)
Convert a PRG ROM address into possible CPU ROM addresses.
prgAddr: PRG ROM address
prgBankSize: PRG ROM bank size (8_192/16_384/32_768)
generate: CPU ROM addresses (0x8000-0xffff)
game_genie_decode(code)
Decode a Game Genie code.
code: 6 or 8 letters from GAME_GENIE_LETTERS
return:
if invalid code: None
otherwise: (cpu_address, replacement_value, compare_value):
cpu_address: 0x8000-0xffff
replacement_value: 0x00-0xff
compare_value: None if 6-letter code, 0x00-0xff if 8-letter
code
game_genie_encode(addr, repl, comp=None)
Encode a Game Genie code.
addr: CPU address (0x0000-0xffff; MSB ignored)
repl: replacement value (0x00-0xff)
comp: compare value (0x00-0xff/None)
return:
if invalid arguments: None
if comp is None : 6-letter code
if comp is not None : 8-letter code
ines_header_decode(handle)
Parse the header of an iNES ROM file.
Note: does not support VS System or PlayChoice-10 flags or NES 2.0 header.
handle: iNES ROM file
return: None on error, otherwise a dict with the following keys:
trainerStart: trainer address
trainerSize: trainer size
prgStart: PRG ROM address
prgSize: PRG ROM size
chrStart: CHR ROM address
chrSize: CHR ROM size
mapper: iNES mapper number (0x00-0xff)
mirroring: name table mirroring ('h'=horizontal, 'v'=vertical,
'f'=four-screen)
extraRam: does the game have extra RAM? (bool)
ines_header_encode(prgSize, chrSize, mapper=0, mirroring='h', extraRam=False)
Create an iNES file header.
Note: does not support VS System or PlayChoice-10 flags or NES 2.0 header.
prgSize: PRG ROM size
chrSize: CHR ROM size
mapper: iNES mapper number (0x00-0xff)
mirroring: name table mirroring ('h'=horizontal, 'v'=vertical,
'f'=four-screen)
extraRam: does the game have extra RAM? (bool)
return: 16 bytes or None on error
is_mapper_known(mapper)
Is the mapper known by this program? (If not, mapper functions are more
likely to return incorrect info.)
mapper: iNES mapper number (0x00-0xff)
return: bool
is_prg_bankswitched(prgSize, mapper)
Does the game use PRG ROM bankswitching? (May give false positives,
especially if the mapper is unknown. Should not give false negatives.)
prgSize: PRG ROM size
mapper: iNES mapper number (0x00-0xff)
return: bool
mapper_name(mapper)
Get the name of the mapper.
mapper: iNES mapper number (0x00-0xff)
return: string ("(unknown)" if unknown mapper)
min_prg_bank_size(prgSize, mapper)
Get the smallest PRG ROM bank size a game may use.
prgSize: PRG ROM size
mapper: iNES mapper number (0x00-0xff)
return: 8_192/16_384/32_768 (8_192 if unknown mapper)
min_prg_bank_size_for_mapper(mapper)
Get the smallest PRG ROM bank size supported by the mapper.
mapper: iNES mapper number (0x00-0xff)
return: 8_192/16_384/32_768 (8_192 if unknown mapper)
tile_slice_decode(loByte, hiByte)
Decode 8*1 pixels of one tile of CHR data.
loByte: low bitplane (0x00-0xff)
hiByte: high bitplane (0x00-0xff)
return: eight 2-bit ints
tile_slice_encode(pixels)
Encode 8*1 pixels of one tile of CHR data.
pixels: eight 2-bit ints
return: (low_bitplane, high_bitplane); both 0x00-0xff
DATA
GAME_GENIE_LETTERS = 'APZLGITYEOXUKSVN'
PALETTE = {0: (116, 116, 116), 1: (36, 24, 140), 2: (0, 0, 168), 3: (6...
NES Game Genie code format:
Requires Pillow.
usage: nes_blaster_mapext.py [-h] [-j] [-n MAP_NUMBER] [-u USB_IMAGE]
[-s SB_IMAGE] [-b BLOCK_IMAGE] [-m MAP_IMAGE]
[-v]
input_file
Extract world maps from NES Blaster Master to PNG files.
positional arguments:
input_file Blaster Master ROM file in iNES format (.nes, US/US
prototype/EUR/JP; see also --japan).
options:
-h, --help show this help message and exit
-j, --japan Input file is Japanese version (Chou-Wakusei Senki -
MetaFight).
-n MAP_NUMBER, --map-number MAP_NUMBER
Map to extract: 0-7 = side view of area 1-8, 8-15 =
overhead view of area 1-8. Default=0.
-u USB_IMAGE, --usb-image USB_IMAGE
Save ultra-subblocks (16*16 px each) as PNG file (up
to 256*256 px).
-s SB_IMAGE, --sb-image SB_IMAGE
Save subblocks (32*32 px each) as PNG file (up to
512*512 px).
-b BLOCK_IMAGE, --block-image BLOCK_IMAGE
Save blocks (64*64 px each) as PNG file (up to
1024*1024 px).
-m MAP_IMAGE, --map-image MAP_IMAGE
Save map as PNG file (up to 32*32 blocks or 2048*2048
px).
-v, --verbose Print more information.
Requires Pillow.
Extract map data from NES Irritating Ship. Arguments: inputFile outputFile (inputFile = iNES ROM, outputFile = PNG (will be overwritten)).
Generate an FCEUX movie that plays Irritating Ship. Under construction.
Note: This program is at an early stage. VGMaps has much better maps of Super Mario Bros.
Requires Pillow.
Extract map data (excluding enemies) from NES Super Mario Bros. by Nintendo.
Argument syntax:
Short summary of all areas:
INPUTFILE
All data and image of one area:
INPUTFILE OUTPUTFILE AREATYPE AREA
Arguments:
INPUTFILE: iNES format, US version.
OUTPUTFILE: PNG, will be overwritten!
AREATYPE: 0=water, 1=ground, 2=underground, 3=castle.
AREA: 0 or greater; max. value depends on AREATYPE.
E.g. AREATYPE 1, AREA 5 = above-ground part of level 1-1.
Note: looping castle areas look totally wrong; all other areas look more or
less wrong too.