diff --git a/.vscode/launch.json b/.vscode/launch.json index f20eee6..b92e88b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -72,6 +72,25 @@ "\"${workspaceFolder}\\out\\sf30ac\"" ] }, + { + "name": "Python: Toolbox - Testing SF30AC (Verbose)", + "type": "python", + "request": "launch", + "program": "toolbox.py", + "console": "integratedTerminal", + "cwd": "${workspaceFolder}/src/gex", + "justMyCode": true, + "args": [ + "tasks", + "extract", + "--task", + "sf30ac", + "--destdir", + "\"${workspaceFolder}\\out\\sf30ac\"", + "-v", + "DEBUG" + ] + }, { "name": "Python: Toolbox - Profile SF30AC", "type": "python", @@ -127,9 +146,7 @@ "--destdir", "\"${workspaceFolder}\\out\\snk40\"", "--srcdir", - "\"C:\\Program Files (x86)\\Amazon Games\\Library\\SNK 40th Anniversary Collection\"", - "--prop", - "include-partials=True" + "\"C:\\Program Files (x86)\\Amazon Games\\Library\\SNK 40th Anniversary Collection\"" ] }, { @@ -308,7 +325,7 @@ ] }, { - "name": "Python: Toolbox - Testing Disney Classics Aladding and Lion King w/ DLC", + "name": "Python: Toolbox - Testing Disney Classics Aladdin and Lion King w/ DLC", "type": "python", "request": "launch", "program": "toolbox.py", @@ -377,6 +394,74 @@ "include-arcade-partials=True" ] }, + { + "name": "Python: Toolbox - Testing AGS Galaga", + "type": "python", + "request": "launch", + "program": "toolbox.py", + "console": "integratedTerminal", + "cwd": "${workspaceFolder}/src/gex", + "justMyCode": true, + "args": [ + "tasks", + "extract", + "--task", + "ags_galaga", + "--destdir", + "\"${workspaceFolder}\\out\\ags_galaga\"" + ] + }, + { + "name": "Python: Toolbox - Testing AGS Dig Dug", + "type": "python", + "request": "launch", + "program": "toolbox.py", + "console": "integratedTerminal", + "cwd": "${workspaceFolder}/src/gex", + "justMyCode": true, + "args": [ + "tasks", + "extract", + "--task", + "ags_digdug", + "--destdir", + "\"${workspaceFolder}\\out\\ags_digdug\"" + ] + }, + { + "name": "Python: Toolbox - Testing AGS Pac-Man", + "type": "python", + "request": "launch", + "program": "toolbox.py", + "console": "integratedTerminal", + "cwd": "${workspaceFolder}/src/gex", + "justMyCode": true, + "args": [ + "tasks", + "extract", + "--task", + "ags_pacman", + "--destdir", + "\"${workspaceFolder}\\out\\ags_pacman\"" + ] + }, + { + "name": "Python: Toolbox - Testing AGS Ms. Pac-Man", + "type": "python", + "request": "launch", + "program": "toolbox.py", + "console": "integratedTerminal", + "cwd": "${workspaceFolder}/src/gex", + "justMyCode": true, + "args": [ + "tasks", + "extract", + "--task", + "ags_mspacman", + "--destdir", + "\"${workspaceFolder}\\out\\ags_mspacman\"" + ] + }, { "name": "Python: Toolbox - Testing AGS", "type": "python", @@ -484,9 +569,7 @@ "--destdir", "\"${workspaceFolder}\\out\\cas1\"", "--prop", - "include-partials=True", - "--verbosity", - "DEBUG" + "include-partials=True" ] }, { @@ -526,6 +609,19 @@ "--prop", "include-partials=True" ] + }, + { + "name": "Python: Toolbox - List Tasks", + "type": "python", + "request": "launch", + "program": "toolbox.py", + "console": "integratedTerminal", + "cwd": "${workspaceFolder}/src/gex", + "justMyCode": true, + "args": [ + "tasks", + "list" + ] } ] } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 7478123..2430aaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +# 0.1.4 +- Updated Collections: + - Genesis and Mega Drive Collection + - Fixed mislabeled Super Thunder Blade ROM + - IREM Arcade Classics + - Fix bug preventing details output + - SNK 40th Anniversary Edition + - Bermuda Triangle: Completed extraction on actual Bermuda Triangle (#37) +- Improvements: + - Added input/output file verification to tasks (#36) +- Internal: + - Made a few reusable tasks - 'CopyTask', 'ZipSpliceTask', 'SpliceTask' + # 0.1.3 - Improvements: - Fixed forgotten version number roll diff --git a/README.md b/README.md index 1eb9311..8228e66 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,10 @@ I prefer not to be artificially locked to specific platforms - why play a 25 yea ### Why not just download the ROMs? It is illegal. One can discuss economic moral implications all day, but at the end of the day, it's theft. As a software developer myself, I don't want my code stolen - so I can't claim a moral high ground there. Equally importantly, showing classic game owners that the market will support rereleases increases the liklihood of rereleases, and I want people who can't/won't download ROMs to enjoy these titles as well. +### What artificial limitations does this tool have to prevent copyright claims? +* This tool will not hold decryption keys. +* This tool will not hold any 'whole' files, nor substantial parts of files. A limited 'patch' capability is allowed for less than 1% of a file, but this should be very limited. + ### This MAME ROM is actually XXXXYY, not XXXXZZ - why do you have it that way? The goal of this tool is not to create a perfect ROM set for the latest MAME, because it can't. A few factors go into what version of MAME we target: @@ -108,30 +112,33 @@ These are noted in the documentation for each script. If you think a ROM is misi ### Playable -**Collection** | **Status** | **Notes** +**Collection** | **Status** | **Verification** | **Notes** --------------------------------------------|-------------|--------------------------------------------------------------------- - **Arcade Collection Anniversary Classics** | 75% | A couple games are good extractions so far... - **Atari Vault** | 90% | Some arcade ROMs from this collection are incomplete. - **Blizzard Arcade Collection** | 100% | - **Bubsy Two-Fur** | 100% | - **Capcom Arcade Stadium 1 (via Depot)** | 95% | Requires Steam depot downloading, a couple shaky ROMs... - **Capcom Beat 'Em Up Bundle** | 95% | 6/7 playable on some version of MAME, but wof/wofj missing audiocpu data - **Capcom Fighting Collection** | 90% | CPS2 is semi-standard. No Enc keys present. CP3 game is a curveball! - **Collection of SaGa/Final Fantasy Legend** | 100% | - **Disney Afternoon Collection** | 100% | - **Disney Classics Aladdin & Lion King w/DLC** | 100% | Includes Jungle Book DLC - **Double Dragon Trilogy** | 100% | - **IREM Arcade Classics** | 100% | - **Mega Man Legacy Collection 1** | 100% | - **Mega Man X Legacy Collection 1** | 75% | X4 doesn't appear to be ROM based - **Namco Arcade Game Series** | 75% | Ms. Pac-Man cannot be cleanly extracted - **Pac Man Museum Plus** | 40% | Some progress, but there are a lot of non-extractable titles. - **Sega Genesis and Mega Drive Collection** | 90% | Some compressed variants not yet extracted - **Sonic Adventure DX (Hidden Game Gear games)**| 100% | This is only the Game Gear games - SADX itself can not be made into a ROM/ISO! - **SNK 40th Anniversary Collection** | 100% | All games supported by an emulator are extracted! - **Street Fighter 30th Anniversary Collection** | 90% | Now includes all playable international versions. - **Wonder Boy: The Dragon's Trap** | 100% | - **Zombies Ate My Neighbors and Ghoul Patrol** | 100% | + **Arcade Collection Anniversary Classics** | 75% | Y | A couple games are good extractions so far... + **Atari Vault** | 90% | Y | Some arcade ROMs from this collection are incomplete. + **Blizzard Arcade Collection** | 100% | Y | + **Bubsy Two-Fur** | 100% | Y | + **Capcom Arcade Stadium 1 (via Depot)** | 95% | N | Requires Steam depot downloading, a couple shaky ROMs... + **Capcom Beat 'Em Up Bundle** | 95% | Y | 6/7 playable on some version of MAME, but wof/wofj missing audiocpu data + **Capcom Fighting Collection** | 90% | Y | CPS2 is semi-standard. No Enc keys present. CP3 game is a curveball! + **Collection of SaGa/Final Fantasy Legend** | 100% | Y | + **Disney Afternoon Collection** | 100% | Y | + **Disney Classics Aladdin & Lion King w/DLC** | 100% | Y | Includes Jungle Book DLC + **Double Dragon Trilogy** | 100% | Y | + **IREM Arcade Classics** | 100% | Y | + **Mega Man Legacy Collection 1** | 100% | Y | + **Mega Man X Legacy Collection 1** | 75% | Y | X4 doesn't appear to be ROM based + **Namco Arcade Game Series: Dig Dug** | 100% | Y | + **Namco Arcade Game Series: Galaga** | 100% | Y | + **Namco Arcade Game Series: Ms. Pac-Man** | 100% | Y | + **Namco Arcade Game Series: Pacman** | 100% | Y | + **Pac Man Museum Plus** | 40% | Y | Some progress, but there are a lot of non-extractable titles. + **Sega Genesis and Mega Drive Collection** | 90% | Y | Some compressed variants not yet extracted + **Sonic Adventure DX (Hidden Game Gear games)**| 100% | Y | This is only the Game Gear games - SADX itself can not be made into a ROM/ISO! + **SNK 40th Anniversary Collection** | 100% | Y | All games supported by an emulator are extracted! + **Street Fighter 30th Anniversary Collection** | 90% | Y | Now includes all playable international versions. + **Wonder Boy: The Dragon's Trap** | 100% | Y | + **Zombies Ate My Neighbors and Ghoul Patrol** | 100% | Y | ### Completely Unplayable @@ -155,4 +162,4 @@ These are noted in the documentation for each script. If you think a ROM is misi * The ROM has missing files that can be filled with placeholders or left out. * Files are present that work as normal, but have bad CRCs. This may be due to copyright changes, etc., but ultimately does not match a known good source. * Publishers may offer modified ROMs - such as increased difficulty, theming, or new game modes - which are often not publicly tracked. - * It may only work in older versions of emulators due to odd dumps, missing files, etc. \ No newline at end of file + * It may only work in older versions of emulators due to odd dumps, missing files, etc. diff --git a/ROADMAP.md b/ROADMAP.md index bc26d92..e3319e5 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -4,6 +4,10 @@ - Retro Classix by Data East In title\title_Data\StreamingAssets folder - Brave Battle Saga - The Legend of The Magic Warrior +- Activision Anthology Remix PC + https://forums.atariage.com/topic/336118-how-to-extract-roms-from-the-activision-anthology-for-pc-and-a-request-for-info-on-the-included-roms/ +- Sega Mega Drive & Genesis Classics + Compressed ROMS: https://github.com/farmerbb/RED-Project/wiki/Sega-Mega-Drive-&-Genesis-Classics ### Uses BPList/Mbundle - Samuari Shodown Collection @@ -30,6 +34,7 @@ ## Owned / Under Investigation - Teenage Mutant Ninja Turtles: The Cowabunga Collection (August 30th, 2022) Assets are jammed into one file, but that file appears to be encrypted or compressed. Notes in #17. + https://github.com/Masquerade64/Cowabunga - Capcom Arcade Stadium 1 Current versions have an odd archive format (unlike the CAS1_Old ZIP version). PLACEHOLDER ADDED. See #18. @@ -42,6 +47,11 @@ - Arcade Collection Anniversary Classics Mostly working, but 2 titles remain... - Psiyko Shooter Collector's Bundle https://store.steampowered.com/bundle/18805/PSIKYO_SHOOTER_Collectors_Bundle/ +- PSP: EA Replay + \PSP_GAME\USRDIR\data\roms.viv is an EA BIG4 archive that can be extracted via QuickBMS + It has sensible ROM filenames, but the files are too small and not in an expected format. + They don't appear to have REFPACK, zlib or gzip headers, nor use RAW DEFLATE. + ## Not Yet Owned / Future Investigation @@ -60,35 +70,29 @@ - CAVE: Deathsmiles I + II Recommended in #15. - Darius Cozmic Collection Arcade +- Taito Legends 1 and 2 +- Saturn Cotton Collection + https://gbatemp.net/threads/saturn-emulation-using-cotton-guardian-force-testing-and-debug.600756/ ## Upcoming Releases - Atari 50th: Anniversary Collection (Winter 2022) +## Unlikely +- Williams Arcade Classics (PC CD-ROM, 1995) + Initial research shows that this is likely not ROM based. + ## Not Complete ROMs (may add partial extraction later) - Mortal Kombat Kollection Audio ROMs were replaced with a different audio solution. - Dungeons & Dragons: Chronicles of Mystara Maincpu and Gfx ROMs are there, but audio is completely reworked. -- Midway Arcade Treasures Vol. 1 (PS2) - Audio ROMs replaced. For example, Smash TV has all the game ROMs, but none of the sound ROMs. - Klax - - Missing OKI sound roms - - Missing Pals - - pfrom.klx - split - 0x00000 0x1000 136075-2010.17x - 0x10000 0x1000 136075-2012.12x - 0x20000 0x1000 136075-2014.17y - 0x30000 0x1000 136075-2009.17u - 0x40000 0x1000 136075-2011.12u - 0x50000 0x1000 136075-2013.17w - - fixedcpu.klx - cut in half - deinterleave each, 1 byte - 136075-6006.3k - 136075-6005.1k - 136075-6008.3k - 136075-6007.1k + +### .SR Releases +The SR archives can be extracted via QuickBMS script: https://forum.xentax.com/viewtopic.php?t=13718 +However, these seem to always use rebuilt audio, and some of the games have been rebuilt as native ELF executables. +- PSP: Capcom Classics Collection: Remixed +- PS2: Midway Arcade Treasures Vol. 1 +- PS2: Midway Arcade Treasures Vol. 2 ## Not ROMs - Phoenix Wright Ace Attorney Trilogy @@ -99,4 +103,7 @@ Windows Version - Earthworm Jim 1 and 2 (Steam, GOG) DOS Version +- Disney's Hercules + https://www.gog.com/en/game/disneys_hercules + Native PC Game diff --git a/pyproject.toml b/pyproject.toml index dd8000d..720b661 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "game-extraction-toolbox" -version = "0.1.3" +version = "0.1.4" authors = [ { name="Shawn McNaughton", email="shawngmc@gmail.com" }, ] diff --git a/setup.cfg b/setup.cfg index 649d37b..7385a61 100644 --- a/setup.cfg +++ b/setup.cfg @@ -8,4 +8,8 @@ package_dir = packages = find_namespace: [options.packages.find] -where = src \ No newline at end of file +where = src + +[options.package_data] +* = + *.json \ No newline at end of file diff --git a/src/gex/commands/archive/archive.py b/src/gex/commands/archive/archive.py index 46a7c76..21c5121 100644 --- a/src/gex/commands/archive/archive.py +++ b/src/gex/commands/archive/archive.py @@ -2,6 +2,7 @@ from .arc.arc import arc from .kpka.kpka import kpka +from .zip.zip import zip_cli @click.group() def archive(): @@ -9,3 +10,4 @@ def archive(): archive.add_command(arc) archive.add_command(kpka) +archive.add_command(zip_cli) diff --git a/src/gex/commands/archive/zip/__init__.py b/src/gex/commands/archive/zip/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/gex/commands/archive/zip/list.py b/src/gex/commands/archive/zip/list.py new file mode 100644 index 0000000..8a84687 --- /dev/null +++ b/src/gex/commands/archive/zip/list.py @@ -0,0 +1,50 @@ +import os +import logging +import click +import click_log +from texttable import Texttable +from gex.lib.archive import zip as zip_lib + +logger = logging.getLogger('gextoolbox') + +@click.command(name='list') +@click.option('--in', 'in_file', help = 'path to input ZIP archive', required=True) +@click.option('--format', type=click.Choice(['table', 'verify-json'], case_sensitive=False), default="table") +@click_log.simple_verbosity_option(logger) +def list_files(in_file, format): + """List the contents of a ZIP archive""" + try: + with open(in_file, "rb") as curr_file: + file_content = bytearray(curr_file.read()) + zip_metas = zip_lib.get_metadata(file_content) + + format = format.lower() + if format == "table": + table = Texttable() + table.add_row(["Filename", "Size", "CRC"]) + table.set_cols_dtype(["t", "t", "t"]) + for zip_meta in zip_metas.values(): + table.add_row([zip_meta['filename'], zip_meta['size'], zip_meta['crc']]) + print(table.draw()) + elif format == "verify-json": + print('"verify": {') + print(' "type": "zip",') + print(' "entries": {') + values = list(zip_metas.values()) + for zip_meta in values: + line = ' "' + line += zip_meta.get("filename") + line += '": {"size": ' + line += str(zip_meta.get("size")) + line += ', "crc": "' + line += zip_meta.get("crc") + line += '"}' + if zip_meta != values[-1]: + line += ',' + print(line) + print(' }') + print('}') + + except Exception as error: + logger.error(error) + logger.error('Error While Opening the file!') diff --git a/src/gex/commands/archive/zip/zip.py b/src/gex/commands/archive/zip/zip.py new file mode 100644 index 0000000..79bb828 --- /dev/null +++ b/src/gex/commands/archive/zip/zip.py @@ -0,0 +1,9 @@ +import click + +from .list import list_files + +@click.group(name='zip') +def zip_cli(): + """Operations for ZIP Archives""" + +zip_cli.add_command(list_files) diff --git a/src/gex/commands/file/diff.py b/src/gex/commands/file/diff.py new file mode 100644 index 0000000..6812f85 --- /dev/null +++ b/src/gex/commands/file/diff.py @@ -0,0 +1,80 @@ +import json +import logging +import os +import click +import click_log +from texttable import Texttable +from gex.lib.utils.blob import hash as hash_helper + +logger = logging.getLogger('gextoolbox') + +@click.command() +@click.option('--1', 'file_1', help = 'path to input file 1', required=True) +@click.option('--2', 'file_2', help = 'path to input file 2', required=True) +@click_log.simple_verbosity_option(logger) +def diff(file_1, file_2): + '''Smarter non-interactive diff tool''' + try: + with open(file_1, "rb") as file: + contents_1 = file.read() + except IOError: + logger.error(f"Error reading {file_1}!") + exit() + try: + with open(file_2, "rb") as file: + contents_2 = file.read() + except IOError: + logger.error(f"Error reading {file_2}!") + exit() + + + table = Texttable() + table.add_row(["", "File 1", "File 2", ""]) + table.set_cols_dtype(["t", "t", "t", "t"]) + filename_1 = os.path.basename(file_1) + filename_2 = os.path.basename(file_2) + table.add_row(['filename', filename_1, filename_2, filename_1 == filename_2]) + dir_1 = os.path.abspath(os.path.dirname(file_1)) + dir_2 = os.path.abspath(os.path.dirname(file_2)) + table.add_row(['path', dir_1, dir_2, dir_1 == dir_2]) + + # Diff size + size_1 = len(contents_1) + size_2 = len(contents_2) + if size_1 == size_2: + logger.info(f"File sizes are identical at {size_1} bytes...") + else: + logger.info(f"File sizes are different, {size_1} vs {size_2} bytes...") + table.add_row(['size', size_1, size_2, size_1 == size_2]) + + # Diff CRC + crc_1 = hash_helper.get_crc(contents_1) + crc_2 = hash_helper.get_crc(contents_2) + if crc_1 == crc_2: + logger.info(f"File hashes are identical, {crc_1}...") + else: + logger.info(f"File hashes are different, {crc_1} vs {crc_2}...") + table.add_row(['crc', crc_1, crc_2, crc_1 == crc_2]) + + # TODO: Find sliding match if diff size + + # Simple percent comparison + if size_1 == size_2: + diff_bytes = {} + for x in range(0, size_1): + if contents_1[x] != contents_2[x]: + diff_bytes[x] = {"1": contents_1[x], "2": contents_2[x]} + + identical_percent = (100 - (len(diff_bytes.keys()) / size_1)) / 100 + + logger.info(f"Percent similar: {identical_percent:.4%}") + + # Make a patch-y file + # TODO: Make this a flag + patch_data = {int(k): v["1"] for k, v in diff_bytes.items()} + print(json.dumps(patch_data)) + else: + logger.info("Percentage comparison for differently sized files NYI!") + + print(table.draw()) + diff --git a/src/gex/commands/file/file.py b/src/gex/commands/file/file.py index d9f7ff3..da17837 100644 --- a/src/gex/commands/file/file.py +++ b/src/gex/commands/file/file.py @@ -1,6 +1,7 @@ import click from .deinterleave import deinterleave +from .diff import diff from .hash import hash_cli from .identify import identify from .slice import slice_cli @@ -10,6 +11,7 @@ def file(): """Generic file operations""" file.add_command(deinterleave) +file.add_command(diff) file.add_command(hash_cli) file.add_command(identify) file.add_command(slice_cli) diff --git a/src/gex/commands/tasks/details.py b/src/gex/commands/tasks/details.py index 4e957f6..5587c9c 100644 --- a/src/gex/commands/tasks/details.py +++ b/src/gex/commands/tasks/details.py @@ -12,7 +12,7 @@ def details(task): task_class = helper.load_task(task) if task_class is None: raise Exception(f"Task {task} not found to describe.") - + task_class.read_task_metadata() markdown_text = get_header_display(task_class) markdown_text += "\n\n" markdown_text += task_class.get_details_markdown() diff --git a/src/gex/commands/tasks/extract.py b/src/gex/commands/tasks/extract.py index c26979a..8b7f4f3 100644 --- a/src/gex/commands/tasks/extract.py +++ b/src/gex/commands/tasks/extract.py @@ -36,6 +36,8 @@ def extract(src_dir, dest_dir, task, props): # Ensure the output folder exists or can be made helper.preparepath(dest_dir) + task_class.read_task_metadata() + task_class.set_props(props) task_class.execute(src_dir, dest_dir) diff --git a/src/gex/commands/tasks/list.py b/src/gex/commands/tasks/list.py index 384506f..40b7452 100644 --- a/src/gex/commands/tasks/list.py +++ b/src/gex/commands/tasks/list.py @@ -11,4 +11,6 @@ def list_cli(): for task in impl.__all__: task_class = helper.load_task(task) if task_class: - logger.info(f"{task_class.get_task_name().rjust(15, ' ')}: {task_class.get_title()}") + name = task_class.get_task_name() + if name is not None: + logger.info(f"{name.rjust(15, ' ')}: {task_class.get_title()}") diff --git a/src/gex/lib/archive/zip.py b/src/gex/lib/archive/zip.py new file mode 100644 index 0000000..d724fee --- /dev/null +++ b/src/gex/lib/archive/zip.py @@ -0,0 +1,34 @@ +'''Module to handle ZIP archive (additional utility)''' +import io +import zipfile +import logging + +logger = logging.getLogger('gextoolbox') + +def extract(bytes_obj): + '''Extract a ZIP archive into a list''' + files = {} + with zipfile.ZipFile(io.BytesIO(bytes_obj), "r") as archive: + zip_entries = list(archive.infolist()) + for file_entry in zip_entries: + with archive.open(file_entry) as file_read_obj: + contents = file_read_obj.read() + files[file_entry.filename] = { + "contents": contents, + "entry": file_entry.filename, + "size": file_entry.file_size + } + return files + +def get_metadata(bytes_obj): + '''Get a list of file entries usable for verifying the contents''' + files = {} + with zipfile.ZipFile(io.BytesIO(bytes_obj), "r") as archive: + zip_entries = list(archive.infolist()) + for file_entry in zip_entries: + files[file_entry.filename] = { + "filename": file_entry.filename, + "size": file_entry.file_size, + "crc": hex(file_entry.CRC)[2:].upper().rjust(8, "0") + } + return files diff --git a/src/gex/lib/tasks/basetask.py b/src/gex/lib/tasks/basetask.py index fc08542..0758d4a 100644 --- a/src/gex/lib/tasks/basetask.py +++ b/src/gex/lib/tasks/basetask.py @@ -1,6 +1,13 @@ '''Containes the BaseTask class, the base class for tasks''' import copy +import json +import logging +import os +from gex.lib.utils.blob import hash as hash_helper +from gex.lib.archive import zip as zip_lib + +logger = logging.getLogger('gextoolbox') class BaseTask: '''Base class for rom extraction tasks''' @@ -13,11 +20,144 @@ class BaseTask: _out_file_notes = {} _prop_info = {} _props = {} + _metadata = None def __init__(self): for prop_key, prop_value in self._prop_info.items(): self._props[prop_key] = prop_value['default'] + def read_task_metadata(self): + '''Read the JSON-based metadata for a task''' + basetask_path = os.path.dirname(__file__) + metadata_path = os.path.join(basetask_path, 'impl', self._task_name, 'metadata.json') + if os.path.exists(metadata_path): + with open(metadata_path, 'r', encoding="UTF-8") as metadata_file: + self._metadata = json.load(metadata_file) + if self._metadata is None: + logger.warning(f"Could not find metadata.json for {self._task_name}") + + # Reading data files + # - Multiple mapping types + # - One-to-one: Sometimes, one file is one game + # - One-to-many: Sometimes, one input file is multiple games + # - Many-to-one: Sometimes, we need multiple input files for one game + # - Many-to-many: Sometimes, both are true: for examplen read these 5 ROM types, get multiple variants of the same game out of these files + # - Files can be very large - some games, for example, have single files above 8 GB! + # - Some are straight copies, some are unpacking complex formats + # - Disk IO is expensive, but... it could be worse + # There's no one size fits all. + + def read_all_datafiles(self, in_dir): + '''Read all data files as defined in the metadata - mostly useful for smaller collections with many-to-many relationships''' + # We read all files at once generally because there are a few cases where we cross-read them to fill out missing files + in_files = {} + for file_ref, file_metadata in self._metadata['in']['files'].items(): + data_file = self.read_datafile(in_dir, file_metadata) + in_files[file_ref] = data_file + return in_files + + def read_datafile(self, in_dir, file_metadata): + '''Read a specific data file as defined in the metadata, including CRC/Size check/version identification''' + rel_path = file_metadata.get('rel_path') or [] + data_path = os.path.join(in_dir, *rel_path, file_metadata['filename']) + if os.path.exists(data_path): + # consider switching this to mmap bytearray/readablefile memory-mapped file hybrids to improve memory usage + with open(data_path, 'rb') as data_file: + contents = data_file.read() + + size = len(contents) + crc = hash_helper.get_crc(contents) + sha = hash_helper.get_sha1(contents) + logging.debug(f"Read {data_path} with size {size}, crc {crc} and sha {sha}") + + versions = file_metadata.get("versions") or [] + file_ver_tag = None + for version_tag, version_meta in versions.items(): + # Check size first if we have it + if 'size' in version_meta: + if version_meta['size'] != size: + continue + + if 'sha' in version_meta: + if hex(int(version_meta['sha'], base=16)) == sha: + file_ver_tag = version_tag + break + else: + continue + + if 'crc' in version_meta: + if hex(int(version_meta['crc'], base=16)) == crc: + file_ver_tag = version_tag + break + else: + continue + + + if file_ver_tag: + logging.debug(f"Identified {data_path} as version {file_ver_tag}") + else: + logging.warning(f"Could not identify version of {data_path}!") + + return { + "name": os.path.basename(data_path), + "fullpath": data_path, + "contents": contents, + "version": file_ver_tag + } + else: + logging.warning(f"Could not find file at {data_path}!") + return None + + def verify_out_file(self, file_name, contents): + '''Verify an output file using the method specified in the metadata''' + # Find out_file entry + out_file = next((x for x in self._metadata['out']['files'] if x['filename'] == file_name), None) + if out_file is None: + logger.info(f"Could not find entry to verify {file_name}") + return None + + if out_file['status'] == 'partial' or out_file['status'] == 'no-rom': + logger.info(f"Verification not available for partial ROM {file_name}") + return None + + # Get verify object + verify_obj = out_file.get('verify') + if verify_obj is None: + logger.info(f"Verification data not available for ROM {file_name}") + return None + + # Check verify type + if verify_obj['type'] == 'crc': + crc = hash_helper.get_crc(contents)[2:].upper().rjust(8, "0") + if len(contents) != verify_obj['size']: + logger.info(f"Could NOT verify {file_name}: File size doesn't match!") + return False + elif crc != verify_obj['crc']: + logger.info(f"Could NOT verify {file_name}: CRC doesn't match!") + return False + else: + logger.info(f"Verified {file_name}.") + return True + elif verify_obj['type'] == 'zip': + zip_metas = zip_lib.get_metadata(contents) + # Ensure the file name lists are the same + real_filenames = set(zip_metas.keys()) + expected_filenames = set(verify_obj['entries'].keys()) + if real_filenames != expected_filenames: + logger.info(f"Could NOT verify {file_name}: File lists don't match!") + return False + # Compare file size/CRC + for inner_filename, zip_meta in zip_metas.items(): + verify_entry = verify_obj['entries'][inner_filename] + if zip_meta['crc'] != verify_entry['crc'] or zip_meta['size'] != verify_entry['size'] : + logger.info(f"Could NOT verify {file_name}: {inner_filename} should be {verify_entry['crc']} at {verify_entry['size']} bytes, found {zip_meta['crc']} at {zip_meta['size']}") + return False + logger.info(f"Verified {file_name}.") + return True + else: + logger.info(f"Unknown verify type: {verify_obj['type']}") + return None + def set_props(self, in_props): '''Set any additional props for this task''' for value in in_props: diff --git a/src/gex/lib/tasks/copytask.py b/src/gex/lib/tasks/copytask.py new file mode 100644 index 0000000..34356ea --- /dev/null +++ b/src/gex/lib/tasks/copytask.py @@ -0,0 +1,29 @@ +'''Implementation of basic copy-only task''' +import logging +import os +from gex.lib.tasks.basetask import BaseTask + +logger = logging.getLogger('gextoolbox') + +class CopyTask(BaseTask): + '''Implements basic copy-only task''' + + def get_out_file_info(self): + '''Return a list of output files''' + return { + "files": self._metadata['out']['files'], + "notes": self._metadata['out']['notes'] + } + + def execute(self, in_dir, out_dir): + '''Copy/rename the ROM files''' + for file_metadata in self._metadata['in']['files'].values(): + resolved_file = self.read_datafile(in_dir, file_metadata) + out_file_entry = [x for x in self._metadata['out']['files'] if x['game'] == file_metadata['copy_to']][0] + + filename = out_file_entry['filename'] + _ = self.verify_out_file(filename, resolved_file['contents']) + out_path = os.path.join(out_dir, filename) + with open(out_path, "wb") as out_file: + out_file.write(resolved_file['contents']) + logger.info("Processing complete.") \ No newline at end of file diff --git a/src/gex/lib/tasks/impl/acac.py b/src/gex/lib/tasks/impl/acac/__init__.py similarity index 86% rename from src/gex/lib/tasks/impl/acac.py rename to src/gex/lib/tasks/impl/acac/__init__.py index 04902b1..b29d1d6 100644 --- a/src/gex/lib/tasks/impl/acac.py +++ b/src/gex/lib/tasks/impl/acac/__init__.py @@ -30,133 +30,12 @@ class ACACTask(BaseTask): } } - _game_info_map = [ - { - "name": "AJAX (J)", - "filename": "ajaxj.zip", - 'status': 'playable', - "notes": [] - }, - { - "name": "Typhoon", - "filename": "typhoon.zip", - 'status': 'playable', - "notes": [] - }, - { - "name": "Haunted Castle (Version M)", - "filename": "hcastle.zip", - 'status': 'good', - "notes": [] - }, - { - "name": "Haunted Castle (Version E)", - "filename": "hcastlee.zip", - 'status': 'good', - "notes": [] - }, - { - "name": "Haunted Castle (Version K)", - "filename": "hcastlek.zip", - 'status': 'good', - "notes": [] - }, - { - "name": "Akuma-Jou Dracula (Version N)", - "filename": "akumajoun.zip", - 'status': 'good', - "notes": [] - }, - { - "name": "Nemesis (World?)", - "filename": "nemesisuk.zip", - 'status': 'good', - "notes": [] - }, - { - "name": "Nemesis", - "filename": "nemesis.zip", - 'status': 'good', - "notes": [] - }, - { - "name": "Gradius 2", - "filename": "gradius2.zip", - 'status': 'playable', - "notes": [] - }, - { - "name": "Vulcan Venture", - "filename": "vulcan.zip", - 'status': 'playable', - "notes": [] - }, - { - "name": "Thunder Cross (J)", - "filename": "thunderxj.zip", - 'status': 'good', - "notes": [] - }, - { - "name": "Thunder Cross (Set 1)", - "filename": "thunderx.zip", - 'status': 'good', - "notes": [] - }, - { - "name": "Thunder Cross (Set 2)", - "filename": "thunderxa.zip", - 'status': 'good', - "notes": [] - }, - { - "name": "Thunder Cross (Set 3)", - "filename": "thunderxb.zip", - 'status': 'good', - "notes": [] - }, - { - "name": "Salamander", - "filename": "salamand.zip", - 'status': 'good', - "notes": [] - }, - { - "name": "Salamander (J)", - "filename": "salamandj.zip", - 'status': 'good', - "notes": [] - }, - { - "name": "Lifeforce", - "filename": "lifefrce.zip", - 'status': 'good', - "notes": [] - }, - { - "name": "Lifeforce (J)", - "filename": "lifefrcejzip", - 'status': 'playable', - "notes": [2] - }, - # TWINBEE - can find bits and pieces - # SCRAMBLE - no sign of it - ] - - _out_file_notes = { - "1": "This game has a placeholder file and may be missing some sound samples.", - "2": "This game has a bad dump, but is fully playable." - } - - def __init__(self): - super().__init__() - self._out_file_list = map(lambda x: { - 'filename': x['filename'], - 'game': f"{x['name']}", - 'system': "Arcade", - "status": x['status'], - "notes": x['notes']}, - self._game_info_map) + def get_out_file_info(self): + '''Return a list of output files''' + return { + "files": self._metadata['out']['files'], + "notes": self._metadata['out']['notes'] + } def execute(self, in_dir, out_dir): src_file = os.path.join(in_dir, "AA_AC_ArcadeClassics.exe") @@ -167,7 +46,6 @@ def execute(self, in_dir, out_dir): with open(os.path.join(out_dir, 'merged_decomp_blob'), "wb") as out_file: out_file.write(src_contents_decomp) - out_files = [] out_files.extend(self._handle_nemesis(src_contents)) out_files.extend(self._handle_hcastle(src_contents)) @@ -180,52 +58,15 @@ def execute(self, in_dir, out_dir): if out_files: for out_file_entry in out_files: - out_path = os.path.join(out_dir, out_file_entry['filename']) + filename = out_file_entry['filename'] + _ = self.verify_out_file(filename, out_file_entry['contents']) + out_path = os.path.join(out_dir, filename) with open(out_path, "wb") as out_file: logger.info(f"Writing {out_file_entry['filename']}...") out_file.write(out_file_entry['contents']) - # for game in self._game_info_map: - # if game.get('status') == "no-rom": - # logger.info(f"Skipping {game['name']} as there is no ROM to extract...") - # continue - - # is_partial = game.get('status') == "partial" - # if not self._props.get('include-partials') and is_partial: - # logger.info(f"Skipping {game['name']} as this tool cannot extract a working copy...") - # continue - - # logger.info(f"Extracting {game['name']}...") - - # # Get the specified decompression section - # contents = transforms.cut(src_contents, game['in']['start'], length=game['in']['length']) - # lzd = lzma.LZMADecompressor() - # contents = lzd.decompress(contents) - - # output_files = [] - # if 'handler' in game: - # handler_func = getattr(self, game['handler']) - # output_files.extend(handler_func(contents, game)) - # else: - # logger.warning(f"No handler defined for {game['name']}; dumping contents") - # output_files.extend(self._handle_copyorig(contents, game)) - - # for output_file in output_files: - # filename = f"partial_{output_file['filename']}" if is_partial else output_file['filename'] - # logger.info(f"Saving {filename}...") - # with open(os.path.join(out_dir, filename), "wb") as out_file: - # out_file.write(output_file['contents']) logger.info("Processing complete.") - def _handle_copyorig(self, contents, game): - return [{'filename': game['filename'], 'contents': helpers.build_zip({ "decompressed_blob": contents })}] - - def _handle_generic_copy(self, contents, game): - zip_files = {} - for work_file in game.get('out') or []: - zip_files[work_file['filename']] = transforms.cut(contents, work_file['start'], length=work_file['length']) - return [{'filename': game['filename'], 'contents': helpers.build_zip(zip_files)}] - def _handle_ajax(self, contents): contents = transforms.cut(contents, 0x11B610, length=1124930) lzd = lzma.LZMADecompressor() @@ -1014,7 +855,7 @@ def lzma_multi_decomp(self, in_data, out_dir): b'\x00\x02' ] if comp_mode not in valid_modes: - print(f'offset {hex(offset)}: skipping, invalid comp_type') + logger.debug(f'offset {hex(offset)}: skipping, invalid comp_type') offset += 1 else: try: @@ -1025,12 +866,12 @@ def lzma_multi_decomp(self, in_data, out_dir): curr_chunk = lzd.decompress(target) after_len = len(lzd.unused_data) consumed_bytes = before_len - after_len - print(f'offset {hex(offset)}: magic {magic_bytes}, consumed {consumed_bytes} bytes') + logger.debug(f'offset {hex(offset)}: magic {magic_bytes}, consumed {consumed_bytes} bytes') with open(os.path.join(out_dir, f'decompressed_blob_{hex(offset)}'), "wb") as out_file: out_file.write(curr_chunk) out_data += curr_chunk offset += consumed_bytes except lzma.LZMAError: - print(f'offset {hex(offset)}: magic {magic_bytes}, invalid') + logger.debug(f'offset {hex(offset)}: magic {magic_bytes}, invalid') offset += 1 return out_data diff --git a/src/gex/lib/tasks/impl/acac/metadata.json b/src/gex/lib/tasks/impl/acac/metadata.json new file mode 100644 index 0000000..9358f2b --- /dev/null +++ b/src/gex/lib/tasks/impl/acac/metadata.json @@ -0,0 +1,504 @@ +{ + "in": { + "files": { + "source": { + "filename": "AA_AC_ArcadeClassics.exe", + "versions": { + "Steam": { + "size": 6529856, + "crc": "35C2D2E7" + } + } + } + } + }, + "out": { + "files": [ + { + "name": "AJAX (J)", + "filename": "ajaxj.zip", + "status": "playable", + "system": "Arcade", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "770_l01.n11": {"size": 65536, "crc": "7CEA5274"}, + "770_l02.n12": {"size": 65536, "crc": "AD7D592B"}, + "770_l05.i16": {"size": 32768, "crc": "ED64FBB2"}, + "770_f04.g16": {"size": 65536, "crc": "E0E4EC9C"}, + "770_f03.f16": {"size": 32768, "crc": "3FE914FD"}, + "770c13.n22": {"size": 262144, "crc": "5E6B1C0F"}, + "770c12.k22": {"size": 262144, "crc": "DD435BFA"}, + "770c09.n4": {"size": 524288, "crc": "1AB4A7FF"}, + "770c08.k4": {"size": 524288, "crc": "A8E80586"}, + "770c06.f4": {"size": 262144, "crc": "D0C592EE"}, + "770c07.h4": {"size": 262144, "crc": "067CE912"}, + "770c10": {"size": 262144, "crc": "7FAC825F"}, + "770c11": {"size": 524288, "crc": "299A615A"}, + "63s241.j11": {"size": 512, "crc": "9BDD719F"} + } + } + }, + { + "name": "Typhoon", + "filename": "typhoon.zip", + "status": "playable", + "system": "Arcade", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "770_k01.n11": {"size": 65536, "crc": "5BA74A22"}, + "770_k02.n12": {"size": 65536, "crc": "3BCF782A"}, + "770_k05.i16": {"size": 32768, "crc": "0F1BEBBB"}, + "770_f04.g16": {"size": 65536, "crc": "E0E4EC9C"}, + "770_h03.f16": {"size": 32768, "crc": "3FE914FD"}, + "770c13.n22": {"size": 262144, "crc": "5E6B1C0F"}, + "770c12.k22": {"size": 262144, "crc": "DD435BFA"}, + "770c09.n4": {"size": 524288, "crc": "1AB4A7FF"}, + "770c08.k4": {"size": 524288, "crc": "A8E80586"}, + "770c06.f4": {"size": 262144, "crc": "D0C592EE"}, + "770c07.h4": {"size": 262144, "crc": "067CE912"}, + "770c10": {"size": 262144, "crc": "7FAC825F"}, + "770c11": {"size": 524288, "crc": "299A615A"}, + "63s241.j11": {"size": 512, "crc": "9BDD719F"} + } + } + }, + { + "name": "Haunted Castle (Version M)", + "filename": "hcastle.zip", + "status": "good", + "system": "Arcade", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "m03.k12": {"size": 32768, "crc": "D85E743D"}, + "b06.k8": {"size": 131072, "crc": "ABD07866"}, + "768c07.e17": {"size": 524288, "crc": "01F9889C"}, + "768c09.g21": {"size": 524288, "crc": "E3BE3FDD"}, + "768c08.g19": {"size": 524288, "crc": "9633DB8B"}, + "768c04.j5": {"size": 524288, "crc": "2960680E"}, + "768c05.j6": {"size": 524288, "crc": "65A2F227"}, + "768c13.j21": {"size": 256, "crc": "F5DE80CB"}, + "768c11.i4": {"size": 256, "crc": "F5DE80CB"}, + "768c14.j22": {"size": 256, "crc": "B32071B7"}, + "768c10.i3": {"size": 256, "crc": "B32071B7"}, + "768b12.d20": {"size": 256, "crc": "362544B8"}, + "768e01.e4": {"size": 32768, "crc": "B9FFF184"} + } + } + }, + { + "name": "Haunted Castle (Version E)", + "filename": "hcastlee.zip", + "status": "good", + "system": "Arcade", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "768e03.k12": {"size": 32768, "crc": "0B32619C"}, + "768e06.k8": {"size": 131072, "crc": "0431B8C0"}, + "768c07.e17": {"size": 524288, "crc": "01F9889C"}, + "768c09.g21": {"size": 524288, "crc": "E3BE3FDD"}, + "768c08.g19": {"size": 524288, "crc": "9633DB8B"}, + "768c04.j5": {"size": 524288, "crc": "2960680E"}, + "768c05.j6": {"size": 524288, "crc": "65A2F227"}, + "768c13.j21": {"size": 256, "crc": "F5DE80CB"}, + "768c11.i4": {"size": 256, "crc": "F5DE80CB"}, + "768c14.j22": {"size": 256, "crc": "B32071B7"}, + "768c10.i3": {"size": 256, "crc": "B32071B7"}, + "768b12.d20": {"size": 256, "crc": "362544B8"}, + "768e01.e4": {"size": 32768, "crc": "B9FFF184"} + } + } + }, + { + "name": "Haunted Castle (Version K)", + "filename": "hcastlek.zip", + "status": "good", + "system": "Arcade", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "768k03.k12": {"size": 32768, "crc": "40CE4F38"}, + "768g06.k8": {"size": 131072, "crc": "CDADE920"}, + "768c07.e17": {"size": 524288, "crc": "01F9889C"}, + "768c09.g21": {"size": 524288, "crc": "E3BE3FDD"}, + "768c08.g19": {"size": 524288, "crc": "9633DB8B"}, + "768c04.j5": {"size": 524288, "crc": "2960680E"}, + "768c05.j6": {"size": 524288, "crc": "65A2F227"}, + "768c13.j21": {"size": 256, "crc": "F5DE80CB"}, + "768c11.i4": {"size": 256, "crc": "F5DE80CB"}, + "768c14.j22": {"size": 256, "crc": "B32071B7"}, + "768c10.i3": {"size": 256, "crc": "B32071B7"}, + "768b12.d20": {"size": 256, "crc": "362544B8"}, + "768e01.e4": {"size": 32768, "crc": "B9FFF184"} + } + } + }, + { + "name": "Akuma-Jou Dracula (Version N)", + "filename": "akumajoun.zip", + "status": "good", + "system": "Arcade", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "768n03.k12": {"size": 32768, "crc": "3E4DCA2A"}, + "768j06.k8": {"size": 131072, "crc": "42283C3E"}, + "768c07.e17": {"size": 524288, "crc": "01F9889C"}, + "768c09.g21": {"size": 524288, "crc": "E3BE3FDD"}, + "768c08.g19": {"size": 524288, "crc": "9633DB8B"}, + "768c04.j5": {"size": 524288, "crc": "2960680E"}, + "768c05.j6": {"size": 524288, "crc": "65A2F227"}, + "768c13.j21": {"size": 256, "crc": "F5DE80CB"}, + "768c11.i4": {"size": 256, "crc": "F5DE80CB"}, + "768c14.j22": {"size": 256, "crc": "B32071B7"}, + "768c10.i3": {"size": 256, "crc": "B32071B7"}, + "768b12.d20": {"size": 256, "crc": "362544B8"}, + "768e01.e4": {"size": 32768, "crc": "B9FFF184"} + } + } + }, + { + "name": "Nemesis (World?)", + "filename": "nemesisuk.zip", + "status": "good", + "system": "Arcade", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "456-e01.12a": {"size": 32768, "crc": "E1993F91"}, + "456-e05.12c": {"size": 32768, "crc": "C9761C78"}, + "456-e02.13a": {"size": 32768, "crc": "F6169C4B"}, + "456-e06.13c": {"size": 32768, "crc": "AF58C548"}, + "456-e03.14a": {"size": 32768, "crc": "8CEFB25F"}, + "456-e07.14c": {"size": 32768, "crc": "D50B82CB"}, + "456-e04.15a": {"size": 32768, "crc": "322423D0"}, + "456-e08.15c": {"size": 32768, "crc": "EB656266"}, + "456-b09.9c": {"size": 16384, "crc": "26BF9636"}, + "400-a01.fse": {"size": 256, "crc": "5827B1E8"}, + "400-a02.fse": {"size": 256, "crc": "2F44F970"} + } + } + }, + { + "name": "Nemesis", + "filename": "nemesis.zip", + "status": "good", + "system": "Arcade", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "456-d01.12a": {"size": 32768, "crc": "35FF1AAA"}, + "456-d05.12c": {"size": 32768, "crc": "23155FAA"}, + "456-d02.13a": {"size": 32768, "crc": "AC0CF163"}, + "456-d06.13c": {"size": 32768, "crc": "023F22A9"}, + "456-d03.14a": {"size": 32768, "crc": "8CEFB25F"}, + "456-d07.14c": {"size": 32768, "crc": "D50B82CB"}, + "456-d04.15a": {"size": 32768, "crc": "9CA75592"}, + "456-d08.15c": {"size": 32768, "crc": "03C0B7F5"}, + "456-d09.9c": {"size": 16384, "crc": "26BF9636"}, + "400-a01.fse": {"size": 256, "crc": "5827B1E8"}, + "400-a02.fse": {"size": 256, "crc": "2F44F970"} + } + } + }, + { + "name": "Gradius 2", + "filename": "gradius2.zip", + "status": "playable", + "system": "Arcade", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "785_x05.6n": {"size": 65536, "crc": "8A23A7B8"}, + "785_x04.4n": {"size": 65536, "crc": "88E466CE"}, + "785_x09.6r": {"size": 65536, "crc": "3F3D7D7A"}, + "785_x08.4r": {"size": 65536, "crc": "C39C8EFD"}, + "785_g14.d8": {"size": 16384, "crc": "9DCDAD9D"}, + "785_g03.10a": {"size": 32768, "crc": "67A3B50D"}, + "785f15.p13": {"size": 524288, "crc": "5BD239AC"}, + "785f17.p16": {"size": 524288, "crc": "4E7A7B82"}, + "785f16.p15": {"size": 524288, "crc": "95C6B8A3"}, + "785f18.p18": {"size": 524288, "crc": "3F604E9A"}, + "785_p07.10n": {"size": 65536, "crc": "686D549D"}, + "785_p06.8n": {"size": 65536, "crc": "70C94BEE"}, + "785_p13.10s": {"size": 65536, "crc": "478FDB0A"}, + "785_p12.8s": {"size": 65536, "crc": "38EA402A"}, + "785_f01.5a": {"size": 131072, "crc": "A0D8D69E"}, + "785_f02.7c": {"size": 131072, "crc": "7EE8CDCD"} + } + } + }, + { + "name": "Vulcan Venture", + "filename": "vulcan.zip", + "status": "playable", + "system": "Arcade", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "785_w05.6n": {"size": 65536, "crc": "6E0E99CD"}, + "785_w04.4n": {"size": 65536, "crc": "23EC74CA"}, + "785_w09.6r": {"size": 65536, "crc": "377E4F28"}, + "785_w08.4r": {"size": 65536, "crc": "813D41EA"}, + "785_h14.d8": {"size": 16384, "crc": "02F4B16F"}, + "785_g03.10a": {"size": 32768, "crc": "67A3B50D"}, + "785f15.p13": {"size": 524288, "crc": "5BD239AC"}, + "785f17.p16": {"size": 524288, "crc": "4E7A7B82"}, + "785f16.p15": {"size": 524288, "crc": "95C6B8A3"}, + "785f18.p18": {"size": 524288, "crc": "3F604E9A"}, + "785_p07.10n": {"size": 65536, "crc": "686D549D"}, + "785_p06.8n": {"size": 65536, "crc": "70C94BEE"}, + "785_p13.10s": {"size": 65536, "crc": "478FDB0A"}, + "785_p12.8s": {"size": 65536, "crc": "38EA402A"}, + "785_f01.5a": {"size": 131072, "crc": "A0D8D69E"}, + "785_f02.7c": {"size": 131072, "crc": "7EE8CDCD"} + } + } + }, + { + "name": "Thunder Cross (J)", + "filename": "thunderxj.zip", + "status": "good", + "system": "Arcade", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "873-n02.k13": {"size": 65536, "crc": "55AFA2CC"}, + "873-n03.k15": {"size": 65536, "crc": "A01E2E3E"}, + "873a08.f20": {"size": 256, "crc": "E2D09A1B"}, + "873c04a.f11": {"size": 65536, "crc": "F7740BF3"}, + "873c04c.f10": {"size": 65536, "crc": "5DACBD2B"}, + "873c05a.f9": {"size": 65536, "crc": "D73E107D"}, + "873c05c.f8": {"size": 65536, "crc": "59903200"}, + "873c04b.e11": {"size": 65536, "crc": "9AC581DA"}, + "873c04d.e10": {"size": 65536, "crc": "44A4668C"}, + "873c05b.e9": {"size": 65536, "crc": "81059B99"}, + "873c05d.e8": {"size": 65536, "crc": "7FA3D7DF"}, + "873c06a.f6": {"size": 65536, "crc": "0E340B67"}, + "873c06c.f5": {"size": 65536, "crc": "EF0E72CD"}, + "873c07a.f4": {"size": 65536, "crc": "A8AAB84F"}, + "873c07c.f3": {"size": 65536, "crc": "2521009A"}, + "873c06b.e6": {"size": 65536, "crc": "97AD202E"}, + "873c06d.e5": {"size": 65536, "crc": "8393D42E"}, + "873c07b.e4": {"size": 65536, "crc": "12A2B8BA"}, + "873c07d.e3": {"size": 65536, "crc": "FAE9F965"}, + "873-f01.f8": {"size": 32768, "crc": "EA35FFA3"} + } + } + }, + { + "name": "Thunder Cross (Set 1)", + "filename": "thunderx.zip", + "status": "good", + "system": "Arcade", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "873-s02.k13": {"size": 65536, "crc": "6619333A"}, + "873-s03.k15": {"size": 65536, "crc": "2AEC2699"}, + "873a08.f20": {"size": 256, "crc": "E2D09A1B"}, + "873c04a.f11": {"size": 65536, "crc": "F7740BF3"}, + "873c04c.f10": {"size": 65536, "crc": "5DACBD2B"}, + "873c05a.f9": {"size": 65536, "crc": "D73E107D"}, + "873c05c.f8": {"size": 65536, "crc": "59903200"}, + "873c04b.e11": {"size": 65536, "crc": "9AC581DA"}, + "873c04d.e10": {"size": 65536, "crc": "44A4668C"}, + "873c05b.e9": {"size": 65536, "crc": "81059B99"}, + "873c05d.e8": {"size": 65536, "crc": "7FA3D7DF"}, + "873c06a.f6": {"size": 65536, "crc": "0E340B67"}, + "873c06c.f5": {"size": 65536, "crc": "EF0E72CD"}, + "873c07a.f4": {"size": 65536, "crc": "A8AAB84F"}, + "873c07c.f3": {"size": 65536, "crc": "2521009A"}, + "873c06b.e6": {"size": 65536, "crc": "97AD202E"}, + "873c06d.e5": {"size": 65536, "crc": "8393D42E"}, + "873c07b.e4": {"size": 65536, "crc": "12A2B8BA"}, + "873c07d.e3": {"size": 65536, "crc": "FAE9F965"}, + "873-f01.f8": {"size": 32768, "crc": "EA35FFA3"} + } + } + }, + { + "name": "Thunder Cross (Set 2)", + "filename": "thunderxa.zip", + "status": "good", + "system": "Arcade", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "873-k02.k13": {"size": 65536, "crc": "80CC1C45"}, + "873-k03.k15": {"size": 65536, "crc": "276817AD"}, + "873-h01.f8": {"size": 32768, "crc": "990B7A7C"}, + "873a08.f20": {"size": 256, "crc": "E2D09A1B"}, + "873c04a.f11": {"size": 65536, "crc": "F7740BF3"}, + "873c04c.f10": {"size": 65536, "crc": "5DACBD2B"}, + "873c05a.f9": {"size": 65536, "crc": "D73E107D"}, + "873c05c.f8": {"size": 65536, "crc": "59903200"}, + "873c04b.e11": {"size": 65536, "crc": "9AC581DA"}, + "873c04d.e10": {"size": 65536, "crc": "44A4668C"}, + "873c05b.e9": {"size": 65536, "crc": "81059B99"}, + "873c05d.e8": {"size": 65536, "crc": "7FA3D7DF"}, + "873c06a.f6": {"size": 65536, "crc": "0E340B67"}, + "873c06c.f5": {"size": 65536, "crc": "EF0E72CD"}, + "873c07a.f4": {"size": 65536, "crc": "A8AAB84F"}, + "873c07c.f3": {"size": 65536, "crc": "2521009A"}, + "873c06b.e6": {"size": 65536, "crc": "97AD202E"}, + "873c06d.e5": {"size": 65536, "crc": "8393D42E"}, + "873c07b.e4": {"size": 65536, "crc": "12A2B8BA"}, + "873c07d.e3": {"size": 65536, "crc": "FAE9F965"} + } + } + }, + { + "name": "Thunder Cross (Set 3)", + "filename": "thunderxb.zip", + "status": "good", + "system": "Arcade", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "873-02.k13": {"size": 65536, "crc": "C58B2C34"}, + "873-03.k15": {"size": 65536, "crc": "36680A4E"}, + "873a08.f20": {"size": 256, "crc": "E2D09A1B"}, + "873c04a.f11": {"size": 65536, "crc": "F7740BF3"}, + "873c04c.f10": {"size": 65536, "crc": "5DACBD2B"}, + "873c05a.f9": {"size": 65536, "crc": "D73E107D"}, + "873c05c.f8": {"size": 65536, "crc": "59903200"}, + "873c04b.e11": {"size": 65536, "crc": "9AC581DA"}, + "873c04d.e10": {"size": 65536, "crc": "44A4668C"}, + "873c05b.e9": {"size": 65536, "crc": "81059B99"}, + "873c05d.e8": {"size": 65536, "crc": "7FA3D7DF"}, + "873c06a.f6": {"size": 65536, "crc": "0E340B67"}, + "873c06c.f5": {"size": 65536, "crc": "EF0E72CD"}, + "873c07a.f4": {"size": 65536, "crc": "A8AAB84F"}, + "873c07c.f3": {"size": 65536, "crc": "2521009A"}, + "873c06b.e6": {"size": 65536, "crc": "97AD202E"}, + "873c06d.e5": {"size": 65536, "crc": "8393D42E"}, + "873c07b.e4": {"size": 65536, "crc": "12A2B8BA"}, + "873c07d.e3": {"size": 65536, "crc": "FAE9F965"}, + "873-f01.f8": {"size": 32768, "crc": "EA35FFA3"} + } + } + }, + { + "name": "Salamander", + "filename": "salamand.zip", + "status": "good", + "system": "Arcade", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "587-d02.18b": {"size": 65536, "crc": "A42297F9"}, + "587-d05.18c": {"size": 65536, "crc": "F9130B0A"}, + "587-c01.10a": {"size": 131072, "crc": "09FE0632"}, + "587-d08.8g": {"size": 16384, "crc": "F9AC6B82"}, + "587-d09.11j": {"size": 32768, "crc": "5020972C"}, + "587-c03.17b": {"size": 131072, "crc": "E5CAF6E6"}, + "587-c06.17c": {"size": 131072, "crc": "C2F567EA"} + } + } + }, + { + "name": "Salamander (J)", + "filename": "salamandj.zip", + "status": "good", + "system": "Arcade", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "587-j02.18b": {"size": 65536, "crc": "F68EE99A"}, + "587-j05.18c": {"size": 65536, "crc": "72C16128"}, + "587-c01.10a": {"size": 131072, "crc": "09FE0632"}, + "587-d08.8g": {"size": 16384, "crc": "F9AC6B82"}, + "587-d09.11j": {"size": 32768, "crc": "5020972C"}, + "587-c03.17b": {"size": 131072, "crc": "E5CAF6E6"}, + "587-c06.17c": {"size": 131072, "crc": "C2F567EA"} + } + } + }, + { + "name": "Lifeforce", + "filename": "lifefrce.zip", + "status": "good", + "system": "Arcade", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "587-k02.18b": {"size": 65536, "crc": "4A44DA18"}, + "587-k05.18c": {"size": 65536, "crc": "2F8C1CBD"}, + "587-c01.10a": {"size": 131072, "crc": "09FE0632"}, + "587-k08.8g": {"size": 16384, "crc": "7F0E9B41"}, + "587-k09.11j": {"size": 32768, "crc": "2255FE8C"}, + "587-c03.17b": {"size": 131072, "crc": "E5CAF6E6"}, + "587-c06.17c": {"size": 131072, "crc": "C2F567EA"} + } + } + }, + { + "name": "Lifeforce (J)", + "filename": "lifefrcej.zip", + "status": "playable", + "system": "Arcade", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "587-n02.18b": {"size": 65536, "crc": "235DBA71"}, + "587-n05.18c": {"size": 65536, "crc": "054E569F"}, + "587-c01.10a": {"size": 131072, "crc": "09FE0632"}, + "587-n08.8g": {"size": 16384, "crc": "7F0E9B41"}, + "587-n09.11j": {"size": 32768, "crc": "E8496150"}, + "587-n03.17b": {"size": 131072, "crc": "9041F850"}, + "587-n06.17c": {"size": 131072, "crc": "FBA8B6AA"} + } + } + }, + { + "name": "Twinbee", + "filename": "twinbee.zip", + "status": "partial", + "system": "Arcade", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "400-a01.fse": {"size": 256, "crc": "5827B1E8"}, + "400-a02.fse": {"size": 256, "crc": "2F44F970"}, + "412-a05.17l": {"size": 131072, "crc": "D93C5499"}, + "412-a07.12l": {"size": 131072, "crc": "2B357069"} + } + } + }, + { + "name": "Scramble", + "filename": "N/A", + "status": "no-rom", + "system": "Arcade", + "notes": [] + } + ], + "notes": { + "1": "This game has a placeholder file and may be missing some sound samples.", + "2": "This game has a bad dump, but is fully playable." + } + } +} \ No newline at end of file diff --git a/src/gex/lib/tasks/impl/ags.py b/src/gex/lib/tasks/impl/ags.py deleted file mode 100644 index 13e0a31..0000000 --- a/src/gex/lib/tasks/impl/ags.py +++ /dev/null @@ -1,399 +0,0 @@ -'''Implementation of ags: Namco Arcade Game Series''' -import logging -import os -from gex.lib.tasks.basetask import BaseTask -from gex.lib.tasks import helpers -from gex.lib.utils.blob import transforms - -logger = logging.getLogger('gextoolbox') - -class AGSTask(BaseTask): - '''Implements ags: Namco Arcade Game Series''' - _task_name = "ags" - _title = "Namco Arcade Game Series" - _details_markdown = ''' -Based on: https://github.com/farmerbb/RED-Project/blob/master/ROM%20Extraction/namco-ags-extract.sh - -These are pulled out of the plugin DLL. - ''' - _default_input_folder = helpers.STEAM_APP_ROOT - _input_folder_desc = "Steam library root" - - - _prop_info = { - "include-partials": { - "description": "Include the partial ROMs that are missing data; useful for mixing with other sources or investigation", - "default": False, - "type": "Boolean" - } - } - _game_info_map = [ - { - "name": "Ms. Pac-Man", - "src_path": r"Ms. PAC-MAN\Ms. PAC-MAN_Data\Plugins\Release_2.dll", - "files": [ - { - "filename": "82s126.1m", - "start": 0x1AE30, - "length": 0x100 - }, - { - "filename": "82s123.7f", - "start": 0x1AF30, - "length": 0x20 - }, - { - "filename": "82s126.4a", # CRC Mismatch - "start": 0x1AF50, - "length": 0x100 - }, - { - "filename": "pacman.5ef", - "start": 0x1B050, - "length": 0x1000 - }, - { - "filename": "5e", - "start": 0x1D050, - "length": 0x1000 - }, - { - "filename": "boot1", - "start": 0x28C20, - "length": 0x1000 - }, - { - "filename": "boot2", - "start": 0x29C20, - "length": 0x1000 - }, - { - "filename": "boot3", - "start": 0x2AC20, - "length": 0x1000 - }, - { - "filename": "boot4", - "start": 0x2BC20, - "length": 0x1000 - }, - { - "filename": "boot5", - "start": 0x30C20, - "length": 0x1000 - }, - { - "filename": "boot6", - "start": 0x31C20, - "length": 0x1000 - }, - { - "filename": "82s126.3m", - "start": 'placeholder', - "length": 0x100 - } - ], - "filename": "mspacman.zip", - 'status': "partial", - "notes": [] - }, - { - "name": "Galaga", - "src_path": r"GALAGA\GALAGA_Data\Plugins\Release_1.dll", - "files": [ - { - "filename": "prom-1.1d", - "start": 0x56710, - "length": 0x100 - }, - { - "filename": "prom-5.5n", - "start": 0x56810, - "length": 0x20 - }, - { - "filename": "prom-3.1c", - "start": 0x56830, - "length": 0x100 - }, - { - "filename": "prom-4.2n", - "start": 0x56930, - "length": 0x100 - }, - { - "filename": "gg1_11.4d", - "start": 0x56A30, - "length": 0x1000 - }, - { - "filename": "gg1_10.4f", - "start": 0x57A30, - "length": 0x1000 - }, - { - "filename": "gg1_9.4l", - "start": 0x58A30, - "length": 0x1000 - }, - { - "filename": "gg1_7b.2c", - "start": 0x64A00, - "length": 0x1000 - }, - { - "filename": "gg1_5b.3f", - "start": 0x65A00, - "length": 0x1000 - }, - { - "filename": "gg1_1b.3p", - "start": 0x66A00, - "length": 0x1000 - }, - { - "filename": "gg1_2b.3m", - "start": 0x67A00, - "length": 0x1000 - }, - { - "filename": "gg1_3.2m", - "start": 0x68A00, - "length": 0x1000 - }, - { - "filename": "gg1_4b.2l", - "start": 0x69A00, - "length": 0x1000 - }, - { - "filename": "prom-2.5c", - "start": 'placeholder', - "length": 0x100 - }, - { - "filename": "51xx.bin", - "start": 'placeholder', - "length": 0x400 - }, - { - "filename": "54xx.bin", - "start": 'placeholder', - "length": 0x400 - } - ], - 'status': "playable", - "filename": "galaga.zip", - "notes": [1] - }, - { - "name": "Dig Dug", - "src_path": r"DIG DUG\DIG DUG_Data\Plugins\Release_0.dll", - "files": [ - { - "filename": "digdug.spr", - "start": 0x1D9F0, - "length": 0x100 - }, - { - "filename": "dd1.10b", - "start": 0x1DAF0, - "length": 0x1000 - }, - { - "filename": "digdug.5n", - "start": 0x1EAF0, - "length": 0x20 - }, - { - "filename": "digdug.1c", - "start": 0x1EB10, - "length": 0x100 - }, - { - "filename": "digdug.2n", - "start": 0x1EC10, - "length": 0x100 - }, - { - "filename": "136007.116", - "start": 0x1ED10, - "length": 0x1000 - }, - { - "filename": "dd1.14", - "start": 0x1FD10, - "length": 0x1000 - }, - { - "filename": "136007.118", - "start": 0x20D10, - "length": 0x1000 - }, - { - "filename": "136007.119", - "start": 0x21D10, - "length": 0x1000 - }, - { - "filename": "dd1.9", - "start": 0x22D10, - "length": 0x800 - }, - { - "filename": "dd1.11", - "start": 0x23510, - "length": 0x1000 - }, - { - "filename": "136007.107", - "start": 0x35420, - "length": 0x1000 - }, - { - "filename": "dd1.5b", - "start": 0x36420, - "length": 0x1000 - }, - { - "filename": "dd1.6b", - "start": 0x37420, - "length": 0x1000 - }, - { - "filename": "136007.101", - "start": 0x38420, - "length": 0x1000 - }, - { - "filename": "136007.102", - "start": 0x39420, - "length": 0x1000 - }, - { - "filename": "136007.103", - "start": 0x3A420, - "length": 0x1000 - }, - { - "filename": "dd1.4b", - "start": 0x3B420, - "length": 0x1000 - }, - { - "filename": "136007.109", - "start": 'placeholder', - "length": 0x100 - } - ], - 'status': "playable", - "filename": "digdug.zip", - "notes": [2] - }, - { - "name": "Pac-Man", - "src_path": r"PAC-MAN\PAC-MAN_Data\Plugins\Release_3.dll", - "files": [ - { - "filename": "82s126.1m", - "start": 0x1AA30, - "length": 0x100 - }, - { - "filename": "82s123.7f", - "start": 0x1AB30, - "length": 0x20 - }, - { - "filename": "82s126.4a", - "start": 0x1AB50, - "length": 0x100 - }, - { - "filename": "pacman.5f", - "start": 0x1AC50, - "length": 0x1000 - }, - { - "filename": "pacman.5e", - "start": 0x1C050, - "length": 0x1000 - }, - { - "filename": "pacman.6e", - "start": 0x28020, - "length": 0x1000 - }, - { - "filename": "pacman.6f", - "start": 0x29020, - "length": 0x1000 - }, - { - "filename": "pacman.6h", - "start": 0x2A020, - "length": 0x1000 - }, - { - "filename": "pacman.6j", - "start": 0x2B020, - "length": 0x1000 - }, - { - "filename": "82s126.3m", - "start": 'placeholder', - "length": 0x100 - }, - ], - 'status': "good", - "filename": "pacman.zip", - "notes": [] - } - ] - - _out_file_notes = { - "1": "This extraction requires MAME 2017/1.39 due to the NAMCO base ROMs, which have placeholders.", - "2": "This extraction requires MAME 2003/0.78 due to the NAMCO base ROMs." - } - - def __init__(self): - super().__init__() - self._out_file_list = map(lambda x: { - 'filename': x['filename'], - 'game': f"{x['name']}", - 'system': "Arcade", - "status": x['status'], - "notes": x['notes']}, - self._game_info_map) - - def execute(self, in_dir, out_dir): - for game in self._game_info_map: - is_partial = game.get('status') == 'partial' - if not self._props.get('include-partials') and is_partial: - logger.info(f"Skipping {game['name']} as this tool cannot extract a working copy...") - continue - - src_file = os.path.join(in_dir, game['src_path']) - if not os.path.exists(src_file): - logger.info(f"Skipping {game['name']} as this tool cannot find it in the given Steam library folder...") - continue - - logger.info(f"Extracting {game['name']}...") - with open(src_file, 'rb') as dll_file: - contents = dll_file.read() - zip_files = {} - for file in game['files']: - if file['start'] == 'placeholder': - file_content = bytearray(b'0' * file['length']) - else: - file_content = transforms.cut(contents, file['start'], length=file['length']) - - zip_files[file['filename']] = file_content - if is_partial: - zip_files['full_dump'] = contents - - logger.info(f"Saving {game['filename']}...") - with open(os.path.join(out_dir, game['filename']), "wb") as out_file: - out_file.write(helpers.build_zip(zip_files)) - - logger.info("Processing complete.") diff --git a/src/gex/lib/tasks/impl/ags_digdug/__init__.py b/src/gex/lib/tasks/impl/ags_digdug/__init__.py new file mode 100644 index 0000000..a83558c --- /dev/null +++ b/src/gex/lib/tasks/impl/ags_digdug/__init__.py @@ -0,0 +1,19 @@ +'''Implementation of ags_digdug: Namco Arcade Game Series: Dig Dug''' +import logging +from gex.lib.tasks.zipsplicetask import ZipSpliceTask +from gex.lib.tasks import helpers +from gex.lib.utils.blob import transforms + +logger = logging.getLogger('gextoolbox') + +class AGSDigDugTask(ZipSpliceTask): + '''Implements ags_digdug: Namco Arcade Game Series: Dig Dug''' + _task_name = "ags_digdug" + _title = "Namco Arcade Game Series: Dig Dug" + _details_markdown = ''' +Based on: https://github.com/farmerbb/RED-Project/blob/master/ROM%20Extraction/namco-ags-extract.sh + +These are pulled out of the plugin DLL. + ''' + _default_input_folder = helpers.gen_steam_app_default_folder("DIG DUG") + _input_folder_desc = "AGS Dig Dug install folder" diff --git a/src/gex/lib/tasks/impl/ags_digdug/metadata.json b/src/gex/lib/tasks/impl/ags_digdug/metadata.json new file mode 100644 index 0000000..c68ce5d --- /dev/null +++ b/src/gex/lib/tasks/impl/ags_digdug/metadata.json @@ -0,0 +1,75 @@ +{ + "in": { + "files": { + "source": { + "rel_path": ["DIG DUG_Data", "Plugins"], + "filename": "Release_0.dll", + "versions": { + "Steam": { + "size": 394240, + "crc": "AA58DC77" + } + } + } + } + }, + "out": { + "files": [ + { + "game": "Dig Dug", + "system": "Arcade", + "filename": "digdug.zip", + "status": "playable", + "notes": [1], + "zip_files": { + "digdug.spr": {"start": "0x1D9F0", "length": "0x100"}, + "dd1.10b": {"start": "0x1DAF0", "length": "0x1000"}, + "digdug.5n": {"start": "0x1EAF0", "length": "0x20"}, + "digdug.1c": {"start": "0x1EB10", "length": "0x100"}, + "digdug.2n": {"start": "0x1EC10", "length": "0x100"}, + "136007.116": {"start": "0x1ED10", "length": "0x1000"}, + "dd1.14": {"start": "0x1FD10", "length": "0x1000"}, + "136007.118": {"start": "0x20D10", "length": "0x1000"}, + "136007.119": {"start": "0x21D10", "length": "0x1000"}, + "dd1.9": {"start": "0x22D10", "length": "0x800"}, + "dd1.11": {"start": "0x23510", "length": "0x1000"}, + "136007.107": {"start": "0x35420", "length": "0x1000"}, + "dd1.5b": {"start": "0x36420", "length": "0x1000"}, + "dd1.6b": {"start": "0x37420", "length": "0x1000"}, + "136007.101": {"start": "0x38420", "length": "0x1000"}, + "136007.102": {"start": "0x39420", "length": "0x1000"}, + "136007.103": {"start": "0x3A420", "length": "0x1000"}, + "dd1.4b": {"start": "0x3B420", "length": "0x1000"}, + "136007.109": {"type": "placeholder", "length": "0x100"} + }, + "verify": { + "type": "zip", + "entries": { + "digdug.spr": { "size": 256, "crc": "7A2815B4"}, + "dd1.10b": { "size": 4096, "crc": "2CF399C2"}, + "digdug.5n": { "size": 32, "crc": "4CB9DA99"}, + "digdug.1c": { "size": 256, "crc": "00C7C419"}, + "digdug.2n": { "size": 256, "crc": "E9B3E08E"}, + "136007.116": { "size": 4096, "crc": "E22957C8"}, + "dd1.14": { "size": 4096, "crc": "2829EC99"}, + "136007.118": { "size": 4096, "crc": "458499E9"}, + "136007.119": { "size": 4096, "crc": "C58252A0"}, + "dd1.9": { "size": 2048, "crc": "F14A6FE1"}, + "dd1.11": { "size": 4096, "crc": "7B383983"}, + "136007.107": { "size": 4096, "crc": "A41BCE72"}, + "dd1.5b": { "size": 4096, "crc": "370EF9B4"}, + "dd1.6b": { "size": 4096, "crc": "361EEB71"}, + "136007.101": { "size": 4096, "crc": "B9198079"}, + "136007.102": { "size": 4096, "crc": "B2ACBE49"}, + "136007.103": { "size": 4096, "crc": "D6407B49"}, + "dd1.4b": { "size": 4096, "crc": "F4CEBC16"}, + "136007.109": { "size": 256, "crc": "8889DEB7"} + } + } + } + ], + "notes": { + "1": "This extraction requires MAME 2003/0.78 due to the NAMCO base ROMs." + } + } +} \ No newline at end of file diff --git a/src/gex/lib/tasks/impl/ags_galaga/__init__.py b/src/gex/lib/tasks/impl/ags_galaga/__init__.py new file mode 100644 index 0000000..43088b4 --- /dev/null +++ b/src/gex/lib/tasks/impl/ags_galaga/__init__.py @@ -0,0 +1,19 @@ +'''Implementation of ags_galaga: Namco Arcade Game Series: Galaga''' +import logging +from gex.lib.tasks.zipsplicetask import ZipSpliceTask +from gex.lib.tasks import helpers +from gex.lib.utils.blob import transforms + +logger = logging.getLogger('gextoolbox') + +class AGSGalagaTask(ZipSpliceTask): + '''Implements ags_galaga: Namco Arcade Game Series: Galaga''' + _task_name = "ags_galaga" + _title = "Namco Arcade Game Series: Galaga" + _details_markdown = ''' +Based on: https://github.com/farmerbb/RED-Project/blob/master/ROM%20Extraction/namco-ags-extract.sh + +These are pulled out of the plugin DLL. + ''' + _default_input_folder = helpers.gen_steam_app_default_folder("GALAGA") + _input_folder_desc = "AGS Galaga install folder" diff --git a/src/gex/lib/tasks/impl/ags_galaga/metadata.json b/src/gex/lib/tasks/impl/ags_galaga/metadata.json new file mode 100644 index 0000000..a0e4563 --- /dev/null +++ b/src/gex/lib/tasks/impl/ags_galaga/metadata.json @@ -0,0 +1,69 @@ +{ + "in": { + "files": { + "source": { + "rel_path": ["GALAGA_Data", "Plugins"], + "filename": "Release_1.dll", + "versions": { + "Steam": { + "size": 505344, + "crc": "772CE8A9" + } + } + } + } + }, + "out": { + "files": [ + { + "game": "Galaga", + "system": "Arcade", + "filename": "galaga.zip", + "status": "playable", + "notes": [1], + "zip_files": { + "prom-1.1d": {"start": "0x56710", "length": "0x100"}, + "prom-5.5n": {"start": "0x56810", "length": "0x20"}, + "prom-3.1c": {"start": "0x56830", "length": "0x100"}, + "prom-4.2n": {"start": "0x56930", "length": "0x100"}, + "gg1_11.4d": {"start": "0x56A30", "length": "0x1000"}, + "gg1_10.4f": {"start": "0x57A30", "length": "0x1000"}, + "gg1_9.4l": {"start": "0x58A30", "length": "0x1000"}, + "gg1_7b.2c": {"start": "0x64A00", "length": "0x1000"}, + "gg1_5b.3f": {"start": "0x65A00", "length": "0x1000"}, + "gg1_1b.3p": {"start": "0x66A00", "length": "0x1000"}, + "gg1_2b.3m": {"start": "0x67A00", "length": "0x1000"}, + "gg1_3.2m": {"start": "0x68A00", "length": "0x1000"}, + "gg1_4b.2l": {"start": "0x69A00", "length": "0x1000"}, + "prom-2.5c": {"type": "placeholder", "length": "0x100"}, + "51xx.bin": {"type": "placeholder", "length": "0x400"}, + "54xx.bin": {"type": "placeholder", "length": "0x400"} + }, + "verify": { + "type": "zip", + "entries": { + "prom-1.1d": {"size": 256, "crc": "7A2815B4"}, + "prom-5.5n": {"size": 32, "crc": "54603C6B"}, + "prom-3.1c": {"size": 256, "crc": "4A04BB6B"}, + "prom-4.2n": {"size": 256, "crc": "59B6EDAB"}, + "gg1_11.4d": {"size": 4096, "crc": "AD447C80"}, + "gg1_10.4f": {"size": 4096, "crc": "DD6F1AFC"}, + "gg1_9.4l": {"size": 4096, "crc": "58B2F47C"}, + "gg1_7b.2c": {"size": 4096, "crc": "D016686B"}, + "gg1_5b.3f": {"size": 4096, "crc": "BB5CAAE3"}, + "gg1_1b.3p": {"size": 4096, "crc": "AB036C9F"}, + "gg1_2b.3m": {"size": 4096, "crc": "D9232240"}, + "gg1_3.2m": {"size": 4096, "crc": "753CE503"}, + "gg1_4b.2l": {"size": 4096, "crc": "499FCC76"}, + "prom-2.5c": {"size": 256, "crc": "8889DEB7"}, + "51xx.bin": {"size": 1024, "crc": "ACDE76FC"}, + "54xx.bin": {"size": 1024, "crc": "ACDE76FC"} + } + } + } + ], + "notes": { + "1": "This extraction requires MAME 2017/1.39 due to the NAMCO base ROMs, which have placeholders." + } + } +} \ No newline at end of file diff --git a/src/gex/lib/tasks/impl/ags_mspacman/__init__.py b/src/gex/lib/tasks/impl/ags_mspacman/__init__.py new file mode 100644 index 0000000..274d538 --- /dev/null +++ b/src/gex/lib/tasks/impl/ags_mspacman/__init__.py @@ -0,0 +1,19 @@ +'''Implementation of ags_mspacman: Namco Arcade Game Series: Ms. Pac-Man''' +import logging +from gex.lib.tasks.zipsplicetask import ZipSpliceTask +from gex.lib.tasks import helpers +from gex.lib.utils.blob import transforms + +logger = logging.getLogger('gextoolbox') + +class AGSMsPacManTask(ZipSpliceTask): + '''Implements ags_mspacman: Namco Arcade Game Series: Ms. Pac-Man''' + _task_name = "ags_mspacman" + _title = "Namco Arcade Game Series: Ms. Pac-Man" + _details_markdown = ''' +Based on: https://github.com/farmerbb/RED-Project/blob/master/ROM%20Extraction/namco-ags-extract.sh + +These are pulled out of the plugin DLL, and is not yet a playable ROM. + ''' + _default_input_folder = helpers.gen_steam_app_default_folder("Ms. PAC-MAN") + _input_folder_desc = "AGS Ms. Pac-Man install folder" diff --git a/src/gex/lib/tasks/impl/ags_mspacman/metadata.json b/src/gex/lib/tasks/impl/ags_mspacman/metadata.json new file mode 100644 index 0000000..eff4f18 --- /dev/null +++ b/src/gex/lib/tasks/impl/ags_mspacman/metadata.json @@ -0,0 +1,67 @@ +{ + "in": { + "files": { + "source": { + "rel_path": ["Ms. PAC-MAN_Data", "Plugins"], + "filename": "Release_2.dll", + "versions": { + "Steam": { + "size": 250368, + "crc": "33F288DC" + } + } + } + } + }, + "out": { + "files": [ + { + "game": "Ms. Pac-Man", + "system": "Arcade", + "filename": "mspacmab.zip", + "status": "playable", + "notes": [], + "zip_files": { + "82s126.1m": { "start": "0x1AE30", "length": "0x100"}, + "82s123.7f": { "start": "0x1AF30", "length": "0x20"}, + "82s126.4a": { "start": "0x1AF50", "length": "0x100"}, + "5f": { "start": "0x1B050", "length": "0x1000"}, + "5e": { "start": "0x1D050", "length": "0x1000"}, + "boot1": { "start": "0x28C20", "length": "0x1000", + "patch": {"2": 0, "56": 195, "57": 155, "58": 31, "4087": 10, "4088": 237, "4089": 12, "4090": 20, "4091": 10, "4093": 8} + }, + "boot2": { "start": "0x29C20", "length": "0x1000", + "patch": {"3994": 33, "3995": 245, "3996": 237, "3997": 87, "3998": 183, "3999": 40, "4000": 4, "4001": 241, "4002": 195, "4003": 141, "4005": 241, "4006": 195, "4008": 48} + }, + "boot3": { "start": "0x2AC20", "length": "0x1000", + "patch": {"828": 86, "829": 0, "830": 0, "831": 0} + }, + "boot4": { "start": "0x2BC20", "length": "0x1000", + "patch": {"26": 0, "27": 0, "387": 237, "388": 71} + }, + "boot5": { "start": "0x30C20", "length": "0x1000"}, + "boot6": { "start": "0x31C20", "length": "0x1000"}, + "82s126.3m": { "type": "placeholder", "length": "0x100"} + }, + "verify": { + "type": "zip", + "entries": { + "82s126.1m": { "size": 256, "crc": "A9CC86BF"}, + "82s123.7f": { "size": 32, "crc": "2FC650BD"}, + "82s126.4a": { "size": 256, "crc": "3EB3A8E4"}, + "5f": { "size": 4096, "crc": "615AF909"}, + "5e": { "size": 4096, "crc": "5C281D01"}, + "boot1": { "size": 4096, "crc": "D16B31B7"}, + "boot2": { "size": 4096, "crc": "0D32DE5E"}, + "boot3": { "size": 4096, "crc": "1821EE0B"}, + "boot4": { "size": 4096, "crc": "165A9DD8"}, + "boot5": { "size": 4096, "crc": "8C3E6DE6"}, + "boot6": { "size": 4096, "crc": "368CB165"}, + "82s126.3m": { "size": 256, "crc": "0D968558"} + } + } + } + ], + "notes": {} + } +} \ No newline at end of file diff --git a/src/gex/lib/tasks/impl/ags_pacman/__init__.py b/src/gex/lib/tasks/impl/ags_pacman/__init__.py new file mode 100644 index 0000000..fa95874 --- /dev/null +++ b/src/gex/lib/tasks/impl/ags_pacman/__init__.py @@ -0,0 +1,19 @@ +'''Implementation of ags_pacman: Namco Arcade Game Series: Pac-Man''' +import logging +from gex.lib.tasks.zipsplicetask import ZipSpliceTask +from gex.lib.tasks import helpers +from gex.lib.utils.blob import transforms + +logger = logging.getLogger('gextoolbox') + +class AGSPacManTask(ZipSpliceTask): + '''Implements ags_pacman: Namco Arcade Game Series: Pac-Man''' + _task_name = "ags_pacman" + _title = "Namco Arcade Game Series: Pac-Man" + _details_markdown = ''' +Based on: https://github.com/farmerbb/RED-Project/blob/master/ROM%20Extraction/namco-ags-extract.sh + +These are pulled out of the plugin DLL. + ''' + _default_input_folder = helpers.gen_steam_app_default_folder("PAC-MAN") + _input_folder_desc = "AGS Pac-Man install folder" diff --git a/src/gex/lib/tasks/impl/ags_pacman/metadata.json b/src/gex/lib/tasks/impl/ags_pacman/metadata.json new file mode 100644 index 0000000..6f0dec4 --- /dev/null +++ b/src/gex/lib/tasks/impl/ags_pacman/metadata.json @@ -0,0 +1,55 @@ +{ + "in": { + "files": { + "source": { + "rel_path": ["PAC-MAN_Data", "Plugins"], + "filename": "Release_3.dll", + "versions": { + "Steam": { + "size": 394240, + "crc": "AA58DC77" + } + } + } + } + }, + "out": { + "files": [ + { + "game": "Pac-Man", + "system": "Arcade", + "filename": "pacman.zip", + "status": "playable", + "notes": [], + "zip_files": { + "82s126.1m": { "start": "0x1AA30", "length": "0x100"}, + "82s123.7f": { "start": "0x1AB30", "length": "0x20"}, + "82s126.4a": { "start": "0x1AB50", "length": "0x100"}, + "pacman.5f": { "start": "0x1AC50", "length": "0x1000"}, + "pacman.5e": { "start": "0x1C050", "length": "0x1000"}, + "pacman.6e": { "start": "0x28020", "length": "0x1000"}, + "pacman.6f": { "start": "0x29020", "length": "0x1000"}, + "pacman.6h": { "start": "0x2A020", "length": "0x1000"}, + "pacman.6j": { "start": "0x2B020", "length": "0x1000"}, + "82s126.3m": { "type": "placeholder", "length": "0x100"} + }, + "verify": { + "type": "zip", + "entries": { + "82s126.1m": {"size": 256, "crc": "A9CC86BF"}, + "82s123.7f": {"size": 32, "crc": "2FC650BD"}, + "82s126.4a": {"size": 256, "crc": "3EB3A8E4"}, + "pacman.5f": {"size": 4096, "crc": "958FEDF9"}, + "pacman.5e": {"size": 4096, "crc": "0C944964"}, + "pacman.6e": {"size": 4096, "crc": "C1E6AB10"}, + "pacman.6f": {"size": 4096, "crc": "1A6FB2D4"}, + "pacman.6h": {"size": 4096, "crc": "BCDD1BEB"}, + "pacman.6j": {"size": 4096, "crc": "817D94E3"}, + "82s126.3m": {"size": 256, "crc": "8889DEB7"} + } + } + } + ], + "notes": {} + } +} \ No newline at end of file diff --git a/src/gex/lib/tasks/impl/atarivault/__init__.py b/src/gex/lib/tasks/impl/atarivault/__init__.py index b37aaba..ea24749 100644 --- a/src/gex/lib/tasks/impl/atarivault/__init__.py +++ b/src/gex/lib/tasks/impl/atarivault/__init__.py @@ -1,8 +1,9 @@ '''Implementation of atarivault: Atari Vault''' import logging +import os from gex.lib.tasks.basetask import BaseTask from gex.lib.tasks import helpers -from gex.lib.tasks.impl.atarivault import atari2600, atari5200, prototype2600, mnetwork, arcade +from gex.lib.tasks.impl.atarivault import arcade logger = logging.getLogger('gextoolbox') @@ -49,41 +50,43 @@ class AtariVaultTask(BaseTask): } } - _out_file_list = [] - _out_file_list.extend(atari2600.get_game_list()) - _out_file_list.extend(atari5200.get_game_list()) - _out_file_list.extend(prototype2600.get_game_list()) - _out_file_list.extend(mnetwork.get_game_list()) - _out_file_list.extend(arcade.get_game_list()) - _out_file_list.append({ - 'filename': "N/A", - 'game': "Pong", - 'system': "Arcade", - "notes": [4], - 'status': "no-rom" - }) - - _out_file_notes = { - "1": "Arcade ROMs require MAME 2003.", - "2": "This ROM has a CRC mismatch, but appears to work fine.", - "3": "This Arcade ROM is currently non-functional - too small, etc.", - "4": "This title uses TTL logic and does not have an associated ROM.", - "5": "This ROM cannot be extracted.", - "6": "The sprites and/or tiles for this ROM have been converted to bitmaps." - } + def get_out_file_info(self): + '''Return a list of output files''' + return { + "files": self._metadata['out']['files'], + "notes": self._metadata['out']['notes'] + } def execute(self, in_dir, out_dir): if self._props.get('include-2600'): - atari2600.copy(in_dir, out_dir) + self.extract_console_set(in_dir, out_dir, '2600') if self._props.get('include-5200'): - atari5200.copy(in_dir, out_dir) + self.extract_console_set(in_dir, out_dir, '5200') if self._props.get('include-prototype'): - prototype2600.copy(in_dir, out_dir) + self.extract_console_set(in_dir, out_dir, 'prototype') if self._props.get('include-mnetwork'): - mnetwork.copy(in_dir, out_dir) + self.extract_console_set(in_dir, out_dir, 'mnetwork') if self._props.get('include-arcade'): - arcade.extract(in_dir, out_dir) - if self._props.get('include-arcade-partials'): - arcade.extract_partials(in_dir, out_dir) + include_partials = self._props.get('include-arcade-partials') + arcade.extract(in_dir, out_dir, self, include_partials) logger.info("Processing complete.") + + + def extract_console_set(self, in_dir, out_dir, game_set): + '''Extract Atari Console ROMs''' + + for file_metadata in self._metadata['in']['files'].values(): + resolved_file = self.read_datafile(in_dir, file_metadata) + if 'copy_to' in file_metadata: + out_file_entries = [x for x in self._metadata['out']['files'] if x['game'] == file_metadata['copy_to'] and x['set'] == game_set] + # Set isn't used in verification. Make 2600/5200/Arcade rom names unique, but keep the set match here + if len(out_file_entries) == 1: + out_file_entry = out_file_entries[0] + logger.info(f"Copying {out_file_entry['game']}...") + filename = out_file_entry['filename'] + _ = self.verify_out_file(filename, resolved_file['contents']) + out_path = os.path.join(out_dir, filename) + with open(out_path, "wb") as out_file: + out_file.write(resolved_file['contents']) + diff --git a/src/gex/lib/tasks/impl/atarivault/arcade.py b/src/gex/lib/tasks/impl/atarivault/arcade.py index 6ac43d9..bd8bdc3 100644 --- a/src/gex/lib/tasks/impl/atarivault/arcade.py +++ b/src/gex/lib/tasks/impl/atarivault/arcade.py @@ -7,465 +7,51 @@ logger = logging.getLogger('gextoolbox') -games = [ - { - "name": "Asteroids", - "files": [ - "Asteroids.bin" - ], - "mame_name": "asteroid", - "split": [ - "035145.02", - "035144.02", - "035143.02", - "035127.02" - ], - "status": "good" - }, - { - "name": "Asteroids Deluxe", - "files": [ - "Asteroids Deluxe.bin" - ], - "mame_name": "astdelux", - "split": [ - "036430.02", - "036431.02", - "036432.02", - "036433.03", - "036800.02", - "036799.01" - ], - "status": "good" - }, - { - "name": "Black Widow", - "files": [ - "Black Widow.bin" - ], - "mame_name": "bwidow", - "truncate": 38912, - "split": { - "136017.107": 2048, - "136017.108": 4096, - "136017.109": 4096, - "136017.110": 4096, - "136017.101": 4096, - "136017.102": 4096, - "136017.103": 4096, - "136017.104": 4096, - "136017.105": 4096, - "136017.106": 4096 - }, - "status": "playable", - "notes": [2] - }, - { - "name": "Canyon Bomber", - "files": [ - "CanyonBomber.bin", - "CanyonBomberSprites.bmp", - "CanyonBomberTiles.bmp" - ], - "mame_name": "canyon", - # "handler": "_handle_canyon", - "status": "partial", - "notes": [6] - }, - { - "name": "Centipede", - "files": [ - "Centipede.bin", - "Centipede.bmp" - ], - "mame_name": "centiped", - "status": "partial", - "notes": [6] - }, - { - "name": "Crystal Castles", - "files": [ - "Crystal Castles.bin", - "Crystal Castles.bmp" - ], - "mame_name": "ccastles", - "status": "partial" - }, - { - "name": "Gravitar", - "files": [ - "Gravitar.bin" - ], - "mame_name": "gravitar", - "truncate": 38912, - "split": { - "136010.210": 2048, - "136010.207": 4096, - "136010.208": 4096, - "136010.309": 4096, - "136010.301": 4096, - "136010.302": 4096, - "136010.303": 4096, - "136010.304": 4096, - "136010.305": 4096, - "136010.306": 4096 - }, - "status": "good", - "notes": [] - }, - { - "name": "Liberator", - "files": [ - "Liberator.bin", - "Liberator.bmp", - "Liberator Projection.bin" - ], - "mame_name": "liberatr", - "status": "partial", - "notes": [6] - }, - { - "name": "Lunar Lander", - "files": [ - "Lunar Lander.bin" - ], - "mame_name": "llander", - "split": [ - "034599.01", - "034598.01", - "034571.02", - "034572.02", - "034597.01", - "034570.01", - "034569.02" - ], - "status": "playable", - "notes": [2] - }, - { - "name": "Major Havoc", - "files": [ - "Major Havoc alpha banks.bin", - "Major Havoc gamma.bin", - "Major Havoc vector banks.bin", - "Major Havoc.bin" - ], - "status": "good", - "mame_name": "mhavoc", - "handler": "_handle_mhavoc", - "notes": [] - }, - { - "name": "Millipede", - "files": [ - "Millipede.bin", - "Millipede.bmp" - ], - "mame_name": "milliped", - "status": "partial", - "notes": [6] - }, - { - "name": "Missile Command", - "files": [ - "Missile Command.bin" - ], - "mame_name": "missile", - "split": [ - "035820.02", - "035821.02", - "035822.02", - "035823.02", - "035824.02", - "035825.02" - ], - "status": "good" - }, - { - "name": "Red Baron", - "files": [ - "Red Baron.bin" - ], - "mame_name": "redbaron", - "handler": "_handle_redbaron", - "status": "good" - }, - { - "name": "Space Duel", - "files": [ - "Space Duel.bin" - ], - "mame_name": "spacduel", - "split": { - "136006.106": 2048, - "136006.107": 4096, - "136006.201": 4096, - "136006.102": 4096, - "136006.103": 4096, - "136006.104": 4096, - "136006.105": 4096 - }, - "status": "good" - }, - { - "name": "Sprint2", - "files": [ - "Sprint2.bin", - "Sprint2Sprites.bmp", - "Sprint2Tiles.bmp" - ], - "mame_name": "sprint2", - "handler": "_handle_sprint2", - "status": "good", - "notes": [6] - }, - { - "name": "Super Breakout", - "files": [ - "Super Breakout.bin", - "Super Breakout vector.bmp", - "Super Breakout.bmp" - ], - "mame_name": "sbrkout", - "status": "partial", - "notes": [6] - }, - { - "name": "Tempest", - "files": [ - "Tempest.bin" - ], - "mame_name": "tempest3", - "split": [ - "237.002", - "136.002", - "235.002", - "134.002", - "133.002", - "138.002" - ], - "status": "good" - }, - { - "name": "Warlords", - "files": [ - "Warlords.bin", - "Warlords Background.bmp", - "Warlords.bmp" - ], - "mame_name": "warlords", - "status": "partial", - "notes": [6] - }, - { - "name": "Avalanche", - "files": [ - "Avalanche.bin" - ], - "status": "good", - "mame_name": "avalnche", - "handler": "_handle_avalnche" - }, - { - "name": "Atari Baseball", - "files": [ - "AtariBaseball.bin", - "AtariBaseballTiles1.bmp", - "AtariBaseballTiles2.bmp" - ], - "mame_name": "abaseb", - "status": "partial", - "notes": [6] - }, - { - "name": "Atari Basketball", - "files": [ - "AtariBasketball.bin", - "AtariBasketballTiles.bmp", - "AtariBasketballSprites.bmp" - ], - "mame_name": "bsktball", - "status": "partial" - }, - { - "name": "Destroyer", - "files": [ - "Destroyer.bin", - "DestroyerSprites1.bmp", - "DestroyerSprites2.bmp", - "DestroyerTiles.bmp", - "DestroyerWaves.bmp" - ], - "mame_name": "destroyr1", - "status": "partial" - }, - { - "name": "Dominos", - "files": [ - "Dominos.bin", - "DominosTiles.bmp" - ], - "mame_name": "dominos", - "status": "partial", - "notes": [6] - }, - { - "name": "Fire Truck", - "files": [ - "FireTruck.bin", - "FireTruckSprites1.bmp", - "FireTruckSprites2.bmp", - "FireTruckTiles1.bmp", - "FireTruckTiles2.bmp" - ], - "mame_name": "firetrk", - "status": "partial", - "notes": [6] - }, - { - "name": "Atari Football", - "files": [ - "AtariFootball.bin", - "AtariFootballTiles1.bmp", - "AtariFootballTiles2.bmp" - ], - "mame_name": "atarifb", - "status": "partial", - "notes": [6] - }, - { - "name": "Maze Invaders", - "files": [ - "MazeInvaders.bin", - "MazeInvaders.bmp" - ], - "mame_name": "mazeinv", - "status": "partial", - "notes": [6] - }, - { - "name": "Monte Carlo", - "files": [ - "MonteCarlo.bin", - "MonteCarloColors.bin", - "MonteCarloSprites1.bmp", - "MonteCarloSprites2.bmp", - "MonteCarloTiles1.bmp", - "MonteCarloTiles2.bmp" - ], - "mame_name": "montecar", - "handler": "_handle_montecar", - "status": "partial", - "notes": [6] - }, - { - "name": "Pool Shark", - "files": [ - "Poolshark.bin", - "PoolsharkSprites.bmp", - "PoolsharkTiles.bmp" - ], - "mame_name": "poolshrk", - "status": "partial", - "notes": [6] - }, - { - "name": "Sky Diver", - "files": [ - "SkydiverROM.bin", - "SkydiverSprites.bmp", - "SkydiverTiles.bmp" - ], - "mame_name": "skydiver", - "status": "partial", - "notes": [6] - }, - { - "name": "Atari Soccer", - "files": [ - "AtariSoccer.bin", - "AtariSoccerSprites.bmp", - "AtariSoccerTiles1.bmp", - "AtariSoccerTiles2.bmp" - ], - "mame_name": "soccer", - "status": "partial", - "notes": [6] - }, - { - "name": "Super Bug", - "files": [ - "SuperBug.bin", - "SuperBugSprites.bmp", - "SuperBugTiles1.bmp", - "SuperBugTiles2.bmp" - ], - "mame_name": "superbug", - "status": "partial", - "notes": [6] - } -] - - -def get_game_list(): - '''Transform the game map for documentation''' - return map(lambda x: { - 'filename': f"{x['mame_name']}{'-partial' if x['status'] == 'partial' else ''}.zip", - 'game': x['name'], - 'system': "Arcade", - 'status': x['status'], - "notes": [[1] if 'mame_name' in x else None] + [[5] if 'unextractable' in x and x['unextractable'] else None] + [x['notes'] if 'notes' in x else None]}, games) - -def _handle_mhavoc(in_dir, game_desc): +def _handle_mhavoc(in_files, game_desc): zip_files = {} + # Major Havoc.bin - with open(os.path.join(in_dir, "Major Havoc.bin"), "rb") as curr_file: - contents = bytearray(curr_file.read()) - chunks = transforms.custom_split(contents, [0x1000, 0x4000, 0x4000]) - zip_files['136025.210'] = transforms.pad(chunks[0], 0x2000) - zip_files['136025.216'] = chunks[1] - zip_files['136025.217'] = chunks[2] + contents = in_files.get('Major Havoc.bin')['contents'] + chunks = transforms.custom_split(contents, [0x1000, 0x4000, 0x4000]) + zip_files['136025.210'] = transforms.pad(chunks[0], 0x2000) + zip_files['136025.216'] = chunks[1] + zip_files['136025.217'] = chunks[2] # Major Havoc alpha banks.bin - with open(os.path.join(in_dir, "Major Havoc alpha banks.bin"), "rb") as curr_file: - contents = bytearray(curr_file.read()) - chunks = transforms.equal_split(contents, 2) - zip_files['136025.215'] = chunks[0] - zip_files['136025.318'] = chunks[1] + contents = in_files.get('Major Havoc alpha banks.bin')['contents'] + chunks = transforms.equal_split(contents, 2) + zip_files['136025.215'] = chunks[0] + zip_files['136025.318'] = chunks[1] # Major Havoc gamma.bin - with open(os.path.join(in_dir, "Major Havoc gamma.bin"), "rb") as curr_file: - contents = bytearray(curr_file.read()) - zip_files['136025.108'] = contents + contents = in_files.get('Major Havoc gamma.bin')['contents'] + zip_files['136025.108'] = contents # Major Havoc vector banks.bin - with open(os.path.join(in_dir, "Major Havoc vector banks.bin"), "rb") as curr_file: - contents = bytearray(curr_file.read()) - chunks = transforms.equal_split(contents, 2) - zip_files['136025.106'] = chunks[0] - zip_files['136025.107'] = chunks[1] + contents = in_files.get('Major Havoc vector banks.bin')['contents'] + chunks = transforms.equal_split(contents, 2) + zip_files['136025.106'] = chunks[0] + zip_files['136025.107'] = chunks[1] return [{ - 'filename': f"{game_desc['mame_name']}.zip", + 'filename': game_desc['filename'], 'contents': helpers.build_zip(zip_files) }] -def _handle_montecar(in_dir, game_desc): +def _handle_montecar(in_files, game_desc): zip_files = {} # MonteCarlo.bin - with open(os.path.join(in_dir, "MonteCarlo.bin"), "rb") as curr_file: - contents = bytearray(curr_file.read()) - chunks = transforms.equal_split(contents, 4) - zip_files['35763-01.h1'] = chunks[0] - zip_files['35763-01.f1'] = chunks[1] - zip_files['35763-01.d1'] = chunks[2] - zip_files['35763-01.c1'] = chunks[3] + contents = in_files.get('MonteCarlo.bin')['contents'] + chunks = transforms.equal_split(contents, 4) + zip_files['35763-01.h1'] = chunks[0] + zip_files['35763-01.f1'] = chunks[1] + zip_files['35763-01.d1'] = chunks[2] + zip_files['35763-01.c1'] = chunks[3] # MonteCarloColors.bin - with open(os.path.join(in_dir, "MonteCarloColors.bin"), "rb") as curr_file: - contents = bytearray(curr_file.read()) - zip_files['35785-01.e7'] = contents + contents = in_files.get('MonteCarloColors.bin')['contents'] + zip_files['35785-01.e7'] = contents # Bitmaps bitmaps = [ @@ -475,260 +61,248 @@ def _handle_montecar(in_dir, game_desc): "MonteCarloTiles2.bmp" ] for bitmap_file in bitmaps: - with open(os.path.join(in_dir, bitmap_file), "rb") as curr_file: - contents = bytearray(curr_file.read()) - zip_files[bitmap_file] = contents + contents = in_files.get(bitmap_file)['contents'] + zip_files[bitmap_file] = contents return [{ - 'filename': f"{game_desc['mame_name']}-partial.zip", + 'filename': game_desc['filename'], 'contents': helpers.build_zip(zip_files) }] -def _handle_redbaron(in_dir, game_desc): +def _handle_redbaron(in_files, game_desc): zip_files = {} # Red Baron.bin - with open(os.path.join(in_dir, "Red Baron.bin"), "rb") as curr_file: - contents = bytearray(curr_file.read()) - chunks = transforms.equal_split(contents, 9) - zip_files['35763-01.h1'] = chunks[0] - - - zip_files["037587.01"] = transforms.merge([chunks[0] + chunks[2]]) - zip_files["037000.01e"] = chunks[1] - zip_files["036998.01e"] = chunks[3] - zip_files["036997.01e"] = chunks[4] - zip_files["036996.01e"] = chunks[5] - zip_files["036995.01e"] = chunks[6] - zip_files["037006.01e"] = chunks[7] - zip_files["037007.01e"] = chunks[8] + contents = in_files.get('Red Baron.bin')['contents'] + chunks = transforms.equal_split(contents, 9) + zip_files['35763-01.h1'] = chunks[0] + + zip_files["037587.01"] = transforms.merge([chunks[0] + chunks[2]]) + zip_files["037000.01e"] = chunks[1] + zip_files["036998.01e"] = chunks[3] + zip_files["036997.01e"] = chunks[4] + zip_files["036996.01e"] = chunks[5] + zip_files["036995.01e"] = chunks[6] + zip_files["037006.01e"] = chunks[7] + zip_files["037007.01e"] = chunks[8] return [{ - 'filename': f"{game_desc['mame_name']}.zip", + 'filename': game_desc['filename'], 'contents': helpers.build_zip(zip_files) }] -def _handle_sprint2(in_dir, game_desc): +def _handle_sprint2(in_files, game_desc): zip_files = {} # Sprint2.bin - with open(os.path.join(in_dir, "Sprint2.bin"), "rb") as curr_file: - contents = bytearray(curr_file.read()) - chunks = transforms.equal_split(contents, 4) - zip_files['6290-01.b1'] = chunks[0] - zip_files['6291-01.c1'] = chunks[1] - zip_files['6404.d1'] = chunks[2] - zip_files['6405.e1'] = chunks[3] + contents = in_files.get('Sprint2.bin')['contents'] + chunks = transforms.equal_split(contents, 4) + zip_files['6290-01.b1'] = chunks[0] + zip_files['6291-01.c1'] = chunks[1] + zip_files['6404.d1'] = chunks[2] + zip_files['6405.e1'] = chunks[3] # Sprint2Sprites.bmp - with open(os.path.join(in_dir, "Sprint2Sprites.bmp"), "rb") as curr_file: - contents = bytearray(curr_file.read()) - contents = gfx_rebuilder.reverse_bmp(contents) - sprint2_car_layout = { - 'width': 16, - 'height': 8, - 'total': 32, - 'planes': 1, - 'planeoffset': [0], - 'xoffset': [0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0, - 0xf, 0xe, 0xd, 0xc, 0xb, 0xa, 0x9, 0x8], - 'yoffset': [0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70], - 'charincrement': 0x80 - } - contents = gfx_rebuilder.reencode_gfx(contents, sprint2_car_layout) - chunks = transforms.deinterleave_nibble(contents, 2) - zip_files['6399-01.j6'] = chunks[0] - zip_files['6398-01.k6'] = chunks[1] + contents = in_files.get('Sprint2Sprites.bmp')['contents'] + contents = gfx_rebuilder.reverse_bmp(contents) + sprint2_car_layout = { + 'width': 16, + 'height': 8, + 'total': 32, + 'planes': 1, + 'planeoffset': [0], + 'xoffset': [0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0, + 0xf, 0xe, 0xd, 0xc, 0xb, 0xa, 0x9, 0x8], + 'yoffset': [0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70], + 'charincrement': 0x80 + } + contents = gfx_rebuilder.reencode_gfx(contents, sprint2_car_layout) + chunks = transforms.deinterleave_nibble(contents, 2) + zip_files['6399-01.j6'] = chunks[0] + zip_files['6398-01.k6'] = chunks[1] # Sprint2Tiles.bmp - with open(os.path.join(in_dir, "Sprint2Tiles.bmp"), "rb") as curr_file: - contents = bytearray(curr_file.read()) - contents = gfx_rebuilder.reverse_bmp(contents) - sprint2_tile_layout = { - 'width': 8, - 'height': 8, - 'total': 64, - 'planes': 1, - 'planeoffset': [0], - 'xoffset': [0, 1, 2, 3, 4, 5, 6, 7], - 'yoffset': [0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38], - 'charincrement': 0x40 - } - contents = gfx_rebuilder.reencode_gfx(contents, sprint2_tile_layout) - chunks = transforms.deinterleave_nibble(contents, 2) - zip_files['6396-01.p4'] = chunks[0] - zip_files['6397-01.r4'] = chunks[1] - - zip_files['6400-01.m2'] = bytearray(0x100) - zip_files['6401-01.e2'] = bytearray(0x20) + contents = in_files.get('Sprint2Tiles.bmp')['contents'] + contents = gfx_rebuilder.reverse_bmp(contents) + sprint2_tile_layout = { + 'width': 8, + 'height': 8, + 'total': 64, + 'planes': 1, + 'planeoffset': [0], + 'xoffset': [0, 1, 2, 3, 4, 5, 6, 7], + 'yoffset': [0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38], + 'charincrement': 0x40 + } + contents = gfx_rebuilder.reencode_gfx(contents, sprint2_tile_layout) + chunks = transforms.deinterleave_nibble(contents, 2) + zip_files['6396-01.p4'] = chunks[0] + zip_files['6397-01.r4'] = chunks[1] + + zip_files['6400-01.m2'] = bytearray(0x100) + zip_files['6401-01.e2'] = bytearray(0x20) return [{ - 'filename': f"{game_desc['mame_name']}.zip", + 'filename': game_desc['filename'], 'contents': helpers.build_zip(zip_files) }] -# def _handle_canyon(in_dir, game_desc): +# def _handle_canyon(in_files, game_desc): # zip_files = {} # # CanyonBomber.bin -# with open(os.path.join(in_dir, "CanyonBomber.bin"), "rb") as curr_file: -# contents = bytearray(curr_file.read()) -# chunks = transforms.custom_split(contents, [1024, 1024, 2048]) -# nib_chunks = transforms.deinterleave_nibble(chunks[0], 2) -# zip_files['9503-01.p1'] = nib_chunks[0] -# zip_files['9499-01.j1'] = nib_chunks[1] -# zip_files['9496-01.d1'] = chunks[2] +# contents = in_files.get('CanyonBomber.bin')['contents'] +# chunks = transforms.custom_split(contents, [1024, 1024, 2048]) +# nib_chunks = transforms.deinterleave_nibble(chunks[0], 2) +# zip_files['9503-01.p1'] = nib_chunks[0] +# zip_files['9499-01.j1'] = nib_chunks[1] +# zip_files['9496-01.d1'] = chunks[2] # # CanyonBomberSprites.bmp -# with open(os.path.join(in_dir, "CanyonBomberSprites.bmp"), "rb") as curr_file: -# contents = bytearray(curr_file.read()) -# contents = gfx_rebuilder.reverse_bmp(contents) -# _SPRITE_LAYOUT = { -# 'width': 32, -# 'height': 16, -# 'total': 4, -# 'planes': 1, -# 'planeoffset': [0], -# 'xoffset': [0x007, 0x006, 0x005, 0x004, 0x003, 0x002, 0x001, 0x000, -# 0x00F, 0x00E, 0x00D, 0x00C, 0x00B, 0x00A, 0x009, 0x008, -# 0x107, 0x106, 0x105, 0x104, 0x103, 0x102, 0x101, 0x100, -# 0x10F, 0x10E, 0x10D, 0x10C, 0x10B, 0x10A, 0x109, 0x108], -# 'yoffset': [0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, -# 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0], -# 'charincrement': 0x200 -# } -# contents = gfx_rebuilder.reencode_gfx(contents, _SPRITE_LAYOUT) -# chunks = transforms.deinterleave_nibble(contents, 2) -# zip_files['9505-01.n5'] = chunks[0] -# zip_files['9506-01.m5'] = chunks[1] +# contents = in_files.get('CanyonBomberSprites.bmp')['contents'] +# contents = gfx_rebuilder.reverse_bmp(contents) +# _SPRITE_LAYOUT = { +# 'width': 32, +# 'height': 16, +# 'total': 4, +# 'planes': 1, +# 'planeoffset': [0], +# 'xoffset': [0x007, 0x006, 0x005, 0x004, 0x003, 0x002, 0x001, 0x000, +# 0x00F, 0x00E, 0x00D, 0x00C, 0x00B, 0x00A, 0x009, 0x008, +# 0x107, 0x106, 0x105, 0x104, 0x103, 0x102, 0x101, 0x100, +# 0x10F, 0x10E, 0x10D, 0x10C, 0x10B, 0x10A, 0x109, 0x108], +# 'yoffset': [0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, +# 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0], +# 'charincrement': 0x200 +# } +# contents = gfx_rebuilder.reencode_gfx(contents, _SPRITE_LAYOUT) +# chunks = transforms.deinterleave_nibble(contents, 2) +# zip_files['9505-01.n5'] = chunks[0] +# zip_files['9506-01.m5'] = chunks[1] # # CanyonBomberTiles.bmp # # Something is wrong with the math on this one, # # and I think it's a discrepancy vs. the mame tile layout -# with open(os.path.join(in_dir, "CanyonBomberTiles.bmp"), "rb") as curr_file: -# contents = bytearray(curr_file.read()) -# contents = gfx_rebuilder.reverse_bmp(contents) -# zip_files['tiles_temp'] = contents -# _TILE_LAYOUT = { -# 'width': 8, -# 'height': 8, -# 'total': 64, -# 'planes': 1, -# 'planeoffset': [0], -# 'xoffset': [4, 5, 6, 7, 0, 1, 2, 3], -# 'yoffset': [0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38], -# 'charincrement': 0x80 -# } -# contents = gfx_rebuilder.reencode_gfx(contents, _TILE_LAYOUT) -# zip_files['9492-01.n8'] = contents +# contents = in_files.get('CanyonBomberTiles.bmp')['contents'] +# contents = gfx_rebuilder.reverse_bmp(contents) +# zip_files['tiles_temp'] = contents +# _TILE_LAYOUT = { +# 'width': 8, +# 'height': 8, +# 'total': 64, +# 'planes': 1, +# 'planeoffset': [0], +# 'xoffset': [4, 5, 6, 7, 0, 1, 2, 3], +# 'yoffset': [0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38], +# 'charincrement': 0x80 +# } +# contents = gfx_rebuilder.reencode_gfx(contents, _TILE_LAYOUT) +# zip_files['9492-01.n8'] = contents # return [{ # 'filename': f"{game_desc['mame_name']}.zip", # 'contents': helpers.build_zip(zip_files) # }] -def _handle_avalnche(in_dir, game_desc): +def _handle_avalnche(in_files, game_desc): # Avalanche.bin - with open(os.path.join(in_dir, "Avalanche.bin"), "rb") as curr_file: - contents = bytearray(curr_file.read()) - - chunks = transforms.equal_split(contents, 3) - new_chunks = [] - for chunk in chunks: - new_chunks.extend(transforms.deinterleave_nibble(chunk, 2)) - - filenames = [ - "30612.d2", - "30615.d3", - "30613.e2", - "30616.e3", - "30611.c2", - "30614.c3", - ] - zip_files = dict(zip(filenames, new_chunks)) + contents = in_files.get('Avalanche.bin')['contents'] + chunks = transforms.equal_split(contents, 3) + new_chunks = [] + for chunk in chunks: + new_chunks.extend(transforms.deinterleave_nibble(chunk, 2)) + + filenames = [ + "30612.d2", + "30615.d3", + "30613.e2", + "30616.e3", + "30611.c2", + "30614.c3", + ] + zip_files = dict(zip(filenames, new_chunks)) return [{ - 'filename': f"{game_desc['mame_name']}.zip", + 'filename': game_desc['filename'], 'contents': helpers.build_zip(zip_files) }] -def _handle_standard(in_dir, game_desc): +def _handle_standard(in_files, game_desc): out_files = [] - with open(os.path.join(in_dir, game_desc['files'][0]), "rb") as curr_file: - contents = bytearray(curr_file.read()) - - # Truncate - if 'truncate' in game_desc: - contents = transforms.truncate(contents, game_desc['truncate']) - - # Split - split_data = game_desc['split'] - if isinstance(split_data, list): - chunks = transforms.equal_split(contents, len(game_desc['split'])) - filenames = split_data - elif isinstance(split_data, dict): - filenames = list(split_data.keys()) - sizes = list(split_data.values()) - chunks = transforms.custom_split(contents, sizes) - else: - logger.error("Invalid split type!") - return [] - out_files.append({ - 'filename': f"{game_desc['mame_name']}.zip", - 'contents': helpers.build_zip(dict(zip(filenames, chunks))) - }) - return out_files - -def extract_partials(in_dir, out_dir): - '''Extract Partial Atari Arcade ROMs''' - rom_path = os.path.join(in_dir, "AtariVault_Data", - "StreamingAssets", "FOCAL_Emulator") - - output_files = [] - funcs = globals() - for game in games: - if game['status'] == 'partial': - logger.info(f"Copying partially extracted {game['name']}...") - if 'handler' in game: - handler_func = funcs[game['handler']] - output_files += handler_func(rom_path, game) - else: - zip_files = {} - for filename in game['files']: - with open(os.path.join(rom_path, filename), "rb") as curr_file: - contents = bytearray(curr_file.read()) - zip_files[filename] = contents - - out_path = os.path.join(out_dir, f"{game['mame_name']}-partial.zip") - with open(out_path, "wb") as out_file: - out_file.write(helpers.build_zip(zip_files)) - - for output_file in output_files: - logger.info(f"Writing {output_file['filename']}...") - out_path = os.path.join(out_dir, output_file['filename']) - with open(out_path, "wb") as out_file: - out_file.write(output_file['contents']) + contents = list(in_files.values())[0]['contents'] + + # Truncate + if 'truncate' in game_desc: + contents = transforms.truncate(contents, game_desc['truncate']) + + # Split + split_data = game_desc['split'] + if isinstance(split_data, list): + chunks = transforms.equal_split(contents, len(game_desc['split'])) + filenames = split_data + elif isinstance(split_data, dict): + filenames = list(split_data.keys()) + sizes = list(split_data.values()) + chunks = transforms.custom_split(contents, sizes) + else: + logger.error("Invalid split type!") + return [] + out_files.append({ + 'filename': game_desc['filename'], + 'contents': helpers.build_zip(dict(zip(filenames, chunks))) + }) + return out_files -def extract(in_dir, out_dir): +def extract(in_dir, out_dir, class_ref, include_partials): '''Extract Atari Arcade ROMs''' - rom_path = os.path.join(in_dir, "AtariVault_Data", - "StreamingAssets", "FOCAL_Emulator") - - output_files = [] funcs = globals() - for game in games: - if game['status'] != 'partial': - logger.info(f"Extracting {game['name']}...") - if 'handler' in game: - handler_func = funcs[game['handler']] + for game in class_ref._metadata['out']['files']: + if game['set'] == 'Arcade' and game['status'] != 'no-rom': + is_partial = game['status'] == 'partial' + if is_partial and not include_partials: + continue + + logger.info(f"Reading {game['game']}...") + + # Read the input files + in_files = {} + for in_file_ref in game['in_files']: + file_metadata = class_ref._metadata['in']['files'].get(in_file_ref) + datafile = class_ref.read_datafile(in_dir, file_metadata) + in_files[datafile['name']] = { + "contents": datafile['contents'], + "metadata": file_metadata + } + + if is_partial: + logger.info(f"Copying partially extracted {game['game']}...") + + if 'handler' in game: + handler_func = funcs[game['handler']] + output_files = handler_func(in_files, game) + else: + zip_files = {} + for filename in game['in_files']: + zip_files[filename] = in_files[filename]['contents'] + + output_files = [{ + 'filename': game['filename'], + 'contents': helpers.build_zip(zip_files) + }] else: - handler_func = _handle_standard - output_files += handler_func(rom_path, game) - logger.info("Saving games...") - for output_file in output_files: - logger.info(f"Writing {output_file['filename']}...") - out_path = os.path.join(out_dir, output_file['filename']) - with open(out_path, "wb") as out_file: - out_file.write(output_file['contents']) + logger.info(f"Extracting {game['game']}...") + if 'handler' in game: + handler_func = funcs[game['handler']] + else: + handler_func = _handle_standard + output_files = handler_func(in_files, game) + + for output_file in output_files: + filename = output_file['filename'] + logger.info(f"Writing {game['game']} to {filename}...") + _ = class_ref.verify_out_file(filename, output_file['contents']) + out_path = os.path.join(out_dir, filename) + with open(out_path, "wb") as out_file: + out_file.write(output_file['contents']) diff --git a/src/gex/lib/tasks/impl/atarivault/atari2600.py b/src/gex/lib/tasks/impl/atarivault/atari2600.py deleted file mode 100644 index bc09862..0000000 --- a/src/gex/lib/tasks/impl/atarivault/atari2600.py +++ /dev/null @@ -1,143 +0,0 @@ -'''Extraction code for Atari 2600 ROMs''' -import glob -import logging -import os -import shutil - -logger = logging.getLogger('gextoolbox') - - -game_name_map = { - '3d_tic.bin': '3-D Tic-Tac-Toe', - 'advnture.bin': 'Adventure', - 'airseabt.bin': 'Air-Sea Battle', - 'asteroid.bin': 'Asteroids', - 'backgamn.bin': 'Backgammon', - 'basmath.bin': 'Basic Math', - 'basketbl.bin': 'Basketball', - 'black_j.bin': 'Blackjack', - 'Bowling.bin': 'Bowling', - 'braingms.bin': 'Brain Games', - 'breakout.bin': 'Breakout', - 'canyonb.bin': 'Canyon Bomber', - 'casino.bin': 'Casino', - 'centiped.bin': 'Centipede', - 'pelesocr.bin': 'Championship Soccer', - 'vidcheck.bin': 'Checkers', - 'vidchess.bin': 'Chess', - 'circatri.bin': 'Circus Atari', - 'codebrk.bin': 'Codebreaker', - 'combat.bin': 'Combat', - 'combat2.bin': 'Combat 2', - 'concentr.bin': 'Concentration', - 'cryscast.bin': 'Crystal Castles', - 'demondim.bin': 'Demons to Diamonds', - 'dsrtfalc.bin': 'Desert Falcon', - 'dodge_em.bin': 'Dodge Em', - 'doubdunk.bin': 'Double Dunk', - 'fatalrun.bin': 'Fatal Run', - 'flagcap.bin': 'Flag Capture', - 'football.bin': 'Football', - 'golf.bin': 'Golf', - 'grav2600.bin': 'Gravitar', - 'hangman.bin': 'Hangman', - 'haunthse.bin': 'Haunted House', - 'homerun.bin': 'Home Run', - 'human_cb.bin': 'Human Cannonball', - 'mazecrz.bin': 'Maze Craze', - 'milliped.bin': 'Millipede', - 'min_golf.bin': 'Miniature Golf', - 'misscomm.bin': 'Missile Command', - 'nightdrv.bin': 'Night Driver', - 'ofthwall.bin': 'Off the Wall', - 'outlaw.bin': 'Outlaw', - 'quadrun.bin': 'Quadrun', - 'indy500.bin': 'Race', - 'radarlok.bin': 'Radar Lock', - 'rs_baseb.bin': 'RealSports Baseball', - 'rsbasket.bin': 'RealSports Basketball', - 'rsboxing.bin': 'RealSports Boxing', - 'rs_footb.bin': 'RealSports Football', - 'rssoccer.bin': 'RealSports Soccer', - 'rstennis.bin': 'RealSports Tennis', - 'rs_volly.bin': 'RealSports Volleyball', - 'ret2hh.bin': 'Return to Haunted House', - 'SaveMary_NTSC.bin': 'Save Mary', - 'secretq.bin': 'Secret Quest', - 'sentinel.bin': 'Sentinel', - 'skydiver.bin': 'Sky Diver', - 'slotmach.bin': 'Slot Machine', - 'slotrace.bin': 'Slot Racers', - 'spacewar.bin': 'Space War', - 'sprntmas.bin': 'Sprint Master', - 'starraid.bin': 'Star Raiders', - 'starship.bin': 'Star Ship', - 'steplchs.bin': 'Steeplechase', - 'stlrtrak.bin': 'Stellar Track', - 'stunt.bin': 'Stunt Cycle', - 'streetrc.bin': 'Street Racer', - 'subcmdr.bin': 'Submarine Commander', - 'sprbaseb.bin': 'Super Baseball', - 'superbrk.bin': 'Super Breakout', - 'sprfootb.bin': 'Super Football', - 'surround.bin': 'Surround', - 'sq_earth.bin': 'Sword Quest Earthworld', - 'sq_fire.bin': 'Sword Quest Fireworld', - 'sq_water.bin': 'Sword Quest Waterworld', - 'temp2600.bin': 'Tempest', - 'vidcube.bin': 'Video Cube', - 'vid_olym.bin': 'Video Olympics', - 'vidpin.bin': 'Video Pinball', - 'warl2600.bin': 'Warlords', - 'yar_rev.bin': 'Yars Revenge', -} - - -def _info_transform(game_name): - transformed_name = game_name.replace(" ", "") - return { - 'filename': f'{transformed_name}.a26', - 'name': game_name - } - - -game_info_map = {k: _info_transform(v) for k, v in game_name_map.items()} - - -def get_game_list(): - '''Transform the game map for documentation''' - return map(lambda x: { - 'filename': x['filename'], - 'game': f"{x['name']}", - 'system': "Atari 2600", - 'status': "good", - "notes": []}, - game_info_map.values()) - - -def find_files(base_path): - '''Find the files this task supports''' - uncomp_rom_path = os.path.join( - base_path, "AtariVault_Data", "StreamingAssets", "FOCAL_Emulator") - archive_list = glob.glob(uncomp_rom_path + '/*.*') - return archive_list - - -def copy(in_dir, out_dir): - '''Copy/rename 2600 ROMs''' - rom_files = find_files(in_dir) - for file_path in rom_files: - file_name = os.path.basename(file_path) - game_info = game_info_map.get(file_name) - if game_info is not None: - display_name = game_info['name'] - logger.info( - f"Copying {file_name} to {game_info['filename']}: {display_name}") - try: - shutil.copyfile(file_path, os.path.join( - out_dir, game_info['filename'])) - except OSError as error: - logger.warning(f'Error while processing {file_path}!') - logger.warning(error) - else: - logger.debug(f'Skipping unmatched file {file_path}!') diff --git a/src/gex/lib/tasks/impl/atarivault/atari5200.py b/src/gex/lib/tasks/impl/atarivault/atari5200.py deleted file mode 100644 index 8c0b7fa..0000000 --- a/src/gex/lib/tasks/impl/atarivault/atari5200.py +++ /dev/null @@ -1,78 +0,0 @@ -'''Extraction code for Atari 5200 ROMs''' -import glob -import logging -import os -import shutil - -logger = logging.getLogger('gextoolbox') - - -game_name_map = { - "asteroids.bin": "Asteroids", - "centipede.bin": "Centipede", - "countermeasure.bin": "Countermeasure", - "millipede.bin": "Millipede", - "missile_command.bin": "Missile Command", - "realsports_baseball.bin": "RealSports Baseball", - "realsports_basketball.bin": "RealSports Basketball", - "realsports_football.bin": "RealSports Football", - "realsports_soccer.bin": "RealSports Soccer", - "realsports_tennis.bin": "RealSports Tennis", - "star_raiders.bin": "Star Raiders", - "super_breakout.bin": "Super Breakout", - "final_legacy.bin": "Final Legacy", - "microgammon.bin": "Micro-Gammon", - "miniature_golf.bin": "Miniature Golf", - "xari_arena.bin": "Xari Arena", - "bios.bin": "5200 BIOS" -} - - -def _info_transform(game_name): - transformed_name = game_name.replace(" ", "") - return { - 'filename': f'{transformed_name}.a52', - 'name': game_name - } - - -game_info_map = {k: _info_transform(v) for k, v in game_name_map.items()} - - -def get_game_list(): - '''Transform the game map for documentation''' - return map(lambda x: { - 'filename': x['filename'], - 'game': f"{x['name']}", - 'system': "Atari 5200", - 'status': "good", - "notes": []}, - game_info_map.values()) - - -def find_files(base_path): - '''Find the files this task supports''' - uncomp_rom_path = os.path.join( - base_path, "AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "5200") - archive_list = glob.glob(uncomp_rom_path + '/*.*') - return archive_list - - -def copy(in_dir, out_dir): - '''Copy/rename 5200 ROMs''' - rom_files = find_files(in_dir) - for file_path in rom_files: - file_name = os.path.basename(file_path) - game_info = game_info_map.get(file_name) - if game_info is not None: - display_name = game_info['name'] - logger.info( - f"Copying {file_name} to {game_info['filename']}: {display_name}") - try: - shutil.copyfile(file_path, os.path.join( - out_dir, game_info['filename'])) - except OSError as error: - logger.warning(f'Error while processing {file_path}!') - logger.warning(error) - else: - logger.debug(f'Skipping unmatched file {file_path}!') diff --git a/src/gex/lib/tasks/impl/atarivault/metadata.json b/src/gex/lib/tasks/impl/atarivault/metadata.json new file mode 100644 index 0000000..317faec --- /dev/null +++ b/src/gex/lib/tasks/impl/atarivault/metadata.json @@ -0,0 +1,4301 @@ +{ + "in": { + "files": { + "Asteroids.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Asteroids.bin", + "versions": { + "Steam": { + "size": 8192, + "crc": "1143BA1E" + } + } + }, + "Asteroids Deluxe.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Asteroids Deluxe.bin", + "versions": { + "Steam": { + "size": 12288, + "crc": "B095201C" + } + } + }, + "Black Widow.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Black Widow.bin", + "versions": { + "Steam": { + "size": 43008, + "crc": "1FF6C231" + } + } + }, + "CanyonBomber.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "CanyonBomber.bin", + "versions": { + "Steam": { + "size": 4096, + "crc": "9B93E001" + } + } + }, + "CanyonBomberSprites.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "CanyonBomberSprites.bmp", + "versions": { + "Steam": { + "size": 2166, + "crc": "58DCDED9" + } + } + }, + "CanyonBomberTiles.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "CanyonBomberTiles.bmp", + "versions": { + "Steam": { + "size": 4214, + "crc": "F363205F" + } + } + }, + "Centipede.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Centipede.bin", + "versions": { + "Steam": { + "size": 8192, + "crc": "65445D14" + } + } + }, + "Centipede.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Centipede.bmp", + "versions": { + "Steam": { + "size": 24652, + "crc": "3D5730A2" + } + } + }, + "Crystal Castles.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Crystal Castles.bin", + "versions": { + "Steam": { + "size": 40960, + "crc": "549C331F" + } + } + }, + "Crystal Castles.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Crystal Castles.bmp", + "versions": { + "Steam": { + "size": 32856, + "crc": "7F3454BD" + } + } + }, + "Gravitar.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Gravitar.bin", + "versions": { + "Steam": { + "size": 43008, + "crc": "4A6EADAF" + } + } + }, + "Liberator.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Liberator.bin", + "versions": { + "Steam": { + "size": 28672, + "crc": "8F2DDE2B" + } + } + }, + "Liberator.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Liberator.bmp", + "versions": { + "Steam": { + "size": 196784, + "crc": "CCF0891F" + } + } + }, + "Liberator Projection.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Liberator Projection.bin", + "versions": { + "Steam": { + "size": 20634, + "crc": "279B6269" + } + } + }, + "Lunar Lander.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Lunar Lander.bin", + "versions": { + "Steam": { + "size": 14336, + "crc": "27773A10" + } + } + }, + "Major Havoc alpha banks.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Major Havoc alpha banks.bin", + "versions": { + "Steam": { + "size": 32768, + "crc": "756B4074" + } + } + }, + "Major Havoc gamma.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Major Havoc gamma.bin", + "versions": { + "Steam": { + "size": 16384, + "crc": "93FAF210" + } + } + }, + "Major Havoc vector banks.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Major Havoc vector banks.bin", + "versions": { + "Steam": { + "size": 32768, + "crc": "59E92881" + } + } + }, + "Major Havoc.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Major Havoc.bin", + "versions": { + "Steam": { + "size": 36864, + "crc": "8C856F2F" + } + } + }, + "Millipede.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Millipede.bin", + "versions": { + "Steam": { + "size": 16384, + "crc": "EDC72E1D" + } + } + }, + "Millipede.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Millipede.bmp", + "versions": { + "Steam": { + "size": 49272, + "crc": "01F40794" + } + } + }, + "Missile Command.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Missile Command.bin", + "versions": { + "Steam": { + "size": 12288, + "crc": "0992FB02" + } + } + }, + "Red Baron.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Red Baron.bin", + "versions": { + "Steam": { + "size": 18432, + "crc": "897EE08B" + } + } + }, + "Space Duel.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Space Duel.bin", + "versions": { + "Steam": { + "size": 26624, + "crc": "DE1668C8" + } + } + }, + "Sprint2.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Sprint2.bin", + "versions": { + "Steam": { + "size": 8192, + "crc": "59F85A0A" + } + } + }, + "Sprint2Sprites.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Sprint2Sprites.bmp", + "versions": { + "Steam": { + "size": 4214, + "crc": "CAA4F9F7" + } + } + }, + "Sprint2Tiles.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Sprint2Tiles.bmp", + "versions": { + "Steam": { + "size": 4214, + "crc": "D291DCE6" + } + } + }, + "Super Breakout.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Super Breakout.bin", + "versions": { + "Steam": { + "size": 5120, + "crc": "2D6D06E7" + } + } + }, + "Super Breakout vector.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Super Breakout vector.bmp", + "versions": { + "Steam": { + "size": 2422, + "crc": "64FCFE15" + } + } + }, + "Super Breakout.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Super Breakout.bmp", + "versions": { + "Steam": { + "size": 4176, + "crc": "3BFBCF60" + } + } + }, + "Tempest.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Tempest.bin", + "versions": { + "Steam": { + "size": 24576, + "crc": "4FF276D2" + } + } + }, + "Warlords.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Warlords.bin", + "versions": { + "Steam": { + "size": 12288, + "crc": "7F2391FD" + } + } + }, + "Warlords Background.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Warlords Background.bmp", + "versions": { + "Steam": { + "size": 62520, + "crc": "855CFB96" + } + } + }, + "Warlords.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Warlords.bmp", + "versions": { + "Steam": { + "size": 16456, + "crc": "7B402A19" + } + } + }, + "Avalanche.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Avalanche.bin", + "versions": { + "Steam": { + "size": 6144, + "crc": "9478BC10" + } + } + }, + "AtariBaseball.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "AtariBaseball.bin", + "versions": { + "Steam": { + "size": 8192, + "crc": "F5B812DD" + } + } + }, + "AtariBaseballTiles1.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "AtariBaseballTiles1.bmp", + "versions": { + "Steam": { + "size": 4214, + "crc": "63F56CC1" + } + } + }, + "AtariBaseballTiles2.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "AtariBaseballTiles2.bmp", + "versions": { + "Steam": { + "size": 4214, + "crc": "0899E576" + } + } + }, + "AtariBasketball.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "AtariBasketball.bin", + "versions": { + "Steam": { + "size": 8192, + "crc": "49AC3012" + } + } + }, + "AtariBasketballTiles.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "AtariBasketballTiles.bmp", + "versions": { + "Steam": { + "size": 4214, + "crc": "4D9D520C" + } + } + }, + "AtariBasketballSprites.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "AtariBasketballSprites.bmp", + "versions": { + "Steam": { + "size": 16502, + "crc": "0F8AE748" + } + } + }, + "Destroyer.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Destroyer.bin", + "versions": { + "Steam": { + "size": 2048, + "crc": "E560C712" + } + } + }, + "DestroyerSprites1.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "DestroyerSprites1.bmp", + "versions": { + "Steam": { + "size": 4214, + "crc": "113FEB96" + } + } + }, + "DestroyerSprites2.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "DestroyerSprites2.bmp", + "versions": { + "Steam": { + "size": 12534, + "crc": "CE8C6992" + } + } + }, + "DestroyerTiles.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "DestroyerTiles.bmp", + "versions": { + "Steam": { + "size": 4214, + "crc": "886D701D" + } + } + }, + "DestroyerWaves.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "DestroyerWaves.bmp", + "versions": { + "Steam": { + "size": 374, + "crc": "EBE88168" + } + } + }, + "Dominos.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Dominos.bin", + "versions": { + "Steam": { + "size": 4096, + "crc": "10354EFF" + } + } + }, + "DominosTiles.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "DominosTiles.bmp", + "versions": { + "Steam": { + "size": 4214, + "crc": "E71C6BA0" + } + } + }, + "FireTruck.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "FireTruck.bin", + "versions": { + "Steam": { + "size": 8192, + "crc": "91A9982A" + } + } + }, + "FireTruckSprites1.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "FireTruckSprites1.bmp", + "versions": { + "Steam": { + "size": 8310, + "crc": "F41F46EA" + } + } + }, + "FireTruckSprites2.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "FireTruckSprites2.bmp", + "versions": { + "Steam": { + "size": 32886, + "crc": "F2CB2D34" + } + } + }, + "FireTruckTiles1.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "FireTruckTiles1.bmp", + "versions": { + "Steam": { + "size": 8310, + "crc": "F3328F0E" + } + } + }, + "FireTruckTiles2.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "FireTruckTiles2.bmp", + "versions": { + "Steam": { + "size": 16502, + "crc": "30C49BC4" + } + } + }, + "AtariFootball.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "AtariFootball.bin", + "versions": { + "Steam": { + "size": 6144, + "crc": "DCACB14B" + } + } + }, + "AtariFootballTiles1.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "AtariFootballTiles1.bmp", + "versions": { + "Steam": { + "size": 4214, + "crc": "F3B1898B" + } + } + }, + "AtariFootballTiles2.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "AtariFootballTiles2.bmp", + "versions": { + "Steam": { + "size": 4214, + "crc": "664F35D0" + } + } + }, + "MazeInvaders.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "MazeInvaders.bin", + "versions": { + "Steam": { + "size": 20480, + "crc": "DC8E2879" + } + } + }, + "MazeInvaders.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "MazeInvaders.bmp", + "versions": { + "Steam": { + "size": 49272, + "crc": "F7D1147C" + } + } + }, + "MonteCarlo.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "MonteCarlo.bin", + "versions": { + "Steam": { + "size": 8192, + "crc": "EABF1C0E" + } + } + }, + "MonteCarloColors.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "MonteCarloColors.bin", + "versions": { + "Steam": { + "size": 512, + "crc": "386C543A" + } + } + }, + "MonteCarloSprites1.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "MonteCarloSprites1.bmp", + "versions": { + "Steam": { + "size": 8310, + "crc": "CF51E071" + } + } + }, + "MonteCarloSprites2.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "MonteCarloSprites2.bmp", + "versions": { + "Steam": { + "size": 8310, + "crc": "A668C0F8" + } + } + }, + "MonteCarloTiles1.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "MonteCarloTiles1.bmp", + "versions": { + "Steam": { + "size": 4214, + "crc": "4B1CDDA7" + } + } + }, + "MonteCarloTiles2.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "MonteCarloTiles2.bmp", + "versions": { + "Steam": { + "size": 16502, + "crc": "929999FB" + } + } + }, + "Poolshark.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Poolshark.bin", + "versions": { + "Steam": { + "size": 4096, + "crc": "067FCF82" + } + } + }, + "PoolsharkSprites.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "PoolsharkSprites.bmp", + "versions": { + "Steam": { + "size": 4214, + "crc": "28773457" + } + } + }, + "PoolsharkTiles.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "PoolsharkTiles.bmp", + "versions": { + "Steam": { + "size": 4214, + "crc": "D0BE43C0" + } + } + }, + "SkydiverROM.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "SkydiverROM.bin", + "versions": { + "Steam": { + "size": 8192, + "crc": "3733D335" + } + } + }, + "SkydiverSprites.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "SkydiverSprites.bmp", + "versions": { + "Steam": { + "size": 8310, + "crc": "921F4FCC" + } + } + }, + "SkydiverTiles.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "SkydiverTiles.bmp", + "versions": { + "Steam": { + "size": 4214, + "crc": "A058FC30" + } + } + }, + "AtariSoccer.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "AtariSoccer.bin", + "versions": { + "Steam": { + "size": 8192, + "crc": "A8818B3C" + } + } + }, + "AtariSoccerSprites.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "AtariSoccerSprites.bmp", + "versions": { + "Steam": { + "size": 8310, + "crc": "E4CDD1F3" + } + } + }, + "AtariSoccerTiles1.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "AtariSoccerTiles1.bmp", + "versions": { + "Steam": { + "size": 4214, + "crc": "5219EBD4" + } + } + }, + "AtariSoccerTiles2.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "AtariSoccerTiles2.bmp", + "versions": { + "Steam": { + "size": 4214, + "crc": "E8E2D22B" + } + } + }, + "SuperBug.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "SuperBug.bin", + "versions": { + "Steam": { + "size": 6144, + "crc": "D0A12884" + } + } + }, + "SuperBugSprites.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "SuperBugSprites.bmp", + "versions": { + "Steam": { + "size": 32884, + "crc": "ED8D0E5F" + } + } + }, + "SuperBugTiles1.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "SuperBugTiles1.bmp", + "versions": { + "Steam": { + "size": 8310, + "crc": "661399EE" + } + } + }, + "SuperBugTiles2.bmp": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "SuperBugTiles2.bmp", + "versions": { + "Steam": { + "size": 16502, + "crc": "0FAE9384" + } + } + }, + "3d_tic.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "3d_tic.bin", + "copy_to": "3-D Tic-Tac-Toe", + "versions": { + "Steam": { + "size": 2048, + "crc": "58805709" + } + } + }, + "advnture.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "advnture.bin", + "copy_to": "Adventure", + "versions": { + "Steam": { + "size": 4096, + "crc": "A6DB4B3A" + } + } + }, + "airseabt.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "airseabt.bin", + "copy_to": "Air-Sea Battle", + "versions": { + "Steam": { + "size": 2048, + "crc": "2A2A9F81" + } + } + }, + "asteroid.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "asteroid.bin", + "copy_to": "Asteroids", + "versions": { + "Steam": { + "size": 8192, + "crc": "70A59647" + } + } + }, + "backgamn.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "backgamn.bin", + "copy_to": "Backgammon", + "versions": { + "Steam": { + "size": 4096, + "crc": "E2A7FFA6" + } + } + }, + "basmath.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "basmath.bin", + "copy_to": "Basic Math", + "versions": { + "Steam": { + "size": 2048, + "crc": "D48EBAC0" + } + } + }, + "basketbl.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "basketbl.bin", + "copy_to": "Basketball", + "versions": { + "Steam": { + "size": 2048, + "crc": "32F60182" + } + } + }, + "black_j.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "black_j.bin", + "copy_to": "Blackjack", + "versions": { + "Steam": { + "size": 2048, + "crc": "4B0EE010" + } + } + }, + "Bowling.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "Bowling.bin", + "copy_to": "Bowling", + "versions": { + "Steam": { + "size": 2048, + "crc": "FEA0D6D5" + } + } + }, + "braingms.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "braingms.bin", + "copy_to": "Brain Games", + "versions": { + "Steam": { + "size": 2048, + "crc": "150709C2" + } + } + }, + "breakout.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "breakout.bin", + "copy_to": "Breakout", + "versions": { + "Steam": { + "size": 2048, + "crc": "3037638C" + } + } + }, + "canyonb.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "canyonb.bin", + "copy_to": "Canyon Bomber", + "versions": { + "Steam": { + "size": 2048, + "crc": "E914B8CA" + } + } + }, + "casino.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "casino.bin", + "copy_to": "Casino", + "versions": { + "Steam": { + "size": 4096, + "crc": "420B8248" + } + } + }, + "centiped.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "centiped.bin", + "copy_to": "Centipede", + "versions": { + "Steam": { + "size": 8192, + "crc": "77396102" + } + } + }, + "pelesocr.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "pelesocr.bin", + "copy_to": "Championship Soccer", + "versions": { + "Steam": { + "size": 4096, + "crc": "3F59BB60" + } + } + }, + "vidcheck.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "vidcheck.bin", + "copy_to": "Checkers", + "versions": { + "Steam": { + "size": 4096, + "crc": "3DF33335" + } + } + }, + "vidchess.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "vidchess.bin", + "copy_to": "Chess", + "versions": { + "Steam": { + "size": 4096, + "crc": "B6226A54" + } + } + }, + "circatri.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "circatri.bin", + "copy_to": "Circus Atari", + "versions": { + "Steam": { + "size": 4096, + "crc": "D2A330A3" + } + } + }, + "codebrk.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "codebrk.bin", + "copy_to": "Codebreaker", + "versions": { + "Steam": { + "size": 2048, + "crc": "947EDB18" + } + } + }, + "combat.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "combat.bin", + "copy_to": "Combat", + "versions": { + "Steam": { + "size": 2048, + "crc": "0D64A9C5" + } + } + }, + "combat2.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "combat2.bin", + "copy_to": "Combat 2", + "versions": { + "Steam": { + "size": 8192, + "crc": "8CABE1FD" + } + } + }, + "concentr.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "concentr.bin", + "copy_to": "Concentration", + "versions": { + "Steam": { + "size": 2048, + "crc": "17DE8070" + } + } + }, + "cryscast.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "cryscast.bin", + "copy_to": "Crystal Castles", + "versions": { + "Steam": { + "size": 16384, + "crc": "9007B5AC" + } + } + }, + "demondim.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "demondim.bin", + "copy_to": "Demons to Diamonds", + "versions": { + "Steam": { + "size": 4096, + "crc": "9B97C3DA" + } + } + }, + "dsrtfalc.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "dsrtfalc.bin", + "copy_to": "Desert Falcon", + "versions": { + "Steam": { + "size": 16384, + "crc": "CAA0054E" + } + } + }, + "dodge_em.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "dodge_em.bin", + "copy_to": "Dodge Em", + "versions": { + "Steam": { + "size": 4096, + "crc": "0C74479B" + } + } + }, + "doubdunk.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "doubdunk.bin", + "copy_to": "Double Dunk", + "versions": { + "Steam": { + "size": 16384, + "crc": "6112CBF5" + } + } + }, + "fatalrun.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "fatalrun.bin", + "copy_to": "Fatal Run", + "versions": { + "Steam": { + "size": 32768, + "crc": "826C2E3D" + } + } + }, + "flagcap.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "flagcap.bin", + "copy_to": "Flag Capture", + "versions": { + "Steam": { + "size": 2048, + "crc": "8AA1C41E" + } + } + }, + "football.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "football.bin", + "copy_to": "Football", + "versions": { + "Steam": { + "size": 2048, + "crc": "3B73EE02" + } + } + }, + "golf.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "golf.bin", + "copy_to": "Golf", + "versions": { + "Steam": { + "size": 2048, + "crc": "46A9F200" + } + } + }, + "grav2600.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "grav2600.bin", + "copy_to": "Gravitar", + "versions": { + "Steam": { + "size": 8192, + "crc": "C87FCCBE" + } + } + }, + "hangman.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "hangman.bin", + "copy_to": "Hangman", + "versions": { + "Steam": { + "size": 4096, + "crc": "C2BCC789" + } + } + }, + "haunthse.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "haunthse.bin", + "copy_to": "Haunted House", + "versions": { + "Steam": { + "size": 4096, + "crc": "AA62D961" + } + } + }, + "homerun.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "homerun.bin", + "copy_to": "Home Run", + "versions": { + "Steam": { + "size": 2048, + "crc": "45ACE998" + } + } + }, + "human_cb.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "human_cb.bin", + "copy_to": "Human Cannonball", + "versions": { + "Steam": { + "size": 2048, + "crc": "F05A41E1" + } + } + }, + "mazecrz.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "mazecrz.bin", + "copy_to": "Maze Craze", + "versions": { + "Steam": { + "size": 4096, + "crc": "0098E428" + } + } + }, + "milliped.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "milliped.bin", + "copy_to": "Millipede", + "versions": { + "Steam": { + "size": 16384, + "crc": "CCC82DD0" + } + } + }, + "min_golf.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "min_golf.bin", + "copy_to": "Miniature Golf", + "versions": { + "Steam": { + "size": 2048, + "crc": "28562315" + } + } + }, + "misscomm.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "misscomm.bin", + "copy_to": "Missile Command", + "versions": { + "Steam": { + "size": 4096, + "crc": "CFF14904" + } + } + }, + "nightdrv.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "nightdrv.bin", + "copy_to": "Night Driver", + "versions": { + "Steam": { + "size": 2048, + "crc": "600D8A96" + } + } + }, + "ofthwall.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "ofthwall.bin", + "copy_to": "Off the Wall", + "versions": { + "Steam": { + "size": 16384, + "crc": "E425A1CF" + } + } + }, + "outlaw.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "outlaw.bin", + "copy_to": "Outlaw", + "versions": { + "Steam": { + "size": 2048, + "crc": "68DD7ACD" + } + } + }, + "quadrun.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "quadrun.bin", + "copy_to": "Quadrun", + "versions": { + "Steam": { + "size": 8192, + "crc": "A95CDD6F" + } + } + }, + "indy500.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "indy500.bin", + "copy_to": "Race", + "versions": { + "Steam": { + "size": 2048, + "crc": "B43DA2A3" + } + } + }, + "radarlok.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "radarlok.bin", + "copy_to": "Radar Lock", + "versions": { + "Steam": { + "size": 16384, + "crc": "C29F7285" + } + } + }, + "rs_baseb.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "rs_baseb.bin", + "copy_to": "RealSports Baseball", + "versions": { + "Steam": { + "size": 8192, + "crc": "3C5A1B5F" + } + } + }, + "rsbasket.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "rsbasket.bin", + "copy_to": "RealSports Basketball", + "versions": { + "Steam": { + "size": 8192, + "crc": "364FEAA6" + } + } + }, + "rsboxing.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "rsboxing.bin", + "copy_to": "RealSports Boxing", + "versions": { + "Steam": { + "size": 16384, + "crc": "3398A1B2" + } + } + }, + "rs_footb.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "rs_footb.bin", + "copy_to": "RealSports Football", + "versions": { + "Steam": { + "size": 8192, + "crc": "F89F64EF" + } + } + }, + "rssoccer.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "rssoccer.bin", + "copy_to": "RealSports Soccer", + "versions": { + "Steam": { + "size": 8192, + "crc": "02D89819" + } + } + }, + "rstennis.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "rstennis.bin", + "copy_to": "RealSports Tennis", + "versions": { + "Steam": { + "size": 8192, + "crc": "379001A0" + } + } + }, + "rs_volly.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "rs_volly.bin", + "copy_to": "RealSports Volleyball", + "versions": { + "Steam": { + "size": 4096, + "crc": "54FC9EB2" + } + } + }, + "ret2hh.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "ret2hh.bin", + "copy_to": "Return to Haunted House", + "versions": { + "Steam": { + "size": 4096, + "crc": "95D29756" + } + } + }, + "SaveMary_NTSC.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "SaveMary_NTSC.bin", + "copy_to": "Save Mary", + "versions": { + "Steam": { + "size": 16384, + "crc": "01E18F53" + } + } + }, + "secretq.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "secretq.bin", + "copy_to": "Secret Quest", + "versions": { + "Steam": { + "size": 16384, + "crc": "93C9EB47" + } + } + }, + "sentinel.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "sentinel.bin", + "copy_to": "Sentinel", + "versions": { + "Steam": { + "size": 16384, + "crc": "27ACC8A3" + } + } + }, + "skydiver.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "skydiver.bin", + "copy_to": "Sky Diver", + "versions": { + "Steam": { + "size": 2048, + "crc": "00312EA9" + } + } + }, + "slotmach.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "slotmach.bin", + "copy_to": "Slot Machine", + "versions": { + "Steam": { + "size": 2048, + "crc": "CB378D95" + } + } + }, + "slotrace.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "slotrace.bin", + "copy_to": "Slot Racers", + "versions": { + "Steam": { + "size": 2048, + "crc": "177DBDF8" + } + } + }, + "spacewar.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "spacewar.bin", + "copy_to": "Space War", + "versions": { + "Steam": { + "size": 2048, + "crc": "65622F2A" + } + } + }, + "sprntmas.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "sprntmas.bin", + "copy_to": "Sprint Master", + "versions": { + "Steam": { + "size": 16384, + "crc": "C495904E" + } + } + }, + "starraid.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "starraid.bin", + "copy_to": "Star Raiders", + "versions": { + "Steam": { + "size": 8192, + "crc": "2AE193EE" + } + } + }, + "starship.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "starship.bin", + "copy_to": "Star Ship", + "versions": { + "Steam": { + "size": 2048, + "crc": "6609267E" + } + } + }, + "steplchs.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "steplchs.bin", + "copy_to": "Steeplechase", + "versions": { + "Steam": { + "size": 2048, + "crc": "5F6C32C3" + } + } + }, + "stlrtrak.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "stlrtrak.bin", + "copy_to": "Stellar Track", + "versions": { + "Steam": { + "size": 4096, + "crc": "A76E93BF" + } + } + }, + "stunt.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "stunt.bin", + "copy_to": "Stunt Cycle", + "versions": { + "Steam": { + "size": 2048, + "crc": "6354FF4C" + } + } + }, + "streetrc.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "streetrc.bin", + "copy_to": "Street Racer", + "versions": { + "Steam": { + "size": 2048, + "crc": "47592880" + } + } + }, + "subcmdr.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "subcmdr.bin", + "copy_to": "Submarine Commander", + "versions": { + "Steam": { + "size": 4096, + "crc": "3262960A" + } + } + }, + "sprbaseb.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "sprbaseb.bin", + "copy_to": "Super Baseball", + "versions": { + "Steam": { + "size": 16384, + "crc": "2245F170" + } + } + }, + "superbrk.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "superbrk.bin", + "copy_to": "Super Breakout", + "versions": { + "Steam": { + "size": 4096, + "crc": "171DBE92" + } + } + }, + "sprfootb.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "sprfootb.bin", + "copy_to": "Super Football", + "versions": { + "Steam": { + "size": 16384, + "crc": "C9B16F3C" + } + } + }, + "surround.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "surround.bin", + "copy_to": "Surround", + "versions": { + "Steam": { + "size": 2048, + "crc": "DCB11F23" + } + } + }, + "sq_earth.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "sq_earth.bin", + "copy_to": "Sword Quest Earthworld", + "versions": { + "Steam": { + "size": 8192, + "crc": "D5E21B79" + } + } + }, + "sq_fire.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "sq_fire.bin", + "copy_to": "Sword Quest Fireworld", + "versions": { + "Steam": { + "size": 8192, + "crc": "6AE46A0C" + } + } + }, + "sq_water.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "sq_water.bin", + "copy_to": "Sword Quest Waterworld", + "versions": { + "Steam": { + "size": 8192, + "crc": "CA7B4685" + } + } + }, + "temp2600.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "temp2600.bin", + "copy_to": "Tempest", + "versions": { + "Steam": { + "size": 8192, + "crc": "E6DABC1B" + } + } + }, + "vidcube.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "vidcube.bin", + "copy_to": "Video Cube", + "versions": { + "Steam": { + "size": 4096, + "crc": "8172299E" + } + } + }, + "vid_olym.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "vid_olym.bin", + "copy_to": "Video Olympics", + "versions": { + "Steam": { + "size": 2048, + "crc": "E4BC89C4" + } + } + }, + "vidpin.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "vidpin.bin", + "copy_to": "Video Pinball", + "versions": { + "Steam": { + "size": 4096, + "crc": "10D95426" + } + } + }, + "warl2600.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "warl2600.bin", + "copy_to": "Warlords", + "versions": { + "Steam": { + "size": 4096, + "crc": "CF174B57" + } + } + }, + "yar_rev.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator"], + "filename": "yar_rev.bin", + "copy_to": "Yars Revenge", + "versions": { + "Steam": { + "size": 4096, + "crc": "DFA1C825" + } + } + }, + "asteroids.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "5200"], + "filename": "asteroids.bin", + "copy_to": "Asteroids (5200)", + "versions": { + "Steam": { + "size": 8192, + "crc": "38480891" + } + } + }, + "centipede.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "5200"], + "filename": "centipede.bin", + "copy_to": "Centipede (5200)", + "versions": { + "Steam": { + "size": 16384, + "crc": "536A70FE" + } + } + }, + "countermeasure.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "5200"], + "filename": "countermeasure.bin", + "copy_to": "Countermeasure (5200)", + "versions": { + "Steam": { + "size": 16384, + "crc": "FF7AF233" + } + } + }, + "millipede.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "5200"], + "filename": "millipede.bin", + "copy_to": "Millipede (5200)", + "versions": { + "Steam": { + "size": 16384, + "crc": "969CFE1A" + } + } + }, + "missile_command.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "5200"], + "filename": "missile_command.bin", + "copy_to": "Missile Command (5200)", + "versions": { + "Steam": { + "size": 8192, + "crc": "44D3FF6F" + } + } + }, + "realsports_baseball.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "5200"], + "filename": "realsports_baseball.bin", + "copy_to": "RealSports Baseball (5200)", + "versions": { + "Steam": { + "size": 32768, + "crc": "44166592" + } + } + }, + "realsports_basketball.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "5200"], + "filename": "realsports_basketball.bin", + "copy_to": "RealSports Basketball (5200)", + "versions": { + "Steam": { + "size": 32768, + "crc": "DD217276" + } + } + }, + "realsports_football.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "5200"], + "filename": "realsports_football.bin", + "copy_to": "RealSports Football (5200)", + "versions": { + "Steam": { + "size": 16384, + "crc": "4336C2CC" + } + } + }, + "realsports_soccer.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "5200"], + "filename": "realsports_soccer.bin", + "copy_to": "RealSports Soccer (5200)", + "versions": { + "Steam": { + "size": 16384, + "crc": "ECBD1853" + } + } + }, + "realsports_tennis.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "5200"], + "filename": "realsports_tennis.bin", + "copy_to": "RealSports Tennis (5200)", + "versions": { + "Steam": { + "size": 16384, + "crc": "10F33C90" + } + } + }, + "star_raiders.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "5200"], + "filename": "star_raiders.bin", + "copy_to": "Star Raiders (5200)", + "versions": { + "Steam": { + "size": 16384, + "crc": "7D819A9F" + } + } + }, + "super_breakout.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "5200"], + "filename": "super_breakout.bin", + "copy_to": "Super Breakout (5200)", + "versions": { + "Steam": { + "size": 4096, + "crc": "A0642110" + } + } + }, + "final_legacy.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "5200"], + "filename": "final_legacy.bin", + "copy_to": "Final Legacy (5200)", + "versions": { + "Steam": { + "size": 16384, + "crc": "D3BD3221" + } + } + }, + "microgammon.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "5200"], + "filename": "microgammon.bin", + "copy_to": "Micro-Gammon (5200)", + "versions": { + "Steam": { + "size": 16384, + "crc": "931A454A" + } + } + }, + "miniature_golf.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "5200"], + "filename": "miniature_golf.bin", + "copy_to": "Miniature Golf (5200)", + "versions": { + "Steam": { + "size": 16384, + "crc": "C597C087" + } + } + }, + "xari_arena.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "5200"], + "filename": "xari_arena.bin", + "copy_to": "Xari Arena (5200)", + "versions": { + "Steam": { + "size": 16384, + "crc": "B8FAAEC3" + } + } + }, + "bios.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "5200"], + "filename": "bios.bin", + "copy_to": "5200 BIOS (5200)", + "versions": { + "Steam": { + "size": 2048, + "crc": "4248D3E3" + } + } + }, + "airaidrs.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets" , "FOCAL_Emulator", "vol3"], + "filename": "airaidrs.bin", + "copy_to": "Air Raiders", + "versions": { + "Steam": { + "size": 4096, + "crc": "BB16539D" + } + } + }, + "armambsh.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "vol3"], + "filename": "armambsh.bin", + "copy_to": "Armor Ambush", + "versions": { + "Steam": { + "size": 4096, + "crc": "FC35704B" + } + } + }, + "astrblst.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "vol3"], + "filename": "astrblst.bin", + "copy_to": "Astroblast", + "versions": { + "Steam": { + "size": 4096, + "crc": "1DE25331" + } + } + }, + "darkcvrn.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "vol3"], + "filename": "darkcvrn.bin", + "copy_to": "Dark Cavern", + "versions": { + "Steam": { + "size": 4096, + "crc": "0481078C" + } + } + }, + "frogflys.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "vol3"], + "filename": "frogflys.bin", + "copy_to": "Frogs And Flies", + "versions": { + "Steam": { + "size": 4096, + "crc": "6476C136" + } + } + }, + "pele_tw.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "vol3"], + "filename": "pele_tw.bin", + "copy_to": "International Soccer", + "versions": { + "Steam": { + "size": 4096, + "crc": "B9D549A2" + } + } + }, + "seabattle.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "vol3"], + "filename": "seabattle.bin", + "copy_to": "Sea Battle", + "versions": { + "Steam": { + "size": 4096, + "crc": "83B4EB19" + } + } + }, + "spacattk.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "vol3"], + "filename": "spacattk.bin", + "copy_to": "Space Attack", + "versions": { + "Steam": { + "size": 4096, + "crc": "B34A3E57" + } + } + }, + "starstrk.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "vol3"], + "filename": "starstrk.bin", + "copy_to": "Star Strike", + "versions": { + "Steam": { + "size": 4096, + "crc": "936A596D" + } + } + }, + "suprbase.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "vol3"], + "filename": "suprbase.bin", + "copy_to": "Super Challenge Baseball", + "versions": { + "Steam": { + "size": 4096, + "crc": "F7E88EC2" + } + } + }, + "suprfoot.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "vol3"], + "filename": "suprfoot.bin", + "copy_to": "Super Challenge Football", + "versions": { + "Steam": { + "size": 4096, + "crc": "55F02EFE" + } + } + }, + "swordfight.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "vol3"], + "filename": "swordfight.bin", + "copy_to": "Swordfight", + "versions": { + "Steam": { + "size": 4096, + "crc": "F1AD77BE" + } + } + }, + "adventureii.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "vol3"], + "filename": "adventureii.bin", + "copy_to": "Adventure II", + "versions": { + "Steam": { + "size": 8192, + "crc": "BFD846C5" + } + } + }, + "aquavent.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "vol3"], + "filename": "aquavent.bin", + "copy_to": "Aquaventure", + "versions": { + "Steam": { + "size": 8192, + "crc": "87A8CB8B" + } + } + }, + "frog_pond_8_27_82.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "vol3"], + "filename": "frog_pond_8_27_82.bin", + "copy_to": "Frog Pond", + "versions": { + "Steam": { + "size": 8192, + "crc": "5874385A" + } + } + }, + "holemole.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "vol3"], + "filename": "holemole.bin", + "copy_to": "Holey Moley", + "versions": { + "Steam": { + "size": 8192, + "crc": "3BB2E71D" + } + } + }, + "motorodeo_ntsc.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "vol3"], + "filename": "motorodeo_ntsc.bin", + "copy_to": "Motorodeo", + "versions": { + "Steam": { + "size": 16384, + "crc": "89998E29" + } + } + }, + "saboteur.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "vol3"], + "filename": "saboteur.bin", + "copy_to": "Saboteur", + "versions": { + "Steam": { + "size": 8192, + "crc": "C359C13D" + } + } + }, + "wizard.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "vol3"], + "filename": "wizard.bin", + "copy_to": "Wizard", + "versions": { + "Steam": { + "size": 4096, + "crc": "D2F5A554" + } + } + }, + "yarsreturn.bin": { + "rel_path": ["AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "vol3"], + "filename": "yarsreturn.bin", + "copy_to": "Yars Return", + "versions": { + "Steam": { + "size": 8192, + "crc": "DAF83348" + } + } + } + } + }, + "out": { + "files": [ + { + "game": "Asteroids", + "filename": "asteroid.zip", + "system": "Arcade", + "set": "Arcade", + "status": "good", + "notes": [], + "in_files": [ + "Asteroids.bin" + ], + "split": [ + "035145.02", + "035144.02", + "035143.02", + "035127.02" + ], + "verify": { + "type": "zip", + "entries": { + "035145.02": {"size": 2048, "crc": "0CC75459"}, + "035144.02": {"size": 2048, "crc": "096ED35C"}, + "035143.02": {"size": 2048, "crc": "312CAA02"}, + "035127.02": {"size": 2048, "crc": "8B71FD9E"} + } + } + }, + { + "game": "Asteroids Deluxe", + "filename": "astdelux.zip", + "system": "Arcade", + "set": "Arcade", + "status": "good", + "notes": [], + "in_files": [ + "Asteroids Deluxe.bin" + ], + "split": [ + "036430.02", + "036431.02", + "036432.02", + "036433.03", + "036800.02", + "036799.01" + ], + "verify": { + "type": "zip", + "entries": { + "036430.02": {"size": 2048, "crc": "A4D7A525"}, + "036431.02": {"size": 2048, "crc": "D4004AAE"}, + "036432.02": {"size": 2048, "crc": "6D720C41"}, + "036433.03": {"size": 2048, "crc": "0DCC0BE6"}, + "036800.02": {"size": 2048, "crc": "BB8CABE1"}, + "036799.01": {"size": 2048, "crc": "7D511572"} + } + } + }, + { + "game": "Black Widow", + "filename": "bwidow.zip", + "system": "Arcade", + "set": "Arcade", + "status": "playable", + "notes": [2], + "in_files": [ + "Black Widow.bin" + ], + "truncate": 38912, + "split": { + "136017.107": 2048, + "136017.108": 4096, + "136017.109": 4096, + "136017.110": 4096, + "136017.101": 4096, + "136017.102": 4096, + "136017.103": 4096, + "136017.104": 4096, + "136017.105": 4096, + "136017.106": 4096 + }, + "verify": { + "type": "zip", + "entries": { + "136017.107": {"size": 2048, "crc": "97F6000C"}, + "136017.108": {"size": 4096, "crc": "3DA354ED"}, + "136017.109": {"size": 4096, "crc": "2FC4CE79"}, + "136017.110": {"size": 4096, "crc": "0DD52987"}, + "136017.101": {"size": 4096, "crc": "FE3FEBB7"}, + "136017.102": {"size": 4096, "crc": "10AD0376"}, + "136017.103": {"size": 4096, "crc": "8A1430EE"}, + "136017.104": {"size": 4096, "crc": "44F9943F"}, + "136017.105": {"size": 4096, "crc": "1FDF801C"}, + "136017.106": {"size": 4096, "crc": "4DC28B22"} + } + } + }, + { + "game": "Canyon Bomber", + "filename": "canyon-partial.zip", + "system": "Arcade", + "set": "Arcade", + "status": "partial", + "notes": [6], + "in_files": [ + "CanyonBomber.bin", + "CanyonBomberSprites.bmp", + "CanyonBomberTiles.bmp" + ], + "verify": { + "type": "zip", + "entries": { + "9503-01.p1": {"size": 1024, "crc": "1EDDBE28"}, + "9499-01.j1": {"size": 1024, "crc": "31800767"}, + "9496-01.d1": {"size": 2048, "crc": "8BE15080"}, + "9505-01.n5": {"size": 256, "crc": "60507C07"}, + "9506-01.m5": {"size": 256, "crc": "0D63396A"}, + "tiles_temp": {"size": 4096, "crc": "764C11C0"}, + "9492-01.n8": {"size": 512, "crc": "5127B727"} + } + } + }, + { + "game": "Centipede", + "filename": "centiped-partial.zip", + "system": "Arcade", + "set": "Arcade", + "status": "partial", + "notes": [6], + "in_files": [ + "Centipede.bin", + "Centipede.bmp" + ], + "verify": { + "type": "zip", + "entries": { + "centiped.307": {"size": 2048, "crc": "5AB0D9DE"}, + "centiped.308": {"size": 2048, "crc": "4C07FD3E"}, + "centiped.309": {"size": 2048, "crc": "FF69B424"}, + "centiped.310": {"size": 2048, "crc": "44E40FA4"}, + "centiped.211": {"size": 6144, "crc": "00FCDBCD"}, + "centiped.212": {"size": 6144, "crc": "3B9955EC"} + } + } + }, + { + "game": "Crystal Castles", + "filename": "ccastles-partial.zip", + "system": "Arcade", + "set": "Arcade", + "status": "partial", + "notes": [], + "in_files": [ + "Crystal Castles.bin", + "Crystal Castles.bmp" + ] + }, + { + "game": "Gravitar", + "filename": "gravitar.zip", + "system": "Arcade", + "set": "Arcade", + "status": "good", + "notes": [], + "in_files": [ + "Gravitar.bin" + ], + "truncate": 38912, + "split": { + "136010.210": 2048, + "136010.207": 4096, + "136010.208": 4096, + "136010.309": 4096, + "136010.301": 4096, + "136010.302": 4096, + "136010.303": 4096, + "136010.304": 4096, + "136010.305": 4096, + "136010.306": 4096 + }, + "verify": { + "type": "zip", + "entries": { + "136010.210": {"size": 2048, "crc": "DEBCB243"}, + "136010.207": {"size": 4096, "crc": "4135629A"}, + "136010.208": {"size": 4096, "crc": "358F25D9"}, + "136010.309": {"size": 4096, "crc": "4AC78DF4"}, + "136010.301": {"size": 4096, "crc": "A2A55013"}, + "136010.302": {"size": 4096, "crc": "D3700B3C"}, + "136010.303": {"size": 4096, "crc": "8E12E3E0"}, + "136010.304": {"size": 4096, "crc": "467AD5DA"}, + "136010.305": {"size": 4096, "crc": "840603AF"}, + "136010.306": {"size": 4096, "crc": "3F3805AD"} + } + } + }, + { + "game": "Liberator", + "filename": "liberatr-partial.zip", + "system": "Arcade", + "set": "Arcade", + "status": "partial", + "notes": [6], + "in_files": [ + "Liberator.bin", + "Liberator.bmp", + "Liberator Projection.bin" + ] + }, + { + "game": "Lunar Lander", + "filename": "llander.zip", + "system": "Arcade", + "set": "Arcade", + "status": "playable", + "notes": [2], + "in_files": [ + "Lunar Lander.bin" + ], + "split": [ + "034599.01", + "034598.01", + "034571.02", + "034572.02", + "034597.01", + "034570.01", + "034569.02" + ], + "verify": { + "type": "zip", + "entries": { + "034599.01": {"size": 2048, "crc": "355A9371"}, + "034598.01": {"size": 2048, "crc": "9C4FFA68"}, + "034571.02": {"size": 2048, "crc": "3F55D17F"}, + "034572.02": {"size": 2048, "crc": "B8763EEA"}, + "034597.01": {"size": 2048, "crc": "77DA4B2F"}, + "034570.01": {"size": 2048, "crc": "2724E591"}, + "034569.02": {"size": 2048, "crc": "72837A4E"} + } + } + }, + { + "game": "Major Havoc", + "filename": "mhavoc.zip", + "system": "Arcade", + "set": "Arcade", + "status": "good", + "notes": [], + "handler": "_handle_mhavoc", + "in_files": [ + "Major Havoc alpha banks.bin", + "Major Havoc gamma.bin", + "Major Havoc vector banks.bin", + "Major Havoc.bin" + ], + "verify": { + "type": "zip", + "entries": { + "136025.210": {"size": 8192, "crc": "C67284CA"}, + "136025.216": {"size": 16384, "crc": "522A9CC0"}, + "136025.217": {"size": 16384, "crc": "EA3D6877"}, + "136025.215": {"size": 16384, "crc": "A4D380CA"}, + "136025.318": {"size": 16384, "crc": "BA935067"}, + "136025.108": {"size": 16384, "crc": "93FAF210"}, + "136025.106": {"size": 16384, "crc": "2CA83C76"}, + "136025.107": {"size": 16384, "crc": "5F81C5F3"} + } + } + }, + { + "game": "Millipede", + "filename": "milliped-partial.zip", + "system": "Arcade", + "set": "Arcade", + "status": "partial", + "notes": [6], + "in_files": [ + "Millipede.bin", + "Millipede.bmp" + ] + }, + { + "game": "Missile Command", + "filename": "missile.zip", + "system": "Arcade", + "set": "Arcade", + "status": "good", + "notes": [], + "in_files": [ + "Missile Command.bin" + ], + "split": [ + "035820.02", + "035821.02", + "035822.02", + "035823.02", + "035824.02", + "035825.02" + ], + "verify": { + "type": "zip", + "entries": { + "035820.02": {"size": 2048, "crc": "7A62CE6A"}, + "035821.02": {"size": 2048, "crc": "DF3BD57F"}, + "035822.02": {"size": 2048, "crc": "A1CD384A"}, + "035823.02": {"size": 2048, "crc": "82E552BB"}, + "035824.02": {"size": 2048, "crc": "606E42E0"}, + "035825.02": {"size": 2048, "crc": "F752EAEB"} + } + } + }, + { + "game": "Red Baron", + "filename": "redbaron.zip", + "system": "Arcade", + "set": "Arcade", + "status": "good", + "notes": [], + "in_files": [ + "Red Baron.bin" + ], + "handler": "_handle_redbaron", + "verify": { + "type": "zip", + "entries": { + "35763-01.h1": {"size": 2048, "crc": "B9486A6A"}, + "037587.01": {"size": 4096, "crc": "60F23983"}, + "037000.01e": {"size": 2048, "crc": "69BED808"}, + "036998.01e": {"size": 2048, "crc": "D1104DD7"}, + "036997.01e": {"size": 2048, "crc": "7434ACB4"}, + "036996.01e": {"size": 2048, "crc": "C0E7589E"}, + "036995.01e": {"size": 2048, "crc": "AD81D1DA"}, + "037006.01e": {"size": 2048, "crc": "9FCFFEA0"}, + "037007.01e": {"size": 2048, "crc": "60250EDE"} + } + } + }, + { + "game": "Space Duel", + "filename": "spacduel.zip", + "system": "Arcade", + "set": "Arcade", + "status": "good", + "notes": [], + "in_files": [ + "Space Duel.bin" + ], + "split": { + "136006.106": 2048, + "136006.107": 4096, + "136006.201": 4096, + "136006.102": 4096, + "136006.103": 4096, + "136006.104": 4096, + "136006.105": 4096 + }, + "verify": { + "type": "zip", + "entries": { + "136006.106": {"size": 2048, "crc": "691122FE"}, + "136006.107": {"size": 4096, "crc": "D8DD0461"}, + "136006.201": {"size": 4096, "crc": "F4037B6E"}, + "136006.102": {"size": 4096, "crc": "4C451E8A"}, + "136006.103": {"size": 4096, "crc": "EE72DA63"}, + "136006.104": {"size": 4096, "crc": "E41B38A3"}, + "136006.105": {"size": 4096, "crc": "5652710F"} + } + } + }, + { + "game": "Sprint2", + "filename": "sprint2.zip", + "system": "Arcade", + "set": "Arcade", + "status": "good", + "notes": [6], + "in_files": [ + "Sprint2.bin", + "Sprint2Sprites.bmp", + "Sprint2Tiles.bmp" + ], + "handler": "_handle_sprint2", + "verify": { + "type": "zip", + "entries": { + "6290-01.b1": {"size": 2048, "crc": "41FC985E"}, + "6291-01.c1": {"size": 2048, "crc": "07F7A920"}, + "6404.d1": {"size": 2048, "crc": "D2878FF6"}, + "6405.e1": {"size": 2048, "crc": "6C991C80"}, + "6399-01.j6": {"size": 512, "crc": "63D685B2"}, + "6398-01.k6": {"size": 512, "crc": "C9E1017E"}, + "6396-01.p4": {"size": 512, "crc": "801B42DD"}, + "6397-01.r4": {"size": 512, "crc": "135BA1AA"}, + "6400-01.m2": {"size": 256, "crc": "0D968558"}, + "6401-01.e2": {"size": 32, "crc": "190A55AD"} + } + } + }, + { + "game": "Super Breakout", + "filename": "sbrkout-partial.zip", + "system": "Arcade", + "set": "Arcade", + "status": "partial", + "notes": [6], + "in_files": [ + "Super Breakout.bin", + "Super Breakout vector.bmp", + "Super Breakout.bmp" + ] + }, + { + "game": "Tempest", + "filename": "tempest3.zip", + "system": "Arcade", + "set": "Arcade", + "status": "good", + "notes": [], + "in_files": [ + "Tempest.bin" + ], + "split": [ + "237.002", + "136.002", + "235.002", + "134.002", + "133.002", + "138.002" + ], + "verify": { + "type": "zip", + "entries": { + "237.002": {"size": 4096, "crc": "1D0CC503"}, + "136.002": {"size": 4096, "crc": "C88E3524"}, + "235.002": {"size": 4096, "crc": "A4B2CE3F"}, + "134.002": {"size": 4096, "crc": "65A9A9F9"}, + "133.002": {"size": 4096, "crc": "DE4E9E34"}, + "138.002": {"size": 4096, "crc": "9995256D"} + } + } + }, + { + "game": "Warlords", + "filename": "warlords-partial.zip", + "system": "Arcade", + "set": "Arcade", + "status": "partial", + "notes": [6], + "in_files": [ + "Warlords.bin", + "Warlords Background.bmp", + "Warlords.bmp" + ] + }, + { + "game": "Avalanche", + "filename": "avalnche.zip", + "system": "Arcade", + "set": "Arcade", + "status": "good", + "notes": [], + "in_files": [ + "Avalanche.bin" + ], + "handler": "_handle_avalnche", + "verify": { + "type": "zip", + "entries": { + "30612.d2": {"size": 2048, "crc": "3F975171"}, + "30615.d3": {"size": 2048, "crc": "3E1A86B4"}, + "30613.e2": {"size": 2048, "crc": "47A224D3"}, + "30616.e3": {"size": 2048, "crc": "F620F0F8"}, + "30611.c2": {"size": 2048, "crc": "0AD07F85"}, + "30614.c3": {"size": 2048, "crc": "A12D5D64"} + } + } + }, + { + "game": "Atari Baseball", + "filename": "abaseb-partial.zip", + "system": "Arcade", + "set": "Arcade", + "status": "partial", + "notes": [6], + "in_files": [ + "AtariBaseball.bin", + "AtariBaseballTiles1.bmp", + "AtariBaseballTiles2.bmp" + ] + }, + { + "game": "Atari Basketball", + "filename": "bsktball-partial.zip", + "system": "Arcade", + "set": "Arcade", + "status": "partial", + "notes": [], + "in_files": [ + "AtariBasketball.bin", + "AtariBasketballTiles.bmp", + "AtariBasketballSprites.bmp" + ] + }, + { + "game": "Destroyer", + "filename": "destroyr1-partial.zip", + "system": "Arcade", + "set": "Arcade", + "status": "partial", + "notes": [], + "in_files": [ + "Destroyer.bin", + "DestroyerSprites1.bmp", + "DestroyerSprites2.bmp", + "DestroyerTiles.bmp", + "DestroyerWaves.bmp" + ] + }, + { + "game": "Dominos", + "filename": "dominos-partial.zip", + "system": "Arcade", + "set": "Arcade", + "status": "partial", + "notes": [6], + "in_files": [ + "Dominos.bin", + "DominosTiles.bmp" + ] + }, + { + "game": "Fire Truck", + "filename": "firetrk-partial.zip", + "system": "Arcade", + "set": "Arcade", + "status": "partial", + "notes": [6], + "in_files": [ + "FireTruck.bin", + "FireTruckSprites1.bmp", + "FireTruckSprites2.bmp", + "FireTruckTiles1.bmp", + "FireTruckTiles2.bmp" + ] + }, + { + "game": "Atari Football", + "filename": "atarifb-partial.zip", + "system": "Arcade", + "set": "Arcade", + "status": "partial", + "notes": [6], + "in_files": [ + "AtariFootball.bin", + "AtariFootballTiles1.bmp", + "AtariFootballTiles2.bmp" + ] + }, + { + "game": "Maze Invaders", + "filename": "mazeinv-partial.zip", + "system": "Arcade", + "set": "Arcade", + "status": "partial", + "notes": [6], + "in_files": [ + "MazeInvaders.bin", + "MazeInvaders.bmp" + ] + }, + { + "game": "Monte Carlo", + "filename": "montecar-partial.zip", + "system": "Arcade", + "set": "Arcade", + "status": "partial", + "handler": "_handle_montecar", + "notes": [6], + "in_files": [ + "MonteCarlo.bin", + "MonteCarloColors.bin", + "MonteCarloSprites1.bmp", + "MonteCarloSprites2.bmp", + "MonteCarloTiles1.bmp", + "MonteCarloTiles2.bmp" + ] + }, + { + "game": "Pool Shark", + "filename": "poolshrk-partial.zip", + "system": "Arcade", + "set": "Arcade", + "status": "partial", + "notes": [6], + "in_files": [ + "Poolshark.bin", + "PoolsharkSprites.bmp", + "PoolsharkTiles.bmp" + ] + }, + { + "game": "Sky Diver", + "filename": "skydiver-partial.zip", + "system": "Arcade", + "set": "Arcade", + "status": "partial", + "notes": [6], + "in_files": [ + "SkydiverROM.bin", + "SkydiverSprites.bmp", + "SkydiverTiles.bmp" + ] + }, + { + "game": "Atari Soccer", + "filename": "soccer-partial.zip", + "system": "Arcade", + "set": "Arcade", + "status": "partial", + "notes": [6], + "in_files": [ + "AtariSoccer.bin", + "AtariSoccerSprites.bmp", + "AtariSoccerTiles1.bmp", + "AtariSoccerTiles2.bmp" + ] + }, + { + "game": "Super Bug", + "filename": "superbug-partial.zip", + "system": "Arcade", + "set": "Arcade", + "status": "partial", + "notes": [6], + "in_files": [ + "SuperBug.bin", + "SuperBugSprites.bmp", + "SuperBugTiles1.bmp", + "SuperBugTiles2.bmp" + ] + }, + { + "game": "3-D Tic-Tac-Toe", + "filename": "3-D_Tic-Tac-Toe.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "58805709" + } + }, + { + "game": "Adventure", + "filename": "Adventure.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "A6DB4B3A" + } + }, + { + "game": "Air-Sea Battle", + "filename": "Air-Sea_Battle.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "2A2A9F81" + } + }, + { + "game": "Asteroids", + "filename": "Asteroids.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 8192, + "crc": "70A59647" + } + }, + { + "game": "Backgammon", + "filename": "Backgammon.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "E2A7FFA6" + } + }, + { + "game": "Basic Math", + "filename": "Basic_Math.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "D48EBAC0" + } + }, + { + "game": "Basketball", + "filename": "Basketball.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "32F60182" + } + }, + { + "game": "Blackjack", + "filename": "Blackjack.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "4B0EE010" + } + }, + { + "game": "Bowling", + "filename": "Bowling.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "FEA0D6D5" + } + }, + { + "game": "Brain Games", + "filename": "Brain_Games.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "150709C2" + } + }, + { + "game": "Breakout", + "filename": "Breakout.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "3037638C" + } + }, + { + "game": "Canyon Bomber", + "filename": "Canyon_Bomber.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "E914B8CA" + } + }, + { + "game": "Casino", + "filename": "Casino.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "420B8248" + } + }, + { + "game": "Centipede", + "filename": "Centipede.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 8192, + "crc": "77396102" + } + }, + { + "game": "Championship Soccer", + "filename": "Championship_Soccer.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "3F59BB60" + } + }, + { + "game": "Checkers", + "filename": "Checkers.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "3DF33335" + } + }, + { + "game": "Chess", + "filename": "Chess.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "B6226A54" + } + }, + { + "game": "Circus Atari", + "filename": "Circus_Atari.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "D2A330A3" + } + }, + { + "game": "Codebreaker", + "filename": "Codebreaker.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "947EDB18" + } + }, + { + "game": "Combat", + "filename": "Combat.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "0D64A9C5" + } + }, + { + "game": "Combat 2", + "filename": "Combat_2.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 8192, + "crc": "8CABE1FD" + } + }, + { + "game": "Concentration", + "filename": "Concentration.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "17DE8070" + } + }, + { + "game": "Crystal Castles", + "filename": "Crystal_Castles.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 16384, + "crc": "9007B5AC" + } + }, + { + "game": "Demons to Diamonds", + "filename": "Demons_to_Diamonds.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "9B97C3DA" + } + }, + { + "game": "Desert Falcon", + "filename": "Desert_Falcon.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 16384, + "crc": "CAA0054E" + } + }, + { + "game": "Dodge Em", + "filename": "Dodge_Em.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "0C74479B" + } + }, + { + "game": "Double Dunk", + "filename": "Double_Dunk.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 16384, + "crc": "6112CBF5" + } + }, + { + "game": "Fatal Run", + "filename": "Fatal_Run.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 32768, + "crc": "826C2E3D" + } + }, + { + "game": "Flag Capture", + "filename": "Flag_Capture.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "8AA1C41E" + } + }, + { + "game": "Football", + "filename": "Football.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "3B73EE02" + } + }, + { + "game": "Golf", + "filename": "Golf.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "46A9F200" + } + }, + { + "game": "Gravitar", + "filename": "Gravitar.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 8192, + "crc": "C87FCCBE" + } + }, + { + "game": "Hangman", + "filename": "Hangman.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "C2BCC789" + } + }, + { + "game": "Haunted House", + "filename": "Haunted_House.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "AA62D961" + } + }, + { + "game": "Home Run", + "filename": "Home_Run.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "45ACE998" + } + }, + { + "game": "Human Cannonball", + "filename": "Human_Cannonball.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "F05A41E1" + } + }, + { + "game": "Maze Craze", + "filename": "Maze_Craze.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "0098E428" + } + }, + { + "game": "Millipede", + "filename": "Millipede.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 16384, + "crc": "CCC82DD0" + } + }, + { + "game": "Miniature Golf", + "filename": "Miniature_Golf.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "28562315" + } + }, + { + "game": "Missile Command", + "filename": "Missile_Command.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "CFF14904" + } + }, + { + "game": "Night Driver", + "filename": "Night_Driver.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "600D8A96" + } + }, + { + "game": "Off the Wall", + "filename": "Off_the_Wall.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 16384, + "crc": "E425A1CF" + } + }, + { + "game": "Outlaw", + "filename": "Outlaw.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "68DD7ACD" + } + }, + { + "game": "Quadrun", + "filename": "Quadrun.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 8192, + "crc": "A95CDD6F" + } + }, + { + "game": "Race", + "filename": "Race.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "B43DA2A3" + } + }, + { + "game": "Radar Lock", + "filename": "Radar_Lock.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 16384, + "crc": "C29F7285" + } + }, + { + "game": "RealSports Baseball", + "filename": "RealSports_Baseball.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 8192, + "crc": "3C5A1B5F" + } + }, + { + "game": "RealSports Basketball", + "filename": "RealSports_Basketball.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 8192, + "crc": "364FEAA6" + } + }, + { + "game": "RealSports Boxing", + "filename": "RealSports_Boxing.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 16384, + "crc": "3398A1B2" + } + }, + { + "game": "RealSports Football", + "filename": "RealSports_Football.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 8192, + "crc": "F89F64EF" + } + }, + { + "game": "RealSports Soccer", + "filename": "RealSports_Soccer.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 8192, + "crc": "02D89819" + } + }, + { + "game": "RealSports Tennis", + "filename": "RealSports_Tennis.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 8192, + "crc": "379001A0" + } + }, + { + "game": "RealSports Volleyball", + "filename": "RealSports_Volleyball.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "54FC9EB2" + } + }, + { + "game": "Return to Haunted House", + "filename": "Return_to_Haunted_House.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "95D29756" + } + }, + { + "game": "Save Mary", + "filename": "Save_Mary.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 16384, + "crc": "01E18F53" + } + }, + { + "game": "Secret Quest", + "filename": "Secret_Quest.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 16384, + "crc": "93C9EB47" + } + }, + { + "game": "Sentinel", + "filename": "Sentinel.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 16384, + "crc": "27ACC8A3" + } + }, + { + "game": "Sky Diver", + "filename": "Sky_Diver.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "00312EA9" + } + }, + { + "game": "Slot Machine", + "filename": "Slot_Machine.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "CB378D95" + } + }, + { + "game": "Slot Racers", + "filename": "Slot_Racers.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "177DBDF8" + } + }, + { + "game": "Space War", + "filename": "Space_War.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "65622F2A" + } + }, + { + "game": "Sprint Master", + "filename": "Sprint_Master.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 16384, + "crc": "C495904E" + } + }, + { + "game": "Star Raiders", + "filename": "Star_Raiders.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 8192, + "crc": "2AE193EE" + } + }, + { + "game": "Star Ship", + "filename": "Star_Ship.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "6609267E" + } + }, + { + "game": "Steeplechase", + "filename": "Steeplechase.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "5F6C32C3" + } + }, + { + "game": "Stellar Track", + "filename": "Stellar_Track.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "A76E93BF" + } + }, + { + "game": "Stunt Cycle", + "filename": "Stunt_Cycle.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "6354FF4C" + } + }, + { + "game": "Street Racer", + "filename": "Street_Racer.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "47592880" + } + }, + { + "game": "Submarine Commander", + "filename": "Submarine_Commander.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "3262960A" + } + }, + { + "game": "Super Baseball", + "filename": "Super_Baseball.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 16384, + "crc": "2245F170" + } + }, + { + "game": "Super Breakout", + "filename": "Super_Breakout.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "171DBE92" + } + }, + { + "game": "Super Football", + "filename": "Super_Football.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 16384, + "crc": "C9B16F3C" + } + }, + { + "game": "Surround", + "filename": "Surround.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "DCB11F23" + } + }, + { + "game": "Sword Quest Earthworld", + "filename": "Sword_Quest_Earthworld.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 8192, + "crc": "D5E21B79" + } + }, + { + "game": "Sword Quest Fireworld", + "filename": "Sword_Quest_Fireworld.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 8192, + "crc": "6AE46A0C" + } + }, + { + "game": "Sword Quest Waterworld", + "filename": "Sword_Quest_Waterworld.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 8192, + "crc": "CA7B4685" + } + }, + { + "game": "Tempest", + "filename": "Tempest.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 8192, + "crc": "E6DABC1B" + } + }, + { + "game": "Video Cube", + "filename": "Video_Cube.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "8172299E" + } + }, + { + "game": "Video Olympics", + "filename": "Video_Olympics.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "E4BC89C4" + } + }, + { + "game": "Video Pinball", + "filename": "Video_Pinball.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "10D95426" + } + }, + { + "game": "Warlords", + "filename": "Warlords.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "CF174B57" + } + }, + { + "game": "Yars Revenge", + "filename": "Yars_Revenge.a26", + "system": "Atari 2600", + "set": "2600", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "DFA1C825" + } + }, + { + "game": "Asteroids (5200)", + "filename": "Asteroids.a52", + "system": "Atari 5200", + "set": "5200", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 8192, + "crc": "38480891" + } + }, + { + "game": "Centipede (5200)", + "filename": "Centipede.a52", + "system": "Atari 5200", + "set": "5200", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 16384, + "crc": "536A70FE" + } + }, + { + "game": "Countermeasure (5200)", + "filename": "Countermeasure.a52", + "system": "Atari 5200", + "set": "5200", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 16384, + "crc": "FF7AF233" + } + }, + { + "game": "Millipede (5200)", + "filename": "Millipede.a52", + "system": "Atari 5200", + "set": "5200", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 16384, + "crc": "969CFE1A" + } + }, + { + "game": "Missile Command (5200)", + "filename": "Missile_Command.a52", + "system": "Atari 5200", + "set": "5200", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 8192, + "crc": "44D3FF6F" + } + }, + { + "game": "RealSports Baseball (5200)", + "filename": "RealSports_Baseball.a52", + "system": "Atari 5200", + "set": "5200", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 32768, + "crc": "44166592" + } + }, + { + "game": "RealSports Basketball (5200)", + "filename": "RealSports_Basketball.a52", + "system": "Atari 5200", + "set": "5200", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 32768, + "crc": "DD217276" + } + }, + { + "game": "RealSports Football (5200)", + "filename": "RealSports_Football.a52", + "system": "Atari 5200", + "set": "5200", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 16384, + "crc": "4336C2CC" + } + }, + { + "game": "RealSports Soccer (5200)", + "filename": "RealSports_Soccer.a52", + "system": "Atari 5200", + "set": "5200", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 16384, + "crc": "ECBD1853" + } + }, + { + "game": "RealSports Tennis (5200)", + "filename": "RealSports_Tennis.a52", + "system": "Atari 5200", + "set": "5200", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 16384, + "crc": "10F33C90" + } + }, + { + "game": "Star Raiders (5200)", + "filename": "Star_Raiders.a52", + "system": "Atari 5200", + "set": "5200", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 16384, + "crc": "7D819A9F" + } + }, + { + "game": "Super Breakout (5200)", + "filename": "Super_Breakout.a52", + "system": "Atari 5200", + "set": "5200", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "A0642110" + } + }, + { + "game": "Final Legacy (5200)", + "filename": "Final_Legacy.a52", + "system": "Atari 5200", + "set": "5200", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 16384, + "crc": "D3BD3221" + } + }, + { + "game": "Micro-Gammon (5200)", + "filename": "Micro-Gammon.a52", + "system": "Atari 5200", + "set": "5200", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 16384, + "crc": "931A454A" + } + }, + { + "game": "Miniature Golf (5200)", + "filename": "Miniature_Golf.a52", + "system": "Atari 5200", + "set": "5200", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 16384, + "crc": "C597C087" + } + }, + { + "game": "Xari Arena (5200)", + "filename": "Xari_Arena.a52", + "system": "Atari 5200", + "set": "5200", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 16384, + "crc": "B8FAAEC3" + } + }, + { + "game": "5200 BIOS (5200)", + "filename": "5200_BIOS.a52", + "system": "Atari 5200", + "set": "5200", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2048, + "crc": "4248D3E3" + } + }, + { + "game": "Air Raiders", + "filename": "Air_Raiders_MNetwork.a26", + "system": "Atari 2600", + "set": "MNetwork", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "BB16539D" + } + }, + { + "game": "Armor Ambush", + "filename": "Armor_Ambush_MNetwork.a26", + "system": "Atari 2600", + "set": "MNetwork", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "FC35704B" + } + }, + { + "game": "Astroblast", + "filename": "Astroblast_MNetwork.a26", + "system": "Atari 2600", + "set": "MNetwork", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "1DE25331" + } + }, + { + "game": "Dark Cavern", + "filename": "Dark_Cavern_MNetwork.a26", + "system": "Atari 2600", + "set": "MNetwork", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "0481078C" + } + }, + { + "game": "Frogs And Flies", + "filename": "Frogs_And_Flies_MNetwork.a26", + "system": "Atari 2600", + "set": "MNetwork", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "6476C136" + } + }, + { + "game": "International Soccer", + "filename": "International_Soccer_MNetwork.a26", + "system": "Atari 2600", + "set": "MNetwork", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "B9D549A2" + } + }, + { + "game": "Sea Battle", + "filename": "Sea_Battle_MNetwork.a26", + "system": "Atari 2600", + "set": "MNetwork", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "83B4EB19" + } + }, + { + "game": "Space Attack", + "filename": "Space_Attack_MNetwork.a26", + "system": "Atari 2600", + "set": "MNetwork", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "B34A3E57" + } + }, + { + "game": "Star Strike", + "filename": "Star_Strike_MNetwork.a26", + "system": "Atari 2600", + "set": "MNetwork", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "936A596D" + } + }, + { + "game": "Super Challenge Baseball", + "filename": "Super_Challenge_Baseball_MNetwork.a26", + "system": "Atari 2600", + "set": "MNetwork", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "F7E88EC2" + } + }, + { + "game": "Super Challenge Football", + "filename": "Super_Challenge_Football_MNetwork.a26", + "system": "Atari 2600", + "set": "MNetwork", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "55F02EFE" + } + }, + { + "game": "Swordfight", + "filename": "Swordfight_MNetwork.a26", + "system": "Atari 2600", + "set": "MNetwork", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "F1AD77BE" + } + }, + { + "game": "Adventure II", + "filename": "Adventure_II_Prototype.a26", + "system": "Atari 2600", + "set": "Prototype", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 8192, + "crc": "BFD846C5" + } + }, + { + "game": "Aquaventure", + "filename": "Aquaventure_Prototype.a26", + "system": "Atari 2600", + "set": "Prototype", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 8192, + "crc": "87A8CB8B" + } + }, + { + "game": "Frog Pond", + "filename": "Frog_Pond_Prototype.a26", + "system": "Atari 2600", + "set": "Prototype", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 8192, + "crc": "5874385A" + } + }, + { + "game": "Holey Moley", + "filename": "Holey_Moley_Prototype.a26", + "system": "Atari 2600", + "set": "Prototype", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 8192, + "crc": "3BB2E71D" + } + }, + { + "game": "Motorodeo", + "filename": "Motorodeo_Prototype.a26", + "system": "Atari 2600", + "set": "Prototype", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 16384, + "crc": "89998E29" + } + }, + { + "game": "Saboteur", + "filename": "Saboteur_Prototype.a26", + "system": "Atari 2600", + "set": "Prototype", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 8192, + "crc": "C359C13D" + } + }, + { + "game": "Wizard", + "filename": "Wizard_Prototype.a26", + "system": "Atari 2600", + "set": "Prototype", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4096, + "crc": "D2F5A554" + } + }, + { + "game": "Yars Return", + "filename": "Yars_Return_Prototype.a26", + "system": "Atari 2600", + "set": "Prototype", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 8192, + "crc": "DAF83348" + } + }, + { + "filename": "N/A", + "game": "Pong", + "system": "Arcade", + "set": "Arcade", + "notes": [4], + "status": "no-rom" + } + ], + "notes": { + "1": "Arcade ROMs require MAME 2003.", + "2": "This ROM has a CRC mismatch, but appears to work fine.", + "3": "This Arcade ROM is currently non-functional - too small, etc.", + "4": "This title uses TTL logic and does not have an associated ROM.", + "5": "This ROM cannot be extracted.", + "6": "The sprites and/or tiles for this ROM have been converted to bitmaps." + } + } +} \ No newline at end of file diff --git a/src/gex/lib/tasks/impl/atarivault/mnetwork.py b/src/gex/lib/tasks/impl/atarivault/mnetwork.py deleted file mode 100644 index 1892063..0000000 --- a/src/gex/lib/tasks/impl/atarivault/mnetwork.py +++ /dev/null @@ -1,72 +0,0 @@ -'''Extraction code for Atari 2600 MNetwork ROMs''' -import glob -import logging -import os -import shutil - -logger = logging.getLogger('gextoolbox') - -game_name_map = { - "airaidrs.bin": "Air Raiders", - "armambsh.bin": "Armor Ambush", - "astrblst.bin": "Astroblast", - "darkcvrn.bin": "Dark Cavern", - "frogflys.bin": "Frogs And Flies", - "pele_tw.bin": "International Soccer", - "seabattle.bin": "Sea Battle", - "spacattk.bin": "Space Attack", - "starstrk.bin": "Star Strike", - "suprbase.bin": "Super Challenge Baseball", - "suprfoot.bin": "Super Challenge Football", - "swordfight.bin": "Swordfight" -} - - -def _info_transform(game_name): - transformed_name = game_name.replace(" ", "") - return { - 'filename': f'{transformed_name}_MNetwork.a26', - 'name': game_name - } - - -game_info_map = {k: _info_transform(v) for k, v in game_name_map.items()} - - -def get_game_list(): - '''Transform the game map for documentation''' - return map(lambda x: { - 'filename': x['filename'], - 'game': f"{x['name']}", - 'system': "Atari 2600 (M Network)", - 'status': "playable", - "notes": []}, - game_info_map.values()) - - -def find_files(base_path): - '''Find the files this task supports''' - uncomp_rom_path = os.path.join( - base_path, "AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "vol3") - archive_list = glob.glob(uncomp_rom_path + '/*.*') - return archive_list - - -def copy(in_dir, out_dir): - '''Copy/rename MNetwork 2600 ROMs''' - rom_files = find_files(in_dir) - for file_path in rom_files: - file_name = os.path.basename(file_path) - game_info = game_info_map.get(file_name) - if game_info is not None: - display_name = game_info['name'] - logger.info( - f"Copying {file_name} to {game_info['filename']}: {display_name}") - try: - shutil.copyfile(file_path, os.path.join( - out_dir, game_info['filename'])) - except OSError as error: - logger.warning(f'Error while processing {file_path}!') - logger.warning(error) - else: - logger.debug(f'Skipping unmatched file {file_path}!') diff --git a/src/gex/lib/tasks/impl/atarivault/prototype2600.py b/src/gex/lib/tasks/impl/atarivault/prototype2600.py deleted file mode 100644 index 48ecb25..0000000 --- a/src/gex/lib/tasks/impl/atarivault/prototype2600.py +++ /dev/null @@ -1,68 +0,0 @@ -'''Extraction code for Atari 2600 Prototypes ROMs''' -import glob -import logging -import os -import shutil - -logger = logging.getLogger('gextoolbox') - -game_name_map = { - "adventureii.bin": "Adventure II", - "aquavent.bin": "Aquaventure", - "frog_pond_8_27_82.bin": "Frog Pond", - "holemole.bin": "Holey Moley", - "motorodeo_ntsc.bin": "Motorodeo", - "saboteur.bin": "Saboteur", - "wizard.bin": "Wizard", - "yarsreturn.bin": "Yars Return" -} - - -def _info_transform(game_name): - transformed_name = game_name.replace(" ", "") - return { - 'filename': f'{transformed_name}_Prototype.a26', - 'name': game_name - } - - -game_info_map = {k: _info_transform(v) for k, v in game_name_map.items()} - - -def get_game_list(): - '''Transform the game map for documentation''' - return map(lambda x: { - 'filename': x['filename'], - 'game': f"{x['name']}", - 'system': "Atari 2600 (Prototype)", - 'status': "playable", - "notes": []}, - game_info_map.values()) - - -def find_files(base_path): - '''Find the files this task supports''' - uncomp_rom_path = os.path.join( - base_path, "AtariVault_Data", "StreamingAssets", "FOCAL_Emulator", "vol3") - archive_list = glob.glob(uncomp_rom_path + '/*.*') - return archive_list - - -def copy(in_dir, out_dir): - '''Copy/rename Prototype 2600 ROMs''' - rom_files = find_files(in_dir) - for file_path in rom_files: - file_name = os.path.basename(file_path) - game_info = game_info_map.get(file_name) - if game_info is not None: - display_name = game_info['name'] - logger.info( - f"Copying {file_name} to {game_info['filename']}: {display_name}") - try: - shutil.copyfile(file_path, os.path.join( - out_dir, game_info['filename'])) - except OSError as error: - logger.warning(f'Error while processing {file_path}!') - logger.warning(error) - else: - logger.debug(f'Skipping unmatched file {file_path}!') diff --git a/src/gex/lib/tasks/impl/blizzarcade.py b/src/gex/lib/tasks/impl/blizzarcade.py deleted file mode 100644 index c6fbdb7..0000000 --- a/src/gex/lib/tasks/impl/blizzarcade.py +++ /dev/null @@ -1,133 +0,0 @@ -'''Implementation of blizzarcade: Blizzard Arcade Collection''' -import logging -import os -import shutil -from gex.lib.tasks.basetask import BaseTask - -logger = logging.getLogger('gextoolbox') - -class BlizzArcadeTask(BaseTask): - '''Implements blizzarcade: Blizzard Arcade Collection''' - _task_name = "blizzarcade" - _title = "Blizzard Arcade Collection" - _details_markdown = ''' -These are the ROMs just sitting in the assets/roms folder. -''' - _default_input_folder = r"C:\Program Files (x86)\Blizzard Arcade Collection" - _input_folder_desc = "Blizzard Arcade Collection install folder" - - _game_info_map = { - 'Blackthorne (U) (32X) [patched].32x': { - 'path': r'Sega\32X\Blackthorne (U) (32X) [patched].32x', - 'filename': 'Blackthorne_U_Patched.32x', - 'name': 'Blackthorne', - 'system': '32X' - }, - 'Blackthorne.bin': { - 'path': r'SNES\Blackthorne.bin', - 'filename': 'Blackthorne.sfc', - 'name': 'Blackthorne', - 'system': 'SNES' - }, - 'BlackthorneLZPatch.bin': { - 'path': r'SNES\BlackthorneLZPatch.bin', - 'filename': 'Blackthorne_ZPatch.sfc', - 'name': 'Blackthorne', - 'system': 'SNES', - 'version': 'Z-Patched' - }, - 'RockNRollRacing.bin': { - 'path': r'SNES\RockNRollRacing.bin', - 'filename': 'RockAndRollRacing.sfc', - 'name': 'Rock n Roll Racing', - 'system': 'SNES' - }, - "Rock n' Roll Racing (U) [_].bin": { - 'path': r"Sega\Genesis\Rock n' Roll Racing (U) [_].bin", - 'filename': 'RockAndRollRacing_U.bin', - 'name': 'Rock n Roll Racing', - 'system': 'Genesis' - }, - 'RockNRollRacingDefinitiveA.bin': { - 'path': r'SNES\RockNRollRacingDefinitiveA.bin', - 'filename': 'RockAndRollRacing_DefinitiveA.sfc', - 'name': 'Rock n Roll Racing', - 'system': 'SNES', - 'version': 'Definitive Edition A' - }, - 'RockNRollRacingDefinitiveB.bin': { - 'path': r'SNES\RockNRollRacingDefinitiveB.bin', - 'filename': 'RockAndRollRacing_DefinitiveB.sfc', - 'name': 'Rock n Roll Racing', - 'system': 'SNES', - 'version': 'Definitive Edition B' - }, - 'Lost Vikings, The (U) [_].bin': { - 'path': r'Sega\Genesis\Lost Vikings, The (U) [_].bin', - 'filename': 'LostVikings_U.bin', - 'name': 'The Lost Vikings', - 'system': 'Genesis' - }, - 'LostVikings.bin': { - 'path': r'SNES\LostVikings.bin', - 'filename': 'LostVikings.sfc', - 'name': 'The Lost Vikings', - 'system': 'SNES' - }, - 'LostVikingsDE.bin': { - 'path': r'SNES\LostVikingsDE.bin', - 'filename': 'LostVikings_Definitive.sfc', - 'name': 'The Lost Vikings', - 'system': 'SNES', - 'version': 'Definitive Edition' - }, - 'LostVikings2.bin': { - 'path': r'SNES\LostVikings2.bin', - 'filename': 'LostVikings2.sfc', - 'name': 'The Lost Vikings 2', - 'system': 'SNES' - }, - 'RadicalPsychoMachineRacing.bin': { - 'path': r'SNES\RadicalPsychoMachineRacing.bin', - 'filename': 'RadicalPsychoMachineRacing.sfc', - 'name': 'Radical Psycho Machine Racing', - 'system': 'SNES' - } - } - - def __init__(self): - super().__init__() - self._out_file_list = map(lambda x: { - 'filename': x['filename'], - 'game': x['name'], - 'status': "good", - 'system': x['system'], - "notes": []}, - self._game_info_map.values()) - - def _find_files(self, base_path): - new_paths = [] - for game_info in self._game_info_map.values(): - new_path = os.path.join(base_path, 'assets', 'roms', game_info['path']) - if os.path.exists(new_path): - new_paths.append(new_path) - else: - logging.warning(f"Could not find {game_info['path']} in {base_path}") - return new_paths - - def execute(self, in_dir, out_dir): - rom_files = self._find_files(in_dir) - for file_path in rom_files: - file_name = os.path.basename(file_path) - game_info = self._game_info_map.get(file_name) - if game_info is not None: - display_name = f"{game_info['name']} ({game_info['system']}{(' ' + game_info['version']) if game_info.get('version') else ''})" - logger.info(f"Copying {file_name}: {display_name}") - try: - shutil.copyfile(file_path, os.path.join(out_dir, game_info['filename'])) - except OSError as error: - logger.warning(f'Error while processing {file_path}!') - logger.warning(error) - else: - logger.info(f'Skipping unmatched file {file_path}!') - logger.info("Processing complete.") diff --git a/src/gex/lib/tasks/impl/blizzarcade/__init__.py b/src/gex/lib/tasks/impl/blizzarcade/__init__.py new file mode 100644 index 0000000..6347b81 --- /dev/null +++ b/src/gex/lib/tasks/impl/blizzarcade/__init__.py @@ -0,0 +1,13 @@ +'''Implementation of blizzarcade: Blizzard Arcade Collection''' +from gex.lib.tasks.copytask import CopyTask +from gex.lib.tasks import helpers + +class BubsyTask(CopyTask): + '''Implements blizzarcade: Blizzard Arcade Collection''' + _task_name = "blizzarcade" + _title = "Blizzard Arcade Collection" + _details_markdown = ''' +These are the ROMs just sitting in the install folder. + ''' + _default_input_folder = r"C:\Program Files (x86)\Blizzard Arcade Collection" + _input_folder_desc = "Blizzard Arcade Collection install folder" diff --git a/src/gex/lib/tasks/impl/blizzarcade/metadata.json b/src/gex/lib/tasks/impl/blizzarcade/metadata.json new file mode 100644 index 0000000..c4f01ff --- /dev/null +++ b/src/gex/lib/tasks/impl/blizzarcade/metadata.json @@ -0,0 +1,287 @@ +{ + "in": { + "files": { + "blackthorne32x": { + "rel_path": ["assets", "roms", "Sega", "32X"], + "filename": "Blackthorne (U) (32X) [patched].32x", + "copy_to": "Blackthorne (32X)", + "versions": { + "Battle.net": { + "crc": "BBA167E2", + "size": 3145728 + } + } + }, + "blackthornesnes": { + "rel_path": ["assets", "roms", "SNES"], + "filename": "Blackthorne.bin", + "copy_to": "Blackthorne (SNES)", + "versions": { + "Battle.net": { + "crc": "E8735614", + "size": 1048576 + } + } + }, + "blackthornezpatchsnes": { + "rel_path": ["assets", "roms", "SNES"], + "filename": "BlackthorneLZPatch.bin", + "copy_to": "Blackthorne Z-Patch (SNES)", + "versions": { + "Battle.net": { + "crc": "C5DBD672", + "size": 1048576 + } + } + }, + "lostvikingsgenesis": { + "rel_path": ["assets", "roms", "Sega", "Genesis"], + "filename": "Lost Vikings, The (U) [_].bin", + "copy_to": "Lost Vikings (Genesis)", + "versions": { + "Battle.net": { + "crc": "5CC41D7B", + "size": 1048576 + } + } + }, + "lostvikingssnes": { + "rel_path": ["assets", "roms", "SNES"], + "filename": "LostVikings.bin", + "copy_to": "Lost Vikings (SNES)", + "versions": { + "Battle.net": { + "crc": "DF7C313A", + "size": 1048576 + } + } + }, + "lostvikingsdesnes": { + "rel_path": ["assets", "roms", "SNES"], + "filename": "LostVikingsDE.bin", + "copy_to": "Lost Vikings Definitive Edition (SNES)", + "versions": { + "Battle.net": { + "crc": "894F8466", + "size": 2097152 + } + } + }, + "lostvikings2snes": { + "rel_path": ["assets", "roms", "SNES"], + "filename": "LostVikings2.bin", + "copy_to": "Lost Vikings 2 (SNES)", + "versions": { + "Battle.net": { + "crc": "FD18B3D1", + "size": 1048576 + } + } + }, + "rocknrollracinggenesis": { + "rel_path": ["assets", "roms", "Sega", "Genesis"], + "filename": "Rock n' Roll Racing (U) [_].bin", + "copy_to": "Rock n Roll Racing (Genesis)", + "versions": { + "Battle.net": { + "crc": "242AA285", + "size": 1048576 + } + } + }, + "rocknrollracingsnes": { + "rel_path": ["assets", "roms", "SNES"], + "filename": "RockNRollRacing.bin", + "copy_to": "Rock n Roll Racing (SNES)", + "versions": { + "Battle.net": { + "crc": "60A07658", + "size": 1048576 + } + } + }, + "rocknrollracingdeasnes": { + "rel_path": ["assets", "roms", "SNES"], + "filename": "RockNRollRacingDefinitiveA.bin", + "copy_to": "Rock n Roll Racing Definitive Edition (A) (SNES)", + "versions": { + "Battle.net": { + "crc": "B7DF9EB8", + "size": 1040384 + } + } + }, + "rocknrollracingdebsnes": { + "rel_path": ["assets", "roms", "SNES"], + "filename": "RockNRollRacingDefinitiveB.bin", + "copy_to": "Rock n Roll Racing Definitive Edition (B) (SNES)", + "versions": { + "Battle.net": { + "crc": "2A2D41AE", + "size": 1040384 + } + } + }, + "rpmracing": { + "rel_path": ["assets", "roms", "SNES"], + "filename": "RadicalPsychoMachineRacing.bin", + "copy_to": "Radical Psycho Machine Racing", + "versions": { + "Battle.net": { + "crc": "98BDED42", + "size": 524288 + } + } + } + } + }, + "out": { + "files": [ + { + "game": "Blackthorne (32X)", + "system": "32X", + "filename": "Blackthorne_U_Patched.32x", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "BBA167E2", + "size": 3145728 + } + }, + { + "game": "Blackthorne (SNES)", + "system": "SNES", + "filename": "Blackthorne.sfc", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "E8735614", + "size": 1048576 + } + }, + { + "game": "Blackthorne Z-Patch (SNES)", + "system": "SNES", + "filename": "Blackthorne_ZPatch.sfc", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "C5DBD672", + "size": 1048576 + } + }, + { + "game": "Lost Vikings (Genesis)", + "system": "Genesis", + "filename": "LostVikings_U.bin", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "5CC41D7B", + "size": 1048576 + } + }, + { + "game": "Lost Vikings (SNES)", + "system": "SNES", + "filename": "LostVikings.sfc", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "DF7C313A", + "size": 1048576 + } + }, + { + "game": "Lost Vikings Definitive Edition (SNES)", + "system": "SNES", + "filename": "LostVikings_Definitive.sfc", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "894F8466", + "size": 2097152 + } + }, + { + "game": "Lost Vikings 2 (SNES)", + "system": "SNES", + "filename": "LostVikings2.sfc", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "FD18B3D1", + "size": 1048576 + } + }, + { + "game": "Rock n Roll Racing (Genesis)", + "system": "Genesis", + "filename": "RockAndRollRacing_U.bin", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "242AA285", + "size": 1048576 + } + }, + { + "game": "Rock n Roll Racing (SNES)", + "system": "SNES", + "filename": "RockAndRollRacing.sfc", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "60A07658", + "size": 1048576 + } + }, + { + "game": "Rock n Roll Racing Definitive Edition (A) (SNES)", + "system": "SNES", + "filename": "RockAndRollRacing_DefinitiveA.sfc", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "B7DF9EB8", + "size": 1040384 + } + }, + { + "game": "Rock n Roll Racing Definitive Edition (B) (SNES)", + "system": "SNES", + "filename": "RockAndRollRacing_DefinitiveB.sfc", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "2A2D41AE", + "size": 1040384 + } + }, + { + "game": "Radical Psycho Machine Racing", + "system": "SNES", + "filename": "RadicalPsychoMachineRacing.sfc", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "98BDED42", + "size": 524288 + } + } + ], + "notes": {} + } +} \ No newline at end of file diff --git a/src/gex/lib/tasks/impl/bubsy.py b/src/gex/lib/tasks/impl/bubsy.py deleted file mode 100644 index e90e352..0000000 --- a/src/gex/lib/tasks/impl/bubsy.py +++ /dev/null @@ -1,66 +0,0 @@ -'''Implementation of bubsy: Bubsy Two-Fur''' -import shutil -import logging -import os -from gex.lib.tasks.basetask import BaseTask -from gex.lib.tasks import helpers - -logger = logging.getLogger('gextoolbox') - -class BubsyTask(BaseTask): - '''Implements bubsy: Bubsy Two-Fur''' - _task_name = "bubsy" - _title = "Bubsy Two-Fur" - _details_markdown = ''' -These are the ROMs just sitting in the install folder. - ''' - _default_input_folder = helpers.gen_steam_app_default_folder("Bubsy Two-Fur") - _input_folder_desc = "Bubsy Two-Fur Steam Folder" - - _game_info_map = { - 'bubsy_1': { - 'filename': 'Bubsy.sfc', - 'name': 'Bubsy' - }, - 'bubsy_2': { - 'filename': 'Bubsy2.sfc', - 'name': 'Bubsy 2' - } - } - - def __init__(self): - super().__init__() - self._out_file_list = map(lambda x: { - 'filename': x['filename'], - 'game': x['name'], - 'status': "good", - 'system': "SNES", - "notes": []}, - self._game_info_map.values()) - - def _find_files(self, base_path): - new_paths = [] - for filename in self._game_info_map: - new_path = os.path.join(base_path, filename) - if os.path.exists(new_path): - new_paths.append(new_path) - else: - logging.warning(f"Could not find {filename} in {base_path}") - return new_paths - - def execute(self, in_dir, out_dir): - rom_files = self._find_files(in_dir) - for file_path in rom_files: - file_name = os.path.basename(file_path) - game_info = self._game_info_map.get(file_name) - if game_info is not None: - display_name = game_info['name'] - logger.info(f"Copying {file_name}: {display_name}") - try: - shutil.copyfile(file_path, os.path.join(out_dir, game_info['filename'])) - except OSError as error: - logger.warning(f'Error while processing {file_path}!') - logger.warning(error) - else: - logger.info(f'Skipping unmatched file {file_path}!') - logger.info("Processing complete.") diff --git a/src/gex/lib/tasks/impl/bubsy/__init__.py b/src/gex/lib/tasks/impl/bubsy/__init__.py new file mode 100644 index 0000000..6c6b8ea --- /dev/null +++ b/src/gex/lib/tasks/impl/bubsy/__init__.py @@ -0,0 +1,13 @@ +'''Implementation of bubsy: Bubsy Two-Fur''' +from gex.lib.tasks.copytask import CopyTask +from gex.lib.tasks import helpers + +class BubsyTask(CopyTask): + '''Implements bubsy: Bubsy Two-Fur''' + _task_name = "bubsy" + _title = "Bubsy Two-Fur" + _details_markdown = ''' +These are the ROMs just sitting in the install folder. + ''' + _default_input_folder = helpers.gen_steam_app_default_folder("Bubsy Two-Fur") + _input_folder_desc = "Bubsy Two-Fur Steam Folder" diff --git a/src/gex/lib/tasks/impl/bubsy/metadata.json b/src/gex/lib/tasks/impl/bubsy/metadata.json new file mode 100644 index 0000000..281ab61 --- /dev/null +++ b/src/gex/lib/tasks/impl/bubsy/metadata.json @@ -0,0 +1,55 @@ +{ + "in": { + "files": { + "bubsy": { + "filename": "bubsy_1", + "copy_to": "Bubsy", + "versions": { + "Steam": { + "crc": "C19F0876", + "size": 2097152 + } + } + }, + "bubsy2" : { + "filename": "bubsy_2", + "copy_to": "Bubsy 2", + "versions": { + "Steam": { + "crc": "9582F89F", + "size": 2097152 + } + } + } + } + }, + "out": { + "files": [ + { + "game": "Bubsy", + "system": "SNES", + "filename": "Bubsy.sfc", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "C19F0876", + "size": 2097152 + } + }, + { + "game": "Bubsy 2", + "system": "SNES", + "filename": "Bubsy2.sfc", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "9582F89F", + "size": 2097152 + } + } + ], + "notes": {} + } +} \ No newline at end of file diff --git a/src/gex/lib/tasks/impl/cas1.py b/src/gex/lib/tasks/impl/cas1/__init__.py similarity index 64% rename from src/gex/lib/tasks/impl/cas1.py rename to src/gex/lib/tasks/impl/cas1/__init__.py index 68d8917..f947aa6 100644 --- a/src/gex/lib/tasks/impl/cas1.py +++ b/src/gex/lib/tasks/impl/cas1/__init__.py @@ -29,17 +29,52 @@ class CAS1Task(BaseTask): These appear to be KPKA archives, and it is reasonably certain that the extraction is correct, as most files have a 3-4 character allcaps header indicating file type. Note that the file order can differ between KPKA files; the size and header bytes are best used for identification. -#### Example KPKA (1556708) - - 1556708_0_1957557.dat - One of the ROM packages - - 1556708_1_331.dat - has '.psb' at the beginning, but does not appear to be a valid M2 MArchive/PSB Archive - - 1556708_2_1976307.dat - One of the ROM packages - - 1556708_3_150.dat - Small MAME file describing ROM name? - - 1556708_4_138.dat - Small file of null bytes - - 1556708_5_667.dat - SCN file - Scene description? - - 1556708_6_3828.dat - Moderate MMAC file listing ROM file names and possible keys? - - 1556708_7_26.dat - Very small MMAC file - -### PSB +### File Types +It's more effective to actually categorize the files. + +#### ROM Data (New Only) + - Has no header + - Large (very similar to the extracted ZIP file sizes, but slightly smaller - perhaps diff compression) + - 1-2 per PAK (typically 2, but only 1 if the game didn't have a US release) + - Is this an encrypted version of the PKZIP file? + +#### Very Small MMAC + - MMAC Header + - Always 26 bytes + - 1-2 per PAK (does not necessarily match the number of ROM Data packages) + +#### Moderate MMAC + - MMAC Header + - Typically a couple K in size + +#### 'MAME' file + - MAME header + - Typically less than 1K + - Some internal paths, some also mention DSW1/DSW2 - could these be DIP Switches? + - Like a MAME engine config file for the ROM, to tell it MAME driver name, etc.? + +#### SCN + - SCN Header + - Typically less than 1K + - RE Engine Scene Description? + - Has paths for other related files + +#### PSB + - '.psb' header + - Always 331 bytes + - CAS1 - all PSBs are the same + - CAS2 - no per-pak PSB, 1 in the main archive + - CAS1 and CAS2 a little different + - 0x31-0x35 - 5 bytes + - 0x3A-0x46 - 13 bytes + - 0x6F-0x82 - 20 bytes + - 38/331 bytes - about 11% + +#### PKZIP (Old Depot Only) + - 'PK' Header + - Appears to be a standard ZIP file with the ROM + +##### Diff vs. M2 PSB In the example above, 1556708_1_331.dat appears to have ".psb" at the beginning; however, this doesn't match what we know about the PSB filetype. - If this was an uncompressed PSB file, we would expect the first three bytes to be "PSB" - If this were a compressed PSB file, we would expect the first three bytes to be a compression type indicator, like "mdf" @@ -50,6 +85,29 @@ class CAS1Task(BaseTask): For CAS1, every '.psb' file is identical. CAS2 does not have these '.psb' files (at least in the per-DLC packages). However, there is a '.psb' file in the main package (look for the 331 byte file size/file 1888). It is definitely different than the CAS1 PSB, but only about 30% of the file is changed. (0x30-0x47, 0x6F-0x81) + +### Examples +#### Example 1 - (1556708) + - 1556708_0_1957557.dat - One of the ROM packages + - 1556708_1_331.dat - has '.psb' at the beginning, but does not appear to be a valid M2 MArchive/PSB Archive + - 1556708_2_1976307.dat - One of the ROM packages + - 1556708_3_150.dat - Small MAME file describing ROM name? + - 1556708_4_138.dat - Small file of null bytes + - 1556708_5_667.dat - SCN file - Scene description? + - 1556708_6_3828.dat - Moderate MMAC file listing ROM file names and possible keys? + - 1556708_7_26.dat - Very small MMAC file + +#### Example 2 - 1556700 (Vulgus) +| Old | New | Info | +|--------------------|---------------------|-----------------------------------------------------------------| +| 1_346.dat | 1_346.dat | MAME file; both 346 bytes, identical, for 'vulgus', has DSWs | +| 6_134.dat | 7_134.dat | MAME file; both 134 bytes, identical, for 'vulgusj' | +| 4_26.dat | 5_26.dat | Very Small MMAC; Both 26 bytes, 1 byte diff (0x08) | +| 0_14.dat | 0_26.dat | Very Small MMAC; 14 vs 26 bytes | +| 5_655.dat | 6_655.dat | SCN file; Both 655 bytes, identical | +| N/A | 3_331.dat | '.psb' file; only in new | +| 2_71436.dat | 2_70421.dat | PK vs ??? file, guessing via size and orig this is vulgusj | +| 3_71071.dat | 4_70123.dat | PK vs ??? file, guessing via size and orig this is vulgus | ''' _out_file_list = [ ] @@ -77,11 +135,12 @@ def execute(self, in_dir, out_dir): file_id = None filename = os.path.basename(file) if "patch" in filename: - logger.info(f"Skipping patch file {filename}") + # logger.info(f"Skipping patch file {filename}") + file_id = "patch" elif filename == "re_chunk_000.pak": - file_id = "1515951" + file_id = "chunk" else: - file_id = file[-11:-4] + file_id = file.split(".")[0].split("_")[-1] logger.info(f"Extracting {file}: {file_id}") try: diff --git a/src/gex/lib/tasks/impl/cas2.py b/src/gex/lib/tasks/impl/cas2/__init__.py similarity index 100% rename from src/gex/lib/tasks/impl/cas2.py rename to src/gex/lib/tasks/impl/cas2/__init__.py diff --git a/src/gex/lib/tasks/impl/cbeub/__init__.py b/src/gex/lib/tasks/impl/cbeub/__init__.py index bf30ff6..d9db8b2 100644 --- a/src/gex/lib/tasks/impl/cbeub/__init__.py +++ b/src/gex/lib/tasks/impl/cbeub/__init__.py @@ -1,6 +1,4 @@ '''Implementation of cbeub: Capcom Beat 'em Up Bundle''' -import re -import glob import logging import os @@ -22,178 +20,55 @@ class CBEUBTask(BaseTask): This was a Japanese set of shell scripts and odd generic operation executables. There is some weird encoding here too. This script will extract and prep the ROMs. Some per-rom errata are in the notes below. ''' - _out_file_list = [ - { - "game": "Final Fight (U)", - "system": "Arcade", - "filename": "ffight.zip", - "status": "playable", - "notes": [2] - }, - { - "game": "Final Fight (J)", - "system": "Arcade", - "filename": "ffightj.zip", - "status": "playable", - "notes": [2] - }, - { - "game": "King of Dragons (U)", - "system": "Arcade", - "filename": "kod.zip", - "status": "playable", - "notes": [2] - }, - { - "game": "King of Dragons (J)", - "system": "Arcade", - "filename": "kodf.zip", - "status": "playable", - "notes": [2] - }, - { - "game": "Captain Commando (U)", - "system": "Arcade", - "filename": "captcomm.zip", - "status": "playable", - "notes": [2, 3] - }, - { - "game": "Captain Commando (J)", - "system": "Arcade", - "filename": "captcommj.zip", - "status": "playable", - "notes": [2, 3] - }, - { - "game": "Knights of the Round (U)", - "system": "Arcade", - "filename": "knights.zip", - "status": "playable", - "notes": [2] - }, - { - "game": "Knights of the Round (J)", - "system": "Arcade", - "filename": "knightsj.zip", - "status": "playable", - "notes": [2] - }, - { - "game": "Warriors of Fate (U)", - "system": "Arcade", - "filename": "wof.zip", - "status": "playable", - "notes": [2, 4] - }, - { - "game": "Warriors of Fate (J)", - "system": "Arcade", - "filename": "wofj.zip", - "status": "playable", - "notes": [2, 4] - }, - { - "game": "Powered Gear (U)", - "system": "Arcade", - "filename": "pgear.zip", - "status": "playable", - "notes": [1] - }, - { - "game": "Powered Gear (J)", - "system": "Arcade", - "filename": "armwar.zip", - "status": "playable", - "notes": [1] - }, - { - "game": "Battle Circuit (U)", - "system": "Arcade", - "filename": "batcir.zip", - "status": "playable", - "notes": [1] - }, - { - "game": "Battle Circuit (J)", - "system": "Arcade", - "filename": "batcirj.zip", - "status": "playable", - "notes": [1] - } - ] - - _out_file_notes = { - "1": "These ROMs require an older version MAME. They test fine in MAME 0.139 (Mame 2010 in RetroArch). This is typically due to a missing decryption key, dl-1425.bin qsound rom, or other ROM files that the older MAME did not strictly require", - "2": "These ROMs play fine, even in the current MAME, despite the bad CRCs. The bad CRCs are small ancillary files that aren't strictly required or included, but stubbed out to pass checks. ", - "3": "The JP version of this ROM is fine in modern MAME 0.246; the English version needs 0.139", - "4": "The Audio CPU ROM for this is not present in the expected format. Further investigation required." - } + _default_input_folder = helpers.gen_steam_app_default_folder("CBEUB") _input_folder_desc = "CBEUB Steam folder" - def execute(self, in_dir, out_dir): - pak_files = self._find_files(in_dir) - for file_path in pak_files: - file_name = os.path.basename(file_path) - pkg_name = self._pkg_name_map[file_name] - logger.info(f"Extracting {file_name}: {pkg_name}") - try: - with open(file_path, "rb") as curr_file: - file_content = bytearray(curr_file.read()) - arc_contents = arc.extract(file_content) - output_files = [] - - # Get the bin entry - merged_rom_contents = None - for _, arc_content in arc_contents.items(): - if arc_content['path'].startswith('bin'): - merged_rom_contents = arc_content['contents'] - - handler_func = self.find_handler_func(pkg_name) - if merged_rom_contents is not None and handler_func is not None: - output_files = handler_func(merged_rom_contents) - for output_file in output_files: - out_path = os.path.join(out_dir, output_file['filename']) - with open(out_path, "wb") as out_file: - out_file.write(output_file['contents']) - elif merged_rom_contents is None: - logger.warning( - "Could not find merged rom data in arc.") - elif handler_func is None: - logger.warning( - "Could not find matching handler function.") - except Exception as _: - logger.warning(f'Error while processing {file_path}!') + def get_out_file_info(self): + '''Return a list of output files''' + return { + "files": self._metadata['out']['files'], + "notes": self._metadata['out']['notes'] + } + def execute(self, in_dir, out_dir): + # for each output file entry + for out_file_entry in self._metadata['out']['files']: + pkg_name = out_file_entry['in_file'] + # Check the status of it + if out_file_entry['status'] == 'no-rom': + logger.info(f"Skipping {pkg_name} - cannot extract...") + else: + logger.info(f"Extracting {pkg_name}...") + + # read the matching input file + in_file_entry = self._metadata['in']['files'][pkg_name] + loaded_file = self.read_datafile(in_dir, in_file_entry) + + # extract the input file + arc_contents = arc.extract(loaded_file['contents']) + + # Get the bin entry + merged_rom_contents = None + for _, arc_content in arc_contents.items(): + if arc_content['path'].startswith('bin'): + merged_rom_contents = arc_content['contents'] + + # run the handler + handler_func = self.find_handler_func(pkg_name) + if merged_rom_contents is not None and handler_func is not None: + output_contents = handler_func(merged_rom_contents) + + _ = self.verify_out_file(out_file_entry['filename'], output_contents) + + with open(os.path.join(out_dir, out_file_entry['filename']), "wb") as out_file: + out_file.write(output_contents) + elif merged_rom_contents is None: + logger.warning("Could not find merged rom data in arc.") + elif handler_func is None: + logger.warning("Could not find matching handler function.") logger.info("Processing complete.") - _pkg_name_map = { - "game_00.arc": "ffightj", - "game_01.arc": "ffight", - "game_10.arc": "kodj", - "game_11.arc": "kod", - "game_20.arc": "captcommj", - "game_21.arc": "captcomm", - "game_30.arc": "knightsj", - "game_31.arc": "knights", - "game_40.arc": "wofj", - "game_41.arc": "wof", - "game_50.arc": "pgear", - "game_51.arc": "armwar", - "game_60.arc": "batcirj", - "game_61.arc": "batcir", - } - - def _find_files(self, base_path): - arc_path = os.path.join(base_path, "nativeDX11x64", "arc") - candidate_files = glob.glob(arc_path + '/game_*.arc') - archive_list = [] - for candidate in candidate_files: - if re.search(r'game_\d\d.arc', candidate): - archive_list.append(candidate) - return archive_list - def _deshuffle_gfx_common(self, start, length, filenames, num_deinterleave_split, do_split): def gfx(contents): # Cut out the section @@ -246,7 +121,6 @@ def audio(contents): ################################################################################ def _handle_ffight(self, merged_contents): - out_files = [] func_map = {} maincpu_filenames = [ @@ -301,13 +175,9 @@ def maincpu(contents): } func_map['placeholders'] = helpers.placeholder_helper(ph_files) - zip_contents = helpers.build_rom(merged_contents, func_map) - out_files.append({'filename': 'ffight.zip', 'contents': zip_contents}) - - return out_files + return helpers.build_rom(merged_contents, func_map) def _handle_ffightj(self, merged_contents): - out_files = [] func_map = {} maincpu_filenames = [ @@ -371,16 +241,13 @@ def maincpu(contents): } func_map['placeholders'] = helpers.placeholder_helper(ph_files) - zip_contents = helpers.build_rom(merged_contents, func_map) - out_files.append({'filename': 'ffightj.zip', 'contents': zip_contents}) - return out_files + return helpers.build_rom(merged_contents, func_map) ################################################################################ # The King of Dragons # ################################################################################ def _handle_kod(self, merged_contents): - out_files = [] func_map = {} maincpu_filenames = [ @@ -440,13 +307,9 @@ def maincpu(contents): } func_map['placeholders'] = helpers.placeholder_helper(ph_files) - zip_contents = helpers.build_rom(merged_contents, func_map) - out_files.append({'filename': 'kod.zip', 'contents': zip_contents}) - - return out_files + return helpers.build_rom(merged_contents, func_map) def _handle_kodj(self, merged_contents): - out_files = [] func_map = {} maincpu_filenames = [ @@ -506,16 +369,13 @@ def maincpu(contents): } func_map['placeholders'] = helpers.placeholder_helper(ph_files) - zip_contents = helpers.build_rom(merged_contents, func_map) - out_files.append({'filename': 'kodj.zip', 'contents': zip_contents}) - return out_files + return helpers.build_rom(merged_contents, func_map) ################################################################################ # Captain Commando # ################################################################################ def _handle_captcomm(self, merged_contents): - out_files = [] func_map = {} maincpu_filenames = [ @@ -572,14 +432,9 @@ def maincpu(contents): } func_map['placeholders'] = helpers.placeholder_helper(ph_files) - zip_contents = helpers.build_rom(merged_contents, func_map) - out_files.append( - {'filename': 'captcomm.zip', 'contents': zip_contents} - ) - return out_files + return helpers.build_rom(merged_contents, func_map) def _handle_captcommj(self, merged_contents): - out_files = [] func_map = {} maincpu_filenames = [ @@ -638,18 +493,13 @@ def maincpu(contents): } func_map['placeholders'] = helpers.placeholder_helper(ph_files) - zip_contents = helpers.build_rom(merged_contents, func_map) - out_files.append( - {'filename': 'captcommj.zip', 'contents': zip_contents}) - - return out_files + return helpers.build_rom(merged_contents, func_map) ################################################################################ # Knights of the Round # ################################################################################ def _handle_knights(self, merged_contents): - out_files = [] func_map = {} maincpu_filenames = [ @@ -699,13 +549,9 @@ def maincpu(contents): } func_map['placeholders'] = helpers.placeholder_helper(ph_files) - zip_contents = helpers.build_rom(merged_contents, func_map) - out_files.append({'filename': 'knights.zip', 'contents': zip_contents}) - - return out_files + return helpers.build_rom(merged_contents, func_map) def _handle_knightsj(self, merged_contents): - out_files = [] func_map = {} maincpu_filenames = [ @@ -755,11 +601,7 @@ def maincpu(contents): } func_map['placeholders'] = helpers.placeholder_helper(ph_files) - zip_contents = helpers.build_rom(merged_contents, func_map) - out_files.append( - {'filename': 'knightsj.zip', 'contents': zip_contents}) - - return out_files + return helpers.build_rom(merged_contents, func_map) ################################################################################ # Warriors of Fate # @@ -785,7 +627,6 @@ def audio(contents): return audio def _handle_wof(self, merged_contents): - out_files = [] func_map = {} maincpu_filenames = [ @@ -839,13 +680,9 @@ def maincpu(contents): } func_map['placeholders'] = helpers.placeholder_helper(ph_files) - zip_contents = helpers.build_rom(merged_contents, func_map) - out_files.append({'filename': 'wof.zip', 'contents': zip_contents}) - - return out_files + return helpers.build_rom(merged_contents, func_map) def _handle_wofj(self, merged_contents): - out_files = [] func_map = {} maincpu_filenames = [ @@ -900,10 +737,7 @@ def maincpu(contents): } func_map['placeholders'] = helpers.placeholder_helper(ph_files) - zip_contents = helpers.build_rom(merged_contents, func_map) - out_files.append({'filename': 'wofj.zip', 'contents': zip_contents}) - - return out_files + return helpers.build_rom(merged_contents, func_map) ################################################################################ # Armored Warriors # @@ -966,7 +800,6 @@ def _armwar_qsound(self, contents): return dict(zip(filenames, chunks)) def _handle_armwar(self, merged_contents): - out_files = [] def maincpu(contents): contents = contents[0x40:0x400040] @@ -987,12 +820,10 @@ def maincpu(contents): func_map['gfx'] = self._armwar_gfx func_map['audiocpu'] = self._armwar_audio func_map['qsound'] = self._armwar_qsound - out_files.append({'filename': 'armwar.zip', 'contents': helpers.build_rom( - merged_contents, func_map)}) - return out_files + + return helpers.build_rom(merged_contents, func_map) def _handle_pgear(self, merged_contents): - out_files = [] def maincpu(contents): contents = contents[0x40:0x400040] @@ -1013,9 +844,8 @@ def maincpu(contents): func_map['gfx'] = self._armwar_gfx func_map['audiocpu'] = self._armwar_audio func_map['qsound'] = self._armwar_qsound - out_files.append({'filename': 'pgear.zip', 'contents': helpers.build_rom( - merged_contents, func_map)}) - return out_files + + return helpers.build_rom(merged_contents, func_map) ################################################################################ # Battle Circuit # @@ -1069,7 +899,6 @@ def _batcir_qsound(self, contents): return dict(zip(filenames, chunks)) def _handle_batcir(self, merged_contents): - out_files = [] def maincpu(contents): contents = contents[0x40:0x380040] @@ -1089,12 +918,10 @@ def maincpu(contents): func_map['gfx'] = self._batcir_gfx func_map['audiocpu'] = self._batcir_audio func_map['qsound'] = self._batcir_qsound - out_files.append({'filename': 'batcir.zip', 'contents': helpers.build_rom( - merged_contents, func_map)}) - return out_files + + return helpers.build_rom(merged_contents, func_map) def _handle_batcirj(self, merged_contents): - out_files = [] def maincpu(contents): contents = contents[0x40:0x380040] @@ -1114,6 +941,5 @@ def maincpu(contents): func_map['gfx'] = self._batcir_gfx func_map['audiocpu'] = self._batcir_audio func_map['qsound'] = self._batcir_qsound - out_files.append({'filename': 'batcirj.zip', 'contents': helpers.build_rom( - merged_contents, func_map)}) - return out_files + + return helpers.build_rom(merged_contents, func_map) diff --git a/src/gex/lib/tasks/impl/cbeub/metadata.json b/src/gex/lib/tasks/impl/cbeub/metadata.json new file mode 100644 index 0000000..0161eb0 --- /dev/null +++ b/src/gex/lib/tasks/impl/cbeub/metadata.json @@ -0,0 +1,665 @@ +{ + "in": { + "files": { + "ffightj": { + "rel_path": ["nativeDX11x64", "arc"], + "filename": "game_00.arc", + "versions": { + "Steam": { + "size": 1320360, + "crc": "AA975CFE" + } + } + }, + "ffight": { + "rel_path": ["nativeDX11x64", "arc"], + "filename": "game_01.arc", + "versions": { + "Steam": { + "size": 1319839, + "crc": "DD55F271" + } + } + }, + "kodj": { + "rel_path": ["nativeDX11x64", "arc"], + "filename": "game_10.arc", + "versions": { + "Steam": { + "size": 2105638, + "crc": "82B472CF" + } + } + }, + "kod": { + "rel_path": ["nativeDX11x64", "arc"], + "filename": "game_11.arc", + "versions": { + "Steam": { + "size": 2105639, + "crc": "03FD238D" + } + } + }, + "captcommj": { + "rel_path": ["nativeDX11x64", "arc"], + "filename": "game_20.arc", + "versions": { + "Steam": { + "size": 2327988, + "crc": "CB7601D4" + } + } + }, + "captcomm": { + "rel_path": ["nativeDX11x64", "arc"], + "filename": "game_21.arc", + "versions": { + "Steam": { + "size": 2327989, + "crc": "1CFCBB3B" + } + } + }, + "knightsj": { + "rel_path": ["nativeDX11x64", "arc"], + "filename": "game_30.arc", + "versions": { + "Steam": { + "size": 2160669, + "crc": "A75849E0" + } + } + }, + "knights": { + "rel_path": ["nativeDX11x64", "arc"], + "filename": "game_31.arc", + "versions": { + "Steam": { + "size": 2160706, + "crc": "7149E39A" + } + } + }, + "wofj": { + "rel_path": ["nativeDX11x64", "arc"], + "filename": "game_40.arc", + "versions": { + "Steam": { + "size": 3732432, + "crc": "96B1F3E9" + } + } + }, + "wof": { + "rel_path": ["nativeDX11x64", "arc"], + "filename": "game_41.arc", + "versions": { + "Steam": { + "size": 3730773, + "crc": "85A1E964" + } + } + }, + "pgear": { + "rel_path": ["nativeDX11x64", "arc"], + "filename": "game_50.arc", + "versions": { + "Steam": { + "size": 13697509, + "crc": "E1AA4F63" + } + } + }, + "armwar": { + "rel_path": ["nativeDX11x64", "arc"], + "filename": "game_51.arc", + "versions": { + "Steam": { + "size": 13807321, + "crc": "27CF4C63" + } + } + }, + "batcirj": { + "rel_path": ["nativeDX11x64", "arc"], + "filename": "game_60.arc", + "versions": { + "Steam": { + "size": 11067807, + "crc": "473FE92A" + } + } + }, + "batcir": { + "rel_path": ["nativeDX11x64", "arc"], + "filename": "game_61.arc", + "versions": { + "Steam": { + "size": 11067778, + "crc": "ED5DA76A" + } + } + } + } + }, + "out": { + "files": [ + { + "game": "Final Fight (U)", + "system": "Arcade", + "filename": "ffight.zip", + "in_file": "ffight", + "status": "playable", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "ff_42.11h": {"size": 131072, "crc": "65F11215"}, + "ffe_43.12h": {"size": 131072, "crc": "995E968A"}, + "ff_36.11f": {"size": 131072, "crc": "F9A5CE83"}, + "ff_37.12f": {"size": 131072, "crc": "E1033784"}, + "ff-32m.8h": {"size": 524288, "crc": "C747696E"}, + "ff-5m.7a": {"size": 524288, "crc": "9C284108"}, + "ff-7m.9a": {"size": 524288, "crc": "A7584DFB"}, + "ff-1m.3a": {"size": 524288, "crc": "0B605E44"}, + "ff-3m.5a": {"size": 524288, "crc": "52291CD2"}, + "ff_09.12b": {"size": 65536, "crc": "B8367EB5"}, + "ff_18.11c": {"size": 131072, "crc": "375C66E7"}, + "ff_19.12c": {"size": 131072, "crc": "1EF137F9"}, + "buf1": {"size": 279, "crc": "4BFEC235"}, + "ioa1": {"size": 279, "crc": "4BFEC235"}, + "prg1": {"size": 279, "crc": "4BFEC235"}, + "rom1": {"size": 279, "crc": "4BFEC235"}, + "sou1": {"size": 279, "crc": "4BFEC235"}, + "s224b.1a": {"size": 279, "crc": "4BFEC235"}, + "iob1.11e": {"size": 279, "crc": "4BFEC235"} + } + } + }, + { + "game": "Final Fight (J)", + "system": "Arcade", + "filename": "ffightj.zip", + "in_file": "ffightj", + "status": "playable", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "ff42.bin": {"size": 131072, "crc": "65F11215"}, + "ff43.bin": {"size": 131072, "crc": "B6DEE1C3"}, + "ffj_40.10h": {"size": 131072, "crc": "8075BAB9"}, + "ffj_41.11h": {"size": 131072, "crc": "2AF68154"}, + "ff36.bin": {"size": 131072, "crc": "F9A5CE83"}, + "ff37.bin": {"size": 131072, "crc": "E1033784"}, + "ffj_34.10f": {"size": 131072, "crc": "0C8DC3FC"}, + "ffj_35.11f": {"size": 131072, "crc": "4A934121"}, + "ffj_09.4b": {"size": 131072, "crc": "5B116D0D"}, + "ffj_10.5b": {"size": 131072, "crc": "624A924A"}, + "ffj_01.4a": {"size": 131072, "crc": "815B1797"}, + "ffj_02.5a": {"size": 131072, "crc": "5D91F694"}, + "ffj_13.9b": {"size": 131072, "crc": "8721A7DA"}, + "ffj_14.10b": {"size": 131072, "crc": "0A2E9101"}, + "ffj_05.9a": {"size": 131072, "crc": "D0FCD4B5"}, + "ffj_06.10a": {"size": 131072, "crc": "1C18F042"}, + "ffj_24.5e": {"size": 131072, "crc": "A1AB607A"}, + "ffj_25.7e": {"size": 131072, "crc": "6E8181EA"}, + "ffj_17.5c": {"size": 131072, "crc": "2DC18CF4"}, + "ffj_18.7c": {"size": 131072, "crc": "B19EDE59"}, + "ffj_38.8h": {"size": 131072, "crc": "6535A57F"}, + "ffj_39.9h": {"size": 131072, "crc": "9416B477"}, + "ffj_32.8f": {"size": 131072, "crc": "C8BC4A57"}, + "ffj_33.9f": {"size": 131072, "crc": "7369FA07"}, + "ff_23.bin": {"size": 65536, "crc": "B8367EB5"}, + "ffj_30.bin": {"size": 131072, "crc": "375C66E7"}, + "ffj_31.bin": {"size": 131072, "crc": "1EF137F9"}, + "buf1": {"size": 279, "crc": "4BFEC235"}, + "ioa1": {"size": 279, "crc": "4BFEC235"}, + "prg1": {"size": 279, "crc": "4BFEC235"}, + "rom1": {"size": 279, "crc": "4BFEC235"}, + "sou1": {"size": 279, "crc": "4BFEC235"}, + "s222b.1a": {"size": 279, "crc": "4BFEC235"}, + "lwio.12c": {"size": 279, "crc": "4BFEC235"} + } + } + }, + { + "game": "King of Dragons (U)", + "system": "Arcade", + "filename": "kod.zip", + "in_file": "kod", + "status": "playable", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "kde_37a.11f": {"size": 131072, "crc": "F22E5266"}, + "kde_38a.12f": {"size": 131072, "crc": "57D6ED3A"}, + "kd_35.9f": {"size": 131072, "crc": "4CA6A48A"}, + "kd_36a.10f": {"size": 131072, "crc": "95A3CEF8"}, + "kde_30a.11e": {"size": 131072, "crc": "FCB5EFE2"}, + "kde_31a.12e": {"size": 131072, "crc": "C710D722"}, + "kd_28.9e": {"size": 131072, "crc": "9367BCD9"}, + "kd_29.10e": {"size": 131072, "crc": "0360FA72"}, + "kd-5m.4a": {"size": 524288, "crc": "E45B8701"}, + "kd-6m.4c": {"size": 524288, "crc": "113358F3"}, + "kd-7m.6a": {"size": 524288, "crc": "A7750322"}, + "kd-8m.6c": {"size": 524288, "crc": "38853C44"}, + "kd-1m.3a": {"size": 524288, "crc": "5F74BF78"}, + "kd-2m.3c": {"size": 524288, "crc": "9EF36604"}, + "kd-3m.5a": {"size": 524288, "crc": "5E5303BF"}, + "kd-4m.5c": {"size": 524288, "crc": "402B9B4F"}, + "kd_9.12a": {"size": 65536, "crc": "BAC6EC26"}, + "kd_18.11c": {"size": 131072, "crc": "4C63181D"}, + "kd_19.12c": {"size": 131072, "crc": "92941B80"}, + "buf1": {"size": 279, "crc": "4BFEC235"}, + "ioa1": {"size": 279, "crc": "4BFEC235"}, + "prg1": {"size": 279, "crc": "4BFEC235"}, + "rom1": {"size": 279, "crc": "4BFEC235"}, + "sou1": {"size": 279, "crc": "4BFEC235"}, + "kd29b.1a": {"size": 279, "crc": "4BFEC235"}, + "iob1.11d": {"size": 279, "crc": "4BFEC235"}, + "ioc1.ic7": {"size": 260, "crc": "91A9701B"}, + "c632.ic1": {"size": 279, "crc": "4BFEC235"} + } + } + }, + { + "game": "King of Dragons (J)", + "system": "Arcade", + "filename": "kodj.zip", + "in_file": "kodj", + "status": "playable", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "kdj_37a.11f": {"size": 131072, "crc": "E55C3529"}, + "kdj_38a.12f": {"size": 131072, "crc": "57D6ED3A"}, + "kdj_30a.11e": {"size": 131072, "crc": "EBC788AD"}, + "kdj_31a.12e": {"size": 131072, "crc": "C710D722"}, + "kd_33.6f": {"size": 524288, "crc": "9BD7AD4B"}, + "kd_06.8a": {"size": 524288, "crc": "E45B8701"}, + "kd_15.8c": {"size": 524288, "crc": "113358F3"}, + "kd_08.10a": {"size": 524288, "crc": "A7750322"}, + "kd_17.10c": {"size": 524288, "crc": "38853C44"}, + "kd_05.7a": {"size": 524288, "crc": "5F74BF78"}, + "kd_14.7c": {"size": 524288, "crc": "9EF36604"}, + "kd_07.9a": {"size": 524288, "crc": "5E5303BF"}, + "kd_16.9c": {"size": 524288, "crc": "402B9B4F"}, + "kd_09.12a": {"size": 65536, "crc": "BAC6EC26"}, + "kd_18.11c": {"size": 131072, "crc": "4C63181D"}, + "kd_19.12c": {"size": 131072, "crc": "92941B80"}, + "buf1": {"size": 279, "crc": "4BFEC235"}, + "ioa1": {"size": 279, "crc": "4BFEC235"}, + "prg1": {"size": 279, "crc": "4BFEC235"}, + "rom1": {"size": 279, "crc": "4BFEC235"}, + "sou1": {"size": 279, "crc": "4BFEC235"}, + "kd29b.1a": {"size": 279, "crc": "4BFEC235"}, + "iob1.11d": {"size": 279, "crc": "4BFEC235"}, + "ioc1.ic7": {"size": 260, "crc": "91A9701B"}, + "c632.ic1": {"size": 279, "crc": "4BFEC235"} + } + } + }, + { + "game": "Captain Commando (U)", + "system": "Arcade", + "filename": "captcomm.zip", + "in_file": "captcomm", + "status": "playable", + "notes": [2, 3], + "verify": { + "type": "zip", + "entries": { + "cce_23f.8f": {"size": 524288, "crc": "42C814C5"}, + "cc_28f.9f": {"size": 131072, "crc": "FC3C2906"}, + "cc_22f.7f": {"size": 524288, "crc": "0FD34195"}, + "cc_24f.9e": {"size": 131072, "crc": "3A794F25"}, + "cc-5m.3a": {"size": 524288, "crc": "7261D8BA"}, + "cc-6m.7a": {"size": 524288, "crc": "28718BED"}, + "cc-7m.5a": {"size": 524288, "crc": "6A60F949"}, + "cc-8m.9a": {"size": 524288, "crc": "D4ACC53A"}, + "cc-1m.4a": {"size": 524288, "crc": "00637302"}, + "cc-2m.8a": {"size": 524288, "crc": "0C69F151"}, + "cc-3m.6a": {"size": 524288, "crc": "CC87CF61"}, + "cc-4m.10a": {"size": 524288, "crc": "1F9EBB97"}, + "cc_09.11a": {"size": 65536, "crc": "698E8B58"}, + "cc_18.11c": {"size": 131072, "crc": "6DE2C2DB"}, + "cc_19.12c": {"size": 131072, "crc": "B99091AE"}, + "buf1": {"size": 279, "crc": "4BFEC235"}, + "ioa1": {"size": 279, "crc": "4BFEC235"}, + "prg1": {"size": 279, "crc": "4BFEC235"}, + "rom1": {"size": 279, "crc": "4BFEC235"}, + "sou1": {"size": 279, "crc": "4BFEC235"}, + "cc63b.1a": {"size": 279, "crc": "4BFEC235"}, + "iob1.12d": {"size": 279, "crc": "4BFEC235"}, + "ccprg1.11d": {"size": 279, "crc": "4BFEC235"}, + "ioc1.ic7": {"size": 260, "crc": "91A9701B"}, + "c632b.ic1": {"size": 279, "crc": "4BFEC235"} + } + } + }, + { + "game": "Captain Commando (J)", + "system": "Arcade", + "filename": "captcommj.zip", + "in_file": "captcommj", + "status": "playable", + "notes": [2, 3], + "verify": { + "type": "zip", + "entries": { + "ccj_23f.8f": {"size": 524288, "crc": "5B482B62"}, + "ccj_28f.9f": {"size": 131072, "crc": "FC3C2906"}, + "ccj_22f.7f": {"size": 524288, "crc": "0FD34195"}, + "ccj_24f.9e": {"size": 131072, "crc": "3A794F25"}, + "cc_01.3a": {"size": 524288, "crc": "7261D8BA"}, + "cc_05.7a": {"size": 524288, "crc": "28718BED"}, + "cc_02.4a": {"size": 524288, "crc": "6A60F949"}, + "cc_06.8a": {"size": 524288, "crc": "D4ACC53A"}, + "cc_03.5a": {"size": 524288, "crc": "00637302"}, + "cc_07.9a": {"size": 524288, "crc": "0C69F151"}, + "cc_04.6a": {"size": 524288, "crc": "CC87CF61"}, + "cc_08.10a": {"size": 524288, "crc": "1F9EBB97"}, + "ccj_09.12a": {"size": 65536, "crc": "698E8B58"}, + "ccj_18.11c": {"size": 131072, "crc": "6DE2C2DB"}, + "ccj_19.12c": {"size": 131072, "crc": "B99091AE"}, + "buf1": {"size": 279, "crc": "4BFEC235"}, + "ioa1": {"size": 279, "crc": "4BFEC235"}, + "prg1": {"size": 279, "crc": "4BFEC235"}, + "rom1": {"size": 279, "crc": "4BFEC235"}, + "sou1": {"size": 279, "crc": "4BFEC235"}, + "cc63b.1a": {"size": 279, "crc": "4BFEC235"}, + "iob1.12d": {"size": 279, "crc": "4BFEC235"}, + "ccprg1.11d": {"size": 279, "crc": "4BFEC235"}, + "ioc1.ic7": {"size": 260, "crc": "91A9701B"}, + "c632.ic1": {"size": 279, "crc": "4BFEC235"} + } + } + }, + { + "game": "Knights of the Round (U)", + "system": "Arcade", + "filename": "knights.zip", + "in_file": "knights", + "status": "playable", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "kr_23e.8f": {"size": 524288, "crc": "1B3997EB"}, + "kr_22.7f": {"size": 524288, "crc": "D0B671A9"}, + "kr-5m.3a": {"size": 524288, "crc": "9E36C1A4"}, + "kr-6m.7a": {"size": 524288, "crc": "1F4298D2"}, + "kr-7m.5a": {"size": 524288, "crc": "C5832CAE"}, + "kr-8m.9a": {"size": 524288, "crc": "37FA8751"}, + "kr-1m.4a": {"size": 524288, "crc": "F095BE2D"}, + "kr-2m.8a": {"size": 524288, "crc": "0200BC3D"}, + "kr-3m.6a": {"size": 524288, "crc": "179DFD96"}, + "kr-4m.10a": {"size": 524288, "crc": "0BB2B4E7"}, + "kr_09.11a": {"size": 65536, "crc": "5E44D9EE"}, + "kr_18.11c": {"size": 131072, "crc": "DA69D15F"}, + "kr_19.12c": {"size": 131072, "crc": "BFC654E9"}, + "buf1": {"size": 279, "crc": "4BFEC235"}, + "ioa1": {"size": 279, "crc": "4BFEC235"}, + "prg1": {"size": 279, "crc": "4BFEC235"}, + "rom1": {"size": 279, "crc": "4BFEC235"}, + "sou1": {"size": 279, "crc": "4BFEC235"}, + "kr63b.1a": {"size": 279, "crc": "4BFEC235"}, + "iob1.12d": {"size": 279, "crc": "4BFEC235"}, + "bprg1.11d": {"size": 279, "crc": "4BFEC235"}, + "ioc1.ic7": {"size": 260, "crc": "91A9701B"}, + "c632.ic1": {"size": 279, "crc": "4BFEC235"} + } + } + }, + { + "game": "Knights of the Round (J)", + "system": "Arcade", + "filename": "knightsj.zip", + "in_file": "knightsj", + "status": "playable", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "kr_23j.8f": {"size": 524288, "crc": "EAE7417F"}, + "kr_22.7f": {"size": 524288, "crc": "D0B671A9"}, + "kr_01.3a": {"size": 524288, "crc": "9E36C1A4"}, + "kr_05.7a": {"size": 524288, "crc": "1F4298D2"}, + "kr_02.4a": {"size": 524288, "crc": "C5832CAE"}, + "kr_06.8a": {"size": 524288, "crc": "37FA8751"}, + "kr_03.5a": {"size": 524288, "crc": "F095BE2D"}, + "kr_07.9a": {"size": 524288, "crc": "0200BC3D"}, + "kr_04.6a": {"size": 524288, "crc": "179DFD96"}, + "kr_08.10a": {"size": 524288, "crc": "0BB2B4E7"}, + "kr_09.12a": {"size": 65536, "crc": "5E44D9EE"}, + "kr_18.11c": {"size": 131072, "crc": "DA69D15F"}, + "kr_19.12c": {"size": 131072, "crc": "BFC654E9"}, + "buf1": {"size": 279, "crc": "4BFEC235"}, + "ioa1": {"size": 279, "crc": "4BFEC235"}, + "prg1": {"size": 279, "crc": "4BFEC235"}, + "rom1": {"size": 279, "crc": "4BFEC235"}, + "sou1": {"size": 279, "crc": "4BFEC235"}, + "kr63b.1a": {"size": 279, "crc": "4BFEC235"}, + "iob1.12d": {"size": 279, "crc": "4BFEC235"}, + "bprg1.11d": {"size": 279, "crc": "4BFEC235"}, + "ioc1.ic7": {"size": 260, "crc": "91A9701B"}, + "c632.ic1": {"size": 279, "crc": "4BFEC235"} + } + } + }, + { + "game": "Warriors of Fate (U)", + "system": "Arcade", + "filename": "wof.zip", + "in_file": "wof", + "status": "playable", + "notes": [2, 4], + "verify": { + "type": "zip", + "entries": { + "tk2e_23c.8f": {"size": 524288, "crc": "0D708505"}, + "tk2e_22c.7f": {"size": 524288, "crc": "608C17E3"}, + "tk2-1m.3a": {"size": 524288, "crc": "0D9CB9BF"}, + "tk2-5m.7a": {"size": 524288, "crc": "291F0F0B"}, + "tk2-3m.5a": {"size": 524288, "crc": "45227027"}, + "tk2-7m.9a": {"size": 524288, "crc": "3EDEB949"}, + "tk2-2m.4a": {"size": 524288, "crc": "C5CA2460"}, + "tk2-6m.8a": {"size": 524288, "crc": "1ABD14D6"}, + "tk2-4m.6a": {"size": 524288, "crc": "E349551C"}, + "tk2-8m.10a": {"size": 524288, "crc": "B27948E3"}, + "tk2_qa.5k": {"size": 131072, "crc": "C1D7D477"}, + "tk2-q1.1k": {"size": 524288, "crc": "611268CF"}, + "tk2-q2.2k": {"size": 524288, "crc": "20F55CA9"}, + "tk2-q3.3k": {"size": 524288, "crc": "BFCF6F52"}, + "tk2-q4.4k": {"size": 524288, "crc": "36642E88"}, + "buf1": {"size": 279, "crc": "4BFEC235"}, + "ioa1": {"size": 279, "crc": "4BFEC235"}, + "prg2": {"size": 279, "crc": "4BFEC235"}, + "rom1": {"size": 279, "crc": "4BFEC235"}, + "tk263b.1a": {"size": 279, "crc": "4BFEC235"}, + "iob1.12d": {"size": 279, "crc": "4BFEC235"}, + "bprg1.11d": {"size": 279, "crc": "4BFEC235"}, + "ioc1.ic1": {"size": 260, "crc": "91A9701B"}, + "d7l1.7l": {"size": 279, "crc": "4BFEC235"}, + "d8l1.8l": {"size": 279, "crc": "4BFEC235"}, + "d9k1.9k": {"size": 279, "crc": "4BFEC235"}, + "d10f1.10f": {"size": 279, "crc": "4BFEC235"} + } + } + }, + { + "game": "Warriors of Fate (J)", + "system": "Arcade", + "filename": "wofj.zip", + "in_file": "wofj", + "status": "playable", + "notes": [2, 4], + "verify": { + "type": "zip", + "entries": { + "tk2j_23c.8f": {"size": 524288, "crc": "9B215A68"}, + "tk2j_22c.7f": {"size": 524288, "crc": "B74B09AC"}, + "tk2_01.3a": {"size": 524288, "crc": "0D9CB9BF"}, + "tk2_05.7a": {"size": 524288, "crc": "E4A44D53"}, + "tk2_02.4a": {"size": 524288, "crc": "45227027"}, + "tk2_06.8a": {"size": 524288, "crc": "58066BA8"}, + "tk2_03.5a": {"size": 524288, "crc": "C5CA2460"}, + "tk2_07.9a": {"size": 524288, "crc": "D706568E"}, + "tk2_04.6a": {"size": 524288, "crc": "E349551C"}, + "tk2_08.10a": {"size": 524288, "crc": "D4A19A02"}, + "tk2_qa.5k": {"size": 131072, "crc": "C1D7D477"}, + "tk2-q1.1k": {"size": 524288, "crc": "611268CF"}, + "tk2-q2.2k": {"size": 524288, "crc": "20F55CA9"}, + "tk2-q3.3k": {"size": 524288, "crc": "BFCF6F52"}, + "tk2-q4.4k": {"size": 524288, "crc": "36642E88"}, + "buf1": {"size": 279, "crc": "4BFEC235"}, + "ioa1": {"size": 279, "crc": "4BFEC235"}, + "prg1": {"size": 279, "crc": "4BFEC235"}, + "sou1": {"size": 279, "crc": "4BFEC235"}, + "rom1": {"size": 279, "crc": "4BFEC235"}, + "tk263b.1a": {"size": 279, "crc": "4BFEC235"}, + "iob1.12d": {"size": 279, "crc": "4BFEC235"}, + "bprg1.11d": {"size": 279, "crc": "4BFEC235"}, + "ioc1.ic1": {"size": 260, "crc": "91A9701B"}, + "d7l1.7l": {"size": 279, "crc": "4BFEC235"}, + "d8l1.8l": {"size": 279, "crc": "4BFEC235"}, + "d9k1.9k": {"size": 279, "crc": "4BFEC235"}, + "d10f1.10f": {"size": 279, "crc": "4BFEC235"} + } + } + }, + { + "game": "Powered Gear (U)", + "system": "Arcade", + "filename": "pgear.zip", + "in_file": "pgear", + "status": "playable", + "notes": [1], + "verify": { + "type": "zip", + "entries": { + "pwgj.03a": {"size": 524288, "crc": "C79C0C02"}, + "pwgj.04a": {"size": 524288, "crc": "167C6ED8"}, + "pwgj.05a": {"size": 524288, "crc": "A63FB400"}, + "pwg.06": {"size": 524288, "crc": "87A60CE8"}, + "pwg.07": {"size": 524288, "crc": "F7B148DF"}, + "pwg.08": {"size": 524288, "crc": "CC62823E"}, + "pwg.09a": {"size": 524288, "crc": "4C26BAEE"}, + "pwg.10": {"size": 524288, "crc": "07C4FB28"}, + "pwg.13m": {"size": 4194304, "crc": "AE8FE08E"}, + "pwg.14m": {"size": 1048576, "crc": "C3F9BA63"}, + "pwg.15m": {"size": 4194304, "crc": "DB560F58"}, + "pwg.16m": {"size": 1048576, "crc": "815B0E7B"}, + "pwg.17m": {"size": 4194304, "crc": "BC475B94"}, + "pwg.18m": {"size": 1048576, "crc": "0109C71B"}, + "pwg.19m": {"size": 4194304, "crc": "07439FF7"}, + "pwg.20m": {"size": 1048576, "crc": "EB75FFBE"}, + "pwg.01": {"size": 131072, "crc": "18A5C0E4"}, + "pwg.02": {"size": 131072, "crc": "C9DFFFA6"}, + "pwg.11m": {"size": 2097152, "crc": "A78F7433"}, + "pwg.12m": {"size": 2097152, "crc": "77438ED0"} + } + } + }, + { + "game": "Powered Gear (J)", + "system": "Arcade", + "filename": "armwar.zip", + "in_file": "armwar", + "status": "playable", + "notes": [1], + "verify": { + "type": "zip", + "entries": { + "pwge.03c": {"size": 524288, "crc": "31F74931"}, + "pwge.04c": {"size": 524288, "crc": "16F34F5F"}, + "pwge.05b": {"size": 524288, "crc": "4403ED08"}, + "pwg.06": {"size": 524288, "crc": "87A60CE8"}, + "pwg.07": {"size": 524288, "crc": "F7B148DF"}, + "pwg.08": {"size": 524288, "crc": "CC62823E"}, + "pwg.09a": {"size": 524288, "crc": "4C26BAEE"}, + "pwg.10": {"size": 524288, "crc": "07C4FB28"}, + "pwg.13m": {"size": 4194304, "crc": "AE8FE08E"}, + "pwg.14m": {"size": 1048576, "crc": "C3F9BA63"}, + "pwg.15m": {"size": 4194304, "crc": "DB560F58"}, + "pwg.16m": {"size": 1048576, "crc": "815B0E7B"}, + "pwg.17m": {"size": 4194304, "crc": "BC475B94"}, + "pwg.18m": {"size": 1048576, "crc": "0109C71B"}, + "pwg.19m": {"size": 4194304, "crc": "07439FF7"}, + "pwg.20m": {"size": 1048576, "crc": "EB75FFBE"}, + "pwg.01": {"size": 131072, "crc": "18A5C0E4"}, + "pwg.02": {"size": 131072, "crc": "C9DFFFA6"}, + "pwg.11m": {"size": 2097152, "crc": "A78F7433"}, + "pwg.12m": {"size": 2097152, "crc": "77438ED0"} + } + } + }, + { + "game": "Battle Circuit (U)", + "system": "Arcade", + "filename": "batcir.zip", + "in_file": "batcir", + "status": "playable", + "notes": [1], + "verify": { + "type": "zip", + "entries": { + "btce.03": {"size": 524288, "crc": "BC60484B"}, + "btce.04": {"size": 524288, "crc": "457D55F6"}, + "btce.05": {"size": 524288, "crc": "E86560D7"}, + "btce.06": {"size": 524288, "crc": "F778E61B"}, + "btc.07": {"size": 524288, "crc": "7322D5DB"}, + "btc.08": {"size": 524288, "crc": "6AAC85AB"}, + "btc.09": {"size": 524288, "crc": "1203DB08"}, + "btc.13m": {"size": 4194304, "crc": "DC705BAD"}, + "btc.15m": {"size": 4194304, "crc": "E5779A3C"}, + "btc.17m": {"size": 4194304, "crc": "B33F4112"}, + "btc.19m": {"size": 4194304, "crc": "A6FCDB7E"}, + "btc.01": {"size": 131072, "crc": "1E194310"}, + "btc.02": {"size": 131072, "crc": "01AEB8E6"}, + "btc.11m": {"size": 2097152, "crc": "C27F2229"}, + "btc.12m": {"size": 2097152, "crc": "418A2E33"} + } + } + }, + { + "game": "Battle Circuit (J)", + "system": "Arcade", + "filename": "batcirj.zip", + "in_file": "batcirj", + "status": "playable", + "notes": [1], + "verify": { + "type": "zip", + "entries": { + "btcj.03": {"size": 524288, "crc": "6B7E168D"}, + "btcj.04": {"size": 524288, "crc": "46BA3467"}, + "btcj.05": {"size": 524288, "crc": "0E23A859"}, + "btcj.06": {"size": 524288, "crc": "A853B59C"}, + "btc.07": {"size": 524288, "crc": "7322D5DB"}, + "btc.08": {"size": 524288, "crc": "6AAC85AB"}, + "btc.09": {"size": 524288, "crc": "1203DB08"}, + "btc.13m": {"size": 4194304, "crc": "DC705BAD"}, + "btc.15m": {"size": 4194304, "crc": "E5779A3C"}, + "btc.17m": {"size": 4194304, "crc": "B33F4112"}, + "btc.19m": {"size": 4194304, "crc": "A6FCDB7E"}, + "btc.01": {"size": 131072, "crc": "1E194310"}, + "btc.02": {"size": 131072, "crc": "01AEB8E6"}, + "btc.11m": {"size": 2097152, "crc": "C27F2229"}, + "btc.12m": {"size": 2097152, "crc": "418A2E33"} + } + } + } + ], + "notes": { + "1": "These ROMs require an older version MAME. They test fine in MAME 0.139 (Mame 2010 in RetroArch). This is typically due to a missing decryption key, dl-1425.bin qsound rom, or other ROM files that the older MAME did not strictly require", + "2": "These ROMs play fine, even in the current MAME, despite the bad CRCs. The bad CRCs are small ancillary files that aren't strictly required or included, but stubbed out to pass checks. ", + "3": "The JP version of this ROM is fine in modern MAME 0.246; the English version needs 0.139", + "4": "The Audio CPU ROM for this is not present in the expected format. Further investigation required." + } + } +} \ No newline at end of file diff --git a/src/gex/lib/tasks/impl/cfc/__init__.py b/src/gex/lib/tasks/impl/cfc/__init__.py index d2de956..ba0f6ed 100644 --- a/src/gex/lib/tasks/impl/cfc/__init__.py +++ b/src/gex/lib/tasks/impl/cfc/__init__.py @@ -1,6 +1,4 @@ '''Implementation of cfc: Capcom Fighting Collection''' -import re -import glob import logging import os @@ -21,203 +19,54 @@ class CFCTask(BaseTask): This script will extract and prep the ROMs. Some per-rom errata are in the notes below. All CRCs are currently mismatched. ''' - _out_file_list = [ - { - "game": "Darkstalkers: The Night Warriors (U)", - "system": "Arcade", - "filename": "dstlku.zip", - "status": "playable", - "notes": [1] - }, - { - "game": "Darkstalkers: The Night Warriors (J)", - "system": "Arcade", - "filename": "vampj.zip", - "status": "playable", - "notes": [1] - }, - { - "game": "Night Warriors:Darkstalkers' Revenge (U)", - "system": "Arcade", - "filename": "nwarru.zip", - "status": "playable", - "notes": [1] - }, - { - "game": "Night Warriors:Darkstalkers' Revenge (J)", - "system": "Arcade", - "filename": "vhuntjr2.zip", - "status": "playable", - "notes": [1] - }, - { - "game": "Vampire Savior: The Lord of Vampire (U)", - "system": "Arcade", - "filename": "vsavu.zip", - "status": "playable", - "notes": [1] - }, - { - "game": "Vampire Hunter 2: Darkstalkers Revenge (J)", - "system": "Arcade", - "filename": "vhunt2.zip", - "status": "playable", - "notes": [1] - }, - { - "game": "Vampire Savior 2: The Lord of Vampire (J)", - "system": "Arcade", - "filename": "vsav2.zip", - "status": "playable", - "notes": [1] - }, - { - "game": "Cyberbots: Fullmetal Madness (U)", - "system": "Arcade", - "filename": "cybotsj.zip", - "status": "playable", - "notes": [1] - }, - { - "game": "Cyberbots: Fullmetal Madness (J)", - "system": "Arcade", - "filename": "cybotsu.zip", - "status": "playable", - "notes": [1] - }, - { - "game": "Super Puzzle Fighter II Turbo (U)", - "system": "Arcade", - "filename": "spf2tu.zip", - "status": "playable", - "notes": [1, 3] - }, - { - "game": "Super Puzzle Fighter II Turbo (J)", - "system": "Arcade", - "filename": "spf2xj.zip", - "status": "playable", - "notes": [1, 3] - }, - { - "game": "Super Gem Fighter Mini Mix (U)", - "system": "Arcade", - "filename": "sgemf.zip", - "status": "playable", - "notes": [1] - }, - { - "game": "Super Gem Fighter Mini Mix (J)", - "system": "Arcade", - "filename": "pfghtj.zip", - "status": "playable", - "notes": [1] - }, - { - "game": "Hyper Street Fighter II: Anniversary Edition (U)", - "system": "Arcade", - "filename": "hsf2.zip", - "status": "playable", - "notes": [1, 4] - }, - { - "game": "Hyper Street Fighter II: Anniversary Edition (J)", - "system": "Arcade", - "filename": "hsf2j.zip", - "status": "playable", - "notes": [1, 4] - }, - { - "game": "Red Earth (U)", - "system": "Arcade", - "filename": "N/A", - "status": "no-rom", - "notes": [2] - }, - { - "game": "Warzard (J)", - "system": "Arcade", - "filename": "N/A", - "status": "no-rom", - "notes": [2] - } - ] - _out_file_notes = { - "1": "These ROMs require an older version MAME. They test fine in MAME 0.139 (Mame 2010 in RetroArch). This is typically due to a missing decryption key, dl-1425.bin qsound rom, or other ROM files that the older MAME did not strictly require", - "2": "This CPS3 game cannot yet be extracted.", - "3": "The US version of this does not have a valid MAME release.", - "4": "The JP version of this is using an older internal file naming convention." - } _default_input_folder = helpers.gen_steam_app_default_folder("CAPCOM FIGHTING COLLECTION") _input_folder_desc = "CFC Steam folder" + def get_out_file_info(self): + '''Return a list of output files''' + return { + "files": self._metadata['out']['files'], + "notes": self._metadata['out']['notes'] + } + def execute(self, in_dir, out_dir): - pak_files = self._find_files(in_dir) - for file_path in pak_files: - file_name = os.path.basename(file_path) - pkg_name = self._pkg_name_map.get(file_name) - if pkg_name is not None: - logger.info(f"Extracting {file_name}: {pkg_name}") - try: - with open(file_path, "rb") as curr_file: - file_content = bytearray(curr_file.read()) - arc_contents = arc.extract(file_content) - output_files = [] - - # Get the bin entry - merged_rom_contents = None - for _, arc_content in arc_contents.items(): - if arc_content['path'].startswith('bin'): - merged_rom_contents = arc_content['contents'] - - handler_func = self.find_handler_func(pkg_name) - if merged_rom_contents is not None and handler_func is not None: - output_files = handler_func(merged_rom_contents) - - for output_file in output_files: - with open(os.path.join(out_dir, output_file['filename']), "wb") as out_file: - out_file.write(output_file['contents']) - elif merged_rom_contents is None: - logger.warning( - "Could not find merged rom data in arc.") - elif handler_func is None: - logger.warning( - "Could not find matching handler function.") - except Exception as _: - logger.warning(f'Error while processing {file_path}!') + # for each output file entry + for out_file_entry in self._metadata['out']['files']: + pkg_name = out_file_entry['in_file'] + # Check the status of it + if out_file_entry['status'] == 'no-rom': + logger.info(f"Skipping {pkg_name} - cannot extract...") else: - logger.info(f'Skipping unmatched file {file_path}!') + logger.info(f"Extracting {pkg_name}...") + + # read the matching input file + in_file_entry = self._metadata['in']['files'][pkg_name] + loaded_file = self.read_datafile(in_dir, in_file_entry) + + # extract the input file + arc_contents = arc.extract(loaded_file['contents']) + + # Get the bin entry + merged_rom_contents = None + for _, arc_content in arc_contents.items(): + if arc_content['path'].startswith('bin'): + merged_rom_contents = arc_content['contents'] + + # run the handler + handler_func = self.find_handler_func(pkg_name) + if merged_rom_contents is not None and handler_func is not None: + output_contents = handler_func(merged_rom_contents) + + _ = self.verify_out_file(out_file_entry['filename'], output_contents) + + with open(os.path.join(out_dir, out_file_entry['filename']), "wb") as out_file: + out_file.write(output_contents) + elif merged_rom_contents is None: + logger.warning("Could not find merged rom data in arc.") + elif handler_func is None: + logger.warning("Could not find matching handler function.") logger.info("Processing complete.") - _pkg_name_map = { - "game_00.arc": "vampj", - "game_01.arc": "dstlku", - "game_10.arc": "vhuntjr2", - "game_11.arc": "nwarru", - "game_20.arc": "vsavj", - "game_21.arc": "vsavu", - "game_30.arc": "vhunt2", - "game_40.arc": "vsav2", - "game_50.arc": "cybotsj", - "game_51.arc": "cybotsu", - "game_60.arc": "spf2xj", - "game_61.arc": "spf2tu", - "game_70.arc": "pfghtj", - "game_71.arc": "sgemf", - "game_80.arc": "hsf2j", - "game_81.arc": "hsf2", - "game_90.arc": "warzard", - "game_91.arc": "redearth", - } - - def _find_files(self, base_path): - arc_path = os.path.join(base_path, "nativeDX11x64", "arc", "pc") - candidate_files = glob.glob(arc_path + '/game_*.arc') - archive_list = [] - for candidate in candidate_files: - if re.search(r'game_\d\d.arc', candidate): - archive_list.append(candidate) - return archive_list ################################################################################ # Darkstalkers/Vampire: The Night Warriors # @@ -245,7 +94,6 @@ def _find_files(self, base_path): ] def _handle_vampj(self, merged_contents): - out_files = [] func_map = {} maincpu_filenames = [ @@ -267,13 +115,9 @@ def _handle_vampj(self, merged_contents): func_map['qsound'] = capcom.qsound_cps2( 0x1C50040, 0x400000, self._vam_qsound_filenames) - out_files.append({'filename': 'vampj.zip', 'contents': helpers.build_rom( - merged_contents, func_map)}) - - return out_files + return helpers.build_rom(merged_contents, func_map) def _handle_dstlku(self, merged_contents): - out_files = [] func_map = {} maincpu_filenames = [ @@ -295,10 +139,7 @@ def _handle_dstlku(self, merged_contents): func_map['qsound'] = capcom.qsound_cps2( 0x1C50040, 0x400000, self._vam_qsound_filenames) - out_files.append({'filename': 'dstlku.zip', 'contents': helpers.build_rom( - merged_contents, func_map)}) - - return out_files + return helpers.build_rom(merged_contents, func_map) ################################################################################ # Vampire Hunter/Night Warriors: Darkstalkers' Revenge # @@ -326,7 +167,6 @@ def _handle_dstlku(self, merged_contents): ] def _handle_vhuntjr2(self, merged_contents): - out_files = [] func_map = {} maincpu_filenames = [ @@ -348,13 +188,9 @@ def _handle_vhuntjr2(self, merged_contents): func_map['qsound'] = capcom.qsound_cps2( 0x2850040, 0x400000, self._vph_qsound_filenames) - out_files.append({'filename': 'vhuntjr2.zip', 'contents': helpers.build_rom( - merged_contents, func_map)}) - - return out_files + return helpers.build_rom(merged_contents, func_map) def _handle_nwarru(self, merged_contents): - out_files = [] maincpu_filenames = [ "vphu.03f", @@ -377,10 +213,7 @@ def _handle_nwarru(self, merged_contents): func_map['qsound'] = capcom.qsound_cps2( 0x2850040, 0x400000, self._vph_qsound_filenames) - out_files.append({'filename': 'nwarru.zip', 'contents': helpers.build_rom( - merged_contents, func_map)}) - - return out_files + return helpers.build_rom(merged_contents, func_map) ################################################################################ # Vampire Savior: The Lord of Vampire # @@ -408,7 +241,6 @@ def _handle_nwarru(self, merged_contents): ] def _handle_vsavj(self, merged_contents): - out_files = [] func_map = {} maincpu_filenames = [ @@ -430,13 +262,9 @@ def _handle_vsavj(self, merged_contents): func_map['qsound'] = capcom.qsound_cps2( 0x2850040, 0x800000, self._vm3_qsound_filenames) - out_files.append({'filename': 'vsavj.zip', 'contents': helpers.build_rom( - merged_contents, func_map)}) - - return out_files + return helpers.build_rom(merged_contents, func_map) def _handle_vsavu(self, merged_contents): - out_files = [] func_map = {} maincpu_filenames = [ @@ -458,10 +286,7 @@ def _handle_vsavu(self, merged_contents): func_map['qsound'] = capcom.qsound_cps2( 0x2850040, 0x800000, self._vm3_qsound_filenames) - out_files.append({'filename': 'vsavu.zip', 'contents': helpers.build_rom( - merged_contents, func_map)}) - - return out_files + return helpers.build_rom(merged_contents, func_map) ################################################################################ # Vampire Hunter 2: Darkstalkers Revenge # @@ -489,7 +314,6 @@ def _handle_vsavu(self, merged_contents): ] def _handle_vhunt2(self, merged_contents): - out_files = [] func_map = {} maincpu_filenames = [ @@ -511,10 +335,7 @@ def _handle_vhunt2(self, merged_contents): func_map['qsound'] = capcom.qsound_cps2( 0x2850040, 0x800000, self._vh2_qsound_filenames) - out_files.append({'filename': 'vhunt2.zip', 'contents': helpers.build_rom( - merged_contents, func_map)}) - - return out_files + return helpers.build_rom(merged_contents, func_map) ################################################################################ # Vampire Savior 2: The Lord of Vampire # @@ -542,7 +363,6 @@ def _handle_vhunt2(self, merged_contents): ] def _handle_vsav2(self, merged_contents): - out_files = [] func_map = {} maincpu_filenames = [ @@ -564,10 +384,7 @@ def _handle_vsav2(self, merged_contents): func_map['qsound'] = capcom.qsound_cps2( 0x2850040, 0x800000, self._vs2_qsound_filenames) - out_files.append({'filename': 'vsav2.zip', 'contents': helpers.build_rom( - merged_contents, func_map)}) - - return out_files + return helpers.build_rom(merged_contents, func_map) ################################################################################ # Cyberbots: Fullmetal Madness # @@ -595,7 +412,6 @@ def _handle_vsav2(self, merged_contents): ] def _handle_cybotsj(self, merged_contents): - out_files = [] func_map = {} maincpu_filenames = [ @@ -617,13 +433,9 @@ def _handle_cybotsj(self, merged_contents): func_map['qsound'] = capcom.qsound_cps2( 0x2850040, 0x400000, self._cybots_qsound_filenames) - out_files.append({'filename': 'cybotsj.zip', 'contents': helpers.build_rom( - merged_contents, func_map)}) - - return out_files + return helpers.build_rom(merged_contents, func_map) def _handle_cybotsu(self, merged_contents): - out_files = [] func_map = {} maincpu_filenames = [ @@ -645,10 +457,7 @@ def _handle_cybotsu(self, merged_contents): func_map['qsound'] = capcom.qsound_cps2( 0x2850040, 0x400000, self._cybots_qsound_filenames) - out_files.append({'filename': 'cybotsu.zip', 'contents': helpers.build_rom( - merged_contents, func_map)}) - - return out_files + return helpers.build_rom(merged_contents, func_map) ################################################################################ # Super Puzzle Fighter II Turbo # @@ -672,7 +481,6 @@ def _handle_cybotsu(self, merged_contents): ] def _handle_spf2xj(self, merged_contents): - out_files = [] func_map = {} maincpu_filenames = [ @@ -688,13 +496,9 @@ def _handle_spf2xj(self, merged_contents): func_map['qsound'] = capcom.qsound_cps2( 0x1450040, 0x400000, self._pzf_qsound_filenames) - out_files.append({'filename': 'spf2xj.zip', 'contents': helpers.build_rom( - merged_contents, func_map)}) - - return out_files + return helpers.build_rom(merged_contents, func_map) def _handle_spf2tu(self, merged_contents): - out_files = [] func_map = {} maincpu_filenames = [ @@ -710,10 +514,7 @@ def _handle_spf2tu(self, merged_contents): func_map['qsound'] = capcom.qsound_cps2( 0x1450040, 0x400000, self._pzf_qsound_filenames) - out_files.append({'filename': 'spf2tu.zip', 'contents': helpers.build_rom( - merged_contents, func_map)}) - - return out_files + return helpers.build_rom(merged_contents, func_map) ################################################################################ # Super Gem Fighter Mini Mix # @@ -741,7 +542,6 @@ def _handle_spf2tu(self, merged_contents): ] def _handle_pfghtj(self, merged_contents): - out_files = [] func_map = {} maincpu_filenames = [ @@ -760,13 +560,9 @@ def _handle_pfghtj(self, merged_contents): func_map['qsound'] = capcom.qsound_cps2( 0x1C50040, 0x800000, self._pcf_qsound_filenames) - out_files.append({'filename': 'pfghtj.zip', 'contents': helpers.build_rom( - merged_contents, func_map)}) - - return out_files + return helpers.build_rom(merged_contents, func_map) def _handle_sgemf(self, merged_contents): - out_files = [] func_map = {} maincpu_filenames = [ @@ -782,10 +578,7 @@ def _handle_sgemf(self, merged_contents): func_map['qsound'] = capcom.qsound_cps2( 0x1C50040, 0x800000, self._pcf_qsound_filenames) - out_files.append({'filename': 'sgemf.zip', 'contents': helpers.build_rom( - merged_contents, func_map)}) - - return out_files + return helpers.build_rom(merged_contents, func_map) ################################################################################ # Hyper Street Fighter II: Anniversary Edition # @@ -808,7 +601,6 @@ def _handle_sgemf(self, merged_contents): ] def _handle_hsf2j(self, merged_contents): - out_files = [] func_map = {} maincpu_filenames = [ @@ -830,13 +622,9 @@ def _handle_hsf2j(self, merged_contents): func_map['qsound'] = capcom.qsound_cps2( 0x2850040, 0x800000, self._hs2_qsound_filenames, num_chunks=1) - out_files.append({'filename': 'hsf2j.zip', 'contents': helpers.build_rom( - merged_contents, func_map)}) - - return out_files + return helpers.build_rom(merged_contents, func_map) def _handle_hsf2(self, merged_contents): - out_files = [] func_map = {} maincpu_filenames = [ @@ -858,10 +646,7 @@ def _handle_hsf2(self, merged_contents): func_map['qsound'] = capcom.qsound_cps2( 0x2850040, 0x800000, self._hs2_qsound_filenames, num_chunks=1) - out_files.append({'filename': 'hsf2.zip', 'contents': helpers.build_rom( - merged_contents, func_map)}) - - return out_files + return helpers.build_rom(merged_contents, func_map) ################################################################################ # Red Earth # @@ -918,7 +703,7 @@ def _handle_hsf2(self, merged_contents): # return { 'endian.bin': contents } # func_map['endian'] = endian - # out_files.append( + # return # {'filename': 'warzard.zip', 'contents': helpers.build_rom(merged_contents, func_map)} # ) # return out_files @@ -932,7 +717,7 @@ def _handle_hsf2(self, merged_contents): # return { 'endian.bin': contents } # func_map['endian'] = endian - # out_files.append( + # return # {'filename': 'redearth.zip', 'contents': helpers.build_rom(merged_contents, func_map)} # ) # return out_files diff --git a/src/gex/lib/tasks/impl/cfc/metadata.json b/src/gex/lib/tasks/impl/cfc/metadata.json new file mode 100644 index 0000000..f4ff22f --- /dev/null +++ b/src/gex/lib/tasks/impl/cfc/metadata.json @@ -0,0 +1,669 @@ +{ + "in": { + "files": { + "vampj": { + "rel_path": ["nativeDX11x64", "arc", "pc"], + "filename": "game_00.arc", + "versions": { + "Steam": { + "size": 13447403, + "crc": "0DFEC976" + } + } + }, + "dstlku": { + "rel_path": ["nativeDX11x64", "arc", "pc"], + "filename": "game_01.arc", + "versions": { + "Steam": { + "size": 13702867, + "crc": "292A64FD" + } + } + }, + "vhuntjr2": { + "rel_path": ["nativeDX11x64", "arc", "pc"], + "filename": "game_10.arc", + "versions": { + "Steam": { + "size": 17308161, + "crc": "D8DB1572" + } + } + }, + "nwarru": { + "rel_path": ["nativeDX11x64", "arc", "pc"], + "filename": "game_11.arc", + "versions": { + "Steam": { + "size": 17310244, + "crc": "DEB41B47" + } + } + }, + "vsavj": { + "rel_path": ["nativeDX11x64", "arc", "pc"], + "filename": "game_20.arc", + "versions": { + "Steam": { + "size": 20099042, + "crc": "42116EF4" + } + } + }, + "vsavu": { + "rel_path": ["nativeDX11x64", "arc", "pc"], + "filename": "game_21.arc", + "versions": { + "Steam": { + "size": 20099071, + "crc": "A327A39D" + } + } + }, + "vhunt2": { + "rel_path": ["nativeDX11x64", "arc", "pc"], + "filename": "game_30.arc", + "versions": { + "Steam": { + "size": 20042507, + "crc": "D131FEB7" + } + } + }, + "vsav2": { + "rel_path": ["nativeDX11x64", "arc", "pc"], + "filename": "game_40.arc", + "versions": { + "Steam": { + "size": 19970806, + "crc": "34FF1078" + } + } + }, + "cybotsj": { + "rel_path": ["nativeDX11x64", "arc", "pc"], + "filename": "game_50.arc", + "versions": { + "Steam": { + "size": 17030696, + "crc": "641D217A" + } + } + }, + "cybotsu": { + "rel_path": ["nativeDX11x64", "arc", "pc"], + "filename": "game_51.arc", + "versions": { + "Steam": { + "size": 17030662, + "crc": "666B2E29" + } + } + }, + "spf2xj": { + "rel_path": ["nativeDX11x64", "arc", "pc"], + "filename": "game_60.arc", + "versions": { + "Steam": { + "size": 4952375, + "crc": " 2424C2BB" + } + } + }, + "spf2tu": { + "rel_path": ["nativeDX11x64", "arc", "pc"], + "filename": "game_61.arc", + "versions": { + "Steam": { + "size": 4952414, + "crc": " 6005A159" + } + } + }, + "pfghtj": { + "rel_path": ["nativeDX11x64", "arc", "pc"], + "filename": "game_70.arc", + "versions": { + "Steam": { + "size": 14449803, + "crc": "CA5FF893" + } + } + }, + "sgemf": { + "rel_path": ["nativeDX11x64", "arc", "pc"], + "filename": "game_71.arc", + "versions": { + "Steam": { + "size": 14449785, + "crc": "07BFDC17" + } + } + }, + "hsf2j": { + "rel_path": ["nativeDX11x64", "arc", "pc"], + "filename": "game_80.arc", + "versions": { + "Steam": { + "size": 18395361, + "crc": "E51FAB87" + } + } + }, + "hsf2": { + "rel_path": ["nativeDX11x64", "arc", "pc"], + "filename": "game_81.arc", + "versions": { + "Steam": { + "size": 18395414, + "crc": "F80EB2D7" + } + } + }, + "warzard": { + "rel_path": ["nativeDX11x64", "arc", "pc"], + "filename": "game_90.arc", + "versions": { + "Steam": { + "size": 49730575, + "crc": "2E3BD464" + } + } + }, + "redearth": { + "rel_path": ["nativeDX11x64", "arc", "pc"], + "filename": "game_91.arc", + "versions": { + "Steam": { + "size": 49732507, + "crc": "E515469E" + } + } + } + } + }, + "out": { + "files": [ + { + "game": "Darkstalkers: The Night Warriors (U)", + "system": "Arcade", + "filename": "dstlku.zip", + "in_file": "dstlku", + "status": "playable", + "notes": [1], + "verify": { + "type": "zip", + "entries": { + "vamu.03b": {"size": 524288, "crc": "68A6343F"}, + "vamu.04b": {"size": 524288, "crc": "58161453"}, + "vamu.05b": {"size": 524288, "crc": "DFC038B8"}, + "vamu.06b": {"size": 524288, "crc": "C3842C89"}, + "vamu.07b": {"size": 524288, "crc": "25B60B6E"}, + "vamu.08b": {"size": 524288, "crc": "2113C596"}, + "vamu.09b": {"size": 524288, "crc": "2D1E9AE5"}, + "vamu.10b": {"size": 524288, "crc": "81145622"}, + "vam.13m": {"size": 4194304, "crc": "C51BAF99"}, + "vam.14m": {"size": 1048576, "crc": "BD87243C"}, + "vam.15m": {"size": 4194304, "crc": "3CE83C77"}, + "vam.16m": {"size": 1048576, "crc": "AFEC855F"}, + "vam.17m": {"size": 4194304, "crc": "4F2408E0"}, + "vam.18m": {"size": 1048576, "crc": "3A033625"}, + "vam.19m": {"size": 4194304, "crc": "9FF60250"}, + "vam.20m": {"size": 1048576, "crc": "2BFF6A89"}, + "vam.01": {"size": 131072, "crc": "64B685D5"}, + "vam.02": {"size": 131072, "crc": "CF7C97C7"}, + "vam.11m": {"size": 2097152, "crc": "4A39DEB2"}, + "vam.12m": {"size": 2097152, "crc": "1A3E5C03"} + } + } + }, + { + "game": "Darkstalkers: The Night Warriors (J)", + "system": "Arcade", + "filename": "vampj.zip", + "in_file": "vampj", + "status": "playable", + "notes": [1], + "verify": { + "type": "zip", + "entries": { + "vamj.03a": {"size": 524288, "crc": "F55D3722"}, + "vamj.04b": {"size": 524288, "crc": "4D9C43C4"}, + "vamj.05a": {"size": 524288, "crc": "6C497E92"}, + "vamj.06a": {"size": 524288, "crc": "F1BBECB6"}, + "vamj.07a": {"size": 524288, "crc": "1067AD84"}, + "vamj.08a": {"size": 524288, "crc": "4B89F41F"}, + "vamj.09a": {"size": 524288, "crc": "FC0A4AAC"}, + "vamj.10a": {"size": 524288, "crc": "9270C26B"}, + "vam.13m": {"size": 4194304, "crc": "C51BAF99"}, + "vam.14m": {"size": 1048576, "crc": "BD87243C"}, + "vam.15m": {"size": 4194304, "crc": "3CE83C77"}, + "vam.16m": {"size": 1048576, "crc": "AFEC855F"}, + "vam.17m": {"size": 4194304, "crc": "4F2408E0"}, + "vam.18m": {"size": 1048576, "crc": "3A033625"}, + "vam.19m": {"size": 4194304, "crc": "9FF60250"}, + "vam.20m": {"size": 1048576, "crc": "2BFF6A89"}, + "vam.01": {"size": 131072, "crc": "64B685D5"}, + "vam.02": {"size": 131072, "crc": "CF7C97C7"}, + "vam.11m": {"size": 2097152, "crc": "4A39DEB2"}, + "vam.12m": {"size": 2097152, "crc": "1A3E5C03"} + + } + } + }, + { + "game": "Night Warriors:Darkstalkers' Revenge (U)", + "system": "Arcade", + "filename": "nwarru.zip", + "in_file": "nwarru", + "status": "playable", + "notes": [1], + "verify": { + "type": "zip", + "entries": { + "vphu.03f": {"size": 524288, "crc": "85D6A359"}, + "vphu.04c": {"size": 524288, "crc": "CB7FCE77"}, + "vphu.05e": {"size": 524288, "crc": "E08F2BBA"}, + "vphu.06c": {"size": 524288, "crc": "08C04CDB"}, + "vphu.07b": {"size": 524288, "crc": "B5A5AB19"}, + "vphu.08b": {"size": 524288, "crc": "51BB20FB"}, + "vphu.09b": {"size": 524288, "crc": "41A64205"}, + "vphu.10b": {"size": 524288, "crc": "2B1D43AE"}, + "vph.13m": {"size": 4194304, "crc": "C51BAF99"}, + "vph.14m": {"size": 4194304, "crc": "7A0E1ADD"}, + "vph.15m": {"size": 4194304, "crc": "3CE83C77"}, + "vph.16m": {"size": 4194304, "crc": "2F41CA75"}, + "vph.17m": {"size": 4194304, "crc": "4F2408E0"}, + "vph.18m": {"size": 4194304, "crc": "64498EED"}, + "vph.19m": {"size": 4194304, "crc": "9FF60250"}, + "vph.20m": {"size": 4194304, "crc": "17F2433F"}, + "vph.01": {"size": 131072, "crc": "5045DCAC"}, + "vph.02": {"size": 131072, "crc": "86B60E59"}, + "vph.11m": {"size": 2097152, "crc": "E1837D33"}, + "vph.12m": {"size": 2097152, "crc": "FBD3CD90"} + } + } + }, + { + "game": "Night Warriors:Darkstalkers' Revenge (J)", + "system": "Arcade", + "filename": "vhuntjr2.zip", + "in_file": "vhuntjr2", + "status": "playable", + "notes": [1], + "verify": { + "type": "zip", + "entries": { + "vphj.03b": {"size": 524288, "crc": "679C3FA9"}, + "vphj.04a": {"size": 524288, "crc": "EB6E71E4"}, + "vphj.05a": {"size": 524288, "crc": "EAF634EA"}, + "vphj.06a": {"size": 524288, "crc": "B70CC6BE"}, + "vphj.07a": {"size": 524288, "crc": "46AB907D"}, + "vphj.08a": {"size": 524288, "crc": "1C00355E"}, + "vphj.09a": {"size": 524288, "crc": "026E6F82"}, + "vphj.10a": {"size": 524288, "crc": "AADFB3EA"}, + "vph.13m": {"size": 4194304, "crc": "C51BAF99"}, + "vph.14m": {"size": 4194304, "crc": "7A0E1ADD"}, + "vph.15m": {"size": 4194304, "crc": "3CE83C77"}, + "vph.16m": {"size": 4194304, "crc": "2F41CA75"}, + "vph.17m": {"size": 4194304, "crc": "4F2408E0"}, + "vph.18m": {"size": 4194304, "crc": "64498EED"}, + "vph.19m": {"size": 4194304, "crc": "9FF60250"}, + "vph.20m": {"size": 4194304, "crc": "17F2433F"}, + "vph.01": {"size": 131072, "crc": "5045DCAC"}, + "vph.02": {"size": 131072, "crc": "86B60E59"}, + "vph.11m": {"size": 2097152, "crc": "E1837D33"}, + "vph.12m": {"size": 2097152, "crc": "FBD3CD90"} + } + } + }, + { + "game": "Vampire Savior: The Lord of Vampire (U)", + "system": "Arcade", + "filename": "vsavu.zip", + "in_file": "vsavu", + "status": "playable", + "notes": [1], + "verify": { + "type": "zip", + "entries": { + "vm3u.03d": {"size": 524288, "crc": "1F295274"}, + "vm3u.04d": {"size": 524288, "crc": "C46ADF81"}, + "vm3.05a": {"size": 524288, "crc": "4118E00F"}, + "vm3.06a": {"size": 524288, "crc": "2F4FD3A9"}, + "vm3.07b": {"size": 524288, "crc": "CBDA91B8"}, + "vm3.08a": {"size": 524288, "crc": "6CA47259"}, + "vm3.09b": {"size": 524288, "crc": "F4A339E3"}, + "vm3.10b": {"size": 524288, "crc": "FFFBB5B8"}, + "vm3.13m": {"size": 4194304, "crc": "FD8A11EB"}, + "vm3.14m": {"size": 4194304, "crc": "C1A28E6C"}, + "vm3.15m": {"size": 4194304, "crc": "DD1E7D4E"}, + "vm3.16m": {"size": 4194304, "crc": "194A7304"}, + "vm3.17m": {"size": 4194304, "crc": "6B89445E"}, + "vm3.18m": {"size": 4194304, "crc": "DF9A9F47"}, + "vm3.19m": {"size": 4194304, "crc": "3830FDC7"}, + "vm3.20m": {"size": 4194304, "crc": "C22FC3D9"}, + "vm3.01": {"size": 131072, "crc": "F778769B"}, + "vm3.02": {"size": 131072, "crc": "CC09FAA1"}, + "vm3.11m": {"size": 4194304, "crc": "E80E956E"}, + "vm3.12m": {"size": 4194304, "crc": "9CD71557"} + } + } + }, + { + "game": "Vampire Hunter 2: Darkstalkers Revenge (J)", + "system": "Arcade", + "filename": "vhunt2.zip", + "in_file": "vhunt2", + "status": "playable", + "notes": [1], + "verify": { + "type": "zip", + "entries": { + "vh2j.03a": {"size": 524288, "crc": "9AE8F186"}, + "vh2j.04a": {"size": 524288, "crc": "E2FABF53"}, + "vh2j.05": {"size": 524288, "crc": "DE34F624"}, + "vh2j.06": {"size": 524288, "crc": "6A3B9897"}, + "vh2j.07": {"size": 524288, "crc": "B021C029"}, + "vh2j.08": {"size": 524288, "crc": "AC873DFF"}, + "vh2j.09": {"size": 524288, "crc": "EAEFCE9C"}, + "vh2j.10": {"size": 524288, "crc": "11730952"}, + "vh2.13m": {"size": 4194304, "crc": "3B02DDAA"}, + "vh2.14m": {"size": 4194304, "crc": "CD09BD63"}, + "vh2.15m": {"size": 4194304, "crc": "4E40DE66"}, + "vh2.16m": {"size": 4194304, "crc": "E0182C15"}, + "vh2.17m": {"size": 4194304, "crc": "B31D00C9"}, + "vh2.18m": {"size": 4194304, "crc": "778DC4F6"}, + "vh2.19m": {"size": 4194304, "crc": "149BE3AB"}, + "vh2.20m": {"size": 4194304, "crc": "605D9D1D"}, + "vh2.01": {"size": 131072, "crc": "67B9F779"}, + "vh2.02": {"size": 131072, "crc": "AAF15FCB"}, + "vh2.11m": {"size": 4194304, "crc": "38922EFD"}, + "vh2.12m": {"size": 4194304, "crc": "6E2430AF"} + } + } + }, + { + "game": "Vampire Savior 2: The Lord of Vampire (J)", + "system": "Arcade", + "filename": "vsav2.zip", + "in_file": "vsav2", + "status": "playable", + "notes": [1], + "verify": { + "type": "zip", + "entries": { + "vs2j.03": {"size": 524288, "crc": "89FD86B4"}, + "vs2j.04": {"size": 524288, "crc": "107C091B"}, + "vs2j.05": {"size": 524288, "crc": "61979638"}, + "vs2j.06": {"size": 524288, "crc": "F37C5BC2"}, + "vs2j.07": {"size": 524288, "crc": "8F885809"}, + "vs2j.08": {"size": 524288, "crc": "2018C120"}, + "vs2j.09": {"size": 524288, "crc": "FAC3C217"}, + "vs2j.10": {"size": 524288, "crc": "EB490213"}, + "vs2.13m": {"size": 4194304, "crc": "5C852F52"}, + "vs2.14m": {"size": 4194304, "crc": "CD09BD63"}, + "vs2.15m": {"size": 4194304, "crc": "A20F58AF"}, + "vs2.16m": {"size": 4194304, "crc": "E0182C15"}, + "vs2.17m": {"size": 4194304, "crc": "39DB59AD"}, + "vs2.18m": {"size": 4194304, "crc": "778DC4F6"}, + "vs2.19m": {"size": 4194304, "crc": "00C763A7"}, + "vs2.20m": {"size": 4194304, "crc": "605D9D1D"}, + "vs2.01": {"size": 131072, "crc": "35190139"}, + "vs2.02": {"size": 131072, "crc": "C32DBA09"}, + "vs2.11m": {"size": 4194304, "crc": "D67E47B7"}, + "vs2.12m": {"size": 4194304, "crc": "6D020A14"} + } + } + }, + { + "game": "Cyberbots: Fullmetal Madness (U)", + "system": "Arcade", + "filename": "cybotsj.zip", + "in_file": "cybotsj", + "status": "playable", + "notes": [1], + "verify": { + "type": "zip", + "entries": { + "cybj.03": {"size": 524288, "crc": "6096EADA"}, + "cybj.04": {"size": 524288, "crc": "7B0FFAA9"}, + "cyb.05": {"size": 524288, "crc": "EC40408E"}, + "cyb.06": {"size": 524288, "crc": "1AD0BED2"}, + "cyb.07": {"size": 524288, "crc": "6245A39A"}, + "cyb.08": {"size": 524288, "crc": "4B48E223"}, + "cyb.09": {"size": 524288, "crc": "E15238F6"}, + "cyb.10": {"size": 524288, "crc": "75F4003B"}, + "cyb.13m": {"size": 4194304, "crc": "F0DCE192"}, + "cyb.14m": {"size": 4194304, "crc": "C1537957"}, + "cyb.15m": {"size": 4194304, "crc": "187AA39C"}, + "cyb.16m": {"size": 4194304, "crc": "15349E86"}, + "cyb.17m": {"size": 4194304, "crc": "8A0E4B12"}, + "cyb.18m": {"size": 4194304, "crc": "D83E977D"}, + "cyb.19m": {"size": 4194304, "crc": "34B62612"}, + "cyb.20m": {"size": 4194304, "crc": "77CDAD5C"}, + "cyb.01": {"size": 131072, "crc": "9C0FB079"}, + "cyb.02": {"size": 131072, "crc": "51CB0C4E"}, + "cyb.11m": {"size": 2097152, "crc": "362CCAB2"}, + "cyb.12m": {"size": 2097152, "crc": "7066E9CC"} + } + } + }, + { + "game": "Cyberbots: Fullmetal Madness (J)", + "system": "Arcade", + "filename": "cybotsu.zip", + "in_file": "cybotsu", + "status": "playable", + "notes": [1], + "verify": { + "type": "zip", + "entries": { + "cybu.03": {"size": 524288, "crc": "DB4DA8F4"}, + "cybu.04": {"size": 524288, "crc": "1EEC68AC"}, + "cyb.05": {"size": 524288, "crc": "EC40408E"}, + "cyb.06": {"size": 524288, "crc": "1AD0BED2"}, + "cyb.07": {"size": 524288, "crc": "6245A39A"}, + "cyb.08": {"size": 524288, "crc": "4B48E223"}, + "cyb.09": {"size": 524288, "crc": "E15238F6"}, + "cyb.10": {"size": 524288, "crc": "75F4003B"}, + "cyb.13m": {"size": 4194304, "crc": "F0DCE192"}, + "cyb.14m": {"size": 4194304, "crc": "C1537957"}, + "cyb.15m": {"size": 4194304, "crc": "187AA39C"}, + "cyb.16m": {"size": 4194304, "crc": "15349E86"}, + "cyb.17m": {"size": 4194304, "crc": "8A0E4B12"}, + "cyb.18m": {"size": 4194304, "crc": "D83E977D"}, + "cyb.19m": {"size": 4194304, "crc": "34B62612"}, + "cyb.20m": {"size": 4194304, "crc": "77CDAD5C"}, + "cyb.01": {"size": 131072, "crc": "9C0FB079"}, + "cyb.02": {"size": 131072, "crc": "51CB0C4E"}, + "cyb.11m": {"size": 2097152, "crc": "362CCAB2"}, + "cyb.12m": {"size": 2097152, "crc": "7066E9CC"} + } + } + }, + { + "game": "Super Puzzle Fighter II Turbo (U)", + "system": "Arcade", + "filename": "spf2tu.zip", + "in_file": "spf2tu", + "status": "playable", + "notes": [1, 3], + "verify": { + "type": "zip", + "entries": { + "pzfu.03a": {"size": 524288, "crc": "346E62EF"}, + "pzf.04": {"size": 524288, "crc": "B80649E2"}, + "pzf.14m": {"size": 1048576, "crc": "2D4881CB"}, + "pzf.16m": {"size": 1048576, "crc": "4B0FD1BE"}, + "pzf.18m": {"size": 1048576, "crc": "E43AAC33"}, + "pzf.20m": {"size": 1048576, "crc": "7F536FF1"}, + "pzf.01": {"size": 131072, "crc": "600FB2A3"}, + "pzf.02": {"size": 131072, "crc": "496076E0"}, + "pzf.11m": {"size": 2097152, "crc": "78442743"}, + "pzf.12m": {"size": 2097152, "crc": "399D2C7B"} + } + } + }, + { + "game": "Super Puzzle Fighter II Turbo (J)", + "system": "Arcade", + "filename": "spf2xj.zip", + "in_file": "spf2xj", + "status": "playable", + "notes": [1, 3], + "verify": { + "type": "zip", + "entries": { + "pzfj.03a": {"size": 524288, "crc": "2070554A"}, + "pzf.04": {"size": 524288, "crc": "B80649E2"}, + "pzf.14m": {"size": 1048576, "crc": "2D4881CB"}, + "pzf.16m": {"size": 1048576, "crc": "4B0FD1BE"}, + "pzf.18m": {"size": 1048576, "crc": "E43AAC33"}, + "pzf.20m": {"size": 1048576, "crc": "7F536FF1"}, + "pzf.01": {"size": 131072, "crc": "600FB2A3"}, + "pzf.02": {"size": 131072, "crc": "496076E0"}, + "pzf.11m": {"size": 2097152, "crc": "78442743"}, + "pzf.12m": {"size": 2097152, "crc": "399D2C7B"} + } + } + }, + { + "game": "Super Gem Fighter Mini Mix (U)", + "system": "Arcade", + "filename": "sgemf.zip", + "in_file": "sgemf", + "status": "playable", + "notes": [1], + "verify": { + "type": "zip", + "entries": { + "pcfu.03a": {"size": 524288, "crc": "AC2E8566"}, + "pcf.04": {"size": 524288, "crc": "F4314C96"}, + "pcf.13m": {"size": 4194304, "crc": "22D72AB9"}, + "pcf.14m": {"size": 1048576, "crc": "0383897C"}, + "pcf.15m": {"size": 4194304, "crc": "16A4813C"}, + "pcf.16m": {"size": 1048576, "crc": "76F91084"}, + "pcf.17m": {"size": 4194304, "crc": "1097E035"}, + "pcf.18m": {"size": 1048576, "crc": "756C3754"}, + "pcf.19m": {"size": 4194304, "crc": "D362D874"}, + "pcf.20m": {"size": 1048576, "crc": "9EC9277D"}, + "pcf.01": {"size": 131072, "crc": "254E5F33"}, + "pcf.02": {"size": 131072, "crc": "6902F4F9"}, + "pcf.11m": {"size": 4194304, "crc": "A5DEA005"}, + "pcf.12m": {"size": 4194304, "crc": "4CE235FE"} + } + } + }, + { + "game": "Super Gem Fighter Mini Mix (J)", + "system": "Arcade", + "filename": "pfghtj.zip", + "in_file": "pfghtj", + "status": "playable", + "notes": [1], + "verify": { + "type": "zip", + "entries": { + "pcfj.03": {"size": 524288, "crc": "681DA43E"}, + "pcf.04": {"size": 524288, "crc": "F4314C96"}, + "pcf.05": {"size": 524288, "crc": "215655F6"}, + "pcf.06": {"size": 524288, "crc": "EA6F13EA"}, + "pcf.07": {"size": 524288, "crc": "5AC6D5EA"}, + "pcf.13m": {"size": 4194304, "crc": "22D72AB9"}, + "pcf.14m": {"size": 1048576, "crc": "0383897C"}, + "pcf.15m": {"size": 4194304, "crc": "16A4813C"}, + "pcf.16m": {"size": 1048576, "crc": "76F91084"}, + "pcf.17m": {"size": 4194304, "crc": "1097E035"}, + "pcf.18m": {"size": 1048576, "crc": "756C3754"}, + "pcf.19m": {"size": 4194304, "crc": "D362D874"}, + "pcf.20m": {"size": 1048576, "crc": "9EC9277D"}, + "pcf.01": {"size": 131072, "crc": "254E5F33"}, + "pcf.02": {"size": 131072, "crc": "6902F4F9"}, + "pcf.11m": {"size": 4194304, "crc": "A5DEA005"}, + "pcf.12m": {"size": 4194304, "crc": "4CE235FE"} + } + } + }, + { + "game": "Hyper Street Fighter II: Anniversary Edition (U)", + "system": "Arcade", + "filename": "hsf2.zip", + "in_file": "hsf2", + "status": "playable", + "notes": [1, 4], + "verify": { + "type": "zip", + "entries": { + "hs2u.03": {"size": 524288, "crc": "B308151E"}, + "hs2u.04": {"size": 524288, "crc": "327AA49C"}, + "hs2.05": {"size": 524288, "crc": "DDE34A35"}, + "hs2.06": {"size": 524288, "crc": "F4E56DDA"}, + "hs2.07": {"size": 524288, "crc": "EE4420FC"}, + "hs2.08": {"size": 524288, "crc": "C9441533"}, + "hs2.09": {"size": 524288, "crc": "3FC638A8"}, + "hs2.10": {"size": 524288, "crc": "20D0F9E4"}, + "hs2.13m": {"size": 8388608, "crc": "A6ECAB17"}, + "hs2.15m": {"size": 8388608, "crc": "10A0AE4D"}, + "hs2.17m": {"size": 8388608, "crc": "ADFA7726"}, + "hs2.19m": {"size": 8388608, "crc": "BB3AE322"}, + "hs2.01": {"size": 131072, "crc": "C1A13786"}, + "hs2.02": {"size": 131072, "crc": "2D8794AA"}, + "hs2.11m": {"size": 8388608, "crc": "0E15C359"} + } + } + }, + { + "game": "Hyper Street Fighter II: Anniversary Edition (J)", + "system": "Arcade", + "filename": "hsf2j.zip", + "in_file": "hsf2j", + "status": "playable", + "notes": [1, 4], + "verify": { + "type": "zip", + "entries": { + "hs2j.03": {"size": 524288, "crc": "6EFE661F"}, + "hs2j.04": {"size": 524288, "crc": "93F2500A"}, + "hs2j.05": {"size": 524288, "crc": "DDE34A35"}, + "hs2j.06": {"size": 524288, "crc": "F4E56DDA"}, + "hs2j.07": {"size": 524288, "crc": "EE4420FC"}, + "hs2j.08": {"size": 524288, "crc": "C9441533"}, + "hs2j.09": {"size": 524288, "crc": "3FC638A8"}, + "hs2j.10": {"size": 524288, "crc": "20D0F9E4"}, + "hs2.13m": {"size": 8388608, "crc": "A6ECAB17"}, + "hs2.15m": {"size": 8388608, "crc": "10A0AE4D"}, + "hs2.17m": {"size": 8388608, "crc": "ADFA7726"}, + "hs2.19m": {"size": 8388608, "crc": "BB3AE322"}, + "hs2.01": {"size": 131072, "crc": "C1A13786"}, + "hs2.02": {"size": 131072, "crc": "2D8794AA"}, + "hs2.11m": {"size": 8388608, "crc": "0E15C359"} + } + } + }, + { + "game": "Red Earth (U)", + "system": "Arcade", + "filename": "N/A", + "in_file": "redearth", + "status": "no-rom", + "notes": [2] + }, + { + "game": "Warzard (J)", + "system": "Arcade", + "filename": "N/A", + "in_file": "warzard", + "status": "no-rom", + "notes": [2] + } + ], + "notes": { + "1": "These ROMs require an older version MAME. They test fine in MAME 0.139 (Mame 2010 in RetroArch). This is typically due to a missing decryption key, dl-1425.bin qsound rom, or other ROM files that the older MAME did not strictly require", + "2": "This CPS3 game cannot yet be extracted.", + "3": "The US version of this does not have a valid MAME release.", + "4": "The JP version of this is using an older internal file naming convention." + } + } +} \ No newline at end of file diff --git a/src/gex/lib/tasks/impl/ddragontrilogy.py b/src/gex/lib/tasks/impl/ddragontrilogy/__init__.py similarity index 87% rename from src/gex/lib/tasks/impl/ddragontrilogy.py rename to src/gex/lib/tasks/impl/ddragontrilogy/__init__.py index 8ad7631..021d08d 100644 --- a/src/gex/lib/tasks/impl/ddragontrilogy.py +++ b/src/gex/lib/tasks/impl/ddragontrilogy/__init__.py @@ -16,41 +16,19 @@ class DoubleDragonTrilogyTask(BaseTask): _details_markdown = ''' Based on dotemu2mame.js: https://gist.github.com/cxx/81b9f45eb5b3cb87b4f3783ccdf8894f ''' - _game_info_list = [ - { - "game": "Double Dragon", - "filename": "ddragon.zip", - "notes": [] - }, - { - "game": "Double Dragon 2: The Revenge", - "filename": "ddragon2.zip", - "notes": [] - }, - { - "game": "Double Dragon 3: The Rosetta Stone", - "filename": "dragon3.zip", - "notes": [1] - } - ] - _out_file_notes = { - "1": "This ROM is missing the PROM file. A placeholder allows it to work for MAME, but this doesn't work for FB Neo." - } _default_input_folder = helpers.gen_steam_app_default_folder("Double Dragon Trilogy") _input_folder_desc = "Double Dragon Trilogy Steam folder" - def __init__(self): - super().__init__() - self._out_file_list = map(lambda x: { - 'filename': x['filename'], - 'game': x['game'], - 'status': "good", - 'system': "Arcade", - "notes": x['notes']}, - self._game_info_list) + def get_out_file_info(self): + '''Return a list of output files''' + return { + "files": self._metadata['out']['files'], + "notes": self._metadata['out']['notes'] + } def execute(self, in_dir, out_dir): - all_ddragon_trio_files = self._read_all_files(in_dir) + verified_in_files = self.read_all_datafiles(in_dir) + in_files = {k: v['contents'] for k,v in verified_in_files.items()} funcs = [ self._ddragon, @@ -60,22 +38,13 @@ def execute(self, in_dir, out_dir): for func in funcs: logger.info(f"Extracting {func.__name__[1:]}...") - rom_package = func(all_ddragon_trio_files) + rom_package = func(in_files) + _ = self.verify_out_file(rom_package['filename'], rom_package['contents']) with open(os.path.join(out_dir, rom_package['filename']), "wb") as out_file: out_file.write(rom_package['contents']) logger.info("Processing complete.") - def _read_all_files(self, base_path): - files_path = os.path.join(base_path, "resources", "game") - file_paths = glob.glob(files_path +'/*.*') - files = {} - for file_path in file_paths: - with open(file_path, 'rb') as file_obj: - file_data = file_obj.read() - files[os.path.basename(file_path)] = file_data - return files - def _dotemu_reencode_gfx_helper(self, in_file_name, filenames, layout): def encode(in_files): contents = in_files[in_file_name] diff --git a/src/gex/lib/tasks/impl/ddragontrilogy/metadata.json b/src/gex/lib/tasks/impl/ddragontrilogy/metadata.json new file mode 100644 index 0000000..a710777 --- /dev/null +++ b/src/gex/lib/tasks/impl/ddragontrilogy/metadata.json @@ -0,0 +1,308 @@ +{ + "in": { + "files": { + "ddragon2_gfxdata1.bin": { + "rel_path": ["resources", "game"], + "filename": "ddragon2_gfxdata1.bin", + "versions": { + "Steam": { + "crc": "CBFF4713", + "size": 131072 + } + } + }, + "ddragon2_gfxdata2.bin": { + "rel_path": ["resources", "game"], + "filename": "ddragon2_gfxdata2.bin", + "versions": { + "Steam": { + "crc": "FF97392E", + "size": 1572864 + } + } + }, + "ddragon2_gfxdata3.bin": { + "rel_path": ["resources", "game"], + "filename": "ddragon2_gfxdata3.bin", + "versions": { + "Steam": { + "crc": "D1696A65", + "size": 524288 + } + } + }, + "ddragon2_hd6309.bin": { + "rel_path": ["resources", "game"], + "filename": "ddragon2_hd6309.bin", + "versions": { + "Steam": { + "crc": "6A11D7EE", + "size": 131072 + } + } + }, + "ddragon2_oki.bin": { + "rel_path": ["resources", "game"], + "filename": "ddragon2_oki.bin", + "versions": { + "Steam": { + "crc": "F0A160D6", + "size": 262144 + } + } + }, + "ddragon2_z80sound.bin": { + "rel_path": ["resources", "game"], + "filename": "ddragon2_z80sound.bin", + "versions": { + "Steam": { + "crc": "75E36CD6", + "size": 32768 + } + } + }, + "ddragon2_z80sub.bin": { + "rel_path": ["resources", "game"], + "filename": "ddragon2_z80sub.bin", + "versions": { + "Steam": { + "crc": "EA437867", + "size": 65536 + } + } + }, + "ddragon3_gfxdata1.bin": { + "rel_path": ["resources", "game"], + "filename": "ddragon3_gfxdata1.bin", + "versions": { + "Steam": { + "crc": "C82ECFE4", + "size": 2097152 + } + } + }, + "ddragon3_gfxdata2.bin": { + "rel_path": ["resources", "game"], + "filename": "ddragon3_gfxdata2.bin", + "versions": { + "Steam": { + "crc": "4E1FF192", + "size": 4718592 + } + } + }, + "ddragon3_m68k.bin": { + "rel_path": ["resources", "game"], + "filename": "ddragon3_m68k.bin", + "versions": { + "Steam": { + "crc": "C4EDC727", + "size": 524288 + } + } + }, + "ddragon3_oki.bin": { + "rel_path": ["resources", "game"], + "filename": "ddragon3_oki.bin", + "versions": { + "Steam": { + "crc": "C3AD40F3", + "size": 524288 + } + } + }, + "ddragon3_z80.bin": { + "rel_path": ["resources", "game"], + "filename": "ddragon3_z80.bin", + "versions": { + "Steam": { + "crc": "1E974D9B", + "size": 65536 + } + } + }, + "ddragon_adpcm.bin": { + "rel_path": ["resources", "game"], + "filename": "ddragon_adpcm.bin", + "versions": { + "Steam": { + "crc": "CF003BD6", + "size": 131072 + } + } + }, + "ddragon_gfxdata1.bin": { + "rel_path": ["resources", "game"], + "filename": "ddragon_gfxdata1.bin", + "versions": { + "Steam": { + "crc": "60D388CE", + "size": 65536 + } + } + }, + "ddragon_gfxdata2.bin": { + "rel_path": ["resources", "game"], + "filename": "ddragon_gfxdata2.bin", + "versions": { + "Steam": { + "crc": "E39C0594", + "size": 1048576 + } + } + }, + "ddragon_gfxdata3.bin": { + "rel_path": ["resources", "game"], + "filename": "ddragon_gfxdata3.bin", + "versions": { + "Steam": { + "crc": "C7844D5C", + "size": 524288 + } + } + }, + "ddragon_hd6309.bin": { + "rel_path": ["resources", "game"], + "filename": "ddragon_hd6309.bin", + "versions": { + "Steam": { + "crc": "BFD3CBB5", + "size": 131072 + } + } + }, + "ddragon_hd63701.bin": { + "rel_path": ["resources", "game"], + "filename": "ddragon_hd63701.bin", + "versions": { + "Steam": { + "crc": "F5232D03", + "size": 16384 + } + } + }, + "ddragon_m6809.bin": { + "rel_path": ["resources", "game"], + "filename": "ddragon_m6809.bin", + "versions": { + "Steam": { + "crc": "9EFA95BB", + "size": 32768 + } + } + }, + "proms.bin": { + "rel_path": ["resources", "game"], + "filename": "proms.bin", + "versions": { + "Steam": { + "crc": "35C1DB1C", + "size": 768 + } + } + } + } + }, + "out": { + "files": [ + { + "game": "Double Dragon", + "filename": "ddragon.zip", + "notes": [], + "status": "good", + "system": "Arcade", + "verify": { + "type": "zip", + "entries": { + "21j-1-5.26": {"size": 32768, "crc": "42045DFD"}, + "21j-2-3.25": {"size": 32768, "crc": "5779705E"}, + "21j-3.24": {"size": 32768, "crc": "3BDEA613"}, + "21j-4-1.23": {"size": 32768, "crc": "728F87B9"}, + "21jm-0.ic55": {"size": 16384, "crc": "F5232D03"}, + "21j-0-1": {"size": 32768, "crc": "9EFA95BB"}, + "21j-5": {"size": 32768, "crc": "7A8B8DB4"}, + "21j-a": {"size": 65536, "crc": "574FACE3"}, + "21j-b": {"size": 65536, "crc": "40507A76"}, + "21j-c": {"size": 65536, "crc": "BB0BC76F"}, + "21j-d": {"size": 65536, "crc": "CB4F231B"}, + "21j-e": {"size": 65536, "crc": "A0A0C261"}, + "21j-f": {"size": 65536, "crc": "6BA152F6"}, + "21j-g": {"size": 65536, "crc": "3220A0B6"}, + "21j-h": {"size": 65536, "crc": "65C7517D"}, + "21j-8": {"size": 65536, "crc": "7C435887"}, + "21j-9": {"size": 65536, "crc": "C6640AED"}, + "21j-i": {"size": 65536, "crc": "5EFFB0A0"}, + "21j-j": {"size": 65536, "crc": "5FB42E7C"}, + "21j-6": {"size": 65536, "crc": "34755DE3"}, + "21j-7": {"size": 65536, "crc": "904DE6F8"}, + "21j-k-0": {"size": 256, "crc": "FDB130A9"}, + "21j-l-0": {"size": 512, "crc": "46339529"} + } + } + }, + { + "game": "Double Dragon 2: The Revenge", + "filename": "ddragon2.zip", + "notes": [], + "status": "good", + "system": "Arcade", + "verify": { + "type": "zip", + "entries": { + "26a9-04.bin": {"size": 32768, "crc": "F2CFC649"}, + "26aa-03.bin": {"size": 32768, "crc": "44DD5D4B"}, + "26ab-0.bin": {"size": 32768, "crc": "49DDDDCD"}, + "26ac-0e.63": {"size": 32768, "crc": "57ACAD2C"}, + "26ae-0.bin": {"size": 65536, "crc": "EA437867"}, + "26ad-0.bin": {"size": 32768, "crc": "75E36CD6"}, + "26a8-0e.19": {"size": 65536, "crc": "4E80CD36"}, + "26j0-0.bin": {"size": 131072, "crc": "DB309C84"}, + "26j1-0.bin": {"size": 131072, "crc": "C3081E0C"}, + "26af-0.bin": {"size": 131072, "crc": "3A615AAD"}, + "26j2-0.bin": {"size": 131072, "crc": "589564AE"}, + "26j3-0.bin": {"size": 131072, "crc": "DAF040D6"}, + "26a10-0.bin": {"size": 131072, "crc": "6D16D889"}, + "26j4-0.bin": {"size": 131072, "crc": "A8C93E76"}, + "26j5-0.bin": {"size": 131072, "crc": "EE555237"}, + "26j6-0.bin": {"size": 131072, "crc": "A84B2A29"}, + "26j7-0.bin": {"size": 131072, "crc": "BC6A48D5"}, + "21j-k-0": {"size": 256, "crc": "FDB130A9"}, + "prom.16": {"size": 512, "crc": "46339529"} + } + } + }, + { + "game": "Double Dragon 3: The Rosetta Stone", + "filename": "ddragon3.zip", + "notes": [1], + "status": "good", + "system": "Arcade", + "verify": { + "type": "zip", + "entries": { + "30a15-0.ic79": {"size": 131072, "crc": "AD50E92C"}, + "30a14-0.ic78": {"size": 262144, "crc": "F42FE016"}, + "30a13-0.ic43": {"size": 65536, "crc": "1E974D9B"}, + "30j-6.ic5": {"size": 262144, "crc": "9BF1538E"}, + "30j-4.ic7": {"size": 262144, "crc": "0F74EA1C"}, + "30j-7.ic4": {"size": 262144, "crc": "89D58D32"}, + "30j-5.ic6": {"size": 262144, "crc": "8F671A62"}, + "30j-3.ic9": {"size": 524288, "crc": "B3151871"}, + "30a12-0.ic8": {"size": 65536, "crc": "20D64BEA"}, + "30j-2.ic11": {"size": 524288, "crc": "41C6FB08"}, + "30a11-0.ic10": {"size": 65536, "crc": "785D71B0"}, + "30j-1.ic13": {"size": 524288, "crc": "67A6F114"}, + "30a10-0.ic12": {"size": 65536, "crc": "15E43D12"}, + "30j-0.ic15": {"size": 524288, "crc": "F15DAFBE"}, + "30a9-0.ic14": {"size": 65536, "crc": "5A47E7A4"}, + "30j-8.ic73": {"size": 524288, "crc": "C3AD40F3"}, + "mb7114h.ic38": {"size": 256, "crc": "0D968558"} + } + } + } + ], + "notes": { + "1": "This ROM is missing the PROM file. A placeholder allows it to work for MAME, but this doesn't work for FB Neo." + } + } +} \ No newline at end of file diff --git a/src/gex/lib/tasks/impl/disneyac.py b/src/gex/lib/tasks/impl/disneyac.py deleted file mode 100644 index 882d80a..0000000 --- a/src/gex/lib/tasks/impl/disneyac.py +++ /dev/null @@ -1,97 +0,0 @@ -'''Implemntation of disneyac: Disney Afternoon Collection''' -import logging -import os -from gex.lib.tasks.basetask import BaseTask -from gex.lib.tasks import helpers - -logger = logging.getLogger('gextoolbox') - -class DisneyAfternoonCollectionTask(BaseTask): - '''Implemnts disneyac: Disney Afternoon Collection''' - _task_name = "disneyac" - _title = "Disney Afternoon Collection" - _details_markdown = ''' -Based on MMLC & DAC Extractor - https://github.com/HTV04/mmlc-dac-extractor -''' - _out_file_notes = {} - _default_input_folder = helpers.gen_steam_app_default_folder("DisneyAfternoon") - _input_folder_desc = "DisneyAfternoon Folder (Steam install folder)" - - _game_info_list = [ - { - 'filename': 'Chip n Dale - Rescue Rangers (DAC).nes', - 'name': 'Chip n Dale - Rescue Rangers', - 'sections': { - 'prg': {'start': 0x7F2F30, 'length': 0x40000} - }, - 'header': b'\x4E\x45\x53\x1A\x08\x10\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00' - }, - { - 'filename': 'Chip n Dale - Rescue Rangers 2 (DAC).nes', - 'name': 'Chip n Dale - Rescue Rangers 2', - 'sections': { - 'prg': {'start': 0x832F30, 'length': 0x40000} - }, - 'header': b'\x4E\x45\x53\x1A\x08\x10\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00' - }, - { - 'filename': 'Darkwing Duck (DAC).nes', - 'name': 'Darkwing Duck', - 'sections': { - 'prg': {'start': 0x792F30, 'length': 0x20000}, - 'cha': {'start': 0x772F30, 'length': 0x20000} - }, - 'header': b'\x4E\x45\x53\x1A\x08\x10\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00' - }, - { - 'filename': 'DuckTales (DAC).nes', - 'name': 'DuckTales', - 'sections': { - 'prg': {'start': 0x7B2F30, 'length': 0x20000} - }, - 'header': b'\x4E\x45\x53\x1A\x08\x00\x21\x00\x00\x00\x00\x00\x00\x00\x00\x00' - }, - { - 'filename': 'DuckTales 2 (DAC).nes', - 'name': 'DuckTales 2', - 'sections': { - 'prg': {'start': 0x7D2F30, 'length': 0x20000} - }, - 'header': b'\x4E\x45\x53\x1A\x08\x00\x21\x00\x00\x00\x00\x00\x00\x00\x00\x00' - }, - { - 'filename': 'TaleSpin (DAC).nes', - 'name': 'TaleSpin', - 'sections': { - 'prg': {'start': 0x872F30, 'length': 0x40000} - }, - 'header': b'\x4E\x45\x53\x1A\x08\x10\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00' - } - ] - - def __init__(self): - super().__init__() - self._out_file_list = map(lambda x: { - 'filename': x['filename'], - 'game': x['name'], - 'status': "good", - 'system': "NES", - "notes": []}, - self._game_info_list) - - def execute(self, in_dir, out_dir): - exe_path = os.path.join(in_dir, 'capcom_disney_afternoon.exe') - with open(exe_path, 'rb') as exe_file: - exe_data = exe_file.read() - - for game_info in self._game_info_list: - logger.info(f"Extracting {game_info['name']}...") - game_data = bytearray() - game_data.extend(game_info['header']) - for section in game_info['sections'].values(): - game_data.extend(exe_data[section['start']:section['start']+section['length']]) - - with open(os.path.join(out_dir, game_info['filename']), "wb") as out_file: - out_file.write(game_data) - - logger.info("Processing complete.") diff --git a/src/gex/lib/tasks/impl/disneyac/__init__.py b/src/gex/lib/tasks/impl/disneyac/__init__.py new file mode 100644 index 0000000..fbe56bb --- /dev/null +++ b/src/gex/lib/tasks/impl/disneyac/__init__.py @@ -0,0 +1,14 @@ +'''Implemntation of disneyac: Disney Afternoon Collection''' +from gex.lib.tasks.splicetask import SpliceTask +from gex.lib.tasks import helpers + +class DisneyAfternoonCollectionTask(SpliceTask): + '''Implemnts disneyac: Disney Afternoon Collection''' + _task_name = "disneyac" + _title = "Disney Afternoon Collection" + _details_markdown = ''' +Based on MMLC & DAC Extractor - https://github.com/HTV04/mmlc-dac-extractor +''' + _out_file_notes = {} + _default_input_folder = helpers.gen_steam_app_default_folder("DisneyAfternoon") + _input_folder_desc = "DisneyAfternoon Folder (Steam install folder)" diff --git a/src/gex/lib/tasks/impl/disneyac/metadata.json b/src/gex/lib/tasks/impl/disneyac/metadata.json new file mode 100644 index 0000000..7d7f7b6 --- /dev/null +++ b/src/gex/lib/tasks/impl/disneyac/metadata.json @@ -0,0 +1,117 @@ +{ + "in": { + "files": { + "source": { + "filename": "capcom_disney_afternoon.exe", + "versions": { + "Steam": { + "crc": "6F75A8A1", + "size": 11639296 + } + } + } + } + }, + "out": { + "files": [ + { + "game": "Chip n Dale - Rescue Rangers", + "system": "NES", + "filename": "Chip n Dale - Rescue Rangers (DAC).nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "F3396499", + "size": 262160 + }, + "sections": { + "prg": {"start": "0x7F2F30", "length": "0x40000"} + }, + "header": "4E45531A081010000000000000000000" + }, + { + "game": "Chip n Dale - Rescue Rangers 2", + "system": "NES", + "filename": "Chip n Dale - Rescue Rangers 2 (DAC).nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "A8D3A5F9", + "size": 262160 + }, + "sections": { + "prg": {"start": "0x832F30", "length": "0x40000"} + }, + "header": "4E45531A081010000000000000000000" + }, + { + "game": "Darkwing Duck", + "system": "NES", + "filename": "Darkwing Duck (DAC).nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "A8D3A5F9", + "size": 262160 + }, + "sections": { + "prg": {"start": "0x792F30", "length": "0x20000"}, + "cha": {"start": "0x772F30", "length": "0x20000"} + }, + "header": "4E45531A081010000000000000000000" + }, + { + "game": "DuckTales", + "system": "NES", + "filename": "DuckTales (DAC).nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "76CAE92F", + "size": 131088 + }, + "sections": { + "prg": {"start": "0x7B2F30", "length": "0x20000"} + }, + "header": "4E45531A080021000000000000000000" + }, + { + "game": "DuckTales 2", + "system": "NES", + "filename": "DuckTales 2 (DAC).nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "64018A4D", + "size": 131088 + }, + "sections": { + "prg": {"start": "0x7D2F30", "length": "0x20000"} + }, + "header": "4E45531A080021000000000000000000" + }, + { + "game": "TaleSpin", + "system": "NES", + "filename": "TaleSpin (DAC).nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "C4CDEF75", + "size": 262160 + }, + "sections": { + "prg": {"start": "0x872F30", "length": "0x40000"} + }, + "header": "4E45531A081010000000000000000000" + } + ], + "notes": {} + } +} \ No newline at end of file diff --git a/src/gex/lib/tasks/impl/disneyalkb.py b/src/gex/lib/tasks/impl/disneyalkb.py deleted file mode 100644 index 9118306..0000000 --- a/src/gex/lib/tasks/impl/disneyalkb.py +++ /dev/null @@ -1,219 +0,0 @@ -'''Implementation of disneyalkb: Disney Aladdin / Lion King Bundle (and DLC)''' -import glob -import logging -import os -from gex.lib.contrib.bputil import BPListReader -from gex.lib.tasks import helpers -from gex.lib.tasks.basetask import BaseTask - -logger = logging.getLogger('gextoolbox') - -class DisneyClassicsTask(BaseTask): - '''Implements disneyalkb: Disney Aladdin / Lion King Bundle (and DLC)''' - _task_name = "disneyalkb" - _title = "Disney Aladdin / Lion King Bundle (and DLC)" - _details_markdown = ''' -Based on https://github.com/farmerbb/RED-Project/wiki/Disney-Classic-Games:-Aladdin-and-The-Lion-King -''' - _out_file_list = [ - { - "game": "Aladdin", - "system": "Game Boy", - "filename": "Aladdin.gb", - 'status': "good", - "notes": [] - }, - { - "game": "Jungle Book", - "system": "Game Boy", - "filename": "JungleBook.gb", - 'status': "good", - "notes": [] - }, - { - "game": "Lion King", - "system": "Game Boy", - "filename": "LionKing.gb", - 'status': "good", - "notes": [] - }, - { - "game": "Aladdin (4F7A Patch)", - "system": "Genesis", - "filename": "Aladdin.4F7A.PATCHED.md", - 'status': "playable", - "notes": [] - }, - { - "game": "Aladdin (9CB2 Patch)", - "system": "Genesis", - "filename": "Aladdin.9CB2.PATCHED.md", - 'status': "playable", - "notes": [] - }, - { - "game": "Aladdin (CES Patch)", - "system": "Genesis", - "filename": "Aladdin.CES.PATCHED.md", - 'status': "playable", - "notes": [] - }, - { - "game": "Aladdin Remix", - "system": "Genesis", - "filename": "Aladdin-Remix.md", - 'status': "playable", - "notes": [] - }, - { - "game": "Jungle Book", - "system": "Genesis", - "filename": "JungleBook.md", - 'status': "good", - "notes": [] - }, - { - "game": "Jungle Book (Patched)", - "system": "Genesis", - "filename": "JUNGLEBOOK.PATCHED.md", - 'status': "playable", - "notes": [] - }, - { - "game": "Lion King (0D3D Patch)", - "system": "Genesis", - "filename": "LionKing.0D3D.PATCHED.md", - 'status': "playable", - "notes": [] - }, - { - "game": "Jungle Book", - "system": "NES", - "filename": "JungleBook.sfc", - 'status': "good", - "notes": [] - }, - { - "game": "Aladdin", - "system": "SNES", - "filename": "Aladdin.sfc", - 'status': "good", - "notes": [] - }, - { - "game": "Jungle Book", - "system": "SNES", - "filename": "JungleBook.sfc", - 'status': "good", - "notes": [] - }, - { - "game": "Jungle Book Music", - "system": "SNES", - "filename": "JungleBookMusicROM.sfc", - 'status': "good", - "notes": [] - }, - { - "game": "Lion King (919A Patch)", - "system": "SNES", - "filename": "LionKing.919A.PATCHED.sfc", - 'status': "playable", - "notes": [] - }, - { - "game": "Lion King (DE6E Patch)", - "system": "SNES", - "filename": "LionKing.DE6E.PATCHED.sfc", - 'status': "playable", - "notes": [] - } - ] - _out_file_notes = {} - _default_input_folder = helpers.gen_steam_app_default_folder( - "Disney Classic Games Aladdin and the Lion King") - _input_folder_desc = "Disney Classics Steam folder" - - def execute(self, in_dir, out_dir): - bundle_files = self._find_files(in_dir) - for file_path in bundle_files: - with open(file_path, 'rb') as in_file: - file_name = os.path.basename(file_path) - pkg_name = self._pkg_name_map.get(file_name) - if pkg_name is not None: - logger.info(f'Reading files for {file_name}...') - contents = in_file.read() - reader = BPListReader(contents) - parsed = reader.parse() - - handler_func = self.find_handler_func(pkg_name) - if parsed is not None and handler_func is not None: - output_files = handler_func(parsed) - for out_file_entry in output_files: - out_path = os.path.join(out_dir, out_file_entry['filename']) - with open(out_path, "wb") as out_file: - out_file.write(out_file_entry['contents']) - elif parsed is None: - logger.warning("Could not find merged rom data in mbundle.") - elif handler_func is None: - logger.warning("Could not find matching handler function.") - else: - logger.info(f'Skipping {file_name} as it contains no known roms...') - logger.info("Processing complete.") - - _pkg_name_map = { - 'bundleAladdin.mbundle': 'aladdin', - 'bundleDLC1.mbundle': 'dlc', - 'bundleLionKing.mbundle': 'lionking', - 'bundleMain.mbundle': 'main', - } - - def _find_files(self, base_path): - bundle_path = os.path.join(base_path, "Bundle", '*.mbundle') - archive_list = glob.glob(bundle_path) - return archive_list - - def _handle_aladdin(self, mbundle_entries): - files = { - 'Aladdin-Remix.bin', - 'Aladdin.4F7A.PATCHED.bin', - 'Aladdin.9CB2.PATCHED.bin', - 'Aladdin.CES.PATCHED.bin', - 'Aladdin.gb' - } - return self._bundle_handler(files, mbundle_entries) - - def _handle_dlc(self, mbundle_entries): - files = { - 'JungleBook.gb', - 'JungleBook.md', - 'JungleBook.nes', - 'Aladdin.sfc', - 'JungleBook.sfc', - 'JungleBookMusicROM.sfc' - } - return self._bundle_handler(files, mbundle_entries) - - def _handle_lionking(self, mbundle_entries): - files = { - 'LionKing.0D3D.PATCHED.bin', - 'LionKing.gb', - 'LionKing.919A.PATCHED.sfc', - 'LionKing.DE6E.PATCHED.sfc', - } - return self._bundle_handler(files, mbundle_entries) - - def _handle_main(self, mbundle_entries): - files = { - 'JUNGLEBOOK.PATCHED.md', - } - return self._bundle_handler(files, mbundle_entries) - - def _bundle_handler(self, files, mbundle_entries): - out_files = [] - for file in files: - out_name = file.replace('.bin', '.md') - logger.info(f'Extracting {out_name}...') - out_files.append({'filename': out_name, 'contents': mbundle_entries[file]}) - return out_files - \ No newline at end of file diff --git a/src/gex/lib/tasks/impl/disneyalkb/__init__.py b/src/gex/lib/tasks/impl/disneyalkb/__init__.py new file mode 100644 index 0000000..b594551 --- /dev/null +++ b/src/gex/lib/tasks/impl/disneyalkb/__init__.py @@ -0,0 +1,103 @@ +'''Implementation of disneyalkb: Disney Aladdin / Lion King Bundle (and DLC)''' +import glob +import logging +import os +from gex.lib.contrib.bputil import BPListReader +from gex.lib.tasks import helpers +from gex.lib.tasks.basetask import BaseTask + +logger = logging.getLogger('gextoolbox') + +class DisneyClassicsTask(BaseTask): + '''Implements disneyalkb: Disney Aladdin / Lion King Bundle (and DLC)''' + _task_name = "disneyalkb" + _title = "Disney Aladdin / Lion King Bundle (and DLC)" + _details_markdown = ''' +Based on https://github.com/farmerbb/RED-Project/wiki/Disney-Classic-Games:-Aladdin-and-The-Lion-King +''' + _default_input_folder = helpers.gen_steam_app_default_folder( + "Disney Classic Games Aladdin and the Lion King") + _input_folder_desc = "Disney Classics Steam folder" + + def get_out_file_info(self): + '''Return a list of output files''' + return { + "files": self._metadata['out']['files'], + "notes": self._metadata['out']['notes'] + } + + def execute(self, in_dir, out_dir): + for file_metadata in self._metadata['in']['files'].values(): + file_name = file_metadata['filename'] + pkg_name = self._pkg_name_map.get(file_name) + datafile = self.read_datafile(in_dir, file_metadata) + contents = datafile['contents'] + logger.info(f'Reading files for {file_name}...') + reader = BPListReader(contents) + parsed = reader.parse() + + handler_func = self.find_handler_func(pkg_name) + if parsed is not None and handler_func is not None: + output_files = handler_func(parsed) + for out_file_entry in output_files: + _ = self.verify_out_file(out_file_entry['filename'], out_file_entry['contents']) + out_path = os.path.join(out_dir, out_file_entry['filename']) + with open(out_path, "wb") as out_file: + out_file.write(out_file_entry['contents']) + elif parsed is None: + logger.warning("Could not find merged rom data in mbundle.") + elif handler_func is None: + logger.warning("Could not find matching handler function.") + logger.info("Processing complete.") + + _pkg_name_map = { + 'bundleAladdin.mbundle': 'aladdin', + 'bundleDLC1.mbundle': 'dlc', + 'bundleLionKing.mbundle': 'lionking', + 'bundleMain.mbundle': 'main', + } + + def _handle_aladdin(self, mbundle_entries): + files = { + 'Aladdin-Remix.bin', + 'Aladdin.4F7A.PATCHED.bin', + 'Aladdin.9CB2.PATCHED.bin', + 'Aladdin.CES.PATCHED.bin', + 'Aladdin.gb' + } + return self._bundle_handler(files, mbundle_entries) + + def _handle_dlc(self, mbundle_entries): + files = { + 'JungleBook.gb', + 'JungleBook.md', + 'JungleBook.nes', + 'Aladdin.sfc', + 'JungleBook.sfc', + 'JungleBookMusicROM.sfc' + } + return self._bundle_handler(files, mbundle_entries) + + def _handle_lionking(self, mbundle_entries): + files = { + 'LionKing.0D3D.PATCHED.bin', + 'LionKing.gb', + 'LionKing.919A.PATCHED.sfc', + 'LionKing.DE6E.PATCHED.sfc', + } + return self._bundle_handler(files, mbundle_entries) + + def _handle_main(self, mbundle_entries): + files = { + 'JUNGLEBOOK.PATCHED.md', + } + return self._bundle_handler(files, mbundle_entries) + + def _bundle_handler(self, files, mbundle_entries): + out_files = [] + for file in files: + out_name = file.replace('.bin', '.md') + logger.info(f'Extracting {out_name}...') + out_files.append({'filename': out_name, 'contents': mbundle_entries[file]}) + return out_files + \ No newline at end of file diff --git a/src/gex/lib/tasks/impl/disneyalkb/metadata.json b/src/gex/lib/tasks/impl/disneyalkb/metadata.json new file mode 100644 index 0000000..d78a1b0 --- /dev/null +++ b/src/gex/lib/tasks/impl/disneyalkb/metadata.json @@ -0,0 +1,243 @@ +{ + "in": { + "files": { + "aladdin": { + "rel_path": ["Bundle"], + "filename": "bundleAladdin.mbundle", + "versions": { + "Steam": { + "crc": "62C5484D", + "size": 953025346 + } + } + }, + "dlc" : { + "rel_path": ["Bundle"], + "filename": "bundleDLC1.mbundle", + "versions": { + "Steam": { + "crc": "B8EA48BB", + "size": 395996529 + } + } + }, + "lionking" : { + "rel_path": ["Bundle"], + "filename": "bundleLionKing.mbundle", + "versions": { + "Steam": { + "crc": "85DAC996", + "size": 385352264 + } + } + }, + "main" : { + "rel_path": ["Bundle"], + "filename": "bundleMain.mbundle", + "versions": { + "Steam": { + "crc": "2C46726B", + "size": 859395319 + } + } + } + } + }, + "out": { + "files": [ + { + "game": "Aladdin Remix", + "system": "Genesis", + "filename": "Aladdin-Remix.md", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2384052, + "crc": "DD66B3FA" + } + }, + { + "game": "Aladdin (4F7A Patch)", + "system": "Genesis", + "filename": "Aladdin.4F7A.PATCHED.md", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2097152, + "crc": "E4A7AA54" + } + }, + { + "game": "Aladdin (9CB2 Patch)", + "system": "Genesis", + "filename": "Aladdin.9CB2.PATCHED.md", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2097152, + "crc": "C4616DCB" + } + }, + { + "game": "Aladdin (CES Patch)", + "system": "Genesis", + "filename": "Aladdin.CES.PATCHED.md", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4194304, + "crc": "404930F5" + } + }, + { + "game": "Aladdin", + "system": "Game Boy", + "filename": "Aladdin.gb", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 262144, + "crc": "53918941" + } + }, + { + "game": "Aladdin", + "system": "SNES", + "filename": "Aladdin.sfc", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 1572864, + "crc": "C997AED1" + } + }, + { + "game": "Jungle Book", + "system": "Game Boy", + "filename": "JungleBook.gb", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 131072, + "crc": "4A2C16FF" + } + }, + { + "game": "Jungle Book", + "system": "Genesis", + "filename": "JungleBook.md", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2097152, + "crc": "F48EB5DA" + } + }, + { + "game": "Jungle Book", + "system": "NES", + "filename": "JungleBook.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 262160, + "crc": "93477495" + } + }, + { + "game": "Jungle Book (Patched)", + "system": "Genesis", + "filename": "JUNGLEBOOK.PATCHED.md", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2097152, + "crc": "F48EB5DA" + } + }, + { + "game": "Jungle Book", + "system": "SNES", + "filename": "JungleBook.sfc", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2097152, + "crc": "A690CF68" + } + }, + { + "game": "Jungle Book Music", + "system": "SNES", + "filename": "JungleBookMusicROM.sfc", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 2097152, + "crc": "E6F93C72" + } + }, + { + "game": "Lion King (0D3D Patch)", + "system": "Genesis", + "filename": "LionKing.0D3D.PATCHED.md", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 3145728, + "crc": "5D4287E6" + } + }, + { + "game": "Lion King (919A Patch)", + "system": "SNES", + "filename": "LionKing.919A.PATCHED.sfc", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4194304, + "crc": "E04B0914" + } + }, + { + "game": "Lion King (DE6E Patch)", + "system": "SNES", + "filename": "LionKing.DE6E.PATCHED.sfc", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 4194304, + "crc": "881CE80A" + } + }, + { + "game": "Lion King", + "system": "Game Boy", + "filename": "LionKing.gb", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 524288, + "crc": "E435ED72" + } + } + ], + "notes": {} + } +} \ No newline at end of file diff --git a/src/gex/lib/tasks/impl/genesis/__init__.py b/src/gex/lib/tasks/impl/genesis/__init__.py index 006927f..7fcc7ec 100644 --- a/src/gex/lib/tasks/impl/genesis/__init__.py +++ b/src/gex/lib/tasks/impl/genesis/__init__.py @@ -1,11 +1,8 @@ '''Implementation of genesis: Sega Genesis and Mega Drive Collection''' -import shutil -import glob import logging import os - -from gex.lib.tasks import helpers from gex.lib.tasks.basetask import BaseTask +from gex.lib.tasks import helpers logger = logging.getLogger('gextoolbox') @@ -20,378 +17,25 @@ class GenesisTask(BaseTask): _default_input_folder = helpers.gen_steam_app_default_folder("Sega Classics") _input_folder_desc = "Sega Classics Steam Folder" - def __init__(self): - super().__init__() - self._out_file_list = map(lambda x: { - 'filename': x['filename'], - 'game': f"{x['name']} ({x['region']})", - 'system': "Genesis", - 'status': 'good' -, "notes": []}, - self._game_info_map.values()) - self._out_file_notes = {} + def get_out_file_info(self): + '''Return a list of output files''' + return { + "files": self._metadata['out']['files'], + "notes": self._metadata['out']['notes'] + } def execute(self, in_dir, out_dir): - rom_files = self._find_files(in_dir) - for file_path in rom_files: - # TODO: Add a handler for the pak compressed ones - file_name = os.path.basename(file_path) - game_info = self._game_info_map.get(file_name) - if game_info is not None: - display_name = game_info['name'] - if game_info['region']: - display_name += f' ({game_info["region"]})' - logger.info(f"Copying {file_name}: {display_name}") - try: - shutil.copyfile(file_path, os.path.join(out_dir, game_info['filename'])) - except OSError as error: - logger.warning(f'Error while processing {file_path}!') - logger.warning(error) + '''Copy/rename the ROM files''' + for file_metadata in self._metadata['in']['files'].values(): + resolved_file = self.read_datafile(in_dir, file_metadata) + if 'copy_to' in file_metadata: + out_file_entry = [x for x in self._metadata['out']['files'] if x['game'] == file_metadata['copy_to']][0] + + filename = out_file_entry['filename'] + _ = self.verify_out_file(filename, resolved_file['contents']) + out_path = os.path.join(out_dir, filename) + with open(out_path, "wb") as out_file: + out_file.write(resolved_file['contents']) else: - logger.info(f'Skipping unmatched file {file_path}!') + logger.warning("Compressed ROMs not yet supported!") logger.info("Processing complete.") - - - _game_info_map = { - 'ALEXKIDD_U.68K': { - 'filename': 'AlexKiddInTheEnchantedCastle.bin', - 'name': 'Alex Kidd in the Enchanted Castle', - 'region': 'US' - }, - 'AlienSoldier_Europe.SGD': { - 'filename': 'AlienSoldier.bin', - 'name': 'Alien Soldier', - 'region': 'Euro' - }, - 'AlienStorm_USA.SGD': { - 'filename': 'AlienStorm.bin', - 'name': 'Alien Storm', - 'region': 'US' - }, - 'ALTEREDB_UE.68K': { - 'filename': 'AlteredBeast.bin', - 'name': 'Altered Beast', - 'region': 'US/Euro' - }, - 'BEYONDOA_E.68K': { - 'filename': 'BeyondOasisAKAStoryofThor_E.bin', - 'name': 'Beyond Oasis / Story of Thor', - 'region': 'England' - }, - 'BEYONDOA_F.68K': { - 'filename': 'BeyondOasisAKAStoryofThor_F.bin', - 'name': 'Beyond Oasis / Story of Thor', - 'region': 'France' - }, - 'BEYONDOA_G.68K': { - 'filename': 'BeyondOasisAKAStoryofThor_G.bin', - 'name': 'Beyond Oasis / Story of Thor', - 'region': 'Germany' - }, - 'BEYONDOA_J.68K': { - 'filename': 'BeyondOasisAKAStoryofThor_J.bin', - 'name': 'Beyond Oasis / Story of Thor', - 'region': 'Japan' - }, - 'BEYONDOA_S.68K': { - 'filename': 'BeyondOasisAKAStoryofThor_S.bin', - 'name': 'Beyond Oasis / Story of Thor', - 'region': 'Spain' - }, - 'BEYONDOA_U.68K': { - 'filename': 'BeyondOasisAKAStoryofThor_U.bin', - 'name': 'Beyond Oasis / Story of Thor', - 'region': 'US' - }, - 'BONANZAB_JE.68K': { - 'filename': 'BonanzaBros.bin', - 'name': 'Bonanza Bros.', - 'region': 'Japan/Euro' - }, - 'COLUMNS_W.68K': { - 'filename': 'Columns.bin', - 'name': 'Columns', - 'region': 'World' - }, - 'Columns3_USA.SGD': { - 'filename': 'ColumnsIII.bin', - 'name': 'Columns III', - 'region': 'US' - }, - 'COMIXZON_U.68K': { - 'filename': 'ComixZone.bin', - 'name': 'Comix Zone', - 'region': 'US' - }, - 'CrackDown_USA.SGD': { - 'filename': 'CrackDown.bin', - 'name': 'Crack Down', - 'region': 'US' - }, - 'Crying_USA.SGD': { - 'filename': 'BioHazardBattle.bin', - 'name': 'Bio Hazard Battle', - 'region': 'US' - }, - 'DECAP_UE.68K': { - 'filename': 'DecapAttack.bin', - 'name': 'Decap Attack', - 'region': 'US/Euro' - }, - 'DYNAHEAD_J.68K': { - 'filename': 'DynamiteHeaddy_J.bin', - 'name': 'Dynamite Headdy', - 'region': 'Japan' - }, - 'DYNAHEAD_UE.68K': { - 'filename': 'DynamiteHeaddy_UE.bin', - 'name': 'Dynamite Headdy', - 'region': 'US/Euro' - }, - 'ECCO_UE.68K': { - 'filename': 'EccoTheDolphin.bin', - 'name': 'Ecco the Dolphin', - 'region': 'US/Euro' - }, - 'ECCO2_U.68K': { - 'filename': 'EccoTheTidesOfTime.bin', - 'name': 'Ecco - The Tides of Time', - 'region': 'US' - }, - 'eccojr.smd': { - 'filename': 'EccoJr.bin', - 'name': 'Ecco Jr.', - 'region': '' - }, - 'ESWAT_U.68K': { - 'filename': 'ESWATCityUnderSiege.bin', - 'name': 'ESWAT - City Under Siege', - 'region': 'US' - }, - 'EternalChampions_USA.SGD': { - 'filename': 'EternalChampions.bin', - 'name': 'Eternal Champions', - 'region': 'US' - }, - 'FATALLAB_JU.68K': { - 'filename': 'FatalLabyrinth.bin', - 'name': 'Fatal Labyrinth', - 'region': 'Japan/US' - }, - 'FLICKY_UE.68K': { - 'filename': 'Flicky.bin', - 'name': 'Flicky', - 'region': 'US/Euro' - }, - 'GAING_UE.68K': { - 'filename': 'GainGround.bin', - 'name': 'Gain Ground', - 'region': 'US/Euro' - }, - 'GalaxyForceII_UE.SGD': { - 'filename': 'GalaxyForceII.bin', - 'name': 'Galaxy Force II', - 'region': 'US/Euro' - }, - 'GAXE_W.68K': { - 'filename': 'GoldenAxe.bin', - 'name': 'Golden Axe', - 'region': 'World' - }, - 'GAXE2_W.68K': { - 'filename': 'GoldenAxe2.bin', - 'name': 'Golden Axe 2', - 'region': 'World' - }, - 'GAXE3_J.68K': { - 'filename': 'GoldenAxe3.bin', - 'name': 'Golden Axe 3', - 'region': 'Japan' - }, - 'Gunstar Heroes U.bin': { - 'filename': 'GunstarHeroes.bin', - 'name': 'Gunstar Heroes', - 'region': 'US' - }, - 'KIDCHAM_UE.68K': { - 'filename': 'KidChameleon.bin', - 'name': 'Kid Chameleon', - 'region': 'US/Euro' - }, - 'LandStalker_USA.SGD': { - 'filename': 'Landstalker.bin', - 'name': 'Landstalker', - 'region': 'US' - }, - 'LightCrusader_USA.SGD': { - 'filename': 'LightCrusader.bin', - 'name': 'Light Crusader', - 'region': 'US' - }, - 'MonsterLair_JUE.SGD': { - 'filename': 'WonderBoyIIIMonsterLair.bin', - 'name': 'Wonder Boy III - Monster Lair', - 'region': 'Japan/US/Euro' - }, - 'MonsterWorld3.SGD': { - 'filename': 'WonderBoyVMonsterWorldIII.bin', - 'name': 'Wonder Boy V - Monster World III', - 'region': 'Japan' - }, - 'MonsterWorld3_USA.SGD': { - 'filename': 'WonderBoyInMonsterWorld.bin', - 'name': 'Wonder Boy in Monster World', - 'region': 'US' - }, - 'PhantasyStar2_UE_GreenCrossFix.SGD': { - 'filename': 'PhantasyStar2_ModdedCross.bin', - 'name': 'Phantasy Star 2 (Modded Green Cross Fix)', - 'region': 'US/Euro' - }, - 'PhantasyStar3_USA.SGD': { - 'filename': 'PhantasyStar3_ModdedUSA.bin', - 'name': 'Phantasy Star 3 (Modded USA)', - 'region': 'US' - }, - 'PhantasyStar4.SGD': { - 'filename': 'PhantasyStar4.bin', - 'name': 'Phantasy Star 4', - 'region': '' - }, - 'RISTAR_UE.68K': { - 'filename': 'Ristar.bin', - 'name': 'Ristar', - 'region': 'US/Euro' - }, - 'ROBOTNIK_U.68K': { - 'filename': 'DrRobotniksMeanBeanMachine.bin', - 'name': 'Dr. Robotnik\'s Mean Bean Machine', - 'region': 'US' - }, - 'ShadowDancer.SGD': { - 'filename': 'ShadowDancerTheSecretofShinobi.bin', - 'name': 'Shadow Dancer: The Secret of Shinobi (Shinobi 2)', - 'region': '' - }, - 'SHINING2_U.68K': { - 'filename': 'ShiningForce2.bin', - 'name': 'Shining Force 2', - 'region': 'US' - }, - 'SHININGD_UE.68K': { - 'filename': 'ShiningInTheDarkness.bin', - 'name': 'Shining in the Darkness', - 'region': 'US/Euro' - }, - 'SHININGF_U.68K': { - 'filename': 'ShiningForce.bin', - 'name': 'Shining Force', - 'region': 'US' - }, - 'SHINOBI3_U.68K': { - 'filename': 'Shinobi3.bin', - 'name': 'Shinobi 3', - 'region': 'US' - }, - 'Sonic_Knuckles_wSonic3.bin': { - 'filename': 'Sonic3andKnuckles.bin', - 'name': 'Sonic 3 & Knuckles', - 'region': '' - }, - 'SONIC_W.68K': { - 'filename': 'Sonic.bin', - 'name': 'Sonic the Hedgehog', - 'region': 'World' - }, - 'SONIC2_W.68K': { - 'filename': 'Sonic2.bin', - 'name': 'Sonic 2', - 'region': 'World' - }, - 'SONIC3D_UE.68K': { - 'filename': 'Sonic3D.bin', - 'name': 'Sonic 3D', - 'region': 'US/Euro' - }, - 'SONICSPI_U.68K': { - 'filename': 'SonicSpinball.bin', - 'name': 'Sonic Spinball', - 'region': 'US' - }, - 'sov.smd': { - 'filename': 'SwordOfVermillion.bin', - 'name': 'Sword of Vermillion', - 'region': '' - }, - 'SPACEHARRIERII.bin': { - 'filename': 'SpaceHarrierII.bin', - 'name': 'Space Harrier II', - 'region': '' - }, - 'STHUNDER_W.68K': { - 'filename': 'StreetsOfRage_W.bin', - 'name': 'Streets of Rage', - 'region': 'World' - }, - 'STREETS_W.68K': { - 'filename': 'StreetsOfRage.bin', - 'name': 'Streets of Rage', - 'region': 'World' - }, - 'STREETS2_U.68K': { - 'filename': 'StreetsOfRage2.bin', - 'name': 'Streets of Rage 2', - 'region': 'US' - }, - 'STREETS3_E.68K': { - 'filename': 'StreetsOfRage3_E.bin', - 'name': 'Streets of Rage 3', - 'region': 'Euro' - }, - 'STREETS3_J.68K': { - 'filename': 'StreetsOfRage3_J.bin', - 'name': 'Streets of Rage 3', - 'region': 'Japan' - }, - 'STREETS3_U.68K': { - 'filename': 'StreetsOfRage3_U.bin', - 'name': 'Streets of Rage 3', - 'region': 'US' - }, - 'TheSuperShinobi_JUE.SGD': { - 'filename': 'RevengeOfShinobi.bin', - 'name': 'Revenge of Shinobi (aka The Super Shinobi)', - 'region': 'Japan/US/Euro' - }, - 'ToeJamEarl.SGD': { - 'filename': 'ToeJamAndEarl.bin', - 'name': 'ToeJam and Earl', - 'region': '' - }, - 'ToeJamEarl2_USA.SGD': { - 'filename': 'ToeJamAndEarlInPanicOnFunkotron.bin', - 'name': 'ToeJam and Earl In Panic On Funkotron', - 'region': 'US' - }, - 'VECTMAN_UE.68K': { - 'filename': 'VectorMan.bin', - 'name': 'VectorMan', - 'region': 'US/Euro' - }, - 'VECTMAN2_U.68K': { - 'filename': 'VectorMan2.bin', - 'name': 'VectorMan 2', - 'region': 'US' - }, - 'VIRTUAFIGHTER2.bin': { - 'filename': 'VirtuaFighter2.bin', - 'name': 'Virtua Fighter 2', - 'region': '' - } - } - - def _find_files(self, base_path): - uncomp_rom_path = os.path.join(base_path, "uncompressed ROMs") - archive_list = glob.glob(uncomp_rom_path +'/*.*') - # TODO: Add Pak roms to search - possibly only the non-dupes? - return archive_list diff --git a/src/gex/lib/tasks/impl/genesis/metadata.json b/src/gex/lib/tasks/impl/genesis/metadata.json new file mode 100644 index 0000000..446f264 --- /dev/null +++ b/src/gex/lib/tasks/impl/genesis/metadata.json @@ -0,0 +1,1619 @@ +{ + "in": { + "files": { + "ALEXKIDD_U": { + "rel_path": ["uncompressed ROMs"], + "filename": "ALEXKIDD_U.68K", + "copy_to": "Alex Kidd in the Enchanted Castle (US)", + "versions": { + "Steam": { + "crc": "47DBA0AC", + "size": 262144 + } + } + }, + "AlienSoldier_Europe": { + "rel_path": ["uncompressed ROMs"], + "filename": "AlienSoldier_Europe.SGD", + "copy_to": "Alien Soldier (Euro)", + "versions": { + "Steam": { + "crc": "0496E06C", + "size": 2097152 + } + } + }, + "AlienStorm_USA": { + "rel_path": ["uncompressed ROMs"], + "filename": "AlienStorm_USA.SGD", + "copy_to": "Alien Storm (US)", + "versions": { + "Steam": { + "crc": "5AB9C9F8", + "size": 524288 + } + } + }, + "ALTEREDB_UE": { + "rel_path": ["uncompressed ROMs"], + "filename": "ALTEREDB_UE.68K", + "copy_to": "Altered Beast (US/Euro)", + "versions": { + "Steam": { + "crc": "154D59BB", + "size": 524288 + } + } + }, + "BEYONDOA_E": { + "rel_path": ["uncompressed ROMs"], + "filename": "BEYONDOA_E.68K", + "copy_to": "Beyond Oasis / Story of Thor (England)", + "versions": { + "Steam": { + "crc": "1110B0DB", + "size": 3145728 + } + } + }, + "BEYONDOA_F": { + "rel_path": ["uncompressed ROMs"], + "filename": "BEYONDOA_F.68K", + "copy_to": "Beyond Oasis / Story of Thor (France)", + "versions": { + "Steam": { + "crc": "B97CCA1C", + "size": 3145728 + } + } + }, + "BEYONDOA_G": { + "rel_path": ["uncompressed ROMs"], + "filename": "BEYONDOA_G.68K", + "copy_to": "Beyond Oasis / Story of Thor (Germany)", + "versions": { + "Steam": { + "crc": "FA20D011", + "size": 3145728 + } + } + }, + "BEYONDOA_J": { + "rel_path": ["uncompressed ROMs"], + "filename": "BEYONDOA_J.68K", + "copy_to": "Beyond Oasis / Story of Thor (Japan)", + "versions": { + "Steam": { + "crc": "4F39783C", + "size": 3145728 + } + } + }, + "BEYONDOA_S": { + "rel_path": ["uncompressed ROMs"], + "filename": "BEYONDOA_S.68K", + "copy_to": "Beyond Oasis / Story of Thor (Spain)", + "versions": { + "Steam": { + "crc": "4631F941", + "size": 3145728 + } + } + }, + "BEYONDOA_U": { + "rel_path": ["uncompressed ROMs"], + "filename": "BEYONDOA_U.68K", + "copy_to": "Beyond Oasis / Story of Thor (US)", + "versions": { + "Steam": { + "crc": "C4728225", + "size": 3145728 + } + } + }, + "Crying_USA": { + "rel_path": ["uncompressed ROMs"], + "filename": "Crying_USA.SGD", + "copy_to": "Bio Hazard Battle (US)", + "versions": { + "Steam": { + "crc": "95B0EA2B", + "size": 1048576 + } + } + }, + "BONANZAB_JE": { + "rel_path": ["uncompressed ROMs"], + "filename": "BONANZAB_JE.68K", + "copy_to": "Bonanza Bros. (Japan/Euro)", + "versions": { + "Steam": { + "crc": "C6AAC589", + "size": 524288 + } + } + }, + "COLUMNS_W": { + "rel_path": ["uncompressed ROMs"], + "filename": "COLUMNS_W.68K", + "copy_to": "Columns (World)", + "versions": { + "Steam": { + "crc": "D783C244", + "size": 131072 + } + } + }, + "Columns3_USA": { + "rel_path": ["uncompressed ROMs"], + "filename": "Columns3_USA.SGD", + "copy_to": "Columns III (US)", + "versions": { + "Steam": { + "crc": "DC678F6D", + "size": 524288 + } + } + }, + "COMIXZON_U": { + "rel_path": ["uncompressed ROMs"], + "filename": "COMIXZON_U.68K", + "copy_to": "Comix Zone (US)", + "versions": { + "Steam": { + "crc": "17DA0354", + "size": 2097152 + } + } + }, + "CrackDown_USA": { + "rel_path": ["uncompressed ROMs"], + "filename": "CrackDown_USA.SGD", + "copy_to": "Crack Down (US)", + "versions": { + "Steam": { + "crc": "B9CE9051", + "size": 524288 + } + } + }, + "DECAP_UE": { + "rel_path": ["uncompressed ROMs"], + "filename": "DECAP_UE.68K", + "copy_to": "Decap Attack (US/Euro)", + "versions": { + "Steam": { + "crc": "73DC0DD8", + "size": 524288 + } + } + }, + "ROBOTNIK_U": { + "rel_path": ["uncompressed ROMs"], + "filename": "ROBOTNIK_U.68K", + "copy_to": "Dr. Robotnik's Mean Bean Machine (US)", + "versions": { + "Steam": { + "crc": "C7CA517F", + "size": 1048576 + } + } + }, + "DYNAHEAD_J": { + "rel_path": ["uncompressed ROMs"], + "filename": "DYNAHEAD_J.68K", + "copy_to": "Dynamite Headdy (Japan)", + "versions": { + "Steam": { + "crc": "D03CDB53", + "size": 2097152 + } + } + }, + "DYNAHEAD_UE": { + "rel_path": ["uncompressed ROMs"], + "filename": "DYNAHEAD_UE.68K", + "copy_to": "Dynamite Headdy (US/Euro)", + "versions": { + "Steam": { + "crc": "3DFEEB77", + "size": 2097152 + } + } + }, + "eccojr": { + "rel_path": ["uncompressed ROMs"], + "filename": "eccojr.smd", + "copy_to": "Ecco Jr.", + "versions": { + "Steam": { + "crc": "5B13FC7C", + "size": 1049088 + } + } + }, + "ECCO_UE": { + "rel_path": ["uncompressed ROMs"], + "filename": "ECCO_UE.68K", + "copy_to": "Ecco the Dolphin (US/Euro)", + "versions": { + "Steam": { + "crc": "45547390", + "size": 1048576 + } + } + }, + "ECCO2_U": { + "rel_path": ["uncompressed ROMs"], + "filename": "ECCO2_U.68K", + "copy_to": "Ecco - The Tides of Time (US)", + "versions": { + "Steam": { + "crc": "CCB21F98", + "size": 2097152 + } + } + }, + "ESWAT_U": { + "rel_path": ["uncompressed ROMs"], + "filename": "ESWAT_U.68K", + "copy_to": "ESWAT - City Under Siege (US)", + "versions": { + "Steam": { + "crc": "E72F8A36", + "size": 524288 + } + } + }, + "EternalChampions_USA": { + "rel_path": ["uncompressed ROMs"], + "filename": "EternalChampions_USA.SGD", + "copy_to": "Eternal Champions (US)", + "versions": { + "Steam": { + "crc": "48F1A42E", + "size": 3145728 + } + } + }, + "FATALLAB_JU": { + "rel_path": ["uncompressed ROMs"], + "filename": "FATALLAB_JU.68K", + "copy_to": "Fatal Labyrinth (Japan/US)", + "versions": { + "Steam": { + "crc": "5F0BD984", + "size": 131072 + } + } + }, + "FLICKY_UE": { + "rel_path": ["uncompressed ROMs"], + "filename": "FLICKY_UE.68K", + "copy_to": "Flicky (US/Euro)", + "versions": { + "Steam": { + "crc": "4291C8AB", + "size": 131072 + } + } + }, + "GAING_UE": { + "rel_path": ["uncompressed ROMs"], + "filename": "GAING_UE.68K", + "copy_to": "Gain Ground (US/Euro)", + "versions": { + "Steam": { + "crc": "83E7B8AE", + "size": 524288 + } + } + }, + "GalaxyForceII_UE": { + "rel_path": ["uncompressed ROMs"], + "filename": "GalaxyForceII_UE.SGD", + "copy_to": "Galaxy Force II (US/Euro)", + "versions": { + "Steam": { + "crc": "E4D84E4A", + "size": 1048576 + } + } + }, + "GAXE_W": { + "rel_path": ["uncompressed ROMs"], + "filename": "GAXE_W.68K", + "copy_to": "Golden Axe (World)", + "versions": { + "Steam": { + "crc": "665D7DF9", + "size": 524288 + } + } + }, + "GAXE2_W": { + "rel_path": ["uncompressed ROMs"], + "filename": "GAXE2_W.68K", + "copy_to": "Golden Axe 2 (World)", + "versions": { + "Steam": { + "crc": "725E0A18", + "size": 524288 + } + } + }, + "GAXE3_J": { + "rel_path": ["uncompressed ROMs"], + "filename": "GAXE3_J.68K", + "copy_to": "Golden Axe 3 (Japan)", + "versions": { + "Steam": { + "crc": "C7862EA3", + "size": 1048576 + } + } + }, + "Gunstar Heroes U": { + "rel_path": ["uncompressed ROMs"], + "filename": "Gunstar Heroes U.bin", + "copy_to": "Gunstar Heroes (US)", + "versions": { + "Steam": { + "crc": "B813CF0D", + "size": 1048576 + } + } + }, + "KIDCHAM_UE": { + "rel_path": ["uncompressed ROMs"], + "filename": "KIDCHAM_UE.68K", + "copy_to": "Kid Chameleon (US/Euro)", + "versions": { + "Steam": { + "crc": "CE36E6CC", + "size": 1048576 + } + } + }, + "LandStalker_USA": { + "rel_path": ["uncompressed ROMs"], + "filename": "LandStalker_USA.SGD", + "copy_to": "Landstalker (US)", + "versions": { + "Steam": { + "crc": "FBBB5B97", + "size": 2097152 + } + } + }, + "LightCrusader_USA": { + "rel_path": ["uncompressed ROMs"], + "filename": "LightCrusader_USA.SGD", + "copy_to": "Light Crusader (US)", + "versions": { + "Steam": { + "crc": "BEB715DC", + "size": 2097152 + } + } + }, + "PhantasyStar2_UE_GreenCrossFix": { + "rel_path": ["uncompressed ROMs"], + "filename": "PhantasyStar2_UE_GreenCrossFix.SGD", + "copy_to": "Phantasy Star 2 (Modded Green Cross Fix) (US/Euro)", + "versions": { + "Steam": { + "crc": "75AF3D59", + "size": 1048576 + } + } + }, + "PhantasyStar3_USA": { + "rel_path": ["uncompressed ROMs"], + "filename": "PhantasyStar3_USA.SGD", + "copy_to": "Phantasy Star 3 (Modded USA) (US)", + "versions": { + "Steam": { + "crc": "CC194AD8", + "size": 1048576 + } + } + }, + "PhantasyStar4": { + "rel_path": ["uncompressed ROMs"], + "filename": "PhantasyStar4.SGD", + "copy_to": "Phantasy Star 4", + "versions": { + "Steam": { + "crc": "B23CD7AA", + "size": 4194304 + } + } + }, + "TheSuperShinobi_JUE": { + "rel_path": ["uncompressed ROMs"], + "filename": "TheSuperShinobi_JUE.SGD", + "copy_to": "Revenge of Shinobi (aka The Super Shinobi) (Japan/US/Euro)", + "versions": { + "Steam": { + "crc": "5CA24F66", + "size": 524288 + } + } + }, + "RISTAR_UE": { + "rel_path": ["uncompressed ROMs"], + "filename": "RISTAR_UE.68K", + "copy_to": "Ristar (US/Euro)", + "versions": { + "Steam": { + "crc": "6511AA61", + "size": 2097152 + } + } + }, + "ShadowDancer": { + "rel_path": ["uncompressed ROMs"], + "filename": "ShadowDancer.SGD", + "copy_to": "Shadow Dancer: The Secret of Shinobi (Shinobi 2)", + "versions": { + "Steam": { + "crc": "5CD3E295", + "size": 524288 + } + } + }, + "SHININGF_U": { + "rel_path": ["uncompressed ROMs"], + "filename": "SHININGF_U.68K", + "copy_to": "Shining Force (US)", + "versions": { + "Steam": { + "crc": "E0594ABE", + "size": 1572864 + } + } + }, + "SHINING2_U": { + "rel_path": ["uncompressed ROMs"], + "filename": "SHINING2_U.68K", + "copy_to": "Shining Force 2 (US)", + "versions": { + "Steam": { + "crc": "4815E075", + "size": 2097152 + } + } + }, + "SHININGD_UE": { + "rel_path": ["uncompressed ROMs"], + "filename": "SHININGD_UE.68K", + "copy_to": "Shining in the Darkness (US/Euro)", + "versions": { + "Steam": { + "crc": "4D2785BC", + "size": 1048576 + } + } + }, + "SHINOBI3_U": { + "rel_path": ["uncompressed ROMs"], + "filename": "SHINOBI3_U.68K", + "copy_to": "Shinobi 3 (US)", + "versions": { + "Steam": { + "crc": "5381506F", + "size": 1048576 + } + } + }, + "SONIC_W": { + "rel_path": ["uncompressed ROMs"], + "filename": "SONIC_W.68K", + "copy_to": "Sonic the Hedgehog (World)", + "versions": { + "Steam": { + "crc": "AFE05EEE", + "size": 524288 + } + } + }, + "SONIC2_W": { + "rel_path": ["uncompressed ROMs"], + "filename": "SONIC2_W.68K", + "copy_to": "Sonic 2 (World)", + "versions": { + "Steam": { + "crc": "7B905383", + "size": 1048576 + } + } + }, + "Sonic_Knuckles_wSonic3": { + "rel_path": ["uncompressed ROMs"], + "filename": "Sonic_Knuckles_wSonic3.bin", + "copy_to": "Sonic 3 & Knuckles", + "versions": { + "Steam": { + "crc": "0C06AA82", + "size": 4194304 + } + } + }, + "SONIC3D_UE": { + "rel_path": ["uncompressed ROMs"], + "filename": "SONIC3D_UE.68K", + "copy_to": "Sonic 3D (US/Euro)", + "versions": { + "Steam": { + "crc": "44A2CA44", + "size": 4194304 + } + } + }, + "SONICSPI_U": { + "rel_path": ["uncompressed ROMs"], + "filename": "SONICSPI_U.68K", + "copy_to": "Sonic Spinball (US)", + "versions": { + "Steam": { + "crc": "677206CB", + "size": 1048576 + } + } + }, + "SPACEHARRIERII": { + "rel_path": ["uncompressed ROMs"], + "filename": "SPACEHARRIERII.bin", + "copy_to": "Space Harrier II", + "versions": { + "Steam": { + "crc": "E5C9CBB0", + "size": 524288 + } + } + }, + "STREETS_W": { + "rel_path": ["uncompressed ROMs"], + "filename": "STREETS_W.68K", + "copy_to": "Streets of Rage (World)", + "versions": { + "Steam": { + "crc": "4052E845", + "size": 524288 + } + } + }, + "STREETS2_U": { + "rel_path": ["uncompressed ROMs"], + "filename": "STREETS2_U.68K", + "copy_to": "Streets of Rage 2 (US)", + "versions": { + "Steam": { + "crc": "E01FA526", + "size": 2097152 + } + } + }, + "STREETS3_E": { + "rel_path": ["uncompressed ROMs"], + "filename": "STREETS3_E.68K", + "copy_to": "Streets of Rage 3 (Euro)", + "versions": { + "Steam": { + "crc": "90EF991E", + "size": 3145728 + } + } + }, + "STREETS3_J": { + "rel_path": ["uncompressed ROMs"], + "filename": "STREETS3_J.68K", + "copy_to": "Streets of Rage 3 (Japan)", + "versions": { + "Steam": { + "crc": "5D09236F", + "size": 3145728 + } + } + }, + "STREETS3_U": { + "rel_path": ["uncompressed ROMs"], + "filename": "STREETS3_U.68K", + "copy_to": "Streets of Rage 3 (US)", + "versions": { + "Steam": { + "crc": "D5BB15D9", + "size": 3145728 + } + } + }, + "STHUNDER_W": { + "rel_path": ["uncompressed ROMs"], + "filename": "STHUNDER_W.68K", + "copy_to": "Super Thunder Blade (World)", + "versions": { + "Steam": { + "crc": "B13087EE", + "size": 524288 + } + } + }, + "sov": { + "rel_path": ["uncompressed ROMs"], + "filename": "sov.smd", + "copy_to": "Sword of Vermillion", + "versions": { + "Steam": { + "crc": "36D2F822", + "size": 655872 + } + } + }, + "ToeJamEarl": { + "rel_path": ["uncompressed ROMs"], + "filename": "ToeJamEarl.SGD", + "copy_to": "ToeJam and Earl", + "versions": { + "Steam": { + "crc": "7A588F4B", + "size": 1048576 + } + } + }, + "ToeJamEarl2_USA": { + "rel_path": ["uncompressed ROMs"], + "filename": "ToeJamEarl2_USA.SGD", + "copy_to": "ToeJam and Earl In Panic On Funkotron (US)", + "versions": { + "Steam": { + "crc": "AA021BDD", + "size": 2097152 + } + } + }, + "VECTMAN_UE": { + "rel_path": ["uncompressed ROMs"], + "filename": "VECTMAN_UE.68K", + "copy_to": "VectorMan (US/Euro)", + "versions": { + "Steam": { + "crc": "D38B3354", + "size": 2097152 + } + } + }, + "VECTMAN2_U": { + "rel_path": ["uncompressed ROMs"], + "filename": "VECTMAN2_U.68K", + "copy_to": "VectorMan 2 (US)", + "versions": { + "Steam": { + "crc": "C1A24088", + "size": 3145728 + } + } + }, + "VIRTUAFIGHTER2": { + "rel_path": ["uncompressed ROMs"], + "filename": "VIRTUAFIGHTER2.bin", + "copy_to": "Virtua Fighter 2", + "versions": { + "Steam": { + "crc": "937380F3", + "size": 4194304 + } + } + }, + "MonsterLair_JUE": { + "rel_path": ["uncompressed ROMs"], + "filename": "MonsterLair_JUE.SGD", + "copy_to": "Wonder Boy III - Monster Lair (Japan/US/Euro)", + "versions": { + "Steam": { + "crc": "C24BC5E4", + "size": 524288 + } + } + }, + "MonsterWorld3_USA": { + "rel_path": ["uncompressed ROMs"], + "filename": "MonsterWorld3_USA.SGD", + "copy_to": "Wonder Boy in Monster World (US)", + "versions": { + "Steam": { + "crc": "1592F5B0", + "size": 786432 + } + } + }, + "MonsterWorld3": { + "rel_path": ["uncompressed ROMs"], + "filename": "MonsterWorld3.SGD", + "copy_to": "Wonder Boy V - Monster World III (Japan)", + "versions": { + "Steam": { + "crc": "45A50F96", + "size": 655360 + } + } + } + } + }, + "out": { + "files": [ + { + "game": "Alex Kidd in the Enchanted Castle (US)", + "region": "US", + "title": "Alex Kidd in the Enchanted Castle", + "status": "good", + "notes": [], + "filename": "AlexKiddInTheEnchantedCastle.bin", + "verify": { + "type": "crc", + "crc": "47DBA0AC", + "size": 262144 + } + }, + { + "game": "Alien Soldier (Euro)", + "region": "Euro", + "title": "Alien Soldier", + "status": "good", + "notes": [], + "filename": "AlienSoldier.bin", + "verify": { + "type": "crc", + "crc": "0496E06C", + "size": 2097152 + } + }, + { + "game": "Alien Storm (US)", + "region": "US", + "title": "Alien Storm", + "status": "good", + "notes": [], + "filename": "AlienStorm.bin", + "verify": { + "type": "crc", + "crc": "5AB9C9F8", + "size": 524288 + } + }, + { + "game": "Altered Beast (US/Euro)", + "region": "US/Euro", + "title": "Altered Beast", + "status": "good", + "notes": [], + "filename": "AlteredBeast.bin", + "verify": { + "type": "crc", + "crc": "154D59BB", + "size": 524288 + } + }, + { + "game": "Beyond Oasis / Story of Thor (England)", + "region": "England", + "title": "Beyond Oasis / Story of Thor", + "status": "good", + "notes": [], + "filename": "BeyondOasisAKAStoryofThor_E.bin", + "verify": { + "type": "crc", + "crc": "1110B0DB", + "size": 3145728 + } + }, + { + "game": "Beyond Oasis / Story of Thor (France)", + "region": "France", + "title": "Beyond Oasis / Story of Thor", + "status": "good", + "notes": [], + "filename": "BeyondOasisAKAStoryofThor_F.bin", + "verify": { + "type": "crc", + "crc": "B97CCA1C", + "size": 3145728 + } + }, + { + "game": "Beyond Oasis / Story of Thor (Germany)", + "region": "Germany", + "title": "Beyond Oasis / Story of Thor", + "status": "good", + "notes": [], + "filename": "BeyondOasisAKAStoryofThor_G.bin", + "verify": { + "type": "crc", + "crc": "FA20D011", + "size": 3145728 + } + }, + { + "game": "Beyond Oasis / Story of Thor (Japan)", + "region": "Japan", + "title": "Beyond Oasis / Story of Thor", + "status": "good", + "notes": [], + "filename": "BeyondOasisAKAStoryofThor_J.bin", + "verify": { + "type": "crc", + "crc": "4F39783C", + "size": 3145728 + } + }, + { + "game": "Beyond Oasis / Story of Thor (Spain)", + "region": "Spain", + "title": "Beyond Oasis / Story of Thor", + "status": "good", + "notes": [], + "filename": "BeyondOasisAKAStoryofThor_S.bin", + "verify": { + "type": "crc", + "crc": "4631F941", + "size": 3145728 + } + }, + { + "game": "Beyond Oasis / Story of Thor (US)", + "region": "US", + "title": "Beyond Oasis / Story of Thor", + "status": "good", + "notes": [], + "filename": "BeyondOasisAKAStoryofThor_U.bin", + "verify": { + "type": "crc", + "crc": "C4728225", + "size": 3145728 + } + }, + { + "game": "Bio Hazard Battle (US)", + "region": "US", + "title": "Bio Hazard Battle", + "status": "good", + "notes": [], + "filename": "BioHazardBattle.bin", + "verify": { + "type": "crc", + "crc": "95B0EA2B", + "size": 1048576 + } + }, + { + "game": "Bonanza Bros. (Japan/Euro)", + "region": "Japan/Euro", + "title": "Bonanza Bros.", + "status": "good", + "notes": [], + "filename": "BonanzaBros.bin", + "verify": { + "type": "crc", + "crc": "C6AAC589", + "size": 524288 + } + }, + { + "game": "Columns (World)", + "region": "World", + "title": "Columns", + "status": "good", + "notes": [], + "filename": "Columns.bin", + "verify": { + "type": "crc", + "crc": "D783C244", + "size": 131072 + } + }, + { + "game": "Columns III (US)", + "region": "US", + "title": "Columns III", + "status": "good", + "notes": [], + "filename": "ColumnsIII.bin", + "verify": { + "type": "crc", + "crc": "DC678F6D", + "size": 524288 + } + }, + { + "game": "Comix Zone (US)", + "region": "US", + "title": "Comix Zone", + "status": "good", + "notes": [], + "filename": "ComixZone.bin", + "verify": { + "type": "crc", + "crc": "17DA0354", + "size": 2097152 + } + }, + { + "game": "Crack Down (US)", + "region": "US", + "title": "Crack Down", + "status": "good", + "notes": [], + "filename": "CrackDown.bin", + "verify": { + "type": "crc", + "crc": "B9CE9051", + "size": 524288 + } + }, + { + "game": "Decap Attack (US/Euro)", + "region": "US/Euro", + "title": "Decap Attack", + "status": "good", + "notes": [], + "filename": "DecapAttack.bin", + "verify": { + "type": "crc", + "crc": "73DC0DD8", + "size": 524288 + } + }, + { + "game": "Dr. Robotnik's Mean Bean Machine (US)", + "region": "US", + "title": "Dr. Robotnik's Mean Bean Machine", + "status": "good", + "notes": [], + "filename": "DrRobotniksMeanBeanMachine.bin", + "verify": { + "type": "crc", + "crc": "C7CA517F", + "size": 1048576 + } + }, + { + "game": "Dynamite Headdy (Japan)", + "region": "Japan", + "title": "Dynamite Headdy", + "status": "good", + "notes": [], + "filename": "DynamiteHeaddy_J.bin", + "verify": { + "type": "crc", + "crc": "D03CDB53", + "size": 2097152 + } + }, + { + "game": "Dynamite Headdy (US/Euro)", + "region": "US/Euro", + "title": "Dynamite Headdy", + "status": "good", + "notes": [], + "filename": "DynamiteHeaddy_UE.bin", + "verify": { + "type": "crc", + "crc": "3DFEEB77", + "size": 2097152 + } + }, + { + "game": "Ecco Jr.", + "region": "", + "title": "Ecco Jr.", + "status": "good", + "notes": [], + "filename": "EccoJr.bin", + "verify": { + "type": "crc", + "crc": "5B13FC7C", + "size": 1049088 + } + }, + { + "game": "Ecco the Dolphin (US/Euro)", + "region": "US/Euro", + "title": "Ecco the Dolphin", + "status": "good", + "notes": [], + "filename": "EccoTheDolphin.bin", + "verify": { + "type": "crc", + "crc": "45547390", + "size": 1048576 + } + }, + { + "game": "Ecco - The Tides of Time (US)", + "region": "US", + "title": "Ecco - The Tides of Time", + "status": "good", + "notes": [], + "filename": "EccoTheTidesOfTime.bin", + "verify": { + "type": "crc", + "crc": "CCB21F98", + "size": 2097152 + } + }, + { + "game": "ESWAT - City Under Siege (US)", + "region": "US", + "title": "ESWAT - City Under Siege", + "status": "good", + "notes": [], + "filename": "ESWATCityUnderSiege.bin", + "verify": { + "type": "crc", + "crc": "E72F8A36", + "size": 524288 + } + }, + { + "game": "Eternal Champions (US)", + "region": "US", + "title": "Eternal Champions", + "status": "good", + "notes": [], + "filename": "EternalChampions.bin", + "verify": { + "type": "crc", + "crc": "48F1A42E", + "size": 3145728 + } + }, + { + "game": "Fatal Labyrinth (Japan/US)", + "region": "Japan/US", + "title": "Fatal Labyrinth", + "status": "good", + "notes": [], + "filename": "FatalLabyrinth.bin", + "verify": { + "type": "crc", + "crc": "5F0BD984", + "size": 131072 + } + }, + { + "game": "Flicky (US/Euro)", + "region": "US/Euro", + "title": "Flicky", + "status": "good", + "notes": [], + "filename": "Flicky.bin", + "verify": { + "type": "crc", + "crc": "4291C8AB", + "size": 131072 + } + }, + { + "game": "Gain Ground (US/Euro)", + "region": "US/Euro", + "title": "Gain Ground", + "status": "good", + "notes": [], + "filename": "GainGround.bin", + "verify": { + "type": "crc", + "crc": "83E7B8AE", + "size": 524288 + } + }, + { + "game": "Galaxy Force II (US/Euro)", + "region": "US/Euro", + "title": "Galaxy Force II", + "status": "good", + "notes": [], + "filename": "GalaxyForceII.bin", + "verify": { + "type": "crc", + "crc": "E4D84E4A", + "size": 1048576 + } + }, + { + "game": "Golden Axe (World)", + "region": "World", + "title": "Golden Axe", + "status": "good", + "notes": [], + "filename": "GoldenAxe.bin", + "verify": { + "type": "crc", + "crc": "665D7DF9", + "size": 524288 + } + }, + { + "game": "Golden Axe 2 (World)", + "region": "World", + "title": "Golden Axe 2", + "status": "good", + "notes": [], + "filename": "GoldenAxe2.bin", + "verify": { + "type": "crc", + "crc": "725E0A18", + "size": 524288 + } + }, + { + "game": "Golden Axe 3 (Japan)", + "region": "Japan", + "title": "Golden Axe 3", + "status": "good", + "notes": [], + "filename": "GoldenAxe3.bin", + "verify": { + "type": "crc", + "crc": "C7862EA3", + "size": 1048576 + } + }, + { + "game": "Gunstar Heroes (US)", + "region": "US", + "title": "Gunstar Heroes", + "status": "good", + "notes": [], + "filename": "GunstarHeroes.bin", + "verify": { + "type": "crc", + "crc": "B813CF0D", + "size": 1048576 + } + }, + { + "game": "Kid Chameleon (US/Euro)", + "region": "US/Euro", + "title": "Kid Chameleon", + "status": "good", + "notes": [], + "filename": "KidChameleon.bin", + "verify": { + "type": "crc", + "crc": "CE36E6CC", + "size": 1048576 + } + }, + { + "game": "Landstalker (US)", + "region": "US", + "title": "Landstalker", + "status": "good", + "notes": [], + "filename": "Landstalker.bin", + "verify": { + "type": "crc", + "crc": "FBBB5B97", + "size": 2097152 + } + }, + { + "game": "Light Crusader (US)", + "region": "US", + "title": "Light Crusader", + "status": "good", + "notes": [], + "filename": "LightCrusader.bin", + "verify": { + "type": "crc", + "crc": "BEB715DC", + "size": 2097152 + } + }, + { + "game": "Phantasy Star 2 (Modded Green Cross Fix) (US/Euro)", + "region": "US/Euro", + "title": "Phantasy Star 2 (Modded Green Cross Fix)", + "status": "good", + "notes": [], + "filename": "PhantasyStar2_ModdedCross.bin", + "verify": { + "type": "crc", + "crc": "75AF3D59", + "size": 1048576 + } + }, + { + "game": "Phantasy Star 3 (Modded USA) (US)", + "region": "US", + "title": "Phantasy Star 3 (Modded USA)", + "status": "good", + "notes": [], + "filename": "PhantasyStar3_ModdedUSA.bin", + "verify": { + "type": "crc", + "crc": "CC194AD8", + "size": 1048576 + } + }, + { + "game": "Phantasy Star 4", + "region": "", + "title": "Phantasy Star 4", + "status": "good", + "notes": [], + "filename": "PhantasyStar4.bin", + "verify": { + "type": "crc", + "crc": "B23CD7AA", + "size": 4194304 + } + }, + { + "game": "Revenge of Shinobi (aka The Super Shinobi) (Japan/US/Euro)", + "region": "Japan/US/Euro", + "title": "Revenge of Shinobi (aka The Super Shinobi)", + "status": "good", + "notes": [], + "filename": "RevengeOfShinobi.bin", + "verify": { + "type": "crc", + "crc": "5CA24F66", + "size": 524288 + } + }, + { + "game": "Ristar (US/Euro)", + "region": "US/Euro", + "title": "Ristar", + "status": "good", + "notes": [], + "filename": "Ristar.bin", + "verify": { + "type": "crc", + "crc": "6511AA61", + "size": 2097152 + } + }, + { + "game": "Shadow Dancer: The Secret of Shinobi (Shinobi 2)", + "region": "", + "title": "Shadow Dancer: The Secret of Shinobi (Shinobi 2)", + "status": "good", + "notes": [], + "filename": "ShadowDancerTheSecretofShinobi.bin", + "verify": { + "type": "crc", + "crc": "5CD3E295", + "size": 524288 + } + }, + { + "game": "Shining Force (US)", + "region": "US", + "title": "Shining Force", + "status": "good", + "notes": [], + "filename": "ShiningForce.bin", + "verify": { + "type": "crc", + "crc": "E0594ABE", + "size": 1572864 + } + }, + { + "game": "Shining Force 2 (US)", + "region": "US", + "title": "Shining Force 2", + "status": "good", + "notes": [], + "filename": "ShiningForce2.bin", + "verify": { + "type": "crc", + "crc": "4815E075", + "size": 2097152 + } + }, + { + "game": "Shining in the Darkness (US/Euro)", + "region": "US/Euro", + "title": "Shining in the Darkness", + "status": "good", + "notes": [], + "filename": "ShiningInTheDarkness.bin", + "verify": { + "type": "crc", + "crc": "4D2785BC", + "size": 1048576 + } + }, + { + "game": "Shinobi 3 (US)", + "region": "US", + "title": "Shinobi 3", + "status": "good", + "notes": [], + "filename": "Shinobi3.bin", + "verify": { + "type": "crc", + "crc": "5381506F", + "size": 1048576 + } + }, + { + "game": "Sonic the Hedgehog (World)", + "region": "World", + "title": "Sonic the Hedgehog", + "status": "good", + "notes": [], + "filename": "Sonic.bin", + "verify": { + "type": "crc", + "crc": "AFE05EEE", + "size": 524288 + } + }, + { + "game": "Sonic 2 (World)", + "region": "World", + "title": "Sonic 2", + "status": "good", + "notes": [], + "filename": "Sonic2.bin", + "verify": { + "type": "crc", + "crc": "7B905383", + "size": 1048576 + } + }, + { + "game": "Sonic 3 & Knuckles", + "region": "", + "title": "Sonic 3 & Knuckles", + "status": "good", + "notes": [], + "filename": "Sonic3andKnuckles.bin", + "verify": { + "type": "crc", + "crc": "0C06AA82", + "size": 4194304 + } + }, + { + "game": "Sonic 3D (US/Euro)", + "region": "US/Euro", + "title": "Sonic 3D", + "status": "good", + "notes": [], + "filename": "Sonic3D.bin", + "verify": { + "type": "crc", + "crc": "44A2CA44", + "size": 4194304 + } + }, + { + "game": "Sonic Spinball (US)", + "region": "US", + "title": "Sonic Spinball", + "status": "good", + "notes": [], + "filename": "SonicSpinball.bin", + "verify": { + "type": "crc", + "crc": "677206CB", + "size": 1048576 + } + }, + { + "game": "Space Harrier II", + "region": "", + "title": "Space Harrier II", + "status": "good", + "notes": [], + "filename": "SpaceHarrierII.bin", + "verify": { + "type": "crc", + "crc": "E5C9CBB0", + "size": 524288 + } + }, + { + "game": "Streets of Rage (World)", + "region": "World", + "title": "Streets of Rage", + "status": "good", + "notes": [], + "filename": "StreetsOfRage.bin", + "verify": { + "type": "crc", + "crc": "4052E845", + "size": 524288 + } + }, + { + "game": "Streets of Rage 2 (US)", + "region": "US", + "title": "Streets of Rage 2", + "status": "good", + "notes": [], + "filename": "StreetsOfRage2.bin", + "verify": { + "type": "crc", + "crc": "E01FA526", + "size": 2097152 + } + }, + { + "game": "Streets of Rage 3 (Euro)", + "region": "Euro", + "title": "Streets of Rage 3", + "status": "good", + "notes": [], + "filename": "StreetsOfRage3_E.bin", + "verify": { + "type": "crc", + "crc": "90EF991E", + "size": 3145728 + } + }, + { + "game": "Streets of Rage 3 (Japan)", + "region": "Japan", + "title": "Streets of Rage 3", + "status": "good", + "notes": [], + "filename": "StreetsOfRage3_J.bin", + "verify": { + "type": "crc", + "crc": "5D09236F", + "size": 3145728 + } + }, + { + "game": "Streets of Rage 3 (US)", + "region": "US", + "title": "Streets of Rage 3", + "status": "good", + "notes": [], + "filename": "StreetsOfRage3_U.bin", + "verify": { + "type": "crc", + "crc": "D5BB15D9", + "size": 3145728 + } + }, + { + "game": "Super Thunder Blade (World)", + "region": "World", + "title": "Super Thunder Blade", + "status": "good", + "notes": [], + "filename": "SuperThunderBlade_W.bin", + "verify": { + "type": "crc", + "crc": "B13087EE", + "size": 524288 + } + }, + { + "game": "Sword of Vermillion", + "region": "", + "title": "Sword of Vermillion", + "status": "good", + "notes": [], + "filename": "SwordOfVermillion.bin", + "verify": { + "type": "crc", + "crc": "36D2F822", + "size": 655872 + } + }, + { + "game": "ToeJam and Earl", + "region": "", + "title": "ToeJam and Earl", + "status": "good", + "notes": [], + "filename": "ToeJamAndEarl.bin", + "verify": { + "type": "crc", + "crc": "7A588F4B", + "size": 1048576 + } + }, + { + "game": "ToeJam and Earl In Panic On Funkotron (US)", + "region": "US", + "title": "ToeJam and Earl In Panic On Funkotron", + "status": "good", + "notes": [], + "filename": "ToeJamAndEarlInPanicOnFunkotron.bin", + "verify": { + "type": "crc", + "crc": "AA021BDD", + "size": 2097152 + } + }, + { + "game": "VectorMan (US/Euro)", + "region": "US/Euro", + "title": "VectorMan", + "status": "good", + "notes": [], + "filename": "VectorMan.bin", + "verify": { + "type": "crc", + "crc": "D38B3354", + "size": 2097152 + } + }, + { + "game": "VectorMan 2 (US)", + "region": "US", + "title": "VectorMan 2", + "status": "good", + "notes": [], + "filename": "VectorMan2.bin", + "verify": { + "type": "crc", + "crc": "C1A24088", + "size": 3145728 + } + }, + { + "game": "Virtua Fighter 2", + "region": "", + "title": "Virtua Fighter 2", + "status": "good", + "notes": [], + "filename": "VirtuaFighter2.bin", + "verify": { + "type": "crc", + "crc": "937380F3", + "size": 4194304 + } + }, + { + "game": "Wonder Boy III - Monster Lair (Japan/US/Euro)", + "region": "Japan/US/Euro", + "title": "Wonder Boy III - Monster Lair", + "status": "good", + "notes": [], + "filename": "WonderBoyIIIMonsterLair.bin", + "verify": { + "type": "crc", + "crc": "C24BC5E4", + "size": 524288 + } + }, + { + "game": "Wonder Boy in Monster World (US)", + "region": "US", + "title": "Wonder Boy in Monster World", + "status": "good", + "notes": [], + "filename": "WonderBoyInMonsterWorld.bin", + "verify": { + "type": "crc", + "crc": "1592F5B0", + "size": 786432 + } + }, + { + "game": "Wonder Boy V - Monster World III (Japan)", + "region": "Japan", + "title": "Wonder Boy V - Monster World III", + "status": "good", + "notes": [], + "filename": "WonderBoyVMonsterWorldIII.bin", + "verify": { + "type": "crc", + "crc": "45A50F96", + "size": 655360 + } + } + ], + "notes": {} + } +} \ No newline at end of file diff --git a/src/gex/lib/tasks/impl/irem.py b/src/gex/lib/tasks/impl/irem/__init__.py similarity index 91% rename from src/gex/lib/tasks/impl/irem.py rename to src/gex/lib/tasks/impl/irem/__init__.py index 0281af6..28ff2f5 100644 --- a/src/gex/lib/tasks/impl/irem.py +++ b/src/gex/lib/tasks/impl/irem/__init__.py @@ -21,114 +21,22 @@ class IremTask(BaseTask): _default_input_folder = r"C:\Program Files (x86)\GameFools\Irem Arcade Hits" _input_folder_desc = "Irem Arcade Hits install folder" - _game_info_map = { - "airduel": { - "name": "Air Duel", - "status": "playable" - }, - "bchopper": { - "name": "Battle Chopper", - "status": "NYI" - }, - "bmaster": { - "name": "Battle Master", - "status": "playable" - }, - "cosmccop": { - "name": "Cosmic Cop", - "status": "playable" - }, - "dbreed72": { - "name": "Dragon Breed", - "status": "playable", - "mame_name": 'dbreedm72' - }, - "gunforce": { - "name": "Gunforce", - "status": "NYI" - }, - "gunforc2": { - "name": "Gunforce 2", - "status": "NYI" - }, - "hharry": { - "name": "Hammerin' Harry", - "status": "NYI" - }, - "imgfight": { - "name": "Image Fight", - "status": "NYI" - }, - "inthunt": { - "name": "In the Hunt", - "status": "NYI" - }, - "kungfum": { - "name": "Kung-Fu Master", # ("b-6f-.bin" is missing) - "status": "NYI" - }, - "loht": { - "name": "Legend of Hero Tonma", - "status": "NYI" - }, - "mrheli": { - "name": "Mr. HELI no Daibouken", - "status": "NYI" - }, - "mysticri": { - "name": "Mystic Riders", - "status": "NYI" - }, - "nspirit": { - "name": "Ninja Spirit", # ("proms" and "plds" ROMs are missing) - "status": "NYI" - }, - "rtypeleo": { - "name": "R-Type Leo", - "status": "NYI" - }, - "ssoldier": { - "name": "Superior Soldiers", - "status": "NYI" - }, - "uccops": { - "name": "Undercover Cops", - "status": "NYI" - }, - "uccopsj": { - "name": "Undercover Cops (J)", - "status": "NYI" - }, - "vigilant": { - "name": "Vigilante", # ("plds" ROMs are missing) - "status": "NYI" + def get_out_file_info(self): + '''Return a list of output files''' + return { + "files": self._metadata['out']['files'], + "notes": self._metadata['out']['notes'] } - } - - _out_file_notes = { - "1": "This game requires MAME 2010 due to an older input file structure/variant. Some are also missing an MCU or PIDS rom, but play OK." - } - def __init__(self): - super().__init__() - self._out_file_list = map(lambda in_name, game: { - 'filename': f"{game['mame_name'] if 'mame_name' in game else in_name}.zip", - 'game': f"{game['name']}", - 'system': "Arcade", - "status": game['status'], - "notes": [1]}, - self._game_info_map.items()) - - def _read_irem_game(self, name, in_dir): + def _read_irem_game(self, in_name, in_dir): '''Handle the zip-in-zip packaging format''' - file_name = f"arcade_{name}.zip" - file_path = os.path.join(in_dir, "gamefiles", "Games", "roms", file_name) - with ZipFile(file_path, 'r') as outer_zip: - inner_zip_bytes = outer_zip.read(file_name) + outer_zip = self.read_datafile(in_dir, self._metadata['in']['files'][in_name]) + outer_zip_bytes = outer_zip['contents'] + with ZipFile(BytesIO(outer_zip_bytes), 'r') as outer_zip: + inner_zip_bytes = outer_zip.read(f"arcade_{in_name}.zip") - inner_zip_file = BytesIO(inner_zip_bytes) out_files = {} - with ZipFile(inner_zip_file, 'r') as inner_zip: + with ZipFile(BytesIO(inner_zip_bytes), 'r') as inner_zip: for filename in inner_zip.namelist(): out_files[filename] = inner_zip.read(filename) @@ -138,14 +46,16 @@ def execute(self, in_dir, out_dir): '''Main implementation call for the extraction task''' logger.info("Processing complete.") - for in_name, game in self._game_info_map.items(): - logger.info(f"Extracting {game['name']}...") + for game in self._metadata['out']['files']: + logger.info(f"Extracting {game['game']}...") + in_name = game['extract']['in_file'] in_files = self._read_irem_game(in_name, in_dir) handler_func = self.find_handler_func(in_name) contents = handler_func(in_files) if contents: - filename = f"{game['mame_name'] if 'mame_name' in game else in_name}.zip" - logger.info(f"Saving {game['name']} as {filename}...") + filename = game['filename'] + logger.info(f"Saving {game['game']} as {filename}...") + _ = self.verify_out_file(filename, contents) with open(os.path.join(out_dir, filename), "wb") as out_file: out_file.write(contents) diff --git a/src/gex/lib/tasks/impl/irem/metadata.json b/src/gex/lib/tasks/impl/irem/metadata.json new file mode 100644 index 0000000..69ca393 --- /dev/null +++ b/src/gex/lib/tasks/impl/irem/metadata.json @@ -0,0 +1,863 @@ +{ + "in": { + "files": { + "airduel": { + "rel_path": ["gamefiles", "Games", "roms"], + "filename": "arcade_airduel.zip", + "versions": { + "GameFools": { + "size": 1899225, + "crc": "DC449913" + } + } + }, + "bchopper": { + "rel_path": ["gamefiles", "Games", "roms"], + "filename": "arcade_bchopper.zip", + "versions": { + "GameFools": { + "size": 1368898, + "crc": "E3BF1297" + } + } + }, + "bmaster": { + "rel_path": ["gamefiles", "Games", "roms"], + "filename": "arcade_bmaster.zip", + "versions": { + "GameFools": { + "size": 2654193, + "crc": "D4C4EF82" + } + } + }, + "cosmccop": { + "rel_path": ["gamefiles", "Games", "roms"], + "filename": "arcade_cosmccop.zip", + "versions": { + "GameFools": { + "size": 1614303, + "crc": "7EAC7AF9" + } + } + }, + "dbreed72": { + "rel_path": ["gamefiles", "Games", "roms"], + "filename": "arcade_dbreed72.zip", + "versions": { + "GameFools": { + "size": 1790070, + "crc": "B298182E" + } + } + }, + "gunforc2": { + "rel_path": ["gamefiles", "Games", "roms"], + "filename": "arcade_gunforc2.zip", + "versions": { + "GameFools": { + "size": 4872051, + "crc": "F7ACDF33" + } + } + }, + "gunforce": { + "rel_path": ["gamefiles", "Games", "roms"], + "filename": "arcade_gunforce.zip", + "versions": { + "GameFools": { + "size": 1777103, + "crc": "D699C554" + } + } + }, + "hharry": { + "rel_path": ["gamefiles", "Games", "roms"], + "filename": "arcade_hharry.zip", + "versions": { + "GameFools": { + "size": 1547440, + "crc": "E3C972EE" + } + } + }, + "imgfight": { + "rel_path": ["gamefiles", "Games", "roms"], + "filename": "arcade_imgfight.zip", + "versions": { + "GameFools": { + "size": 1350568, + "crc": "FF8BA655" + } + } + }, + "inthunt": { + "rel_path": ["gamefiles", "Games", "roms"], + "filename": "arcade_inthunt.zip", + "versions": { + "GameFools": { + "size": 3655909, + "crc": "A5F9D955" + } + } + }, + "kungfum": { + "rel_path": ["gamefiles", "Games", "roms"], + "filename": "arcade_kungfum.zip", + "versions": { + "GameFools": { + "size": 959715, + "crc": "1EA84611" + } + } + }, + "loht": { + "rel_path": ["gamefiles", "Games", "roms"], + "filename": "arcade_loht.zip", + "versions": { + "GameFools": { + "size": 1527575, + "crc": "20207713" + } + } + }, + "mrheli": { + "rel_path": ["gamefiles", "Games", "roms"], + "filename": "arcade_mrheli.zip", + "versions": { + "GameFools": { + "size": 1369476, + "crc": "30356B3E" + } + } + }, + "mysticri": { + "rel_path": ["gamefiles", "Games", "roms"], + "filename": "arcade_mysticri.zip", + "versions": { + "GameFools": { + "size": 2223235, + "crc": "CEA9332C" + } + } + }, + "nspirit": { + "rel_path": ["gamefiles", "Games", "roms"], + "filename": "arcade_nspirit.zip", + "versions": { + "GameFools": { + "size": 1346901, + "crc": "4295FF2D" + } + } + }, + "rtypeleo": { + "rel_path": ["gamefiles", "Games", "roms"], + "filename": "arcade_rtypeleo.zip", + "versions": { + "GameFools": { + "size": 2893161, + "crc": "28A16AA8" + } + } + }, + "ssoldier": { + "rel_path": ["gamefiles", "Games", "roms"], + "filename": "arcade_ssoldier.zip", + "versions": { + "GameFools": { + "size": 5516942, + "crc": "A5E17320" + } + } + }, + "uccops": { + "rel_path": ["gamefiles", "Games", "roms"], + "filename": "arcade_uccops.zip", + "versions": { + "GameFools": { + "size": 4417671, + "crc": "75EA8818" + } + } + }, + "uccopsj": { + "rel_path": ["gamefiles", "Games", "roms"], + "filename": "arcade_uccopsj.zip", + "versions": { + "GameFools": { + "size": 4662671, + "crc": "32CD8181" + } + } + }, + "vigilant": { + "rel_path": ["gamefiles", "Games", "roms"], + "filename": "arcade_vigilant.zip", + "versions": { + "GameFools": { + "size": 1100561, + "crc": "0439B213" + } + } + } + } + }, + "out": { + "files": [ + { + "game": "Air Duel", + "status": "playable", + "filename": "airduel.zip", + "system": "Arcade", + "notes": [1], + "extract": { + "in_file": "airduel" + }, + "verify": { + "type": "zip", + "entries": { + "ad-c-l0.bin": {"size": 131072, "crc": "4AC0B91D"}, + "ad-c-l3.bin": {"size": 131072, "crc": "9DD343F7"}, + "ad-c-h0.bin": {"size": 131072, "crc": "12140276"}, + "ad-c-h3.bin": {"size": 131072, "crc": "9F7CFCA3"}, + "ad-00.bin": {"size": 131072, "crc": "2F0D599B"}, + "ad-10.bin": {"size": 131072, "crc": "9865856B"}, + "ad-20.bin": {"size": 131072, "crc": "D392AEF2"}, + "ad-30.bin": {"size": 131072, "crc": "923240C3"}, + "ad-a0.bin": {"size": 131072, "crc": "CE134B47"}, + "ad-a1.bin": {"size": 131072, "crc": "097FD853"}, + "ad-a2.bin": {"size": 131072, "crc": "6A94C1B9"}, + "ad-a3.bin": {"size": 131072, "crc": "6637C349"}, + "ad-b0.bin": {"size": 131072, "crc": "CE134B47"}, + "ad-b1.bin": {"size": 131072, "crc": "097FD853"}, + "ad-b2.bin": {"size": 131072, "crc": "6A94C1B9"}, + "ad-b3.bin": {"size": 131072, "crc": "6637C349"}, + "ad-v0.bin": {"size": 131072, "crc": "339F474D"} + } + } + }, + { + "game": "Battle Chopper", + "status": "playable", + "filename": "bchopper.zip", + "system": "Arcade", + "notes": [1], + "extract": { + "in_file": "bchopper" + }, + "verify": { + "type": "zip", + "entries": { + "c-l0-b.rom": {"size": 65536, "crc": "9F887096"}, + "c-l1-b.rom": {"size": 65536, "crc": "41DDA999"}, + "c-l3-b.rom": {"size": 65536, "crc": "11562221"}, + "c-h0-b.rom": {"size": 65536, "crc": "F2FEAB16"}, + "c-h1-b.rom": {"size": 65536, "crc": "A995D64F"}, + "c-h3-b.rom": {"size": 65536, "crc": "AB9451CA"}, + "c-00-a.rom": {"size": 65536, "crc": "F6E6E660"}, + "c-01-b.rom": {"size": 65536, "crc": "708CDD37"}, + "c-10-a.rom": {"size": 65536, "crc": "292C8520"}, + "c-11-b.rom": {"size": 65536, "crc": "20904CF3"}, + "c-20-a.rom": {"size": 65536, "crc": "1AB50C23"}, + "c-21-b.rom": {"size": 65536, "crc": "C823D34C"}, + "c-30-a.rom": {"size": 65536, "crc": "11F6C56B"}, + "c-31-b.rom": {"size": 65536, "crc": "23134EC5"}, + "b-a0-b.rom": {"size": 65536, "crc": "E46ED7BF"}, + "b-a1-b.rom": {"size": 65536, "crc": "590605FF"}, + "b-a2-b.rom": {"size": 65536, "crc": "F8158226"}, + "b-a3-b.rom": {"size": 65536, "crc": "0F07B9B7"}, + "b-b0-.rom": {"size": 65536, "crc": "B5B95776"}, + "b-b1-.rom": {"size": 65536, "crc": "74CA16EE"}, + "b-b2-.rom": {"size": 65536, "crc": "B82CCA04"}, + "b-b3-.rom": {"size": 65536, "crc": "A7AFC920"}, + "c-v0-b.rom": {"size": 65536, "crc": "D0C27E58"} + } + } + }, + { + "game": "Battle Master", + "status": "playable", + "filename": "bmaster.zip", + "system": "Arcade", + "notes": [1], + "extract": { + "in_file": "bmaster" + }, + "verify": { + "type": "zip", + "entries": { + "bm_d-l0-b.5f": {"size": 262144, "crc": "A873523E"}, + "bm_d-l1-b.5j": {"size": 65536, "crc": "6FF0C04E"}, + "bm_d-h0-b.5m": {"size": 262144, "crc": "49B257C7"}, + "bm_d-h1-b.5l": {"size": 65536, "crc": "082B7158"}, + "bm_d-sl0.rom": {"size": 65536, "crc": "1FA87C89"}, + "bm_d-sh0.rom": {"size": 65536, "crc": "9F7C075B"}, + "bm_c0.rom": {"size": 262144, "crc": "2CC966B8"}, + "bm_c1.rom": {"size": 262144, "crc": "46DF773E"}, + "bm_c2.rom": {"size": 262144, "crc": "05B867BD"}, + "bm_c3.rom": {"size": 262144, "crc": "0A2227A4"}, + "bm_000.rom": {"size": 524288, "crc": "339FC9F3"}, + "bm_010.rom": {"size": 524288, "crc": "6A14377D"}, + "bm_020.rom": {"size": 524288, "crc": "31532198"}, + "bm_030.rom": {"size": 524288, "crc": "D1A041D3"}, + "bm_da.rom": {"size": 524288, "crc": "62CE5798"} + } + } + }, + { + "game": "Cosmic Cop", + "status": "playable", + "filename": "cosmccop.zip", + "system": "Arcade", + "notes": [1], + "extract": { + "in_file": "cosmccop" + }, + "verify": { + "type": "zip", + "entries": { + "cc-d-l0b.bin": {"size": 262144, "crc": "EFF87F70"}, + "cc-d-h0b.bin": {"size": 262144, "crc": "38958B01"}, + "cc-d-sp.bin": {"size": 65536, "crc": "3E3ACE60"}, + "cc-c-00.bin": {"size": 131072, "crc": "9D99DEAA"}, + "cc-c-10.bin": {"size": 131072, "crc": "7EB083ED"}, + "cc-c-20.bin": {"size": 131072, "crc": "9421489E"}, + "cc-c-30.bin": {"size": 131072, "crc": "920EC735"}, + "cc-d-g00.bin": {"size": 131072, "crc": "E7F3D772"}, + "cc-d-g10.bin": {"size": 131072, "crc": "418B4E4C"}, + "cc-d-g20.bin": {"size": 131072, "crc": "A4B558EB"}, + "cc-d-g30.bin": {"size": 131072, "crc": "F64A3166"}, + "cc-c-v0.bin": {"size": 131072, "crc": "6247BADE"} + } + } + }, + { + "game": "Dragon Breed", + "status": "playable", + "filename": "dbreedm72.zip", + "system": "Arcade", + "notes": [1], + "extract": { + "in_file": "dbreed72" + }, + "verify": { + "type": "zip", + "entries": { + "db_c-l3.rom": {"size": 131072, "crc": "E4B89B79"}, + "db_c-l0.rom": {"size": 65536, "crc": "ED0F5E06"}, + "db_c-h3.rom": {"size": 131072, "crc": "4BF3063C"}, + "db_c-h0.rom": {"size": 65536, "crc": "5AA79FB2"}, + "db_k800m.00": {"size": 131072, "crc": "C027A8CF"}, + "db_k801m.10": {"size": 131072, "crc": "093FAF33"}, + "db_k802m.20": {"size": 131072, "crc": "055B4C59"}, + "db_k803m.30": {"size": 131072, "crc": "8ED63922"}, + "db_k804m.a0": {"size": 131072, "crc": "4C83E92E"}, + "db_k805m.a1": {"size": 131072, "crc": "835EF268"}, + "db_k806m.a2": {"size": 131072, "crc": "5117F114"}, + "db_k807m.a3": {"size": 131072, "crc": "8EB0C978"}, + "db_k804m.b0": {"size": 131072, "crc": "4C83E92E"}, + "db_k805m.b1": {"size": 131072, "crc": "835EF268"}, + "db_k806m.b2": {"size": 131072, "crc": "5117F114"}, + "db_k807m.b3": {"size": 131072, "crc": "8EB0C978"}, + "db_c-v0.rom": {"size": 131072, "crc": "312F7282"} + } + } + }, + { + "game": "Gunforce", + "status": "playable", + "filename": "gunforce.zip", + "system": "Arcade", + "notes": [1], + "extract": { + "in_file": "gunforce" + }, + "verify": { + "type": "zip", + "entries": { + "gf_l0-c.5f": {"size": 131072, "crc": "1BEF6F7D"}, + "gf_l1-c.5j": {"size": 131072, "crc": "B189F72A"}, + "gf_h0-c.5m": {"size": 131072, "crc": "C09BB634"}, + "gf_h1-c.5l": {"size": 131072, "crc": "C84188B7"}, + "gf_sl0.rom": {"size": 65536, "crc": "DB0B13A3"}, + "gf_sh0.rom": {"size": 65536, "crc": "3F8F16E0"}, + "gf_c0.rom": {"size": 262144, "crc": "B3B74979"}, + "gf_c1.rom": {"size": 262144, "crc": "F5C8590A"}, + "gf_c2.rom": {"size": 262144, "crc": "30F9FB64"}, + "gf_c3.rom": {"size": 262144, "crc": "87B3E621"}, + "gf_000.rom": {"size": 262144, "crc": "209E8E8D"}, + "gf_010.rom": {"size": 262144, "crc": "6E6E7808"}, + "gf_020.rom": {"size": 262144, "crc": "6F5C3CB0"}, + "gf_030.rom": {"size": 262144, "crc": "18978A9F"}, + "gf-da.rom": {"size": 131072, "crc": "933BA935"} + } + } + }, + { + "game": "Gunforce 2", + "status": "playable", + "filename": "gunforc2.zip", + "system": "Arcade", + "notes": [1], + "extract": { + "in_file": "gunforc2" + }, + "verify": { + "type": "zip", + "entries": { + "a2-l0-a.8h": {"size": 262144, "crc": "8C88B278"}, + "a2-l1-a.8f": {"size": 262144, "crc": "C8C13F51"}, + "a2-h0-a.6h": {"size": 262144, "crc": "49965E22"}, + "a2-h1-a.6f": {"size": 262144, "crc": "34280B88"}, + "a2_sl0.5l": {"size": 65536, "crc": "2287E0B3"}, + "a2_sh0.3l": {"size": 65536, "crc": "2E2D103D"}, + "a2_c0.1a": {"size": 524288, "crc": "68B8F574"}, + "a2_c1.1b": {"size": 524288, "crc": "0B9EFE67"}, + "a2_c2.3a": {"size": 524288, "crc": "7A9E9978"}, + "a2_c3.3b": {"size": 524288, "crc": "1395EE6D"}, + "a2_000.8a": {"size": 1048576, "crc": "38E03147"}, + "a2_010.8b": {"size": 1048576, "crc": "1D5B05F8"}, + "a2_020.8c": {"size": 1048576, "crc": "F2F461CC"}, + "a2_030.8d": {"size": 1048576, "crc": "97609D9D"}, + "a2_da.1l": {"size": 1048576, "crc": "3C8CDB6A"} + } + } + }, + { + "game": "Hammerin' Harry", + "status": "playable", + "filename": "hharry.zip", + "system": "Arcade", + "notes": [1], + "extract": { + "in_file": "hharry" + }, + "verify": { + "type": "zip", + "entries": { + "a-l0-v.rom": {"size": 131072, "crc": "F463074C"}, + "a-l1-0.rom": {"size": 65536, "crc": "BC6AC5F9"}, + "a-h0-v.rom": {"size": 131072, "crc": "C52802A5"}, + "a-h1-0.rom": {"size": 65536, "crc": "3AE21335"}, + "a-sp-0.rom": {"size": 65536, "crc": "80E210E7"}, + "hh_00.rom": {"size": 131072, "crc": "EC5127EF"}, + "hh_10.rom": {"size": 131072, "crc": "DEF65294"}, + "hh_20.rom": {"size": 131072, "crc": "BB0D6AD4"}, + "hh_30.rom": {"size": 131072, "crc": "4351044E"}, + "hh_a0.rom": {"size": 131072, "crc": "C577BA5F"}, + "hh_a1.rom": {"size": 131072, "crc": "429D12AB"}, + "hh_a2.rom": {"size": 131072, "crc": "B5B163B0"}, + "hh_a3.rom": {"size": 131072, "crc": "8EF566A1"}, + "a-v0-0.rom": {"size": 131072, "crc": "FAAACAFF"} + } + } + }, + { + "game": "Image Fight", + "status": "playable", + "filename": "imgfight.zip", + "system": "Arcade", + "notes": [1], + "extract": { + "in_file": "imgfight" + }, + "verify": { + "type": "zip", + "entries": { + "if-c-l0-a.bin": {"size": 65536, "crc": "87C534FE"}, + "if-c-l3.bin": {"size": 131072, "crc": "C66AE348"}, + "if-c-h0-a.bin": {"size": 65536, "crc": "F5C94464"}, + "if-c-h3.bin": {"size": 131072, "crc": "EA030541"}, + "if-c-00.bin": {"size": 131072, "crc": "745E6638"}, + "if-c-10.bin": {"size": 131072, "crc": "B7108449"}, + "if-c-20.bin": {"size": 131072, "crc": "AEF33CBA"}, + "if-c-30.bin": {"size": 131072, "crc": "1F98E695"}, + "if-a-a0.bin": {"size": 65536, "crc": "34EE2D77"}, + "if-a-a1.bin": {"size": 65536, "crc": "6BD2845B"}, + "if-a-a2.bin": {"size": 65536, "crc": "090D50E5"}, + "if-a-a3.bin": {"size": 65536, "crc": "3A8E3083"}, + "if-a-b0.bin": {"size": 65536, "crc": "B425C829"}, + "if-a-b1.bin": {"size": 65536, "crc": "E9BFE23E"}, + "if-a-b2.bin": {"size": 65536, "crc": "256E50F2"}, + "if-a-b3.bin": {"size": 65536, "crc": "4C682785"}, + "if-c-v0.bin": {"size": 65536, "crc": "CB64A194"}, + "if-c-v1.bin": {"size": 65536, "crc": "45B68BF5"} + } + } + }, + { + "game": "In the Hunt", + "status": "playable", + "filename": "inthunt.zip", + "system": "Arcade", + "notes": [1], + "extract": { + "in_file": "inthunt" + }, + "verify": { + "type": "zip", + "entries": { + "ith-l0-d.bin": {"size": 262144, "crc": "5DB79EB7"}, + "ith-l1-b.bin": {"size": 131072, "crc": "955A605A"}, + "ith-h0-d.bin": {"size": 262144, "crc": "52F8E7A6"}, + "ith-h1-b.bin": {"size": 131072, "crc": "FC2899DF"}, + "ith-sl0.rom": {"size": 65536, "crc": "18472D65"}, + "ith-sh0.rom": {"size": 65536, "crc": "209C8B7F"}, + "ith_ic26.rom": {"size": 524288, "crc": "4C1818CF"}, + "ith_ic25.rom": {"size": 524288, "crc": "91145BAE"}, + "ith_ic24.rom": {"size": 524288, "crc": "FC03FE3B"}, + "ith_ic23.rom": {"size": 524288, "crc": "EE156A0A"}, + "ith_ic34.rom": {"size": 1048576, "crc": "A019766E"}, + "ith_ic35.rom": {"size": 1048576, "crc": "3FCA3073"}, + "ith_ic36.rom": {"size": 1048576, "crc": "20D1B28B"}, + "ith_ic37.rom": {"size": 1048576, "crc": "90B6FD4B"}, + "ith_ic9.rom": {"size": 524288, "crc": "318EE71A"} + } + } + }, + { + "game": "Kung-Fu Master", + "status": "playable", + "filename": "kungfum.zip", + "system": "Arcade", + "notes": [1], + "extract": { + "in_file": "kungfum" + }, + "verify": { + "type": "zip", + "entries": { + "a-4e-c.bin": {"size": 16384, "crc": "B6E2D083"}, + "a-4d-c.bin": {"size": 16384, "crc": "7532918E"}, + "a-3e-.bin": {"size": 8192, "crc": "58E87AB0"}, + "a-3f-.bin": {"size": 8192, "crc": "C81E31EA"}, + "a-3h-.bin": {"size": 8192, "crc": "D99FB995"}, + "g-4c-a.bin": {"size": 8192, "crc": "6B2CC9C8"}, + "g-4d-a.bin": {"size": 8192, "crc": "C648F558"}, + "g-4e-a.bin": {"size": 8192, "crc": "FBE9276E"}, + "b-4k-.bin": {"size": 8192, "crc": "16FB5150"}, + "b-4f-.bin": {"size": 8192, "crc": "67745A33"}, + "b-4l-.bin": {"size": 8192, "crc": "BD1C2261"}, + "b-4h-.bin": {"size": 8192, "crc": "8AC5ED3A"}, + "b-3n-.bin": {"size": 8192, "crc": "28A213AA"}, + "b-4n-.bin": {"size": 8192, "crc": "D5228DF3"}, + "b-4m-.bin": {"size": 8192, "crc": "B16DE4F2"}, + "b-3m-.bin": {"size": 8192, "crc": "EBA0D66B"}, + "b-4c-.bin": {"size": 8192, "crc": "01298885"}, + "b-4e-.bin": {"size": 8192, "crc": "C77B87D4"}, + "b-4d-.bin": {"size": 8192, "crc": "6A70615F"}, + "b-4a-.bin": {"size": 8192, "crc": "6189D626"}, + "b-5f-.bin": {"size": 32, "crc": "7A601C3D"}, + "g-1j-.bin": {"size": 256, "crc": "668E6BCA"}, + "b-1m-.bin": {"size": 256, "crc": "76C05A9C"}, + "g-1f-.bin": {"size": 256, "crc": "964B6495"}, + "b-1n-.bin": {"size": 256, "crc": "23F06B99"}, + "g-1h-.bin": {"size": 256, "crc": "550563E1"}, + "b-1l-.bin": {"size": 256, "crc": "35E45021"}, + "b-6f-.bin": {"size": 256, "crc": "0D968558"} + } + } + }, + { + "game": "Legend of Hero Tonma", + "status": "playable", + "filename": "loht.zip", + "system": "Arcade", + "notes": [1], + "extract": { + "in_file": "loht" + }, + "verify": { + "type": "zip", + "entries": { + "tom_c-l0.rom": {"size": 131072, "crc": "E788002F"}, + "tom_c-l3-": {"size": 131072, "crc": "2F049B03"}, + "tom_c-h0.rom": {"size": 131072, "crc": "A63204B6"}, + "tom_c-h3-": {"size": 131072, "crc": "714778B5"}, + "tom_m53.rom": {"size": 131072, "crc": "0B83265F"}, + "tom_m51.rom": {"size": 131072, "crc": "8EC5F6F3"}, + "tom_m49.rom": {"size": 131072, "crc": "A41D3BFD"}, + "tom_m47.rom": {"size": 131072, "crc": "9D81A25B"}, + "tom_m21.rom": {"size": 65536, "crc": "3CA3E771"}, + "tom_m22.rom": {"size": 65536, "crc": "7A05EE2F"}, + "tom_m20.rom": {"size": 65536, "crc": "79AA2335"}, + "tom_m23.rom": {"size": 65536, "crc": "789E8B24"}, + "tom_m26.rom": {"size": 65536, "crc": "44626BF6"}, + "tom_m27.rom": {"size": 65536, "crc": "464952CF"}, + "tom_m25.rom": {"size": 65536, "crc": "3DB9B2C7"}, + "tom_m24.rom": {"size": 65536, "crc": "F01FE899"}, + "tom_m44.rom": {"size": 65536, "crc": "3ED51D1F"} + } + } + }, + { + "game": "Mr. HELI no Daibouken", + "status": "playable", + "filename": "mrheli.zip", + "system": "Arcade", + "notes": [1], + "extract": { + "in_file": "mrheli" + }, + "verify": { + "type": "zip", + "entries": { + "mh-c-l0.bin": {"size": 65536, "crc": "643E23CD"}, + "mh-c-l1.bin": {"size": 65536, "crc": "5F8BDA69"}, + "mh-c-l3.bin": {"size": 65536, "crc": "C0982536"}, + "mh-c-h0.bin": {"size": 65536, "crc": "E2CA5646"}, + "mh-c-h1.bin": {"size": 65536, "crc": "8974E84D"}, + "mh-c-h3.bin": {"size": 65536, "crc": "143F596E"}, + "mh-c-00.bin": {"size": 131072, "crc": "DEC4E121"}, + "mh-c-10.bin": {"size": 131072, "crc": "7AAA151E"}, + "mh-c-20.bin": {"size": 131072, "crc": "EAE0DE74"}, + "mh-c-30.bin": {"size": 131072, "crc": "01D5052F"}, + "mh-b-a0.bin": {"size": 65536, "crc": "6A0DB256"}, + "mh-b-a1.bin": {"size": 65536, "crc": "14EC9795"}, + "mh-b-a2.bin": {"size": 65536, "crc": "DFCB510E"}, + "mh-b-a3.bin": {"size": 65536, "crc": "957E329B"}, + "b-b0-.rom": {"size": 65536, "crc": "B5B95776"}, + "b-b1-.bin": {"size": 65536, "crc": "74CA16EE"}, + "b-b2-.rom": {"size": 65536, "crc": "B82CCA04"}, + "b-b3-.rom": {"size": 65536, "crc": "A7AFC920"}, + "c-v0-b.rom": {"size": 65536, "crc": "D0C27E58"} + } + } + }, + { + "game": "Mystic Riders", + "status": "playable", + "filename": "mysticri.zip", + "system": "Arcade", + "notes": [1], + "extract": { + "in_file": "mysticri" + }, + "verify": { + "type": "zip", + "entries": { + "mr-l0-b.bin": {"size": 262144, "crc": "A457AB44"}, + "mr-l1-b.bin": {"size": 65536, "crc": "A87C62B4"}, + "mr-h0-b.bin": {"size": 262144, "crc": "D529F887"}, + "mr-h1-b.bin": {"size": 65536, "crc": "E17649B9"}, + "mr-sl0.bin": {"size": 65536, "crc": "0FA32721"}, + "mr-sh0.bin": {"size": 65536, "crc": "50D335E4"}, + "mr-c0.bin": {"size": 262144, "crc": "872A8FAD"}, + "mr-c1.bin": {"size": 262144, "crc": "D2FFB27A"}, + "mr-c2.bin": {"size": 262144, "crc": "62BFF287"}, + "mr-c3.bin": {"size": 262144, "crc": "D0DA62AB"}, + "mr-o00.bin": {"size": 524288, "crc": "A0F9CE16"}, + "mr-o10.bin": {"size": 524288, "crc": "4E70A9E9"}, + "mr-o20.bin": {"size": 524288, "crc": "B9C468FC"}, + "mr-o30.bin": {"size": 524288, "crc": "CC32433A"}, + "mr-da.bin": {"size": 262144, "crc": "1A11FC59"} + } + } + }, + { + "game": "Ninja Spirit", + "status": "playable", + "filename": "nspirit.zip", + "system": "Arcade", + "notes": [1], + "extract": { + "in_file": "nspirit" + }, + "verify": { + "type": "zip", + "entries": { + "nin_c-l0.6d": {"size": 65536, "crc": "9A405898"}, + "nin_c-l1.6c": {"size": 65536, "crc": "B75C9A4D"}, + "nin_c-l2.6b": {"size": 65536, "crc": "C52CA78C"}, + "nin_c-l3.6a": {"size": 65536, "crc": "FD7408B8"}, + "nin_c-h0.6h": {"size": 65536, "crc": "035692FA"}, + "nin_c-h1.6j": {"size": 65536, "crc": "CBC10586"}, + "nin_c-h2.6l": {"size": 65536, "crc": "8AD818FA"}, + "nin_c-h3.6m": {"size": 65536, "crc": "501104EF"}, + "nin-r00.7m": {"size": 131072, "crc": "5F61D30B"}, + "nin-r10.7j": {"size": 131072, "crc": "0CAAD107"}, + "nin-r20.7f": {"size": 131072, "crc": "EF3617D3"}, + "nin-r30.7d": {"size": 131072, "crc": "175D2A24"}, + "nin_b-a0.4c": {"size": 65536, "crc": "63F8F658"}, + "nin_b-a1.4d": {"size": 65536, "crc": "75EB8306"}, + "nin_b-a2.4b": {"size": 65536, "crc": "DF532172"}, + "nin_b-a3.4e": {"size": 65536, "crc": "4DEDD64C"}, + "b0.4j": {"size": 65536, "crc": "1B0E08A6"}, + "b1.4k": {"size": 65536, "crc": "728727F0"}, + "b2.4h": {"size": 65536, "crc": "F87EFD75"}, + "b3.4f": {"size": 65536, "crc": "98856CB4"}, + "nin-v0.7a": {"size": 65536, "crc": "A32E8CAF"}, + "m72_a-8l.8l": {"size": 256, "crc": "0D968558"}, + "m72_a-9l.9l": {"size": 256, "crc": "0D968558"}, + "nin_c-3f.3f": {"size": 256, "crc": "0D968558"}, + "m72_a-3d.3d": {"size": 256, "crc": "0D968558"}, + "m72_a-4d.4d": {"size": 256, "crc": "0D968558"} + } + } + }, + { + "game": "R-Type Leo", + "status": "playable", + "filename": "rtypeleo.zip", + "system": "Arcade", + "notes": [1], + "extract": { + "in_file": "rtypeleo" + }, + "verify": { + "type": "zip", + "entries": { + "rtl-l0-c.bin": {"size": 262144, "crc": "8156456B"}, + "rtl-l1-d.bin": {"size": 131072, "crc": "FD34EA46"}, + "rtl-h0-c.bin": {"size": 262144, "crc": "5FEF7FA1"}, + "rtl-h1-d.bin": {"size": 131072, "crc": "352FF444"}, + "rtl-sl0a.bin": {"size": 65536, "crc": "896F0D36"}, + "rtl-sh0a.bin": {"size": 65536, "crc": "E518B4E3"}, + "rtl-c0.bin": {"size": 524288, "crc": "FB588D7C"}, + "rtl-c1.bin": {"size": 524288, "crc": "E5541BFF"}, + "rtl-c2.bin": {"size": 524288, "crc": "FAA9AE27"}, + "rtl-c3.bin": {"size": 524288, "crc": "3A2343F6"}, + "rtl-000.bin": {"size": 1048576, "crc": "82A06870"}, + "rtl-010.bin": {"size": 1048576, "crc": "417E7A56"}, + "rtl-020.bin": {"size": 1048576, "crc": "F9A3F3A1"}, + "rtl-030.bin": {"size": 1048576, "crc": "03528D95"}, + "rtl-da.bin": {"size": 524288, "crc": "DBEBD1FF"} + } + } + }, + { + "game": "Superior Soldiers", + "status": "playable", + "filename": "ssoldier.zip", + "system": "Arcade", + "notes": [1], + "extract": { + "in_file": "ssoldier" + }, + "verify": { + "type": "zip", + "entries": { + "f3-l0-h.bin": {"size": 262144, "crc": "419361A2"}, + "f3-l1-a.bin": {"size": 131072, "crc": "8CB5C396"}, + "f3-h0-h.bin": {"size": 262144, "crc": "B63FB9DA"}, + "f3-h1-a.bin": {"size": 131072, "crc": "E3D9F619"}, + "f3_sl0.sl0": {"size": 65536, "crc": "77C16D57"}, + "f3_sh0.sh0": {"size": 65536, "crc": "90B55E5E"}, + "f3_w50.c0": {"size": 262144, "crc": "47E788EE"}, + "f3_w51.c1": {"size": 262144, "crc": "E20EEA22"}, + "f3_w52.c2": {"size": 262144, "crc": "8E535E3F"}, + "f3_w53.c3": {"size": 262144, "crc": "E20EEA22"}, + "f3_w38.001": {"size": 1048576, "crc": "755BAB10"}, + "f3_w40.011": {"size": 1048576, "crc": "2E906889"}, + "f3_w42.021": {"size": 1048576, "crc": "124589B9"}, + "f3_w44.031": {"size": 1048576, "crc": "D0FC84AC"}, + "f3_w37.000": {"size": 1048576, "crc": "FD4CDA03"}, + "f3_w39.010": {"size": 1048576, "crc": "B21CED92"}, + "f3_w41.020": {"size": 1048576, "crc": "02455D10"}, + "f3_w43.030": {"size": 1048576, "crc": "DAE7327A"}, + "f3_w95.da": {"size": 524288, "crc": "F7CA432B"} + } + } + }, + { + "game": "Undercover Cops", + "status": "playable", + "filename": "uccops.zip", + "system": "Arcade", + "notes": [1], + "extract": { + "in_file": "uccops" + }, + "verify": { + "type": "zip", + "entries": { + "uc_l0.rom": {"size": 262144, "crc": "DF9A4826"}, + "uc_l1.rom": {"size": 131072, "crc": "A8A402D8"}, + "uc_h0.rom": {"size": 262144, "crc": "240AA5F7"}, + "uc_h1.rom": {"size": 131072, "crc": "8D29BCD6"}, + "uc_sl0.rom": {"size": 65536, "crc": "96C11AAC"}, + "uc_sh0.rom": {"size": 65536, "crc": "DF90B198"}, + "uc_w38m.rom": {"size": 524288, "crc": "130A40E5"}, + "uc_w39m.rom": {"size": 524288, "crc": "E42CA144"}, + "uc_w40m.rom": {"size": 524288, "crc": "C2961648"}, + "uc_w41m.rom": {"size": 524288, "crc": "F5334B80"}, + "uc_k16m.rom": {"size": 1048576, "crc": "4A225F09"}, + "uc_k17m.rom": {"size": 1048576, "crc": "E4ED9A54"}, + "uc_k18m.rom": {"size": 1048576, "crc": "A626EB12"}, + "uc_k19m.rom": {"size": 1048576, "crc": "5DF46549"}, + "uc_w42.rom": {"size": 524288, "crc": "D17D3FD6"} + } + } + }, + { + "game": "Undercover Cops (J)", + "status": "playable", + "filename": "uccopsj.zip", + "system": "Arcade", + "notes": [1], + "extract": { + "in_file": "uccopsj" + }, + "verify": { + "type": "zip", + "entries": { + "uc_l0_a.ic39": {"size": 262144, "crc": "4A4E3208"}, + "uc_l1_a.ic38": {"size": 131072, "crc": "19628280"}, + "uc_h0_a.ic28": {"size": 262144, "crc": "9E17CADA"}, + "uc_h1_a.ic27": {"size": 131072, "crc": "83F78DEA"}, + "uc_sl0.ic31": {"size": 524288, "crc": "F04A5FD9"}, + "uc_sh0.ic30": {"size": 524288, "crc": "6982FE88"}, + "uc_c0.ic26": {"size": 524288, "crc": "6A419A36"}, + "uc_c1.ic25": {"size": 524288, "crc": "D703ECC7"}, + "uc_c2.ic24": {"size": 524288, "crc": "96397AC6"}, + "uc_c3.ic23": {"size": 524288, "crc": "5D07D10D"}, + "uc_000.ic34": {"size": 1048576, "crc": "97F7775E"}, + "uc_010.ic35": {"size": 1048576, "crc": "5E0B1D65"}, + "uc_020.ic36": {"size": 1048576, "crc": "BDC224B3"}, + "uc_030.ic37": {"size": 1048576, "crc": "7526DAEC"}, + "uc_da.bin": {"size": 524288, "crc": "0B2855E9"} + } + } + }, + { + "game": "Vigilante", + "status": "playable", + "filename": "vigilant.zip", + "system": "Arcade", + "notes": [1], + "extract": { + "in_file": "vigilant" + }, + "verify": { + "type": "zip", + "entries": { + "g07_c03.bin": {"size": 32768, "crc": "9DCCA081"}, + "j07_c04.bin": {"size": 65536, "crc": "E0159105"}, + "g05_c02.bin": {"size": 65536, "crc": "10582B2D"}, + "f05_c08.bin": {"size": 65536, "crc": "01579D20"}, + "h05_c09.bin": {"size": 65536, "crc": "4F5872F0"}, + "n07_c12.bin": {"size": 65536, "crc": "10AF8EB2"}, + "k07_c10.bin": {"size": 65536, "crc": "9576F304"}, + "o07_c13.bin": {"size": 65536, "crc": "B1D9D4DC"}, + "l07_c11.bin": {"size": 65536, "crc": "4598BE4A"}, + "t07_c16.bin": {"size": 65536, "crc": "F5425E42"}, + "p07_c14.bin": {"size": 65536, "crc": "CB50A17C"}, + "v07_c17.bin": {"size": 65536, "crc": "959BA3C7"}, + "s07_c15.bin": {"size": 65536, "crc": "7F2E91C5"}, + "d01_c05.bin": {"size": 65536, "crc": "81B1EE5C"}, + "e01_c06.bin": {"size": 65536, "crc": "D0D33673"}, + "f01_c07.bin": {"size": 65536, "crc": "AAE81695"}, + "d04_c01.bin": {"size": 65536, "crc": "9B85101D"}, + "pal16l8.8r": {"size": 260, "crc": "91A9701B"}, + "pal16l8.4m": {"size": 260, "crc": "91A9701B"}, + "pal16l8.1b": {"size": 260, "crc": "91A9701B"} + } + } + } + ], + "notes": { + "1": "This game requires MAME 2010 due to an older input file structure/variant. Some are also missing an MCU or PIDS rom, but play OK." + } + } +} \ No newline at end of file diff --git a/src/gex/lib/tasks/impl/mkak.py b/src/gex/lib/tasks/impl/mkak/__init__.py similarity index 99% rename from src/gex/lib/tasks/impl/mkak.py rename to src/gex/lib/tasks/impl/mkak/__init__.py index b43d809..31c9a4a 100644 --- a/src/gex/lib/tasks/impl/mkak.py +++ b/src/gex/lib/tasks/impl/mkak/__init__.py @@ -7,7 +7,7 @@ logger = logging.getLogger('gextoolbox') -class BubsyTask(BaseTask): +class MKAKTask(BaseTask): '''Implements mkak: Mortal Kombat Arcade Kollection''' _task_name = "mkak" _title = "Mortal Kombat Arcade Kollection" diff --git a/src/gex/lib/tasks/impl/mmlc1.py b/src/gex/lib/tasks/impl/mmlc1.py deleted file mode 100644 index ad7f700..0000000 --- a/src/gex/lib/tasks/impl/mmlc1.py +++ /dev/null @@ -1,145 +0,0 @@ -'''Implementation of mmlc1: Mega Man Legacy Collection 1''' -import logging -import os -from gex.lib.tasks.basetask import BaseTask -from gex.lib.tasks import helpers - -logger = logging.getLogger('gextoolbox') - -class MegaManLegacyCollection1Task(BaseTask): - '''Implements mmlc1: Mega Man Legacy Collection 1''' - _task_name = "mmlc1" - _title = "Mega Man Legacy Collection 1" - _details_markdown = ''' -Based on MMLC & DAC Extractor - https://github.com/HTV04/mmlc-dac-extractor -''' - _out_file_notes = {} - _default_input_folder = helpers.gen_steam_app_default_folder("Suzy") - _input_folder_desc = "'Suzy' Folder (Steam MMLC install folder)" - - _game_info_list = [ - { - 'filename': 'rockman.nes', - 'name': 'Rockman', - 'sections': { - 'prg': {'start': 0x512230, 'length': 0x20000} - }, - 'header': b'\x4E\x45\x53\x1A\x08\x00\x21\x00\x00\x00\x00\x00\x00\x00\x00\x00', - }, - { - 'filename': 'rockman2.nes', - 'name': 'Rockman 2 - Dr Wily no Nazo', - 'sections': { - 'prg': {'start': 0x2F20F0, 'length': 0x40000} - }, - 'header': b'\x4E\x45\x53\x1A\x10\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00' - }, - { - 'filename': 'rockman3.nes', - 'name': 'Rockman 3 - Dr Wily no Saigo!', - 'sections': { - 'prg': {'start': 0x332130, 'length': 0x60000} - }, - 'header': b'\x4E\x45\x53\x1A\x10\x10\x41\x00\x00\x00\x00\x00\x00\x00\x00\x00' - }, - { - 'filename': 'rockman4.nes', - 'name': 'Rockman 4 - Aratanaru Yabou!!', - 'sections': { - 'prg': {'start': 0x392170, 'length': 0x80000} - }, - 'header': b'\x4E\x45\x53\x1A\x20\x00\x41\x00\x00\x00\x00\x00\x00\x00\x00\x00' - }, - { - 'filename': 'rockman5.nes', - 'name': 'Rockman 5 - Blues no Wana!', - 'sections': { - 'prg': {'start': 0x4121B0, 'length': 0x80000} - }, - 'header': b'\x4E\x45\x53\x1A\x10\x20\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00' - }, - { - 'filename': 'rockman6.nes', - 'name': 'Rockman 6 - Shijou Saidai no Tatakai!!', - 'sections': { - 'prg': {'start': 0x4921F0, 'length': 0x80000} - }, - 'header': b'\x4E\x45\x53\x1A\x20\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00' - }, - { - 'filename': 'megaman.nes', - 'name': 'Mega Man', - 'sections': { - 'prg': {'start': 0x2AEEB0, 'length': 0x20000} - }, - 'header': b'\x4E\x45\x53\x1A\x08\x00\x21\x00\x00\x00\x00\x00\x00\x00\x00\x00' - }, - { - 'filename': 'megaman2.nes', - 'name': 'Mega Man 2', - 'sections': { - 'prg': {'start': 0x8ED70, 'length': 0x40000} - }, - 'header': b'\x4E\x45\x53\x1A\x10\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00' - }, - { - 'filename': 'megaman3.nes', - 'name': 'Mega Man 3', - 'sections': { - 'prg': {'start': 0xCEDB0, 'length': 0x40000}, - 'cha': {'start': 0x10EDB0, 'length': 0x20000} - }, - 'header': b'\x4E\x45\x53\x1A\x10\x10\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00' - }, - { - 'filename': 'megaman4.nes', - 'name': 'Mega Man 4', - 'sections': { - 'prg': {'start': 0x12EDF0, 'length': 0x80000} - }, - 'header': b'\x4E\x45\x53\x1A\x20\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00' - }, - { - 'filename': 'megaman5.nes', - 'name': 'Mega Man 5', - 'sections': { - 'prg': {'start': 0x1AEE30, 'length': 0x80000} - }, - 'header': b'\x4E\x45\x53\x1A\x10\x20\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00' - }, - { - 'filename': 'megaman6.nes', - 'name': 'Mega Man 6', - 'sections': { - 'prg': {'start': 0x22EE70, 'length': 0x80000} - }, - 'header': b'\x4E\x45\x53\x1A\x20\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00' - } - ] - - def __init__(self): - super().__init__() - self._out_file_list = map(lambda x: { - 'filename': x['filename'], - 'game': x['name'], - 'status': "good", - 'system': "NES", - "notes": []}, - self._game_info_list) - - def execute(self, in_dir, out_dir): - exe_path = os.path.join(in_dir, 'Proteus.exe') - with open(exe_path, 'rb') as exe_file: - exe_data = exe_file.read() - - for game_info in self._game_info_list: - logger.info(f"Extracting {game_info['name']}...") - game_data = bytearray() - game_data.extend(game_info['header']) - for section in game_info['sections'].values(): - game_data.extend(exe_data[section['start']:section['start']+section['length']]) - - with open(os.path.join(out_dir, game_info['filename']), "wb") as out_file: - out_file.write(game_data) - - logger.info("Processing complete.") diff --git a/src/gex/lib/tasks/impl/mmlc1/__init__.py b/src/gex/lib/tasks/impl/mmlc1/__init__.py new file mode 100644 index 0000000..27e0394 --- /dev/null +++ b/src/gex/lib/tasks/impl/mmlc1/__init__.py @@ -0,0 +1,13 @@ +'''Implementation of mmlc1: Mega Man Legacy Collection 1''' +from gex.lib.tasks.splicetask import SpliceTask +from gex.lib.tasks import helpers + +class MegaManLegacyCollection1Task(SpliceTask): + '''Implements mmlc1: Mega Man Legacy Collection 1''' + _task_name = "mmlc1" + _title = "Mega Man Legacy Collection 1" + _details_markdown = ''' +Based on MMLC & DAC Extractor - https://github.com/HTV04/mmlc-dac-extractor +''' + _default_input_folder = helpers.gen_steam_app_default_folder("Suzy") + _input_folder_desc = "'Suzy' Folder (Steam MMLC install folder)" diff --git a/src/gex/lib/tasks/impl/mmlc1/metadata.json b/src/gex/lib/tasks/impl/mmlc1/metadata.json new file mode 100644 index 0000000..97fa639 --- /dev/null +++ b/src/gex/lib/tasks/impl/mmlc1/metadata.json @@ -0,0 +1,213 @@ +{ + "in": { + "files": { + "source": { + "filename": "Proteus.exe", + "versions": { + "Steam": { + "crc": "E70E4AA2", + "size": 6083696 + } + } + } + } + }, + "out": { + "files": [ + { + "game": "Rockman", + "system": "NES", + "filename": "rockman.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "E0141A24", + "size": 131088 + }, + "sections": { + "prg": {"start": "0x512230", "length": "0x20000"} + }, + "header": "4E45531A080021000000000000000000" + }, + { + "game": "Rockman 2 - Dr Wily no Nazo", + "system": "NES", + "filename": "rockman2.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "30B91650", + "size": 262160 + }, + "sections": { + "prg": {"start": "0x2F20F0", "length": "0x40000"} + }, + "header": "4E45531A100010000000000000000000" + }, + { + "game": "Rockman 3 - Dr Wily no Saigo!", + "system": "NES", + "filename": "rockman3.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "07A6F576", + "size": 393232 + }, + "sections": { + "prg": {"start": "0x332130", "length": "0x60000"} + }, + "header": "4E45531A101041000000000000000000" + }, + { + "game": "Rockman 4 - Aratanaru Yabou!!", + "system": "NES", + "filename": "rockman4.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "F9EE29F8", + "size": 524304 + }, + "sections": { + "prg": {"start": "0x392170", "length": "0x80000"} + }, + "header": "4E45531A200041000000000000000000" + }, + { + "game": "Rockman 5 - Blues no Wana!", + "system": "NES", + "filename": "rockman5.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "9D01E44C", + "size": 524304 + }, + "sections": { + "prg": {"start": "0x4121B0", "length": "0x80000"} + }, + "header": "4E45531A102040000000000000000000" + }, + { + "game": "Rockman 6 - Shijou Saidai no Tatakai!!", + "system": "NES", + "filename": "rockman6.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "AB1D7979", + "size": 524304 + }, + "sections": { + "prg": {"start": "0x4921F0", "length": "0x80000"} + }, + "header": "4E45531A200040000000000000000000" + }, + { + "game": "Mega Man", + "system": "NES", + "filename": "megaman.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "2F4E0136", + "size": 131088 + }, + "sections": { + "prg": {"start": "0x2AEEB0", "length": "0x20000"} + }, + "header": "4E45531A080021000000000000000000" + }, + { + "game": "Mega Man 2", + "system": "NES", + "filename": "megaman2.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "9EB4A590", + "size": 262160 + }, + "sections": { + "prg": {"start": "0x8ED70", "length": "0x40000"} + }, + "header": "4E45531A100010000000000000000000" + }, + { + "game": "Mega Man 3", + "system": "NES", + "filename": "megaman3.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "7C81030B", + "size": 393232 + }, + "sections": { + "prg": {"start": "0xCEDB0", "length": "0x40000"}, + "cha": {"start": "0x10EDB0", "length": "0x20000"} + }, + "header": "4E45531A101040000000000000000000" + }, + { + "game": "Mega Man 4", + "system": "NES", + "filename": "megaman4.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "89D1BB93", + "size": 524304 + }, + "sections": { + "prg": {"start": "0x12EDF0", "length": "0x80000"} + }, + "header": "4E45531A200040000000000000000000" + }, + { + "game": "Mega Man 5", + "system": "NES", + "filename": "megaman5.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "08669C51", + "size": 524304 + }, + "sections": { + "prg": {"start": "0x1AEE30", "length": "0x80000"} + }, + "header": "4E45531A102040000000000000000000" + }, + { + "game": "Mega Man 6", + "system": "NES", + "filename": "megaman6.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "5ABC7A12", + "size": 524304 + }, + "sections": { + "prg": {"start": "0x22EE70", "length": "0x80000"} + }, + "header": "4E45531A200040000000000000000000" + } + ], + "notes": {} + } +} \ No newline at end of file diff --git a/src/gex/lib/tasks/impl/mmxlc1.py b/src/gex/lib/tasks/impl/mmxlc1.py deleted file mode 100644 index fcce6cd..0000000 --- a/src/gex/lib/tasks/impl/mmxlc1.py +++ /dev/null @@ -1,115 +0,0 @@ -'''Implementation of mmxlc1: Mega Man X Legacy Collection 1''' -import logging -import os -from gex.lib.tasks.basetask import BaseTask -from gex.lib.tasks import helpers - -logger = logging.getLogger('gextoolbox') - -class MegaManXLegacyCollection1Task(BaseTask): - '''Implements mmxlc1: Mega Man X Legacy Collection 1''' - _task_name = "mmxlc1" - _title = "Mega Man X Legacy Collection 1" - _details_markdown = ''' -Based on: https://github.com/s3phir0th115/MMXLC1-Rom-Extractor/blob/master/mmxlc_rom_extract.py - -Mega Man X4 does not appear to be ROM based, but investigation is ongoing. -''' - _default_input_folder = helpers.gen_steam_app_default_folder("Mega Man X Legacy Collection") - _input_folder_desc = "Steam MMxLC install folder" - _out_file_notes = {} - _game_info_list = [ - { - 'filename': 'rockmanx.sfc', - 'name': 'Rockman X', - "system": "SNES", - "status": "good", - 'sections': { - 'rom': {'start': 0xB8C4E0, 'length': 0x180000} - } - }, - { - 'filename': 'rockmanx2.sfc', - 'name': 'Rockman X2', - "system": "SNES", - "status": "good", - 'sections': { - 'rom': {'start': 0xF8C4E0, 'length': 0x180000} - } - }, - { - 'filename': 'rockmanx3.sfc', - 'name': 'Rockman X3', - "system": "SNES", - "status": "good", - 'sections': { - 'rom': {'start': 0x128C4E0, 'length': 0x200000} - } - }, - { - 'filename': 'N/A', - 'name': 'Rockman X4', - "system": "Playstation", - "status": "no-rom" - }, - { - 'filename': 'megamanx.sfc', - 'name': 'Mega Man X', - "system": "SNES", - "status": "good", - 'sections': { - 'rom': {'start': 0xD8C4E0, 'length': 0x180000} - } - }, - { - 'filename': 'megamanx2.sfc', - 'name': 'Mega Man X2', - "system": "SNES", - "status": "good", - 'sections': { - 'rom': {'start': 0x110C4E0, 'length': 0x180000} - } - }, - { - 'filename': 'megamanx3.sfc', - 'name': 'Mega Man X3', - "system": "SNES", - "status": "good", - 'sections': { - 'rom': {'start': 0x148C4E0, 'length': 0x200000} - } - }, - { - 'filename': 'N/A', - 'name': 'Mega Man X4', - "system": "Playstation", - "status": "no-rom" - } - ] - - def __init__(self): - super().__init__() - self._out_file_list = map(lambda x: { - 'filename': x['filename'], - 'game': x['name'], - 'status': x['status'], - 'system': x['system'], - "notes": []}, - self._game_info_list) - - def execute(self, in_dir, out_dir): - exe_path = os.path.join(in_dir, 'RXC1.exe') - with open(exe_path, 'rb') as exe_file: - exe_data = exe_file.read() - - for game_info in self._game_info_list: - if game_info['status'] == 'good': - logger.info(f"Extracting {game_info['name']}...") - game_data = bytearray() - for section in game_info['sections'].values(): - game_data.extend(exe_data[section['start']:section['start']+section['length']]) - - with open(os.path.join(out_dir, game_info['filename']), "wb") as out_file: - out_file.write(game_data) - - logger.info("Processing complete.") diff --git a/src/gex/lib/tasks/impl/mmxlc1/__init__.py b/src/gex/lib/tasks/impl/mmxlc1/__init__.py new file mode 100644 index 0000000..e430e1c --- /dev/null +++ b/src/gex/lib/tasks/impl/mmxlc1/__init__.py @@ -0,0 +1,15 @@ +'''Implementation of mmxlc1: Mega Man X Legacy Collection 1''' +from gex.lib.tasks.splicetask import SpliceTask +from gex.lib.tasks import helpers + +class MegaManXLegacyCollection1Task(SpliceTask): + '''Implements mmxlc1: Mega Man X Legacy Collection 1''' + _task_name = "mmxlc1" + _title = "Mega Man X Legacy Collection 1" + _details_markdown = ''' +Based on: https://github.com/s3phir0th115/MMXLC1-Rom-Extractor/blob/master/mmxlc_rom_extract.py + +Mega Man X4 does not appear to be ROM based, but investigation is ongoing. +''' + _default_input_folder = helpers.gen_steam_app_default_folder("Mega Man X Legacy Collection") + _input_folder_desc = "Steam MMxLC install folder" diff --git a/src/gex/lib/tasks/impl/mmxlc1/metadata.json b/src/gex/lib/tasks/impl/mmxlc1/metadata.json new file mode 100644 index 0000000..3906588 --- /dev/null +++ b/src/gex/lib/tasks/impl/mmxlc1/metadata.json @@ -0,0 +1,124 @@ +{ + "in": { + "files": { + "source": { + "filename": "RXC1.exe", + "versions": { + "Steam": { + "crc": "1D8902FE", + "size": 24034944 + } + } + } + } + }, + "out": { + "files": [ + { + "game": "Rockman X", + "system": "SNES", + "filename": "rockmanx.sfc", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "94CA42BF", + "size": 1572864 + }, + "sections": { + "prg": {"start": "0xB8C4E0", "length": "0x180000"} + } + }, + { + "game": "Rockman X2", + "system": "SNES", + "filename": "rockmanx2.sfc", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "011E5068", + "size": 1572864 + }, + "sections": { + "prg": {"start": "0xF8C4E0", "length": "0x180000"} + } + }, + { + "game": "Rockman X3", + "system": "SNES", + "filename": "rockmanx3.sfc", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "741AB27B", + "size": 2097152 + }, + "sections": { + "prg": {"start": "0x128C4E0", "length": "0x200000"} + } + }, + { + "game": "Mega Man X", + "system": "SNES", + "filename": "megamanx.sfc", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "97A10846", + "size": 1572864 + }, + "sections": { + "prg": {"start": "0xD8C4E0", "length": "0x180000"} + } + }, + { + "game": "Mega Man X2", + "system": "SNES", + "filename": "megamanx2.sfc", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "8972DF65", + "size": 1572864 + }, + "sections": { + "prg": {"start": "0x110C4E0", "length": "0x180000"} + } + }, + { + "game": "Mega Man X3", + "system": "SNES", + "filename": "megamanx3.sfc", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "1ACB643D", + "size": 2097152 + }, + "sections": { + "prg": {"start": "0x148C4E0", "length": "0x200000"} + } + }, + { + "game": "Rockman X4", + "system": "Playstation", + "filename": "N/A", + "status": "no-rom", + "notes": [] + }, + { + "game": "Mega Man X4", + "system": "Playstation", + "filename": "N/A", + "status": "no-rom", + "notes": [] + } + ], + "notes": {} + } +} \ No newline at end of file diff --git a/src/gex/lib/tasks/impl/pacmanmplus.py b/src/gex/lib/tasks/impl/pacmanmplus.py deleted file mode 100644 index 973ae76..0000000 --- a/src/gex/lib/tasks/impl/pacmanmplus.py +++ /dev/null @@ -1,322 +0,0 @@ -'''Implementation of pacmanmplus: Pac Man Museum Plus''' -import logging -import os -import lzma -from gex.lib.tasks.basetask import BaseTask -from gex.lib.tasks import helpers -from gex.lib.utils.blob import transforms - -logger = logging.getLogger('gextoolbox') - -class PacManMuseumPlusTask(BaseTask): - '''Implements pacmanmplus: Pac Man Museum Plus''' - _task_name = "pacmanmplus" - _title = "Pac Man Museum Plus" - _details_markdown = '''''' - _default_input_folder = helpers.gen_steam_app_default_folder("PAC-MAN MUSEUM PLUS") - _input_folder_desc = "Pac Man Museum Plus install folder" - - _prop_info = { - "include-partials": { - "description": "Include the partial ROMs that are missing data; useful for mixing with other sources or investigation", - "default": False, - "type": "Boolean" - } - } - _game_info_map = [ - { - "name": "PAC Land", - "system": "Arcade", - "filename": "paclandj.zip", - "in": { - "filename": "GamePacland_pacmuseum2021_windows_x64_Release.dll", - "start": 170352, - "length": 116880 - }, - "out": [ - { "filename": "pl1-2.1t", "start": 0x00000, "length": 0x400 }, - { "filename": "pl1-1.1r", "start": 0x00400, "length": 0x400 }, - { "filename": "pl1-5.5t", "start": 0x00800, "length": 0x400 }, - { "filename": "pl1-4.4n", "start": 0x00C00, "length": 0x400 }, - { "filename": "pl1-3.6l", "start": 0x01000, "length": 0x400 }, - { "filename": "pl6_01.8b", "start": 0x01400, "length": 0x4000 }, - { "filename": "pl6_02.8d", "start": 0x05400, "length": 0x4000 }, - { "filename": "pl1_3.8e", "start": 0x09400, "length": 0x4000 }, - { "filename": "pl1_4.8f", "start": 0x0D400, "length": 0x4000 }, - { "filename": "pl1_5.8h", "start": 0x11400, "length": 0x4000 }, - { "filename": "pl1_6.8j", "start": 0x15400, "length": 0x4000 }, - { "filename": "pl1_7.3e", "start": 0x19400, "length": 0x2000 }, - { "filename": "cus60-60a1.mcu", "start": 0x1B400, "length": 0x1000 }, - { "filename": "pl6_12.6n", "start": 0x1C400, "length": 0x2000 }, - { "filename": "pl1_13.6t", "start": 0x1E400, "length": 0x2000 }, - { "filename": "pl1_9b.6f", "start": 0x20400, "length": 0x4000 }, - { "filename": "pl1_8.6e", "start": 0x24400, "length": 0x4000 }, - { "filename": "pl1_10b.7e", "start": 0x28400, "length": 0x4000 }, - { "filename": "pl1_11.7f", "start": 0x2C400, "length": 0x4000 } - ], - "status": "playable", - "notes": [4] - }, - { - "name": "PAC Attack", - "system": "SNES", - "filename": "pacattack.zip", - "in": { - "filename": "GameSFC_Pacattack_pacmuseum2021_windows_x64_Release.dll", - "start": 0, - "length": 600000 - }, - "out": [], - "status": 'partial', - "notes": [1, 8] - }, - { - "name": "Super PAC-MAN", - "system": "Arcade", - "filename": "superpac.zip", - "in": { - "filename": "GameSuperpacman_pacmuseum2021_windows_x64_Release.dll", - "start": 141616, - "length": 58144 - }, - "out": [ - {"filename": "sp1-2.1c", "start": 0x2000, "length": 0x2000}, - {"filename": "sp1-1.1b", "start": 0x4000, "length": 0x2000}, - {"filename": "spc-3.1k", "start": 0x6000, "length": 0x1000}, - {"filename": "sp1-6.3c", "start": 0x8000, "length": 0x1000}, - {"filename": "spv-2.3f", "start": 0x9000, "length": 0x2000}, - {"filename": "superpac.4c", "start": 0xE000, "length": 0x20}, - {"filename": "superpac.4e", "start": 0xE020, "length": 0x100}, - {"filename": "superpac.3l", "start": 0xE120, "length": 0x100}, - {"filename": "superpac.3m", "start": 0xE220, "length": 0x100} - ], - "status": 'good', - "notes": [] - }, - { - "name": "PAC Motos", - "system": "Wii", - "filename": "N/A", - "status": 'no-rom', - "notes": [2] - }, - { - "name": "PAC'N Roll Remix", - "system": "Wii", - "filename": "N/A", - "status": 'no-rom', - "notes": [2] - }, - { - "name": "PAC-MAN BATTLE ROYALE", - "system": "Arcade", - "filename": "N/A", - "status": 'no-rom', - "notes": [2] - }, - { - "name": "PAC'N Roll Remix", - "system": "Mobile", - "filename": "N/A", - "status": 'no-rom', - "notes": [2] - }, - # PAC-IN-TIME - # Official ROM is 1,048,576 - # DLL is 1,062,400 - # So, it really does need to be compressed! - # binwalk -e -M doesn't find anything - { - "name": "PAC-IN-TIME", - "system": "SNES", - "filename": "pacintime.zip", - "in": { - "filename": "GameSFC_Pacintime_pacmuseum2021_windows_x64_Release.dll", - "start": 0, - "length": 1062400 - }, - "out": [], - "status": 'partial', - "notes": [1, 8] - }, - { - "name": "PAC and Pal", - "system": "Arcade", - "filename": "pacnpal.zip", - "in": { - "filename": "GamePacandpal_pacmuseum2021_windows_x64_Release.dll", - "start": 141424, - "length": 58144 - }, - "out": [ - {"filename": "pap1-3b.1d", "start": 0x0000, "length": 0x2000}, - {"filename": "pap1-2b.1c", "start": 0x2000, "length": 0x2000}, - {"filename": "pap3-1.1b", "start": 0x4000, "length": 0x2000}, - {"filename": "pap1-4.1k", "start": 0x6000, "length": 0x1000}, - {"filename": "pap1-6.3c", "start": 0x8000, "length": 0x1000}, - {"filename": "pap1-5.3f", "start": 0x9000, "length": 0x2000}, - {"filename": "pap1-6.4c", "start": 0xE000, "length": 0x20}, - {"filename": "pap1-5.4e", "start": 0xE020, "length": 0x100}, - {"filename": "pap1-4.3l", "start": 0xE120, "length": 0x100}, - {"filename": "pap1-3.3m", "start": 0xE220, "length": 0x100} - ], - "status": 'good', - "notes": [] - }, - { - "name": "PAC-MANIA", - "system": "Arcade", - "filename": "pacmania.zip", - "in": { - "filename": "GamePacmania_Pacmuseum2021_windows_x64_Release.dll", - "start": 208768, - "length": 1445930 - }, - "out": [ - {"filename": "pn2_v0.bin", "start": 0x000000, "length": 0x10000}, - {"filename": "pn_chr-0.bin", "start": 0x01000A, "length": 0x20000}, - {"filename": "pn_chr-1.bin", "start": 0x03000A, "length": 0x20000}, - {"filename": "pn_chr-2.bin", "start": 0x05000A, "length": 0x20000}, - {"filename": "pn_chr-3.bin", "start": 0x07000A, "length": 0x20000}, - {"filename": "pn2_c8.bin", "start": 0x090012, "length": 0x10000}, - {"filename": "pn_obj-0.bin", "start": 0x0A0012, "length": 0x20000}, - {"filename": "pnx_obj1.bin", "start": 0x0C0012, "length": 0x20000}, - {"filename": "pn_prg-6.bin", "start": 0x0E002A, "length": 0x20000}, - {"filename": "pn2_p7.bin", "start": 0x10002A, "length": 0x10000}, - {"filename": "pn2_s0.bin", "start": 0x11002A, "length": 0x10000}, - {"filename": "pn2_s1.bin", "start": 0x127FF0, "length": 0x10000}, - {"filename": "cus64-64a1.mcu", "start": 0x16002A, "length": 0x1000} - ], - "status": 'playable', - "notes": [3] - }, - { - "name": "PAC-MAN", - "system": "Arcade", - "filename": "puckman.zip", - "in": { - "filename": "GamePacman_pacmuseum2021_windows_x64_Release.dll", - "start": 139008, - "length": 77344 - }, - "out": [ - {"filename": "pm1_prg1.6e", "start": 0x00000, "length": 0x800}, - {"filename": "pm1_prg2.6k", "start": 0x00800, "length": 0x800}, - {"filename": "pm1_prg3.6f", "start": 0x01000, "length": 0x800}, - {"filename": "pm1_prg4.6m", "start": 0x01800, "length": 0x800}, - {"filename": "pm1_prg5.6h", "start": 0x02000, "length": 0x800}, - {"filename": "pm1_prg6.6n", "start": 0x02800, "length": 0x800}, - {"filename": "pm1_prg7.6j", "start": 0x03000, "length": 0x800}, - {"filename": "pm1_prg8.6p", "start": 0x03800, "length": 0x800}, - # 0x04000 - 0x10000: Empty - {"filename": "pm1-3.1m", "start": 0x10000, "length": 0x100}, - {"filename": "pm1-1.7f", "start": 0x10100, "length": 0x20}, - {"filename": "pm1-4.4a", "start": 0x10120, "length": 0x100}, - # 0x10220 - 0x10A20: ??? - {"filename": "pm1_chg1.5e", "start": 0x10A20, "length": 0x800}, - {"filename": "pm1_chg2.5h", "start": 0x11220, "length": 0x800}, - {"filename": "pm1_chg3.5f", "start": 0x11A20, "length": 0x800}, - {"filename": "pm1_chg4.5j", "start": 0x12220, "length": 0x800}, - {"filename": "pm1-2.3m", "start": 0x12A20, "length": 0x100}, - # 0x12A20 - 0x12E20: ??? - ], - "status": 'playable', - "notes": [4] - }, - { - "name": "PAC-MAN ARRANGEMENT Arcade Ver.", - "system": "Arcade", - "filename": "pacman_arrangement_arcade.zip", - "in": { - "filename": "GamePacmanarrangement_pacmuseum2021_windows_x64_Release.dll", - "start": 423008, - "length": 7864320 - }, - "status": 'partial', - "notes": [1, 5] - }, - { - "name": "PAC-MAN ARRANGEMENT Console Ver.", - "system": "???", - "filename": "pacman_arrangement_console.zip", - "in": { - "filename": "GamePacmanarrangement_pacmuseum2021_windows_x64_Release.dll", - "start": 423008, - "length": 7864320 - }, - "status": 'partial', - "notes": [1, 6] - }, - { - "name": "PAC-MAN CHAMPIONSHIP EDITION", - "system": "Windows Port", - "filename": "N/A", - "status": 'no-rom', - "notes": [2, 7] - } - ] - - _out_file_notes = { - "1": "This tool cannot create a playable extraction for this title.", - "2": "This title not ROM-based (a rebuild or a native Windows port), so no extraction is possible.", - "3": "Along with some CRC mismatches, this game renders upside-down. MAME and RetroArchMAME have slightly different ways to fix this per game.", - "4": "There are minor CRC mismatches, but this ROM works properly.", - "5": "MAME does not appear to support this Arcade title, which was originally part of Namco Classic Collection Vol. 2.", - "6": "This title is likely a native/DirectX port for XBox 360, and not a packagable ROM.", - "7": "This title appears to launch with a Bandai Namco splash and is likely a native/DirectX port.", - "8": "These SNES titles do not appear to be raw or LZMA compressed in the DLL, and cannot yet be extracted." - } - - def __init__(self): - super().__init__() - self._out_file_list = map(lambda x: { - 'filename': x['filename'], - 'game': x['name'], - 'status': x['status'], - 'system': x['system'], - "notes": x['notes']}, - self._game_info_map) - - def execute(self, in_dir, out_dir): - for game in self._game_info_map: - if game.get('status') == "no-rom": - logger.info(f"Skipping {game['name']} as there is no ROM to extract...") - continue - - is_partial = game.get('status') == "partial" - if not self._props.get('include-partials') and is_partial: - logger.info(f"Skipping {game['name']} as this tool cannot extract a working copy...") - continue - - src_file = os.path.join(in_dir, r"PAC-MAN MUSEUM+_Data\Plugins\x86_64", game['in']['filename']) - if not os.path.exists(src_file): - logger.info(f"Skipping {game['name']} as this tool cannot find it in the given Steam library folder...") - continue - - logger.info(f"Extracting {game['name']}...") - with open(src_file, 'rb') as dll_file: - contents = dll_file.read() - zip_files = {} - - contents = transforms.cut(contents, game['in']['start'], length=game['in']['length']) - if game['system'] == "Arcade": - lzd = lzma.LZMADecompressor() - contents = lzd.decompress(contents) - if is_partial: - zip_files["decompressed_blob"] = contents - - for work_file in game.get('out') or []: - zip_files[work_file['filename']] = transforms.cut(contents, work_file['start'], length=work_file['length']) - else: - if is_partial: - zip_files["blob"] = contents - - for work_file in game.get('out') or []: - zip_files[work_file['filename']] = transforms.cut(contents, work_file['start'], length=work_file['length']) - - filename = f"partial_{game['filename']}" if is_partial else game['filename'] - logger.info(f"Saving {filename}...") - with open(os.path.join(out_dir, filename), "wb") as out_file: - out_file.write(helpers.build_zip(zip_files)) - - logger.info("Processing complete.") diff --git a/src/gex/lib/tasks/impl/pacmanmplus/__init__.py b/src/gex/lib/tasks/impl/pacmanmplus/__init__.py new file mode 100644 index 0000000..a025545 --- /dev/null +++ b/src/gex/lib/tasks/impl/pacmanmplus/__init__.py @@ -0,0 +1,89 @@ +'''Implementation of pacmanmplus: Pac Man Museum Plus''' +import logging +import os +import lzma +from gex.lib.tasks.basetask import BaseTask +from gex.lib.tasks import helpers +from gex.lib.utils.blob import transforms + +logger = logging.getLogger('gextoolbox') + +class PacManMuseumPlusTask(BaseTask): + '''Implements pacmanmplus: Pac Man Museum Plus''' + _task_name = "pacmanmplus" + _title = "Pac Man Museum Plus" + _details_markdown = '''''' + _default_input_folder = helpers.gen_steam_app_default_folder("PAC-MAN MUSEUM PLUS") + _input_folder_desc = "Pac Man Museum Plus install folder" + + _prop_info = { + "include-partials": { + "description": "Include the partial ROMs that are missing data; useful for mixing with other sources or investigation", + "default": False, + "type": "Boolean" + } + } + + # PAC-IN-TIME + # Official ROM is 1,048,576 + # DLL is 1,062,400 + # So, it really does need to be compressed! + # binwalk -e -M doesn't find anything + + def get_out_file_info(self): + '''Return a list of output files''' + return { + "files": self._metadata['out']['files'], + "notes": self._metadata['out']['notes'] + } + + + def execute(self, in_dir, out_dir): + for game in self._metadata['out']['files']: + if game.get('status') == "no-rom": + logger.info(f"Skipping {game['game']} as there is no ROM to extract...") + continue + + is_partial = game.get('status') == "partial" + if not self._props.get('include-partials') and is_partial: + logger.info(f"Skipping {game['game']} as this tool cannot extract a working copy...") + continue + + # read the matching input file + pkg_name = game['extract']['in_file'] + in_file_entry = self._metadata['in']['files'][pkg_name] + contents = self.read_datafile(in_dir, in_file_entry)['contents'] + + logger.info(f"Extracting {game['game']}...") + zip_files = {} + + contents = transforms.cut(contents, game['extract']['start'], length=game['extract']['length']) + if game['system'] == "Arcade": + lzd = lzma.LZMADecompressor() + contents = lzd.decompress(contents) + if is_partial: + zip_files["decompressed_blob"] = contents + + work_files = game.get('zip_files') or {} + for work_filename, geometry in work_files.items(): + start = int(geometry['start'], 16) + length = int(geometry['length'], 16) + zip_files[work_filename] = transforms.cut(contents, start, length=length) + else: + if is_partial: + zip_files["blob"] = contents + + for work_file in game.get('out') or []: + zip_files[work_file['filename']] = transforms.cut(contents, work_file['start'], length=work_file['length']) + + game_data = helpers.build_zip(zip_files) + filename = f"partial_{game['filename']}" if is_partial else game['filename'] + if not is_partial: + _ = self.verify_out_file(filename, game_data) + else: + logger.info(f"Skipping verification for partial extract {filename}.") + out_path = os.path.join(out_dir, filename) + with open(out_path, "wb") as out_file: + out_file.write(game_data) + + logger.info("Processing complete.") diff --git a/src/gex/lib/tasks/impl/pacmanmplus/metadata.json b/src/gex/lib/tasks/impl/pacmanmplus/metadata.json new file mode 100644 index 0000000..99b5238 --- /dev/null +++ b/src/gex/lib/tasks/impl/pacmanmplus/metadata.json @@ -0,0 +1,412 @@ +{ + "in": { + "files": { + "pacattack": { + "rel_path": ["PAC-MAN MUSEUM+_Data", "Plugins", "x86_64"], + "filename": "GameSFC_Pacattack_pacmuseum2021_windows_x64_Release.dll", + "versions": { + "Steam": { + "size": 547328, + "crc": "A67D96C5" + } + } + }, + "pacandpal": { + "rel_path": ["PAC-MAN MUSEUM+_Data", "Plugins", "x86_64"], + "filename": "GamePacandpal_pacmuseum2021_windows_x64_Release.dll", + "versions": { + "Steam": { + "size": 219648, + "crc": "0BB49B8C" + } + } + }, + "pacintime": { + "rel_path": ["PAC-MAN MUSEUM+_Data", "Plugins", "x86_64"], + "filename": "GameSFC_Pacintime_pacmuseum2021_windows_x64_Release.dll", + "versions": { + "Steam": { + "size": 1062400, + "crc": "F7E1C4EB" + } + } + }, + "pacland": { + "rel_path": ["PAC-MAN MUSEUM+_Data", "Plugins", "x86_64"], + "filename": "GamePacland_pacmuseum2021_windows_x64_Release.dll", + "versions": { + "Steam": { + "size": 287232, + "crc": "AE20C3C8" + } + } + }, + "pacman": { + "rel_path": ["PAC-MAN MUSEUM+_Data", "Plugins", "x86_64"], + "filename": "GamePacman_pacmuseum2021_windows_x64_Release.dll", + "versions": { + "Steam": { + "size": 222208, + "crc": "0D7244FE" + } + } + }, + "pacmanarrangement": { + "rel_path": ["PAC-MAN MUSEUM+_Data", "Plugins", "x86_64"], + "filename": "GamePacmanarrangement_pacmuseum2021_windows_x64_Release.dll", + "versions": { + "Steam": { + "size": 2687488, + "crc": "3BCE84B8" + } + } + }, + "pacmania": { + "rel_path": ["PAC-MAN MUSEUM+_Data", "Plugins", "x86_64"], + "filename": "GamePacmania_Pacmuseum2021_windows_x64_Release.dll", + "versions": { + "Steam": { + "size": 478720, + "crc": "98968FE2" + } + } + }, + "superpacman": { + "rel_path": ["PAC-MAN MUSEUM+_Data", "Plugins", "x86_64"], + "filename": "GameSuperpacman_pacmuseum2021_windows_x64_Release.dll", + "versions": { + "Steam": { + "size": 214528, + "crc": "4785DDC9" + } + } + } + } + }, + "out": { + "files": [ + { + "game": "PAC and Pal", + "system": "Arcade", + "filename": "pacnpal.zip", + "status": "good", + "notes": [], + "extract": { + "in_file": "pacandpal", + "start": 141424, + "length": 58144 + }, + "zip_files": { + "pap1-3b.1d": {"start": "0x0000", "length": "0x2000"}, + "pap1-2b.1c": {"start": "0x2000", "length": "0x2000"}, + "pap3-1.1b": {"start": "0x4000", "length": "0x2000"}, + "pap1-4.1k": {"start": "0x6000", "length": "0x1000"}, + "pap1-6.3c": {"start": "0x8000", "length": "0x1000"}, + "pap1-5.3f": {"start": "0x9000", "length": "0x2000"}, + "pap1-6.4c": {"start": "0xE000", "length": "0x20"}, + "pap1-5.4e": {"start": "0xE020", "length": "0x100"}, + "pap1-4.3l": {"start": "0xE120", "length": "0x100"}, + "pap1-3.3m": {"start": "0xE220", "length": "0x100"} + }, + "verify": { + "type": "zip", + "entries": { + "pap1-3b.1d": {"size": 8192, "crc": "ED64A565"}, + "pap1-2b.1c": {"size": 8192, "crc": "15308BCF"}, + "pap3-1.1b": {"size": 8192, "crc": "3CAC401C"}, + "pap1-4.1k": {"size": 4096, "crc": "330E20DE"}, + "pap1-6.3c": {"size": 4096, "crc": "A36B96CB"}, + "pap1-5.3f": {"size": 8192, "crc": "FB6F56E3"}, + "pap1-6.4c": {"size": 32, "crc": "52634B41"}, + "pap1-5.4e": {"size": 256, "crc": "AC46203C"}, + "pap1-4.3l": {"size": 256, "crc": "686BDE84"}, + "pap1-3.3m": {"size": 256, "crc": "94782DB5"} + } + } + }, + { + "game": "Pac Land", + "system": "Arcade", + "filename": "paclandj.zip", + "status": "playable", + "notes": [4], + "extract": { + "in_file": "pacland", + "start": 170352, + "length": 116880 + }, + "zip_files": { + "pl1-2.1t": { "start": "0x00000", "length": "0x400" }, + "pl1-1.1r": { "start": "0x00400", "length": "0x400" }, + "pl1-5.5t": { "start": "0x00800", "length": "0x400" }, + "pl1-4.4n": { "start": "0x00C00", "length": "0x400" }, + "pl1-3.6l": { "start": "0x01000", "length": "0x400" }, + "pl6_01.8b": { "start": "0x01400", "length": "0x4000" }, + "pl6_02.8d": { "start": "0x05400", "length": "0x4000" }, + "pl1_3.8e": { "start": "0x09400", "length": "0x4000" }, + "pl1_4.8f": { "start": "0x0D400", "length": "0x4000" }, + "pl1_5.8h": { "start": "0x11400", "length": "0x4000" }, + "pl1_6.8j": { "start": "0x15400", "length": "0x4000" }, + "pl1_7.3e": { "start": "0x19400", "length": "0x2000" }, + "cus60-60a1.mcu": { "start": "0x1B400", "length": "0x1000" }, + "pl6_12.6n": { "start": "0x1C400", "length": "0x2000" }, + "pl1_13.6t": { "start": "0x1E400", "length": "0x2000" }, + "pl1_9b.6f": { "start": "0x20400", "length": "0x4000" }, + "pl1_8.6e": { "start": "0x24400", "length": "0x4000" }, + "pl1_10b.7e": { "start": "0x28400", "length": "0x4000" }, + "pl1_11.7f": { "start": "0x2C400", "length": "0x4000" } + }, + "verify": { + "type": "zip", + "entries": { + "pl1-2.1t": {"size": 1024, "crc": "472885DE"}, + "pl1-1.1r": {"size": 1024, "crc": "A78EBDAF"}, + "pl1-5.5t": {"size": 1024, "crc": "4B7EE712"}, + "pl1-4.4n": {"size": 1024, "crc": "3A7BE418"}, + "pl1-3.6l": {"size": 1024, "crc": "80558DA8"}, + "pl6_01.8b": {"size": 16384, "crc": "4C96E11C"}, + "pl6_02.8d": {"size": 16384, "crc": "8CF5BD8D"}, + "pl1_3.8e": {"size": 16384, "crc": "AA9FA739"}, + "pl1_4.8f": {"size": 16384, "crc": "2B895A90"}, + "pl1_5.8h": {"size": 16384, "crc": "7AF66200"}, + "pl1_6.8j": {"size": 16384, "crc": "B01E59A9"}, + "pl1_7.3e": {"size": 8192, "crc": "8C5BECAE"}, + "cus60-60a1.mcu": {"size": 4096, "crc": "076EA82A"}, + "pl6_12.6n": {"size": 8192, "crc": "C8CB61AB"}, + "pl1_13.6t": {"size": 8192, "crc": "3AE582FD"}, + "pl1_9b.6f": {"size": 16384, "crc": "3F564D17"}, + "pl1_8.6e": {"size": 16384, "crc": "417E1359"}, + "pl1_10b.7e": {"size": 16384, "crc": "A1C93FBB"}, + "pl1_11.7f": {"size": 16384, "crc": "0222CFBF"} + } + } + }, + { + "game": "PAC-MAN", + "system": "Arcade", + "filename": "puckman.zip", + "status": "playable", + "notes": [4], + "extract": { + "in_file": "pacman", + "start": 139008, + "length": 77344 + }, + "zip_files": { + "pm1_prg1.6e": {"start": "0x00000", "length": "0x800"}, + "pm1_prg2.6k": {"start": "0x00800", "length": "0x800"}, + "pm1_prg3.6f": {"start": "0x01000", "length": "0x800"}, + "pm1_prg4.6m": {"start": "0x01800", "length": "0x800"}, + "pm1_prg5.6h": {"start": "0x02000", "length": "0x800"}, + "pm1_prg6.6n": {"start": "0x02800", "length": "0x800"}, + "pm1_prg7.6j": {"start": "0x03000", "length": "0x800"}, + "pm1_prg8.6p": {"start": "0x03800", "length": "0x800"}, + "pm1-3.1m": {"start": "0x10000", "length": "0x100"}, + "pm1-1.7f": {"start": "0x10100", "length": "0x20"}, + "pm1-4.4a": {"start": "0x10120", "length": "0x100"}, + "pm1_chg1.5e": {"start": "0x10A20", "length": "0x800"}, + "pm1_chg2.5h": {"start": "0x11220", "length": "0x800"}, + "pm1_chg3.5f": {"start": "0x11A20", "length": "0x800"}, + "pm1_chg4.5j": {"start": "0x12220", "length": "0x800"}, + "pm1-2.3m": {"start": "0x12A20", "length": "0x100"} + }, + "verify": { + "type": "zip", + "entries": { + "pm1_prg1.6e": {"size": 2048, "crc": "F36E88AB"}, + "pm1_prg2.6k": {"size": 2048, "crc": "618BD9B3"}, + "pm1_prg3.6f": {"size": 2048, "crc": "7D177853"}, + "pm1_prg4.6m": {"size": 2048, "crc": "D3E8914C"}, + "pm1_prg5.6h": {"size": 2048, "crc": "6BF4F625"}, + "pm1_prg6.6n": {"size": 2048, "crc": "A948CE83"}, + "pm1_prg7.6j": {"size": 2048, "crc": "3F7EDFC4"}, + "pm1_prg8.6p": {"size": 2048, "crc": "E941B680"}, + "pm1-3.1m": {"size": 256, "crc": "A9CC86BF"}, + "pm1-1.7f": {"size": 32, "crc": "2FC650BD"}, + "pm1-4.4a": {"size": 256, "crc": "3EB3A8E4"}, + "pm1_chg1.5e": {"size": 2048, "crc": "425808A4"}, + "pm1_chg2.5h": {"size": 2048, "crc": "3591B89D"}, + "pm1_chg3.5f": {"size": 2048, "crc": "9E39323A"}, + "pm1_chg4.5j": {"size": 2048, "crc": "1B1D9096"}, + "pm1-2.3m": {"size": 256, "crc": "5C0ABCD1"} + } + } + }, + { + "game": "PAC-MANIA", + "system": "Arcade", + "filename": "pacmania.zip", + "status": "playable", + "notes": [3], + "extract": { + "in_file": "pacmania", + "start": 208768, + "length": 1445930 + }, + "zip_files": { + "pn2_v0.bin": {"start": "0x000000", "length": "0x10000"}, + "pn_chr-0.bin": {"start": "0x01000A", "length": "0x20000"}, + "pn_chr-1.bin": {"start": "0x03000A", "length": "0x20000"}, + "pn_chr-2.bin": {"start": "0x05000A", "length": "0x20000"}, + "pn_chr-3.bin": {"start": "0x07000A", "length": "0x20000"}, + "pn2_c8.bin": {"start": "0x090012", "length": "0x10000"}, + "pn_obj-0.bin": {"start": "0x0A0012", "length": "0x20000"}, + "pnx_obj1.bin": {"start": "0x0C0012", "length": "0x20000"}, + "pn_prg-6.bin": {"start": "0x0E002A", "length": "0x20000"}, + "pn2_p7.bin": {"start": "0x10002A", "length": "0x10000"}, + "pn2_s0.bin": {"start": "0x11002A", "length": "0x10000"}, + "pn2_s1.bin": {"start": "0x127FF0", "length": "0x10000"}, + "cus64-64a1.mcu": {"start": "0x16002A", "length": "0x1000"} + }, + "verify": { + "type": "zip", + "entries": { + "pn2_v0.bin": {"size": 65536, "crc": "E2689F79"}, + "pn_chr-0.bin": {"size": 131072, "crc": "7C57644C"}, + "pn_chr-1.bin": {"size": 131072, "crc": "7EAA67ED"}, + "pn_chr-2.bin": {"size": 131072, "crc": "27E739AC"}, + "pn_chr-3.bin": {"size": 131072, "crc": "1DFDA293"}, + "pn2_c8.bin": {"size": 65536, "crc": "F3AFD65D"}, + "pn_obj-0.bin": {"size": 131072, "crc": "FDA57E8B"}, + "pnx_obj1.bin": {"size": 131072, "crc": "4C08AFFE"}, + "pn_prg-6.bin": {"size": 131072, "crc": "FE94900C"}, + "pn2_p7.bin": {"size": 65536, "crc": "2AA99E2B"}, + "pn2_s0.bin": {"size": 65536, "crc": "D5EF5EEE"}, + "pn2_s1.bin": {"size": 65536, "crc": "9B5C73D6"}, + "cus64-64a1.mcu": {"size": 4096, "crc": "FFB5C0BD"} + } + } + }, + { + "game": "Super PAC-MAN", + "system": "Arcade", + "filename": "superpac.zip", + "status": "good", + "notes": [], + "extract": { + "in_file": "superpacman", + "start": 141616, + "length": 58144 + }, + "zip_files": { + "sp1-2.1c": { "start": "0x2000", "length": "0x2000"}, + "sp1-1.1b": { "start": "0x4000", "length": "0x2000"}, + "spc-3.1k": { "start": "0x6000", "length": "0x1000"}, + "sp1-6.3c": { "start": "0x8000", "length": "0x1000"}, + "spv-2.3f": { "start": "0x9000", "length": "0x2000"}, + "superpac.4c": { "start": "0xE000", "length": "0x20"}, + "superpac.4e": { "start": "0xE020", "length": "0x100"}, + "superpac.3l": { "start": "0xE120", "length": "0x100"}, + "superpac.3m": { "start": "0xE220", "length": "0x100"} + }, + "verify": { + "type": "zip", + "entries": { + "sp1-2.1c": {"size": 8192, "crc": "4BB33D9C"}, + "sp1-1.1b": {"size": 8192, "crc": "846FBB4A"}, + "spc-3.1k": {"size": 4096, "crc": "04445DDB"}, + "sp1-6.3c": {"size": 4096, "crc": "91C5935C"}, + "spv-2.3f": {"size": 8192, "crc": "670A42F2"}, + "superpac.4c": {"size": 32, "crc": "9CE22C46"}, + "superpac.4e": {"size": 256, "crc": "1253C5C1"}, + "superpac.3l": {"size": 256, "crc": "D4D7026F"}, + "superpac.3m": {"size": 256, "crc": "AD43688F"} + } + } + }, + { + "game": "PAC Motos", + "system": "Wii", + "filename": "N/A", + "status": "no-rom", + "notes": [2] + }, + { + "game": "PAC'N Roll Remix", + "system": "Wii", + "filename": "N/A", + "status": "no-rom", + "notes": [2] + }, + { + "game": "PAC-MAN BATTLE ROYALE", + "system": "Arcade", + "filename": "N/A", + "status": "no-rom", + "notes": [2] + }, + { + "game": "PAC'N Roll Remix", + "system": "Mobile", + "filename": "N/A", + "status": "no-rom", + "notes": [2] + }, + { + "game": "PAC-MAN CHAMPIONSHIP EDITION", + "system": "Windows Port", + "filename": "N/A", + "status": "no-rom", + "notes": [2, 7] + }, + { + "game": "PAC Attack", + "system": "SNES", + "filename": "pacattack.zip", + "status": "partial", + "notes": [1, 8], + "extract": { + "in_file": "pacattack", + "start": 0, + "length": 600000 + } + }, + { + "game": "PAC-IN-TIME", + "system": "SNES", + "filename": "pacintime.zip", + "status": "partial", + "notes": [1, 8], + "extract": { + "in_file": "pacintime", + "start": 0, + "length": 1062400 + } + }, + { + "game": "PAC-MAN ARRANGEMENT Arcade Ver.", + "system": "Arcade", + "filename": "pacman_arrangement_arcade.zip", + "status": "partial", + "notes": [1, 5], + "extract": { + "in_file": "pacmanarrangement", + "start": 423008, + "length": 7864320 + } + }, + { + "game": "PAC-MAN ARRANGEMENT Console Ver.", + "system": "???", + "filename": "pacman_arrangement_console.zip", + "status": "partial", + "notes": [1, 6], + "extract": { + "in_file": "pacmanarrangement", + "start": 423008, + "length": 7864320 + } + } + ], + "notes": { + "1": "This tool cannot create a playable extraction for this title.", + "2": "This title not ROM-based (a rebuild or a native Windows port), so no extraction is possible.", + "3": "Along with some CRC mismatches, this game renders upside-down. MAME and RetroArchMAME have slightly different ways to fix this per game.", + "4": "There are minor CRC mismatches, but this ROM works properly.", + "5": "MAME does not appear to support this Arcade title, which was originally part of Namco Classic Collection Vol. 2.", + "6": "This title is likely a native/DirectX port for XBox 360, and not a packagable ROM.", + "7": "This title appears to launch with a Bandai Namco splash and is likely a native/DirectX port.", + "8": "These SNES titles do not appear to be raw or LZMA compressed in the DLL, and cannot yet be extracted." + } + } +} \ No newline at end of file diff --git a/src/gex/lib/tasks/impl/psikyo.py b/src/gex/lib/tasks/impl/psikyo/__init__.py similarity index 88% rename from src/gex/lib/tasks/impl/psikyo.py rename to src/gex/lib/tasks/impl/psikyo/__init__.py index d5a4b5c..d763377 100644 --- a/src/gex/lib/tasks/impl/psikyo.py +++ b/src/gex/lib/tasks/impl/psikyo/__init__.py @@ -199,7 +199,7 @@ def raw_files(in_files): return {f'orig/{k}':v for (k,v) in in_files.items()} func_map["raw"] = raw_files - # maincpu - identical, but 426b missing at the end of each file + # maincpu - identical, but 426 bytes missing at the end of each file def maincpu(in_files): contents = in_files['SH922.BIN'] contents = transforms.swap_endian(contents) @@ -211,16 +211,32 @@ def maincpu(in_files): return dict(zip(filenames, chunks)) func_map['maincpu'] = maincpu - # # gfx1_1 - # def gfx1_1(in_files): - # contents = in_files['CGCMN.BIN'] - # chunks = transforms.deinterleave(contents, num_ways=2, word_size=2) - # filenames = [ - # "2prog_h.u21", - # "1prog_l.u22" - # ] - # return dict(zip(filenames, chunks)) - # func_map['gfx1_1'] = gfx1_1 + # gfx1_1 + def gfx1_1(in_files): + contents = in_files['CGCMN.IMG'] + chunks = [] + filenames = [ + # Identical + "1l.u4", + "1h.u12", + + # Appears to have matches, but junk thrown in? + "2l.u5", + "2h.u13", + ] + + # 1l.u4 / 1h.u12 - easy + temp_contents = transforms.cut(contents, 0, 0x400000) + temp_chunks = transforms.deinterleave(temp_contents, num_ways=2, word_size=2) + chunks += temp_chunks + + # filenames = [ + # "odd", + # "even" + # ] + # chunks = transforms.deinterleave(contents, num_ways=2, word_size=2) + return dict(zip(filenames, chunks)) + func_map['gfx1_1'] = gfx1_1 return {'filename': game_info['filename'], 'contents': helpers.build_rom(in_files, func_map)} diff --git a/src/gex/lib/tasks/impl/sadxgg.py b/src/gex/lib/tasks/impl/sadxgg.py deleted file mode 100644 index afa8359..0000000 --- a/src/gex/lib/tasks/impl/sadxgg.py +++ /dev/null @@ -1,178 +0,0 @@ -'''Implementation of sadxgg: Sonic Adventure DX - Game Gear''' -import logging -import os - -from gex.lib.tasks.basetask import BaseTask -from gex.lib.tasks import helpers -from gex.lib.archive.prs import DecompressPrs - -logger = logging.getLogger('gextoolbox') - -class SonicAdventureDXGameGearTask(BaseTask): - '''Implements sadxgg: Sonic Adventure DX - Game Gear''' - _task_name = "sadxgg" - _title = "Sonic Adventure DX - Game Gear" - _details_markdown = ''' -Largely based on: -Romextract.sh - https://gitlab.com/vaiski/romextract/tree/master - -However, this doesn't use an external PRS tool and is intended to target Sonic Adventure DX from Steam. -PRS Code from: https://forums.qhimm.com/index.php?topic=11225.0 -''' - _out_file_notes = {} - _default_input_folder = helpers.gen_steam_app_default_folder("Sonic Adventure DX") - _input_folder_desc = "Sonic Adventure DX Steam folder" - - def execute(self, in_dir, out_dir): - bundle_files = self._find_files(in_dir) - for file_path in bundle_files: - file_name = os.path.basename(file_path) - game_info = self._game_info_map.get(file_name.lower()) - if game_info: - logger.info(f"Extracting {file_path}: {game_info['name']}") - with open(file_path, 'rb') as in_file: - in_data = in_file.read() - prs = DecompressPrs(in_data) - rom_data = prs.decompress() - filename = f"{game_info['name']} ({game_info['region']}).gg" - with open(os.path.join(out_dir, filename), "wb") as out_file: - out_file.write(rom_data) - else: - logger.info(f'Skipping {file_path} as it contains no known ROMS!') - - logger.info("Processing complete.") - - def _find_files(self, base_path): - new_paths = [] - for filename in self._game_info_map: - new_path = os.path.join(base_path, 'system', filename) - if os.path.exists(new_path): - new_paths.append(new_path) - else: - logging.warning(f"Could not find {filename} in {base_path}") - return new_paths - - def __init__(self): - super().__init__() - self._out_file_list = map(lambda x: { - 'filename': x['filename'], - 'game': f"{x['name']} ({x['region']})", - 'status': x['status'], - 'system': x['system'], - "notes": x['notes']}, - self._game_info_map.values()) - - _game_info_map = { - "g-sonic.prs": { - 'name': "G-Sonic - Sonic Blast", - 'region': "World", - "system": "Game Gear", - "status": "good", - "filename": "G-Sonic - Sonic Blast (World).gg", - "notes": [] - }, - "labylin.prs": { - 'name': "Sonic Labyrinth", - 'region': "World", - "system": "Game Gear", - "status": "good", - "filename": "Sonic Labyrinth (World).gg", - "notes": [] - }, - "mbmachin.prs": { - 'name': "Dr. Robotnik's Mean Bean Machine", - 'region': "USA,Europe", - "system": "Game Gear", - "status": "good", - "filename": "Dr. Robotnik's Mean Bean Machine (USA,Europe).gg", - "notes": [] - }, - "s-drift2.prs": { - 'name': "Sonic Drift 2", - 'region': "Japan,USA", - "system": "Game Gear", - "status": "good", - "filename": "Sonic Drift 2 (Japan,USA).gg", - "notes": [] - }, - "skypat.prs": { - 'name': "Tails no Skypatrol", - 'region': "Japan", - "system": "Game Gear", - "status": "good", - "filename": "Tails no Skypatrol (Japan).gg", - "notes": [] - }, - "sonic2.prs": { - 'name': "Sonic The Hedgehog 2", - 'region': "World", - "system": "Game Gear", - "status": "good", - "filename": "Sonic The Hedgehog 2 (World).gg", - "notes": [] - }, - "sonic-ch.prs": { - 'name': "Sonic Chaos", - 'region': "USA,Europe", - "system": "Game Gear", - "status": "good", - "filename": "Sonic Chaos (USA,Europe).gg", - "notes": [] - }, - "sonicdri.prs": { - 'name': "Sonic Drift", - 'region': "Japan", - "system": "Game Gear", - "status": "good", - "filename": "Sonic Drift (Japan).gg", - "notes": [] - }, - "sonic.prs": { - 'name': "Sonic The Hedgehog (Rev 1)", - 'region': "World", - "system": "Game Gear", - "status": "good", - "filename": "Sonic The Hedgehog (Rev 1) (World).gg", - "notes": [] - }, - "sonictai.prs": { - 'name': "Sonic & Tails", - 'region': "Japan", - "system": "Game Gear", - "status": "good", - "filename": "Sonic & Tails (Japan).gg", - "notes": [] - }, - "sonic_tt.prs": { - 'name': "Sonic & Tails 2", - 'region': "Japan", - "system": "Game Gear", - "status": "good", - "filename": "Sonic & Tails 2 (Japan).gg", - "notes": [] - }, - "spinball.prs": { - 'name': "Sonic Spinball", - 'region': "USA,Europe", - "system": "Game Gear", - "status": "good", - "filename": "Sonic Spinball (USA,Europe).gg", - "notes": [] - }, - "s-tail2.prs": { - 'name': "Sonic The Hedgehog - Triple Trouble", - 'region': "USA,Europe", - "system": "Game Gear", - "status": "good", - "filename": "Sonic The Hedgehog - Triple Trouble (USA,Europe).gg", - "notes": [] - }, - "tailsadv.prs": { - 'name': "Tails Adventures", - 'region': "World", - "system": "Game Gear", - "status": "good", - "filename": "Tails Adventures (World).gg", - "notes": [] - } - } diff --git a/src/gex/lib/tasks/impl/sadxgg/__init__.py b/src/gex/lib/tasks/impl/sadxgg/__init__.py new file mode 100644 index 0000000..a7828d7 --- /dev/null +++ b/src/gex/lib/tasks/impl/sadxgg/__init__.py @@ -0,0 +1,50 @@ +'''Implementation of sadxgg: Sonic Adventure DX - Game Gear''' +import logging +import os + +from gex.lib.tasks.basetask import BaseTask +from gex.lib.tasks import helpers +from gex.lib.archive.prs import DecompressPrs + +logger = logging.getLogger('gextoolbox') + +class SonicAdventureDXGameGearTask(BaseTask): + '''Implements sadxgg: Sonic Adventure DX - Game Gear''' + _task_name = "sadxgg" + _title = "Sonic Adventure DX - Game Gear" + _details_markdown = ''' +Largely based on: +Romextract.sh - https://gitlab.com/vaiski/romextract/tree/master + +However, this doesn't use an external PRS tool and is intended to target Sonic Adventure DX from Steam. +PRS Code from: https://forums.qhimm.com/index.php?topic=11225.0 +''' + _default_input_folder = helpers.gen_steam_app_default_folder("Sonic Adventure DX") + _input_folder_desc = "Sonic Adventure DX Steam folder" + + + def get_out_file_info(self): + '''Return a list of output files''' + return { + "files": self._metadata['out']['files'], + "notes": self._metadata['out']['notes'] + } + + def execute(self, in_dir, out_dir): + '''Copy/rename the ROM files''' + for file_metadata in self._metadata['in']['files'].values(): + resolved_file = self.read_datafile(in_dir, file_metadata) + out_file_entry = [x for x in self._metadata['out']['files'] if x['game'] == file_metadata['copy_to']][0] + + # Process the file + logger.info(f"Decompressing {out_file_entry['game']}...") + prs = DecompressPrs(resolved_file['contents']) + contents = prs.decompress() + filename = out_file_entry['filename'] + + logger.info(f"Verifying {out_file_entry['game']}...") + _ = self.verify_out_file(filename, contents) + out_path = os.path.join(out_dir, filename) + with open(out_path, "wb") as out_file: + out_file.write(contents) + logger.info("Processing complete.") diff --git a/src/gex/lib/tasks/impl/sadxgg/metadata.json b/src/gex/lib/tasks/impl/sadxgg/metadata.json new file mode 100644 index 0000000..81352fa --- /dev/null +++ b/src/gex/lib/tasks/impl/sadxgg/metadata.json @@ -0,0 +1,347 @@ +{ + "in": { + "files": { + "G-SONIC": { + "rel_path": ["system"], + "copy_to": "G-Sonic - Sonic Blast", + "filename": "G-SONIC.PRS", + "versions": { + "Steam": { + "crc": "17F6E4FE", + "size": 545584 + } + } + }, + "LABYLIN": { + "rel_path": ["system"], + "copy_to": "Sonic Labyrinth", + "filename": "LABYLIN.PRS", + "versions": { + "Steam": { + "crc": "40A6CAF5", + "size": 243652 + } + } + }, + "MBMACHIN": { + "rel_path": ["system"], + "copy_to": "Dr. Robotnik's Mean Bean Machine", + "filename": "MBMACHIN.PRS", + "versions": { + "Steam": { + "crc": "FE029CBD", + "size": 136360 + } + } + }, + "S-DRIFT2": { + "rel_path": ["system"], + "copy_to": "Sonic Drift 2", + "filename": "S-DRIFT2.PRS", + "versions": { + "Steam": { + "crc": "91143FA1", + "size": 335571 + } + } + }, + "S-TAIL2": { + "rel_path": ["system"], + "copy_to": "Sonic & Tails 2", + "filename": "SONIC_TT.PRS", + "versions": { + "Steam": { + "crc": "D596831B", + "size": 310691 + } + } + }, + "SKYPAT": { + "rel_path": ["system"], + "copy_to": "Tails no Skypatrol", + "filename": "SKYPAT.PRS", + "versions": { + "Steam": { + "crc": "3524A627", + "size": 134122 + } + } + }, + "SONIC-CH": { + "rel_path": ["system"], + "copy_to": "Sonic Chaos (Sonic & Tails)", + "filename": "SONIC-CH.PRS", + "versions": { + "Steam": { + "crc": "C32284D0", + "size": 244378 + } + } + }, + "SONIC": { + "rel_path": ["system"], + "copy_to": "Sonic The Hedgehog (Rev 1)", + "filename": "SONIC.PRS", + "versions": { + "Steam": { + "crc": "2CD62918", + "size": 168536 + } + } + }, + "SONIC2": { + "rel_path": ["system"], + "copy_to": "Sonic The Hedgehog 2", + "filename": "SONIC2.PRS", + "versions": { + "Steam": { + "crc": "1CDC8DB3", + "size": 246137 + } + } + }, + "SONICDRI": { + "rel_path": ["system"], + "copy_to": "Sonic Drift", + "filename": "SONICDRI.PRS", + "versions": { + "Steam": { + "crc": "FE50BC1F", + "size": 210065 + } + } + }, + "SONICTAI": { + "rel_path": ["system"], + "copy_to": "Sonic & Tails", + "filename": "SONICTAI.PRS", + "versions": { + "Steam": { + "crc": "CBEFD07C", + "size": 243745 + } + } + }, + "SONIC_TT": { + "rel_path": ["system"], + "copy_to": "Sonic The Hedgehog - Triple Trouble (Sonic & Tails 2)", + "filename": "S-TAIL2.PRS", + "versions": { + "Steam": { + "crc": "FDE9D4B0", + "size": 311352 + } + } + }, + "SPINBALL": { + "rel_path": ["system"], + "copy_to": "Sonic Spinball", + "filename": "SPINBALL.PRS", + "versions": { + "Steam": { + "crc": "EA158744", + "size": 258308 + } + } + }, + "TAILSADV": { + "rel_path": ["system"], + "copy_to": "Tails Adventures", + "filename": "TAILSADV.PRS", + "versions": { + "Steam": { + "crc": "AFDAEDDD", + "size": 267256 + } + } + } + } + }, + "out": { + "files": [ + { + "game": "G-Sonic - Sonic Blast", + "region": "World", + "system": "Game Gear", + "status": "good", + "filename": "G-Sonic - Sonic Blast (World).gg", + "notes": [], + "verify": { + "type": "crc", + "crc": "031B9DA9", + "size": 1048576 + } + }, + { + "game": "Sonic Labyrinth", + "region": "World", + "system": "Game Gear", + "status": "good", + "filename": "Sonic Labyrinth (World).gg", + "notes": [], + "verify": { + "type": "crc", + "crc": "5550173B", + "size": 524288 + } + }, + { + "game": "Dr. Robotnik's Mean Bean Machine", + "region": "USA,Europe", + "system": "Game Gear", + "status": "good", + "filename": "Dr. Robotnik's Mean Bean Machine (USA,Europe).gg", + "notes": [], + "verify": { + "type": "crc", + "crc": "3C2D4F48", + "size": 262144 + } + }, + { + "game": "Sonic Drift 2", + "region": "Japan,USA", + "system": "Game Gear", + "status": "good", + "filename": "Sonic Drift 2 (Japan,USA).gg", + "notes": [], + "verify": { + "type": "crc", + "crc": "D6E8A305", + "size": 524288 + } + }, + { + "game": "Tails no Skypatrol", + "region": "Japan", + "system": "Game Gear", + "status": "good", + "filename": "Tails no Skypatrol (Japan).gg", + "notes": [], + "verify": { + "type": "crc", + "crc": "88618AFA", + "size": 262144 + } + }, + { + "game": "Sonic The Hedgehog 2", + "region": "World", + "system": "Game Gear", + "status": "good", + "filename": "Sonic The Hedgehog 2 (World).gg", + "notes": [], + "verify": { + "type": "crc", + "crc": "95A18EC7", + "size": 524288 + } + }, + { + "game": "Sonic Chaos (Sonic & Tails)", + "region": "USA,Europe", + "system": "Game Gear", + "status": "good", + "filename": "Sonic Chaos (Sonic & Tails) (USA,Europe).gg", + "notes": [], + "verify": { + "type": "crc", + "crc": "663F2ABB", + "size": 524288 + } + }, + { + "game": "Sonic Drift", + "region": "Japan", + "system": "Game Gear", + "status": "good", + "filename": "Sonic Drift (Japan).gg", + "notes": [], + "verify": { + "type": "crc", + "crc": "68F0A776", + "size": 524288 + } + }, + { + "game": "Sonic The Hedgehog (Rev 1)", + "region": "World", + "system": "Game Gear", + "status": "good", + "filename": "Sonic The Hedgehog (Rev 1) (World).gg", + "notes": [], + "verify": { + "type": "crc", + "crc": "D163356E", + "size": 262144 + } + }, + { + "game": "Sonic & Tails", + "region": "Japan", + "system": "Game Gear", + "status": "good", + "filename": "Sonic & Tails (Japan).gg", + "notes": [], + "verify": { + "type": "crc", + "crc": "8AC0DADE", + "size": 524288 + } + }, + { + "game": "Sonic & Tails 2", + "region": "Japan", + "system": "Game Gear", + "status": "good", + "filename": "Sonic & Tails 2 (Japan).gg", + "notes": [], + "verify": { + "type": "crc", + "crc": "496BCE64", + "size": 524288 + } + }, + { + "game": "Sonic Spinball", + "region": "USA,Europe", + "system": "Game Gear", + "status": "good", + "filename": "Sonic Spinball (USA,Europe).gg", + "notes": [], + "verify": { + "type": "crc", + "crc": "A9210434", + "size": 524288 + } + }, + { + "game": "Sonic The Hedgehog - Triple Trouble (Sonic & Tails 2)", + "region": "USA,Europe", + "system": "Game Gear", + "status": "good", + "filename": "Sonic The Hedgehog - Triple Trouble (Sonic & Tails 2) (USA,Europe).gg", + "notes": [], + "verify": { + "type": "crc", + "crc": "D23A2A93", + "size": 524288 + } + }, + { + "game": "Tails Adventures", + "region": "World", + "system": "Game Gear", + "status": "good", + "filename": "Tails Adventures (World).gg", + "notes": [], + "verify": { + "type": "crc", + "crc": "5BB6E5D6", + "size": 524288 + } + } + ], + "notes": {} + } +} \ No newline at end of file diff --git a/src/gex/lib/tasks/impl/saga.py b/src/gex/lib/tasks/impl/saga.py deleted file mode 100644 index aaab6e6..0000000 --- a/src/gex/lib/tasks/impl/saga.py +++ /dev/null @@ -1,92 +0,0 @@ -'''Implmentation of saga: Collection of SaGa Final Fantasy Legend''' -import glob -import logging -import os -import UnityPy -from gex.lib.tasks.basetask import BaseTask -from gex.lib.tasks import helpers - -logger = logging.getLogger('gextoolbox') - -class SagaTask(BaseTask): - '''Implments saga: Collection of SaGa Final Fantasy Legend''' - _task_name = "saga" - _title = "Collection of SaGa Final Fantasy Legend" - _details_markdown = ''' -These are extracted from the Unity asset bundle files. -See https://github.com/farmerbb/RED-Project/issues/39 for more info. -''' - _out_file_notes = {} - _default_input_folder = helpers.gen_steam_app_default_folder("Sa・Ga COLLECTION") - _input_folder_desc = "Collection of SaGa Steam folder" - - def execute(self, in_dir, out_dir): - bundle_files = self._find_files(in_dir) - for file_path in bundle_files: - file_name = os.path.basename(file_path) - game_info = self._game_info_map.get(file_name) - if game_info: - logger.info(f"Extracting {file_path}: {game_info['name']}") - try: - unity_bundle = UnityPy.load(file_path) - rom_asset = unity_bundle.container.get(game_info['asset_path']) - if rom_asset: - rom_data = rom_asset.read() - with open(os.path.join(out_dir, game_info['filename']), "wb") as out_file: - out_file.write(rom_data.script) - except Exception as _: - logger.warning(f'Error while processing {file_path}!') - else: - logger.info(f'Skipping {file_path} as it contains no known ROMS!') - - logger.info("Processing complete.") - - def _find_files(self, base_path): - bundle_path = os.path.join(base_path, 'Sa・Ga COLLECTION_Data', 'StreamingAssets', - 'aa', 'Windows', 'StandaloneWindows64', 'rom*.bundle') - archive_list = glob.glob(bundle_path) - return archive_list - - - def __init__(self): - super().__init__() - self._out_file_list = map(lambda x: { - 'filename': x['filename'], - 'game': f"{x['name']}", - 'status': "good", - 'system': "Game Boy", - "notes": []}, - self._game_info_map.values()) - - _game_info_map = { - "romffl1_assets_all_e8aea7590909c1eb45f3809e4f3da68f.bundle": { - 'filename': "FinalFantasyLegend.gb", - 'name': "Final Fantasy Legend 1", - 'asset_path': "Assets/Roms/FFL1.bytes" - }, - "romffl2_assets_all_5d8137a1fdbca63a9fa7b533aa1d9db0.bundle": { - 'filename': "FinalFantasyLegend2.gb", - 'name': "Final Fantasy Legend 2", - 'asset_path': "Assets/Roms/FFL2.bytes" - }, - "romffl3_assets_all_5818995041c2c3cbe070bb00b1783274.bundle": { - 'filename': "FinalFantasyLegend3.gb", - 'name': "Final Fantasy Legend 3", - 'asset_path': "Assets/Roms/FFL3.bytes" - }, - "romjsg1_assets_all_c6047cf2db4f38cbc8f51d592e1a1c76.bundle": { - 'filename': "SaGa.gb", - 'name': "SaGa 1", - 'asset_path': "Assets/Roms/JSG1.bytes" - }, - "romjsg2_assets_all_148d5b61843deae44f69f2dfcc30e168.bundle": { - 'filename': "SaGa2.gb", - 'name': "SaGa 2", - 'asset_path': "Assets/Roms/JSG2.bytes" - }, - "romjsg3_assets_all_942cc896cee03850dc45bfc837017e8f.bundle": { - 'filename': "SaGa3.gb", - 'name': "SaGa 3", - 'asset_path': "Assets/Roms/JSG3.bytes" - } - } diff --git a/src/gex/lib/tasks/impl/saga/__init__.py b/src/gex/lib/tasks/impl/saga/__init__.py new file mode 100644 index 0000000..8fef567 --- /dev/null +++ b/src/gex/lib/tasks/impl/saga/__init__.py @@ -0,0 +1,58 @@ +'''Implmentation of saga: Collection of SaGa Final Fantasy Legend''' +import logging +import os +import UnityPy +from gex.lib.tasks.basetask import BaseTask +from gex.lib.tasks import helpers + +logger = logging.getLogger('gextoolbox') + +class SagaTask(BaseTask): + '''Implments saga: Collection of SaGa Final Fantasy Legend''' + _task_name = "saga" + _title = "Collection of SaGa Final Fantasy Legend" + _details_markdown = ''' +These are extracted from the Unity asset bundle files. +See https://github.com/farmerbb/RED-Project/issues/39 for more info. +''' + _out_file_notes = {} + _default_input_folder = helpers.gen_steam_app_default_folder("Sa・Ga COLLECTION") + _input_folder_desc = "Collection of SaGa Steam folder" + + def get_out_file_info(self): + '''Return a list of output files''' + return { + "files": self._metadata['out']['files'], + "notes": self._metadata['out']['notes'] + } + + def execute(self, in_dir, out_dir): + # for each output file entry + for out_file_entry in self._metadata['out']['files']: + pkg_name = out_file_entry['extract']['in_file'] + # Check the status of it + if out_file_entry['status'] == 'no-rom': + logger.info(f"Skipping {pkg_name} - cannot extract...") + else: + logger.info(f"Extracting {pkg_name}...") + + # read the matching input file + in_file_entry = self._metadata['in']['files'][pkg_name] + loaded_file = self.read_datafile(in_dir, in_file_entry) + + # load the archive + unity_bundle = UnityPy.load(loaded_file['contents']) + + # Get the rom asset entry + rom_asset = unity_bundle.container.get(out_file_entry['extract']['archive_path']) + rom_data = rom_asset.read().script + + if rom_asset is None: + logger.warning("Could not find rom asset in archive.") + else: + _ = self.verify_out_file(out_file_entry['filename'], rom_data) + + with open(os.path.join(out_dir, out_file_entry['filename']), "wb") as out_file: + out_file.write(rom_data) + logger.info("Processing complete.") + diff --git a/src/gex/lib/tasks/impl/saga/metadata.json b/src/gex/lib/tasks/impl/saga/metadata.json new file mode 100644 index 0000000..d809601 --- /dev/null +++ b/src/gex/lib/tasks/impl/saga/metadata.json @@ -0,0 +1,173 @@ +{ + "in": { + "files": { + "ffl1": { + "rel_path": ["Sa・Ga COLLECTION_Data", "StreamingAssets", "aa", "Windows", "StandaloneWindows64"], + "filename": "romffl1_assets_all_e8aea7590909c1eb45f3809e4f3da68f.bundle", + "versions": { + "Steam": { + "size": 109796, + "crc": "385FE479" + } + } + }, + "ffl2": { + "rel_path": ["Sa・Ga COLLECTION_Data", "StreamingAssets", "aa", "Windows", "StandaloneWindows64"], + "filename": "romffl2_assets_all_5d8137a1fdbca63a9fa7b533aa1d9db0.bundle", + "versions": { + "Steam": { + "size": 203574, + "crc": "C37F6B51" + } + } + }, + "ffl3": { + "rel_path": ["Sa・Ga COLLECTION_Data", "StreamingAssets", "aa", "Windows", "StandaloneWindows64"], + "filename": "romffl3_assets_all_5818995041c2c3cbe070bb00b1783274.bundle", + "versions": { + "Steam": { + "size": 220030, + "crc": "1EEA387F" + } + } + }, + "saga1": { + "rel_path": ["Sa・Ga COLLECTION_Data", "StreamingAssets", "aa", "Windows", "StandaloneWindows64"], + "filename": "romjsg1_assets_all_c6047cf2db4f38cbc8f51d592e1a1c76.bundle", + "versions": { + "Steam": { + "size": 44015620, + "crc": "1CA002C9" + } + } + }, + "saga2": { + "rel_path": ["Sa・Ga COLLECTION_Data", "StreamingAssets", "aa", "Windows", "StandaloneWindows64"], + "filename": "romjsg2_assets_all_148d5b61843deae44f69f2dfcc30e168.bundle", + "versions": { + "Steam": { + "size": 48237661, + "crc": "5305CE5F" + } + } + }, + "saga3": { + "rel_path": ["Sa・Ga COLLECTION_Data", "StreamingAssets", "aa", "Windows", "StandaloneWindows64"], + "filename": "romjsg3_assets_all_942cc896cee03850dc45bfc837017e8f.bundle", + "versions": { + "Steam": { + "size": 49292895, + "crc": "1C2CB802" + } + } + } + } + }, + "out": { + "files": [ + { + "game": "Final Fantasy Legend 1", + "filename": "FinalFantasyLegend.gb", + "status": "good", + "system": "Game Boy", + "notes": [], + "extract": { + "type": "unity", + "in_file": "ffl1", + "archive_path": "Assets/Roms/FFL1.bytes" + }, + "verify": { + "type": "crc", + "crc": "00388844", + "size": 131072 + } + }, + { + "game": "Final Fantasy Legend 2", + "filename": "FinalFantasyLegend2.gb", + "status": "good", + "system": "Game Boy", + "notes": [], + "extract": { + "type": "unity", + "in_file": "ffl2", + "archive_path": "Assets/Roms/FFL2.bytes" + }, + "verify": { + "type": "crc", + "crc": "E84E051A", + "size": 262144 + } + }, + { + "game": "Final Fantasy Legend 3", + "filename": "FinalFantasyLegend3.gb", + "status": "good", + "system": "Game Boy", + "notes": [], + "extract": { + "type": "unity", + "in_file": "ffl3", + "archive_path": "Assets/Roms/FFL3.bytes" + }, + "verify": { + "type": "crc", + "crc": "0C5171EF", + "size": 262144 + } + }, + { + "game": "SaGa 1", + "filename": "SaGa.gb", + "status": "good", + "system": "Game Boy", + "notes": [], + "extract": { + "type": "unity", + "in_file": "saga1", + "archive_path": "Assets/Roms/JSG1.bytes" + }, + "verify": { + "type": "crc", + "crc": "0006612D", + "size": 131072 + } + }, + { + "game": "SaGa 2", + "filename": "SaGa2.gb", + "status": "good", + "system": "Game Boy", + "notes": [], + "extract": { + "type": "unity", + "in_file": "saga2", + "archive_path": "Assets/Roms/JSG2.bytes" + }, + "verify": { + "type": "crc", + "crc": "2FE38E18", + "size": 262144 + } + }, + { + "game": "SaGa 3", + "filename": "SaGa3.gb", + "status": "good", + "system": "Game Boy", + "notes": [], + "extract": { + "type": "unity", + "in_file": "saga3", + "archive_path": "Assets/Roms/JSG3.bytes" + }, + "verify": { + "type": "crc", + "crc": "DC4F4E34", + "size": 262144 + } + } + ], + "notes": {} + } +} \ No newline at end of file diff --git a/src/gex/lib/tasks/impl/sf30ac/__init__.py b/src/gex/lib/tasks/impl/sf30ac/__init__.py index e440388..880558c 100644 --- a/src/gex/lib/tasks/impl/sf30ac/__init__.py +++ b/src/gex/lib/tasks/impl/sf30ac/__init__.py @@ -26,266 +26,42 @@ class SF30ACTask(BaseTask): This script will extract and prep the ROMs. Some per-rom errata are in the notes below. -Note that this does NOT extract the Japanese ROMs as those are only included in SF30AC International Edition. As a US player, I can't get them - I've tried! +This will only extract the Japanese ROMs if you have SF30AC International Edition. ''' - _out_file_list = [ - { - "game": "Street Fighter 2 (U)", - "system": "Arcade", - "filename": "sf2ub.zip", - "status": "playable", - "notes": [2, 3] - }, - { - "game": "Street Fighter 2 Championship Edition (U)", - "system": "Arcade", - "filename": "sf2ceua.zip", - "status": "playable", - "notes": [2, 3] - }, - { - "game": "Street Fighter 2 Hyper Fighting (U)", - "system": "Arcade", - "filename": "sf2t.zip", - "status": "playable", - "notes": [2, 3] - }, - { - "game": "Super Street Fighter 2 (U)", - "system": "Arcade", - "filename": "ssf2u.zip", - "status": "playable", - "notes": [1, 3] - }, - { - "game": "Super Street Fighter 2 Turbo (U)", - "system": "Arcade", - "filename": "ssf2tu.zip", - "status": "playable", - "notes": [1, 3] - }, - { - "game": "Street Fighter (W)", - "system": "Arcade", - "filename": "sf.zip", - "status": "playable", - "notes": [] - }, - { - "game": "Street Fighter (J)", - "system": "Arcade", - "filename": "sfj.zip", - "status": "playable", - "notes": [4] - }, - { - "game": "Street Fighter 3", - "system": "Arcade", - "filename": "sfiiina.zip", - "status": "good", - "notes": [] - }, - { - "game": "Street Fighter 3: 2nd Impact", - "system": "Arcade", - "filename": "sfiii2n.zip", - "status": "good", - "notes": [] - }, - { - "game": "Street Fighter 3: 3rd Strike", - "system": "Arcade", - "filename": "sfiii3nr1.zip", - "status": "good", - "notes": [] - }, - { - "game": "Street Fighter 2 (JA)", - "system": "Arcade", - "filename": "sf2ja.zip", - "status": "playable", - "notes": [2, 3, 4] - }, - { - "game": "Street Fighter 2 (JL)", - "system": "Arcade", - "filename": "N/A", - "status": "no-rom", - "notes": [2, 3, 4, 5] - }, - { - "game": "Street Fighter 2 Championship Edition (JB)", - "system": "Arcade", - "filename": "sf2cejb.zip", - "status": "playable", - "notes": [2, 3, 4] - }, - { - "game": "Street Fighter 2 Championship Edition (JC)", - "system": "Arcade", - "filename": "N/A", - "status": "no-rom", - "notes": [2, 3, 4, 5] - }, - { - "game": "Street Fighter 2 Hyper Fighting (J)", - "system": "Arcade", - "filename": "sf2tj.zip", - "status": "playable", - "notes": [2, 3, 4] - }, - { - "game": "Street Fighter Alpha (U)", - "system": "Arcade", - "filename": "sfau.zip", - "status": "playable", - "notes": [1] - }, - { - "game": "Street Fighter Alpha (J)", - "system": "Arcade", - "filename": "sfzj.zip", - "status": "playable", - "notes": [1, 4] - }, - { - "game": "Street Fighter Alpha (JR2)", - "system": "Arcade", - "filename": "sfzjr2.zip", - "status": "playable", - "notes": [1, 4] - }, - { - "game": "Street Fighter Alpha 2 (U)", - "system": "Arcade", - "filename": "sfa2u.zip", - "status": "playable", - "notes": [1, 3] - }, - { - "game": "Street Fighter Alpha 2 (J)", - "system": "Arcade", - "filename": "sfz2j.zip", - "status": "playable", - "notes": [1, 3, 4] - }, - { - "game": "Street Fighter Alpha 2 (JR1)", - "system": "Arcade", - "filename": "N/A", - "status": "no-rom", - "notes": [1, 3, 4, 5] - }, - { - "game": "Street Fighter Alpha 3 (J)", - "system": "Arcade", - "filename": "sfz3j.zip", - "status": "playable", - "notes": [1, 4] - }, - { - "game": "Street Fighter Alpha 3 (JR2)", - "system": "Arcade", - "filename": "sfz3jr2.zip", - "status": "playable", - "notes": [1, 4] - }, - { - "game": "Street Fighter Alpha 3 (U)", - "system": "Arcade", - "filename": "sfa3u.zip", - "status": "playable", - "notes": [1] - }, - { - "game": "Super Street Fighter 2 (J)", - "system": "Arcade", - "filename": "ssf2.zip", - "status": "playable", - "notes": [1, 3, 4] - }, - { - "game": "Super Street Fighter 2 (JR1)", - "system": "Arcade", - "filename": "ssf2u.zip", - "status": "playable", - "notes": [1, 3, 4] - }, - { - "game": "Super Street Fighter 2 Turbo (J)", - "system": "Arcade", - "filename": "ssf2tu.zip", - "status": "playable", - "notes": [1, 3, 4] - }, - { - "game": "Super Street Fighter 2 Turbo (JR1)", - "system": "Arcade", - "filename": "N/A", - "status": "no-rom", - "notes": [1, 3, 4, 5] - } - ] - _out_file_notes = { - "1": "These ROMs require an older version MAME. They test fine in MAME 0.139 (Mame 2010 in RetroArch). "\ - "This is typically due to a missing decryption key, dl-1425.bin qsound rom, or other ROM files that the older MAME did not strictly require.", - "2": "These ROMs require an older version MAME. They test fine in MAME 0.78 (Mame 2003 in RetroArch). "\ - "This is typically due to a missing decryption key, dl-1425.bin qsound rom, or other ROM files that the older MAME did not strictly require.", - "3": "These are using an older naming convention to allow recognition by the targeted MAME version.", - "4": "These ROMs are only present if your Street Fighter 30th Anniversary Collection says it is 'International'.", - "5": "This ROM is not extracted as no known emulators can play it as is due to the missing key and being a newer post-MAME2010 split." - } _default_input_folder = helpers.gen_steam_app_default_folder("Street Fighter 30th Anniversary Collection") _input_folder_desc = "SF30AC Steam folder" - _pkg_name_map = { - 'bundleStreetFighter.mbundle': 'sf', - 'bundleStreetFighterAlpha.mbundle': 'sfa', - 'bundleStreetFighterAlpha2.mbundle': 'sfa2', - 'bundleStreetFighterAlpha3.mbundle': 'sfa3', - 'bundleStreetFighterII.mbundle': 'sf2', - 'bundleStreetFighterIII.mbundle': 'sf3', - 'bundleStreetFighterIII_2ndImpact.mbundle': 'sf3_2i', - 'bundleStreetFighterIII_3rdStrike.mbundle': 'sf3_3s', - 'bundleStreetFighterII_CE.mbundle': 'sf2ce', - 'bundleStreetFighterII_HF.mbundle': 'sf2hf', - 'bundleSuperStreetFighterII.mbundle': 'ssf2', - 'bundleSuperStreetFighterIITurbo.mbundle': 'ssf2t' - } + def get_out_file_info(self): + '''Return a list of output files''' + return { + "files": self._metadata['out']['files'], + "notes": self._metadata['out']['notes'] + } + def execute(self, in_dir, out_dir): - bundle_files = self._find_files(in_dir) - for file_path in bundle_files: - with open(file_path, 'rb') as in_file: - file_name = os.path.basename(file_path) - pkg_name = self._pkg_name_map.get(file_name) - if pkg_name is not None: - logger.info(f'Reading files for {file_name}...') - contents = in_file.read() - reader = BPListReader(contents) - parsed = reader.parse() - - handler_func = self.find_handler_func(pkg_name) - if parsed is not None and handler_func is not None: - output_files = handler_func(parsed) - - for out_file_entry in output_files: - out_path = os.path.join(out_dir, out_file_entry['filename']) - with open(out_path, "wb") as out_file: - out_file.write(out_file_entry['contents']) - elif parsed is None: - logger.warning("Could not find merged rom data in mbundle.") - elif handler_func is None: - logger.warning("Could not find matching handler function.") - else: - logger.info(f'Skipping {file_name} as it contains no known roms...') + for file_ref, file_metadata in self._metadata['in']['files'].items(): + resolved_file = self.read_datafile(in_dir, file_metadata) + reader = BPListReader(resolved_file['contents']) + is_international = resolved_file['version'] == "International Steam" + parsed = reader.parse() + + handler_func = self.find_handler_func(file_ref) + if parsed is not None and handler_func is not None: + output_files = handler_func(parsed, is_international) + + for out_file_entry in output_files: + filename = out_file_entry['filename'] + _ = self.verify_out_file(filename, out_file_entry['contents']) + out_path = os.path.join(out_dir, filename) + with open(out_path, "wb") as out_file: + out_file.write(out_file_entry['contents']) + elif parsed is None: + logger.warning("Could not find merged rom data in mbundle.") + elif handler_func is None: + logger.warning("Could not find matching handler function.") logger.info("Processing complete.") - def _find_files(self, base_path): - bundle_path = os.path.join(base_path, "Bundle", '*.mbundle') - archive_list = glob.glob(bundle_path) - return archive_list - def _process_simm_common(self, simm_id, simm_prefix, simm_size_bytes): def process_simm(in_files): contents = in_files[simm_id] @@ -346,7 +122,7 @@ def _cps2_gfx_deinterleave(self, contents, num_ways=4, word_size=2): # Street Fighter # ################################################################################ - def _handle_sf(self, mbundle_entries): + def _handle_sf(self, mbundle_entries, is_international): func_map = {} out_files = [] in_files = {} @@ -457,8 +233,8 @@ def maincpu(in_files): ) logger.info(f"Extracted {mame_name}.") - # See if the J ROM is present - if in_files['j-68k'] is not None and in_files['j-samples'] is not None: + # Handle international ROMs + if is_international: logger.info("Japanese ROMs found, extracting...") func_map['maincpu'] = sf_maincpu('j-68k', maincpu_filenames) samples_filenames_j = [ @@ -490,7 +266,7 @@ def maincpu(in_files): # Street Fighter 2 # ################################################################################ - def _handle_sf2(self, mbundle_entries): + def _handle_sf2(self, mbundle_entries, is_international): func_map = {} out_files = [] in_files = {} @@ -595,8 +371,8 @@ def maincpu(in_files): logger.info(f"Extracted {mame_name}.") - # See if the J ROM is present - if in_files['ja-68k'] is not None: + # Handle international ROMs + if is_international: logger.info("Japanese ROMs found, extracting...") func_map = {} maincpu_filenames_ja = [ @@ -629,7 +405,7 @@ def maincpu(in_files): # Street Fighter Alpha # ################################################################################ - def _handle_sfa(self, mbundle_entries): + def _handle_sfa(self, mbundle_entries, is_international): out_files = [] func_map = {} in_files = {} @@ -700,8 +476,8 @@ def maincpu(in_files): ) logger.info(f"Extracted {mame_name}.") - # See if the J ROM is present - if in_files['j-68k'] is not None and in_files['jr2-68k'] is not None: + # Handle international ROMs + if is_international: logger.info("Japanese ROMs found, extracting...") func_map = {} maincpu_filenames_j = [ @@ -744,7 +520,7 @@ def maincpu(in_files): # Street Fighter Alpha 2 # ################################################################################ - def _handle_sfa2(self, mbundle_entries): + def _handle_sfa2(self, mbundle_entries, is_international): out_files = [] func_map = {} in_files = {} @@ -821,8 +597,8 @@ def maincpu(in_files): ) logger.info(f"Extracted {mame_name}.") - # See if the J ROM is present - if in_files['j-68k'] is not None and in_files['jr1-68k'] is not None: + # Handle international ROMs + if is_international: logger.info("Japanese ROMs found, extracting...") func_map = {} maincpu_filenames_j = [ @@ -854,7 +630,7 @@ def maincpu(in_files): # Street Fighter Alpha 3 # ################################################################################ - def _handle_sfa3(self, mbundle_entries): + def _handle_sfa3(self, mbundle_entries, is_international): out_files = [] func_map = {} in_files = {} @@ -936,8 +712,8 @@ def maincpu(in_files): ) logger.info(f"Extracted {mame_name}.") - # See if the J ROM is present - if in_files['j-68k'] is not None and in_files['jr2-68k'] is not None: + # Handle international ROMs + if is_international: logger.info("Japanese ROMs found, extracting...") func_map = {} maincpu_filenames_j = [ @@ -1005,7 +781,7 @@ def _sf3_common(self, mbundle_entries, in_bios_filename, in_simm_bank_files, sim return out_files - def _handle_sf3(self, mbundle_entries): + def _handle_sf3(self, mbundle_entries, _): in_prefix = "StreetFighterIII" in_simm_bank_nums = [1, 3, 4, 5] in_simm_files = dict(zip(in_simm_bank_nums, @@ -1024,7 +800,7 @@ def _handle_sf3(self, mbundle_entries): # Street Fighter 3 2nd Impact # ################################################################################ - def _handle_sf3_2i(self, mbundle_entries): + def _handle_sf3_2i(self, mbundle_entries, _): in_prefix = "StreetFighterIII_2ndImpact" in_simm_bank_nums = list(range(1,6)) in_simm_files = dict(zip(in_simm_bank_nums, @@ -1043,7 +819,7 @@ def _handle_sf3_2i(self, mbundle_entries): # Street Fighter 3 3rd Strike # ################################################################################ - def _handle_sf3_3s(self, mbundle_entries): + def _handle_sf3_3s(self, mbundle_entries, _): in_prefix = "StreetFighterIII_3rdStrike" in_simm_files = { 1: f'{in_prefix}.r1.s1', @@ -1067,7 +843,7 @@ def _handle_sf3_3s(self, mbundle_entries): # Street Fighter 2 Championship Edition # ################################################################################ - def _handle_sf2ce(self, mbundle_entries): + def _handle_sf2ce(self, mbundle_entries, is_international): func_map = {} out_files = [] in_files = {} @@ -1162,24 +938,25 @@ def maincpu(in_files): ) logger.info(f"Extracted {mame_name}.") - if in_files['jb-68k'] is not None: + # Handle international ROMs + if is_international: logger.info("Japanese ROMs found, extracting...") func_map = {} - maincpu_filenames_jb = [ + maincpu_filenames = [ "s92j_23b.bin", "s92j_22b.bin", "s92_21a.bin" ] - func_map['maincpu'] = sf2ce_maincpu('jb-68k', maincpu_filenames_jb) + func_map['maincpu'] = sf2ce_maincpu('jb-68k', maincpu_filenames) func_map['common'] = helpers.existing_files_helper(common_file_map) - mame_name_jb = 'sf2cej.zip' - logger.info(f"Building {mame_name_jb}...") + mame_name = 'sf2cej.zip' + logger.info(f"Building {mame_name}...") out_files.append( - {'filename': mame_name_jb, 'contents': helpers.build_rom(in_files, func_map)} + {'filename': mame_name, 'contents': helpers.build_rom(in_files, func_map)} ) - logger.info(f"Extracted {mame_name_jb}.") + logger.info(f"Extracted {mame_name}.") - logger.info("Skipping sf2ceja.zip as it needs a key but isn't in an old keyless MAME.") + logger.info("Skipping sf2cej.zip as it needs a key but isn't in an old keyless MAME.") else: logger.info("Japanese ROMs not found, skipping.") @@ -1189,7 +966,7 @@ def maincpu(in_files): # Street Fighter 2 Hyper Fighting # ################################################################################ - def _handle_sf2hf(self, mbundle_entries): + def _handle_sf2hf(self, mbundle_entries, is_international): func_map = {} out_files = [] in_files = {} @@ -1288,7 +1065,8 @@ def gfx(in_files): ) logger.info(f"Extracted {mame_name}.") - if in_files['j-68k'] is not None and in_files['j-vrom'] is not None: + # Handle international ROMs + if is_international: logger.info("Japanese ROMs found, extracting...") func_map = {} maincpu_filenames = [ @@ -1330,7 +1108,7 @@ def gfx(in_files): # Super Street Fighter 2 # ################################################################################ - def _handle_ssf2(self, mbundle_entries): + def _handle_ssf2(self, mbundle_entries, is_international): func_map = {} out_files = [] in_files = {} @@ -1411,8 +1189,8 @@ def maincpu(in_files): ) logger.info(f"Extracted {mame_name}.") - - if in_files['j-68k'] is not None and in_files['jr1-68k'] is not None: + # Handle international ROMs + if is_international: logger.info("Japanese ROMs found, extracting...") func_map = {} maincpu_filenames = [ @@ -1455,7 +1233,7 @@ def maincpu(in_files): # Super Street Fighter 2 Turbo # ################################################################################ - def _handle_ssf2t(self, mbundle_entries): + def _handle_ssf2t(self, mbundle_entries, is_international): func_map = {} out_files = [] in_files = {} @@ -1537,8 +1315,8 @@ def maincpu(in_files): ) logger.info(f"Extracted {mame_name}.") - - if in_files['j-68k'] is not None: + # Handle international ROMs + if is_international: logger.info("Japanese ROMs found, extracting...") func_map = {} maincpu_filenames = [ diff --git a/src/gex/lib/tasks/impl/sf30ac/metadata.json b/src/gex/lib/tasks/impl/sf30ac/metadata.json new file mode 100644 index 0000000..41274c9 --- /dev/null +++ b/src/gex/lib/tasks/impl/sf30ac/metadata.json @@ -0,0 +1,1170 @@ +{ + "in": { + "files": { + "sf": { + "rel_path": ["Bundle"], + "filename": "bundleStreetFighter.mbundle", + "versions": { + "International Steam": { + "crc": "02081BAD", + "size": 99609526 + }, + "US Steam": { + "crc": "A3B4810D", + "size": 98954064 + } + } + }, + "sfa" : { + "rel_path": ["Bundle"], + "filename": "bundleStreetFighterAlpha.mbundle", + "versions": { + "International Steam": { + "crc": "5A000965", + "size": 214324885 + }, + "US Steam": { + "crc": "CF2234A2", + "size": 208033038 + } + } + }, + "sfa2" : { + "rel_path": ["Bundle"], + "filename": "bundleStreetFighterAlpha2.mbundle", + "versions": { + "International Steam": { + "crc": "47A0FA5C", + "size": 324015815 + }, + "US Steam": { + "crc": "8EDDC428", + "size": 315626811 + } + } + }, + "sfa3" : { + "rel_path": ["Bundle"], + "filename": "bundleStreetFighterAlpha3.mbundle", + "versions": { + "International Steam": { + "crc": "D79C8587", + "size": 319979257 + }, + "US Steam": { + "crc": "FBB39E77", + "size": 309493101 + } + } + }, + "sf2" : { + "rel_path": ["Bundle"], + "filename": "bundleStreetFighterII.mbundle", + "versions": { + "International Steam": { + "crc": "E8555FEB", + "size": 124213735 + }, + "US Steam": { + "crc": "7F422388", + "size": 122116483 + } + } + }, + "sf3" : { + "rel_path": ["Bundle"], + "filename": "bundleStreetFighterIII.mbundle", + "versions": { + "International Steam": { + "crc": "DED0A6DB", + "size": 236824264 + }, + "US Steam": { + "crc": "07EC4BDF", + "size": 236824087 + } + } + }, + "sf3_2i" : { + "rel_path": ["Bundle"], + "filename": "bundleStreetFighterIII_2ndImpact.mbundle", + "versions": { + "International Steam": { + "crc": "6966CEDB", + "size": 67643260 + }, + "US Steam": { + "crc": "77699200", + "size": 67643073 + } + } + }, + "sf3_3s" : { + "rel_path": ["Bundle"], + "filename": "bundleStreetFighterIII_3rdStrike.mbundle", + "versions": { + "International Steam": { + "crc": "F3295D6D", + "size": 344116252 + }, + "US Steam": { + "crc": "E4005712", + "size": 344116065 + } + } + }, + "sf2ce" : { + "rel_path": ["Bundle"], + "filename": "bundleStreetFighterII_CE.mbundle", + "versions": { + "International Steam": { + "crc": "A0F1D1B8", + "size": 139982211 + }, + "US Steam": { + "crc": "AF9DCF75", + "size": 136836377 + } + } + }, + "sf2hf" : { + "rel_path": ["Bundle"], + "filename": "bundleStreetFighterII_HF.mbundle", + "versions": { + "International Steam": { + "crc": "9651BB3C", + "size": 16062864 + }, + "US Steam": { + "crc": "299CE4F8", + "size": 8198431 + } + } + }, + "ssf2" : { + "rel_path": ["Bundle"], + "filename": "bundleSuperStreetFighterII.mbundle", + "versions": { + "International Steam": { + "crc": "8CFA2A0C", + "size": 286763564 + }, + "US Steam": { + "crc": "B39C0B73", + "size": 276277403 + } + } + }, + "ssf2t" : { + "rel_path": ["Bundle"], + "filename": "bundleSuperStreetFighterIITurbo.mbundle", + "versions": { + "International Steam": { + "crc": "38397825", + "size": 307175293 + }, + "US Steam": { + "crc": "BFED9077", + "size": 292494803 + } + } + } + } + }, + "out": { + "files": [ + { + "game": "Street Fighter (W)", + "system": "Arcade", + "filename": "sf.zip", + "status": "playable", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "sfu-00.1h": {"size": 131072, "crc": "A7CCE903"}, + "sf-01.1k": {"size": 131072, "crc": "86E0F0D5"}, + "sfd-19.2a": {"size": 65536, "crc": "FAAF6255"}, + "sfd-22.2c": {"size": 65536, "crc": "E1FE3519"}, + "sfd-20.3a": {"size": 65536, "crc": "44B915BD"}, + "sfd-23.3c": {"size": 65536, "crc": "79C43FF8"}, + "sfd-21.4a": {"size": 65536, "crc": "E8DB799B"}, + "sfd-24.4c": {"size": 65536, "crc": "466A3440"}, + "mb7114h.12k": {"size": 256, "crc": "0D968558"}, + "mb7114h.11h": {"size": 256, "crc": "0D968558"}, + "mb7114h.12j": {"size": 256, "crc": "0D968558"}, + "mmi-7603.13h": {"size": 32, "crc": "190A55AD"}, + "sf-39.2k": {"size": 131072, "crc": "CEE3D292"}, + "sf-38.1k": {"size": 131072, "crc": "2EA99676"}, + "sf-41.4k": {"size": 131072, "crc": "E0280495"}, + "sf-40.3k": {"size": 131072, "crc": "C70B30DE"}, + "sf-25.1d": {"size": 131072, "crc": "7F23042E"}, + "sf-28.1e": {"size": 131072, "crc": "92F8B91C"}, + "sf-30.1g": {"size": 131072, "crc": "B1399856"}, + "sf-34.1h": {"size": 131072, "crc": "96B6AE2E"}, + "sf-26.2d": {"size": 131072, "crc": "54EDE9F5"}, + "sf-29.2e": {"size": 131072, "crc": "F0649A67"}, + "sf-31.2g": {"size": 131072, "crc": "8F4DD71A"}, + "sf-35.2h": {"size": 131072, "crc": "70C00FB4"}, + "sf-15.1m": {"size": 131072, "crc": "FC0113DB"}, + "sf-16.2m": {"size": 131072, "crc": "82E4A6D3"}, + "sf-11.1k": {"size": 131072, "crc": "E112DF1B"}, + "sf-12.2k": {"size": 131072, "crc": "42D52299"}, + "sf-07.1h": {"size": 131072, "crc": "49F340D9"}, + "sf-08.2h": {"size": 131072, "crc": "95ECE9B1"}, + "sf-03.1f": {"size": 131072, "crc": "5CA05781"}, + "sf-17.3m": {"size": 131072, "crc": "69FAC48E"}, + "sf-18.4m": {"size": 131072, "crc": "71CFD18D"}, + "sf-13.3k": {"size": 131072, "crc": "FA2EB24B"}, + "sf-14.4k": {"size": 131072, "crc": "AD955C95"}, + "sf-09.3h": {"size": 131072, "crc": "41B73A31"}, + "sf-10.4h": {"size": 131072, "crc": "91C41C50"}, + "sf-05.3f": {"size": 131072, "crc": "538C7CBE"}, + "sf-27.4d": {"size": 16384, "crc": "2B09B36D"}, + "sf-37.4h": {"size": 65536, "crc": "23D09D3D"}, + "sf-36.3h": {"size": 65536, "crc": "EA16DF6C"}, + "sf-32.3g": {"size": 65536, "crc": "72DF2BD9"}, + "sf-33.4g": {"size": 65536, "crc": "3E99D3D5"}, + "sf-02.7k": {"size": 32768, "crc": "4A9AC534"} + } + } + }, + { + "game": "Street Fighter (J)", + "system": "Arcade", + "filename": "sfj.zip", + "status": "playable", + "notes": [4], + "verify": { + "type": "zip", + "entries": { + "sf-00.1h": {"size": 131072, "crc": "4B733845"}, + "sf-01.1k": {"size": 131072, "crc": "86E0F0D5"}, + "sfd-19.2a": {"size": 65536, "crc": "116027D7"}, + "sfd-22.2c": {"size": 65536, "crc": "D3CBD09E"}, + "sfd-20.3a": {"size": 65536, "crc": "FE07E83F"}, + "sfd-23.3c": {"size": 65536, "crc": "1E435D33"}, + "sfd-21.4a": {"size": 65536, "crc": "E086BC4C"}, + "sfd-24.4c": {"size": 65536, "crc": "13A6696B"}, + "mb7114h.12j": {"size": 256, "crc": "0D968558"}, + "sfb00.bin": {"size": 256, "crc": "0D968558"}, + "sfb05.bin": {"size": 256, "crc": "0D968558"}, + "mmi-7603.13h": {"size": 32, "crc": "190A55AD"}, + "sf_s.id8751h-8.14f": {"size": 4096, "crc": "C71C0011"}, + "sf-39.2k": {"size": 131072, "crc": "CEE3D292"}, + "sf-38.1k": {"size": 131072, "crc": "2EA99676"}, + "sf-41.4k": {"size": 131072, "crc": "E0280495"}, + "sf-40.3k": {"size": 131072, "crc": "C70B30DE"}, + "sf-25.1d": {"size": 131072, "crc": "7F23042E"}, + "sf-28.1e": {"size": 131072, "crc": "92F8B91C"}, + "sf-30.1g": {"size": 131072, "crc": "B1399856"}, + "sf-34.1h": {"size": 131072, "crc": "96B6AE2E"}, + "sf-26.2d": {"size": 131072, "crc": "54EDE9F5"}, + "sf-29.2e": {"size": 131072, "crc": "F0649A67"}, + "sf-31.2g": {"size": 131072, "crc": "8F4DD71A"}, + "sf-35.2h": {"size": 131072, "crc": "70C00FB4"}, + "sf-15.1m": {"size": 131072, "crc": "FC0113DB"}, + "sf-16.2m": {"size": 131072, "crc": "82E4A6D3"}, + "sf-11.1k": {"size": 131072, "crc": "E112DF1B"}, + "sf-12.2k": {"size": 131072, "crc": "42D52299"}, + "sf-07.1h": {"size": 131072, "crc": "49F340D9"}, + "sf-08.2h": {"size": 131072, "crc": "95ECE9B1"}, + "sf-03.1f": {"size": 131072, "crc": "5CA05781"}, + "sf-17.3m": {"size": 131072, "crc": "69FAC48E"}, + "sf-18.4m": {"size": 131072, "crc": "71CFD18D"}, + "sf-13.3k": {"size": 131072, "crc": "FA2EB24B"}, + "sf-14.4k": {"size": 131072, "crc": "AD955C95"}, + "sf-09.3h": {"size": 131072, "crc": "41B73A31"}, + "sf-10.4h": {"size": 131072, "crc": "91C41C50"}, + "sf-05.3f": {"size": 131072, "crc": "538C7CBE"}, + "sf-27.4d": {"size": 16384, "crc": "2B09B36D"}, + "sf-37.4h": {"size": 65536, "crc": "23D09D3D"}, + "sf-36.3h": {"size": 65536, "crc": "EA16DF6C"}, + "sf-32.3g": {"size": 65536, "crc": "72DF2BD9"}, + "sf-33.4g": {"size": 65536, "crc": "3E99D3D5"}, + "sf-02.7k": {"size": 32768, "crc": "4A9AC534"} + } + } + }, + { + "game": "Street Fighter 2 (U)", + "system": "Arcade", + "filename": "sf2ub.zip", + "status": "playable", + "notes": [2, 3], + "verify": { + "type": "zip", + "entries": { + "sf2_30a.bin": {"size": 131072, "crc": "57BD7051"}, + "sf2u.37b": {"size": 131072, "crc": "4A54D479"}, + "sf2_31a.bin": {"size": 131072, "crc": "A673143D"}, + "sf2_38a.bin": {"size": 131072, "crc": "4C2CCEF7"}, + "sf2_28a.bin": {"size": 131072, "crc": "4009955E"}, + "sf2_35a.bin": {"size": 131072, "crc": "8C1F3994"}, + "sf2_29a.bin": {"size": 131072, "crc": "BB4AF315"}, + "sf2_36a.bin": {"size": 131072, "crc": "C02A13EB"}, + "sf2_9.12a": {"size": 65536, "crc": "A4823A1B"}, + "sf2_06.bin": {"size": 524288, "crc": "22C9CC8E"}, + "sf2_08.bin": {"size": 524288, "crc": "57213BE8"}, + "sf2_05.bin": {"size": 524288, "crc": "BA529B4F"}, + "sf2_07.bin": {"size": 524288, "crc": "4B1B33A8"}, + "sf2_15.bin": {"size": 524288, "crc": "2C7E2229"}, + "sf2_17.bin": {"size": 524288, "crc": "B5548F17"}, + "sf2_14.bin": {"size": 524288, "crc": "14B84312"}, + "sf2_16.bin": {"size": 524288, "crc": "5E9CD89A"}, + "sf2_25.bin": {"size": 524288, "crc": "00F1835D"}, + "sf2_27.bin": {"size": 524288, "crc": "C1B85E35"}, + "sf2_24.bin": {"size": 524288, "crc": "4D872721"}, + "sf2_26.bin": {"size": 524288, "crc": "0EFB4EFC"}, + "sf2_18.11c": {"size": 131072, "crc": "7F162009"}, + "sf2_19.12c": {"size": 131072, "crc": "BEADE53F"}, + "buf1": {"size": 279, "crc": "4BFEC235"}, + "c632.ic1": {"size": 279, "crc": "4BFEC235"}, + "ioa1": {"size": 279, "crc": "4BFEC235"}, + "iob1.11d": {"size": 279, "crc": "4BFEC235"}, + "prg1": {"size": 279, "crc": "4BFEC235"}, + "rom1": {"size": 279, "crc": "4BFEC235"}, + "sou1": {"size": 279, "crc": "4BFEC235"}, + "stf29.1a": {"size": 279, "crc": "4BFEC235"} + } + } + }, + { + "game": "Street Fighter 2 Championship Edition (U)", + "system": "Arcade", + "filename": "sf2ceua.zip", + "status": "playable", + "notes": [2, 3], + "verify": { + "type": "zip", + "entries": { + "s92u-23a": {"size": 524288, "crc": "AC44415B"}, + "sf2ce.22": {"size": 524288, "crc": "99F1CCA4"}, + "s92_21a.bin": {"size": 524288, "crc": "925A7877"}, + "s92_09.bin": {"size": 65536, "crc": "08F6B60E"}, + "s92_01.bin": {"size": 524288, "crc": "03B0D852"}, + "s92_02.bin": {"size": 524288, "crc": "840289EC"}, + "s92_03.bin": {"size": 524288, "crc": "CDB5F027"}, + "s92_04.bin": {"size": 524288, "crc": "E2799472"}, + "s92_05.bin": {"size": 524288, "crc": "BA8A2761"}, + "s92_06.bin": {"size": 524288, "crc": "E584BFB5"}, + "s92_07.bin": {"size": 524288, "crc": "21E3F87D"}, + "s92_08.bin": {"size": 524288, "crc": "BEFC47DF"}, + "s92_10.bin": {"size": 524288, "crc": "0FBCFED0"}, + "s92_11.bin": {"size": 524288, "crc": "68503EB0"}, + "s92_12.bin": {"size": 524288, "crc": "5AD54783"}, + "s92_13.bin": {"size": 524288, "crc": "E5F0E13B"}, + "s92_18.bin": {"size": 131072, "crc": "7F162009"}, + "s92_19.bin": {"size": 131072, "crc": "BEADE53F"}, + "bprg1.11d": {"size": 279, "crc": "4BFEC235"}, + "buf1": {"size": 279, "crc": "4BFEC235"}, + "c632.ic1": {"size": 279, "crc": "4BFEC235"}, + "ioa1": {"size": 279, "crc": "4BFEC235"}, + "iob1.12d": {"size": 279, "crc": "4BFEC235"}, + "prg1": {"size": 279, "crc": "4BFEC235"}, + "rom1": {"size": 279, "crc": "4BFEC235"}, + "sou1": {"size": 279, "crc": "4BFEC235"}, + "ioc1.ic7": {"size": 260, "crc": "91A9701B"} + } + } + }, + { + "game": "Street Fighter 2 Hyper Fighting (U)", + "system": "Arcade", + "filename": "sf2t.zip", + "status": "playable", + "notes": [2, 3], + "verify": { + "type": "zip", + "entries": { + "sf2_23a": {"size": 524288, "crc": "89A1FC38"}, + "sf2_22.bin": {"size": 524288, "crc": "AEA6E035"}, + "sf2_21.bin": {"size": 524288, "crc": "FD200288"}, + "s92_01.bin": {"size": 524288, "crc": "03B0D852"}, + "s92_02.bin": {"size": 524288, "crc": "840289EC"}, + "s92_03.bin": {"size": 524288, "crc": "CDB5F027"}, + "s92_04.bin": {"size": 524288, "crc": "E2799472"}, + "s92_05.bin": {"size": 524288, "crc": "BA8A2761"}, + "s92_06.bin": {"size": 524288, "crc": "E584BFB5"}, + "s92_07.bin": {"size": 524288, "crc": "21E3F87D"}, + "s92_08.bin": {"size": 524288, "crc": "BEFC47DF"}, + "s2t_10.bin": {"size": 524288, "crc": "0FBCFED0"}, + "s2t_11.bin": {"size": 524288, "crc": "68503EB0"}, + "s2t_12.bin": {"size": 524288, "crc": "5AD54783"}, + "s2t_13.bin": {"size": 524288, "crc": "E5F0E13B"}, + "s92_09.bin": {"size": 65536, "crc": "08F6B60E"}, + "s92_18.bin": {"size": 131072, "crc": "7F162009"}, + "s92_19.bin": {"size": 131072, "crc": "BEADE53F"}, + "bprg1.11d": {"size": 279, "crc": "4BFEC235"}, + "buf1": {"size": 279, "crc": "4BFEC235"}, + "c632.ic1": {"size": 279, "crc": "4BFEC235"}, + "ioa1": {"size": 279, "crc": "4BFEC235"}, + "iob1.12d": {"size": 279, "crc": "4BFEC235"}, + "prg1": {"size": 279, "crc": "4BFEC235"}, + "rom1": {"size": 279, "crc": "4BFEC235"}, + "sou1": {"size": 279, "crc": "4BFEC235"}, + "ioc1.ic7": {"size": 260, "crc": "91A9701B"} + } + } + }, + { + "game": "Super Street Fighter 2 (U)", + "system": "Arcade", + "filename": "ssf2u.zip", + "status": "playable", + "notes": [1, 3], + "verify": { + "type": "zip", + "entries": { + "ssfu.03a": {"size": 524288, "crc": "72F29C33"}, + "ssfu.04a": {"size": 524288, "crc": "935CEA44"}, + "ssfu.05": {"size": 524288, "crc": "A0ACB28A"}, + "ssfu.06": {"size": 524288, "crc": "47413DCF"}, + "ssfu.07": {"size": 524288, "crc": "E6066077"}, + "ssf.01": {"size": 131072, "crc": "71FCDFC9"}, + "ssf.13m": {"size": 2097152, "crc": "059FA4C1"}, + "ssf.14m": {"size": 1048576, "crc": "89129D74"}, + "ssf.15m": {"size": 2097152, "crc": "0BD0CB66"}, + "ssf.16m": {"size": 1048576, "crc": "5429A630"}, + "ssf.17m": {"size": 2097152, "crc": "A80D2ABF"}, + "ssf.18m": {"size": 1048576, "crc": "C603CB42"}, + "ssf.19m": {"size": 2097152, "crc": "4352A965"}, + "ssf.20m": {"size": 1048576, "crc": "43415401"}, + "ssf.q01": {"size": 524288, "crc": "A6F9DA5C"}, + "ssf.q02": {"size": 524288, "crc": "8C66AE26"}, + "ssf.q03": {"size": 524288, "crc": "695CC2CA"}, + "ssf.q04": {"size": 524288, "crc": "9D9EBE32"}, + "ssf.q05": {"size": 524288, "crc": "4770E7B7"}, + "ssf.q06": {"size": 524288, "crc": "4E79C951"}, + "ssf.q07": {"size": 524288, "crc": "CDD14313"}, + "ssf.q08": {"size": 524288, "crc": "6F5A088C"} + } + } + }, + { + "game": "Super Street Fighter 2 Turbo (U)", + "system": "Arcade", + "filename": "ssf2tu.zip", + "status": "playable", + "notes": [1, 3], + "verify": { + "type": "zip", + "entries": { + "sfxu.03e": {"size": 524288, "crc": "D6FF689E"}, + "sfxu.04a": {"size": 524288, "crc": "532B5FFD"}, + "sfxu.05": {"size": 524288, "crc": "FFA3C6DE"}, + "sfxu.06b": {"size": 524288, "crc": "83F9382B"}, + "sfxu.07a": {"size": 524288, "crc": "6AB673E8"}, + "sfxu.08": {"size": 524288, "crc": "B3C71810"}, + "sfx.09": {"size": 524288, "crc": "642FAE3F"}, + "sfx.01": {"size": 131072, "crc": "B47B8835"}, + "sfx.02": {"size": 131072, "crc": "0022633F"}, + "sfx.13m": {"size": 2097152, "crc": "059FA4C1"}, + "sfx.14m": {"size": 1048576, "crc": "89129D74"}, + "sfx.21m": {"size": 1048576, "crc": "E32854AF"}, + "sfx.15m": {"size": 2097152, "crc": "0BD0CB66"}, + "sfx.16m": {"size": 1048576, "crc": "5429A630"}, + "sfx.23m": {"size": 1048576, "crc": "760F2927"}, + "sfx.17m": {"size": 2097152, "crc": "A80D2ABF"}, + "sfx.18m": {"size": 1048576, "crc": "C603CB42"}, + "sfx.25m": {"size": 1048576, "crc": "1EE90208"}, + "sfx.19m": {"size": 2097152, "crc": "4352A965"}, + "sfx.20m": {"size": 1048576, "crc": "43415401"}, + "sfx.27m": {"size": 1048576, "crc": "F814400F"}, + "sfx.11m": {"size": 2097152, "crc": "7E4812CC"}, + "sfx.12m": {"size": 2097152, "crc": "7B010899"} + } + } + }, + { + "game": "Street Fighter 3", + "system": "Arcade", + "filename": "sfiiina.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "sfiii-simm1.0": {"size": 2097152, "crc": "CFC9E45A"}, + "sfiii-simm1.1": {"size": 2097152, "crc": "57920546"}, + "sfiii-simm1.2": {"size": 2097152, "crc": "0D8F2680"}, + "sfiii-simm1.3": {"size": 2097152, "crc": "EA4CA054"}, + "sfiii-simm3.0": {"size": 2097152, "crc": "080B3BD3"}, + "sfiii-simm3.1": {"size": 2097152, "crc": "5C356F2F"}, + "sfiii-simm3.2": {"size": 2097152, "crc": "F9C97A45"}, + "sfiii-simm3.3": {"size": 2097152, "crc": "09DE3EAD"}, + "sfiii-simm3.4": {"size": 2097152, "crc": "7DD7E1F3"}, + "sfiii-simm3.5": {"size": 2097152, "crc": "47A03A3A"}, + "sfiii-simm3.6": {"size": 2097152, "crc": "E9EB7A26"}, + "sfiii-simm3.7": {"size": 2097152, "crc": "7F44395C"}, + "sfiii-simm4.0": {"size": 2097152, "crc": "9AC080FC"}, + "sfiii-simm4.1": {"size": 2097152, "crc": "6E2C4C94"}, + "sfiii-simm4.2": {"size": 2097152, "crc": "8AFC22D4"}, + "sfiii-simm4.3": {"size": 2097152, "crc": "9F3873B8"}, + "sfiii-simm4.4": {"size": 2097152, "crc": "166B3C97"}, + "sfiii-simm4.5": {"size": 2097152, "crc": "E5EA2547"}, + "sfiii-simm4.6": {"size": 2097152, "crc": "E85B9FDD"}, + "sfiii-simm4.7": {"size": 2097152, "crc": "362C01B7"}, + "sfiii-simm5.0": {"size": 2097152, "crc": "9BC108B2"}, + "sfiii-simm5.1": {"size": 2097152, "crc": "C6F1C066"}, + "sfiii_asia_nocd.29f400.u2": {"size": 524288, "crc": "73E32463"} + } + } + }, + { + "game": "Street Fighter 3: 2nd Impact", + "system": "Arcade", + "filename": "sfiii2n.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "sfiii2-simm1.0": {"size": 2097152, "crc": "2D666F0B"}, + "sfiii2-simm1.1": {"size": 2097152, "crc": "2A3A8EF6"}, + "sfiii2-simm1.2": {"size": 2097152, "crc": "161D2206"}, + "sfiii2-simm1.3": {"size": 2097152, "crc": "87DED8A3"}, + "sfiii2-simm2.0": {"size": 2097152, "crc": "94A4CE0F"}, + "sfiii2-simm2.1": {"size": 2097152, "crc": "67585033"}, + "sfiii2-simm2.2": {"size": 2097152, "crc": "FABFFCD5"}, + "sfiii2-simm2.3": {"size": 2097152, "crc": "623C09CA"}, + "sfiii2-simm3.0": {"size": 2097152, "crc": "DAB2D766"}, + "sfiii2-simm3.1": {"size": 2097152, "crc": "1F2AA34B"}, + "sfiii2-simm3.2": {"size": 2097152, "crc": "6F1A04EB"}, + "sfiii2-simm3.3": {"size": 2097152, "crc": "E05EF205"}, + "sfiii2-simm3.4": {"size": 2097152, "crc": "AFFB074F"}, + "sfiii2-simm3.5": {"size": 2097152, "crc": "6962872E"}, + "sfiii2-simm3.6": {"size": 2097152, "crc": "6EED87DE"}, + "sfiii2-simm3.7": {"size": 2097152, "crc": "E18F479E"}, + "sfiii2-simm4.0": {"size": 2097152, "crc": "764C2503"}, + "sfiii2-simm4.1": {"size": 2097152, "crc": "3E16AF6E"}, + "sfiii2-simm4.2": {"size": 2097152, "crc": "215705E6"}, + "sfiii2-simm4.3": {"size": 2097152, "crc": "E30CBD9C"}, + "sfiii2-simm4.4": {"size": 2097152, "crc": "4185DED9"}, + "sfiii2-simm4.5": {"size": 2097152, "crc": "4E8DB013"}, + "sfiii2-simm4.6": {"size": 2097152, "crc": "08DF48CE"}, + "sfiii2-simm4.7": {"size": 2097152, "crc": "BB8F80A5"}, + "sfiii2-simm5.0": {"size": 2097152, "crc": "EBDC4787"}, + "sfiii2-simm5.1": {"size": 2097152, "crc": "6B7C550E"}, + "sfiii2-simm5.2": {"size": 2097152, "crc": "56FF8C50"}, + "sfiii2-simm5.3": {"size": 2097152, "crc": "3F2AC3E9"}, + "sfiii2-simm5.4": {"size": 2097152, "crc": "48CDA50E"}, + "sfiii2-simm5.5": {"size": 2097152, "crc": "520C0AF6"}, + "sfiii2-simm5.6": {"size": 2097152, "crc": "2EDC5986"}, + "sfiii2-simm5.7": {"size": 2097152, "crc": "93FFA199"}, + "sfiii2_asia_nocd.29f400.u2": {"size": 524288, "crc": "FD297C0D"} + } + } + }, + { + "game": "Street Fighter 3: 3rd Strike", + "system": "Arcade", + "filename": "sfiii3nr1.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "sfiii3-simm1.0": {"size": 2097152, "crc": "66E66235"}, + "sfiii3-simm1.1": {"size": 2097152, "crc": "186E8C5F"}, + "sfiii3-simm1.2": {"size": 2097152, "crc": "BCE18CAB"}, + "sfiii3-simm1.3": {"size": 2097152, "crc": "129DC2C9"}, + "sfiii3-simm2.0": {"size": 2097152, "crc": "06EB969E"}, + "sfiii3-simm2.1": {"size": 2097152, "crc": "E7039F82"}, + "sfiii3-simm2.2": {"size": 2097152, "crc": "645C96F7"}, + "sfiii3-simm2.3": {"size": 2097152, "crc": "610EFAB1"}, + "sfiii3-simm3.0": {"size": 2097152, "crc": "7BAA1F79"}, + "sfiii3-simm3.1": {"size": 2097152, "crc": "234BF8FE"}, + "sfiii3-simm3.2": {"size": 2097152, "crc": "D9EBC308"}, + "sfiii3-simm3.3": {"size": 2097152, "crc": "293CBA77"}, + "sfiii3-simm3.4": {"size": 2097152, "crc": "6055E747"}, + "sfiii3-simm3.5": {"size": 2097152, "crc": "499AA6FC"}, + "sfiii3-simm3.6": {"size": 2097152, "crc": "6C13879E"}, + "sfiii3-simm3.7": {"size": 2097152, "crc": "CF4F8EDE"}, + "sfiii3-simm4.0": {"size": 2097152, "crc": "091FD5BA"}, + "sfiii3-simm4.1": {"size": 2097152, "crc": "0BCA8917"}, + "sfiii3-simm4.2": {"size": 2097152, "crc": "A0FD578B"}, + "sfiii3-simm4.3": {"size": 2097152, "crc": "4BF8C699"}, + "sfiii3-simm4.4": {"size": 2097152, "crc": "137B8785"}, + "sfiii3-simm4.5": {"size": 2097152, "crc": "4FB70671"}, + "sfiii3-simm4.6": {"size": 2097152, "crc": "832374A4"}, + "sfiii3-simm4.7": {"size": 2097152, "crc": "1C88576D"}, + "sfiii3-simm5.0": {"size": 2097152, "crc": "C67D9190"}, + "sfiii3-simm5.1": {"size": 2097152, "crc": "6CB79868"}, + "sfiii3-simm5.2": {"size": 2097152, "crc": "DF69930E"}, + "sfiii3-simm5.3": {"size": 2097152, "crc": "333754E0"}, + "sfiii3-simm5.4": {"size": 2097152, "crc": "78F6D417"}, + "sfiii3-simm5.5": {"size": 2097152, "crc": "8CCAD9B1"}, + "sfiii3-simm5.6": {"size": 2097152, "crc": "85DE59E5"}, + "sfiii3-simm5.7": {"size": 2097152, "crc": "EE7E29B3"}, + "sfiii3-simm6.0": {"size": 2097152, "crc": "8DA69042"}, + "sfiii3-simm6.1": {"size": 2097152, "crc": "1C8C7AC4"}, + "sfiii3-simm6.2": {"size": 2097152, "crc": "A671341D"}, + "sfiii3-simm6.3": {"size": 2097152, "crc": "1A990249"}, + "sfiii3-simm6.4": {"size": 2097152, "crc": "20CB39AC"}, + "sfiii3-simm6.5": {"size": 2097152, "crc": "5F844B2F"}, + "sfiii3-simm6.6": {"size": 2097152, "crc": "450E8D28"}, + "sfiii3-simm6.7": {"size": 2097152, "crc": "CC5F4187"}, + "sfiii3_japan_nocd.29f400.u2": {"size": 524288, "crc": "1EDC6366"} + } + } + }, + { + "game": "Street Fighter 2 (JA)", + "system": "Arcade", + "filename": "sf2ja.zip", + "status": "playable", + "notes": [2, 3, 4], + "verify": { + "type": "zip", + "entries": { + "sf2j_30a.11e": {"size": 131072, "crc": "57BD7051"}, + "sf2u.37b": {"size": 131072, "crc": "1E1F6844"}, + "sf2_31a.bin": {"size": 131072, "crc": "A673143D"}, + "sf2_38a.bin": {"size": 131072, "crc": "4C2CCEF7"}, + "sf2_28a.bin": {"size": 131072, "crc": "4009955E"}, + "sf2_35a.bin": {"size": 131072, "crc": "8C1F3994"}, + "sf2_29a.bin": {"size": 131072, "crc": "BB4AF315"}, + "sf2_36a.bin": {"size": 131072, "crc": "C02A13EB"}, + "sf2_9.12a": {"size": 65536, "crc": "A4823A1B"}, + "sf2_06.bin": {"size": 524288, "crc": "22C9CC8E"}, + "sf2_08.bin": {"size": 524288, "crc": "57213BE8"}, + "sf2_05.bin": {"size": 524288, "crc": "BA529B4F"}, + "sf2_07.bin": {"size": 524288, "crc": "4B1B33A8"}, + "sf2_15.bin": {"size": 524288, "crc": "2C7E2229"}, + "sf2_17.bin": {"size": 524288, "crc": "B5548F17"}, + "sf2_14.bin": {"size": 524288, "crc": "14B84312"}, + "sf2_16.bin": {"size": 524288, "crc": "5E9CD89A"}, + "sf2_25.bin": {"size": 524288, "crc": "00F1835D"}, + "sf2_27.bin": {"size": 524288, "crc": "C1B85E35"}, + "sf2_24.bin": {"size": 524288, "crc": "4D872721"}, + "sf2_26.bin": {"size": 524288, "crc": "0EFB4EFC"}, + "sf2_18.11c": {"size": 131072, "crc": "7F162009"}, + "sf2_19.12c": {"size": 131072, "crc": "BEADE53F"}, + "buf1": {"size": 279, "crc": "4BFEC235"}, + "c632.ic1": {"size": 279, "crc": "4BFEC235"}, + "ioa1": {"size": 279, "crc": "4BFEC235"}, + "iob1.11d": {"size": 279, "crc": "4BFEC235"}, + "prg1": {"size": 279, "crc": "4BFEC235"}, + "rom1": {"size": 279, "crc": "4BFEC235"}, + "sou1": {"size": 279, "crc": "4BFEC235"}, + "stf29.1a": {"size": 279, "crc": "4BFEC235"} + } + } + }, + { + "game": "Street Fighter 2 (JL)", + "system": "Arcade", + "filename": "N/A", + "status": "no-rom", + "notes": [2, 3, 4, 5] + }, + { + "game": "Street Fighter 2 Championship Edition (JB)", + "system": "Arcade", + "filename": "sf2cej.zip", + "status": "playable", + "notes": [2, 3, 4], + "verify": { + "type": "zip", + "entries": { + "s92j_23b.bin": {"size": 524288, "crc": "140876C5"}, + "s92j_22b.bin": {"size": 524288, "crc": "2FBB3BFE"}, + "s92_21a.bin": {"size": 524288, "crc": "925A7877"}, + "s92_09.bin": {"size": 65536, "crc": "08F6B60E"}, + "s92_01.bin": {"size": 524288, "crc": "03B0D852"}, + "s92_02.bin": {"size": 524288, "crc": "840289EC"}, + "s92_03.bin": {"size": 524288, "crc": "CDB5F027"}, + "s92_04.bin": {"size": 524288, "crc": "E2799472"}, + "s92_05.bin": {"size": 524288, "crc": "BA8A2761"}, + "s92_06.bin": {"size": 524288, "crc": "E584BFB5"}, + "s92_07.bin": {"size": 524288, "crc": "21E3F87D"}, + "s92_08.bin": {"size": 524288, "crc": "BEFC47DF"}, + "s92_10.bin": {"size": 524288, "crc": "0FBCFED0"}, + "s92_11.bin": {"size": 524288, "crc": "68503EB0"}, + "s92_12.bin": {"size": 524288, "crc": "5AD54783"}, + "s92_13.bin": {"size": 524288, "crc": "E5F0E13B"}, + "s92_18.bin": {"size": 131072, "crc": "7F162009"}, + "s92_19.bin": {"size": 131072, "crc": "BEADE53F"}, + "bprg1.11d": {"size": 279, "crc": "4BFEC235"}, + "buf1": {"size": 279, "crc": "4BFEC235"}, + "c632.ic1": {"size": 279, "crc": "4BFEC235"}, + "ioa1": {"size": 279, "crc": "4BFEC235"}, + "iob1.12d": {"size": 279, "crc": "4BFEC235"}, + "prg1": {"size": 279, "crc": "4BFEC235"}, + "rom1": {"size": 279, "crc": "4BFEC235"}, + "sou1": {"size": 279, "crc": "4BFEC235"}, + "ioc1.ic7": {"size": 260, "crc": "91A9701B"} + } + } + }, + { + "game": "Street Fighter 2 Championship Edition (JC)", + "system": "Arcade", + "filename": "N/A", + "status": "no-rom", + "notes": [2, 3, 4, 5] + }, + { + "game": "Street Fighter 2 Hyper Fighting (J)", + "system": "Arcade", + "filename": "sf2tj.zip", + "status": "playable", + "notes": [2, 3, 4], + "verify": { + "type": "zip", + "entries": { + "s2tj_23.bin": {"size": 524288, "crc": "EA73B4DC"}, + "sft_22.bin": {"size": 524288, "crc": "AEA6E035"}, + "sft_21.bin": {"size": 524288, "crc": "FD200288"}, + "s92_01.bin": {"size": 524288, "crc": "03B0D852"}, + "s92_02.bin": {"size": 524288, "crc": "840289EC"}, + "s92_03.bin": {"size": 524288, "crc": "CDB5F027"}, + "s92_04.bin": {"size": 524288, "crc": "E2799472"}, + "s92_05.bin": {"size": 524288, "crc": "BA8A2761"}, + "s92_06.bin": {"size": 524288, "crc": "E584BFB5"}, + "s92_07.bin": {"size": 524288, "crc": "21E3F87D"}, + "s92_08.bin": {"size": 524288, "crc": "BEFC47DF"}, + "s2t_10.bin": {"size": 524288, "crc": "A5BE5F83"}, + "s2t_11.bin": {"size": 524288, "crc": "74A0822B"}, + "s2t_12.bin": {"size": 524288, "crc": "A5055505"}, + "s2t_13.bin": {"size": 524288, "crc": "8CF7B369"}, + "s92_09.bin": {"size": 65536, "crc": "08F6B60E"}, + "s92_18.bin": {"size": 131072, "crc": "7F162009"}, + "s92_19.bin": {"size": 131072, "crc": "BEADE53F"}, + "bprg1.11d": {"size": 279, "crc": "4BFEC235"}, + "buf1": {"size": 279, "crc": "4BFEC235"}, + "c632.ic1": {"size": 279, "crc": "4BFEC235"}, + "ioa1": {"size": 279, "crc": "4BFEC235"}, + "iob1.12d": {"size": 279, "crc": "4BFEC235"}, + "prg1": {"size": 279, "crc": "4BFEC235"}, + "rom1": {"size": 279, "crc": "4BFEC235"}, + "sou1": {"size": 279, "crc": "4BFEC235"}, + "ioc1.ic7": {"size": 260, "crc": "91A9701B"} + } + } + }, + { + "game": "Street Fighter Alpha (U)", + "system": "Arcade", + "filename": "sfau.zip", + "status": "playable", + "notes": [1], + "verify": { + "type": "zip", + "entries": { + "sfz.14m": {"size": 2097152, "crc": "90FEFDB3"}, + "sfz.16m": {"size": 2097152, "crc": "5354C948"}, + "sfz.18m": {"size": 2097152, "crc": "41A1E790"}, + "sfz.20m": {"size": 2097152, "crc": "A549DF98"}, + "sfz.01": {"size": 131072, "crc": "FFFFEC7D"}, + "sfz.02": {"size": 131072, "crc": "45F46A08"}, + "sfz.11m": {"size": 2097152, "crc": "C4B093CD"}, + "sfz.12m": {"size": 2097152, "crc": "8BDBC4B4"}, + "sfzu.03a": {"size": 524288, "crc": "49FC7DB9"}, + "sfz.04a": {"size": 524288, "crc": "5F99E9A5"}, + "sfz.05a": {"size": 524288, "crc": "0810544D"}, + "sfz.06": {"size": 524288, "crc": "806E8F38"} + } + } + }, + { + "game": "Street Fighter Alpha (J)", + "system": "Arcade", + "filename": "sfzj.zip", + "status": "playable", + "notes": [1, 4], + "verify": { + "type": "zip", + "entries": { + "sfzj.03c": {"size": 524288, "crc": "F5444120"}, + "sfz.04b": {"size": 524288, "crc": "8B73B0E5"}, + "sfz.05a": {"size": 524288, "crc": "0810544D"}, + "sfz.06": {"size": 524288, "crc": "806E8F38"}, + "sfz.14m": {"size": 2097152, "crc": "90FEFDB3"}, + "sfz.16m": {"size": 2097152, "crc": "5354C948"}, + "sfz.18m": {"size": 2097152, "crc": "41A1E790"}, + "sfz.20m": {"size": 2097152, "crc": "A549DF98"}, + "sfz.01": {"size": 131072, "crc": "FFFFEC7D"}, + "sfz.02": {"size": 131072, "crc": "45F46A08"}, + "sfz.11m": {"size": 2097152, "crc": "C4B093CD"}, + "sfz.12m": {"size": 2097152, "crc": "8BDBC4B4"} + } + } + }, + { + "game": "Street Fighter Alpha (JR2)", + "system": "Arcade", + "filename": "sfzjr2.zip", + "status": "playable", + "notes": [1, 4], + "verify": { + "type": "zip", + "entries": { + "sfzj.03b": {"size": 524288, "crc": "3CFCE93C"}, + "sfz.04a": {"size": 524288, "crc": "0C436D30"}, + "sfz.05a": {"size": 524288, "crc": "1F363612"}, + "sfz.06": {"size": 524288, "crc": "806E8F38"}, + "sfz.14m": {"size": 2097152, "crc": "90FEFDB3"}, + "sfz.16m": {"size": 2097152, "crc": "5354C948"}, + "sfz.18m": {"size": 2097152, "crc": "41A1E790"}, + "sfz.20m": {"size": 2097152, "crc": "A549DF98"}, + "sfz.01": {"size": 131072, "crc": "FFFFEC7D"}, + "sfz.02": {"size": 131072, "crc": "45F46A08"}, + "sfz.11m": {"size": 2097152, "crc": "C4B093CD"}, + "sfz.12m": {"size": 2097152, "crc": "8BDBC4B4"} + } + } + }, + { + "game": "Street Fighter Alpha 2 (U)", + "system": "Arcade", + "filename": "sfa2u.zip", + "status": "playable", + "notes": [1, 3], + "verify": { + "type": "zip", + "entries": { + "sz2u.03": {"size": 524288, "crc": "84A09006"}, + "sz2u.04": {"size": 524288, "crc": "AC46E5ED"}, + "sz2u.05": {"size": 524288, "crc": "6C0C79D3"}, + "sz2u.06": {"size": 524288, "crc": "C5C8EB63"}, + "sz2u.07": {"size": 524288, "crc": "5DE01CC5"}, + "sz2u.08": {"size": 524288, "crc": "BEA11D56"}, + "sz2.13m": {"size": 4194304, "crc": "C1B32915"}, + "sz2.14m": {"size": 1048576, "crc": "0560C6AA"}, + "sz2.15m": {"size": 4194304, "crc": "0B17985B"}, + "sz2.16m": {"size": 1048576, "crc": "AE940F87"}, + "sz2.17m": {"size": 4194304, "crc": "12ADEEF9"}, + "sz2.18m": {"size": 1048576, "crc": "4BC3C8BC"}, + "sz2.19m": {"size": 4194304, "crc": "03F03CE5"}, + "sz2.20m": {"size": 1048576, "crc": "39E674C0"}, + "sz2.01a": {"size": 131072, "crc": "1BC323CF"}, + "sz2.02a": {"size": 131072, "crc": "BA6A5013"}, + "sz2.11m": {"size": 2097152, "crc": "AA47A601"}, + "sz2.12m": {"size": 2097152, "crc": "2237BC53"} + } + } + }, + { + "game": "Street Fighter Alpha 2 (J)", + "system": "Arcade", + "filename": "sfz2j.zip", + "status": "playable", + "notes": [1, 3, 4], + "verify": { + "type": "zip", + "entries": { + "sz2j.03a": {"size": 524288, "crc": "3E1E2E85"}, + "sz2j.04a": {"size": 524288, "crc": "F53D6C45"}, + "sz2.05a": {"size": 524288, "crc": "DD224156"}, + "sz2.06": {"size": 524288, "crc": "A45A75A6"}, + "sz2j.07a": {"size": 524288, "crc": "6352F038"}, + "sz2.08": {"size": 524288, "crc": "92B66E01"}, + "sz2.13m": {"size": 4194304, "crc": "C1B32915"}, + "sz2.14m": {"size": 1048576, "crc": "0560C6AA"}, + "sz2.15m": {"size": 4194304, "crc": "0B17985B"}, + "sz2.16m": {"size": 1048576, "crc": "AE940F87"}, + "sz2.17m": {"size": 4194304, "crc": "12ADEEF9"}, + "sz2.18m": {"size": 1048576, "crc": "4BC3C8BC"}, + "sz2.19m": {"size": 4194304, "crc": "03F03CE5"}, + "sz2.20m": {"size": 1048576, "crc": "39E674C0"}, + "sz2.01a": {"size": 131072, "crc": "1BC323CF"}, + "sz2.02a": {"size": 131072, "crc": "BA6A5013"}, + "sz2.11m": {"size": 2097152, "crc": "AA47A601"}, + "sz2.12m": {"size": 2097152, "crc": "2237BC53"} + } + } + }, + { + "game": "Street Fighter Alpha 2 (JR1)", + "system": "Arcade", + "filename": "N/A", + "status": "no-rom", + "notes": [1, 3, 4, 5] + }, + { + "game": "Street Fighter Alpha 3 (J)", + "system": "Arcade", + "filename": "sfz3j.zip", + "status": "playable", + "notes": [1, 4], + "verify": { + "type": "zip", + "entries": { + "sz3j.03c": {"size": 524288, "crc": "CADF4A51"}, + "sz3j.04c": {"size": 524288, "crc": "FCB31228"}, + "sz3.05c": {"size": 524288, "crc": "57FD0A40"}, + "sz3.06c": {"size": 524288, "crc": "F6305F8B"}, + "sz3.07c": {"size": 524288, "crc": "6EAB0F6F"}, + "sz3.08c": {"size": 524288, "crc": "910C4A3B"}, + "sz3.09c": {"size": 524288, "crc": "B29E5199"}, + "sz3.10b": {"size": 524288, "crc": "DEB2FF52"}, + "sz3.13m": {"size": 4194304, "crc": "58666062"}, + "sz3.14m": {"size": 4194304, "crc": "AE296D65"}, + "sz3.15m": {"size": 4194304, "crc": "B9BFDE30"}, + "sz3.16m": {"size": 4194304, "crc": "6E267EAE"}, + "sz3.17m": {"size": 4194304, "crc": "D37CCDDD"}, + "sz3.18m": {"size": 4194304, "crc": "78B39BFE"}, + "sz3.19m": {"size": 4194304, "crc": "1B6C1A4F"}, + "sz3.20m": {"size": 4194304, "crc": "4EE48C9F"}, + "sz3.01": {"size": 131072, "crc": "DE810084"}, + "sz3.02": {"size": 131072, "crc": "72445DC4"}, + "sz3.11m": {"size": 4194304, "crc": "1C89EED1"}, + "sz3.12m": {"size": 4194304, "crc": "F392B13A"} + } + } + }, + { + "game": "Street Fighter Alpha 3 (JR2)", + "system": "Arcade", + "filename": "sfz3jr2.zip", + "status": "playable", + "notes": [1, 4], + "verify": { + "type": "zip", + "entries": { + "sz3j.03": {"size": 524288, "crc": "F7CB4B13"}, + "sz3j.04": {"size": 524288, "crc": "0846C29D"}, + "sz3.05": {"size": 524288, "crc": "9B21518A"}, + "sz3.06": {"size": 524288, "crc": "E7A6C3A7"}, + "sz3.07": {"size": 524288, "crc": "EC4C0CFD"}, + "sz3.08": {"size": 524288, "crc": "5C7E7240"}, + "sz3.09": {"size": 524288, "crc": "C5589553"}, + "sz3.10": {"size": 524288, "crc": "A9717252"}, + "sz3.13m": {"size": 4194304, "crc": "58666062"}, + "sz3.14m": {"size": 4194304, "crc": "AE296D65"}, + "sz3.15m": {"size": 4194304, "crc": "B9BFDE30"}, + "sz3.16m": {"size": 4194304, "crc": "6E267EAE"}, + "sz3.17m": {"size": 4194304, "crc": "D37CCDDD"}, + "sz3.18m": {"size": 4194304, "crc": "78B39BFE"}, + "sz3.19m": {"size": 4194304, "crc": "1B6C1A4F"}, + "sz3.20m": {"size": 4194304, "crc": "4EE48C9F"}, + "sz3.01": {"size": 131072, "crc": "DE810084"}, + "sz3.02": {"size": 131072, "crc": "72445DC4"}, + "sz3.11m": {"size": 4194304, "crc": "1C89EED1"}, + "sz3.12m": {"size": 4194304, "crc": "F392B13A"} + } + } + }, + { + "game": "Street Fighter Alpha 3 (U)", + "system": "Arcade", + "filename": "sfa3u.zip", + "status": "playable", + "notes": [1], + "verify": { + "type": "zip", + "entries": { + "sz3u.03c": {"size": 524288, "crc": "E007DA2E"}, + "sz3u.04c": {"size": 524288, "crc": "5F78F0E7"}, + "sz3.05c": {"size": 524288, "crc": "57FD0A40"}, + "sz3.06c": {"size": 524288, "crc": "F6305F8B"}, + "sz3.07c": {"size": 524288, "crc": "6EAB0F6F"}, + "sz3.08c": {"size": 524288, "crc": "910C4A3B"}, + "sz3.09c": {"size": 524288, "crc": "B29E5199"}, + "sz3.10b": {"size": 524288, "crc": "DEB2FF52"}, + "sz3.13m": {"size": 4194304, "crc": "58666062"}, + "sz3.14m": {"size": 4194304, "crc": "AE296D65"}, + "sz3.15m": {"size": 4194304, "crc": "B9BFDE30"}, + "sz3.16m": {"size": 4194304, "crc": "6E267EAE"}, + "sz3.17m": {"size": 4194304, "crc": "D37CCDDD"}, + "sz3.18m": {"size": 4194304, "crc": "78B39BFE"}, + "sz3.19m": {"size": 4194304, "crc": "1B6C1A4F"}, + "sz3.20m": {"size": 4194304, "crc": "4EE48C9F"}, + "sz3.01": {"size": 131072, "crc": "DE810084"}, + "sz3.02": {"size": 131072, "crc": "72445DC4"}, + "sz3.11m": {"size": 4194304, "crc": "1C89EED1"}, + "sz3.12m": {"size": 4194304, "crc": "F392B13A"} + } + } + }, + { + "game": "Super Street Fighter 2 (J)", + "system": "Arcade", + "filename": "ssf2j.zip", + "status": "playable", + "notes": [1, 3, 4], + "verify": { + "type": "zip", + "entries": { + "ssfj.03b": {"size": 524288, "crc": "5C2E356D"}, + "ssfj.04a": {"size": 524288, "crc": "013BD55C"}, + "ssfj.05": {"size": 524288, "crc": "0918D19A"}, + "ssfj.06b": {"size": 524288, "crc": "014E0C6D"}, + "ssfj.07": {"size": 524288, "crc": "EB6A9B1B"}, + "ssf.01": {"size": 131072, "crc": "71FCDFC9"}, + "ssf.13m": {"size": 2097152, "crc": "059FA4C1"}, + "ssf.14m": {"size": 1048576, "crc": "89129D74"}, + "ssf.15m": {"size": 2097152, "crc": "0BD0CB66"}, + "ssf.16m": {"size": 1048576, "crc": "5429A630"}, + "ssf.17m": {"size": 2097152, "crc": "A80D2ABF"}, + "ssf.18m": {"size": 1048576, "crc": "C603CB42"}, + "ssf.19m": {"size": 2097152, "crc": "4352A965"}, + "ssf.20m": {"size": 1048576, "crc": "43415401"}, + "ssf.q01": {"size": 524288, "crc": "A6F9DA5C"}, + "ssf.q02": {"size": 524288, "crc": "8C66AE26"}, + "ssf.q03": {"size": 524288, "crc": "695CC2CA"}, + "ssf.q04": {"size": 524288, "crc": "9D9EBE32"}, + "ssf.q05": {"size": 524288, "crc": "4770E7B7"}, + "ssf.q06": {"size": 524288, "crc": "4E79C951"}, + "ssf.q07": {"size": 524288, "crc": "CDD14313"}, + "ssf.q08": {"size": 524288, "crc": "6F5A088C"} + } + } + }, + { + "game": "Super Street Fighter 2 (JR1)", + "system": "Arcade", + "filename": "ssf2jr1.zip", + "status": "playable", + "notes": [1, 3, 4], + "verify": { + "type": "zip", + "entries": { + "ssfj.03a": {"size": 524288, "crc": "0BBF1304"}, + "ssfj.04a": {"size": 524288, "crc": "013BD55C"}, + "ssfj.05": {"size": 524288, "crc": "0918D19A"}, + "ssfj.06": {"size": 524288, "crc": "D808A6CD"}, + "ssfj.07": {"size": 524288, "crc": "EB6A9B1B"}, + "ssf.01": {"size": 131072, "crc": "71FCDFC9"}, + "ssf.13m": {"size": 2097152, "crc": "059FA4C1"}, + "ssf.14m": {"size": 1048576, "crc": "89129D74"}, + "ssf.15m": {"size": 2097152, "crc": "0BD0CB66"}, + "ssf.16m": {"size": 1048576, "crc": "5429A630"}, + "ssf.17m": {"size": 2097152, "crc": "A80D2ABF"}, + "ssf.18m": {"size": 1048576, "crc": "C603CB42"}, + "ssf.19m": {"size": 2097152, "crc": "4352A965"}, + "ssf.20m": {"size": 1048576, "crc": "43415401"}, + "ssf.q01": {"size": 524288, "crc": "A6F9DA5C"}, + "ssf.q02": {"size": 524288, "crc": "8C66AE26"}, + "ssf.q03": {"size": 524288, "crc": "695CC2CA"}, + "ssf.q04": {"size": 524288, "crc": "9D9EBE32"}, + "ssf.q05": {"size": 524288, "crc": "4770E7B7"}, + "ssf.q06": {"size": 524288, "crc": "4E79C951"}, + "ssf.q07": {"size": 524288, "crc": "CDD14313"}, + "ssf.q08": {"size": 524288, "crc": "6F5A088C"} + } + } + }, + { + "game": "Super Street Fighter 2 (JR1)", + "system": "Arcade", + "filename": "ssf2u.zip", + "status": "playable", + "notes": [1, 3, 4], + "verify": { + "type": "zip", + "entries": { + "ssfu.03a": {"size": 524288, "crc": "72F29C33"}, + "ssfu.04a": {"size": 524288, "crc": "935CEA44"}, + "ssfu.05": {"size": 524288, "crc": "A0ACB28A"}, + "ssfu.06": {"size": 524288, "crc": "47413DCF"}, + "ssfu.07": {"size": 524288, "crc": "E6066077"}, + "ssf.01": {"size": 131072, "crc": "71FCDFC9"}, + "ssf.13m": {"size": 2097152, "crc": "059FA4C1"}, + "ssf.14m": {"size": 1048576, "crc": "89129D74"}, + "ssf.15m": {"size": 2097152, "crc": "0BD0CB66"}, + "ssf.16m": {"size": 1048576, "crc": "5429A630"}, + "ssf.17m": {"size": 2097152, "crc": "A80D2ABF"}, + "ssf.18m": {"size": 1048576, "crc": "C603CB42"}, + "ssf.19m": {"size": 2097152, "crc": "4352A965"}, + "ssf.20m": {"size": 1048576, "crc": "43415401"}, + "ssf.q01": {"size": 524288, "crc": "A6F9DA5C"}, + "ssf.q02": {"size": 524288, "crc": "8C66AE26"}, + "ssf.q03": {"size": 524288, "crc": "695CC2CA"}, + "ssf.q04": {"size": 524288, "crc": "9D9EBE32"}, + "ssf.q05": {"size": 524288, "crc": "4770E7B7"}, + "ssf.q06": {"size": 524288, "crc": "4E79C951"}, + "ssf.q07": {"size": 524288, "crc": "CDD14313"}, + "ssf.q08": {"size": 524288, "crc": "6F5A088C"} + } + } + }, + { + "game": "Super Street Fighter 2 Turbo (J)", + "system": "Arcade", + "filename": "ssf2xj.zip", + "status": "playable", + "notes": [1, 3, 4], + "verify": { + "type": "zip", + "entries": { + "sfxj.03c": {"size": 524288, "crc": "50B52B37"}, + "sfxj.04a": {"size": 524288, "crc": "AF7767B4"}, + "sfxj.05": {"size": 524288, "crc": "F4FF18F5"}, + "sfxj.06a": {"size": 524288, "crc": "413477C2"}, + "sfxj.07": {"size": 524288, "crc": "A18B3D83"}, + "sfxj.08": {"size": 524288, "crc": "2DE76F10"}, + "sfx.09": {"size": 524288, "crc": "642FAE3F"}, + "sfx.01": {"size": 131072, "crc": "B47B8835"}, + "sfx.02": {"size": 131072, "crc": "0022633F"}, + "sfx.13m": {"size": 2097152, "crc": "059FA4C1"}, + "sfx.14m": {"size": 1048576, "crc": "89129D74"}, + "sfx.21m": {"size": 1048576, "crc": "E32854AF"}, + "sfx.15m": {"size": 2097152, "crc": "0BD0CB66"}, + "sfx.16m": {"size": 1048576, "crc": "5429A630"}, + "sfx.23m": {"size": 1048576, "crc": "760F2927"}, + "sfx.17m": {"size": 2097152, "crc": "A80D2ABF"}, + "sfx.18m": {"size": 1048576, "crc": "C603CB42"}, + "sfx.25m": {"size": 1048576, "crc": "1EE90208"}, + "sfx.19m": {"size": 2097152, "crc": "4352A965"}, + "sfx.20m": {"size": 1048576, "crc": "43415401"}, + "sfx.27m": {"size": 1048576, "crc": "F814400F"}, + "sfx.11m": {"size": 2097152, "crc": "7E4812CC"}, + "sfx.12m": {"size": 2097152, "crc": "7B010899"} + } + } + }, + { + "game": "Super Street Fighter 2 Turbo (J)", + "system": "Arcade", + "filename": "ssf2tu.zip", + "status": "playable", + "notes": [1, 3, 4], + "verify": { + "type": "zip", + "entries": { + "sfxu.03e": {"size": 524288, "crc": "D6FF689E"}, + "sfxu.04a": {"size": 524288, "crc": "532B5FFD"}, + "sfxu.05": {"size": 524288, "crc": "FFA3C6DE"}, + "sfxu.06b": {"size": 524288, "crc": "83F9382B"}, + "sfxu.07a": {"size": 524288, "crc": "6AB673E8"}, + "sfxu.08": {"size": 524288, "crc": "B3C71810"}, + "sfx.09": {"size": 524288, "crc": "642FAE3F"}, + "sfx.01": {"size": 131072, "crc": "B47B8835"}, + "sfx.02": {"size": 131072, "crc": "0022633F"}, + "sfx.13m": {"size": 2097152, "crc": "059FA4C1"}, + "sfx.14m": {"size": 1048576, "crc": "89129D74"}, + "sfx.21m": {"size": 1048576, "crc": "E32854AF"}, + "sfx.15m": {"size": 2097152, "crc": "0BD0CB66"}, + "sfx.16m": {"size": 1048576, "crc": "5429A630"}, + "sfx.23m": {"size": 1048576, "crc": "760F2927"}, + "sfx.17m": {"size": 2097152, "crc": "A80D2ABF"}, + "sfx.18m": {"size": 1048576, "crc": "C603CB42"}, + "sfx.25m": {"size": 1048576, "crc": "1EE90208"}, + "sfx.19m": {"size": 2097152, "crc": "4352A965"}, + "sfx.20m": {"size": 1048576, "crc": "43415401"}, + "sfx.27m": {"size": 1048576, "crc": "F814400F"}, + "sfx.11m": {"size": 2097152, "crc": "7E4812CC"}, + "sfx.12m": {"size": 2097152, "crc": "7B010899"} + } + } + }, + { + "game": "Super Street Fighter 2 Turbo (JR1)", + "system": "Arcade", + "filename": "N/A", + "status": "no-rom", + "notes": [1, 3, 4, 5] + } + ], + "notes": { + "1": "These ROMs require an older version MAME. They test fine in MAME 0.139 (Mame 2010 in RetroArch). This is typically due to a missing decryption key, dl-1425.bin qsound rom, or other ROM files that the older MAME did not strictly require.", + "2": "These ROMs require an older version MAME. They test fine in MAME 0.78 (Mame 2003 in RetroArch). This is typically due to a missing decryption key, dl-1425.bin qsound rom, or other ROM files that the older MAME did not strictly require.", + "3": "These are using an older naming convention to allow recognition by the targeted MAME version.", + "4": "These ROMs are only present if your Street Fighter 30th Anniversary Collection says it is 'International'.", + "5": "This ROM is not extracted as no known emulators can play it as is due to the missing key and being a newer post-MAME2010 split." + } + } +} \ No newline at end of file diff --git a/src/gex/lib/tasks/impl/snk40/__init__.py b/src/gex/lib/tasks/impl/snk40/__init__.py index d628850..4a19622 100644 --- a/src/gex/lib/tasks/impl/snk40/__init__.py +++ b/src/gex/lib/tasks/impl/snk40/__init__.py @@ -5,7 +5,7 @@ from gex.lib.contrib.bputil import BPListReader from gex.lib.tasks.basetask import BaseTask from gex.lib.tasks import helpers -from gex.lib.tasks.impl.snk40 import partials, nes, arcadedlc, arcademain, arcadepatch +from gex.lib.tasks.impl.snk40 import nes, arcadedlc, arcademain, arcadepatch logger = logging.getLogger('gextoolbox') @@ -30,31 +30,23 @@ class SNK40thAnniversaryCollectionTask(BaseTask): "description": "Include the NES ports that are included in SNK 40th", "default": True, "type": "Boolean" - }, - "include-partials": { - "description": "Include the partial ROMs that are missing data; useful for mixing with other sources or investigation", - "default": False, - "type": "Boolean" } } - _out_file_list = [] - _out_file_list.extend(arcadedlc.out_file_info) - _out_file_list.extend(arcademain.out_file_info) - _out_file_list.extend(arcadepatch.out_file_info) - _out_file_list.extend(nes.out_file_info) - _out_file_list.extend(partials.out_file_info) - - _out_file_notes = { - "1": "This is not extracted as there are missing files, such as Missing PROMs. Add '--prop include-partials=True' to include these.", - "2": "This is playable, but is a bad dump, 1+ files with a bad CRC, and/or 1+ files with empty placeholders.", - "3": "This requires MAME 0.139 to play.", - "4": "There are some variants that MAME does not have info on - this partial contains all the Bermuda Triangle/World Wars files for research." - } + def get_out_file_info(self): + '''Return a list of output files''' + return { + "files": self._metadata['out']['files'], + "notes": self._metadata['out']['notes'] + } def execute(self, in_dir, out_dir): - - bundle_contents = self._read_all_bundles(in_dir) + bundle_contents = {} + for file_ref, file_metadata in self._metadata['in']['files'].items(): + resolved_file = self.read_datafile(in_dir, file_metadata) + reader = BPListReader(resolved_file['contents']) + parsed = reader.parse() + bundle_contents[file_ref] = parsed out_files = [] @@ -64,40 +56,14 @@ def execute(self, in_dir, out_dir): out_files.extend(arcademain.extract(bundle_contents)) out_files.extend(arcadedlc.extract(bundle_contents)) out_files.extend(arcadepatch.extract(bundle_contents)) - if self._props.get('include-partials'): - out_files.extend(partials.extract(bundle_contents)) if out_files: for out_file_entry in out_files: - out_path = os.path.join(out_dir, out_file_entry['filename']) + filename = out_file_entry['filename'] + _ = self.verify_out_file(filename, out_file_entry ['contents']) + out_path = os.path.join(out_dir, filename) with open(out_path, "wb") as out_file: - logger.info(f"Writing {out_file_entry['filename']}...") + logger.info(f"Writing {filename}...") out_file.write(out_file_entry['contents']) logger.info("Processing complete.") - - _pkg_name_map = { - 'bundleMain.mbundle': 'main', - 'bundleDLC1.mbundle': 'dlc', - 'bundlePatch1.mbundle': 'patch' - } - - def _read_all_bundles(self, in_dir): - bundle_contents = {} - bundle_files = self._find_files(in_dir) - for file_path in bundle_files: - with open(file_path, 'rb') as in_file: - file_name = os.path.basename(file_path) - pkg_name = self._pkg_name_map.get(file_name) - if pkg_name is not None: - logger.info(f'Reading files for {file_name}...') - contents = in_file.read() - reader = BPListReader(contents) - parsed = reader.parse() - bundle_contents[pkg_name] = parsed - return bundle_contents - - def _find_files(self, base_path): - bundle_path = os.path.join(base_path, "Bundle", '*.mbundle') - archive_list = glob.glob(bundle_path) - return archive_list diff --git a/src/gex/lib/tasks/impl/snk40/arcadedlc.py b/src/gex/lib/tasks/impl/snk40/arcadedlc.py index e17fa4e..a82055c 100644 --- a/src/gex/lib/tasks/impl/snk40/arcadedlc.py +++ b/src/gex/lib/tasks/impl/snk40/arcadedlc.py @@ -6,51 +6,6 @@ logger = logging.getLogger('gextoolbox') -out_file_info = [ - { - "game": "Beast Busters", - "system": "Arcade", - "filename": "bbusters.zip", - 'status': 'good', - "notes": [3] - }, - { - "game": "Beast Busters", - "system": "Arcade", - "filename": "bbustersj.zip", - 'status': 'good', - "notes": [3] - }, - { - "game": "Beast Busters", - "system": "Arcade", - "filename": "bbustersu.zip", - 'status': 'good', - "notes": [3] - }, - { - "game": "Search and Rescue", - "system": "Arcade", - "filename": "searchar.zip", - 'status': 'good', - "notes": [] - }, - { - "game": "Search and Rescue", - "system": "Arcade", - "filename": "searcharj.zip", - 'status': 'good', - "notes": [] - }, - { - "game": "Search and Rescue", - "system": "Arcade", - "filename": "searcharu.zip", - 'status': 'good', - "notes": [] - } -] - def extract(bundle_contents): '''Extract files from DLC bundle''' out_files = [] diff --git a/src/gex/lib/tasks/impl/snk40/arcademain.py b/src/gex/lib/tasks/impl/snk40/arcademain.py index 47741c6..7a74748 100644 --- a/src/gex/lib/tasks/impl/snk40/arcademain.py +++ b/src/gex/lib/tasks/impl/snk40/arcademain.py @@ -6,247 +6,6 @@ logger = logging.getLogger('gextoolbox') -out_file_info = [ - { - "game": "ASO: ArmoredScrumObject", - "system": "Arcade", - "filename": "aso.zip", - 'status': 'playable', - "notes": [2] - }, - { - "game": "ASO: ArmoredScrumObject", - "system": "Arcade", - "filename": "alphamis.zip", - 'status': 'playable', - "notes": [2] - }, - { - "game": "ASO: ArmoredScrumObject", - "system": "Arcade", - "filename": "arian.zip", - 'status': 'playable', - "notes": [2] - }, - { - "game": "TNKIII", - "system": "Arcade", - "filename": "tnk3.zip", - 'status': 'good', - "notes": [] - }, - { - "game": "TNKIII (J)", - "system": "Arcade", - "filename": "tnk3j.zip", - 'status': 'good', - "notes": [] - }, - { - "game": "Athena", - "system": "Arcade", - "filename": "athena.zip", - 'status': 'good', - "notes": [] - }, - { - "game": "Prehistoric Isle", - "system": "Arcade", - "filename": "gensitou.zip", - 'status': 'good', - "notes": [] - }, - { - "game": "Prehistoric Isle", - "system": "Arcade", - "filename": "prehisle.zip", - 'status': 'good', - "notes": [] - }, - { - "game": "Prehistoric Isle", - "system": "Arcade", - "filename": "prehisleu.zip", - 'status': 'good', - "notes": [] - }, - { - "game": "Street Smart", - "system": "Arcade", - "filename": "streetsm.zip", - 'status': 'good', - "notes": [] - }, - { - "game": "Street Smart", - "system": "Arcade", - "filename": "streetsm1.zip", - 'status': 'good', - "notes": [] - }, - { - "game": "Street Smart", - "system": "Arcade", - "filename": "streetsmj.zip", - 'status': 'good', - "notes": [] - }, - { - "game": "Street Smart", - "system": "Arcade", - "filename": "streetsmw.zip", - 'status': 'good', - "notes": [] - }, - { - "game": "Ikari III: The Rescue", - "system": "Arcade", - "filename": "ikari3.zip", - 'status': 'good', - "notes": [] - }, - { - "game": "Ikari III: The Rescue", - "system": "Arcade", - "filename": "ikari3j.zip", - 'status': 'good', - "notes": [] - }, - { - "game": "Ikari III: The Rescue", - "system": "Arcade", - "filename": "ikari3k.zip", - 'status': 'good', - "notes": [] - }, - { - "game": "Ikari III: The Rescue", - "system": "Arcade", - "filename": "ikari3u.zip", - 'status': 'good', - "notes": [] - }, - { - "game": "P.O.W", - "system": "Arcade", - "filename": "pow.zip", - 'status': 'good', - "notes": [] - }, - { - "game": "P.O.W", - "system": "Arcade", - "filename": "powj.zip", - 'status': 'good', - "notes": [] - }, - { - "game": "Vanguard", - "system": "Arcade", - "filename": "vanguard.zip", - 'status': 'good', - "notes": [] - }, - { - "game": "Vanguard", - "system": "Arcade", - "filename": "vanguardc.zip", - 'status': 'good', - "notes": [] - }, - { - "game": "Vanguard", - "system": "Arcade", - "filename": "vanguardj.zip", - 'status': 'good', - "notes": [] - }, - { - "game": "Guerilla War", - "system": "Arcade", - "filename": "gwar.zip", - 'status': 'playable', - "notes": [2] - }, - { - "game": "Guerilla War (A)", - "system": "Arcade", - "filename": "gwara.zip", - 'status': 'playable', - "notes": [2] - }, - { - "game": "Guerilla War (B)", - "system": "Arcade", - "filename": "gwarb.zip", - 'status': 'playable', - "notes": [2] - }, - { - "game": "Guevara (Guerilla War (J))", - "system": "Arcade", - "filename": "gwarj.zip", - 'status': 'playable', - "notes": [2] - }, - { - "game": "Psycho Soldier", - "system": "Arcade", - "filename": "psychos.zip", - 'status': 'playable', - "notes": [2] - }, - { - "game": "Psycho Soldier (J)", - "system": "Arcade", - "filename": "psychosj.zip", - 'status': 'playable', - "notes": [2] - }, - { - "game": "Ikari I", - "system": "Arcade", - "filename": "ikari.zip", - 'status': 'playable', - "notes": [2] - }, - { - "game": "Ikari I (US Alt.)", - "system": "Arcade", - "filename": "ikaria.zip", - 'status': 'playable', - "notes": [2] - }, - { - "game": "Ikari I (J, No Continues)", - "system": "Arcade", - "filename": "ikarijp.zip", - 'status': 'playable', - "notes": [2] - }, - { - "game": "Ikari I (No Continues)", - "system": "Arcade", - "filename": "ikarinc.zip", - 'status': 'playable', - "notes": [2] - }, - { - "game": "Ikari 2 Victory Road", - "system": "Arcade", - "filename": "victroad.zip", - 'status': 'playable', - "notes": [2] - }, - { - "game": "Dogou Souken (Ikari 2 Victory Road (J))", - "system": "Arcade", - "filename": "dogosoke.zip", - 'status': 'playable', - "notes": [2] - } -] - def extract(bundle_contents): '''Extract Arcade ROMs from main bundle''' out_files = [] diff --git a/src/gex/lib/tasks/impl/snk40/arcadepatch.py b/src/gex/lib/tasks/impl/snk40/arcadepatch.py index e4d73a6..2dcb63c 100644 --- a/src/gex/lib/tasks/impl/snk40/arcadepatch.py +++ b/src/gex/lib/tasks/impl/snk40/arcadepatch.py @@ -6,107 +6,6 @@ logger = logging.getLogger('gextoolbox') -out_file_info = [ - { - "game": "Chopper I", - "system": "Arcade", - "filename": "chopperb.zip", - 'status': 'good', - "notes": [] - }, - { - "game": "Chopper I", - "system": "Arcade", - "filename": "legofair.zip", - 'status': 'good', - "notes": [3] - }, - { - "game": "Fantasy", - "system": "Arcade", - "filename": "fantasyj.zip", - 'status': 'good', - "notes": [] - }, - { - "game": "Fantasy", - "system": "Arcade", - "filename": "fantasyu.zip", - 'status': 'good', - "notes": [] - }, - { - "game": "Time Soldiers", - "system": "Arcade", - "filename": "btlfield.zip", - 'status': 'good', - "notes": [3] - }, - { - "game": "Time Soldiers", - "system": "Arcade", - "filename": "timesold.zip", - 'status': 'good', - "notes": [3] - }, - { - "game": "Munch Mobile (Joyful Road)", - "system": "Arcade", - "filename": "mnchmobl.zip", - 'status': 'good', - "notes": [] - }, - { - "game": "Munch Mobile (Joyful Road)", - "system": "Arcade", - "filename": "joyfulr.zip", - 'status': 'good', - "notes": [] - }, - { - "game": "Sasuke vs. Commander", - "system": "Arcade", - "filename": "sasuke.zip", - 'status': 'good', - "notes": [] - }, - { - "game": "Ozma Wars", - "system": "Arcade", - "filename": "ozmawars.zip", - 'status': 'playable', - "notes": [2] - }, - { - "game": "Paddle Mania", - "system": "Arcade", - "filename": "paddlema.zip", - 'status': 'playable', - "notes": [2] - }, - { - "game": "Bermuda Triangle", - "system": "Arcade", - "filename": "bermudata.zip", - 'status': 'playable', - "notes": [2] - }, - { - "game": "World Wars", - "system": "Arcade", - "filename": "worldwar.zip", - "status": "playable", - "notes": [2] - }, - { - "game": "MarvinsMaze", - "system": "Arcade", - "filename": "marvins.zip", - 'status': 'good', - "notes": [] - } -] - def extract(bundle_contents): '''Extract Arcade ROMs from patch bundle''' out_files = [] @@ -534,55 +433,83 @@ def _handle_bermuda(bundle_contents): '''Extract Bermuda Triangle / World Wars''' out_files = [] - # World Wars Common + # Bermuda Triangle Common func_map = {} - bg_filenames = [ - "ww11.1e", - "ww12.1d", - "ww13.1b", - "ww14.1a" - ] - func_map['bg'] = helpers.equal_split_helper('WorldWars.bg', bg_filenames) sp_filenames = [ - "ww10.3g", - "ww9.3e", - "ww8.3d", - "ww7.3b" + "p9.3b", + "p8.3d", + "p7.3e", + "p6.3g" ] - func_map['sp'] = helpers.equal_split_helper('WorldWars.sp', sp_filenames) + func_map['sp'] = helpers.equal_split_helper('BermudaTriangle.sp', sp_filenames) sp32_filenames = [ - "ww21.7p", - "ww22.7s", - "ww19.8h", - "ww20.8k", - "ww15.8m", - "ww16.8n", - "ww17.8p", - "ww18.8s" + "p11.7p", + "p12.7s", + "p13.8h", + "p14.8k", + "p15.8m", + "p16.8n", + "p17.8p", + "p18.8s" + ] + func_map['sp32'] = helpers.equal_split_helper('BermudaTriangle.sp32', sp32_filenames) + bg_filenames = [ + "p19.1", + "p20.1b", + "p21.1d", + "p22.1e" ] - func_map['sp32'] = helpers.equal_split_helper('WorldWars.sp32', sp32_filenames) + func_map['bg'] = helpers.equal_split_helper('BermudaTriangle.bg', bg_filenames) + pal_filenames = [ + "2.1l", + "1.1k", + "3.2l" + ] + func_map['pal'] = utils.simple_palette_helper('BermudaTriangle.pal', pal_filenames) ph_files = { - 'horizon.5h': 0x400, + 'horizon.6h': 0x400, 'vertical.7h': 0x400 } + func_map['tx'] = helpers.name_file_helper("BermudaTriangle.tx", "p10.3a") + func_map['sub'] = helpers.name_file_helper("BermudaTriangle.1.z80", "p2.8p") func_map['ph'] = helpers.placeholder_helper(ph_files) - logger.info("Processing World Wars common files...") + logger.info("Processing Bermudat Triangle common files...") common_file_map = helpers.process_rom_files(bundle_contents, func_map) - # BERMUDATA + # BERMUDAT func_map = {} - func_map['maincpu'] = helpers.name_file_helper("WorldWars.j.0.z80", "wwu4.4p") - func_map['sub'] = helpers.name_file_helper("WorldWars.j.1.z80", "wwu5.8p") - func_map['audiocpu'] = helpers.name_file_helper("WorldWars.j.2.z80", "wwu3.7k") - func_map['tx'] = helpers.name_file_helper("WorldWars.j.tx", "wwu6.3a") + func_map['maincpu'] = helpers.name_file_helper("BermudaTriangle.0.z80", "p1.4p") + func_map['audiocpu'] = helpers.name_file_helper("BermudaTriangle.2.z80", "p3.7k") + adpcm_filenames = [ + "p4.5e", + "p5.5g" + ] + func_map['adpcm'] = helpers.equal_split_helper('BermudaTriangle.adpcm', adpcm_filenames) func_map['common'] = helpers.existing_files_helper(common_file_map) - pal_filenames = [ - "u2bt.2l", - "u1bt.1k", - "u3bt.1l" + mame_name = "bermudat.zip" + logger.info(f"Building {mame_name}...") + out_files.append( + {'filename': mame_name, 'contents': helpers.build_rom(bundle_contents, func_map)} + ) + logger.info(f"Extracted {mame_name}.") + + + # BERMUDATJ + func_map = {} + func_map['maincpu'] = helpers.name_file_helper("BermudaTriangle.j.0.z80", "p1.4p") + func_map['audiocpu'] = helpers.name_file_helper("BermudaTriangle.j.2.z80", "p3.7k") + adpcm_filenames = [ + "p4.5e", + "p5.5g" ] - func_map['pal'] = utils.simple_palette_helper('WorldWars.j.pal', pal_filenames) - out_files.append(utils.build_snk_rom("bermudata.zip", bundle_contents, func_map)) + func_map['adpcm'] = helpers.equal_split_helper('BermudaTriangle.j.adpcm', adpcm_filenames) + func_map['common'] = helpers.existing_files_helper(common_file_map) + mame_name = "bermudatj.zip" + logger.info(f"Building {mame_name}...") + out_files.append( + {'filename': mame_name, 'contents': helpers.build_rom(bundle_contents, func_map)} + ) + logger.info(f"Extracted {mame_name}.") return out_files @@ -650,6 +577,21 @@ def _handle_worldwars(bundle_contents): ) logger.info(f"Extracted {mame_name}.") + # BERMUDATA - This is actually World Wars (J)! + func_map = {} + func_map['maincpu'] = helpers.name_file_helper("WorldWars.j.0.z80", "wwu4.4p") + func_map['sub'] = helpers.name_file_helper("WorldWars.j.1.z80", "wwu5.8p") + func_map['audiocpu'] = helpers.name_file_helper("WorldWars.j.2.z80", "wwu3.7k") + func_map['tx'] = helpers.name_file_helper("WorldWars.j.tx", "wwu6.3a") + func_map['common'] = helpers.existing_files_helper(common_file_map) + pal_filenames = [ + "u2bt.2l", + "u1bt.1k", + "u3bt.1l" + ] + func_map['pal'] = utils.simple_palette_helper('WorldWars.j.pal', pal_filenames) + out_files.append(utils.build_snk_rom("bermudata.zip", bundle_contents, func_map)) + return out_files def _handle_marvin(bundle_contents): diff --git a/src/gex/lib/tasks/impl/snk40/metadata.json b/src/gex/lib/tasks/impl/snk40/metadata.json new file mode 100644 index 0000000..9a64b56 --- /dev/null +++ b/src/gex/lib/tasks/impl/snk40/metadata.json @@ -0,0 +1,2063 @@ +{ + "in": { + "files": { + "dlc": { + "rel_path": ["Bundle"], + "filename": "bundleDLC1.mbundle", + "versions": { + "Steam": { + "size": 71304979, + "crc": "8EA7DC84" + } + } + }, + "main": { + "rel_path": ["Bundle"], + "filename": "bundleMain.mbundle", + "versions": { + "Steam": { + "size": 1016376903, + "crc": "16BE6EC4" + } + } + }, + "patch": { + "rel_path": ["Bundle"], + "filename": "bundlePatch1.mbundle", + "versions": { + "Steam": { + "size": 167049215, + "crc": "B6E39078" + } + } + } + } + }, + "out": { + "files": [ + { + "game": "Beast Busters", + "system": "Arcade", + "filename": "bbusters.zip", + "status": "good", + "notes": [3], + "verify": { + "type": "zip", + "entries": { + "bb-3.k10": {"size": 131072, "crc": "04DA1820"}, + "bb-5.k12": {"size": 131072, "crc": "777E0611"}, + "bb-2.k8": {"size": 131072, "crc": "20141805"}, + "bb-4.k11": {"size": 131072, "crc": "D482E0E9"}, + "bb-pcmb.l3": {"size": 524288, "crc": "C8D5DD53"}, + "bb-10.l9": {"size": 131072, "crc": "490C0D9B"}, + "bb-f11.m16": {"size": 524288, "crc": "39FDF9C0"}, + "bb-f12.m13": {"size": 524288, "crc": "69EE046B"}, + "bb-f13.m12": {"size": 524288, "crc": "F5EF840E"}, + "bb-f14.m11": {"size": 524288, "crc": "1A7DF3BB"}, + "bb-f21.l10": {"size": 524288, "crc": "530F595B"}, + "bb-f22.l12": {"size": 524288, "crc": "889C562E"}, + "bb-f23.l13": {"size": 524288, "crc": "C89FE0DA"}, + "bb-f24.l15": {"size": 524288, "crc": "E0D81359"}, + "bb-back1.m4": {"size": 524288, "crc": "B5445313"}, + "bb-back2.m6": {"size": 524288, "crc": "8BE996F6"}, + "bb-6.e7": {"size": 65536, "crc": "61F3DE03"}, + "bb-7.h7": {"size": 65536, "crc": "61F3DE03"}, + "bb-8.a14": {"size": 65536, "crc": "61F3DE03"}, + "bb-9.c14": {"size": 65536, "crc": "61F3DE03"}, + "bb-1.e6": {"size": 65536, "crc": "4360F2EE"}, + "bb-pcma.l5": {"size": 524288, "crc": "44CD5BFE"}, + "bbusters-eeprom.bin": {"size": 256, "crc": "A52EBD66"} + } + } + }, + { + "game": "Beast Busters", + "system": "Arcade", + "filename": "bbustersj.zip", + "status": "good", + "notes": [3], + "verify": { + "type": "zip", + "entries": { + "bb3_ver2_j3.k10": {"size": 131072, "crc": "6A1CD941"}, + "bb5_ver2_j3.k12": {"size": 131072, "crc": "7B180752"}, + "bb-2.k8": {"size": 131072, "crc": "20141805"}, + "bb-4.k11": {"size": 131072, "crc": "D482E0E9"}, + "bb-pcmb.l3": {"size": 524288, "crc": "C8D5DD53"}, + "bb-10.l9": {"size": 131072, "crc": "490C0D9B"}, + "bb-f11.m16": {"size": 524288, "crc": "39FDF9C0"}, + "bb-f12.m13": {"size": 524288, "crc": "69EE046B"}, + "bb-f13.m12": {"size": 524288, "crc": "F5EF840E"}, + "bb-f14.m11": {"size": 524288, "crc": "1A7DF3BB"}, + "bb-f21.l10": {"size": 524288, "crc": "530F595B"}, + "bb-f22.l12": {"size": 524288, "crc": "889C562E"}, + "bb-f23.l13": {"size": 524288, "crc": "C89FE0DA"}, + "bb-f24.l15": {"size": 524288, "crc": "E0D81359"}, + "bb-back1.m4": {"size": 524288, "crc": "B5445313"}, + "bb-back2.m6": {"size": 524288, "crc": "8BE996F6"}, + "bb-6.e7": {"size": 65536, "crc": "61F3DE03"}, + "bb-7.h7": {"size": 65536, "crc": "61F3DE03"}, + "bb-8.a14": {"size": 65536, "crc": "61F3DE03"}, + "bb-9.c14": {"size": 65536, "crc": "61F3DE03"}, + "bb-1.e6": {"size": 65536, "crc": "4360F2EE"}, + "bb-pcma.l5": {"size": 524288, "crc": "44CD5BFE"}, + "bbusters-eeprom.bin": {"size": 256, "crc": "A52EBD66"} + } + } + }, + { + "game": "Beast Busters", + "system": "Arcade", + "filename": "bbustersu.zip", + "status": "good", + "notes": [3], + "verify": { + "type": "zip", + "entries": { + "bb-ver3-u3.k10": {"size": 131072, "crc": "C80EC3BC"}, + "bb-ver3-u5.k12": {"size": 131072, "crc": "5DED86D1"}, + "bb-2.k8": {"size": 131072, "crc": "20141805"}, + "bb-4.k11": {"size": 131072, "crc": "D482E0E9"}, + "bb-10.l9": {"size": 131072, "crc": "490C0D9B"}, + "bb-f11.m16": {"size": 524288, "crc": "39FDF9C0"}, + "bb-f12.m13": {"size": 524288, "crc": "69EE046B"}, + "bb-f13.m12": {"size": 524288, "crc": "F5EF840E"}, + "bb-f14.m11": {"size": 524288, "crc": "1A7DF3BB"}, + "bb-f21.l10": {"size": 524288, "crc": "530F595B"}, + "bb-f22.l12": {"size": 524288, "crc": "889C562E"}, + "bb-f23.l13": {"size": 524288, "crc": "C89FE0DA"}, + "bb-f24.l15": {"size": 524288, "crc": "E0D81359"}, + "bb-back1.m4": {"size": 524288, "crc": "B5445313"}, + "bb-back2.m6": {"size": 524288, "crc": "8BE996F6"}, + "bb-6.e7": {"size": 65536, "crc": "61F3DE03"}, + "bb-7.h7": {"size": 65536, "crc": "61F3DE03"}, + "bb-8.a14": {"size": 65536, "crc": "61F3DE03"}, + "bb-9.c14": {"size": 65536, "crc": "61F3DE03"}, + "bb-1.e6": {"size": 65536, "crc": "4360F2EE"}, + "bb-pcma.l5": {"size": 524288, "crc": "44CD5BFE"}, + "bbusters-eeprom.bin": {"size": 256, "crc": "A52EBD66"} + } + } + }, + { + "game": "Search and Rescue", + "system": "Arcade", + "filename": "searchar.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "bhw.2": {"size": 131072, "crc": "E1430138"}, + "bhw.3": {"size": 131072, "crc": "EE1F9374"}, + "bhw.1": {"size": 131072, "crc": "62B60066"}, + "bhw.4": {"size": 131072, "crc": "16D8525C"}, + "bh.5": {"size": 65536, "crc": "53E2FA76"}, + "bh.7": {"size": 32768, "crc": "B0F1B049"}, + "bh.8": {"size": 32768, "crc": "174DDBA7"}, + "bh.c1": {"size": 524288, "crc": "1FB8F0AE"}, + "bh.c3": {"size": 524288, "crc": "FD8BC407"}, + "bh.c5": {"size": 524288, "crc": "1D30ACC3"}, + "bh.c2": {"size": 524288, "crc": "7C803767"}, + "bh.c4": {"size": 524288, "crc": "EEDE7C43"}, + "bh.c6": {"size": 524288, "crc": "9F785CD9"}, + "bh.v1": {"size": 131072, "crc": "07A6114B"} + } + } + }, + { + "game": "Search and Rescue", + "system": "Arcade", + "filename": "searcharj.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "bh2ver3j.9c": {"size": 131072, "crc": "7EF7B172"}, + "bh3ver3j.10c": {"size": 131072, "crc": "3FDEA793"}, + "bhw.1": {"size": 131072, "crc": "62B60066"}, + "bhw.4": {"size": 131072, "crc": "16D8525C"}, + "bh.5": {"size": 65536, "crc": "53E2FA76"}, + "bh.7": {"size": 32768, "crc": "B0F1B049"}, + "bh.8": {"size": 32768, "crc": "174DDBA7"}, + "bh.c1": {"size": 524288, "crc": "1FB8F0AE"}, + "bh.c3": {"size": 524288, "crc": "FD8BC407"}, + "bh.c5": {"size": 524288, "crc": "1D30ACC3"}, + "bh.c2": {"size": 524288, "crc": "7C803767"}, + "bh.c4": {"size": 524288, "crc": "EEDE7C43"}, + "bh.c6": {"size": 524288, "crc": "9F785CD9"}, + "bh.v1": {"size": 131072, "crc": "07A6114B"} + } + } + }, + { + "game": "Search and Rescue", + "system": "Arcade", + "filename": "searcharu.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "bh.2": {"size": 131072, "crc": "C852E2E2"}, + "bh.3": {"size": 131072, "crc": "BC04A4A1"}, + "bh.1": {"size": 131072, "crc": "BA9CA70B"}, + "bh.4": {"size": 131072, "crc": "EABC5DDF"}, + "bh.5": {"size": 65536, "crc": "53E2FA76"}, + "bh.7": {"size": 32768, "crc": "B0F1B049"}, + "bh.8": {"size": 32768, "crc": "174DDBA7"}, + "bh.c1": {"size": 524288, "crc": "1FB8F0AE"}, + "bh.c3": {"size": 524288, "crc": "FD8BC407"}, + "bh.c5": {"size": 524288, "crc": "1D30ACC3"}, + "bh.c2": {"size": 524288, "crc": "7C803767"}, + "bh.c4": {"size": 524288, "crc": "EEDE7C43"}, + "bh.c6": {"size": 524288, "crc": "9F785CD9"}, + "bh.v1": {"size": 131072, "crc": "07A6114B"} + } + } + }, + { + "game": "ASO: ArmoredScrumObject", + "system": "Arcade", + "filename": "aso.zip", + "status": "playable", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "p1.8d": {"size": 16384, "crc": "84981F3C"}, + "p2.7d": {"size": 16384, "crc": "CFE912A6"}, + "p3.5d": {"size": 16384, "crc": "39A666D2"}, + "p4.3d": {"size": 16384, "crc": "A4122355"}, + "p5.2d": {"size": 16384, "crc": "9879E506"}, + "p6.1d": {"size": 16384, "crc": "C0BFDF1F"}, + "p14.1h": {"size": 8192, "crc": "8BAA2253"}, + "p10.14h": {"size": 32768, "crc": "00DFF996"}, + "p7.4f": {"size": 16384, "crc": "DBC19736"}, + "p8.3f": {"size": 16384, "crc": "537726A9"}, + "p9.2f": {"size": 16384, "crc": "AEF5A4F4"}, + "p11.11h": {"size": 32768, "crc": "7FEAC86C"}, + "p12.9h": {"size": 32768, "crc": "6895990B"}, + "p13.8h": {"size": 32768, "crc": "87A81CE1"}, + "mb7122h.13f": {"size": 1024, "crc": "37E28DD8"}, + "mb7122h.12f": {"size": 1024, "crc": "5B0A0059"}, + "mb7122h.14f": {"size": 1024, "crc": "C3FD1DD3"}, + "pal16l8a-1.bin": {"size": 260, "crc": "91A9701B"}, + "pal16l8a-2.bin": {"size": 260, "crc": "91A9701B"}, + "pal16r6a.15b": {"size": 260, "crc": "91A9701B"} + } + } + }, + { + "game": "ASO: ArmoredScrumObject", + "system": "Arcade", + "filename": "alphamis.zip", + "status": "playable", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "p1.8d": {"size": 16384, "crc": "69AF874B"}, + "p2.7d": {"size": 16384, "crc": "7707BFE3"}, + "p3.5d": {"size": 16384, "crc": "B970D642"}, + "p4.3d": {"size": 16384, "crc": "91A89D3C"}, + "p5.2d": {"size": 16384, "crc": "9879E506"}, + "p6.1d": {"size": 16384, "crc": "C0BFDF1F"}, + "p14.1h": {"size": 8192, "crc": "ACBE29B2"}, + "p10.14h": {"size": 32768, "crc": "00DFF996"}, + "p7.4f": {"size": 16384, "crc": "DBC19736"}, + "p8.3f": {"size": 16384, "crc": "537726A9"}, + "p9.2f": {"size": 16384, "crc": "AEF5A4F4"}, + "p11.11h": {"size": 32768, "crc": "7FEAC86C"}, + "p12.9h": {"size": 32768, "crc": "6895990B"}, + "p13.8h": {"size": 32768, "crc": "87A81CE1"}, + "mb7122h.13f": {"size": 1024, "crc": "37E28DD8"}, + "mb7122h.12f": {"size": 1024, "crc": "5B0A0059"}, + "mb7122h.14f": {"size": 1024, "crc": "C3FD1DD3"}, + "pal16l8a-1.bin": {"size": 260, "crc": "91A9701B"}, + "pal16l8a-2.bin": {"size": 260, "crc": "91A9701B"}, + "pal16r6a.15b": {"size": 260, "crc": "91A9701B"} + } + } + }, + { + "game": "ASO: ArmoredScrumObject", + "system": "Arcade", + "filename": "arian.zip", + "status": "playable", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "p1.8d": {"size": 16384, "crc": "0CA89307"}, + "p2.7d": {"size": 16384, "crc": "724518C3"}, + "p3.5d": {"size": 16384, "crc": "4D8DB650"}, + "p4.3d": {"size": 16384, "crc": "47BAF1DB"}, + "p5.2d": {"size": 16384, "crc": "9879E506"}, + "p6.1d": {"size": 16384, "crc": "C0BFDF1F"}, + "p14.1h": {"size": 8192, "crc": "E599BD30"}, + "p10.14h": {"size": 32768, "crc": "00DFF996"}, + "p7.4f": {"size": 16384, "crc": "DBC19736"}, + "p8.3f": {"size": 16384, "crc": "537726A9"}, + "p9.2f": {"size": 16384, "crc": "AEF5A4F4"}, + "p11.11h": {"size": 32768, "crc": "7FEAC86C"}, + "p12.9h": {"size": 32768, "crc": "6895990B"}, + "p13.8h": {"size": 32768, "crc": "87A81CE1"}, + "mb7122h.13f": {"size": 1024, "crc": "37E28DD8"}, + "mb7122h.12f": {"size": 1024, "crc": "5B0A0059"}, + "mb7122h.14f": {"size": 1024, "crc": "C3FD1DD3"}, + "pal16l8a-1.bin": {"size": 260, "crc": "91A9701B"}, + "pal16l8a-2.bin": {"size": 260, "crc": "91A9701B"}, + "pal16r6a.15b": {"size": 260, "crc": "91A9701B"} + } + } + }, + { + "game": "TNKIII", + "system": "Arcade", + "filename": "tnk3.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "p1.4e": {"size": 16384, "crc": "0D2A8CA9"}, + "p2.4f": {"size": 16384, "crc": "0AE0A483"}, + "p3.4h": {"size": 16384, "crc": "D16DD4DB"}, + "p14.1e": {"size": 8192, "crc": "1FD18C43"}, + "p4.2e": {"size": 16384, "crc": "01B45A90"}, + "p5.2f": {"size": 16384, "crc": "60DB6667"}, + "p6.2h": {"size": 16384, "crc": "4761FDE7"}, + "p10.6f": {"size": 16384, "crc": "7BF0A517"}, + "p11.6d": {"size": 16384, "crc": "0569CE27"}, + "p12.3d": {"size": 16384, "crc": "FF495A16"}, + "p13.3c": {"size": 16384, "crc": "F8344843"}, + "p7.7h": {"size": 16384, "crc": "06B92C88"}, + "p8.7f": {"size": 16384, "crc": "63D0E2EB"}, + "p9.7e": {"size": 16384, "crc": "872E3FAC"}, + "1.5g": {"size": 1024, "crc": "6D0AC66A"}, + "2.5f": {"size": 1024, "crc": "34C06BC6"}, + "0.5h": {"size": 1024, "crc": "4662B4C8"} + } + } + }, + { + "game": "TNKIII (J)", + "system": "Arcade", + "filename": "tnk3j.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "p1.4e": {"size": 16384, "crc": "03ACA147"}, + "p2.4f": {"size": 16384, "crc": "0AE0A483"}, + "p3.4h": {"size": 16384, "crc": "D16DD4DB"}, + "p14.1e": {"size": 8192, "crc": "6BD575CA"}, + "p4.2e": {"size": 16384, "crc": "01B45A90"}, + "p5.2f": {"size": 16384, "crc": "60DB6667"}, + "p6.2h": {"size": 16384, "crc": "4761FDE7"}, + "p10.6f": {"size": 16384, "crc": "7BF0A517"}, + "p11.6d": {"size": 16384, "crc": "0569CE27"}, + "p12.3d": {"size": 16384, "crc": "FF495A16"}, + "p13.3c": {"size": 16384, "crc": "F8344843"}, + "p7.7h": {"size": 16384, "crc": "06B92C88"}, + "p8.7f": {"size": 16384, "crc": "63D0E2EB"}, + "p9.7e": {"size": 16384, "crc": "872E3FAC"}, + "1.5g": {"size": 1024, "crc": "6D0AC66A"}, + "2.5f": {"size": 1024, "crc": "34C06BC6"}, + "0.5h": {"size": 1024, "crc": "4662B4C8"} + } + } + }, + { + "game": "Athena", + "system": "Arcade", + "filename": "athena.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "p3.8p": {"size": 16384, "crc": "DF50AF7E"}, + "p4.8m": {"size": 32768, "crc": "F3C933DF"}, + "p5.6g": {"size": 16384, "crc": "42DBE029"}, + "p6.6k": {"size": 32768, "crc": "596F1C8A"}, + "p7.2p": {"size": 32768, "crc": "C63A871F"}, + "p8.2s": {"size": 32768, "crc": "760568D8"}, + "p9.2t": {"size": 32768, "crc": "57B35C73"}, + "p1.4p": {"size": 16384, "crc": "900A113C"}, + "p2.4m": {"size": 32768, "crc": "61C69474"}, + "p11.2d": {"size": 16384, "crc": "18B4BCCA"}, + "p10.2b": {"size": 32768, "crc": "F269C0EB"}, + "2.1b": {"size": 1024, "crc": "D25C9099"}, + "3.2c": {"size": 1024, "crc": "294279AE"}, + "1.1c": {"size": 1024, "crc": "A4A4E7DC"} + } + } + }, + { + "game": "Prehistoric Isle", + "system": "Arcade", + "filename": "gensitou.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "gt-j2.2h": {"size": 131072, "crc": "A2DA0B6B"}, + "gt-j3.3h": {"size": 131072, "crc": "C1A0AE8E"}, + "gt1.1": {"size": 65536, "crc": "80A4C093"}, + "gt15.b15": {"size": 32768, "crc": "AC652412"}, + "pi8914.b14": {"size": 262144, "crc": "207D6187"}, + "pi8916.h16": {"size": 262144, "crc": "7CFFE0F6"}, + "pi8910.k14": {"size": 524288, "crc": "5A101B0B"}, + "gt5.5": {"size": 131072, "crc": "3D3AB273"}, + "gt11.11": {"size": 65536, "crc": "B4F0FCF0"}, + "gt4.4": {"size": 131072, "crc": "85DFB9EC"} + } + } + }, + { + "game": "Prehistoric Isle", + "system": "Arcade", + "filename": "prehisle.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "gt-e2.2h": {"size": 131072, "crc": "7083245A"}, + "gt-e3.3h": {"size": 131072, "crc": "6D8CDF58"}, + "gt1.1": {"size": 65536, "crc": "80A4C093"}, + "gt15.b15": {"size": 32768, "crc": "AC652412"}, + "pi8914.b14": {"size": 262144, "crc": "207D6187"}, + "pi8916.h16": {"size": 262144, "crc": "7CFFE0F6"}, + "pi8910.k14": {"size": 524288, "crc": "5A101B0B"}, + "gt5.5": {"size": 131072, "crc": "3D3AB273"}, + "gt11.11": {"size": 65536, "crc": "B4F0FCF0"}, + "gt4.4": {"size": 131072, "crc": "85DFB9EC"} + } + } + }, + { + "game": "Prehistoric Isle", + "system": "Arcade", + "filename": "prehisleu.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "gt-u2.2h": {"size": 131072, "crc": "A14F49BB"}, + "gt-u3.3h": {"size": 131072, "crc": "F165757E"}, + "gt1.1": {"size": 65536, "crc": "80A4C093"}, + "gt15.b15": {"size": 32768, "crc": "AC652412"}, + "pi8914.b14": {"size": 262144, "crc": "207D6187"}, + "pi8916.h16": {"size": 262144, "crc": "7CFFE0F6"}, + "pi8910.k14": {"size": 524288, "crc": "5A101B0B"}, + "gt5.5": {"size": 131072, "crc": "3D3AB273"}, + "gt11.11": {"size": 65536, "crc": "B4F0FCF0"}, + "gt4.4": {"size": 131072, "crc": "85DFB9EC"} + } + } + }, + { + "game": "Street Smart", + "system": "Arcade", + "filename": "streetsm.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "s2-1ver2.14h": {"size": 131072, "crc": "655F4773"}, + "s2-2ver2.14k": {"size": 131072, "crc": "EFAE4823"}, + "s2-9.25l": {"size": 32768, "crc": "09B6AC67"}, + "s2-10.25m": {"size": 32768, "crc": "89E4EE6F"}, + "s2-5.16c": {"size": 65536, "crc": "CA4B171E"}, + "s2-6.18d": {"size": 131072, "crc": "47DB1605"}, + "stsmart.900": {"size": 524288, "crc": "A8279A7E"}, + "stsmart.902": {"size": 524288, "crc": "2F021AA1"}, + "stsmart.904": {"size": 524288, "crc": "167346F7"}, + "stsmart.901": {"size": 524288, "crc": "C305AF12"}, + "stsmart.903": {"size": 524288, "crc": "73C16D35"}, + "stsmart.905": {"size": 524288, "crc": "A5BEB4E2"} + } + } + }, + { + "game": "Street Smart", + "system": "Arcade", + "filename": "streetsm1.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "s2-1ver1.9c": {"size": 131072, "crc": "B59354C5"}, + "s2-2ver1.10c": {"size": 131072, "crc": "E448B68B"}, + "s2-7.15l": {"size": 32768, "crc": "22BEDFE5"}, + "s2-8.15m": {"size": 32768, "crc": "6A1C70AB"}, + "s2-5.16c": {"size": 65536, "crc": "CA4B171E"}, + "s2-6.18d": {"size": 131072, "crc": "47DB1605"}, + "stsmart.900": {"size": 524288, "crc": "A8279A7E"}, + "stsmart.902": {"size": 524288, "crc": "2F021AA1"}, + "stsmart.904": {"size": 524288, "crc": "167346F7"}, + "stsmart.901": {"size": 524288, "crc": "C305AF12"}, + "stsmart.903": {"size": 524288, "crc": "73C16D35"}, + "stsmart.905": {"size": 524288, "crc": "A5BEB4E2"} + } + } + }, + { + "game": "Street Smart", + "system": "Arcade", + "filename": "streetsmj.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "s2v1j_01.bin": {"size": 131072, "crc": "F031413C"}, + "s2v1j_02.bin": {"size": 131072, "crc": "E403A40B"}, + "s2-7.15l": {"size": 32768, "crc": "22BEDFE5"}, + "s2-8.15m": {"size": 32768, "crc": "6A1C70AB"}, + "s2-5.16c": {"size": 65536, "crc": "CA4B171E"}, + "s2-6.18d": {"size": 131072, "crc": "47DB1605"}, + "stsmart.900": {"size": 524288, "crc": "A8279A7E"}, + "stsmart.902": {"size": 524288, "crc": "2F021AA1"}, + "stsmart.904": {"size": 524288, "crc": "167346F7"}, + "stsmart.901": {"size": 524288, "crc": "C305AF12"}, + "stsmart.903": {"size": 524288, "crc": "73C16D35"}, + "stsmart.905": {"size": 524288, "crc": "A5BEB4E2"} + } + } + }, + { + "game": "Street Smart", + "system": "Arcade", + "filename": "streetsmw.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "s-smart1.bin": {"size": 131072, "crc": "A1F5CEAB"}, + "s-smart2.bin": {"size": 131072, "crc": "263F615D"}, + "s2-7.15l": {"size": 32768, "crc": "22BEDFE5"}, + "s2-8.15m": {"size": 32768, "crc": "6A1C70AB"}, + "s2-5.16c": {"size": 65536, "crc": "CA4B171E"}, + "s2-6.18d": {"size": 131072, "crc": "47DB1605"}, + "stsmart.900": {"size": 524288, "crc": "A8279A7E"}, + "stsmart.902": {"size": 524288, "crc": "2F021AA1"}, + "stsmart.904": {"size": 524288, "crc": "167346F7"}, + "stsmart.901": {"size": 524288, "crc": "C305AF12"}, + "stsmart.903": {"size": 524288, "crc": "73C16D35"}, + "stsmart.905": {"size": 524288, "crc": "A5BEB4E2"} + } + } + }, + { + "game": "Ikari III: The Rescue", + "system": "Arcade", + "filename": "ikari3.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "ik3-2-ver1.c10": {"size": 131072, "crc": "1BAE8023"}, + "ik3-3-ver1.c9": {"size": 131072, "crc": "10E38B66"}, + "ik3-7.16l": {"size": 32768, "crc": "0B4804DF"}, + "ik3-8.16m": {"size": 32768, "crc": "10AB4E50"}, + "ik3-23.bin": {"size": 131072, "crc": "D0FD5C77"}, + "ik3-13.bin": {"size": 131072, "crc": "9A56BD32"}, + "ik3-22.bin": {"size": 131072, "crc": "4878D883"}, + "ik3-12.bin": {"size": 131072, "crc": "0CE6A10A"}, + "ik3-21.bin": {"size": 131072, "crc": "50D0FBF0"}, + "ik3-11.bin": {"size": 131072, "crc": "E4E2BE43"}, + "ik3-20.bin": {"size": 131072, "crc": "9A851EFC"}, + "ik3-10.bin": {"size": 131072, "crc": "AC222372"}, + "ik3-19.bin": {"size": 131072, "crc": "4EBDBA89"}, + "ik3-9.bin": {"size": 131072, "crc": "C33971C2"}, + "ik3-14.bin": {"size": 131072, "crc": "453BEA77"}, + "ik3-24.bin": {"size": 131072, "crc": "E9B26D68"}, + "ik3-15.bin": {"size": 131072, "crc": "781A81FC"}, + "ik3-25.bin": {"size": 131072, "crc": "073B03F1"}, + "ik3-16.bin": {"size": 131072, "crc": "80BA400B"}, + "ik3-26.bin": {"size": 131072, "crc": "9C613561"}, + "ik3-17.bin": {"size": 131072, "crc": "0CC3CE4A"}, + "ik3-27.bin": {"size": 131072, "crc": "16DD227E"}, + "ik3-18.bin": {"size": 131072, "crc": "BA106245"}, + "ik3-28.bin": {"size": 131072, "crc": "711715AE"}, + "ik3-5.16d": {"size": 65536, "crc": "CE6706FC"}, + "ik3-6.18e": {"size": 131072, "crc": "59D256A4"}, + "ik3-1.c8": {"size": 65536, "crc": "47E4D256"}, + "ik3-4.c12": {"size": 65536, "crc": "A43AF6B5"} + } + } + }, + { + "game": "Ikari III: The Rescue", + "system": "Arcade", + "filename": "ikari3j.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "ik3-2-j.c10": {"size": 131072, "crc": "7B1B4BE4"}, + "ik3-3-j.c9": {"size": 131072, "crc": "8E6E2AA9"}, + "ik3-7.16l": {"size": 32768, "crc": "0B4804DF"}, + "ik3-8.16m": {"size": 32768, "crc": "10AB4E50"}, + "ik3-23.bin": {"size": 131072, "crc": "D0FD5C77"}, + "ik3-13.bin": {"size": 131072, "crc": "9A56BD32"}, + "ik3-22.bin": {"size": 131072, "crc": "4878D883"}, + "ik3-12.bin": {"size": 131072, "crc": "0CE6A10A"}, + "ik3-21.bin": {"size": 131072, "crc": "50D0FBF0"}, + "ik3-11.bin": {"size": 131072, "crc": "E4E2BE43"}, + "ik3-20.bin": {"size": 131072, "crc": "9A851EFC"}, + "ik3-10.bin": {"size": 131072, "crc": "AC222372"}, + "ik3-19.bin": {"size": 131072, "crc": "4EBDBA89"}, + "ik3-9.bin": {"size": 131072, "crc": "C33971C2"}, + "ik3-14.bin": {"size": 131072, "crc": "453BEA77"}, + "ik3-24.bin": {"size": 131072, "crc": "E9B26D68"}, + "ik3-15.bin": {"size": 131072, "crc": "781A81FC"}, + "ik3-25.bin": {"size": 131072, "crc": "073B03F1"}, + "ik3-16.bin": {"size": 131072, "crc": "80BA400B"}, + "ik3-26.bin": {"size": 131072, "crc": "9C613561"}, + "ik3-17.bin": {"size": 131072, "crc": "0CC3CE4A"}, + "ik3-27.bin": {"size": 131072, "crc": "16DD227E"}, + "ik3-18.bin": {"size": 131072, "crc": "BA106245"}, + "ik3-28.bin": {"size": 131072, "crc": "711715AE"}, + "ik3-5.16d": {"size": 65536, "crc": "CE6706FC"}, + "ik3-6.18e": {"size": 131072, "crc": "59D256A4"}, + "ik3-1.c8": {"size": 65536, "crc": "47E4D256"}, + "ik3-4.c12": {"size": 65536, "crc": "A43AF6B5"} + } + } + }, + { + "game": "Ikari III: The Rescue", + "system": "Arcade", + "filename": "ikari3k.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "ik3-2k.c10": {"size": 131072, "crc": "A15D2222"}, + "ik3-3k.c9": {"size": 131072, "crc": "E3FC006E"}, + "ik3-7k.16l": {"size": 32768, "crc": "8BFB399B"}, + "ik3-8k.16m": {"size": 32768, "crc": "3F0FE576"}, + "ikari-880d_t53.d2": {"size": 524288, "crc": "5855D95E"}, + "ikari-880c_t54.c2": {"size": 524288, "crc": "6D728362"}, + "ik12.d1": {"size": 131072, "crc": "4EBDBA89"}, + "ik11.c1": {"size": 131072, "crc": "C33971C2"}, + "ikari-880d_t52.b2": {"size": 524288, "crc": "E25380E6"}, + "ikari-880c_t51.a2": {"size": 524288, "crc": "87607772"}, + "ik10.b1": {"size": 131072, "crc": "BA106245"}, + "ik9.a1": {"size": 131072, "crc": "711715AE"}, + "ik3-5.16d": {"size": 65536, "crc": "CE6706FC"}, + "ik3-6.18e": {"size": 131072, "crc": "59D256A4"}, + "ik3-1.c8": {"size": 65536, "crc": "47E4D256"}, + "ik3-4.c12": {"size": 65536, "crc": "A43AF6B5"} + } + } + }, + { + "game": "Ikari III: The Rescue", + "system": "Arcade", + "filename": "ikari3u.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "ik3-2.c10": {"size": 131072, "crc": "A7B34DCD"}, + "ik3-3.c9": {"size": 131072, "crc": "50F2B83D"}, + "ik3-7.16l": {"size": 32768, "crc": "0B4804DF"}, + "ik3-8.16m": {"size": 32768, "crc": "10AB4E50"}, + "ik3-23.bin": {"size": 131072, "crc": "D0FD5C77"}, + "ik3-13.bin": {"size": 131072, "crc": "9A56BD32"}, + "ik3-22.bin": {"size": 131072, "crc": "4878D883"}, + "ik3-12.bin": {"size": 131072, "crc": "0CE6A10A"}, + "ik3-21.bin": {"size": 131072, "crc": "50D0FBF0"}, + "ik3-11.bin": {"size": 131072, "crc": "E4E2BE43"}, + "ik3-20.bin": {"size": 131072, "crc": "9A851EFC"}, + "ik3-10.bin": {"size": 131072, "crc": "AC222372"}, + "ik3-19.bin": {"size": 131072, "crc": "4EBDBA89"}, + "ik3-9.bin": {"size": 131072, "crc": "C33971C2"}, + "ik3-14.bin": {"size": 131072, "crc": "453BEA77"}, + "ik3-24.bin": {"size": 131072, "crc": "E9B26D68"}, + "ik3-15.bin": {"size": 131072, "crc": "781A81FC"}, + "ik3-25.bin": {"size": 131072, "crc": "073B03F1"}, + "ik3-16.bin": {"size": 131072, "crc": "80BA400B"}, + "ik3-26.bin": {"size": 131072, "crc": "9C613561"}, + "ik3-17.bin": {"size": 131072, "crc": "0CC3CE4A"}, + "ik3-27.bin": {"size": 131072, "crc": "16DD227E"}, + "ik3-18.bin": {"size": 131072, "crc": "BA106245"}, + "ik3-28.bin": {"size": 131072, "crc": "711715AE"}, + "ik3-5.15d": {"size": 65536, "crc": "CE6706FC"}, + "ik3-6.18e": {"size": 131072, "crc": "59D256A4"}, + "ik3-1.c8": {"size": 65536, "crc": "47E4D256"}, + "ik3-4.c12": {"size": 65536, "crc": "A43AF6B5"} + } + } + }, + { + "game": "P.O.W", + "system": "Arcade", + "filename": "pow.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "dg1ver1.j14": {"size": 131072, "crc": "8E71A8AF"}, + "dg2ver1.l14": {"size": 131072, "crc": "4287AFFC"}, + "dg9.l25": {"size": 32768, "crc": "DF864A08"}, + "dg10.m25": {"size": 32768, "crc": "9E470D53"}, + "dg8.e25": {"size": 65536, "crc": "D1D61DA3"}, + "dg7.d20": {"size": 65536, "crc": "ABA9A9D3"}, + "pal20l10.a6": {"size": 204, "crc": "C3D9E729"}, + "snk88011a.1a": {"size": 131072, "crc": "E70FD906"}, + "snk88015a.2a": {"size": 131072, "crc": "7A90E957"}, + "snk88012a.1b": {"size": 131072, "crc": "628B1AED"}, + "snk88016a.2b": {"size": 131072, "crc": "E40A6C13"}, + "snk88013a.1c": {"size": 131072, "crc": "19DC8868"}, + "snk88017a.2c": {"size": 131072, "crc": "C7931CC2"}, + "snk88014a.1d": {"size": 131072, "crc": "47CD498B"}, + "snk88018a.2d": {"size": 131072, "crc": "EED72232"}, + "snk88019a.3a": {"size": 131072, "crc": "1775B8DD"}, + "snk88023a.4a": {"size": 131072, "crc": "ADB6AD68"}, + "snk88020a.3b": {"size": 131072, "crc": "F8E752EC"}, + "snk88024a.4b": {"size": 131072, "crc": "DD41865A"}, + "snk88021a.3c": {"size": 131072, "crc": "27E9FFFE"}, + "snk88025a.4c": {"size": 131072, "crc": "055759AD"}, + "snk88022a.3d": {"size": 131072, "crc": "AA9C00D8"}, + "snk88026a.4d": {"size": 131072, "crc": "9BC261C5"} + } + } + }, + { + "game": "P.O.W", + "system": "Arcade", + "filename": "powj.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "1-2": {"size": 131072, "crc": "2F17BFB0"}, + "2-2": {"size": 131072, "crc": "BAA32354"}, + "dg9.l25": {"size": 32768, "crc": "DF864A08"}, + "dg10.m25": {"size": 32768, "crc": "9E470D53"}, + "dg8.e25": {"size": 65536, "crc": "D1D61DA3"}, + "dg7.d20": {"size": 65536, "crc": "ABA9A9D3"}, + "pal20l10.a6": {"size": 204, "crc": "C3D9E729"}, + "snk88011a.1a": {"size": 131072, "crc": "E70FD906"}, + "snk88015a.2a": {"size": 131072, "crc": "7A90E957"}, + "snk88012a.1b": {"size": 131072, "crc": "628B1AED"}, + "snk88016a.2b": {"size": 131072, "crc": "E40A6C13"}, + "snk88013a.1c": {"size": 131072, "crc": "19DC8868"}, + "snk88017a.2c": {"size": 131072, "crc": "C7931CC2"}, + "snk88014a.1d": {"size": 131072, "crc": "47CD498B"}, + "snk88018a.2d": {"size": 131072, "crc": "EED72232"}, + "snk88019a.3a": {"size": 131072, "crc": "1775B8DD"}, + "snk88023a.4a": {"size": 131072, "crc": "ADB6AD68"}, + "snk88020a.3b": {"size": 131072, "crc": "F8E752EC"}, + "snk88024a.4b": {"size": 131072, "crc": "DD41865A"}, + "snk88021a.3c": {"size": 131072, "crc": "27E9FFFE"}, + "snk88025a.4c": {"size": 131072, "crc": "055759AD"}, + "snk88022a.3d": {"size": 131072, "crc": "AA9C00D8"}, + "snk88026a.4d": {"size": 131072, "crc": "9BC261C5"} + } + } + }, + { + "game": "Vanguard", + "system": "Arcade", + "filename": "vanguard.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "sk4_ic07.bin": {"size": 4096, "crc": "6A29E354"}, + "sk4_ic08.bin": {"size": 4096, "crc": "302BBA54"}, + "sk4_ic09.bin": {"size": 4096, "crc": "424755F6"}, + "sk4_ic10.bin": {"size": 4096, "crc": "54603274"}, + "sk4_ic13.bin": {"size": 4096, "crc": "FDE157D0"}, + "sk4_ic14.bin": {"size": 4096, "crc": "0D5B47D0"}, + "sk4_ic15.bin": {"size": 4096, "crc": "8549B8F8"}, + "sk4_ic16.bin": {"size": 4096, "crc": "062E0BE2"}, + "sk5_ic50.bin": {"size": 2048, "crc": "E7D4315B"}, + "sk5_ic51.bin": {"size": 2048, "crc": "96E87858"}, + "sk5_ic7.bin": {"size": 32, "crc": "AD782A73"}, + "sk5_ic6.bin": {"size": 32, "crc": "7DC9D450"}, + "sk4_ic51.bin": {"size": 2048, "crc": "D2A64006"}, + "sk4_ic52.bin": {"size": 2048, "crc": "CC4A0B6F"}, + "sk6_ic07.bin": {"size": 2048, "crc": "2B7CBAE9"}, + "sk6_ic08.bin": {"size": 2048, "crc": "3B7E9D7C"}, + "sk6_ic11.bin": {"size": 2048, "crc": "C36DF041"} + } + } + }, + { + "game": "Vanguard", + "system": "Arcade", + "filename": "vanguardc.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "sk4_ic07.bin": {"size": 4096, "crc": "6A29E354"}, + "sk4_ic08.bin": {"size": 4096, "crc": "302BBA54"}, + "sk4_ic09.bin": {"size": 4096, "crc": "424755F6"}, + "4": {"size": 4096, "crc": "770F9714"}, + "5": {"size": 4096, "crc": "3445CBA6"}, + "sk4_ic14.bin": {"size": 4096, "crc": "0D5B47D0"}, + "sk4_ic15.bin": {"size": 4096, "crc": "8549B8F8"}, + "8": {"size": 4096, "crc": "4B825BC8"}, + "sk5_ic50.bin": {"size": 2048, "crc": "E7D4315B"}, + "sk5_ic51.bin": {"size": 2048, "crc": "96E87858"}, + "sk5_ic7.bin": {"size": 32, "crc": "AD782A73"}, + "sk5_ic6.bin": {"size": 32, "crc": "7DC9D450"}, + "sk4_ic51.bin": {"size": 2048, "crc": "D2A64006"}, + "sk4_ic52.bin": {"size": 2048, "crc": "CC4A0B6F"}, + "sk6_ic07.bin": {"size": 2048, "crc": "2B7CBAE9"}, + "sk6_ic08.bin": {"size": 2048, "crc": "3B7E9D7C"}, + "sk6_ic11.bin": {"size": 2048, "crc": "C36DF041"} + } + } + }, + { + "game": "Vanguard", + "system": "Arcade", + "filename": "vanguardj.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "sk4_ic07.bin": {"size": 4096, "crc": "6A29E354"}, + "sk4_ic08.bin": {"size": 4096, "crc": "302BBA54"}, + "sk4_ic09.bin": {"size": 4096, "crc": "424755F6"}, + "vgj4ic10.bin": {"size": 4096, "crc": "0A91A5D1"}, + "vgj5ic13.bin": {"size": 4096, "crc": "06601A40"}, + "sk4_ic14.bin": {"size": 4096, "crc": "0D5B47D0"}, + "sk4_ic15.bin": {"size": 4096, "crc": "8549B8F8"}, + "sk4_ic16.bin": {"size": 4096, "crc": "062E0BE2"}, + "sk5_ic50.bin": {"size": 2048, "crc": "E7D4315B"}, + "sk5_ic51.bin": {"size": 2048, "crc": "96E87858"}, + "sk5_ic7.bin": {"size": 32, "crc": "AD782A73"}, + "sk5_ic6.bin": {"size": 32, "crc": "7DC9D450"}, + "sk4_ic51.bin": {"size": 2048, "crc": "D2A64006"}, + "sk4_ic52.bin": {"size": 2048, "crc": "CC4A0B6F"}, + "sk6_ic07.bin": {"size": 2048, "crc": "2B7CBAE9"}, + "sk6_ic08.bin": {"size": 2048, "crc": "3B7E9D7C"}, + "sk6_ic11.bin": {"size": 2048, "crc": "C36DF041"} + } + } + }, + { + "game": "Guerilla War", + "system": "Arcade", + "filename": "gwar.zip", + "status": "playable", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "gw5.8p": {"size": 32768, "crc": "80F73E2E"}, + "1.2g": {"size": 65536, "crc": "5BCFA7DC"}, + "gw6.2j": {"size": 65536, "crc": "58600F7D"}, + "7.2l": {"size": 65536, "crc": "A3F9B463"}, + "gw8.2m": {"size": 65536, "crc": "092501BE"}, + "gw9.2p": {"size": 65536, "crc": "25801EA6"}, + "16.2ab": {"size": 65536, "crc": "2B46EDFF"}, + "17.2ad": {"size": 65536, "crc": "BE19888D"}, + "14.2y": {"size": 65536, "crc": "2D653F0C"}, + "15.2aa": {"size": 65536, "crc": "EBBF3BA2"}, + "12.2v": {"size": 65536, "crc": "AEB3707F"}, + "13.2w": {"size": 65536, "crc": "0808F95F"}, + "10.2s": {"size": 65536, "crc": "8DFC7B87"}, + "11.2t": {"size": 65536, "crc": "06822AAC"}, + "18.8x": {"size": 65536, "crc": "F1DCDAEF"}, + "19.8z": {"size": 65536, "crc": "326E4E5E"}, + "gw20.8aa": {"size": 65536, "crc": "0AA70967"}, + "21.8ac": {"size": 65536, "crc": "B7686336"}, + "4.2j": {"size": 65536, "crc": "2255F8DD"}, + "2.6g": {"size": 65536, "crc": "86D931BF"}, + "3.7g": {"size": 65536, "crc": "EB544AB9"}, + "2.9v": {"size": 1024, "crc": "9147DE69"}, + "3.9w": {"size": 1024, "crc": "090236A3"}, + "1.9u": {"size": 1024, "crc": "7F9C839E"}, + "l.1x": {"size": 4096, "crc": "C71C0011"}, + "l.1w": {"size": 4096, "crc": "C71C0011"} + } + } + }, + { + "game": "Guerilla War (A)", + "system": "Arcade", + "filename": "gwara.zip", + "status": "playable", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "gv5.3a": {"size": 32768, "crc": "80F73E2E"}, + "gv3_1.4p": {"size": 65536, "crc": "24936D83"}, + "gv4.8p": {"size": 65536, "crc": "26335A55"}, + "gv2.7k": {"size": 65536, "crc": "896682DD"}, + "gv1.5g": {"size": 65536, "crc": "2255F8DD"}, + "gv9.3g": {"size": 65536, "crc": "58600F7D"}, + "gv8.3e": {"size": 65536, "crc": "A3F9B463"}, + "gv7.3d": {"size": 65536, "crc": "092501BE"}, + "gv6.3b": {"size": 65536, "crc": "25801EA6"}, + "gv14.8l": {"size": 65536, "crc": "2B46EDFF"}, + "gv15.8n": {"size": 65536, "crc": "BE19888D"}, + "gv16.8p": {"size": 65536, "crc": "2D653F0C"}, + "gv17.8s": {"size": 65536, "crc": "EBBF3BA2"}, + "gv18.7p": {"size": 65536, "crc": "AEB3707F"}, + "gv19.7s": {"size": 65536, "crc": "0808F95F"}, + "gv20.8j": {"size": 65536, "crc": "8DFC7B87"}, + "gv21.8k": {"size": 65536, "crc": "06822AAC"}, + "gv13.2a": {"size": 65536, "crc": "F1DCDAEF"}, + "gv12.2b": {"size": 65536, "crc": "326E4E5E"}, + "gv11.2d": {"size": 65536, "crc": "0AA70967"}, + "gv10.2e": {"size": 65536, "crc": "B7686336"}, + "1.1k": {"size": 1024, "crc": "090236A3"}, + "2.1l": {"size": 1024, "crc": "7F9C839E"}, + "3.2l": {"size": 1024, "crc": "9147DE69"}, + "l.1x": {"size": 4096, "crc": "C71C0011"}, + "l.1w": {"size": 4096, "crc": "C71C0011"}, + "horizon.8j": {"size": 1024, "crc": "EFB5AF2E"}, + "vertical.8k": {"size": 1024, "crc": "EFB5AF2E"} + } + } + }, + { + "game": "Guerilla War (B)", + "system": "Arcade", + "filename": "gwarab.zip", + "status": "playable", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "gv5.3a": {"size": 32768, "crc": "80F73E2E"}, + "gv3 ver 1.4p": {"size": 65536, "crc": "ABEC5EEB"}, + "gv4.8p": {"size": 65536, "crc": "26335A55"}, + "gv2.7k": {"size": 65536, "crc": "896682DD"}, + "gv1.5g": {"size": 65536, "crc": "2255F8DD"}, + "gv9.3g": {"size": 65536, "crc": "58600F7D"}, + "gv8.3e": {"size": 65536, "crc": "A3F9B463"}, + "gv7.3d": {"size": 65536, "crc": "092501BE"}, + "gv6.3b": {"size": 65536, "crc": "25801EA6"}, + "gv14.8l": {"size": 65536, "crc": "2B46EDFF"}, + "gv15.8n": {"size": 65536, "crc": "BE19888D"}, + "gv16.8p": {"size": 65536, "crc": "2D653F0C"}, + "gv17.8s": {"size": 65536, "crc": "EBBF3BA2"}, + "gv18.7p": {"size": 65536, "crc": "AEB3707F"}, + "gv19.7s": {"size": 65536, "crc": "0808F95F"}, + "gv20.8j": {"size": 65536, "crc": "8DFC7B87"}, + "gv21.8k": {"size": 65536, "crc": "06822AAC"}, + "gv13.2a": {"size": 65536, "crc": "F1DCDAEF"}, + "gv12.2b": {"size": 65536, "crc": "326E4E5E"}, + "gv11.2d": {"size": 65536, "crc": "0AA70967"}, + "gv10.2e": {"size": 65536, "crc": "B7686336"}, + "1.1k": {"size": 1024, "crc": "090236A3"}, + "2.1l": {"size": 1024, "crc": "7F9C839E"}, + "3.2l": {"size": 1024, "crc": "9147DE69"}, + "l.1x": {"size": 4096, "crc": "C71C0011"}, + "l.1w": {"size": 4096, "crc": "C71C0011"}, + "horizon.8j": {"size": 1024, "crc": "EFB5AF2E"}, + "vertical.8k": {"size": 1024, "crc": "EFB5AF2E"} + } + } + }, + { + "game": "Guevara (Guerilla War (J))", + "system": "Arcade", + "filename": "gwarj.zip", + "status": "playable", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "gw5.8p": {"size": 32768, "crc": "99D7DDF3"}, + "1.2g": {"size": 65536, "crc": "7F8A880C"}, + "2.6g": {"size": 65536, "crc": "86D931BF"}, + "3.7g": {"size": 65536, "crc": "EB544AB9"}, + "gw6.2j": {"size": 65536, "crc": "58600F7D"}, + "7.2l": {"size": 65536, "crc": "A3F9B463"}, + "gw8.2m": {"size": 65536, "crc": "092501BE"}, + "gw9.2p": {"size": 65536, "crc": "25801EA6"}, + "16.2ab": {"size": 65536, "crc": "2B46EDFF"}, + "17.2ad": {"size": 65536, "crc": "BE19888D"}, + "14.2y": {"size": 65536, "crc": "2D653F0C"}, + "15.2aa": {"size": 65536, "crc": "EBBF3BA2"}, + "12.2v": {"size": 65536, "crc": "AEB3707F"}, + "13.2w": {"size": 65536, "crc": "0808F95F"}, + "10.2s": {"size": 65536, "crc": "8DFC7B87"}, + "11.2t": {"size": 65536, "crc": "06822AAC"}, + "18.8x": {"size": 65536, "crc": "F1DCDAEF"}, + "19.8z": {"size": 65536, "crc": "326E4E5E"}, + "gw20.8aa": {"size": 65536, "crc": "0AA70967"}, + "21.8ac": {"size": 65536, "crc": "B7686336"}, + "4.2j": {"size": 65536, "crc": "2255F8DD"}, + "2.9v": {"size": 1024, "crc": "9147DE69"}, + "3.9w": {"size": 1024, "crc": "090236A3"}, + "1.9u": {"size": 1024, "crc": "7F9C839E"}, + "l.1x": {"size": 4096, "crc": "C71C0011"}, + "l.1w": {"size": 4096, "crc": "C71C0011"} + } + } + }, + { + "game": "Psycho Soldier", + "system": "Arcade", + "filename": "psychos.zip", + "status": "playable", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "ps7.4m": {"size": 65536, "crc": "562809F4"}, + "ps5.6j": {"size": 65536, "crc": "64503283"}, + "ps1.5b": {"size": 65536, "crc": "58F1683F"}, + "ps2.5c": {"size": 65536, "crc": "DA3ABDA1"}, + "ps3.5d": {"size": 65536, "crc": "F3683AE8"}, + "ps4.5f": {"size": 65536, "crc": "437D775A"}, + "ps6.8m": {"size": 65536, "crc": "5F426DDB"}, + "ps8.3a": {"size": 32768, "crc": "11A71919"}, + "ps16.1f": {"size": 65536, "crc": "167E5765"}, + "ps15.1d": {"size": 65536, "crc": "8B0FE8D0"}, + "ps14.1c": {"size": 65536, "crc": "F4361C50"}, + "ps13.1a": {"size": 65536, "crc": "E4B0B95E"}, + "ps12.3g": {"size": 32768, "crc": "F96F82DB"}, + "ps11.3e": {"size": 32768, "crc": "2B007733"}, + "ps10.3c": {"size": 32768, "crc": "EFA830E1"}, + "ps9.3b": {"size": 32768, "crc": "24559EE1"}, + "ps17.10f": {"size": 65536, "crc": "2BAC250E"}, + "ps18.10h": {"size": 65536, "crc": "5E1BA353"}, + "ps19.10j": {"size": 65536, "crc": "9FF91A97"}, + "ps20.10l": {"size": 65536, "crc": "AE1965EF"}, + "ps21.10m": {"size": 65536, "crc": "DF283B67"}, + "ps22.10n": {"size": 65536, "crc": "914F051F"}, + "ps23.10r": {"size": 65536, "crc": "C4488472"}, + "ps24.10s": {"size": 65536, "crc": "8EC7FE18"}, + "horizon.8j": {"size": 1024, "crc": "EFB5AF2E"}, + "vertical.8k": {"size": 1024, "crc": "EFB5AF2E"}, + "psc3.1l": {"size": 1024, "crc": "40E78C9E"}, + "psc1.1k": {"size": 1024, "crc": "27B8CA8C"}, + "psc2.2k": {"size": 1024, "crc": "D845D5AC"} + } + } + }, + { + "game": "Psycho Soldier (J)", + "system": "Arcade", + "filename": "psychosj.zip", + "status": "playable", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "ps7.4m": {"size": 65536, "crc": "05DFB409"}, + "ps5.6j": {"size": 65536, "crc": "BBD0A8E3"}, + "ps1.5b": {"size": 65536, "crc": "0F8E8276"}, + "ps2.5c": {"size": 65536, "crc": "34E41DFB"}, + "ps3.5d": {"size": 65536, "crc": "AA583C5E"}, + "ps4.5f": {"size": 65536, "crc": "7E8BCE7A"}, + "ps6.8m": {"size": 65536, "crc": "5F426DDB"}, + "ps8.3a": {"size": 32768, "crc": "11A71919"}, + "ps16.1f": {"size": 65536, "crc": "167E5765"}, + "ps15.1d": {"size": 65536, "crc": "8B0FE8D0"}, + "ps14.1c": {"size": 65536, "crc": "F4361C50"}, + "ps13.1a": {"size": 65536, "crc": "E4B0B95E"}, + "ps12.3g": {"size": 32768, "crc": "F96F82DB"}, + "ps11.3e": {"size": 32768, "crc": "2B007733"}, + "ps10.3c": {"size": 32768, "crc": "EFA830E1"}, + "ps9.3b": {"size": 32768, "crc": "24559EE1"}, + "ps17.10f": {"size": 65536, "crc": "2BAC250E"}, + "ps18.10h": {"size": 65536, "crc": "5E1BA353"}, + "ps19.10j": {"size": 65536, "crc": "9FF91A97"}, + "ps20.10l": {"size": 65536, "crc": "AE1965EF"}, + "ps21.10m": {"size": 65536, "crc": "DF283B67"}, + "ps22.10n": {"size": 65536, "crc": "914F051F"}, + "ps23.10r": {"size": 65536, "crc": "C4488472"}, + "ps24.10s": {"size": 65536, "crc": "8EC7FE18"}, + "horizon.8j": {"size": 1024, "crc": "EFB5AF2E"}, + "vertical.8k": {"size": 1024, "crc": "EFB5AF2E"}, + "psc3.1l": {"size": 1024, "crc": "40E78C9E"}, + "psc1.1k": {"size": 1024, "crc": "27B8CA8C"}, + "psc2.2k": {"size": 1024, "crc": "D845D5AC"} + } + } + }, + { + "game": "Ikari I", + "system": "Arcade", + "filename": "ikari.zip", + "status": "playable", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "1.4p": {"size": 65536, "crc": "52A8B2DD"}, + "2.8p": {"size": 65536, "crc": "45364D55"}, + "3.7k": {"size": 65536, "crc": "56A26699"}, + "p11.4m": {"size": 32768, "crc": "5C75EA8F"}, + "p14.2m": {"size": 32768, "crc": "3293FDE4"}, + "p12.4p": {"size": 32768, "crc": "95138498"}, + "p15.2p": {"size": 32768, "crc": "65A61C99"}, + "p13.4r": {"size": 32768, "crc": "315383D7"}, + "p16.2r": {"size": 32768, "crc": "E9B03E07"}, + "p7.3b": {"size": 16384, "crc": "A7EB4917"}, + "p8.3d": {"size": 32768, "crc": "9827C14A"}, + "p9.3f": {"size": 32768, "crc": "545C790C"}, + "p10.3h": {"size": 32768, "crc": "EC9BA07E"}, + "p17.4d": {"size": 32768, "crc": "E0DBA976"}, + "p18.2d": {"size": 32768, "crc": "24947D5F"}, + "p19.4b": {"size": 32768, "crc": "9EE59E91"}, + "p20.2b": {"size": 32768, "crc": "5DA7EC1A"}, + "a6002-2.2l": {"size": 1024, "crc": "0703A770"}, + "a6002-1.1k": {"size": 1024, "crc": "B9BF2C2C"}, + "a6002-3.1l": {"size": 1024, "crc": "0A11CDDE"} + } + } + }, + { + "game": "Ikari I (US Alt.)", + "system": "Arcade", + "filename": "ikaria.zip", + "status": "playable", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "p1.4l": {"size": 16384, "crc": "AD0E440E"}, + "p2.4k": {"size": 32768, "crc": "B585E931"}, + "p3.8l": {"size": 16384, "crc": "8A9BD1F0"}, + "p4.8k": {"size": 32768, "crc": "F4101CB4"}, + "p5.6e": {"size": 16384, "crc": "863448FA"}, + "p6.6f": {"size": 32768, "crc": "9B16AA57"}, + "p11.4m": {"size": 32768, "crc": "5C75EA8F"}, + "p14.2m": {"size": 32768, "crc": "3293FDE4"}, + "p12.4p": {"size": 32768, "crc": "95138498"}, + "p15.2p": {"size": 32768, "crc": "65A61C99"}, + "p13.4r": {"size": 32768, "crc": "315383D7"}, + "p16.2r": {"size": 32768, "crc": "E9B03E07"}, + "p7.3b": {"size": 16384, "crc": "A7EB4917"}, + "p8.3d": {"size": 32768, "crc": "9827C14A"}, + "p9.3f": {"size": 32768, "crc": "545C790C"}, + "p10.3h": {"size": 32768, "crc": "EC9BA07E"}, + "p17.4d": {"size": 32768, "crc": "E0DBA976"}, + "p18.2d": {"size": 32768, "crc": "24947D5F"}, + "p19.4b": {"size": 32768, "crc": "9EE59E91"}, + "p20.2b": {"size": 32768, "crc": "5DA7EC1A"}, + "2.2j": {"size": 1024, "crc": "0703A770"}, + "1.1h": {"size": 1024, "crc": "B9BF2C2C"}, + "3.1j": {"size": 1024, "crc": "0A11CDDE"}, + "ampal16l8a-a5004-3.2n": {"size": 260, "crc": "91A9701B"}, + "ampal16l8a-a5004-4.8s": {"size": 260, "crc": "91A9701B"}, + "pal20l8a-a5004-2.6m": {"size": 324, "crc": "0D15F915"}, + "ampal16r6a-a5004-1.6d": {"size": 260, "crc": "91A9701B"} + } + } + }, + { + "game": "Ikari I (J, No Continues)", + "system": "Arcade", + "filename": "ikarijp.zip", + "status": "playable", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "p1.4l": {"size": 16384, "crc": "CDE006BE"}, + "p2.4k": {"size": 32768, "crc": "26948850"}, + "p3.8l": {"size": 16384, "crc": "9BB385F8"}, + "p4.8k": {"size": 32768, "crc": "3A144BCA"}, + "p5.6e": {"size": 16384, "crc": "863448FA"}, + "p6.6f": {"size": 32768, "crc": "9B16AA57"}, + "p11.4m": {"size": 32768, "crc": "5C75EA8F"}, + "p14.2m": {"size": 32768, "crc": "3293FDE4"}, + "p12.4p": {"size": 32768, "crc": "95138498"}, + "p15.2p": {"size": 32768, "crc": "65A61C99"}, + "p13.4r": {"size": 32768, "crc": "315383D7"}, + "p16.2r": {"size": 32768, "crc": "E9B03E07"}, + "p7.3b": {"size": 16384, "crc": "9E88F536"}, + "p8.3d": {"size": 32768, "crc": "75D796D0"}, + "p9.3f": {"size": 32768, "crc": "2C34903B"}, + "p10.3h": {"size": 32768, "crc": "DA9CCC94"}, + "p17.4d": {"size": 32768, "crc": "E0DBA976"}, + "p18.2d": {"size": 32768, "crc": "24947D5F"}, + "p19.4b": {"size": 32768, "crc": "566242EC"}, + "p20.2b": {"size": 32768, "crc": "5DA7EC1A"}, + "2.2j": {"size": 1024, "crc": "0703A770"}, + "1.1h": {"size": 1024, "crc": "B9BF2C2C"}, + "3.1j": {"size": 1024, "crc": "0A11CDDE"}, + "ampal16l8a-a5004-3.2n": {"size": 260, "crc": "91A9701B"}, + "ampal16l8a-a5004-4.8s": {"size": 260, "crc": "91A9701B"}, + "pal20l8a-a5004-2.6m": {"size": 324, "crc": "0D15F915"}, + "ampal16r6a-a5004-1.6d": {"size": 260, "crc": "91A9701B"} + } + } + }, + { + "game": "Ikari I (No Continues)", + "system": "Arcade", + "filename": "ikarinc.zip", + "status": "playable", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "p1.4l": {"size": 16384, "crc": "738FCEC4"}, + "p2.4k": {"size": 32768, "crc": "89F7945A"}, + "p3.8l": {"size": 16384, "crc": "8A9BD1F0"}, + "p4.8k": {"size": 32768, "crc": "F4101CB4"}, + "p5.6e": {"size": 16384, "crc": "863448FA"}, + "p6.6f": {"size": 32768, "crc": "9B16AA57"}, + "p11.4m": {"size": 32768, "crc": "5C75EA8F"}, + "p14.2m": {"size": 32768, "crc": "3293FDE4"}, + "p12.4p": {"size": 32768, "crc": "95138498"}, + "p15.2p": {"size": 32768, "crc": "65A61C99"}, + "p13.4r": {"size": 32768, "crc": "315383D7"}, + "p16.2r": {"size": 32768, "crc": "E9B03E07"}, + "p7.3b": {"size": 16384, "crc": "A7EB4917"}, + "p8.3d": {"size": 32768, "crc": "9827C14A"}, + "p9.3f": {"size": 32768, "crc": "545C790C"}, + "p10.3h": {"size": 32768, "crc": "EC9BA07E"}, + "p17.4d": {"size": 32768, "crc": "E0DBA976"}, + "p18.2d": {"size": 32768, "crc": "24947D5F"}, + "p19.4b": {"size": 32768, "crc": "9EE59E91"}, + "p20.2b": {"size": 32768, "crc": "5DA7EC1A"}, + "2.2j": {"size": 1024, "crc": "0703A770"}, + "1.1h": {"size": 1024, "crc": "B9BF2C2C"}, + "3.1j": {"size": 1024, "crc": "0A11CDDE"}, + "ampal16l8a-a5004-3.2n": {"size": 260, "crc": "91A9701B"}, + "ampal16l8a-a5004-4.8s": {"size": 260, "crc": "91A9701B"}, + "pal20l8a-a5004-2.6m": {"size": 324, "crc": "0D15F915"}, + "ampal16r6a-a5004-1.6d": {"size": 260, "crc": "91A9701B"} + } + } + }, + { + "game": "Ikari 2 Victory Road", + "system": "Arcade", + "filename": "victroad.zip", + "status": "playable", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "a5004-1.6d": {"size": 260, "crc": "311E5AE6"}, + "p1.4p": {"size": 65536, "crc": "E334ACEF"}, + "p3.7k": {"size": 65536, "crc": "BAC745F6"}, + "p4.5e": {"size": 65536, "crc": "E10FB8CC"}, + "p5.5g": {"size": 65536, "crc": "93E5F110"}, + "p7.3b": {"size": 16384, "crc": "2B6ED95B"}, + "p8.3d": {"size": 32768, "crc": "DF7F252A"}, + "p9.3f": {"size": 32768, "crc": "9897BC05"}, + "p10.3h": {"size": 32768, "crc": "ECD3C0EA"}, + "p2.8p": {"size": 65536, "crc": "907FAC83"}, + "p11.4m": {"size": 32768, "crc": "668B25A4"}, + "p14.2m": {"size": 32768, "crc": "A7031D4A"}, + "p12.4p": {"size": 32768, "crc": "F44E95FA"}, + "p15.2p": {"size": 32768, "crc": "120D2450"}, + "p13.4r": {"size": 32768, "crc": "980CA3D8"}, + "p16.2r": {"size": 32768, "crc": "9F820E8A"}, + "p17.4c": {"size": 32768, "crc": "19D4518C"}, + "p18.2c": {"size": 32768, "crc": "D818BE43"}, + "p19.4b": {"size": 32768, "crc": "D64E0F89"}, + "p20.2b": {"size": 32768, "crc": "EDBA0F31"}, + "1.1d": {"size": 4096, "crc": "C71C0011"}, + "1.2d": {"size": 4096, "crc": "C71C0011"}, + "a5004-4.8s": {"size": 260, "crc": "91A9701B"}, + "a6002-2.5r": {"size": 324, "crc": "0D15F915"}, + "a6002-3.2p": {"size": 260, "crc": "91A9701B"}, + "c2.2l": {"size": 1024, "crc": "8FECA424"}, + "c1.1k": {"size": 1024, "crc": "491AB831"}, + "c3.1l": {"size": 1024, "crc": "220076CA"} + } + } + }, + { + "game": "Dogou Souken (Ikari 2 Victory Road (J))", + "system": "Arcade", + "filename": "dogosoke.zip", + "status": "playable", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "p1.4p": {"size": 65536, "crc": "37867AD2"}, + "p3.7k": {"size": 65536, "crc": "173FA571"}, + "p4.5e": {"size": 65536, "crc": "5B43FE9F"}, + "p5.5g": {"size": 65536, "crc": "AAE30CD6"}, + "p7.3b": {"size": 16384, "crc": "51A4EC83"}, + "p8.3d": {"size": 32768, "crc": "D43044F8"}, + "p9.3f": {"size": 32768, "crc": "365ED2D8"}, + "p10.3h": {"size": 32768, "crc": "92579BF3"}, + "p2.8p": {"size": 65536, "crc": "907FAC83"}, + "p11.4m": {"size": 32768, "crc": "668B25A4"}, + "p14.2m": {"size": 32768, "crc": "A7031D4A"}, + "p12.4p": {"size": 32768, "crc": "F44E95FA"}, + "p15.2p": {"size": 32768, "crc": "120D2450"}, + "p13.4r": {"size": 32768, "crc": "980CA3D8"}, + "p16.2r": {"size": 32768, "crc": "9F820E8A"}, + "p17.4c": {"size": 32768, "crc": "19D4518C"}, + "p18.2c": {"size": 32768, "crc": "D818BE43"}, + "p19.4b": {"size": 32768, "crc": "D64E0F89"}, + "p20.2b": {"size": 32768, "crc": "EDBA0F31"}, + "1.1d": {"size": 4096, "crc": "C71C0011"}, + "1.2d": {"size": 4096, "crc": "C71C0011"}, + "c2.2l": {"size": 1024, "crc": "99DC9792"}, + "c1.1k": {"size": 1024, "crc": "10A2CE2B"}, + "c3.1l": {"size": 1024, "crc": "E7213160"} + } + } + }, + { + "game": "Chopper I", + "system": "Arcade", + "filename": "chopperb.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "kk1.8g": {"size": 65536, "crc": "8FA2F839"}, + "kk4.6g": {"size": 65536, "crc": "004F7D9A"}, + "1.9w": {"size": 1024, "crc": "7F07A45C"}, + "3.9u": {"size": 1024, "crc": "15359FC3"}, + "2.9v": {"size": 1024, "crc": "79B50F7D"}, + "kk3.3d": {"size": 65536, "crc": "DBAAFB87"}, + "kk5.8p": {"size": 32768, "crc": "DEFC0987"}, + "kk10.8y": {"size": 65536, "crc": "5CF4D22B"}, + "kk11.8z": {"size": 65536, "crc": "9AF4CAD0"}, + "kk12.8ab": {"size": 65536, "crc": "02FEC778"}, + "kk13.8ac": {"size": 65536, "crc": "2756817D"}, + "kk9.3k": {"size": 32768, "crc": "653C4342"}, + "kk8.3l": {"size": 32768, "crc": "2DA45894"}, + "kk7.3n": {"size": 32768, "crc": "A0EBEBDF"}, + "kk6.3p": {"size": 32768, "crc": "284FAD9E"}, + "kk18.3ab": {"size": 65536, "crc": "6ABBFF36"}, + "kk19.2ad": {"size": 65536, "crc": "5283B4D3"}, + "kk20.3y": {"size": 65536, "crc": "6403DDF2"}, + "kk21.3aa": {"size": 65536, "crc": "9F411940"}, + "kk14.3v": {"size": 65536, "crc": "9BAD9E25"}, + "kk15.3x": {"size": 65536, "crc": "89FAF590"}, + "kk16.3s": {"size": 65536, "crc": "EFB1FB6C"}, + "kk17.3t": {"size": 65536, "crc": "6B7FB0A5"}, + "kk2.3j": {"size": 65536, "crc": "06169AE0"}, + "p-a1.2c": {"size": 260, "crc": "311E5AE6"} + } + } + }, + { + "game": "Chopper I", + "system": "Arcade", + "filename": "legofair.zip", + "status": "good", + "notes": [3], + "verify": { + "type": "zip", + "entries": { + "kk1.4m": {"size": 65536, "crc": "79A485C0"}, + "kk4.8m": {"size": 65536, "crc": "96D3A4D9"}, + "1.1k": {"size": 1024, "crc": "7F07A45C"}, + "2.1l": {"size": 1024, "crc": "15359FC3"}, + "3.2k": {"size": 1024, "crc": "79B50F7D"}, + "kk3.6j": {"size": 65536, "crc": "DBAAFB87"}, + "kk5.3a": {"size": 32768, "crc": "DEFC0987"}, + "kk10.1a": {"size": 65536, "crc": "5CF4D22B"}, + "kk11.1b": {"size": 65536, "crc": "9AF4CAD0"}, + "kk12.1d": {"size": 65536, "crc": "02FEC778"}, + "kk13.1e": {"size": 65536, "crc": "2756817D"}, + "kk9.3g": {"size": 32768, "crc": "653C4342"}, + "kk8.3e": {"size": 32768, "crc": "2DA45894"}, + "kk7.3d": {"size": 32768, "crc": "A0EBEBDF"}, + "kk6.3b": {"size": 32768, "crc": "284FAD9E"}, + "kk18.8m": {"size": 65536, "crc": "6ABBFF36"}, + "kk19.8n": {"size": 65536, "crc": "5283B4D3"}, + "kk20.8p": {"size": 65536, "crc": "6403DDF2"}, + "kk21.8s": {"size": 65536, "crc": "9F411940"}, + "kk14.7p": {"size": 65536, "crc": "9BAD9E25"}, + "kk15.7s": {"size": 65536, "crc": "89FAF590"}, + "kk16.8j": {"size": 65536, "crc": "EFB1FB6C"}, + "kk17.8k": {"size": 65536, "crc": "6B7FB0A5"}, + "kk2.5b": {"size": 65536, "crc": "06169AE0"}, + "p-a1.8b": {"size": 260, "crc": "311E5AE6"}, + "horizon.6h": {"size": 1024, "crc": "EFB5AF2E"}, + "vertical.7h": {"size": 1024, "crc": "EFB5AF2E"} + } + } + }, + { + "game": "Fantasy", + "system": "Arcade", + "filename": "fantasyj.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "prom-8.bpr": {"size": 32, "crc": "1AA9285A"}, + "prom-7.bpr": {"size": 32, "crc": "7A6F7DC3"}, + "fs5jic12.bin": {"size": 4096, "crc": "DD1EAC89"}, + "fs1jic7.bin": {"size": 4096, "crc": "7B8115AE"}, + "fs2jic8.bin": {"size": 4096, "crc": "61531DD1"}, + "fs3jic9.bin": {"size": 4096, "crc": "36A12617"}, + "fs4jic10.bin": {"size": 4096, "crc": "DBF7C347"}, + "fs6jic14.bin": {"size": 4096, "crc": "BF59A33A"}, + "fs7jic15.bin": {"size": 4096, "crc": "CC18428E"}, + "fs8jic16.bin": {"size": 4096, "crc": "AE5BF727"}, + "fs9jic17.bin": {"size": 4096, "crc": "FA6903E2"}, + "fs10ic50.bin": {"size": 4096, "crc": "86A801C3"}, + "fs11ic51.bin": {"size": 4096, "crc": "9DFFF71C"}, + "fs_b_51.bin": {"size": 2048, "crc": "48094EC5"}, + "fs_a_52.bin": {"size": 2048, "crc": "1D0316E8"}, + "fs_c_53.bin": {"size": 2048, "crc": "49FD4AE8"}, + "fs_d_7.bin": {"size": 2048, "crc": "A7EF4CC6"}, + "fs_e_8.bin": {"size": 2048, "crc": "19B8FB3E"}, + "fs_f_11.bin": {"size": 2048, "crc": "3A352E1F"} + } + } + }, + { + "game": "Fantasy", + "system": "Arcade", + "filename": "fantasyu.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "fantasy.ic7": {"size": 32, "crc": "361A5E99"}, + "fantasy.ic6": {"size": 32, "crc": "33D974F7"}, + "ic12.cpu": {"size": 4096, "crc": "22CB2249"}, + "ic07.cpu": {"size": 4096, "crc": "0E2880B6"}, + "ic08.cpu": {"size": 4096, "crc": "4C331317"}, + "ic09.cpu": {"size": 4096, "crc": "6AC1DBFC"}, + "ic10.cpu": {"size": 4096, "crc": "C796A406"}, + "ic14.cpu": {"size": 4096, "crc": "6F1F0698"}, + "ic15.cpu": {"size": 4096, "crc": "5534D57E"}, + "ic16.cpu": {"size": 4096, "crc": "6C2AEB6E"}, + "ic17.cpu": {"size": 4096, "crc": "F6AA5DE1"}, + "fs10ic50.bin": {"size": 4096, "crc": "86A801C3"}, + "fs11ic51.bin": {"size": 4096, "crc": "9DFFF71C"}, + "fs_b_51.bin": {"size": 2048, "crc": "48094EC5"}, + "fs_a_52.bin": {"size": 2048, "crc": "1D0316E8"}, + "fs_c_53.bin": {"size": 2048, "crc": "49FD4AE8"}, + "fs_d_7.bin": {"size": 2048, "crc": "A7EF4CC6"}, + "fs_e_8.bin": {"size": 2048, "crc": "19B8FB3E"}, + "fs_f_11.bin": {"size": 2048, "crc": "3A352E1F"} + } + } + }, + { + "game": "Time Soldiers", + "system": "Arcade", + "filename": "btlfield.zip", + "status": "good", + "notes": [3], + "verify": { + "type": "zip", + "entries": { + "bfv1_03.bin": {"size": 65536, "crc": "8720AF0D"}, + "bfv1_04.bin": {"size": 65536, "crc": "7DCCCBE6"}, + "bf.1": {"size": 65536, "crc": "158F4CB3"}, + "bf.2": {"size": 65536, "crc": "AF01A718"}, + "bfv1_06.bin": {"size": 32768, "crc": "022B9DE9"}, + "bfv1_05.bin": {"size": 32768, "crc": "BE269DBF"}, + "bf.7": {"size": 65536, "crc": "F8B293B5"}, + "bf.8": {"size": 65536, "crc": "8A43497B"}, + "bf.9": {"size": 65536, "crc": "1408416F"}, + "bf.10": {"size": 131072, "crc": "613313BA"}, + "bf.14": {"size": 131072, "crc": "EFDA5C45"}, + "bf.18": {"size": 131072, "crc": "E886146A"}, + "bf.11": {"size": 131072, "crc": "92B42EBA"}, + "bf.15": {"size": 131072, "crc": "BA3B9F5A"}, + "bf.19": {"size": 131072, "crc": "8994BF10"}, + "bf.12": {"size": 131072, "crc": "7CA8BB32"}, + "bf.16": {"size": 131072, "crc": "2AA74125"}, + "bf.20": {"size": 131072, "crc": "BAB6A7C5"}, + "bf.13": {"size": 131072, "crc": "56A3A26A"}, + "bf.17": {"size": 131072, "crc": "6B37D048"}, + "bf.21": {"size": 131072, "crc": "BC3B3944"} + } + } + }, + { + "game": "Time Soldiers", + "system": "Arcade", + "filename": "timesold.zip", + "status": "good", + "notes": [3], + "verify": { + "type": "zip", + "entries": { + "bf.3": {"size": 65536, "crc": "A491E533"}, + "bf.4": {"size": 65536, "crc": "34EBACCC"}, + "bf.1": {"size": 65536, "crc": "158F4CB3"}, + "bf.2": {"size": 65536, "crc": "AF01A718"}, + "bf.6": {"size": 32768, "crc": "086A364D"}, + "bf.5": {"size": 32768, "crc": "3CEC2F55"}, + "bf.7": {"size": 65536, "crc": "F8B293B5"}, + "bf.8": {"size": 65536, "crc": "8A43497B"}, + "bf.9": {"size": 65536, "crc": "1408416F"}, + "bf.10": {"size": 131072, "crc": "613313BA"}, + "bf.14": {"size": 131072, "crc": "EFDA5C45"}, + "bf.18": {"size": 131072, "crc": "E886146A"}, + "bf.11": {"size": 131072, "crc": "92B42EBA"}, + "bf.15": {"size": 131072, "crc": "BA3B9F5A"}, + "bf.19": {"size": 131072, "crc": "8994BF10"}, + "bf.12": {"size": 131072, "crc": "7CA8BB32"}, + "bf.16": {"size": 131072, "crc": "2AA74125"}, + "bf.20": {"size": 131072, "crc": "BAB6A7C5"}, + "bf.13": {"size": 131072, "crc": "56A3A26A"}, + "bf.17": {"size": 131072, "crc": "6B37D048"}, + "bf.21": {"size": 131072, "crc": "BC3B3944"} + } + } + }, + { + "game": "Munch Mobile (Joyful Road)", + "system": "Arcade", + "filename": "mnchmobl.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "m1.10e": {"size": 8192, "crc": "A4BEBC6A"}, + "m2.10d": {"size": 8192, "crc": "F502D466"}, + "f1.1g": {"size": 8192, "crc": "B75411D4"}, + "f2.3g": {"size": 8192, "crc": "539A43BA"}, + "f3.5g": {"size": 8192, "crc": "EC996706"}, + "mu.2j": {"size": 8192, "crc": "420ADBD4"}, + "a2001.clr": {"size": 256, "crc": "1B16B907"}, + "s1.10a": {"size": 4096, "crc": "C0BCC301"}, + "s2.10b": {"size": 4096, "crc": "96AA11CA"}, + "b1.2c": {"size": 4096, "crc": "8CE3A403"}, + "b2.2b": {"size": 4096, "crc": "0DF28913"}, + "h": {"size": 8192, "crc": "332584DE"} + } + } + }, + { + "game": "Munch Mobile (Joyful Road)", + "system": "Arcade", + "filename": "joyfulr.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "m1j.10e": {"size": 8192, "crc": "1FE86E25"}, + "m2j.10d": {"size": 8192, "crc": "B144B9A6"}, + "f1j.1g": {"size": 8192, "crc": "93C3C17E"}, + "f2j.3g": {"size": 8192, "crc": "B3FB5BD2"}, + "f3j.5g": {"size": 8192, "crc": "772A7527"}, + "mu.2j": {"size": 8192, "crc": "420ADBD4"}, + "a2001.clr": {"size": 256, "crc": "1B16B907"}, + "s1.10a": {"size": 4096, "crc": "C0BCC301"}, + "s2.10b": {"size": 4096, "crc": "96AA11CA"}, + "b1.2c": {"size": 4096, "crc": "8CE3A403"}, + "b2.2b": {"size": 4096, "crc": "0DF28913"}, + "h": {"size": 8192, "crc": "332584DE"} + } + } + }, + { + "game": "Sasuke vs. Commander", + "system": "Arcade", + "filename": "sasuke.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "sc1": {"size": 2048, "crc": "34CBBE03"}, + "sc2": {"size": 2048, "crc": "38CC14F0"}, + "sc3": {"size": 2048, "crc": "54C41285"}, + "sc4": {"size": 2048, "crc": "23EDAFCF"}, + "sc5": {"size": 2048, "crc": "CA410E4F"}, + "sc6": {"size": 2048, "crc": "80406AFB"}, + "sc7": {"size": 2048, "crc": "04D0F104"}, + "sc8": {"size": 2048, "crc": "0219104B"}, + "sc9": {"size": 2048, "crc": "D6FF889A"}, + "sc10": {"size": 2048, "crc": "19DF6B9A"}, + "mcs_c": {"size": 2048, "crc": "AFF9743D"}, + "mcs_d": {"size": 2048, "crc": "9C805120"}, + "sasuke.clr": {"size": 32, "crc": "B70F34C1"}, + "sc11": {"size": 2048, "crc": "24A0E121"} + } + } + }, + { + "game": "Ozma Wars", + "system": "Arcade", + "filename": "ozmawars.zip", + "status": "playable", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "mw01": {"size": 2048, "crc": "31F4397D"}, + "mw02": {"size": 2048, "crc": "D8E77C62"}, + "mw03": {"size": 2048, "crc": "3BFA418F"}, + "mw04": {"size": 2048, "crc": "E190CE6C"}, + "mw05": {"size": 2048, "crc": "3BC7D4C7"}, + "mw06": {"size": 2048, "crc": "99CA2EAE"}, + "01.1": {"size": 1024, "crc": "AAC24F34"}, + "02.2": {"size": 1024, "crc": "2BDF83A0"} + } + } + }, + { + "game": "Paddle Mania", + "system": "Arcade", + "filename": "paddlema.zip", + "status": "playable", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "padlem.a": {"size": 256, "crc": "CAE6BCD6"}, + "padlem.b": {"size": 256, "crc": "B6DF8DCB"}, + "padlem.c": {"size": 256, "crc": "39CA9B86"}, + "padlem.17j": {"size": 1024, "crc": "86170069"}, + "padlem.16j": {"size": 1024, "crc": "8DA58E2C"}, + "padlem.18c": {"size": 65536, "crc": "9269778D"}, + "padlem.18n": {"size": 32768, "crc": "06506200"}, + "padlem.6g": {"size": 65536, "crc": "C227A6E8"}, + "padlem.3g": {"size": 65536, "crc": "F11A21AA"}, + "padlem.6h": {"size": 65536, "crc": "8897555F"}, + "padlem.3h": {"size": 65536, "crc": "F0FE9B9D"}, + "padlem.9m": {"size": 65536, "crc": "4EE4970D"}, + "padlem.16m": {"size": 65536, "crc": "0984FB4D"}, + "padlem.9n": {"size": 65536, "crc": "A1756F15"}, + "padlem.16n": {"size": 65536, "crc": "4249E047"}, + "padlem.6m": {"size": 65536, "crc": "3F47910C"}, + "padlem.13m": {"size": 65536, "crc": "FD9DBC27"}, + "padlem.6n": {"size": 65536, "crc": "FE337655"}, + "padlem.13n": {"size": 65536, "crc": "1D460486"} + } + } + }, + { + "game": "World Wars (J)", + "system": "Arcade", + "filename": "bermudata.zip", + "status": "playable", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "wwu4.4p": {"size": 65536, "crc": "4DE39D01"}, + "wwu5.8p": {"size": 65536, "crc": "76158E94"}, + "wwu3.7k": {"size": 65536, "crc": "C79134A8"}, + "wwu6.3a": {"size": 32768, "crc": "A0E6710C"}, + "ww11.1e": {"size": 65536, "crc": "603DDCB5"}, + "ww12.1d": {"size": 65536, "crc": "388093FF"}, + "ww13.1b": {"size": 65536, "crc": "83A7EF62"}, + "ww14.1a": {"size": 65536, "crc": "04C784BE"}, + "ww10.3g": {"size": 32768, "crc": "F68A2D51"}, + "ww9.3e": {"size": 32768, "crc": "D9D35911"}, + "ww8.3d": {"size": 32768, "crc": "0EC15086"}, + "ww7.3b": {"size": 32768, "crc": "53C4B24E"}, + "ww21.7p": {"size": 65536, "crc": "BE974FBE"}, + "ww22.7s": {"size": 65536, "crc": "9914972A"}, + "ww19.8h": {"size": 65536, "crc": "C39AC1A7"}, + "ww20.8k": {"size": 65536, "crc": "8504170F"}, + "ww15.8m": {"size": 65536, "crc": "D55CE063"}, + "ww16.8n": {"size": 65536, "crc": "A2D19CE5"}, + "ww17.8p": {"size": 65536, "crc": "A9A6B128"}, + "ww18.8s": {"size": 65536, "crc": "C712D24C"}, + "horizon.5h": {"size": 1024, "crc": "EFB5AF2E"}, + "vertical.7h": {"size": 1024, "crc": "EFB5AF2E"}, + "u2bt.2l": {"size": 1024, "crc": "23CE9707"}, + "u1bt.1k": {"size": 1024, "crc": "1E8FC4C3"}, + "u3bt.1l": {"size": 1024, "crc": "26CAF985"} + } + } + }, + { + "game": "World Wars", + "system": "Arcade", + "filename": "worldwar.zip", + "status": "playable", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "ww4.4p": {"size": 65536, "crc": "BC29D09F"}, + "ww5.8p": {"size": 65536, "crc": "8DC15909"}, + "ww3.7k": {"size": 65536, "crc": "8B74C951"}, + "ww6.3a": {"size": 32768, "crc": "D57570AB"}, + "ww11.1e": {"size": 65536, "crc": "603DDCB5"}, + "ww12.1d": {"size": 65536, "crc": "388093FF"}, + "ww13.1b": {"size": 65536, "crc": "83A7EF62"}, + "ww14.1a": {"size": 65536, "crc": "04C784BE"}, + "ww10.3g": {"size": 32768, "crc": "F68A2D51"}, + "ww9.3e": {"size": 32768, "crc": "D9D35911"}, + "ww8.3d": {"size": 32768, "crc": "0EC15086"}, + "ww7.3b": {"size": 32768, "crc": "53C4B24E"}, + "ww21.7p": {"size": 65536, "crc": "BE974FBE"}, + "ww22.7s": {"size": 65536, "crc": "9914972A"}, + "ww19.8h": {"size": 65536, "crc": "C39AC1A7"}, + "ww20.8k": {"size": 65536, "crc": "8504170F"}, + "ww15.8m": {"size": 65536, "crc": "D55CE063"}, + "ww16.8n": {"size": 65536, "crc": "A2D19CE5"}, + "ww17.8p": {"size": 65536, "crc": "A9A6B128"}, + "ww18.8s": {"size": 65536, "crc": "C712D24C"}, + "horizon.5h": {"size": 1024, "crc": "EFB5AF2E"}, + "vertical.7h": {"size": 1024, "crc": "EFB5AF2E"}, + "2.1l": {"size": 1024, "crc": "5E1616B2"}, + "1.1k": {"size": 1024, "crc": "B88E95F0"}, + "3.2l": {"size": 1024, "crc": "E9770796"}, + "p4.5e": {"size": 65536, "crc": "4BC83229"}, + "p5.5g": {"size": 65536, "crc": "817BD62C"} + } + } + }, + { + "game": "Bermuda Triangle", + "system": "Arcade", + "filename": "bermudat.zip", + "status": "playable", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "p1.4p": {"size": 65536, "crc": "43DEC5E9"}, + "p3.7k": {"size": 65536, "crc": "53A82E50"}, + "p4.5e": {"size": 65536, "crc": "4BC83229"}, + "p5.5g": {"size": 65536, "crc": "817BD62C"}, + "p9.3b": {"size": 32768, "crc": "8FFDF969"}, + "p8.3d": {"size": 32768, "crc": "268D10DF"}, + "p7.3e": {"size": 32768, "crc": "3E39E9DD"}, + "p6.3g": {"size": 32768, "crc": "BF56DA61"}, + "p11.7p": {"size": 65536, "crc": "AAE7410E"}, + "p12.7s": {"size": 65536, "crc": "18914F70"}, + "p13.8h": {"size": 65536, "crc": "CD79CE81"}, + "p14.8k": {"size": 65536, "crc": "EDC57117"}, + "p15.8m": {"size": 65536, "crc": "448BF9F4"}, + "p16.8n": {"size": 65536, "crc": "119999EB"}, + "p17.8p": {"size": 65536, "crc": "B5462139"}, + "p18.8s": {"size": 65536, "crc": "CB416227"}, + "p19.1": {"size": 65536, "crc": "8DAF7DF4"}, + "p20.1b": {"size": 65536, "crc": "B7689599"}, + "p21.1d": {"size": 65536, "crc": "AB6217B7"}, + "p22.1e": {"size": 65536, "crc": "8ED759A0"}, + "2.1l": {"size": 1024, "crc": "BAAC139E"}, + "1.1k": {"size": 1024, "crc": "F4B54D06"}, + "3.2l": {"size": 1024, "crc": "2EDF2E0B"}, + "p10.3a": {"size": 32768, "crc": "D3650211"}, + "p2.8p": {"size": 65536, "crc": "0E193265"}, + "horizon.6h": {"size": 1024, "crc": "EFB5AF2E"}, + "vertical.7h": {"size": 1024, "crc": "EFB5AF2E"} + } + } + }, + { + "game": "Bermuda Triangle", + "system": "Arcade", + "filename": "bermudatj.zip", + "status": "playable", + "notes": [2], + "verify": { + "type": "zip", + "entries": { + "p1.4p": {"size": 65536, "crc": "EDA75F36"}, + "p3.7k": {"size": 65536, "crc": "FEA8A096"}, + "p4.5e": {"size": 65536, "crc": "B2E01129"}, + "p5.5g": {"size": 65536, "crc": "924C24F7"}, + "p9.3b": {"size": 32768, "crc": "8FFDF969"}, + "p8.3d": {"size": 32768, "crc": "268D10DF"}, + "p7.3e": {"size": 32768, "crc": "3E39E9DD"}, + "p6.3g": {"size": 32768, "crc": "BF56DA61"}, + "p11.7p": {"size": 65536, "crc": "AAE7410E"}, + "p12.7s": {"size": 65536, "crc": "18914F70"}, + "p13.8h": {"size": 65536, "crc": "CD79CE81"}, + "p14.8k": {"size": 65536, "crc": "EDC57117"}, + "p15.8m": {"size": 65536, "crc": "448BF9F4"}, + "p16.8n": {"size": 65536, "crc": "119999EB"}, + "p17.8p": {"size": 65536, "crc": "B5462139"}, + "p18.8s": {"size": 65536, "crc": "CB416227"}, + "p19.1": {"size": 65536, "crc": "8DAF7DF4"}, + "p20.1b": {"size": 65536, "crc": "B7689599"}, + "p21.1d": {"size": 65536, "crc": "AB6217B7"}, + "p22.1e": {"size": 65536, "crc": "8ED759A0"}, + "2.1l": {"size": 1024, "crc": "BAAC139E"}, + "1.1k": {"size": 1024, "crc": "F4B54D06"}, + "3.2l": {"size": 1024, "crc": "2EDF2E0B"}, + "p10.3a": {"size": 32768, "crc": "D3650211"}, + "p2.8p": {"size": 65536, "crc": "0E193265"}, + "horizon.6h": {"size": 1024, "crc": "EFB5AF2E"}, + "vertical.7h": {"size": 1024, "crc": "EFB5AF2E"} + } + } + }, + { + "game": "MarvinsMaze", + "system": "Arcade", + "filename": "marvins.zip", + "status": "good", + "notes": [], + "verify": { + "type": "zip", + "entries": { + "pa1": {"size": 8192, "crc": "0008D791"}, + "pa2": {"size": 8192, "crc": "9457003C"}, + "pa3": {"size": 8192, "crc": "54C33ECB"}, + "pb1": {"size": 8192, "crc": "3B6941A5"}, + "m1": {"size": 8192, "crc": "2314C696"}, + "m2": {"size": 8192, "crc": "74BA5799"}, + "b2": {"size": 8192, "crc": "E528BC60"}, + "b1": {"size": 8192, "crc": "E528BC60"}, + "f1": {"size": 8192, "crc": "0BD6B4E5"}, + "f2": {"size": 8192, "crc": "8FC2B081"}, + "f3": {"size": 8192, "crc": "E55C9B83"}, + "s1": {"size": 8192, "crc": "327F70F3"}, + "marvmaze.j2": {"size": 1024, "crc": "D2B25665"}, + "marvmaze.j1": {"size": 1024, "crc": "92F5B06D"}, + "marvmaze.j3": {"size": 1024, "crc": "DF9E6005"} + } + } + }, + { + "game": "Alpha Mission", + "system": "NES", + "filename": "ASO.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 65552, + "crc": "02E67223" + } + }, + { + "game": "Alpha Mission", + "system": "NES", + "filename": "ASO_jp.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 65552, + "crc": "3AFDB6EE" + } + }, + { + "game": "Athena", + "system": "NES", + "filename": "Athena.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 131088, + "crc": "14D42113" + } + }, + { + "game": "Athena", + "system": "NES", + "filename": "Athena_jp.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 131088, + "crc": "B8C436AE" + } + }, + { + "game": "Crystalis", + "system": "NES", + "filename": "Crystalis.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 393232, + "crc": "B305C8EC" + } + }, + { + "game": "Crystalis", + "system": "NES", + "filename": "Crystalis_jp.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 393232, + "crc": "33739A62" + } + }, + { + "game": "Guerrilla War", + "system": "NES", + "filename": "GuerrillaWar.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 262160, + "crc": "005FF9A8" + } + }, + { + "game": "Guerrilla War", + "system": "NES", + "filename": "GuerrillaWar_jp.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 262160, + "crc": "0E77C00C" + } + }, + { + "game": "Ikari Warriors", + "system": "NES", + "filename": "Ikari.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 131088, + "crc": "EED05076" + } + }, + { + "game": "Ikari Warriors", + "system": "NES", + "filename": "Ikari_jp.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 131088, + "crc": "68B0CFDC" + } + }, + { + "game": "Ikari II: Victory Road", + "system": "NES", + "filename": "Ikari2.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 262160, + "crc": "1EAF333C" + } + }, + { + "game": "Ikari II: Victory Road", + "system": "NES", + "filename": "Ikari2_jp.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 262160, + "crc": "8355C1DF" + } + }, + { + "game": "Ikari III: The Rescue", + "system": "NES", + "filename": "Ikari3.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 262160, + "crc": "3BCD370E" + } + }, + { + "game": "Ikari III: The Rescue", + "system": "NES", + "filename": "Ikari3_jp.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 262160, + "crc": "9A6120AF" + } + }, + { + "game": "Iron Tank", + "system": "NES", + "filename": "IronTank.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 262160, + "crc": "DCFD85FC" + } + }, + { + "game": "Iron Tank", + "system": "NES", + "filename": "IronTank_jp.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 262160, + "crc": "7104EF6C" + } + }, + { + "game": "P.O.W", + "system": "NES", + "filename": "POW.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 262160, + "crc": "18967EA6" + } + }, + { + "game": "P.O.W", + "system": "NES", + "filename": "POW_jp.nes", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "size": 262160, + "crc": "5BB9899A" + } + } + ], + "notes": { + "1": "This is not extracted as there are missing files, such as Missing PROMs. Add '--prop include-partials=True' to include these.", + "2": "This is playable, but is a bad dump, 1+ files with a bad CRC, and/or 1+ files with empty placeholders.", + "3": "This requires MAME 0.139 to play." + } + } +} \ No newline at end of file diff --git a/src/gex/lib/tasks/impl/snk40/partials.py b/src/gex/lib/tasks/impl/snk40/partials.py deleted file mode 100644 index c4ad3ae..0000000 --- a/src/gex/lib/tasks/impl/snk40/partials.py +++ /dev/null @@ -1,72 +0,0 @@ -'''Extraction code for incomplete ROMs''' -import logging -from gex.lib.tasks import helpers -from gex.lib.tasks.impl.snk40 import utils - -logger = logging.getLogger('gextoolbox') - -out_file_info = [ - { - "game": "Bermuda Triangle/World Wars", - "system": "Arcade", - "filename": "partial-bermudatriangle-worldwar.zip", - "status": "partial", - "notes": [4] - } -] - - -def extract(bundle_contents): - '''Extract all partial ROMs''' - out_files = [] - - out_files.extend(_handle_btww_all(bundle_contents['patch'])) - - return out_files - - -def _handle_btww_all(bundle_contents): - '''Extract Bermuda Triangle / World Wars''' - out_files = [] - - target_files = [ - "BermudaTriangle.0.z80", - "BermudaTriangle.1.z80", - "BermudaTriangle.2.z80", - "BermudaTriangle.adpcm", - "BermudaTriangle.bg", - "BermudaTriangle.j.0.z80", - "BermudaTriangle.j.2.z80", - "BermudaTriangle.j.adpcm", - "BermudaTriangle.pal", - "BermudaTriangle.sp", - "BermudaTriangle.sp32", - "BermudaTriangle.tx", - "WorldWars.0.z80", - "WorldWars.1.z80", - "WorldWars.2.z80", - "WorldWars.adpcm", - "WorldWars.bg", - "WorldWars.j.0.z80", - "WorldWars.j.1.z80", - "WorldWars.j.2.z80", - "WorldWars.j.pal", - "WorldWars.j.tx", - "WorldWars.pal", - "WorldWars.sp", - "WorldWars.sp32", - "WorldWars.tx" - ] - - zip_files = {} - for target_file in target_files: - zip_files[target_file] = bundle_contents[target_file] - - archive_name = "partial-bermudatriangle-worldwar.zip" - logger.info(f"Building {archive_name}...") - out_files.append( - {'filename': archive_name, 'contents': helpers.build_zip(zip_files)} - ) - logger.info(f"Extracted {archive_name}.") - - return out_files diff --git a/src/gex/lib/tasks/impl/wonderboy3.py b/src/gex/lib/tasks/impl/wonderboy3.py deleted file mode 100644 index 1e0679d..0000000 --- a/src/gex/lib/tasks/impl/wonderboy3.py +++ /dev/null @@ -1,51 +0,0 @@ -'''Implementation of wonderboy3: Wonder Boy The Dragon's Trap''' -import shutil -import logging -import os -from gex.lib.tasks.basetask import BaseTask -from gex.lib.tasks import helpers - -logger = logging.getLogger('gextoolbox') - -class BubsyTask(BaseTask): - '''Implements wonderboy3: Wonder Boy The Dragon's Trap''' - _task_name = "wonderboy3" - _title = "Wonder Boy The Dragon's Trap" - _details_markdown = ''' -This is just sitting in the install folder. - -Note that the white box instead of the Sega logo is an intentional change for this release. - ''' - _default_input_folder = helpers.gen_steam_app_default_folder("Wonder Boy The Dragon's Trap") - _input_folder_desc = "Wonder Boy The Dragon's Trap Steam Folder" - - _game_info_map = { - 'wb3.sms': { - 'filename': 'Wonder Boy 3.sms', - 'name': 'Wonder Boy 3' - }, - } - - def __init__(self): - super().__init__() - self._out_file_list = map(lambda x: { - 'filename': x['filename'], - 'game': x['name'], - 'status': "good", - 'system': "SMS", - "notes": []}, - self._game_info_map.values()) - - def execute(self, in_dir, out_dir): - file_path = os.path.join(in_dir, 'bin_pc\\rom\\wb3.sms') - file_name = os.path.basename(file_path) - game_info = self._game_info_map.get(file_name) - if game_info is not None: - display_name = game_info['name'] - logger.info(f"Copying {file_name}: {display_name}") - try: - shutil.copyfile(file_path, os.path.join(out_dir, game_info['filename'])) - except OSError as error: - logger.warning(f'Error while processing {file_path}!') - logger.warning(error) - logger.info("Processing complete.") diff --git a/src/gex/lib/tasks/impl/wonderboy3/__init__.py b/src/gex/lib/tasks/impl/wonderboy3/__init__.py new file mode 100644 index 0000000..9b09328 --- /dev/null +++ b/src/gex/lib/tasks/impl/wonderboy3/__init__.py @@ -0,0 +1,15 @@ +'''Implementation of wonderboy3: Wonder Boy The Dragon's Trap''' +from gex.lib.tasks.copytask import CopyTask +from gex.lib.tasks import helpers + +class WonderBoyTask(CopyTask): + '''Implements wonderboy3: Wonder Boy The Dragon's Trap''' + _task_name = "wonderboy3" + _title = "Wonder Boy The Dragon's Trap" + _details_markdown = ''' +This is just sitting in the install folder. + +Note that the white box instead of the Sega logo is an intentional change for this release. + ''' + _default_input_folder = helpers.gen_steam_app_default_folder("Wonder Boy The Dragon's Trap") + _input_folder_desc = "Wonder Boy The Dragon's Trap Steam Folder" diff --git a/src/gex/lib/tasks/impl/wonderboy3/metadata.json b/src/gex/lib/tasks/impl/wonderboy3/metadata.json new file mode 100644 index 0000000..891a308 --- /dev/null +++ b/src/gex/lib/tasks/impl/wonderboy3/metadata.json @@ -0,0 +1,34 @@ +{ + "in": { + "files": { + "wonderboy3": { + "rel_path": ["bin_pc", "rom"], + "filename": "wb3.sms", + "copy_to": "Wonder Boy 3", + "versions": { + "Steam": { + "crc": "525F4F3D", + "size": 262144 + } + } + } + } + }, + "out": { + "files": [ + { + "game": "Wonder Boy 3", + "system": "SMS", + "filename": "Wonder Boy 3.sms", + "status": "good", + "notes": [], + "verify": { + "type": "crc", + "crc": "525F4F3D", + "size": 262144 + } + } + ], + "notes": {} + } +} \ No newline at end of file diff --git a/src/gex/lib/tasks/impl/zamn.py b/src/gex/lib/tasks/impl/zamn.py deleted file mode 100644 index 4adb05c..0000000 --- a/src/gex/lib/tasks/impl/zamn.py +++ /dev/null @@ -1,110 +0,0 @@ -'''Implementation of zamn: Zombies Ate My Neighbors and Ghoul Patrol''' -import logging -import os -from gex.lib.tasks.basetask import BaseTask -from gex.lib.utils.blob import hash as hash_helper - -logger = logging.getLogger('gextoolbox') - -class ZAMNTask(BaseTask): - '''Implements zamn: Zombies Ate My Neighbors and Ghoul Patrol''' - _task_name = "zamn" - _title = "Zombies Ate My Neighbors and Ghoul Patrol" - _details_markdown = ''' -Based on: https://www.gog.com/forum/general/rom_based_gog_games_compatible_with_third_party_emulators_thread/post127 - -These ROMs are pulled out of the main executable. - ''' - _default_input_folder = r"C:\Program Files (x86)\GOG Galaxy\Games\Zombies Ate My Neighbour & Ghoul Patrol" - _input_folder_desc = "ZAMN folder" - - _game_info_map = [ - { - "name": "Zombies Ate My Neighbor", - "length": 1024*1024, - "check_offsets": [ - 0x1b0974c, # Steam 1.0 - 0x1b0bd4c, # Steam 1.1 - 0x1b0654c, # GOG 1.0 - 0x1b0894c, # GOG 1.1 - ], - "header_bytes": "02 FE C2 10 E2 20 A2 00 00 9B", - "crc": 0x7cfc0c7c, - "filename": "ZombiesAteMyNeighbor.sfc" - }, - { - "name": "Ghoul Patrol", - "length": 1024*1024, - "check_offsets": [ - 0x19a03c0, # Steam 1.0 - 0x19a29c0, # Steam 1.1 - 0x199d1c0, # GOG 1.0 - 0x199f5c0, # GOG 1.1 - ], - "header_bytes": "80 FE C2 10 E2 20 A2 00 00 9B", - "crc": 0xea16b5a2, - "filename": "GhoulPatrol.sfc" - } - ] - _out_file_notes = {} - - def __init__(self): - super().__init__() - self._out_file_list = map(lambda x: { - 'filename': x['filename'], - 'game': f"{x['name']}", - 'system': "SNES", - 'status': 'good', - "notes": []}, - self._game_info_map) - self._out_file_notes = {} - - def execute(self, in_dir, out_dir): - exe_path = os.path.join(in_dir, "ZAMN_GP.exe") - with open(exe_path, 'rb') as exe_file: - exe_data = exe_file.read() - - for game in self._game_info_map: - game_data = None - game_header = bytes.fromhex(game['header_bytes']) - logger.info(f"Finding {game['name']}...") - - # Try check_offsets - logger.info(f"Finding {game['name']} via known offsets...") - for check_offset in game['check_offsets']: - check_header = exe_data[check_offset:check_offset+10] - if check_header == game_header: - logger.info(f"Found header at {hex(check_offset)}!") - game_data = exe_data[check_offset:check_offset+game['length']] - crc = hash_helper.get_crc(game_data) - if crc == hex(game['crc']): - logger.info(f"Found crc match at {hex(check_offset)}!") - break - else: - logger.info(f"False header match at {hex(check_offset)}!") - game_data = None - - # Do the manual search - if not game_data: - logger.info(f"Finding {game['name']} via full search - please wait...") - for offset in range(0, len(exe_data) - game['length']): - check_header = exe_data[offset:offset+10] - if check_header == game_header: - logger.info(f"Found header at {hex(offset)}!") - game_data = exe_data[offset:offset+game['length']] - crc = hash_helper.get_crc(game_data) - if crc == hex(game['crc']): - logger.info(f"Found crc match at {hex(offset)}!") - break - else: - logger.info(f"False header match at {hex(offset)}!") - game_data = None - - if game_data: - logger.info(f"Saving {game['filename']}...") - with open(os.path.join(out_dir, game['filename']), "wb") as out_file: - out_file.write(game_data) - else: - logger.warning(f"Game {game['name']} not found!") - - logger.info("Processing complete.") diff --git a/src/gex/lib/tasks/impl/zamn/__init__.py b/src/gex/lib/tasks/impl/zamn/__init__.py new file mode 100644 index 0000000..b749035 --- /dev/null +++ b/src/gex/lib/tasks/impl/zamn/__init__.py @@ -0,0 +1,88 @@ +'''Implementation of zamn: Zombies Ate My Neighbors and Ghoul Patrol''' +import logging +import os +from gex.lib.tasks.basetask import BaseTask +from gex.lib.utils.blob import hash as hash_helper + +logger = logging.getLogger('gextoolbox') + +class ZAMNTask(BaseTask): + '''Implements zamn: Zombies Ate My Neighbors and Ghoul Patrol''' + _task_name = "zamn" + _title = "Zombies Ate My Neighbors and Ghoul Patrol" + _details_markdown = ''' +Based on: https://www.gog.com/forum/general/rom_based_gog_games_compatible_with_third_party_emulators_thread/post127 + +These ROMs are pulled out of the main executable. + ''' + _default_input_folder = r"C:\Program Files (x86)\GOG Galaxy\Games\Zombies Ate My Neighbour & Ghoul Patrol" + _input_folder_desc = "ZAMN folder" + + def get_out_file_info(self): + '''Return a list of output files''' + return { + "files": self._metadata['out']['files'], + "notes": self._metadata['out']['notes'] + } + + def execute(self, in_dir, out_dir): + zamngp_file = self.read_all_datafiles(in_dir).get("zamngp") + exe_data = zamngp_file['contents'] + file_ver = zamngp_file['version'] + if file_ver is not None: + logger.info(f"Found {file_ver}...") + + for game in self._metadata['out']['files']: + game_data = None + game_header = bytes.fromhex(game['extract']['header_bytes']) + target_size = game['extract']['length'] + + if file_ver is not None: + logger.info(f"Pulling {game['game']} from known offset...") + version_info = game['extract']['versions'][file_ver] + start = int(version_info['start'], 16) + game_data = exe_data[start:start+target_size] + else: + logger.info(f"Finding {game['game']}...") + + # Try check_offsets + logger.info(f"Finding {game['game']} via known offsets...") + for version_info in game['extract']['versions'].values(): + check_offset = int(version_info['start'], 16) + check_header = exe_data[check_offset:check_offset+10] + if check_header == game_header: + logger.info(f"Found header at {hex(check_offset)}!") + game_data = exe_data[check_offset:check_offset+target_size] + crc = hash_helper.get_crc(game_data)[2:].upper().rjust(8, "0") + if crc == game['verify']['crc']: + logger.info(f"Found crc match at {hex(check_offset)}!") + break + else: + logger.info(f"False header match at {hex(check_offset)}!") + game_data = None + + # Do the manual search + if not game_data: + logger.info(f"Finding {game['game']} via full search - please wait...") + for offset in range(0, len(exe_data) - target_size): + check_header = exe_data[offset:offset+10] + if check_header == game_header: + logger.info(f"Found header at {hex(offset)}!") + game_data = exe_data[offset:offset+target_size] + crc = hash_helper.get_crc(game_data)[2:].upper().rjust(8, "0") + if crc == game['verify']['crc']: + logger.info(f"Found crc match at {hex(offset)}!") + break + else: + logger.info(f"False header match at {hex(offset)}!") + game_data = None + + if game_data: + _ = self.verify_out_file(game['filename'], game_data) + logger.info(f"Saving {game['filename']}...") + with open(os.path.join(out_dir, game['filename']), "wb") as out_file: + out_file.write(game_data) + else: + logger.warning(f"Game {game['game']} not found!") + + logger.info("Processing complete.") diff --git a/src/gex/lib/tasks/impl/zamn/metadata.json b/src/gex/lib/tasks/impl/zamn/metadata.json new file mode 100644 index 0000000..c6f118b --- /dev/null +++ b/src/gex/lib/tasks/impl/zamn/metadata.json @@ -0,0 +1,67 @@ +{ + "in": { + "files": { + "zamngp": { + "filename": "ZAMN_GP.exe", + "versions": { + "Steam1.1": { + "sha": "f6a9bdf8da5bc107307ea80a5813dfe413b0599f" + }, + "GOG1.1": { + "crc": "753DE8C8", + "size": 44352432 + } + } + } + } + }, + "out": { + "files": [ + { + "game": "Zombies Ate My Neighbor", + "system": "SNES", + "filename": "ZombiesAteMyNeighbor.sfc", + "status": "good", + "notes": [], + "extract": { + "versions": { + "Steam1.0": { "start": "0x1B0974C" }, + "Steam1.1": { "start": "0x1B0BD4C" }, + "GOG1.0": { "start": "0x1B0654C" }, + "GOG1.1": { "start": "0x1B0894C" } + }, + "length": 1048576, + "header_bytes": "02 FE C2 10 E2 20 A2 00 00 9B" + }, + "verify": { + "type": "crc", + "crc": "7CFC0C7C", + "size": 1048576 + } + }, + { + "game": "Ghoul Patrol", + "system": "SNES", + "filename": "GhoulPatrol.sfc", + "status": "good", + "notes": [], + "extract": { + "versions": { + "Steam1.0": { "start": "0x19A03C0" }, + "Steam1.1": { "start": "0x19A29C0" }, + "GOG1.0": { "start": "0x199D1C0" }, + "GOG1.1": { "start": "0x199F5C0" } + }, + "length": 1048576, + "header_bytes": "80 FE C2 10 E2 20 A2 00 00 9B" + }, + "verify": { + "type": "crc", + "crc": "EA16B5A2", + "size": 1048576 + } + } + ], + "notes": {} + } +} \ No newline at end of file diff --git a/src/gex/lib/tasks/splicetask.py b/src/gex/lib/tasks/splicetask.py new file mode 100644 index 0000000..ca827a3 --- /dev/null +++ b/src/gex/lib/tasks/splicetask.py @@ -0,0 +1,41 @@ +'''Implementation of basic splice task''' +import logging +import os +from gex.lib.tasks.basetask import BaseTask + +logger = logging.getLogger('gextoolbox') + +class SpliceTask(BaseTask): + '''Implements basic splice task''' + + def get_out_file_info(self): + '''Return a list of output files''' + return { + "files": self._metadata['out']['files'], + "notes": self._metadata['out']['notes'] + } + + def execute(self, in_dir, out_dir): + '''Splice out the ROM files''' + resolved_file = self.read_datafile(in_dir, self._metadata['in']['files']['source']) + source_data = resolved_file['contents'] + + extractable_roms = [x for x in self._metadata['out']['files'] if x['status'] != 'no-rom'] + for file_meta in extractable_roms: + logger.info(f"Extracting {file_meta['game']}...") + game_data = bytearray() + if 'header' in file_meta: + game_data.extend(bytearray.fromhex(file_meta['header'])) + + for section in file_meta['sections'].values(): + start = int(section['start'], 16) + length = int(section['length'], 16) + game_data.extend(source_data[start:start+length]) + + filename = file_meta['filename'] + _ = self.verify_out_file(filename, game_data) + out_path = os.path.join(out_dir, filename) + with open(out_path, "wb") as out_file: + out_file.write(game_data) + + logger.info("Processing complete.") diff --git a/src/gex/lib/tasks/zipsplicetask.py b/src/gex/lib/tasks/zipsplicetask.py new file mode 100644 index 0000000..a3469f9 --- /dev/null +++ b/src/gex/lib/tasks/zipsplicetask.py @@ -0,0 +1,53 @@ +'''Implementation of basic zip splice task (for arcade ROMs, primarily)''' +import logging +import os +from gex.lib.tasks.basetask import BaseTask +from gex.lib.tasks import helpers +from gex.lib.utils.blob import transforms + +logger = logging.getLogger('gextoolbox') + +class ZipSpliceTask(BaseTask): + '''Implements basic zip splice task (for arcade ROMs, primarily)''' + + def get_out_file_info(self): + '''Return a list of output files''' + return { + "files": self._metadata['out']['files'], + "notes": self._metadata['out']['notes'] + } + + def execute(self, in_dir, out_dir): + '''Splice out the ROM files''' + resolved_file = self.read_datafile(in_dir, self._metadata['in']['files']['source']) + source_data = resolved_file['contents'] + + extractable_roms = [x for x in self._metadata['out']['files'] if x['status'] != 'no-rom'] + for file_meta in extractable_roms: + logger.info(f"Extracting {file_meta['game']}...") + zip_files = {} + + for filename, section in file_meta['zip_files'].items(): + if section.get('type') == 'placeholder': + length = int(section['length'], 16) + file_content = bytearray(b'\x00' * length) + else: + start = int(section['start'], 16) + length = int(section['length'], 16) + file_content = transforms.cut(source_data, start, length=length) + + patches = section.get('patch') + if patches and len(patches.keys()) > 0: + for loc, data in patches.items(): + file_content[int(loc)] = data.to_bytes(1, 'little')[0] + + zip_files[filename] = file_content + + game_data = helpers.build_zip(zip_files) + filename = file_meta['filename'] + _ = self.verify_out_file(filename, game_data) + out_path = os.path.join(out_dir, filename) + with open(out_path, "wb") as out_file: + out_file.write(game_data) + + logger.info("Processing complete.") diff --git a/src/gex/lib/utils/helper.py b/src/gex/lib/utils/helper.py index 787ee11..c260755 100644 --- a/src/gex/lib/utils/helper.py +++ b/src/gex/lib/utils/helper.py @@ -30,8 +30,14 @@ def load_task(task): package = f'gex.lib.tasks.impl.{task}' transform_module = importlib.import_module(package) clsmembers = inspect.getmembers(transform_module, inspect.isclass) + exclude_list = [ + 'BaseTask', + 'CopyTask', + 'ZipSpliceTask', + 'SpliceTask' + ] for name, typedef in clsmembers: - if not name == 'BaseTask' and issubclass(typedef, BaseTask): + if name not in exclude_list and issubclass(typedef, BaseTask): return typedef() return None