{"id":26052534,"url":"https://github.com/qalle2/nes-util","last_synced_at":"2025-04-10T23:25:22.239Z","repository":{"id":44692014,"uuid":"144644005","full_name":"qalle2/nes-util","owner":"qalle2","description":"Nintendo Entertainment System utilities","archived":false,"fork":false,"pushed_at":"2024-05-09T20:53:40.000Z","size":393,"stargazers_count":11,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-24T20:12:39.281Z","etag":null,"topics":["blaster-master","command-line","game-genie","ines","nes","python3","rom-hacking"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/qalle2.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-08-13T23:27:18.000Z","updated_at":"2024-10-28T07:58:02.000Z","dependencies_parsed_at":"2023-02-18T04:45:52.813Z","dependency_job_id":"faedd4b0-a7c7-453f-8089-22a870a664cd","html_url":"https://github.com/qalle2/nes-util","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qalle2%2Fnes-util","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qalle2%2Fnes-util/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qalle2%2Fnes-util/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qalle2%2Fnes-util/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/qalle2","download_url":"https://codeload.github.com/qalle2/nes-util/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248313679,"owners_count":21082897,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blaster-master","command-line","game-genie","ines","nes","python3","rom-hacking"],"created_at":"2025-03-08T06:40:54.832Z","updated_at":"2025-04-10T23:25:22.218Z","avatar_url":"https://github.com/qalle2.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"# nes-util\nUtilities for\n[Nintendo Entertainment System](https://en.wikipedia.org/wiki/Nintendo_Entertainment_System)\ngame hacking.\n\nWarning: the test scripts under `test/` delete files. They also need input\nfiles listed in `test-in-files.md5`.\n\nTable of contents:\n* [Non-game-specific](#non-game-specific)\n  * [ines_combine.py](#ines_combinepy)\n  * [ines_info.py](#ines_infopy)\n  * [ines_split.py](#ines_splitpy)\n  * [nes_chr_decode.py](#nes_chr_decodepy)\n  * [nes_chr_encode.py](#nes_chr_encodepy)\n  * [nes_color_swap.py](#nes_color_swappy)\n  * [nes_cpuaddr.py](#nes_cpuaddrpy)\n  * [nes_prgbyte.py](#nes_prgbytepy)\n  * [nesgenie_dec.py](#nesgenie_decpy)\n  * [nesgenie_enc.py](#nesgenie_encpy)\n  * [nesgenie_6to8.py](#nesgenie_6to8py)\n  * [nesgenie_prgaddr.py](#nesgenie_prgaddrpy)\n  * [nesgenie_verconv.py](#nesgenie_verconvpy)\n  * [qneslib.py](#qneslibpy)\n* [Game-specific](#game-specific)\n  * [nes_blaster_mapext.py](#nes_blaster_mapextpy)\n  * [nes_irriship_mapext.py](#nes_irriship_mapextpy)\n  * [nes_irriship_tasgen.py](#nes_irriship_tasgenpy)\n  * [nes_smb_mapext.py](#nes_smb_mapextpy)\n\n## Non-game-specific\n\n### ines_combine.py\n```\nusage: ines_combine.py [-h] -p PRG_ROM [-c CHR_ROM] [-m MAPPER] [-n {h,v,f}]\n                       [-x]\n                       outputFile\n\nCreate an iNES ROM file (.nes).\n\npositional arguments:\n  outputFile            iNES ROM file (.nes) to write.\n\noptions:\n  -h, --help            show this help message and exit\n  -p PRG_ROM, --prg-rom PRG_ROM\n                        PRG ROM data file to read. Required. Size: 16-4096 KiB\n                        and a multiple of 16 KiB.\n  -c CHR_ROM, --chr-rom CHR_ROM\n                        CHR ROM data file to read. Size: 0-2040 KiB and a\n                        multiple of 8 KiB.\n  -m MAPPER, --mapper MAPPER\n                        iNES mapper number (0-255). Default=0 (NROM).\n  -n {h,v,f}, --mirroring {h,v,f}\n                        Type of name table mirroring: h=horizontal (default),\n                        v=vertical, f=four-screen.\n  -x, --extra-ram       The game contains extra RAM at $6000-$7fff.\n```\n\n### ines_info.py\nPrint information of an iNES ROM file (.nes).\n\nExample:\n```\ntrainer size: 0\nPRG ROM size: 32768\nCHR ROM size: 8192\niNES mapper number: 0\nname table mirroring: vertical\nhas extra RAM at $6000-$7fff: no\n```\n\n### ines_split.py\n```\nusage: ines_split.py [-h] [-p PRG] [-c CHR] input_file\n\nExtract PRG ROM and/or CHR ROM data from an iNES ROM file (.nes).\n\npositional arguments:\n  input_file         iNES ROM file (.nes) to read.\n\noptions:\n  -h, --help         show this help message and exit\n  -p PRG, --prg PRG  File to write PRG ROM data to.\n  -c CHR, --chr CHR  File to write CHR ROM data to. Not written if there is no\n                     data.\n```\n\n### nes_chr_decode.py\nRequires [Pillow](https://python-pillow.org).\n```\nConvert NES CHR (graphics) data into a PNG file.\nArguments: inputFile outputFile palette\n    inputFile: File to read. An iNES ROM (.nes) or raw CHR data. Size of raw\n        CHR data must be a multiple of 256 bytes.\n    outputFile: PNG file to write. 16 tiles wide.\n    palette: Optional. Output palette or which colors will correspond to CHR\n        colors 0-3. Four hexadecimal RRGGBB codes (000000-ffffff) separated by\n        commas. Default: 000000,555555,aaaaaa,ffffff\n```\n\n### nes_chr_encode.py\nRequires [Pillow](https://python-pillow.org).\n```\nConvert an image file into an NES CHR (graphics) data file.\nArguments: inputFile outputFile palette\n    inputFile: Image file to read (e.g. PNG). Width must be\n        128 pixels (16 tiles). Height must\n        be a multiple of 8 pixels (1 tile). No more than 4 unique\n        colors.\n    outputFile: NES CHR data file to write. The size will be a multiple of\n        256 bytes (16 tiles).\n    palette: Optional. Input palette (which image colors correspond to CHR\n        colors 0-3). Four hexadecimal RRGGBB color codes (000000-ffffff)\n        separated by commas. All colors must be distinct. Palette must include\n        every unique color in input file. Palette may contain colors not\n        present in input file.\n        Default: 000000,555555,aaaaaa,ffffff\n```\n\n### nes_color_swap.py\n```\nusage: nes_color_swap.py [-h] [-c {0,1,2,3} {0,1,2,3} {0,1,2,3} {0,1,2,3}]\n                         [-f FIRST_TILE] [-n TILE_COUNT]\n                         input_file output_file\n\nSwap colors in the graphics data (CHR ROM) of an iNES ROM file (.nes).\n\npositional arguments:\n  input_file            iNES ROM file (.nes) to read.\n  output_file           iNES ROM file (.nes) to write.\n\noptions:\n  -h, --help            show this help message and exit\n  -c {0,1,2,3} {0,1,2,3} {0,1,2,3} {0,1,2,3},\n  --colors {0,1,2,3} {0,1,2,3} {0,1,2,3} {0,1,2,3}\n                        Change original colors 0...3 to these colors. Four\n                        colors (each 0...3) separated by spaces. Default: 0 2\n                        3 1\n  -f FIRST_TILE, --first-tile FIRST_TILE\n                        First tile to change (0 or greater, default=0).\n  -n TILE_COUNT, --tile-count TILE_COUNT\n                        Number of tiles to change. 0 (default) = all starting\n                        from --first-tile.\n```\n\nAn example from *Super Mario Bros.* by Nintendo:\n\n![screenshot](nes_color_swap.png)\n\n### nes_cpuaddr.py\nRequires qneslib.py (see below).\n\nConvert an NES PRG ROM address into possible CPU addresses using the iNES ROM\nfile (.nes). Args: file address_in_hexadecimal\n\n### nes_prgbyte.py\nGet byte value at specified PRG ROM address in an iNES ROM file (.nes).\nArguments: file address-in-hexadecimal\n\n### nesgenie_dec.py\nDecode an NES Game Genie code. Argument: code (6 or 8 letters from\nAEGIKLNOPSTUVXYZ).\n\nExample:\n```\n$ python3 nesgenie_dec.py yeuzugaa\nCPU address = 0xacb3, replace value = 0x07, compare value = 0x00\n```\n\n### nesgenie_enc.py\nEncode an NES Game Genie code. Arguments: AAAA RR or AAAA RR CC (AAAA =\nCPU address, RR = replacement value, CC = compare value; all in hexadecimal).\n\nExample:\n```\n$ python3 nesgenie_enc.py acb3 07 00\nYEUZUGAA\n```\n\n### nesgenie_6to8.py\nRequires qneslib.py (see below).\n\nConvert a 6-letter NES Game Genie code into 8 letters using the iNES ROM file\n(.nes). Can be useful if the 6-letter code has unintended side effects. Args:\nfile code\n\n### nesgenie_prgaddr.py\nRequires qneslib.py (see below).\n\nFind the PRG ROM addresses affected by an NES Game Genie code in an iNES ROM\nfile (.nes). Args: file code\n\n### nesgenie_verconv.py\nRequires qneslib.py (see below).\n```\nusage: nesgenie_verconv.py [-h] [-s SLICE_LENGTH] [-d MAX_DIFFERENT_BYTES]\n                           [-v]\n                           code file1 file2\n\nConvert an NES Game Genie code from one version of a game to another using\nboth iNES ROM files (.nes). Technical explanation: decode the code; find out\nPRG ROM addresses affected in file1; see what's in and around them; look for\nsimilar bytestrings in file2's PRG ROM; convert the addresses back into CPU\naddresses; encode them into codes.\n\npositional arguments:\n  code                  An NES Game Genie code that is known to work with\n                        file1. Six-letter codes are not allowed if file1 uses\n                        PRG ROM bankswitching.\n  file1                 An iNES ROM file (.nes) to read. The game your code is\n                        known to work with.\n  file2                 Another iNES ROM file (.nes) to read. The equivalent\n                        code for this game will be searched for.\n\noptions:\n  -h, --help            show this help message and exit\n  -s SLICE_LENGTH, --slice-length SLICE_LENGTH\n                        How many PRG ROM bytes to compare both before and\n                        after the relevant byte (that is, total number of\n                        bytes compared is twice this value, plus one). Fewer\n                        bytes will be compared if the relevant byte is too\n                        close to start or end of PRG ROM. 1 to 20, default=4.\n                        Decrease to get more results.\n  -d MAX_DIFFERENT_BYTES, --max-different-bytes MAX_DIFFERENT_BYTES\n                        Maximum number of non-matching bytes allowed in each\n                        pair of PRG ROM slices to compare. (The relevant byte\n                        must always match.) Minimum=0, default=1,\n                        maximum=twice --slice-length, minus one. Increase to\n                        get more results.\n  -v, --verbose         Print more information. Note: all printed numbers are\n                        hexadecimal.\n```\n\n### qneslib.py\nDoes not do anything by itself but is needed by some other programs in this\nrepo. Just copy this file to the same directory. Formerly known as neslib.py,\nineslib.py and nesgenielib.py.\n```\nNAME\n    qneslib - qalle's NES library (Nintendo Entertainment System stuff).\n\nFUNCTIONS\n    address_cpu_to_prg(cpuAddr, prgBankSize, prgSize)\n        Convert a CPU ROM address into possible PRG ROM addresses.\n        cpuAddr:     CPU ROM address (0x8000-0xffff)\n        prgBankSize: PRG ROM bank size (8_192/16_384/32_768)\n        prgSize:     PRG ROM size\n        generate:    PRG ROM addresses\n\n    address_prg_to_cpu(prgAddr, prgBankSize)\n        Convert a PRG ROM address into possible CPU ROM addresses.\n        prgAddr:     PRG ROM address\n        prgBankSize: PRG ROM bank size (8_192/16_384/32_768)\n        generate:    CPU ROM addresses (0x8000-0xffff)\n\n    game_genie_decode(code)\n        Decode a Game Genie code.\n        code: 6 or 8 letters from GAME_GENIE_LETTERS\n        return:\n            if invalid code: None\n            otherwise:       (cpu_address, replacement_value, compare_value):\n                cpu_address:       0x8000-0xffff\n                replacement_value: 0x00-0xff\n                compare_value:     None if 6-letter code, 0x00-0xff if 8-letter\n                                   code\n\n    game_genie_encode(addr, repl, comp=None)\n        Encode a Game Genie code.\n        addr: CPU address (0x0000-0xffff; MSB ignored)\n        repl: replacement value (0x00-0xff)\n        comp: compare value (0x00-0xff/None)\n        return:\n            if invalid arguments: None\n            if comp is None     : 6-letter code\n            if comp is not None : 8-letter code\n\n    ines_header_decode(handle)\n        Parse the header of an iNES ROM file.\n        Note: does not support VS System or PlayChoice-10 flags or NES 2.0 header.\n        handle: iNES ROM file\n        return: None on error, otherwise a dict with the following keys:\n            trainerStart: trainer address\n            trainerSize:  trainer size\n            prgStart:     PRG ROM address\n            prgSize:      PRG ROM size\n            chrStart:     CHR ROM address\n            chrSize:      CHR ROM size\n            mapper:       iNES mapper number (0x00-0xff)\n            mirroring:    name table mirroring ('h'=horizontal, 'v'=vertical,\n                          'f'=four-screen)\n            extraRam:     does the game have extra RAM? (bool)\n\n    ines_header_encode(prgSize, chrSize, mapper=0, mirroring='h', extraRam=False)\n        Create an iNES file header.\n        Note: does not support VS System or PlayChoice-10 flags or NES 2.0 header.\n        prgSize:   PRG ROM size\n        chrSize:   CHR ROM size\n        mapper:    iNES mapper number (0x00-0xff)\n        mirroring: name table mirroring ('h'=horizontal, 'v'=vertical,\n                   'f'=four-screen)\n        extraRam:  does the game have extra RAM? (bool)\n        return:    16 bytes or None on error\n\n    is_mapper_known(mapper)\n        Is the mapper known by this program? (If not, mapper functions are more\n        likely to return incorrect info.)\n        mapper: iNES mapper number (0x00-0xff)\n        return: bool\n\n    is_prg_bankswitched(prgSize, mapper)\n        Does the game use PRG ROM bankswitching? (May give false positives,\n        especially if the mapper is unknown. Should not give false negatives.)\n        prgSize: PRG ROM size\n        mapper:  iNES mapper number (0x00-0xff)\n        return:  bool\n\n    mapper_name(mapper)\n        Get the name of the mapper.\n        mapper: iNES mapper number (0x00-0xff)\n        return: string (\"(unknown)\" if unknown mapper)\n\n    min_prg_bank_size(prgSize, mapper)\n        Get the smallest PRG ROM bank size a game may use.\n        prgSize: PRG ROM size\n        mapper:  iNES mapper number (0x00-0xff)\n        return:  8_192/16_384/32_768 (8_192 if unknown mapper)\n\n    min_prg_bank_size_for_mapper(mapper)\n        Get the smallest PRG ROM bank size supported by the mapper.\n        mapper: iNES mapper number (0x00-0xff)\n        return: 8_192/16_384/32_768 (8_192 if unknown mapper)\n\n    tile_slice_decode(loByte, hiByte)\n        Decode 8*1 pixels of one tile of CHR data.\n        loByte: low bitplane (0x00-0xff)\n        hiByte: high bitplane (0x00-0xff)\n        return: eight 2-bit ints\n\n    tile_slice_encode(pixels)\n        Encode 8*1 pixels of one tile of CHR data.\n        pixels: eight 2-bit ints\n        return: (low_bitplane, high_bitplane); both 0x00-0xff\n\nDATA\n    GAME_GENIE_LETTERS = 'APZLGITYEOXUKSVN'\n    PALETTE = {0: (116, 116, 116), 1: (36, 24, 140), 2: (0, 0, 168), 3: (6...\n```\n\nNES Game Genie code format:\n\n![NES Game Genie code format](nesgenieformat.png)\n\n## Game-specific\n\n### nes_blaster_mapext.py\nRequires [Pillow](https://python-pillow.org).\n```\nusage: nes_blaster_mapext.py [-h] [-j] [-n MAP_NUMBER] [-u USB_IMAGE]\n                             [-s SB_IMAGE] [-b BLOCK_IMAGE] [-m MAP_IMAGE]\n                             [-v]\n                             input_file\n\nExtract world maps from NES Blaster Master to PNG files.\n\npositional arguments:\n  input_file            Blaster Master ROM file in iNES format (.nes, US/US\n                        prototype/EUR/JP; see also --japan).\n\noptions:\n  -h, --help            show this help message and exit\n  -j, --japan           Input file is Japanese version (Chou-Wakusei Senki -\n                        MetaFight).\n  -n MAP_NUMBER, --map-number MAP_NUMBER\n                        Map to extract: 0-7 = side view of area 1-8, 8-15 =\n                        overhead view of area 1-8. Default=0.\n  -u USB_IMAGE, --usb-image USB_IMAGE\n                        Save ultra-subblocks (16*16 px each) as PNG file (up\n                        to 256*256 px).\n  -s SB_IMAGE, --sb-image SB_IMAGE\n                        Save subblocks (32*32 px each) as PNG file (up to\n                        512*512 px).\n  -b BLOCK_IMAGE, --block-image BLOCK_IMAGE\n                        Save blocks (64*64 px each) as PNG file (up to\n                        1024*1024 px).\n  -m MAP_IMAGE, --map-image MAP_IMAGE\n                        Save map as PNG file (up to 32*32 blocks or 2048*2048\n                        px).\n  -v, --verbose         Print more information.\n```\n\n### nes_irriship_mapext.py\nRequires [Pillow](https://python-pillow.org).\n\nExtract map data from NES Irritating Ship. Arguments: inputFile outputFile\n(inputFile = iNES ROM, outputFile = PNG (will be overwritten)).\n\n### nes_irriship_tasgen.py\nGenerate an FCEUX movie that plays Irritating Ship. Under construction.\n\n### nes_smb_mapext.py\n**Note:** This program is at an early stage.\n[VGMaps](https://vgmaps.com/Atlas/NES/index.htm#SuperMarioBros) has much better\nmaps of *Super Mario Bros.*\n\nRequires [Pillow](https://python-pillow.org).\n\n```\nExtract map data (excluding enemies) from NES Super Mario Bros. by Nintendo.\nArgument syntax:\n    Short summary of all areas:\n        INPUTFILE\n    All data and image of one area:\n        INPUTFILE OUTPUTFILE AREATYPE AREA\nArguments:\n    INPUTFILE: iNES format, US version.\n    OUTPUTFILE: PNG, will be overwritten!\n    AREATYPE: 0=water, 1=ground, 2=underground, 3=castle.\n    AREA: 0 or greater; max. value depends on AREATYPE.\nE.g. AREATYPE 1, AREA 5 = above-ground part of level 1-1.\nNote: looping castle areas look totally wrong; all other areas look more or\nless wrong too.\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqalle2%2Fnes-util","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fqalle2%2Fnes-util","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqalle2%2Fnes-util/lists"}