From d360a2d74a7aef9dec2b2b3390130eea364b7ace Mon Sep 17 00:00:00 2001 From: Alexandre Derumier Date: Mon, 20 Apr 2026 08:09:18 +0200 Subject: [PATCH] rework mess support for mame/lr-mame MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a rework for old computers support in mame (mess). The new code is using lua autoboot scripts to load floppy && cass (with fast cass loading when possible). I have used https://github.com/dsync89/mess-curated-autoboot-scripts as base, but I have reworked a lot of scripts and write new one to handle auto-loading based on cassette headers or floppy disk structure, without relying of specific rom name. The lua code is shared between mame && lr-mame, so it's remove a lot of spaghetti code in both generator. It's re-introduce a fake "mess" core, to cleary split code between softlist (mess) && arcade/rom (mame), and avoid the need to rely on system.name. (And also allow user to add new custom systems, compute or arcade, without need to hack the generatorsà In mess mode, by default, a sha1 of the rom is done to compare to mame xml files, to detect the correct softlist and configure the machine && media. A new messSoftlistMap.json has been added, with all existing mess softlists and best compatible machine && media. It's possible to define custom options for each softmap in the json too. (We could also add a new "MESS" system if needed, to allow user to put all obscures system games inside, it should work automatically if autodetected) If no auto detection is found, it's search the default mapping from the system name. For this, A new messSystems.json is introduce to replace messSystems.csv, with mapping based on rom extension to a mess softlist. --- .../generators/libretro/libretroGenerator.py | 9 +- .../generators/libretro/libretroMAMEConfig.py | 609 +- .../generators/mame/mameGenerator.py | 949 +- .../configgen/generators/mame/mamePaths.py | 7 + .../configgen/generators/mame/messUtils.py | 241 + .../data/mame/atom_flop_autoload.csv | 16 - .../data/mame/autoboot_scripts/a800_flop.lua | 23 + .../data/mame/autoboot_scripts/adam_flop.lua | 179 + .../data/mame/autoboot_scripts/alice90.lua | 75 + .../data/mame/autoboot_scripts/apogee.lua | 78 + .../mame/autoboot_scripts/aquarius_cass.lua | 216 + .../data/mame/autoboot_scripts/atom_flop.lua | 407 + .../mame/autoboot_scripts/autoboot_common.lua | 226 + .../mame/autoboot_scripts/autoboot_zip.lua | 120 + .../data/mame/autoboot_scripts/bbc_cass.lua | 81 + .../data/mame/autoboot_scripts/bbcb_flop.lua | 79 + .../mame/autoboot_scripts/bbcb_flop_orig.lua | 79 + .../data/mame/autoboot_scripts/bk0010.lua | 261 + .../data/mame/autoboot_scripts/c64_cass.lua | 52 + .../data/mame/autoboot_scripts/c64_flop.lua | 1 + .../mame/autoboot_scripts/camplynx_cass.lua | 142 + .../data/mame/autoboot_scripts/cdi.lua | 38 + .../mame/autoboot_scripts/cgenie_cass.lua | 163 + .../data/mame/autoboot_scripts/coco_cass.lua | 81 + .../data/mame/autoboot_scripts/coco_flop.lua | 130 + .../mame/autoboot_scripts/coco_sha1_map.json | 10570 ++++++++++++++++ .../data/mame/autoboot_scripts/cpc_cass.lua | 78 + .../data/mame/autoboot_scripts/cpc_flop.lua | 122 + .../data/mame/autoboot_scripts/crvision.lua | 69 + .../data/mame/autoboot_scripts/dai_cass.lua | 97 + .../mame/autoboot_scripts/dragon_cass.lua | 330 + .../data/mame/autoboot_scripts/einstein.lua | 76 + .../mame/autoboot_scripts/electron_cass.lua | 79 + .../mame/autoboot_scripts/electron_flop.lua | 79 + .../mame/autoboot_scripts/famicom_cass.lua | 97 + .../data/mame/autoboot_scripts/fm7_cass.lua | 40 + .../data/mame/autoboot_scripts/galaxy.lua | 78 + .../data/mame/autoboot_scripts/io_base.lua | 19 + .../data/mame/autoboot_scripts/juku.lua | 53 + .../mame/autoboot_scripts/jupace_cass.lua | 173 + .../mame/autoboot_scripts/jupace_snap.lua | 80 + .../data/mame/autoboot_scripts/m5_cass.lua | 76 + .../data/mame/autoboot_scripts/mc10_cass.lua | 231 + .../data/mame/autoboot_scripts/megacd.lua | 32 + .../data/mame/autoboot_scripts/mo5_cass.lua | 23 + .../data/mame/autoboot_scripts/mo6_cass.lua | 76 + .../data/mame/autoboot_scripts/msx1_cass.lua | 199 + .../data/mame/autoboot_scripts/mtx_cass.lua | 135 + .../mame/autoboot_scripts/mz2000_cass.lua | 25 + .../data/mame/autoboot_scripts/mz700_cass.lua | 81 + .../data/mame/autoboot_scripts/mz800_cass.lua | 25 + .../data/mame/autoboot_scripts/mz80k_cass.lua | 33 + .../data/mame/autoboot_scripts/ngp.lua | 23 + .../data/mame/autoboot_scripts/orao_cass.lua | 24 + .../data/mame/autoboot_scripts/oric1_cass.lua | 76 + .../data/mame/autoboot_scripts/orion_cass.lua | 152 + .../mame/autoboot_scripts/pc6001_cass.lua | 50 + .../mame/autoboot_scripts/pc6001mk2_cass.lua | 67 + .../data/mame/autoboot_scripts/pcecd.lua | 26 + .../data/mame/autoboot_scripts/pecom_cass.lua | 113 + .../mame/autoboot_scripts/radio86_cass.lua | 78 + .../data/mame/autoboot_scripts/rx78_cass.lua | 92 + .../mame/autoboot_scripts/samcoupe_flop.lua | 1 + .../data/mame/autoboot_scripts/saturn.lua | 40 + .../mame/autoboot_scripts/sc3000_cass.lua | 77 + .../mame/autoboot_scripts/sorcerer_cass.lua | 158 + .../mame/autoboot_scripts/specpls3_flop.lua | 3 + .../mame/autoboot_scripts/spectrum_cass.lua | 15 + .../mame/autoboot_scripts/super80_cass.lua | 284 + .../mame/autoboot_scripts/svi318_cass.lua | 94 + .../autoboot_scripts/templates/cassette.lua | 82 + .../data/mame/autoboot_scripts/tg16cd.lua | 26 + .../data/mame/autoboot_scripts/timex_cass.lua | 82 + .../data/mame/autoboot_scripts/to_flop.lua | 1 + .../mame/autoboot_scripts/to_flop_to9.lua | 1 + .../data/mame/autoboot_scripts/trs80_cass.lua | 326 + .../data/mame/autoboot_scripts/trs80_flop.lua | 413 + .../data/mame/autoboot_scripts/tvc_cass.lua | 78 + .../data/mame/autoboot_scripts/tvc_flop.lua | 71 + .../mame/autoboot_scripts/vector06_flop.lua | 101 + .../data/mame/autoboot_scripts/vg5k.lua | 72 + .../mame/autoboot_scripts/vtech2_cass.lua | 79 + .../data/mame/autoboot_scripts/zx81_cass.lua | 48 + .../data/mame/camplynx_cass_autoload.csv | 66 - .../data/mame/coco_archive_fetch.py | 223 + .../data/mame/messSoftlistMap.json | 3613 ++++++ .../data/mame/messSystems.csv | 65 - .../data/mame/messSystems.json | 345 + .../batocera-es-system/es_systems.yml | 250 +- 89 files changed, 23294 insertions(+), 1259 deletions(-) create mode 100644 package/batocera/core/batocera-configgen/configgen/configgen/generators/mame/messUtils.py delete mode 100644 package/batocera/core/batocera-configgen/data/mame/atom_flop_autoload.csv create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/a800_flop.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/adam_flop.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/alice90.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/apogee.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/aquarius_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/atom_flop.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/autoboot_common.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/autoboot_zip.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/bbc_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/bbcb_flop.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/bbcb_flop_orig.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/bk0010.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/c64_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/c64_flop.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/camplynx_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/cdi.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/cgenie_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/coco_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/coco_flop.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/coco_sha1_map.json create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/cpc_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/cpc_flop.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/crvision.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/dai_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/dragon_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/einstein.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/electron_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/electron_flop.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/famicom_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/fm7_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/galaxy.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/io_base.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/juku.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/jupace_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/jupace_snap.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/m5_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mc10_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/megacd.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mo5_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mo6_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/msx1_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mtx_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mz2000_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mz700_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mz800_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mz80k_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/ngp.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/orao_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/oric1_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/orion_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/pc6001_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/pc6001mk2_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/pcecd.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/pecom_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/radio86_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/rx78_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/samcoupe_flop.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/saturn.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/sc3000_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/sorcerer_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/specpls3_flop.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/spectrum_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/super80_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/svi318_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/templates/cassette.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/tg16cd.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/timex_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/to_flop.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/to_flop_to9.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/trs80_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/trs80_flop.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/tvc_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/tvc_flop.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/vector06_flop.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/vg5k.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/vtech2_cass.lua create mode 100644 package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/zx81_cass.lua delete mode 100644 package/batocera/core/batocera-configgen/data/mame/camplynx_cass_autoload.csv create mode 100644 package/batocera/core/batocera-configgen/data/mame/coco_archive_fetch.py create mode 100644 package/batocera/core/batocera-configgen/data/mame/messSoftlistMap.json delete mode 100644 package/batocera/core/batocera-configgen/data/mame/messSystems.csv create mode 100644 package/batocera/core/batocera-configgen/data/mame/messSystems.json diff --git a/package/batocera/core/batocera-configgen/configgen/configgen/generators/libretro/libretroGenerator.py b/package/batocera/core/batocera-configgen/configgen/configgen/generators/libretro/libretroGenerator.py index 72392be7ae7..225390846ea 100755 --- a/package/batocera/core/batocera-configgen/configgen/configgen/generators/libretro/libretroGenerator.py +++ b/package/batocera/core/batocera-configgen/configgen/configgen/generators/libretro/libretroGenerator.py @@ -56,9 +56,6 @@ def getHotkeysContext(self) -> HotkeysContext: # Main entry of the module # Configure retroarch and return a command def generate(self, system, rom, playersControllers, metadata, guns, wheels, gameResolution): - # Fix for the removed MESS/MAMEVirtual cores - if system.config.core in [ 'mess', 'mamevirtual' ]: - system.config['core'] = 'mame' # Get the graphics backend first gfxBackend = getGFXBackend(system) @@ -126,11 +123,13 @@ def generate(self, system, rom, playersControllers, metadata, guns, wheels, game shutil.copyfile(RETROARCH_CUSTOM, remapconfigDir / "common.rmp") # Retroarch core on the filesystem - retroarchCore = RETROARCH_CORES / f"{system.config.core}_libretro.so" + # 'mess' uses the mame core binary + coreBinary = "mame" if system.config.core == "mess" else system.config.core + retroarchCore = RETROARCH_CORES / f"{coreBinary}_libretro.so" # for each core, a file /usr/lib/.info must exit, otherwise, info such as rewinding/netplay will not work # to do a global check : cd /usr/lib/libretro && for i in *.so; do INF=$(echo $i | sed -e s+/usr/lib/libretro+/usr/share/libretro/info+ -e s+\.so+.info+); test -e "$INF" || echo $i; done - infoFile = RETROARCH_SHARE / "info" / f"{system.config.core}_libretro.info" + infoFile = RETROARCH_SHARE / "info" / f"{coreBinary}_libretro.info" if not infoFile.exists(): raise MissingCore diff --git a/package/batocera/core/batocera-configgen/configgen/configgen/generators/libretro/libretroMAMEConfig.py b/package/batocera/core/batocera-configgen/configgen/configgen/generators/libretro/libretroMAMEConfig.py index 8d0db4f0880..18369966b68 100644 --- a/package/batocera/core/batocera-configgen/configgen/configgen/generators/libretro/libretroMAMEConfig.py +++ b/package/batocera/core/batocera-configgen/configgen/configgen/generators/libretro/libretroMAMEConfig.py @@ -2,17 +2,26 @@ import codecs import csv +import json import logging import os import shutil -import xml.etree.ElementTree as ET import zipfile from pathlib import Path from typing import TYPE_CHECKING from xml.dom import minidom -from ...batoceraPaths import BIOS, CONFIGS, DEFAULTS_DIR, ROMS, SAVES, USER_DECORATIONS, mkdir_if_not_exists -from ..mame.mameCommon import is_atom_floppy +from ...batoceraPaths import BIOS, CONFIGS, DEFAULTS_DIR, SAVES, USER_DECORATIONS, mkdir_if_not_exists +from ...exceptions import BatoceraException +from ..mame.mamePaths import MESS_AUTOBOOT_SCRIPTS, MESS_SYSTEMS_MAPPING +from ..mame.messUtils import ( + _build_config_args, + _build_rom_ext_args, + _compute_sha1, + _load_softlist_map, + _lookup_rom, + _machine_from_softlist, +) if TYPE_CHECKING: from collections.abc import Sequence @@ -51,379 +60,17 @@ "start": "START" } -def generateMAMEConfigs(playersControllers: Controllers, system: Emulator, rom: Path, guns: Guns) -> None: - # Generate command line for MAME/MESS/MAMEVirtual - commandLine: list[str | Path] = [] - romDrivername = rom.stem - specialController = 'none' - if system.config.core in [ 'mame', 'mess', 'mamevirtual' ]: - corePath = f"lr-{system.config.core}" - else: - corePath = str(system.config.core) +def _corePath(system: Emulator) -> str: + if system.config.core in ['mame', 'mess', 'mamevirtual']: + return f"lr-mame" + return str(system.config.core) - if system.name in [ 'mame', 'neogeo', 'lcdgames', 'tvgames', 'vis', 'namco22', 'model2', 'cave3rd', 'gaelco', 'hikaru' ]: - # Set up command line for basic systems - # ie. no media, softlists, etc. - if system.config.get_bool("customcfg"): - cfgPath = CONFIGS / corePath / "custom" - else: - cfgPath = SAVES / "mame" / "mame" / "cfg" - mkdir_if_not_exists(cfgPath) - if system.name == 'vis': - commandLine += [ 'vis', '-cdrom', f'"{rom}"' ] - else: - commandLine += [ romDrivername ] - commandLine += [ '-cfg_directory', f'"{cfgPath}"' ] - commandLine += [ '-rompath', f'"{rom.parent};/userdata/bios/mame/;/userdata/bios/"' ] - pluginsToLoad: list[str] = [] - if system.config.get_bool("hiscoreplugin", True): - pluginsToLoad += [ "hiscore" ] - if system.config.get_bool("coindropplugin"): - pluginsToLoad += [ "coindrop" ] - if pluginsToLoad: - commandLine += [ "-plugins", "-plugin", ",".join(pluginsToLoad) ] - messMode = -1 - messModel = '' - else: - # Set up command line for MESS or MAMEVirtual - softDir = Path("/var/run/mame_software") - subdirSoftList = [ "mac_hdd", "bbc_hdd", "cdi", "archimedes_hdd", "fmtowns_cd" ] - softList = system.config.get("softList", "none") - if softList == "none": - softList = "" - - # Auto softlist for FM Towns if there is a zip that matches the folder name - # Used for games that require a CD and floppy to both be inserted - if system.name == 'fmtowns' and softList == '' and (ROMS / 'fmtowns' / f'{rom.parent.name}.zip').exists(): - softList = 'fmtowns_cd' - - # Determine MESS system name (if needed) - openFile = (DEFAULTS_DIR / "data" / "mame" / "messSystems.csv").open() - messSystems: list[str] = [] - messSysName: list[str] = [] - messRomType: list[str] = [] - messAutoRun: list[str] = [] - with openFile: - messDataList = csv.reader(openFile, delimiter=';', quotechar="'") - for row in messDataList: - messSystems.append(row[0]) - messSysName.append(row[1]) - messRomType.append(row[2]) - messAutoRun.append(row[3]) - messMode = messSystems.index(system.name) - - # Alternate system for machines that have different configs (ie computers with different hardware) - messModel = messSysName[messMode] - if altmodel := system.config.get("altmodel"): - messModel = altmodel - commandLine += [ messModel ] - - if messSysName[messMode] == "": - # Command line for non-arcade, non-system ROMs (lcdgames, plugnplay) - if system.config.get_bool("customcfg"): - cfgPath = CONFIGS / corePath / "custom" - else: - cfgPath = SAVES / "mame" / "mame" / "cfg" - mkdir_if_not_exists(cfgPath) - commandLine += [ romDrivername ] - commandLine += [ '-cfg_directory', f'"{cfgPath}"' ] - commandLine += [ '-rompath', f'"{rom.parent};/userdata/bios/"' ] - else: - # Command line for MESS consoles/computers - # TI-99 32k RAM expansion & speech modules - # Don't enable 32k by default - if system.name == "ti99": - commandLine += [ "-ioport", "peb" ] - if system.config.get_bool("ti99_32kram"): - commandLine += ["-ioport:peb:slot2", "32kmem"] - if system.config.get_bool("ti99_speech", True): - commandLine += ["-ioport", "speechsyn"] - - #Laser 310 Memory Expansion & joystick - if system.name == "laser310": - commandLine += ['-io', 'joystick', "-mem", system.config.get('memslot', 'laser_64k')] - - # BBC Joystick - if system.name == "bbcmicro" and system.config.get('sticktype', 'none') != 'none': - commandLine += ["-analogue", system.config['sticktype']] - specialController = system.config['sticktype'] - - # Apple II - if system.name == "apple2": - rom_extension = rom.suffix.lower() - # only add SD/IDE control if provided a hard drive image - if rom_extension in {".hdv", ".2mg", ".chd", ".iso", ".bin", ".cue"}: - commandLine += ["-sl7", "cffa202"] - if (gameio := system.config.get('gameio', 'none')) != 'none': - if gameio == 'joyport' and messModel != 'apple2p': - _logger.debug("Joyport is only compatible with Apple II Plus") - else: - commandLine += ["-gameio", gameio] - specialController = gameio - - # RAM size (Mac excluded, special handling below) - ramSize = system.config.get_int('ramsize') - if system.name != "macintosh" and ramSize: - commandLine += [ '-ramsize', str(ramSize) + 'M' ] - - # Mac RAM & Image Reader (if applicable) - if system.name == "macintosh" and ramSize: - if messModel in [ 'maciix', 'maclc3' ]: - if messModel == 'maclc3' and ramSize == 2: - ramSize = 4 - if messModel == 'maclc3' and ramSize > 80: - ramSize = 80 - if messModel == 'maciix' and ramSize == 16: - ramSize = 32 - if messModel == 'maciix' and ramSize == 48: - ramSize = 64 - commandLine += [ '-ramsize', str(ramSize) + 'M' ] - if messModel == 'maciix': - imageSlot = system.config.get('imagereader', 'nba') - if imageSlot != "disabled": - commandLine += [ f"-{imageSlot}", "image" ] - - altromtype = system.config.get_str("altromtype") - boot_disk = system.config.get("bootdisk") - - if softList != "": - # Software list ROM commands - prepSoftwareList(subdirSoftList, softList, softDir, BIOS / "mame" / "hash", rom.parent) - if softList in subdirSoftList: - commandLine += [ rom.parent.name ] - else: - commandLine += [ romDrivername ] - commandLine += [ "-rompath", f'"{softDir};/userdata/bios/"' ] - commandLine += [ "-swpath", f'"{softDir}"' ] - commandLine += [ "-verbose" ] - else: - # Alternate ROM type for systems with mutiple media (ie cassette & floppy) - # Mac will auto change floppy 1 to 2 if a boot disk is enabled - if system.name != "macintosh": - if altromtype: - if altromtype == "flop1" and messModel == "fmtmarty": - commandLine += [ "-flop" ] - else: - commandLine += [ "-" + altromtype ] - elif system.name == "adam": - # add some logic based on the extension - rom_extension = rom.suffix.lower() - if rom_extension == ".ddp": - commandLine += [ "-cass1" ] - elif rom_extension == ".dsk": - commandLine += [ "-flop1" ] - else: - commandLine += [ "-cart1" ] - elif system.name == "coco": - if rom.suffix.casefold() == ".cas": - commandLine += [ "-cass" ] - elif rom.suffix.casefold() == ".dsk": - commandLine += [ "-flop1" ] - else: - commandLine += [ "-cart" ] - # try to choose the right floppy for Apple2gs - elif system.name == "apple2gs": - rom_extension = rom.suffix.lower() - if rom_extension == ".zip": - with zipfile.ZipFile(rom, 'r') as zip_file: - file_list = zip_file.namelist() - # assume only one file in zip - if len(file_list) == 1: - filename = file_list[0] - rom_extension = Path(filename).suffix.lower() - if rom_extension in [".2mg", ".2img", ".img", ".image"]: - commandLine += [ "-flop3" ] - else: - commandLine += [ "-flop1" ] - else: - commandLine += [ "-" + messRomType[messMode] ] - else: - if boot_disk: - if (altromtype == "flop1" or not altromtype) and boot_disk in [ "macos30", "macos608", "macos701", "macos75" ]: - commandLine += [ "-flop2" ] - elif altromtype: - commandLine += [ "-" + altromtype ] - else: - commandLine += [ "-" + messRomType[messMode] ] - else: - if altromtype: - commandLine += [ "-" + altromtype ] - else: - commandLine += [ "-" + messRomType[messMode] ] - # Use the full filename for MESS non-softlist ROMs - commandLine += [ f'"{rom}"' ] - commandLine += [ "-rompath", f'"{rom.parent};/userdata/bios/"' ] - - # Boot disk for Macintosh - # Will use Floppy 1 or Hard Drive, depending on the disk. - if system.name == "macintosh" and boot_disk: - if system.config["bootdisk"] in [ "macos30", "macos608", "macos701", "macos75" ]: - bootType = "-flop1" - bootDisk = '"/userdata/bios/' + boot_disk + '.img"' - else: - bootType = "-hard" - bootDisk = '"/userdata/bios/' + boot_disk + '.chd"' - commandLine += [ bootType, bootDisk ] - - # Create & add a blank disk if needed, insert into drive 2 - # or drive 1 if drive 2 is selected manually or FM Towns Marty. - if system.config.get_bool('addblankdisk'): - if system.name == 'fmtowns': - blankDisk = Path('/usr/share/mame/blank.fmtowns') - targetFolder = SAVES / 'mame' / system.name - targetDisk = targetFolder / f'{rom.stem}.fmtowns' - # Add elif statements here for other systems if enabled - else: - blankDisk = Path('/usr/share/mame/blank.default') - targetFolder = SAVES / 'mame' / system.name - targetDisk = targetFolder / f'{rom.stem}.default' - mkdir_if_not_exists(targetFolder) - if not targetDisk.exists(): - shutil.copy2(blankDisk, targetDisk) - # Add other single floppy systems to this if statement - if messModel == "fmtmarty": - commandLine += [ '-flop', f'"{targetDisk}"' ] - elif altromtype == 'flop2': - commandLine += [ '-flop1', f'"{targetDisk}"' ] - else: - commandLine += [ '-flop2', f'"{targetDisk}"' ] - - # UI enable - for computer systems, the default sends all keys to the emulated system. - # This will enable hotkeys, but some keys may pass through to MAME and not be usable in the emulated system. - if system.config.get_bool("enableui", True): - commandLine += [ "-ui_active" ] - - # MESS config folder - if system.config.get_bool("customcfg"): - cfgPath = CONFIGS / corePath / messSysName[messMode] / "custom" - else: - cfgPath = SAVES / "mame" / "cfg" / messSysName[messMode] - if system.config.get_bool("pergamecfg"): - cfgPath = CONFIGS / corePath / messSysName[messMode] / rom.name - mkdir_if_not_exists(cfgPath) - commandLine += [ '-cfg_directory', f'"{cfgPath}"' ] - - # Autostart via ini file - # Init variables, delete old ini if it exists, prepare ini path - # lr-mame does NOT support multiple ini paths - autoRunCmd = "" - autoRunDelay = 0 - mameIniDir = SAVES / "mame" / "mame" / "ini" - mkdir_if_not_exists(mameIniDir) - if (mameIniDir / "batocera.ini").exists(): - (mameIniDir / "batocera.ini").unlink() - # bbc has different boots for floppy & cassette, no special boot for carts - if system.name == "bbcmicro": - if altromtype or softList: - if altromtype == "cass" or softList[-4:] == "cass": - autoRunCmd = '*tape\\nchain""\\n' - autoRunDelay = 2 - elif (altromtype and altromtype.startswith("flop")) or "flop" in softList: - autoRunCmd = '*cat\\n\\n\\n\\n*exec !boot\\n' - autoRunDelay = 3 - else: - autoRunCmd = '*cat\\n\\n\\n\\n*exec !boot\\n' - autoRunDelay = 3 - # fm7 boots floppies, needs cassette loading - elif system.name == "fm7": - if ( - system.config.get("altromtype") == "cass" - or (softList != "" and softList[-4:] == "cass") - ): - autoRunCmd = 'LOADM”“,,R\\n' - autoRunDelay = 5 - elif system.name == "coco": - romType = 'cart' - autoRunDelay = 2 - - # if using software list, use "usage" for autoRunCmd (if provided) - if softList != "": - softListFile = Path(f'/usr/bin/mame/hash/{softList}.xml') - if softListFile.exists(): - softwarelist = ET.parse(softListFile) - for software in softwarelist.findall('software'): - if software.attrib and software.get('name') == romDrivername: - for info in software.iter('info'): - if info.get('name') == 'usage': - autoRunCmd = f'{info.get('value')}\\n' - - # if still undefined, default autoRunCmd based on media type - if autoRunCmd == "": - if altromtype == "cass" or (softList and softList.endswith("cass")) or rom.suffix.casefold() == ".cas": - romType = 'cass' - if romDrivername.casefold().endswith(".bas"): - autoRunCmd = 'CLOAD:RUN\\n' - else: - autoRunCmd = 'CLOADM:EXEC\\n' - if altromtype == "flop1" or (softList and softList.endswith("flop")) or rom.suffix.casefold() == ".dsk": - romType = 'flop' - if romDrivername.casefold().endswith(".bas"): - autoRunCmd = f'RUN \"{romDrivername}\"\\n' - else: - autoRunCmd = f'LOADM \"{romDrivername}\":EXEC\\n' - - # check for a user override - autoRunFile = CONFIGS / 'mame' / 'autoload' / f'{system.name}_{romType}_autoload.csv' - if autoRunFile.exists(): - with autoRunFile.open() as openARFile: - autoRunList = csv.reader(openARFile, delimiter=';', quotechar="'") - for row in autoRunList: - if row and not row[0].startswith('#') and row[0].casefold() == romDrivername.casefold(): - autoRunCmd = row[1] + "\\n" - elif system.name == "atom": - autoRunDelay = 2 - autoRunCmd = messAutoRun[messMode] - if ( - (altromtype == "flop1") or - (softList and softList.endswith("flop")) or - is_atom_floppy(rom) - ): - autoRunFile = DEFAULTS_DIR / 'data' / 'mame' / 'atom_flop_autoload.csv' - if autoRunFile.exists(): - with autoRunFile.open() as openARFile: - autoRunList = csv.reader(openARFile, delimiter=';', quotechar="'") - for row in autoRunList: - if row and not row[0].startswith('#') and row[0].casefold() == rom.stem.casefold(): - autoRunCmd = row[1] + "\\n" - break - else: - # Check for an override file, otherwise use generic (if it exists) - autoRunCmd = messAutoRun[messMode] - autoRunFile = DEFAULTS_DIR / 'data' / 'mame' / f'{softList}_autoload.csv' - if autoRunFile.exists(): - with autoRunFile.open() as openARFile: - autoRunList = csv.reader(openARFile, delimiter=';', quotechar="'") - for row in autoRunList: - if row[0].casefold() == rom.stem.casefold(): - autoRunCmd = row[1] + "\\n" - autoRunDelay = 3 - - inipath = SAVES / 'mame' / 'mame' / 'ini' - commandLine += [ '-inipath', f'"{inipath}"' ] - if autoRunCmd != "": - if autoRunCmd.startswith("'"): - autoRunCmd.replace("'", "") - iniFile = (SAVES / 'mame' / 'mame' / 'ini' / 'batocera.ini').open("w") - iniFile.write('autoboot_command ' + autoRunCmd + "\n") - iniFile.write('autoboot_delay ' + str(autoRunDelay)) - iniFile.close() - # Create & add a blank disk if needed, insert into drive 2 - # or drive 1 if drive 2 is selected manually. - if system.config.get_bool('addblankdisk'): - lr_mess_dsk = SAVES / 'lr-mess' / system.name / rom.stem - if not lr_mess_dsk.exists(): - lr_mess_dsk.parent.mkdir(parents=True) - shutil.copy2('/usr/share/mame/blank.dsk', lr_mess_dsk) - if altromtype == 'flop2': - commandLine += [ '-flop1', f'"{lr_mess_dsk}"' ] - else: - commandLine += [ '-flop2', f'"{lr_mess_dsk}"' ] +def appendCommonCommandArgs(commandLine: list, system: Emulator, rom: Path) -> None: # Lightgun reload option if system.config.get_bool('offscreenreload'): commandLine += [ "-offscreen_reload" ] - # Art paths - lr-mame displays artwork in the game area and not in the bezel area, so using regular MAME artwork + shaders is not recommended. # By default, will ignore standalone MAME's art paths. if system.config.core != 'same_cdi': @@ -433,7 +80,6 @@ def generateMAMEConfigs(playersControllers: Controllers, system: Emulator, rom: artPath = f"/var/run/mame_artwork/;/usr/bin/mame/artwork/;{BIOS / 'lr-mame' / 'artwork'}" if system.name != "ti99": commandLine += [ '-artpath', f'"{artPath}"' ] - # Artwork crop - default to On for lr-mame # Exceptions for PDP-1 (status lights) and VGM Player (indicators) if "artworkcrop" not in system.config: @@ -442,7 +88,6 @@ def generateMAMEConfigs(playersControllers: Controllers, system: Emulator, rom: else: if system.config.get_bool("artworkcrop"): commandLine += [ "-artwork_crop" ] - # Share plugins with standalone MAME (except TI99) if system.name != "ti99": commandLine += [ "-pluginspath", f"/usr/bin/mame/plugins/;{SAVES / 'mame' / 'plugins'}" ] @@ -453,51 +98,209 @@ def generateMAMEConfigs(playersControllers: Controllers, system: Emulator, rom: mkdir_if_not_exists(SAVES / "mame" / "plugins") mkdir_if_not_exists(BIOS / "mame" / "samples") - # Delete old cmd files & prepare path + +def writeCmdFile(commandLine: list, rom: Path) -> None: cmdPath = Path("/var/run/cmdfiles") mkdir_if_not_exists(cmdPath) for file in cmdPath.iterdir(): if file.suffix == ".cmd": file.unlink() - - # Write command line file - cmdFilename = cmdPath / f"{romDrivername}.cmd" - # Check to see whether user provided a custom cmd file at the default location + cmdFilename = cmdPath / f"{rom.stem}.cmd" if Path(defaultCustomCmdFilepath := f"{rom}.cmd").is_file(): shutil.copyfile(defaultCustomCmdFilepath, cmdFilename) else: - # User did not provide a custom .cmd file. Use the logic above to create a new .cmd file cmdFile = cmdFilename.open("w") cmdFile.write(' '.join(str(item) for item in commandLine)) cmdFile.close() - # Call Controller Config - if messMode == -1: - generateMAMEPadConfig(cfgPath, playersControllers, system, "", rom, specialController, guns) + +def generateMAMEConfigs(playersControllers: Controllers, system: Emulator, rom: Path, guns: Guns) -> None: + if system.config.core == 'mess' or system.config.core == 'same_cdi': + return generateMessConfigs(playersControllers, system, rom, guns) + + # Generate command line for MAME/MAMEVirtual + commandLine: list[str | Path] = [] + romDrivername = rom.stem + specialController = 'none' + + corePath = _corePath(system) + + if system.config.get_bool("customcfg"): + cfgPath = CONFIGS / corePath / "custom" else: - generateMAMEPadConfig(cfgPath, playersControllers, system, messModel, rom, specialController, guns) - -def prepSoftwareList(subdirSoftList: Sequence[str], softList: str, softDir: Path, hashDir: Path, romParent: Path): - mkdir_if_not_exists(softDir) - # Check for/remove existing symlinks, remove hashfile folder - for checkFile in softDir.iterdir(): - if checkFile.is_symlink(): - checkFile.unlink() - if checkFile.is_dir(): - shutil.rmtree(checkFile) - # Prepare hashfile path - mkdir_if_not_exists(hashDir) - # Remove existing xml files - for file in hashDir.iterdir(): - if file.suffix == ".xml": - file.unlink() - # Copy hashfile - shutil.copy2(Path("/usr/bin/mame/hash") / f"{softList}.xml", hashDir / f"{softList}.xml") - # Link ROM's parent folder if needed, ROM's folder otherwise - if softList in subdirSoftList: - (softDir / softList).symlink_to(romParent.parent, target_is_directory=True) + cfgPath = SAVES / "mame" / "mame" / "cfg" + mkdir_if_not_exists(cfgPath) + commandLine += [ romDrivername ] + commandLine += [ '-cfg_directory', f'"{cfgPath}"' ] + commandLine += [ '-rompath', f'"{rom.parent};/userdata/bios/mame/;/userdata/bios/"' ] + pluginsToLoad: list[str] = [] + if system.config.get_bool("hiscoreplugin", True): + pluginsToLoad += [ "hiscore" ] + if system.config.get_bool("coindropplugin"): + pluginsToLoad += [ "coindrop" ] + if pluginsToLoad: + commandLine += [ "-plugins", "-plugin", ",".join(pluginsToLoad) ] + + appendCommonCommandArgs(commandLine, system, rom) + writeCmdFile(commandLine, rom) + + # Call Controller Config (arcade path always uses "" as messModel and 'none' as specialController) + generateMAMEPadConfig(cfgPath, playersControllers, system, "", rom, specialController, guns) + + +def generateMessConfigs(playersControllers: Controllers, system: Emulator, rom: Path, guns: Guns) -> None: + corePath = _corePath(system) + specialController = 'none' + + # ------------------------------------------------------------------ # + # 1. Identify system: attempt SHA1 autodetection first + # ------------------------------------------------------------------ # + softlist_map = _load_softlist_map() + + rom_sha1 = _compute_sha1(rom) + _logger.debug("lr-MESS: SHA1 of %s = %s", rom.name, rom_sha1) + + rom_info = _lookup_rom(rom_sha1) + if rom_info is not None: + softlist = rom_info["softlist"] + xml_media = rom_info["media"] + _logger.info( + "lr-MESS: identified %s as softlist=%s software=%s xml_media=%s", + rom.name, softlist, rom_info["software"], xml_media, + ) + sys_info = softlist_map.get(softlist, {}) + machine = system.config.get_str("altmodel") or sys_info.get("machine") + if not machine: + machine = _machine_from_softlist(softlist) + _logger.info( + "lr-MESS: softlist '%s' not in messSoftlistMap.json, inferred machine=%s", + softlist, machine, + ) + # Priority: user override > messSoftlistMap > MAME hash XML + media = system.config.get_str("altromtype") or sys_info.get("media") or xml_media + _logger.info( + "lr-MESS: media resolved to %s (softlistmap=%s xml=%s)", + media, sys_info.get("media"), xml_media, + ) + else: + # ROM not found — try messSystems.json lookup by system name + extension + softlist = "" + sys_info = {} + try: + systems_mapping = json.loads(MESS_SYSTEMS_MAPPING.read_text()) + sys_ext_map = systems_mapping.get(system.name, {}) + rom_ext = rom.suffix.lower() + if rom_ext == ".zip": + try: + with zipfile.ZipFile(rom, "r") as zf: + names = [n for n in zf.namelist() if not n.endswith("/")] + if names: + rom_ext = Path(names[0]).suffix.lower() + except (zipfile.BadZipFile, OSError): + pass + softlist = sys_ext_map.get(rom_ext) or sys_ext_map.get("*") or "" + if softlist: + _logger.info( + "lr-MESS: ROM not autodetected — found system '%s' ext '%s' in messSystems.json: softlist=%s", + system.name, rom_ext, softlist, + ) + except OSError: + _logger.warning("lr-MESS: messSystems.json not found at %s", MESS_SYSTEMS_MAPPING) + + if softlist: + sys_info = softlist_map.get(softlist, {}) + machine = system.config.get_str("altmodel") or sys_info.get("machine") + if not machine: + machine = _machine_from_softlist(softlist) + _logger.info( + "lr-MESS: softlist '%s' not in messSoftlistMap.json, inferred machine=%s", + softlist, machine, + ) + else: + machine = None + + machine = system.config.get_str("machine") or machine + # Priority: user override > messSoftlistMap + media = system.config.get_str("media") or sys_info.get("media") + if not machine or not media: + raise BatoceraException( + f"ROM '{rom.name}' (sha1={rom_sha1}) was not found in the MAME " + "software-list database. " + "Machine and media must be configured manually " + "(set 'machine' and 'media' in the system options)." + ) + _logger.info("lr-MESS: ROM not autodetected — using machine=%s media=%s", machine, media) + + # ------------------------------------------------------------------ # + # 2. Config path + # ------------------------------------------------------------------ # + if system.config.get_bool("customcfg"): + cfgPath = CONFIGS / corePath / machine / "custom" else: - (softDir / softList).symlink_to(romParent, target_is_directory=True) + cfgPath = SAVES / "mame" / "cfg" / machine + if system.config.get_bool("pergamecfg"): + cfgPath = CONFIGS / corePath / machine / rom.name + mkdir_if_not_exists(cfgPath) + + # ------------------------------------------------------------------ # + # 3. Build command line + # ------------------------------------------------------------------ # + commandLine: list[str | Path] = [] + + # Machine + commandLine += [machine] + + # Extra static args from softlist map + for arg in sys_info.get("extra_args", []): + commandLine.append(arg) + + # Config-driven args + commandLine += _build_config_args(sys_info.get("config_args", []), system, machine) + + # Extension-driven args + commandLine += _build_rom_ext_args(sys_info.get("rom_ext_args", []), rom) + + # Media flag and ROM path (quoted) + commandLine += [f"-{media}", f'"{rom}"'] + + # ROM search path + commandLine += ["-rompath", f'"{rom.parent};/userdata/bios/"'] + + # Config directory + commandLine += ["-cfg_directory", f'"{cfgPath}"'] + + # UI active (enabled by default for computer systems) + if system.config.get_bool("enableui", True): + commandLine += ["-ui_active"] + + # Autoboot Lua script + lua_script_name = sys_info.get("lua_script") + if lua_script_name: + lua_path = MESS_AUTOBOOT_SCRIPTS / lua_script_name + if lua_path.exists(): + commandLine += ["-autoboot_script", f'"{lua_path}"'] + else: + _logger.warning("lr-MESS: Lua autoboot script not found: %s", lua_path) + + # Blank disk handling + if system.config.get_bool("addblankdisk"): + altromtype = system.config.get_str("altromtype") + lr_mess_dsk = SAVES / 'lr-mess' / system.name / rom.stem + if not lr_mess_dsk.exists(): + lr_mess_dsk.parent.mkdir(parents=True) + shutil.copy2('/usr/share/mame/blank.dsk', lr_mess_dsk) + if altromtype == 'flop2': + commandLine += ['-flop1', f'"{lr_mess_dsk}"'] + else: + commandLine += ['-flop2', f'"{lr_mess_dsk}"'] + + # ------------------------------------------------------------------ # + # 4. Common suffix args, write cmd file, pad config + # ------------------------------------------------------------------ # + appendCommonCommandArgs(commandLine, system, rom) + writeCmdFile(commandLine, rom) + generateMAMEPadConfig(cfgPath, playersControllers, system, machine, rom, specialController, guns) + def getMameControlScheme(system: Emulator, rom: Path) -> str: # Game list files diff --git a/package/batocera/core/batocera-configgen/configgen/configgen/generators/mame/mameGenerator.py b/package/batocera/core/batocera-configgen/configgen/configgen/generators/mame/mameGenerator.py index 8a84c326e6b..677bfb5528a 100644 --- a/package/batocera/core/batocera-configgen/configgen/configgen/generators/mame/mameGenerator.py +++ b/package/batocera/core/batocera-configgen/configgen/configgen/generators/mame/mameGenerator.py @@ -1,12 +1,11 @@ from __future__ import annotations -import csv import json import logging import os import shutil import subprocess -import xml.etree.ElementTree as ET +import zipfile from pathlib import Path from typing import TYPE_CHECKING from xml.dom import minidom @@ -18,8 +17,6 @@ BATOCERA_SHARE_DIR, BIOS, CONFIGS, - DEFAULTS_DIR, - ROMS, SAVES, SCREENSHOTS, USER_DECORATIONS, @@ -29,8 +26,15 @@ from ...utils import bezels as bezelsUtil, videoMode from ..Generator import Generator from . import mameControllers -from .mameCommon import is_atom_floppy -from .mamePaths import MAME_BIOS, MAME_CHEATS, MAME_CONFIG, MAME_DEFAULT_DATA, MAME_ROMS, MAME_SAVES +from .mamePaths import MAME_BIOS, MAME_CHEATS, MAME_CONFIG, MAME_DEFAULT_DATA, MAME_SAVES, MESS_AUTOBOOT_SCRIPTS, MESS_SYSTEMS_MAPPING +from .messUtils import ( + _build_config_args, + _build_rom_ext_args, + _compute_sha1, + _load_softlist_map, + _lookup_rom, + _machine_from_softlist, +) if TYPE_CHECKING: from ...Emulator import Emulator @@ -59,584 +63,10 @@ def getHotkeysContext(self) -> HotkeysContext: } def generate(self, system, rom, playersControllers, metadata, guns, wheels, gameResolution): - # Extract "" - romBasename = rom.name - romDirname = rom.parent - romName = rom.stem - romExt = rom.suffix - - softDir = Path("/var/run/mame_software/") - softList = "" - messModel = "" - specialController = "none" - subdirSoftList = [ "mac_hdd", "bbc_hdd", "cdi", "archimedes_hdd", "fmtowns_cd" ] - - # Generate userdata folders if needed - mamePaths = [ - MAME_CONFIG, - MAME_SAVES / "nvram", - MAME_SAVES / "cfg", - MAME_SAVES / "input", - MAME_SAVES / "state", - MAME_SAVES / "diff", - MAME_SAVES / "comments", - MAME_BIOS / "artwork" / "crosshairs", - MAME_CHEATS, - MAME_SAVES / "plugins", - MAME_CONFIG / "ctrlr", - MAME_CONFIG / "ini", - ] - for checkPath in mamePaths: - mkdir_if_not_exists(checkPath) - - messSystems: list[str] = [] - messSysName: list[str] = [] - messRomType: list[str] = [] - messAutoRun: list[str] = [] - - with (DEFAULTS_DIR / 'data' / 'mame' / 'messSystems.csv').open() as openFile: - messDataList = csv.reader(openFile, delimiter=';', quotechar="'") - for row in messDataList: - messSystems.append(row[0]) - messSysName.append(row[1]) - messRomType.append(row[2]) - messAutoRun.append(row[3]) - - # Identify the current system - try: - messMode = messSystems.index(system.name) - except ValueError: - messMode = -1 - - softList = system.config.get_str("softList", "none") - softList = softList if softList != "none" else "" - - # Auto softlist for FM Towns if there is a zip that matches the folder name - # Used for games that require a CD and floppy to both be inserted - if system.name == 'fmtowns' and softList == '' and (ROMS / "fmtowns" / f"{romDirname.name}.zip").exists(): - softList = 'fmtowns_cd' - - commandArray: list[str | Path] = [ "/usr/bin/mame/mame" ] - - # MAME options used here are explained as it's not always straightforward - # A lot more options can be configured, just run mame -showusage and have a look - - # set audio to pipewire to fix audio from 0.278 - commandArray += [ "-sound", "pipewire" ] - # skip game info at start - commandArray += [ "-skip_gameinfo" ] - - if messMode == -1: - commandArray += [ "-rompath", f"{romDirname};{MAME_BIOS};{BIOS}" ] + if system.config.core == 'mess': + return _generate_mess(system, rom, playersControllers, metadata, guns, wheels, gameResolution) else: - if softList in subdirSoftList: - commandArray += [ "-rompath", f"{romDirname};{MAME_BIOS};{BIOS};{MAME_ROMS};{softDir}" ] - else: - commandArray += [ "-rompath", f"{romDirname};{MAME_BIOS};{BIOS};{MAME_ROMS}" ] - - # MAME various paths we can probably do better - commandArray += [ "-bgfx_path", "/usr/bin/mame/bgfx/" ] # Core bgfx files can be left on ROM filesystem - commandArray += [ "-fontpath", "/usr/bin/mame/" ] # Fonts can be left on ROM filesystem - commandArray += [ "-languagepath", "/usr/bin/mame/language/" ] # Translations can be left on ROM filesystem - commandArray += [ "-pluginspath", f"/usr/bin/mame/plugins/;{MAME_SAVES / 'plugins'}" ] - commandArray += [ "-samplepath", MAME_BIOS / "samples" ] # Current batocera storage location for MAME samples - commandArray += [ "-artpath", f"/var/run/mame_artwork/;/usr/bin/mame/artwork/;{MAME_BIOS / 'artwork'};{USER_DECORATIONS}" ] # first for systems ; second for overlays - - # Enable cheats - commandArray += [ "-cheat" ] - commandArray += [ "-cheatpath", MAME_CHEATS ] # Should this point to path containing the cheat.7z file - - # Logs and Swithres ini read by default (including its own verbose) - commandArray += [ "-verbose" ] - commandArray += [ "-switchres_ini" ] - - # MAME saves a lot of stuff, we need to map this on /userdata/saves/mame/ for each one - commandArray += [ "-nvram_directory" , MAME_SAVES / "nvram" ] - - # Set custom config path if option is selected or default path if not - customCfg = system.config.get_bool("customcfg") - - if messMode == -1: - if customCfg: - cfgPath = MAME_CONFIG / "custom" - else: - cfgPath = MAME_CONFIG - mkdir_if_not_exists(MAME_CONFIG) - else: - if customCfg: - cfgPath = MAME_CONFIG / messSysName[messMode] / "custom" - else: - cfgPath = MAME_CONFIG / messSysName[messMode] - mkdir_if_not_exists(MAME_CONFIG / messSysName[messMode]) - mkdir_if_not_exists(cfgPath) - - # MAME will create custom configs per game for MAME ROMs and MESS ROMs with no system attached (LCD games, TV games, etc.) - # This will allow an alternate config path per game for MESS console/computer ROMs that may need additional config. - if system.config.get_bool("pergamecfg") and messMode != -1 and messSysName[messMode] != "": - base_path = MAME_CONFIG / messSysName[messMode] - mkdir_if_not_exists(base_path) - cfgPath = base_path / romBasename - mkdir_if_not_exists(cfgPath) - commandArray += [ "-cfg_directory" , cfgPath ] - commandArray += [ "-input_directory" , MAME_SAVES / "input" ] - commandArray += [ "-state_directory" , MAME_SAVES / "state" ] - commandArray += [ "-snapshot_directory" , SCREENSHOTS ] - commandArray += [ "-diff_directory" , MAME_SAVES / "diff" ] - commandArray += [ "-comment_directory", MAME_SAVES / "comments" ] - commandArray += [ "-homepath" , MAME_SAVES / "plugins" ] - commandArray += [ "-ctrlrpath" , MAME_CONFIG / "ctrlr" ] - commandArray += [ "-inipath" , f"{MAME_CONFIG};{MAME_CONFIG / 'ini'}" ] - commandArray += [ "-crosshairpath" , MAME_BIOS / "artwork" / "crosshairs" ] - if softList != "": - commandArray += [ "-swpath" , softDir ] - commandArray += [ "-hashpath" , softDir / "hash" ] - - # TODO These paths are not handled yet - # TODO -swpath path to loose software - might use if we want software list MESS support - - # BGFX video engine : https://docs.mamedev.org/advanced/bgfx.html - video = system.config.get("video") - if video == "bgfx": - commandArray += [ "-video", "bgfx" ] - - # BGFX backend - bgfxbackend = system.config.get("bgfxbackend", "automatic") - commandArray += [ "-bgfx_backend", "auto" if bgfxbackend == "automatic" else bgfxbackend ] - - # BGFX shaders effects - commandArray += [ "-bgfx_screen_chains", system.config.get("bgfxshaders", "default") ] - - # Other video modes - elif video == "accel": - commandArray += ["-video", "accel" ] - else: - commandArray += [ "-video", "auto" ] - - # CRT / SwitchRes support - if system.config.get_bool("switchres"): - commandArray += [ "-modeline_generation" ] - commandArray += [ "-changeres" ] - commandArray += [ "-modesetting" ] - commandArray += [ "-readconfig" ] - else: - commandArray += [ "-resolution", f"{gameResolution['width']}x{gameResolution['height']}" ] - - # Refresh rate options to help with screen tearing - # syncrefresh is unlisted, it requires specific display timings and 99.9% of users will get unplayable games. - # Leaving it so it can be set manually, for CRT or other arcade-specific display users. - if system.config.get_bool("vsync"): - commandArray += [ "-waitvsync" ] - if system.config.get_bool("syncrefresh"): - commandArray += [ "-syncrefresh" ] - - # Rotation / TATE options - if (rotation := system.config.get("rotation")) in ["autoror", "autorol"]: - commandArray += [ f"-{rotation}" ] - - # Artwork crop - if system.config.get_bool("artworkcrop"): - commandArray += [ "-artwork_crop" ] - - # UI enable - for computer systems, the default sends all keys to the emulated system. - # This will enable hotkeys, but some keys may pass through to MAME and not be usable in the emulated system. - # Hotkey + D-Pad Up will toggle this when in use (scroll lock key) - if system.config.get_bool("enableui", True): - commandArray += [ "-ui_active" ] - - # Load selected plugins - pluginsToLoad = [] - if system.config.get_bool("hiscoreplugin", True): - pluginsToLoad += [ "hiscore" ] - if system.config.get_bool("coindropplugin"): - pluginsToLoad += [ "coindrop" ] - if system.config.get_bool("dataplugin"): - pluginsToLoad += [ "data" ] - if system.config.get_bool('offscreenreload'): # new offscreenreload for light guns games - pluginsToLoad += [ "offscreenreload" ] - if pluginsToLoad: - commandArray += [ "-plugins", "-plugin", ",".join(pluginsToLoad) ] - - # Mouse - useMouse = False - if system.config.get_bool('use_mouse') or not (messSysName[messMode] == "" or messMode == -1): - useMouse = True - commandArray += [ "-dial_device", "mouse" ] - commandArray += [ "-trackball_device", "mouse" ] - commandArray += [ "-paddle_device", "mouse" ] - commandArray += [ "-positional_device", "mouse" ] - commandArray += [ "-mouse_device", "mouse" ] - commandArray += [ "-ui_mouse" ] - if not system.config.use_guns: - commandArray += [ "-lightgun_device", "mouse" ] - commandArray += [ "-adstick_device", "mouse" ] - else: - commandArray += [ "-dial_device", "joystick" ] - commandArray += [ "-trackball_device", "joystick" ] - commandArray += [ "-paddle_device", "joystick" ] - commandArray += [ "-positional_device", "joystick" ] - commandArray += [ "-mouse_device", "joystick" ] - if not system.config.use_guns: - commandArray += [ "-lightgun_device", "joystick" ] - commandArray += [ "-adstick_device", "joystick" ] - # Multimouse option currently hidden in ES, SDL only detects one mouse. - # Leaving code intact for testing & possible ManyMouse integration - multiMouse = system.config.get_bool('multimouse') - if multiMouse: - commandArray += [ "-multimouse" ] - - # guns - useGuns = system.config.use_guns - if useGuns: - commandArray += [ "-lightgunprovider", "udev" ] - commandArray += [ "-lightgun_device", "lightgun" ] - commandArray += [ "-adstick_device", "lightgun" ] - - # wheels - useWheels = system.config.use_wheels - - if system.config.get_bool('multiscreens'): - screens = videoMode.getScreensInfos(system.config) - if len(screens) > 1: - commandArray += [ "-numscreens", str(len(screens)) ] - - # Finally we pass game name - # MESS will use the full filename and pass the system & rom type parameters if needed. - if messSysName[messMode] == "" or messMode == -1: - commandArray += [ romBasename ] - else: - messModel = messSysName[messMode] - # Alternate system for machines that have different configs (ie computers with different hardware) - if altmodel := system.config.get("altmodel"): - messModel = altmodel - commandArray += [ messModel ] - - #TI-99 32k RAM expansion & speech modules - enabled by default - if system.name == "ti99": - commandArray += [ "-ioport", "peb" ] - if system.config.get_bool("ti99_32kram", True): - commandArray += ["-ioport:peb:slot2", "32kmem"] - if system.config.get_bool("ti99_speech", True): - commandArray += ["-ioport", "speechsyn"] - - #Laser 310 Memory Expansion & Joystick - if system.name == "laser310": - commandArray += ['-io', 'joystick', "-mem", system.config.get('memslot', 'laser_64k')] - - # BBC Joystick - if system.name == "bbcmicro" and (sticktype := system.config.get('sticktype', 'none')) != 'none': - commandArray += ["-analogue", sticktype] - specialController = sticktype - - # Enterprise - if system.name == "enterprise": - commandArray += ['-exp', 'exdos'] - - # Apple II - if system.name == "apple2": - rom_extension = rom.suffix.lower() - # only add SD/IDE control if provided a hard drive image - if rom_extension in {".hdv", ".2mg", ".chd", ".iso", ".bin", ".cue"}: - commandArray += ["-sl7", "cffa202"] - if (gameio := system.config.get('gameio', 'none')) != 'none': - if gameio == 'joyport' and messModel != 'apple2p': - _logger.debug("Joyport joystick is only compatible with Apple II Plus") - else: - commandArray += ["-gameio", gameio] - specialController = gameio - - # RAM size (Mac excluded, special handling below) - ramSize = system.config.get_int('ramsize') - if system.name != "macintosh" and ramSize: - commandArray += [ '-ramsize', f'{ramSize}M' ] - - # Mac RAM & Image Reader (if applicable) - if system.name == "macintosh" and ramSize: - if messModel in [ 'maciix', 'maclc3' ]: - if messModel == 'maclc3' and ramSize == 2: - ramSize = 4 - if messModel == 'maclc3' and ramSize > 80: - ramSize = 80 - if messModel == 'maciix' and ramSize == 16: - ramSize = 32 - if messModel == 'maciix' and ramSize == 48: - ramSize = 64 - commandArray += [ '-ramsize', f'{ramSize}M' ] - if messModel == 'maciix': - imageSlot = system.config.get('imagereader', 'nba') - if imageSlot != "disabled": - commandArray += [ f"-{imageSlot}", "image" ] - - altromtype = system.config.get_str("altromtype") - - if softList == "": - # Boot disk for Macintosh - # Will use Floppy 1 or Hard Drive, depending on the disk. - boot_disk = system.config.get("bootdisk") - if system.name == "macintosh" and boot_disk: - if boot_disk in [ "macos30", "macos608", "macos701", "macos75" ]: - bootType = "-flop1" - bootDisk = f"/userdata/bios/{boot_disk}.img" - else: - bootType = "-hard" - bootDisk = f"/userdata/bios/{boot_disk}.chd" - commandArray += [ bootType, bootDisk ] - - # Alternate ROM type for systems with mutiple media (ie cassette & floppy) - # Mac will auto change floppy 1 to 2 if a boot disk is enabled - # Only one drive on FMTMarty - if system.name != "macintosh": - if altromtype: - if messModel == "fmtmarty" and altromtype == "flop1": - commandArray += [ "-flop" ] - else: - commandArray += [ f'-{altromtype}' ] - elif system.name == "adam": - # add some logic based on the rom extension - rom_extension = rom.suffix - if rom_extension == ".ddp": - commandArray += [ "-cass1" ] - elif rom_extension == ".dsk": - commandArray += [ "-flop1" ] - else: - commandArray += [ "-cart1" ] - elif system.name in ("coco", "dragon64"): - if romExt.casefold() == ".cas": - commandArray += [ "-cass" ] - elif romExt.casefold() == ".dsk": - commandArray += [ "-flop1" ] - else: - commandArray += [ "-cart" ] - elif system.name == "sc3000": - if romExt.casefold() in (".cas", ".wav", ".bit"): - commandArray += [ "-cass" ] - else: - commandArray += [ "-cart" ] - elif system.name == "segaai": - if romExt.casefold() in (".wav", ".flac", ".cas"): - commandArray += [ "-cass" ] - else: - commandArray += [ "-card" ] - elif system.name == "mc10": - if romExt.casefold() == ".cas": - commandArray += [ "-cass" ] - else: - commandArray += [ "-cart" ] - else: - commandArray += [ f'-{messRomType[messMode]}' ] - else: - if boot_disk: - if (altromtype == "flop1" or not altromtype) and boot_disk in [ "macos30", "macos608", "macos701", "macos75" ]: - commandArray += [ "-flop2" ] - elif altromtype: - commandArray += [ f'-{altromtype}' ] - else: - commandArray += [ f'-{messRomType[messMode]}' ] - else: - if altromtype: - commandArray += [ f'-{altromtype}' ] - else: - commandArray += [ f'-{messRomType[messMode]}' ] - # Use the full filename for MESS ROMs - commandArray += [ rom ] - else: - # Prepare software lists - if softList != "": - mkdir_if_not_exists(softDir) - for checkFile in softDir.iterdir(): - if checkFile.is_symlink(): - checkFile.unlink() - if checkFile.is_dir(): - shutil.rmtree(checkFile) - mkdir_if_not_exists(softDir / "hash") - (softDir / "hash" / f"{softList}.xml").symlink_to(f"/usr/bin/mame/hash/{softList}.xml") - if softList in subdirSoftList: - (softDir / softList).symlink_to(romDirname.parents[0], target_is_directory=True) - commandArray += [ romDirname.name ] - else: - (softDir / softList).symlink_to(romDirname, target_is_directory=True) - commandArray += [ romName ] - - # Create & add a blank disk if needed, insert into drive 2 - # or drive 1 if drive 2 is selected manually or FM Towns Marty. - if system.config.get_bool('addblankdisk'): - if system.name == 'fmtowns': - blankDisk = Path('/usr/share/mame/blank.fmtowns') - targetFolder = MAME_SAVES / system.name - targetDisk = targetFolder / romName - # Add elif statements here for other systems if enabled - else: - blankDisk = Path('/usr/share/mame/blank.default') - targetFolder = MAME_SAVES / system.name - targetDisk = targetFolder / f'{romName}.default' - mkdir_if_not_exists(targetFolder) - if not targetDisk.exists(): - shutil.copy2(blankDisk, targetDisk) - # Add other single floppy systems to this if statement - if messModel == "fmtmarty": - commandArray += [ '-flop', targetDisk ] - elif system.config.get('altromtype') == 'flop2': - commandArray += [ '-flop1', targetDisk ] - else: - commandArray += [ '-flop2', targetDisk ] - - autoRunCmd = "" - autoRunDelay = 0 - # Autostart computer games where applicable - # bbc has different boots for floppy & cassette, no special boot for carts - if system.name == "bbcmicro": - if altromtype or softList: - if altromtype == "cass" or softList.endswith("cass"): - autoRunCmd = '*tape\\nchain""\\n' - autoRunDelay = 2 - elif (altromtype and altromtype.startswith("flop")) or softList.endswith("flop"): - autoRunCmd = '*cat\\n\\n\\n\\n*exec !boot\\n' - autoRunDelay = 3 - else: - autoRunCmd = '*cat\\n\\n\\n\\n*exec !boot\\n' - autoRunDelay = 3 - # fm7 boots floppies, needs cassette loading - elif system.name == "fm7": - if ( - altromtype == "cass" - or (softList and softList[-4:] == "cass") - ): - autoRunCmd = 'LOADM”“,,R\\n' - autoRunDelay = 5 - elif system.name in ("coco", "dragon64"): - romType = 'cart' - autoRunDelay = 2 - - # if using software list, use "usage" for autoRunCmd (if provided) - if softList != "": - softListFile = Path('/usr/bin/mame/hash') / f'{softList}.xml' - if softListFile.exists(): - softwarelist = ET.parse(softListFile) - for software in softwarelist.findall('software'): - if software.attrib and software.get('name') == romName: - for info in software.iter('info'): - if info.get('name') == 'usage': - autoRunCmd = f"{info.get('value')}\\n" - - # if still undefined, default autoRunCmd based on media type - if autoRunCmd == "": - if altromtype == "cass" or (softList and softList.endswith("cass")) or romExt.casefold() == ".cas": - romType = 'cass' - if romName.casefold().endswith(".bas"): - autoRunCmd = 'CLOAD:RUN\\n' - else: - autoRunCmd = 'CLOADM:EXEC\\n' - if (altromtype == "flop1") or (softList and softList.endswith("flop")) or romExt.casefold() == ".dsk": - romType = 'flop' - if romName.casefold().endswith(".bas"): - autoRunCmd = f'RUN \"{romName}\"\\n' - else: - autoRunCmd = f'LOADM \"{romName}\":EXEC\\n' - - # check for a user override - autoRunFile = MAME_CONFIG / 'autoload' / f'{system.name}_{romType}_autoload.csv' - if autoRunFile.exists(): - with autoRunFile.open() as openARFile: - autoRunList = csv.reader(openARFile, delimiter=';', quotechar="'") - for row in autoRunList: - if row and not row[0].startswith('#') and row[0].casefold() == romName.casefold(): - autoRunCmd = f"{row[1]}\\n" - elif system.name == "mc10": - romType = 'cart' - autoRunDelay = 2 - - # if using software list, use "usage" for autoRunCmd (if provided) - if softList != "": - softListFile = Path('/usr/bin/mame/hash') / f'{softList}.xml' - if softListFile.exists(): - softwarelist = ET.parse(softListFile) - for software in softwarelist.findall('software'): - if software.attrib and software.get('name') == romName: - for info in software.iter('info'): - if info.get('name') == 'usage': - autoRunCmd = f"{info.get('value')}\\n" - - # if still undefined, default autoRunCmd based on media type - if autoRunCmd == "": - if altromtype == "cass" or (softList and softList.endswith("cass")) or romExt.casefold() == ".cas": - romType = 'cass' - autoRunCmd = 'CLOAD\\n' - - # check for a user override - autoRunFile = MAME_CONFIG / 'autoload' / f'{system.name}_{romType}_autoload.csv' - if autoRunFile.exists(): - with autoRunFile.open() as openARFile: - autoRunList = csv.reader(openARFile, delimiter=';', quotechar="'") - for row in autoRunList: - if row and not row[0].startswith('#') and row[0].casefold() == romName.casefold(): - autoRunCmd = f"{row[1]}\\n" - elif system.name == "atom": - autoRunDelay = 1 - autoRunCmd = messAutoRun[messMode] - # Check if the media being used is a floppy type - if ( - (altromtype == "flop1") or - (softList and softList.endswith("flop")) or - is_atom_floppy(rom) - ): - autoRunFile = MAME_DEFAULT_DATA / 'atom_flop_autoload.csv' - if autoRunFile.exists(): - with autoRunFile.open() as openARFile: - autoRunList = csv.reader(openARFile, delimiter=';', quotechar="'") - for row in autoRunList: - if row and not row[0].startswith('#') and row[0].casefold() == romName.casefold(): - autoRunCmd = f"{row[1]}\\n" - break - else: - # Check for an override file, otherwise use generic (if it exists) - autoRunCmd = messAutoRun[messMode] - autoRunFile = MAME_DEFAULT_DATA / f'{softList}_autoload.csv' - if autoRunFile.exists(): - with autoRunFile.open() as openARFile: - autoRunList = csv.reader(openARFile, delimiter=';', quotechar="'") - for row in autoRunList: - if row[0].casefold() == romName.casefold(): - autoRunCmd = f"{row[1]}\\n" - autoRunDelay = 3 - if autoRunCmd != "": - if autoRunCmd.startswith("'"): - autoRunCmd.replace("'", "") - commandArray += [ "-autoboot_delay", str(autoRunDelay), "-autoboot_command", autoRunCmd ] - - # bezels - bezelSet = system.config.get_str('bezel') or None - if system.config.get_bool('forceNoBezel'): - bezelSet = None - - try: - if messMode != -1: - MameGenerator.writeBezelConfig(bezelSet, system, rom, messSysName[messMode], gameResolution, system.guns_borders_size_name(guns), system.guns_border_ratio_type(guns)) - else: - MameGenerator.writeBezelConfig(bezelSet, system, rom, "", gameResolution, system.guns_borders_size_name(guns), system.guns_border_ratio_type(guns)) - except Exception: - MameGenerator.writeBezelConfig(None, system, rom, "", gameResolution, system.guns_borders_size_name(guns), system.guns_border_ratio_type(guns)) - - buttonLayout = getMameControlScheme(system, rom) - - if messMode == -1: - mameControllers.generatePadsConfig(cfgPath, playersControllers, "", buttonLayout, customCfg, specialController, bezelSet, useGuns, guns, useWheels, wheels, useMouse, multiMouse, system) - else: - mameControllers.generatePadsConfig(cfgPath, playersControllers, messModel, buttonLayout, customCfg, specialController, bezelSet, useGuns, guns, useWheels, wheels, useMouse, multiMouse, system) - - # If user provided a custom cmd file at the default location, use that as the customized commandArray - if (defaultCustomCmdFilepath := Path(f"{rom}.cmd")).is_file(): - with defaultCustomCmdFilepath.open() as f: - commandArray = f.read().splitlines() # pyright: ignore - - # Change directory to MAME folder (allows data plugin to load properly) - os.chdir('/usr/bin/mame') - return Command.Command( - array=commandArray, - env={ - "PWD":"/usr/bin/mame/", - "XDG_CONFIG_HOME": CONFIGS, - "XDG_CACHE_HOME": SAVES - } - ) + return _generate_mame(system, rom, playersControllers, metadata, guns, wheels, gameResolution) @staticmethod def writeBezelConfig(bezelSet: str | None, system: Emulator, rom: Path, messSys: str, gameResolution: Resolution, gunsBordersSize: str | None, gunsBordersRatio: str | None) -> None: @@ -821,6 +251,359 @@ def getMameMachineSize(machine: str, tmpdir: Path): raise BatoceraException("Display element not found") +def _generate_mame(system, rom, playersControllers, metadata, guns, wheels, gameResolution): + romBasename = rom.name + customCfg = system.config.get_bool("customcfg") + cfgPath = MAME_CONFIG / "custom" if customCfg else MAME_CONFIG + + extra_plugins = [ "offscreenreload" ] if system.config.get_bool('offscreenreload') else [] + commandArray = _mame_common_options(system, rom, cfgPath, gameResolution, extra_plugins) + + # Mouse + useMouse = False + if system.config.get_bool('use_mouse'): + useMouse = True + commandArray += [ "-dial_device", "mouse", "-trackball_device", "mouse", + "-paddle_device", "mouse", "-positional_device", "mouse", + "-mouse_device", "mouse", "-ui_mouse" ] + if not system.config.use_guns: + commandArray += [ "-lightgun_device", "mouse", "-adstick_device", "mouse" ] + else: + commandArray += [ "-dial_device", "joystick", "-trackball_device", "joystick", + "-paddle_device", "joystick", "-positional_device", "joystick", + "-mouse_device", "joystick" ] + if not system.config.use_guns: + commandArray += [ "-lightgun_device", "joystick", "-adstick_device", "joystick" ] + + # Multimouse option currently hidden in ES, SDL only detects one mouse. + # Leaving code intact for testing & possible ManyMouse integration + multiMouse = system.config.get_bool('multimouse') + if multiMouse: + commandArray += [ "-multimouse" ] + + useGuns = system.config.use_guns + if useGuns: + commandArray += [ "-lightgunprovider", "udev", + "-lightgun_device", "lightgun", "-adstick_device", "lightgun" ] + + useWheels = system.config.use_wheels + + commandArray += [ romBasename ] + + bezelSet = system.config.get_str('bezel') or None + if system.config.get_bool('forceNoBezel'): + bezelSet = None + try: + MameGenerator.writeBezelConfig(bezelSet, system, rom, "", gameResolution, system.guns_borders_size_name(guns), system.guns_border_ratio_type(guns)) + except Exception: + MameGenerator.writeBezelConfig(None, system, rom, "", gameResolution, system.guns_borders_size_name(guns), system.guns_border_ratio_type(guns)) + + buttonLayout = getMameControlScheme(system, rom) + mameControllers.generatePadsConfig(cfgPath, playersControllers, "", buttonLayout, customCfg, "none", bezelSet, useGuns, guns, useWheels, wheels, useMouse, multiMouse, system) + + if (defaultCustomCmdFilepath := Path(f"{rom}.cmd")).is_file(): + with defaultCustomCmdFilepath.open() as f: + commandArray = f.read().splitlines() + + os.chdir('/usr/bin/mame') + return Command.Command( + array=commandArray, + env={ + "PWD":"/usr/bin/mame/", + "XDG_CONFIG_HOME": CONFIGS, + "XDG_CACHE_HOME": SAVES, + } + ) + + +def _mame_common_options(system, rom, cfgPath, gameResolution, extra_plugins=None): + """Build the command-line args and create dirs common to MAME arcade and MESS.""" + romDirname = rom.parent + + for path in [ + MAME_CONFIG, + MAME_SAVES / "nvram", + MAME_SAVES / "cfg", + MAME_SAVES / "input", + MAME_SAVES / "state", + MAME_SAVES / "diff", + MAME_SAVES / "comments", + MAME_BIOS / "artwork" / "crosshairs", + MAME_CHEATS, + MAME_SAVES / "plugins", + MAME_CONFIG / "ctrlr", + MAME_CONFIG / "ini", + ]: + mkdir_if_not_exists(path) + mkdir_if_not_exists(cfgPath) + + # MAME options used here are explained as it's not always straightforward + # A lot more options can be configured, just run mame -showusage and have a look + commandArray: list[str | Path] = [ "/usr/bin/mame/mame" ] + + # set audio to pipewire to fix audio from 0.278 + commandArray += [ "-sound", "pipewire" ] + # skip game info at start + commandArray += [ "-skip_gameinfo" ] + commandArray += [ "-rompath", f"{romDirname};{MAME_BIOS};{BIOS}" ] + + # MAME various paths we can probably do better + commandArray += [ "-bgfx_path", "/usr/bin/mame/bgfx/" ] # Core bgfx files can be left on ROM filesystem + commandArray += [ "-fontpath", "/usr/bin/mame/" ] # Fonts can be left on ROM filesystem + commandArray += [ "-languagepath", "/usr/bin/mame/language/" ] # Translations can be left on ROM filesystem + commandArray += [ "-pluginspath", f"/usr/bin/mame/plugins/;{MAME_SAVES / 'plugins'}" ] + commandArray += [ "-samplepath", MAME_BIOS / "samples" ] # Current batocera storage location for MAME samples + commandArray += [ "-artpath", f"/var/run/mame_artwork/;/usr/bin/mame/artwork/;{MAME_BIOS / 'artwork'};{USER_DECORATIONS}" ] # first for systems ; second for overlays + + # Enable cheats + commandArray += [ "-cheat" ] + commandArray += [ "-cheatpath", MAME_CHEATS ] # Should this point to path containing the cheat.7z file + + # Logs and SwitchRes ini read by default (including its own verbose) + commandArray += [ "-verbose" ] + commandArray += [ "-switchres_ini" ] + + # MAME saves a lot of stuff, we need to map this on /userdata/saves/mame/ for each one + commandArray += [ "-nvram_directory", MAME_SAVES / "nvram" ] + commandArray += [ "-cfg_directory", cfgPath ] + commandArray += [ "-input_directory", MAME_SAVES / "input" ] + commandArray += [ "-state_directory", MAME_SAVES / "state" ] + commandArray += [ "-snapshot_directory", SCREENSHOTS ] + commandArray += [ "-diff_directory", MAME_SAVES / "diff" ] + commandArray += [ "-comment_directory", MAME_SAVES / "comments" ] + commandArray += [ "-homepath", MAME_SAVES / "plugins" ] + commandArray += [ "-ctrlrpath", MAME_CONFIG / "ctrlr" ] + commandArray += [ "-inipath", f"{MAME_CONFIG};{MAME_CONFIG / 'ini'}" ] + commandArray += [ "-crosshairpath", MAME_BIOS / "artwork" / "crosshairs" ] + + # BGFX video engine : https://docs.mamedev.org/advanced/bgfx.html + video = system.config.get("video") + if video == "bgfx": + commandArray += [ "-video", "bgfx" ] + # BGFX backend + bgfxbackend = system.config.get("bgfxbackend", "automatic") + commandArray += [ "-bgfx_backend", "auto" if bgfxbackend == "automatic" else bgfxbackend ] + # BGFX shaders effects + commandArray += [ "-bgfx_screen_chains", system.config.get("bgfxshaders", "default") ] + # Other video modes + elif video == "accel": + commandArray += [ "-video", "accel" ] + else: + commandArray += [ "-video", "auto" ] + + # CRT / SwitchRes support + if system.config.get_bool("switchres"): + commandArray += [ "-modeline_generation", "-changeres", "-modesetting", "-readconfig" ] + else: + commandArray += [ "-resolution", f"{gameResolution['width']}x{gameResolution['height']}" ] + + # Refresh rate options to help with screen tearing + # syncrefresh is unlisted, it requires specific display timings and 99.9% of users will get unplayable games. + # Leaving it so it can be set manually, for CRT or other arcade-specific display users. + if system.config.get_bool("vsync"): + commandArray += [ "-waitvsync" ] + if system.config.get_bool("syncrefresh"): + commandArray += [ "-syncrefresh" ] + + # Rotation / TATE options + if (rotation := system.config.get("rotation")) in ["autoror", "autorol"]: + commandArray += [ f"-{rotation}" ] + + # Artwork crop + if system.config.get_bool("artworkcrop"): + commandArray += [ "-artwork_crop" ] + + # UI enable - for computer systems, the default sends all keys to the emulated system. + # This will enable hotkeys, but some keys may pass through to MAME and not be usable in the emulated system. + # Hotkey + D-Pad Up will toggle this when in use (scroll lock key) + if system.config.get_bool("enableui", True): + commandArray += [ "-ui_active" ] + + # Load selected plugins + pluginsToLoad = [] + if system.config.get_bool("hiscoreplugin", True): + pluginsToLoad += [ "hiscore" ] + if system.config.get_bool("coindropplugin"): + pluginsToLoad += [ "coindrop" ] + if system.config.get_bool("dataplugin"): + pluginsToLoad += [ "data" ] + if extra_plugins: + pluginsToLoad.extend(extra_plugins) + if pluginsToLoad: + commandArray += [ "-plugins", "-plugin", ",".join(pluginsToLoad) ] + + if system.config.get_bool("multiscreens"): + screens = videoMode.getScreensInfos(system.config) + if len(screens) > 1: + commandArray += [ "-numscreens", str(len(screens)) ] + + return commandArray + + +def _generate_mess(system, rom, playersControllers, metadata, guns, wheels, gameResolution): + for path in [ + MAME_CONFIG, + MAME_SAVES / "nvram", + MAME_SAVES / "cfg", + MAME_SAVES / "input", + MAME_SAVES / "state", + MAME_SAVES / "diff", + MAME_SAVES / "comments", + MAME_BIOS / "artwork" / "crosshairs", + MAME_CHEATS, + MAME_SAVES / "plugins", + MAME_CONFIG / "ctrlr", + MAME_CONFIG / "ini", + ]: + mkdir_if_not_exists(path) + + softlist_map = _load_softlist_map() + rom_sha1 = _compute_sha1(rom) + _logger.debug("MESS: SHA1 of %s = %s", rom.name, rom_sha1) + + rom_info = _lookup_rom(rom_sha1) + if rom_info is not None: + softlist = rom_info["softlist"] + xml_media = rom_info["media"] + _logger.info("MESS: identified %s as softlist=%s software=%s xml_media=%s", + rom.name, softlist, rom_info["software"], xml_media) + sys_info = softlist_map.get(softlist, {}) + machine = system.config.get_str("altmodel") or sys_info.get("machine") + if not machine: + machine = _machine_from_softlist(softlist) + _logger.info("MESS: softlist '%s' not in messSoftlistMap.json, inferred machine=%s", + softlist, machine) + media = system.config.get_str("altromtype") or sys_info.get("media") or xml_media + _logger.info("MESS: media resolved to %s (softlistmap=%s xml=%s)", + media, sys_info.get("media"), xml_media) + else: + softlist = "" + sys_info = {} + try: + systems_mapping = json.loads(MESS_SYSTEMS_MAPPING.read_text()) + sys_ext_map = systems_mapping.get(system.name, {}) + rom_ext = rom.suffix.lower() + if rom_ext == ".zip": + try: + with zipfile.ZipFile(rom, "r") as zf: + names = [n for n in zf.namelist() if not n.endswith("/")] + if names: + rom_ext = Path(names[0]).suffix.lower() + except (zipfile.BadZipFile, OSError): + pass + softlist = sys_ext_map.get(rom_ext) or sys_ext_map.get("*") or "" + if softlist: + _logger.info("MESS: ROM not autodetected — found system '%s' ext '%s' in messSystems.json: softlist=%s", + system.name, rom_ext, softlist) + except OSError: + _logger.warning("MESS: messSystems.json not found at %s", MESS_SYSTEMS_MAPPING) + + if softlist: + sys_info = softlist_map.get(softlist, {}) + machine = system.config.get_str("altmodel") or sys_info.get("machine") + if not machine: + machine = _machine_from_softlist(softlist) + _logger.info("MESS: softlist '%s' not in messSoftlistMap.json, inferred machine=%s", + softlist, machine) + else: + machine = None + + machine = system.config.get_str("machine") or machine + media = system.config.get_str("media") or sys_info.get("media") + if not machine or not media: + raise BatoceraException( + f"ROM '{rom.name}' (sha1={rom_sha1}) was not found in the MAME " + "software-list database. " + "Machine and media must be configured manually " + "(set 'machine' and 'media' in the system options)." + ) + _logger.info("MESS: ROM not autodetected — using machine=%s media=%s", machine, media) + + customCfg = system.config.get_bool("customcfg") + mkdir_if_not_exists(MAME_CONFIG / machine) + cfgPath = MAME_CONFIG / machine / "custom" if customCfg else MAME_CONFIG / machine + + commandArray = _mame_common_options(system, rom, cfgPath, gameResolution) + + # Computer systems always use mouse + commandArray += [ + "-dial_device", "mouse", + "-trackball_device", "mouse", + "-paddle_device", "mouse", + "-positional_device", "mouse", + "-mouse_device", "mouse", + "-ui_mouse", + ] + if not system.config.use_guns: + commandArray += ["-lightgun_device", "mouse", "-adstick_device", "mouse"] + if system.config.use_guns: + commandArray += ["-lightgunprovider", "udev", + "-lightgun_device", "lightgun", + "-adstick_device", "lightgun"] + + commandArray += [machine] + for arg in sys_info.get("extra_args", []): + commandArray.append(arg) + commandArray += _build_config_args(sys_info.get("config_args", []), system, machine) + commandArray += _build_rom_ext_args(sys_info.get("rom_ext_args", []), rom) + + commandArray += [f"-{media}", str(rom)] + + if system.config.get_bool("addblankdisk"): + machine_blank = Path(f"/usr/share/mame/blank.{machine}") + blankDisk = machine_blank if machine_blank.exists() else Path("/usr/share/mame/blank.default") + targetFolder = MAME_SAVES / system.name + targetDisk = targetFolder / f"{rom.stem}.{blankDisk.name.split('.', 1)[-1]}" + mkdir_if_not_exists(targetFolder) + if not targetDisk.exists(): + shutil.copy2(blankDisk, targetDisk) + if machine in ("fmtmarty", "fmtowns"): + commandArray += ["-flop", targetDisk] + elif system.config.get_str("altromtype") == "flop2": + commandArray += ["-flop1", targetDisk] + else: + commandArray += ["-flop2", targetDisk] + + lua_script_name = sys_info.get("lua_script") + if lua_script_name: + lua_path = MESS_AUTOBOOT_SCRIPTS / lua_script_name + if lua_path.exists(): + commandArray += ["-autoboot_script", str(lua_path)] + else: + _logger.warning("MESS: Lua autoboot script not found: %s", lua_path) + + if (custom_cmd_file := Path(f"{rom}.cmd")).is_file(): + commandArray = custom_cmd_file.read_text().splitlines() + + bezelSet = system.config.get_str("bezel") or None + if system.config.get_bool("forceNoBezel"): + bezelSet = None + try: + MameGenerator.writeBezelConfig(bezelSet, system, rom, machine, gameResolution, + system.guns_borders_size_name(guns), system.guns_border_ratio_type(guns)) + except Exception: + MameGenerator.writeBezelConfig(None, system, rom, machine, gameResolution, + system.guns_borders_size_name(guns), system.guns_border_ratio_type(guns)) + + mameControllers.generatePadsConfig( + cfgPath, playersControllers, machine, + "default", customCfg, "none", bezelSet, + system.config.use_guns, guns, + system.config.use_wheels, wheels, + True, False, system, + ) + + os.chdir("/usr/bin/mame") + return Command.Command( + array=commandArray, + env={ + "PWD": "/usr/bin/mame/", + "XDG_CONFIG_HOME": CONFIGS, + "XDG_CACHE_HOME": SAVES, + }, + ) + + def getMameControlScheme(system: Emulator, rom_path: Path) -> MameControlScheme: # Game list files mameCapcom = MAME_DEFAULT_DATA / 'mameCapcom.txt' diff --git a/package/batocera/core/batocera-configgen/configgen/configgen/generators/mame/mamePaths.py b/package/batocera/core/batocera-configgen/configgen/configgen/generators/mame/mamePaths.py index db102e8d679..7df5c8c1dc6 100644 --- a/package/batocera/core/batocera-configgen/configgen/configgen/generators/mame/mamePaths.py +++ b/package/batocera/core/batocera-configgen/configgen/configgen/generators/mame/mamePaths.py @@ -10,3 +10,10 @@ MAME_CHEATS: Final = CHEATS / "mame" MAME_ROMS: Final = ROMS / "mame" MAME_DEFAULT_DATA: Final = DEFAULTS_DIR / "data" / "mame" + +MESS_ROMS: Final = ROMS / "mess" +MESS_SOFTLIST_MAP: Final = MAME_DEFAULT_DATA / "messSoftlistMap.json" +MESS_SYSTEMS_MAPPING: Final = MAME_DEFAULT_DATA / "messSystems.json" +MESS_AUTOBOOT_SCRIPTS: Final = MAME_DEFAULT_DATA / "autoboot_scripts" +MESS_HASH_CACHE: Final = MAME_SAVES / "mess_hash_cache.json" +MAME_HASH_DIR: Final = MAME_BIOS / "hash" diff --git a/package/batocera/core/batocera-configgen/configgen/configgen/generators/mame/messUtils.py b/package/batocera/core/batocera-configgen/configgen/configgen/generators/mame/messUtils.py new file mode 100644 index 00000000000..eda3ca6acf5 --- /dev/null +++ b/package/batocera/core/batocera-configgen/configgen/configgen/generators/mame/messUtils.py @@ -0,0 +1,241 @@ +from __future__ import annotations + +import hashlib +import json +import logging +import re +import time +import xml.etree.ElementTree as ET +import zipfile +from pathlib import Path +from typing import TypedDict + +from ...batoceraPaths import mkdir_if_not_exists +from .mamePaths import ( + MAME_HASH_DIR, + MESS_HASH_CACHE, + MESS_SOFTLIST_MAP, +) + +_logger = logging.getLogger(__name__) + +_MAME_BUILTIN_HASH_DIR = Path("/usr/bin/mame/hash") +_CACHE_VERSION = 1 + + +class RomInfo(TypedDict): + softlist: str + software: str + media: str + + +# cdrom must precede cd so that _cdrom is not partially matched as _cd +_SOFTLIST_SUFFIX_RE = re.compile( + r'_(cdrom|flop|cart|cass|disk|cd|rom|snap|hdd|quik|qd|cyl|ptp|ctape|card|ssd).*$' +) + + +def _machine_from_softlist(softlist: str) -> str: + """Derive a machine name from a softlist name by stripping trailing media suffixes.""" + return _SOFTLIST_SUFFIX_RE.sub('', softlist) + + +def _lookup_rom(sha1: str) -> RomInfo | None: + """Look up a SHA1 in the MAME software-list cache, building it if needed.""" + cache = _load_or_build_hash_cache() + return cache.get(sha1) + + +def _build_config_args(config_args: list[dict], system, machine: str) -> list[str]: + """ + Evaluate a config_args spec from messSoftlistMap.json against the live system + config and return the resulting MAME command-line tokens. + """ + result: list[str] = [] + for item in config_args: + key = item["key"] + kind = item.get("type", "str") + skip_if = item.get("skip_if") + + only = item.get("only_machines") + if only is not None and machine not in only: + continue + + overrides: dict = item.get("machine_overrides", {}).get(machine, {}) + + if kind == "bool": + value = system.config.get_bool(key, item.get("default", False)) + if value: + result += item.get("if_true", []) + else: + result += item.get("if_false", []) + + elif kind == "int": + value = system.config.get_int(key) or 0 + if skip_if is not None and value == skip_if: + continue + if value: + value = overrides.get("value_map", {}).get(str(value), value) + if "max" in overrides: + value = min(value, overrides["max"]) + result += [s.replace("{value}", str(value)) for s in item.get("args", [])] + + else: # str + value = system.config.get_str(key) or item.get("default", "") + if skip_if is not None and value == skip_if: + continue + if value: + restriction = item.get("value_machine_restriction", {}) + if value in restriction and machine not in restriction[value]: + _logger.debug( + "MESS: skipping -%s %s: not supported on machine %s (allowed: %s)", + key, value, machine, restriction[value], + ) + continue + result += [s.replace("{value}", value) for s in item.get("args", [])] + + return result + + +def _build_rom_ext_args(rom_ext_args: list[dict], rom: Path) -> list[str]: + """Emit static args based on the ROM file extension.""" + ext = rom.suffix.lower() + result: list[str] = [] + for item in rom_ext_args: + if ext in item.get("extensions", []): + result += item.get("args", []) + return result + + +def _load_softlist_map() -> dict: + """Load the softlist→machine/media/autoboot mapping JSON.""" + if not MESS_SOFTLIST_MAP.exists(): + _logger.warning("MESS: messSoftlistMap.json not found at %s", MESS_SOFTLIST_MAP) + return {} + try: + with MESS_SOFTLIST_MAP.open() as f: + data = json.load(f) + data.pop("_comment", None) + return data + except (json.JSONDecodeError, OSError) as exc: + _logger.error("MESS: Failed to load messSoftlistMap.json: %s", exc) + return {} + + +def _compute_sha1(rom: Path) -> str: + """ + Compute the SHA1 of the ROM's raw data. + + For .zip archives, hashes the first file inside (as MAME stores sha1 of the + uncompressed content, not the archive itself). + """ + suffix = rom.suffix.casefold() + + if suffix == ".zip": + try: + with zipfile.ZipFile(rom, "r") as zf: + names = [n for n in zf.namelist() if not n.endswith("/")] + if names: + with zf.open(names[0]) as inner: + return _sha1_of_stream(inner) + except (zipfile.BadZipFile, KeyError, OSError) as exc: + _logger.warning("MESS: Could not read zip %s: %s – hashing archive directly", rom, exc) + + with rom.open("rb") as f: + return _sha1_of_stream(f) + + +def _sha1_of_stream(stream) -> str: + h = hashlib.sha1() + for chunk in iter(lambda: stream.read(1 << 20), b""): + h.update(chunk) + return h.hexdigest() + + +def _get_hash_dirs() -> list[Path]: + """Return candidate MAME hash directories, user-supplied first.""" + dirs = [] + if MAME_HASH_DIR.exists(): + dirs.append(MAME_HASH_DIR) + if _MAME_BUILTIN_HASH_DIR.exists(): + dirs.append(_MAME_BUILTIN_HASH_DIR) + return dirs + + +def _hash_dir_mtime() -> float: + """Return the most recent mtime across all hash directories.""" + mtime = 0.0 + for d in _get_hash_dirs(): + try: + mtime = max(mtime, d.stat().st_mtime) + except OSError: + pass + return mtime + + +def _load_or_build_hash_cache() -> dict[str, RomInfo]: + """Load the SHA1→RomInfo cache from disk, rebuilding if stale.""" + if MESS_HASH_CACHE.exists(): + try: + with MESS_HASH_CACHE.open() as f: + data = json.load(f) + if ( + data.get("_version") == _CACHE_VERSION + and data.get("_mtime", 0) >= _hash_dir_mtime() + ): + return data.get("entries", {}) + except (json.JSONDecodeError, OSError): + pass + + _logger.info("MESS: Building software-list hash cache (this may take a moment)…") + t0 = time.monotonic() + entries = _build_hash_index() + elapsed = time.monotonic() - t0 + _logger.info("MESS: Cache built with %d entries in %.1fs", len(entries), elapsed) + + payload = { + "_version": _CACHE_VERSION, + "_mtime": _hash_dir_mtime(), + "entries": entries, + } + try: + mkdir_if_not_exists(MESS_HASH_CACHE.parent) + tmp = MESS_HASH_CACHE.with_suffix(".tmp") + with tmp.open("w") as f: + json.dump(payload, f) + tmp.replace(MESS_HASH_CACHE) + except OSError as exc: + _logger.warning("MESS: Could not write hash cache: %s", exc) + + return entries + + +def _build_hash_index() -> dict[str, RomInfo]: + """Parse all MAME software-list XMLs and build a sha1→RomInfo mapping.""" + index: dict[str, RomInfo] = {} + + for hash_dir in _get_hash_dirs(): + for xml_file in sorted(hash_dir.glob("*.xml")): + softlist_name = xml_file.stem + try: + context = ET.iterparse(xml_file, events=("start",)) + current_software: str = "" + current_media: str = "" + for _, elem in context: + tag = elem.tag + if tag == "software": + current_software = elem.get("name", "") + elif tag == "part": + current_media = elem.get("name", "") + elif tag == "rom": + sha1 = (elem.get("sha1") or "").lower() + if sha1 and current_software and sha1 not in index: + index[sha1] = RomInfo( + softlist=softlist_name, + software=current_software, + media=current_media, + ) + except ET.ParseError as exc: + _logger.warning("MESS: Skipping malformed XML %s: %s", xml_file, exc) + + return index diff --git a/package/batocera/core/batocera-configgen/data/mame/atom_flop_autoload.csv b/package/batocera/core/batocera-configgen/data/mame/atom_flop_autoload.csv deleted file mode 100644 index af46538cb71..00000000000 --- a/package/batocera/core/batocera-configgen/data/mame/atom_flop_autoload.csv +++ /dev/null @@ -1,16 +0,0 @@ -chuckie;\n*DOS\n*DIR\n*RUN"runme" -egghead;\n*DOS\n*DIR\n*RUN"EHRUN" -f14;\n*DOS\n*DIR\n*RUN"F1 4RUN" -gala;\n*DOS\n*DIR\n*RUN"runme" -galxians;\n*DOS\n*DIR\n*RUN"GALAXI" -hardhath;\n*DOS\n*DIR\n*RUN"LOADER" -hypervpr;\n*DOS\n*DIR\n*RUN"LOADER" -jetsetmn;\n*DOS\n*DIR\n*RUN"LOADER" -jsw;\n*DOS\n*DIR\n*RUN"JSWRUN" -jsw2;\n*DOS\n*DIR\n*RUN"JSW2RUN" -joeblade;\n*DOS\n*DIR\n*RUN"JOE" -jungle;\n*DOS\n*DIR\n*RUN"runme" -manicmin;\n*DOS\n*DIR\n*RUN"MMRUN" -repton;\n*DOS\n*DIR\n*RUN"runme" -tetris;\n*DOS\n*DIR\n*RUN"SIDRUN" -flappy;\n*DOS\n*DIR\n*RUN"FLAPPY" \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/a800_flop.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/a800_flop.lua new file mode 100644 index 00000000000..0d64e4e64c2 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/a800_flop.lua @@ -0,0 +1,23 @@ +local button = {} +for key, ports in pairs(manager.machine.ioport.ports) do + for field_name, field in pairs(ports.fields) do + button[field_name] = field + end +end + + +local frame_num = 0 +local function process_frame() + frame_num = frame_num + 1 + + if frame_num == 1 then + button["CONS.2: Option"]:set_value(1) + end + + if frame_num == 300 then + button["CONS.2: Option"]:set_value(0) + end + +end + +subscription=emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/adam_flop.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/adam_flop.lua new file mode 100644 index 00000000000..5b02f16e05b --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/adam_flop.lua @@ -0,0 +1,179 @@ +-- adam_flop.lua +-- +-- Coleco ADAM floppy (SmartFDD) autoboot. +-- +-- Boot flow: +-- EOS (Electronic Operating System) loads the first program from the floppy. +-- Most game disks contain T-DOS 4.5 (a CP/M-compatible OS by Tony Morehen) +-- as that first program. T-DOS then gives an A> command prompt. +-- +-- T-DOS autorun: +-- T-DOS 4.5 looks for a file called PROFILE.SUB on drive A: at boot. +-- If PROFILE.SUB exists the game starts automatically (no script needed). +-- If it does not exist, the user sees A> and must type the executable name. +-- Some disks have a PROFILE.SUB with a non-functional command (e.g. the game +-- title text); in those cases we wait for T-DOS to settle and type the correct +-- CP/M executable name ourselves. +-- +-- Executable detection: +-- Scan the raw .dsk image for the first CP/M directory entry with a .COM +-- extension (user 0, extent 0, printable ASCII name). This works regardless +-- of whether the softlist name matches the executable name. +-- Falls back to an uppercase/truncated version of the softlist name if +-- no .COM entry is found in the first 64 KB of the image. +-- +-- Image slot order for the adam machine: +-- 1: cassette1 2: cassette2 3: floppydisk1 4: floppydisk2 5-8: cartridge1-4 + +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") +local zip_util = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_zip.lua") + +local button = {} +local frame_num = 0 + +common_autoboot.populate_buttons(button) +common_autoboot.print_image_info() + +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION + +local FLOP_SLOT = 3 -- floppydisk1 is the third image slot + +-- T-DOS finishes booting in ~5-7 s on real hardware; MAME emulates at ~60 Hz. +-- 600 frames (~10 s) gives a safe margin for T-DOS to load + PROFILE.SUB to fail +-- before we send the executable name. +local TDOS_PROMPT_FRAME = 600 + +local DSK_SCAN_BYTES = 65536 -- 64 KB covers the directory on any ADAM disk layout + +-- ── CP/M directory scanner ──────────────────────────────────────────────────── +-- +-- CP/M directory entries are 32 bytes: +-- byte 0 : user number (0x00 = active user 0, 0xE5 = deleted) +-- bytes 1-8 : filename (8 chars, space-padded, high bit = attribute flag) +-- bytes 9-11: extension (3 chars, space-padded, high bit = attribute flag) +-- byte 12 : extent low (0 for first extent) +-- Entries are always 32-byte aligned within 512-byte sectors, so scanning at +-- 32-byte increments from offset 0 catches every directory entry. + +local function find_first_com_on_disk(data) + if not data then return nil end + local n = #data + local all_coms = {} + + for i = 1, n - 31, 32 do + local user = data:byte(i) + if user == 0x00 and data:byte(i+12) == 0x00 then -- active entry, first extent + -- Validate filename (bytes i+1..i+8): printable ASCII, mask off attribute bit + local chars = {} + local valid = true + for j = i+1, i+8 do + local c = data:byte(j) & 0x7F + if c == 0x20 then + break -- space = padding, end of name + elseif c < 0x21 or c > 0x7E then + valid = false; break + else + table.insert(chars, string.char(c)) + end + end + if valid and #chars > 0 then + -- Check extension (bytes i+9..i+11) is COM + local e1 = data:byte(i+9) & 0x7F + local e2 = data:byte(i+10) & 0x7F + local e3 = data:byte(i+11) & 0x7F + if e1 == 0x43 and e2 == 0x4F and e3 == 0x4D then -- 'C','O','M' + local fname = table.concat(chars) + -- deduplicate + local seen = false + for _, v in ipairs(all_coms) do if v == fname then seen = true; break end end + if not seen then + table.insert(all_coms, fname) + end + end + end + end + end + + if #all_coms == 0 then + print("[adam_flop] No .COM file found in directory scan") + return nil + end + + -- Prefer a COM whose name does not end with a column-mode suffix (-80, -40, 80, 40, _80, _40). + -- The Infocom Zork disks list the 80-column version first; the plain version + -- (ZORK1, ZORKII, ZORK-III) runs on the standard 40-column ADAM display. + for _, fname in ipairs(all_coms) do + if not fname:match("[-_]?[48]0$") then + print(string.format("[adam_flop] Chosen COM (no col-suffix): %s.COM (all: %s)", + fname, table.concat(all_coms, ", "))) + return fname + end + end + + -- All entries have a column-mode suffix — just use the first one. + print(string.format("[adam_flop] Chosen COM (first, all suffixed): %s.COM", all_coms[1])) + return all_coms[1] +end + +local function detect_exe_name(mame_filename, fallback_key) + print("[adam_flop] --- Scanning disk for first .COM file ---") + local data = zip_util.read_bytes(mame_filename, DSK_SCAN_BYTES) + local com_name = find_first_com_on_disk(data) + if com_name then + return com_name + end + local fallback = fallback_key:sub(1, 8):upper() + print("[adam_flop] Falling back to softlist-derived name: " .. fallback) + return fallback +end + +-- ── Startup ─────────────────────────────────────────────────────────────────── + +local current_software_name = manager.machine.images:at(FLOP_SLOT).filename + +-- software_key: base filename without path or extension, lowercased (for boot_sequences lookup) +local software_key = current_software_name:match("([^/\\]+)$") +software_key = software_key:gsub("%.%w+$", ""):lower() + +-- Detect the actual CP/M executable name by scanning the disk image directory. +local exe_name = detect_exe_name(current_software_name, software_key) + +-- ── Boot functions ──────────────────────────────────────────────────────────── + +local function boot_default() + common_autoboot.type_at_frame(frame_num, exe_name .. "\n", TDOS_PROMPT_FRAME, BUTTON_PRESS_DURATION) +end + +-- Per-game overrides — add entries here when disk scanning gives the wrong +-- result (e.g. the game has multiple .COM files and the second one is correct, +-- or a multi-step boot sequence is needed). +local boot_sequences = { + ['default'] = boot_default, +} + +-- ── Main ────────────────────────────────────────────────────────────────────── + +local function process_frame() + frame_num = frame_num + 1 + + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name: " .. current_software_name) + emu.print_info("[adam_flop] Software key: " .. software_key .. " T-DOS executable: " .. exe_name) + + if boot_sequences[software_key] then + emu.print_info("--- Booting using game-specific profile: " .. software_key .. " ---") + else + emu.print_info("--- Booting using default profile (will type: " .. exe_name .. ") ---") + end + end + + common_autoboot.debug_frame_num(frame_num) + + local boot_function = boot_sequences[software_key] or boot_sequences['default'] + if boot_function then + boot_function() + end +end + +subscription = emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/alice90.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/alice90.lua new file mode 100644 index 00000000000..acadf206d37 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/alice90.lua @@ -0,0 +1,75 @@ +-- alice90.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +common_autoboot.populate_buttons(button) + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function boot_default(cassette_handler) + common_autoboot.type_at_frame(frame_num, "CLOAD\n", 100, BUTTON_PRESS_DURATION) + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 200) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + emu.keypost('RUN\n') + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(3).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + ["default"] = boot_default, +} + +-- --- Cassette Loading Handler Setup --- +local cassette_handler = common_autoboot.create_cassette_handler(":cassette") + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + --- Print current frame number every 100 frames --- + if frame_num % 100 == 0 then -- The modulo operator (%) gives the remainder of a division + emu.print_info("Current Frame: " .. frame_num) + end + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/apogee.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/apogee.lua new file mode 100644 index 00000000000..59d1b624362 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/apogee.lua @@ -0,0 +1,78 @@ +-- apogee.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +-- --- Print Info --- +common_autoboot.print_image_info() + +-- --- Cassette Loading Handler Setup --- +local CASSETTE_SLOT = 1 +local CASSETTE_DEVICE_TAG = manager.machine.images:at(CASSETTE_SLOT).device.tag +local cassette_handler = common_autoboot.create_cassette_handler(CASSETTE_DEVICE_TAG) + +common_autoboot.populate_buttons(button) + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function boot_default(cassette_handler) + common_autoboot.type_at_frame(frame_num, "I\n", 100) + common_autoboot.play_cassette_at_frame(frame_num, CASSETTE_DEVICE_TAG, 200) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + emu.keypost('G\n') + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(CASSETTE_SLOT).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + ['default'] = boot_default, +} + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + --- DEBUG: Print current frame number every 100 frames --- + common_autoboot.debug_frame_num(frame_num) + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/aquarius_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/aquarius_cass.lua new file mode 100644 index 00000000000..511fdc4578d --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/aquarius_cass.lua @@ -0,0 +1,216 @@ +-- aquarius_cass.lua +-- +-- Mattel Aquarius cassette autoboot. +-- +-- Aquarius .caq tape format: +-- [0xFF leader bytes] [0x00 marker] [6-byte filename] [0xFF inter-block] [0x00 marker] [data] +-- +-- File type detection via filename in header: +-- ASCII letters → BASIC program → CLOAD, then RUN after tape stops +-- "######" (0x23 × 6) → raw machine code payload → CLOAD (auto-executes) +-- +-- Most commercial games are two-part softlist entries: +-- cass1: BASIC loader (_BAS.caq, ~145 bytes) — handled by this script +-- cass2: machine code payload (_A.caq) — loaded automatically by the BASIC program +-- Single-part games may be pure BASIC or a standalone machine code file. + +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") +local zip_util = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_zip.lua") + +local CAS_SCAN_BYTES = 4096 + +local TAPE_TYPE_BASIC = 0 +local TAPE_TYPE_MACHINE = 1 + +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_STOP_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local button = {} +local frame_num = 0 + +common_autoboot.populate_buttons(button) + +local function find_cassette_image() + for _, cass in pairs(manager.machine.cassettes) do + if cass.exists and cass.filename and #cass.filename > 0 then + return cass.filename, cass.device and cass.device.tag or ":cassette" + end + end + for _, img in pairs(manager.machine.images) do + if img.exists and img.filename and #img.filename > 0 then + local fn = img.filename:lower() + if fn:find("%.caq$") or fn:find("%.cas$") then + return img.filename, img.device and img.device.tag or ":cassette" + end + end + end + return nil, ":cassette" +end + +-- ── .caq header parser ──────────────────────────────────────────────────────── +-- +-- Structure: [0xFF... leader] [0x00 marker] [6-byte filename] [0xFF... inter-block] [0x00 data marker] [data...] +-- Filename "######" (all 0x23) indicates a raw machine code payload. +-- Any other ASCII filename indicates a BASIC program. + +local function parse_caq_header(data) + if not data or #data < 20 then return nil end + + -- Skip 0xFF leader bytes + local i = 1 + while i <= #data and data:byte(i) == 0xFF do i = i + 1 end + + -- Expect 0x00 header marker + if i > #data or data:byte(i) ~= 0x00 then return nil end + i = i + 1 + + -- Read 6-byte filename + if i + 5 > #data then return nil end + local name_bytes = {} + for j = i, i+5 do table.insert(name_bytes, data:byte(j)) end + + -- Detect type: all 0x23 ('#') = machine code payload; otherwise BASIC + local all_hash = true + for _, b in ipairs(name_bytes) do + if b ~= 0x23 then all_hash = false; break end + end + + local filename = "" + for _, b in ipairs(name_bytes) do + if b >= 0x21 and b <= 0x7E then filename = filename .. string.char(b) end + end + + if all_hash then + print("[Aquarius Autoboot] Header: MACHINE CODE (name='######')") + return { file_type = TAPE_TYPE_MACHINE, filename = "######" } + else + print(string.format("[Aquarius Autoboot] Header: BASIC name='%s'", filename)) + return { file_type = TAPE_TYPE_BASIC, filename = filename } + end +end + +local function detect_tape_info() + print("[Aquarius Autoboot] --- Tape type detection ---") + local path = find_cassette_image() + if not path then + print("[Aquarius Autoboot] No cassette image found, defaulting to BASIC.") + return { file_type = TAPE_TYPE_BASIC, filename = "" } + end + print("[Aquarius Autoboot] Tape path: " .. path) + local data = zip_util.read_bytes(path, CAS_SCAN_BYTES) + if not data then + print("[Aquarius Autoboot] Could not read tape, defaulting to BASIC.") + return { file_type = TAPE_TYPE_BASIC, filename = "" } + end + local info = parse_caq_header(data) + if info then return info end + print("[Aquarius Autoboot] No valid header found, defaulting to BASIC.") + return { file_type = TAPE_TYPE_BASIC, filename = "" } +end + +-- ── Cassette handler (same stop-detection pattern as mc10_cass.lua) ─────────── + +local function create_cassette_handler(cassette_device_tag) + local stop_frame = 0 + local seen_playing = false + local load_done = false + + return function(current_frame_num, delay_frames_after_stop) + local dev = manager.machine.cassettes[cassette_device_tag] + if not dev then + print("[Aquarius Autoboot] Cassette device not found: " .. cassette_device_tag) + return false + end + + if dev.is_stopped == false then + manager.machine.video.throttled = false + manager.machine.video.frameskip = 12 + seen_playing = true + else + manager.machine.video.throttled = true + manager.machine.video.frameskip = 0 + if seen_playing and stop_frame == 0 then + stop_frame = current_frame_num + print("[Aquarius Autoboot] Cassette stop detected at frame " .. current_frame_num) + end + end + + if not load_done and stop_frame ~= 0 and + current_frame_num > stop_frame + delay_frames_after_stop then + load_done = true + print("[Aquarius Autoboot] Cassette load complete at frame " .. current_frame_num) + return true + end + return false + end +end + +local function play_cassette(cassette_tag, start_frame) + if frame_num == start_frame then + local dev = manager.machine.cassettes[cassette_tag] + if dev then + dev:play() + print("[Aquarius Autoboot] Playing cassette at frame " .. frame_num) + else + print("[Aquarius Autoboot] Cassette device not found for play: " .. cassette_tag) + end + end +end + +-- ── Boot functions ──────────────────────────────────────────────────────────── + +local tape_info = nil +local cassette_tag = ":cassette" +local cassette_handler = nil + +local function boot_basic() + -- Aquarius BASIC load sequence: + -- 1. Enter — dismiss any initial splash + -- 2. CLOAD"name" — BASIC sends motor-on to the cassette (MAME starts tape automatically) + -- 3. play_cassette — belt-and-suspenders: explicitly start tape in case motor signal is late + -- 4. RUN — after tape stops, run the loaded program + local cmd = string.format('CLOAD"%s"\n', tape_info.filename) + common_autoboot.type_at_frame(frame_num, "\n", 100, BUTTON_PRESS_DURATION) + common_autoboot.type_at_frame(frame_num, cmd, 150, BUTTON_PRESS_DURATION) + play_cassette(cassette_tag, 200) + + if cassette_handler and cassette_handler(frame_num, CASSETTE_STOP_DELAY_FRAMES) then + emu.keypost("RUN\n") + end +end + +local function boot_machine() + -- Machine code payload: same sequence, no RUN needed (auto-executes on load). + common_autoboot.type_at_frame(frame_num, "\n", 100, BUTTON_PRESS_DURATION) + common_autoboot.type_at_frame(frame_num, "CLOAD\n", 150, BUTTON_PRESS_DURATION) + play_cassette(cassette_tag, 200) + + if cassette_handler then + cassette_handler(frame_num, CASSETTE_STOP_DELAY_FRAMES) + end +end + +-- ── Main ────────────────────────────────────────────────────────────────────── + +local function process_frame() + frame_num = frame_num + 1 + + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + common_autoboot.print_image_info() + local _, detected_tag = find_cassette_image() + cassette_tag = detected_tag or ":cassette" + cassette_handler = create_cassette_handler(cassette_tag) + tape_info = detect_tape_info() + end + + common_autoboot.debug_frame_num(frame_num) + + if tape_info and tape_info.file_type == TAPE_TYPE_MACHINE then + boot_machine() + else + boot_basic() + end +end + +subscription = emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/atom_flop.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/atom_flop.lua new file mode 100644 index 00000000000..4359dd6332e --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/atom_flop.lua @@ -0,0 +1,407 @@ +-- atom_flop.lua +-- Autoboot Acorn Atom floppy disks by inspecting the Atom DOS directory. + +local zip_util = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_zip.lua") + +local DISK_SCAN_BYTES = 512 +local DIR_ENTRY_SIZE = 8 +local DIR_ENTRY_COUNT = 32 +local TYPE_DELAY = 120 + +print("[Atom Flop] Loaded from: " .. debug.getinfo(1, 'S').source) + +local frame_num = 0 +local boot_program = nil +local boot_started = false +local boot_stage = 0 +local next_stage_frame = 0 +local f14_key_down = false +local digit_key_down = nil +local lowercase_started = false +local lowercase_text = nil +local lowercase_index = 1 +local lowercase_key = nil +local lowercase_done_frame = 0 +local lowercase_next_frame = 0 +local lowercase_release_frame = 0 +local lowercase_close_posted = false + +local DOS_SETTLE_FRAMES = 140 +local F14_PREFIX_DELAY = 40 +local F14_DIGIT_DELAY = 90 +local F14_SUFFIX_DELAY = 130 +local F14_KEY_HOLD_FRAMES = 20 +local JSW2_PREFIX_DELAY = 40 +local JSW2_DIGIT_DELAY = 500 +local JSW2_SUFFIX_DELAY = 130 +local DIGIT_KEY_HOLD_FRAMES = 200 +local LOWERCASE_START_DELAY = 90 +local LOWERCASE_KEY_HOLD_FRAMES = 16 +local LOWERCASE_KEY_GAP_FRAMES = 12 + +local LETTER_KEYS = { + A = { "Y6", 0x08 }, + B = { "Y5", 0x08 }, + C = { "Y4", 0x08 }, + D = { "Y3", 0x08 }, + E = { "Y2", 0x08 }, + F = { "Y1", 0x08 }, + G = { "Y0", 0x08 }, + H = { "Y9", 0x10 }, + I = { "Y8", 0x10 }, + J = { "Y7", 0x10 }, + K = { "Y6", 0x10 }, + L = { "Y5", 0x10 }, + M = { "Y4", 0x10 }, + N = { "Y3", 0x10 }, + O = { "Y2", 0x10 }, + P = { "Y1", 0x10 }, + Q = { "Y0", 0x10 }, + R = { "Y9", 0x20 }, + S = { "Y8", 0x20 }, + T = { "Y7", 0x20 }, + U = { "Y6", 0x20 }, + V = { "Y5", 0x20 }, + W = { "Y4", 0x20 }, + X = { "Y3", 0x20 }, + Y = { "Y2", 0x20 }, + Z = { "Y1", 0x20 }, +} + +local DIGIT_KEYS = { + ["1"] = { "Y2", 0x02 }, + ["2"] = { "Y1", 0x02 }, + ["3"] = { "Y0", 0x02 }, + ["4"] = { "Y9", 0x04 }, + ["5"] = { "Y8", 0x04 }, + ["6"] = { "Y7", 0x04 }, + ["7"] = { "Y6", 0x04 }, + ["8"] = { "Y5", 0x04 }, + ["9"] = { "Y4", 0x04 }, + ["0"] = { "Y3", 0x02 }, +} + +local PREFERRED_PROGRAMS = { + -- Prefer colour variants when both colour and mono are present. + "CCHUCK", + "CGALA", + + "LOADER", + "JOE", + "EHRUN", + "F14RUN", + "GALAXI", + "JSW2RUN", + "JSWRUN", + "JUNGLE", + "MMRUN", + "RUNME", + "REPLOAD", +} + +local function find_disk_in_zip(zippath) + return zip_util.find_zip_entry(zippath, function(n) + return n:lower():match("%.dsk$") or n:lower():match("%.40t$") + end) +end + +local function is_atom_floppy_name(path) + local lower = path:lower() + return lower:match("%.dsk$") or lower:match("%.40t$") or lower:match("%.mfi$") or + lower:match("%.dfi$") or lower:match("%.hfe$") or lower:match("%.mfm$") or + lower:match("%.td0$") or lower:match("%.imd$") or lower:match("%.d77$") or + lower:match("%.d88$") or lower:match("%.1dd$") or lower:match("%.cqm$") or + lower:match("%.cqi$") +end + +local function find_floppy_path() + for _, img in pairs(manager.machine.images) do + if img.exists and img.filename and #img.filename > 0 then + local fn = img.filename + local lower = fn:lower() + if is_atom_floppy_name(lower) or lower:find("%.zip/") then + print("[Atom Flop] Floppy image: " .. fn) + return fn + end + if lower:match("%.zip$") then + local entry = find_disk_in_zip(fn) + if entry then + local vpath = fn .. "/" .. entry + print("[Atom Flop] Floppy image (zip): " .. vpath) + return vpath + end + end + end + end + return nil +end + +local function clean_dir_name(raw) + local chars = {} + for i = 1, #raw do + local c = raw:byte(i) + if c == 0x00 then break end + if c < 0x20 or c > 0x7e then return nil end + table.insert(chars, string.char(c)) + end + + local name = table.concat(chars):match("^%s*(.-)%s*$") + if name == "" then return nil end + return name +end + +local function parse_atom_dir(data) + local names = {} + local present = {} + if not data or #data < DIR_ENTRY_SIZE then return names, present end + + for idx = 0, DIR_ENTRY_COUNT - 1 do + local off = idx * DIR_ENTRY_SIZE + 1 + if off + DIR_ENTRY_SIZE - 1 > #data then break end + local raw = data:sub(off, off + DIR_ENTRY_SIZE - 1) + local name = clean_dir_name(raw) + if name then + table.insert(names, name) + present[name:upper()] = name + print(string.format("[Atom Flop] Dir[%d]: %s", idx, name)) + end + end + + return names, present +end + +local function choose_from_directory(names, present) + for _, wanted in ipairs(PREFERRED_PROGRAMS) do + if present[wanted] then return present[wanted] end + end + + for _, name in ipairs(names) do + local upper = name:upper() + if upper:match("RUN$") and not upper:match("SCRRUN$") then + return name + end + end + + if present["RUNME"] then return present["RUNME"] end + return nil +end + +local function normalize_boot_program(program) + if program and program:upper() == "REPLOADED" then + return "REPLOAD" + end + return program +end + +local function detect_boot_program() + print("[Atom Flop] --- Floppy autoboot detection ---") + + local path = find_floppy_path() + if not path then + print("[Atom Flop] No floppy image found.") + return nil + end + + local data = zip_util.read_bytes(path, DISK_SCAN_BYTES) + if data then + local names, present = parse_atom_dir(data) + local from_dir = choose_from_directory(names, present) + if from_dir then + print("[Atom Flop] Selected from directory: " .. from_dir) + return normalize_boot_program(from_dir) + end + end + + print("[Atom Flop] No runnable program detected.") + return nil +end + +local function key_1_field() + local port = manager.machine.ioport.ports[":Y2"] + return port and port:field(0x02) or nil +end + +local function digit_field(digit) + local keydef = DIGIT_KEYS[digit] + if not keydef then return nil end + local port = manager.machine.ioport.ports[":" .. keydef[1]] + return port and port:field(keydef[2]) or nil +end + +local function shift_field() + local port = manager.machine.ioport.ports[":Y10"] + return port and port:field(0x80) or nil +end + +local function letter_field(letter) + local keydef = LETTER_KEYS[letter:upper()] + if not keydef then return nil end + local port = manager.machine.ioport.ports[":" .. keydef[1]] + return port and port:field(keydef[2]) or nil +end + +local function set_digit_key(digit, pressed) + local field = digit_field(digit) + if not field then + print("[Atom Flop] Missing key field for digit " .. digit .. ", falling back to keypost") + if pressed then + emu.keypost(digit) + end + return + end + if pressed then + field:set_value(1) + digit_key_down = digit + else + field:clear_value() + digit_key_down = nil + end +end + +local function set_key_1(pressed) + local field = key_1_field() + if not field then + print("[Atom Flop] Missing key field for 1") + return + end + if pressed then + field:set_value(1) + f14_key_down = true + else + field:clear_value() + f14_key_down = false + end +end + +local function has_lowercase(text) + return text:find("%l") ~= nil +end + +local function start_lowercase_text(text, target_frame) + if frame_num == target_frame and not lowercase_started then + print("[Atom Flop] Typing lowercase via matrix: " .. text) + lowercase_text = text + lowercase_index = 1 + lowercase_next_frame = frame_num + lowercase_started = true + end +end + +local function release_lowercase_key() + if lowercase_key then + local field = letter_field(lowercase_key) + if field then field:clear_value() end + lowercase_key = nil + end + local shift = shift_field() + if shift then shift:clear_value() end + lowercase_next_frame = frame_num + LOWERCASE_KEY_GAP_FRAMES +end + +local function process_lowercase_text() + if not lowercase_started or lowercase_done_frame ~= 0 then return end + + if lowercase_key and frame_num >= lowercase_release_frame then + release_lowercase_key() + lowercase_index = lowercase_index + 1 + if lowercase_index > #lowercase_text then + lowercase_done_frame = lowercase_next_frame + end + return + end + + if lowercase_key or frame_num < lowercase_next_frame then return end + + local ch = lowercase_text:sub(lowercase_index, lowercase_index) + local field = letter_field(ch) + local shift = shift_field() + if not field or not shift then + print("[Atom Flop] Missing lowercase key field for: " .. ch) + lowercase_done_frame = frame_num + return + end + + shift:set_value(1) + field:set_value(1) + lowercase_key = ch + lowercase_release_frame = frame_num + LOWERCASE_KEY_HOLD_FRAMES +end + +local function keypost_at(text, target_frame) + if frame_num == target_frame then + print("[Atom Flop] Typing: " .. text:gsub("\n", "\\n")) + emu.keypost(text) + end +end + +local function process_frame() + frame_num = frame_num + 1 + + if not boot_program then + boot_program = detect_boot_program() + if not boot_program then + subscription:unsubscribe() + return + end + end + + if not boot_started then + boot_started = true + print("[Atom Flop] Booting with *RUN\"" .. boot_program .. "\"") + end + + keypost_at("*DOS\n", TYPE_DELAY) + + if boot_stage == 0 and frame_num == TYPE_DELAY then + print("[Atom Flop] Queueing: *DOS") + next_stage_frame = frame_num + DOS_SETTLE_FRAMES + boot_stage = 1 + elseif boot_stage == 1 and frame_num >= next_stage_frame then + print("[Atom Flop] Entering stage 3 at frame " .. frame_num .. ", next_stage_frame=" .. next_stage_frame) + print("[Atom Flop] Typing run command for: " .. boot_program) + boot_stage = 3 + end + + if boot_stage == 3 and boot_program:upper() == "F14RUN" then + keypost_at("*RUN\"F", next_stage_frame + F14_PREFIX_DELAY) + if frame_num == next_stage_frame + F14_DIGIT_DELAY then + print("[Atom Flop] Pressing Atom key 1") + set_key_1(true) + elseif f14_key_down and frame_num == next_stage_frame + F14_DIGIT_DELAY + F14_KEY_HOLD_FRAMES then + set_key_1(false) + end + keypost_at("4RUN\"\n", next_stage_frame + F14_SUFFIX_DELAY) + + elseif boot_stage == 3 and boot_program:upper() == "JSW2RUN" then + keypost_at("*RUN\"JSW", next_stage_frame + JSW2_PREFIX_DELAY) + if frame_num == next_stage_frame + JSW2_DIGIT_DELAY then + print("[Atom Flop] Pressing Atom key 2") + set_digit_key("2", true) + elseif digit_key_down == "2" and frame_num == next_stage_frame + JSW2_DIGIT_DELAY + DIGIT_KEY_HOLD_FRAMES then + set_digit_key("2", false) + end + keypost_at("RUN\"\n", next_stage_frame + JSW2_SUFFIX_DELAY) + + elseif boot_stage == 3 and has_lowercase(boot_program) then + keypost_at("*RUN\"", next_stage_frame + F14_PREFIX_DELAY) + start_lowercase_text(boot_program, next_stage_frame + LOWERCASE_START_DELAY) + process_lowercase_text() + if lowercase_done_frame ~= 0 and not lowercase_close_posted and frame_num >= lowercase_done_frame + LOWERCASE_KEY_GAP_FRAMES then + print("[Atom Flop] Closing lowercase run command") + emu.keypost("\"\n") + lowercase_close_posted = true + end + elseif boot_stage == 3 then + keypost_at("*RUN\"" .. boot_program .. "\"\n", next_stage_frame + F14_PREFIX_DELAY) + end + + if boot_stage == 3 and has_lowercase(boot_program) and lowercase_close_posted and frame_num > lowercase_done_frame + 60 then + subscription:unsubscribe() + elseif boot_stage == 3 and not has_lowercase(boot_program) and frame_num > next_stage_frame + F14_SUFFIX_DELAY + 60 then + if f14_key_down then set_key_1(false) end + if digit_key_down then set_digit_key(digit_key_down, false) end + subscription:unsubscribe() + end +end + +subscription = emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/autoboot_common.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/autoboot_common.lua new file mode 100644 index 00000000000..ea093491d09 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/autoboot_common.lua @@ -0,0 +1,226 @@ +-- autoboot_common.lua + +-- Define common helper functions that will be used by other scripts. +-- These functions assume 'button' and 'frame_num' are available in the calling scope, +-- or they will need to be passed as arguments, which makes them truly independent. +-- For MAME Lua scripts, it's common to expect 'button' and 'frame_num' to be managed +-- by the main calling script. + +-- --- Common Constants --- +local DEFAULT_BUTTON_PRESS_DURATION = 100 -- Default duration for button presses in frames +local DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES = 60 -- Default duration to wait after cassette stopped (after throttle) + +-- Helper function to press and release a button at specific frame numbers +-- Assumes 'frame_num' is globally accessible (or passed in) and 'button' table is global +local function press_and_release_button(button_table, current_frame_num, button_name, press_frame, duration) + local release_frame = press_frame + duration + -- emu.print_info(string.format("Common: %s (Current Frame: %d, Target Press: %d, Target Release: %d)", + -- button_name, current_frame_num, press_frame, release_frame)) + + if current_frame_num == press_frame then + emu.print_info("!!!! PRESSING button: " .. button_name .. " at frame " .. current_frame_num .. " (Duration: " .. duration .. " frames) !!!!") + if button_table[button_name] then + button_table[button_name]:set_value(1) + else + emu.print_info("Warning: Button '" .. button_name .. "' not found for press.") + end + elseif current_frame_num == release_frame then + emu.print_info("!!!! RELEASING button: " .. button_name .. " at frame " .. current_frame_num .. " !!!!") + if button_table[button_name] then + button_table[button_name]:set_value(0) + else + emu.print_info("Warning: Button '" .. button_name .. "' not found for release.") + end + end +end + +-- Helper function to type a string at a specific frame number +-- Assumes 'frame_num' is globally accessible (or passed in) +local function type_string_at_frame(current_frame_num, text, start_frame) + if current_frame_num == start_frame then + emu.print_info("Typing: " .. text:gsub("\n", "\\n") .. " at frame " .. current_frame_num) + emu.keypost(text) + end +end + +-- Function to populate the button table +-- It takes an empty table and populates it. +local function populate_button_table(target_button_table) + for key, ports in pairs(manager.machine.ioport.ports) do + for field_name, field in pairs(ports.fields) do + target_button_table[field_name] = field + end + end +end + +-- Function to get a list of device tag, e.g. :cassette. Some system uses :cassette1 +-- local function print_device_tag() +-- emu.print_info("--- List of Device Tag ---") +-- print(manager.machine.images:at(3).device.tag) +-- emu.print_info("--- End of Device Tag ---") +-- end + +local function print_image_info() + emu.print_info("--- Loaded Image Information ---") + local num_images = manager.machine.images:size() + emu.print_info("Total loaded images: " .. num_images) + + if num_images == 0 then + emu.print_info("No images currently loaded.") + else + -- Iterate through each image slot + for i = 1, num_images do + local image = manager.machine.images:at(i) + if image then + emu.print_info(string.format(" Image %d:", i)) + emu.print_info(string.format(" Device Tag: %s", image.device.tag or "N/A")) + emu.print_info(string.format(" Filename: %s", image.filename or "N/A")) + emu.print_info(string.format(" Mounted: %s", tostring(image.mounted))) + emu.print_info(string.format(" Software Name: %s", image.software_name or "N/A")) -- From softlist, if applicable + emu.print_info(string.format(" Is Cassette: %s", tostring(image.is_cassette))) + emu.print_info(string.format(" Is Harddisk: %s", tostring(image.is_harddisk))) + -- Add more properties as needed from the MAME Lua image_device documentation + else + emu.print_info(string.format(" Image %d: (Error: Could not retrieve image object)", i)) + end + end + end + emu.print_info("--- End of Image Information ---") +end + +-- Function to print the contents of the button table +local function print_button_table(button_table_to_print) + emu.print_info("--- Contents of 'button' table ---") + for field_name, field_object in pairs(button_table_to_print) do + local current_value = field_object.value + if current_value == nil then current_value = -1 end + + local type_class_name = field_object.type_class + if type_class_name == nil then type_class_name = "unknown" end + + local info_string = string.format( + "Key: '%s', Field Name: '%s', Current Value: %d, Type Class: %s", + field_name, + field_object.name, + current_value, + type_class_name + ) + emu.print_info(info_string) + end + emu.print_info("--- End of 'button' table contents ---") +end + +local function play_cassette_at_frame(current_frame_num, cassette_device_tag, start_frame) + if current_frame_num == start_frame then + local cassette_device = manager.machine.cassettes[cassette_device_tag] + if cassette_device then + cassette_device:play() + emu.print_info("Playing cassette '" .. cassette_device_tag .. "' at frame " .. current_frame_num) + else + emu.print_info("WARNING: Cassette device '" .. cassette_device_tag .. "' not found for play at frame " .. current_frame_num) + end + end +end + +-- New function for handling cassette throttling AND detecting load completion +-- This function now takes current_frame_num and returns true ONCE when loading is done. +-- It uses its own internal state variables, so they are not polluting the calling script. +local function create_cassette_handler(cassette_device_tag) + local motor_state_false_frame_num = 0 + local load_done_flag = false -- This flag will be set to true ONCE when loading is complete + local was_playing_and_throttling_off = false -- Tracks if we were actively loading and throttling was off + + return function(current_frame_num, delay_frames_after_motor_off) + local cassette_device = manager.machine.cassettes[cassette_device_tag] + if not cassette_device then + emu.print_info("WARNING: Cassette device with tag '" .. cassette_device_tag .. "' not found!") + return false + end + + -- Handle throttling/frameskip + if cassette_device.is_stopped == false and cassette_device.motor_state == true then + manager.machine.video.throttled = false + manager.machine.video.frameskip = 12 + was_playing_and_throttling_off = true -- Mark that it was actively playing (throttle disabled) + else + manager.machine.video.throttled = true + manager.machine.video.frameskip = 0 + -- If it was just playing and throttling was off, and now it's stopped/motor off + if was_playing_and_throttling_off and motor_state_false_frame_num == 0 then + motor_state_false_frame_num = current_frame_num -- Mark the frame motor just turned off + emu.print_info("Cassette motor OFF detected (and was loading) at frame " .. current_frame_num) + end + was_playing_and_throttling_off = false -- Reset, as it's no longer actively playing + end + + + -- Detect load completion AFTER the motor turns off and the delay passes + if load_done_flag == false then -- Only process if load hasn't been marked done yet + if motor_state_false_frame_num ~= 0 then -- Meaning the motor has turned off at some point + -- This is the delay check: + if current_frame_num > motor_state_false_frame_num + delay_frames_after_motor_off then + load_done_flag = true -- Mark loading as complete + emu.print_info("Cassette loading completed at frame " .. current_frame_num) + emu.print_info("Load done!!! (after delay)") + return true -- Signal that loading is done + end + end + end + + return false -- Indicate loading is not yet done + end +end + +local function create_delay_logic() + local delay_start_frame = 0 + local delay_in_frames = 0 + local delay_active = false + + -- This is the function that will be called continuously to check the delay state + return function(current_frame_num, initiate_delay_frames) + -- If initiate_delay_frames is provided, it means we want to START a new delay + if initiate_delay_frames and not delay_active then + delay_start_frame = current_frame_num + delay_in_frames = initiate_delay_frames + delay_active = true + emu.print_info("Delay initiated at frame " .. current_frame_num .. " for " .. delay_in_frames .. " frames.") + return false -- Delay just started, not done yet + end + + -- If a delay is active, check if it's over + if delay_active then + if current_frame_num >= delay_start_frame + delay_in_frames then + delay_active = false -- Delay is complete + emu.print_info("Delay completed at frame " .. current_frame_num) + return true -- Signal delay is over + else + return false -- Delay is still active + end + end + + return true -- No delay was active or initiated, so it's "done" by default. + end +end + +local function debug_frame_num(frame_num) + if frame_num % 100 == 0 then -- The modulo operator (%) gives the remainder of a division + emu.print_info("Current Frame: " .. frame_num) + end +end + + +-- Return a table of functions +return { + press_and_release = press_and_release_button, + type_at_frame = type_string_at_frame, + populate_buttons = populate_button_table, + print_buttons = print_button_table, + play_cassette_at_frame = play_cassette_at_frame, + create_cassette_handler = create_cassette_handler, + create_delay_logic = create_delay_logic, + DEFAULT_BUTTON_PRESS_DURATION = DEFAULT_BUTTON_PRESS_DURATION, + DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES = DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES, + print_image_info = print_image_info, + print_device_tag = print_device_tag, + debug_frame_num = debug_frame_num, +} \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/autoboot_zip.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/autoboot_zip.lua new file mode 100644 index 00000000000..b0a7353c6e6 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/autoboot_zip.lua @@ -0,0 +1,120 @@ +-- autoboot_zip.lua +-- Shared ZIP and file-reading utilities for MAME autoboot scripts. +-- +-- Usage: +-- local zip_util = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_zip.lua") +-- local data = zip_util.read_bytes(mame_filename, 4096) +-- local entry = zip_util.find_zip_entry(zippath, function(n) return n:lower():match("%.dsk$") end) + +local function u16le(s, pos) + return s:byte(pos) | (s:byte(pos+1) << 8) +end + +local function u32le(s, pos) + return s:byte(pos) | (s:byte(pos+1) << 8) | (s:byte(pos+2) << 16) | (s:byte(pos+3) << 24) +end + +-- Parse a MAME image path into (kind, zippath, entrypath). +-- Virtual zip path: /roms/game.zip/game.cas → "zip", "/roms/game.zip", "game.cas" +-- Plain file path: /roms/game.cas → "plain", nil, "/roms/game.cas" +local function parse_mame_path(fullpath) + local p = fullpath:gsub("\\", "/") + local zippath, entry = p:match("^(.*%.zip)/(.+)$") + if zippath and entry then return "zip", zippath, entry end + return "plain", nil, p +end + +-- Walk a ZIP file's local file headers and return the first entry name +-- for which match_fn(entryname) returns true, or nil. +local function find_zip_entry(zippath, match_fn) + local f = io.open(zippath, "rb") + if not f then return nil end + local zipdata = f:read("*a") + f:close() + if not zipdata or #zipdata < 30 then return nil end + + local pos = 1 + while pos <= #zipdata - 30 do + if zipdata:byte(pos) ~= 0x50 or zipdata:byte(pos+1) ~= 0x4B or + zipdata:byte(pos+2) ~= 0x03 or zipdata:byte(pos+3) ~= 0x04 then break end + local comp_size = u32le(zipdata, pos+18) + local fname_len = u16le(zipdata, pos+26) + local extra_len = u16le(zipdata, pos+28) + local ename = zipdata:sub(pos+30, pos+30+fname_len-1) + local data_start = pos + 30 + fname_len + extra_len + if match_fn(ename) then return ename end + pos = data_start + comp_size + end + return nil +end + +-- Read bytes of a named entry from a ZIP archive. +-- method=0 (stored) : pure Lua, no external process. +-- method=8 (deflated): Python3 fallback. +-- max_bytes: maximum bytes to read, or nil to read the whole entry. +-- Returns a Lua byte-string, or nil on failure. +local function read_entry_from_zip(zippath, entryname, max_bytes) + local f = io.open(zippath, "rb") + if not f then return nil end + local zipdata = f:read("*a") + f:close() + if not zipdata or #zipdata < 30 then return nil end + + local pos = 1 + while pos <= #zipdata - 30 do + if zipdata:byte(pos) ~= 0x50 or zipdata:byte(pos+1) ~= 0x4B or + zipdata:byte(pos+2) ~= 0x03 or zipdata:byte(pos+3) ~= 0x04 then break end + local method = u16le(zipdata, pos+8) + local comp_size = u32le(zipdata, pos+18) + local uncomp_size = u32le(zipdata, pos+22) + local fname_len = u16le(zipdata, pos+26) + local extra_len = u16le(zipdata, pos+28) + local entry_name = zipdata:sub(pos+30, pos+30+fname_len-1) + local data_start = pos + 30 + fname_len + extra_len + + if entry_name:lower() == entryname:lower() then + if method == 0 then + local nbytes = max_bytes and math.min(uncomp_size, max_bytes) or uncomp_size + return zipdata:sub(data_start, data_start + nbytes - 1) + elseif method == 8 then + local zq = zippath:gsub("'", "'\\''") + local nq = entryname:gsub("'", "'\\''") + local pipe = io.popen(string.format( + "python3 -c 'import zipfile,sys; zf=zipfile.ZipFile(sys.argv[1]); sys.stdout.buffer.write(zf.read(sys.argv[2]))' '%s' '%s' 2>/dev/null", + zq, nq), "r") + if not pipe then return nil end + local raw = max_bytes and pipe:read(max_bytes) or pipe:read("*a") + pipe:close() + return (raw and #raw > 0) and raw or nil + end + return nil + end + + pos = data_start + comp_size + end + return nil +end + +-- Read bytes from a file, handling both plain files and MAME virtual zip paths. +-- max_bytes: maximum bytes to read, or nil to read everything. +-- Returns a Lua byte-string, or nil on failure. +local function read_bytes(mame_filename, max_bytes) + local kind, zippath, entrypath = parse_mame_path(mame_filename) + if kind == "zip" then + return read_entry_from_zip(zippath, entrypath, max_bytes) + end + local f = io.open(entrypath, "rb") + if not f then return nil end + local data = max_bytes and f:read(max_bytes) or f:read("*a") + f:close() + return data +end + +return { + u16le = u16le, + u32le = u32le, + parse_mame_path = parse_mame_path, + find_zip_entry = find_zip_entry, + read_entry_from_zip = read_entry_from_zip, + read_bytes = read_bytes, +} diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/bbc_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/bbc_cass.lua new file mode 100644 index 00000000000..9dca8260ae1 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/bbc_cass.lua @@ -0,0 +1,81 @@ +-- bbc_cass.lua + +-- WIP: Some games require *RUN instead of CHAIN, WIP WIP!! + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +common_autoboot.populate_buttons(button) + +-- Print the button table contents for debugging +-- common_autoboot.print_buttons(button) + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function boot_default(cassette_handler) + common_autoboot.type_at_frame(frame_num, "*TAPE\n", 50, BUTTON_PRESS_DURATION) + common_autoboot.type_at_frame(frame_num, "CHAIN\"\"\n", 100, BUTTON_PRESS_DURATION) + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 300) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + -- emu.keypost('RUN\n') + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(1).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + ["default"] = boot_default, +} + +-- --- Cassette Loading Handler Setup --- +local cassette_handler = common_autoboot.create_cassette_handler(":cassette") + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + -- --- Print current frame number every 100 frames --- + if frame_num % 100 == 0 then -- The modulo operator (%) gives the remainder of a division + emu.print_info("Current Frame: " .. frame_num) + end + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/bbcb_flop.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/bbcb_flop.lua new file mode 100644 index 00000000000..b4bcf835ca4 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/bbcb_flop.lua @@ -0,0 +1,79 @@ +-- bbcb_flop.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +common_autoboot.populate_buttons(button) + +-- Print the button table contents for debugging +-- common_autoboot.print_buttons(button) + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function boot_default(cassette_handler) + common_autoboot.type_at_frame(frame_num, "*CAT\n", 50, BUTTON_PRESS_DURATION) + common_autoboot.type_at_frame(frame_num, "*EXEC !BOOT\n", 250, BUTTON_PRESS_DURATION) + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 300) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + -- emu.keypost('RUN\n') + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(1).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + ["default"] = boot_default, +} + +-- --- Cassette Loading Handler Setup --- +local cassette_handler = common_autoboot.create_cassette_handler(":cassette") + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + -- --- Print current frame number every 100 frames --- + if frame_num % 100 == 0 then -- The modulo operator (%) gives the remainder of a division + emu.print_info("Current Frame: " .. frame_num) + end + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/bbcb_flop_orig.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/bbcb_flop_orig.lua new file mode 100644 index 00000000000..3d5e54fd980 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/bbcb_flop_orig.lua @@ -0,0 +1,79 @@ +-- bbcb_flop_orig.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +common_autoboot.populate_buttons(button) + +-- Print the button table contents for debugging +-- common_autoboot.print_buttons(button) + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function boot_default(cassette_handler) + common_autoboot.type_at_frame(frame_num, "*CAT\n", 50, BUTTON_PRESS_DURATION) + common_autoboot.type_at_frame(frame_num, "*EXEC !BOOT\n", 250, BUTTON_PRESS_DURATION) + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 300) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + -- emu.keypost('RUN\n') + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(1).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + ["default"] = boot_default, +} + +-- --- Cassette Loading Handler Setup --- +local cassette_handler = common_autoboot.create_cassette_handler(":cassette") + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + -- --- Print current frame number every 100 frames --- + if frame_num % 100 == 0 then -- The modulo operator (%) gives the remainder of a division + emu.print_info("Current Frame: " .. frame_num) + end + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/bk0010.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/bk0010.lua new file mode 100644 index 00000000000..fd707ce0c9c --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/bk0010.lua @@ -0,0 +1,261 @@ +-- bk0010.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +-- --- Load butons --- +common_autoboot.populate_buttons(button) + +-- --- Print Info --- +common_autoboot.print_image_info() +-- common_autoboot.print_buttons(button) + +-- --- Cassette Loading Handler Setup --- +local CASSETTE_SLOT = 1 +local CASSETTE_DEVICE_TAG = manager.machine.images:at(CASSETTE_SLOT).device.tag +local cassette_handler = common_autoboot.create_cassette_handler(CASSETTE_DEVICE_TAG) + + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = 100 -- common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function create_boot_default_sequence(frame_num, cassette_monitor_func, title_to_type) -- 'cassette_monitor_func' is the per-frame callable handler + local sequence_state = 0 + -- Define states for clarity + local STATES = { + INIT_PRE_LOAD_ACTIONS = 0, -- Initial actions before CLOAD/PLAY + PLAY_CASS_INITIATED = 1, -- CLOAD/PLAY commands sent, waiting for motor to spin up + LOADING_CASS = 2, -- Cassette motor is ON, monitoring for completion + CASS_LOAD_DONE = 3, -- Cassette has finished loading, waiting for post-load actions + POST_LOAD_ACTIONS = 4, -- Executing actions after cassette load + COMPLETE = 5 -- Sequence finished + } + + local post_load_start_frame = 0 -- Frame at which post-load actions began + + return function(current_frame_num) -- This inner function runs every frame + -- Always call cassette_monitor_func once we are in a state where loading should be active. + -- This ensures continuous monitoring, throttling, and detection of load completion. + if sequence_state >= STATES.LOADING_CASS and sequence_state < STATES.CASS_LOAD_DONE then + local cassette_load_done = cassette_monitor_func(current_frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + if cassette_load_done then + sequence_state = STATES.CASS_LOAD_DONE -- Transition directly to CASS_LOAD_DONE + post_load_start_frame = current_frame_num -- Mark start for relative timing of post-actions + emu.print_info("Boot Default: Cassette loading is complete (triggered by handler). Transitioning to post-load actions.") + return -- Exit early for this frame after state change, to prevent double-execution + end + end + + -- --- State Machine Logic --- + if sequence_state == STATES.INIT_PRE_LOAD_ACTIONS then + -- Schedule initial pre-load actions + common_autoboot.type_at_frame(current_frame_num, "MO\n", 100) + common_autoboot.type_at_frame(current_frame_num, "M\n", 200) + common_autoboot.type_at_frame(current_frame_num, title_to_type .. "\n", 300) + common_autoboot.play_cassette_at_frame(current_frame_num, CASSETTE_DEVICE_TAG, 400) + + -- Transition to PLAY_CASS_INITIATED after these actions are scheduled (at the last target frame or beyond) + if current_frame_num >= 350 then + sequence_state = STATES.PLAY_CASS_INITIATED + emu.print_info("Boot Default: Pre-load actions scheduled. Waiting for cassette motor to engage.") + end + + elseif sequence_state == STATES.PLAY_CASS_INITIATED then + -- Wait for the cassette motor to actually spin up + local cassette_device = manager.machine.cassettes[CASSETTE_DEVICE_TAG] + if cassette_device and cassette_device.motor_state == true then + sequence_state = STATES.LOADING_CASS + emu.print_info("Boot Default: Cassette motor confirmed ON. Beginning continuous monitoring.") + end + + -- If sequence_state becomes CASS_LOAD_DONE (from the monitor above), this block is skipped, + -- and the logic will fall through to the next `elseif` for POST_LOAD_ACTIONS in the subsequent frame. + + elseif sequence_state == STATES.CASS_LOAD_DONE then + -- This state is primarily a transition point. + -- The 'RUN' command is NOT issued here. It's issued by the cassette_monitor_func internally. + -- We transition immediately to POST_LOAD_ACTIONS after load is detected. + sequence_state = STATES.POST_LOAD_ACTIONS + emu.print_info("Boot Default: Transitioning to post-load actions.") + + elseif sequence_state == STATES.POST_LOAD_ACTIONS then + -- --- Actions to perform AFTER cassette load is done --- + -- Use `post_load_start_frame` for relative timing + common_autoboot.type_at_frame(current_frame_num, "S\n", post_load_start_frame + 50, 1) + + -- Check if all post-load actions are completed + if current_frame_num >= post_load_start_frame + 100 + BUTTON_PRESS_DURATION then + sequence_state = STATES.COMPLETE + emu.print_info("Boot Default: All post-load actions completed. Sequence finished.") + end + + elseif sequence_state == STATES.COMPLETE then + -- Do nothing, sequence is finished. + end + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(CASSETTE_SLOT).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + aljur = create_boot_default_sequence(frame_num, cassette_handler, "ALJUR .COD"), + antix = create_boot_default_sequence(frame_num, cassette_handler, "Antix"), + apple = create_boot_default_sequence(frame_num, cassette_handler, "Apple"), + arkano = create_boot_default_sequence(frame_num, cassette_handler, "Arkano"), + arkanoid = create_boot_default_sequence(frame_num, cassette_handler, "Arkanoid"), + asprekl = create_boot_default_sequence(frame_num, cassette_handler, "Asp_rekl"), + ass = create_boot_default_sequence(frame_num, cassette_handler, "Ass"), + ass2 = create_boot_default_sequence(frame_num, cassette_handler, "Ass2"), + astrdrom = create_boot_default_sequence(frame_num, cassette_handler, "Astrdrom"), + baby = create_boot_default_sequence(frame_num, cassette_handler, "Baby"), + bally = create_boot_default_sequence(frame_num, cassette_handler, "Bally"), + bapple = create_boot_default_sequence(frame_num, cassette_handler, "Bapple"), + barb = create_boot_default_sequence(frame_num, cassette_handler, "Barb"), + barbar = create_boot_default_sequence(frame_num, cassette_handler, "Barbar"), + barman = create_boot_default_sequence(frame_num, cassette_handler, "Barman"), + batiskaf = create_boot_default_sequence(frame_num, cassette_handler, "Batiskaf"), + bigchess = create_boot_default_sequence(frame_num, cassette_handler, "Bigchess"), + bil = create_boot_default_sequence(frame_num, cassette_handler, "Bil"), + billiard = create_boot_default_sequence(frame_num, cassette_handler, "BILLIARD"), + biowar = create_boot_default_sequence(frame_num, cassette_handler, "Biowar"), + bkdemo = create_boot_default_sequence(frame_num, cassette_handler, "BKDEMO"), + bkpack = create_boot_default_sequence(frame_num, cassette_handler, "Bkpack"), + blcout = create_boot_default_sequence(frame_num, cassette_handler, "Blcout"), + blockout = create_boot_default_sequence(frame_num, cassette_handler, "BLOCKOUT"), + bolde2 = create_boot_default_sequence(frame_num, cassette_handler, "Bolde2"), + bolder2 = create_boot_default_sequence(frame_num, cassette_handler, "Bolder2"), + bolder3 = create_boot_default_sequence(frame_num, cassette_handler, "Bolder3"), + bomb4 = create_boot_default_sequence(frame_num, cassette_handler, "Bomb4"), + breach = create_boot_default_sequence(frame_num, cassette_handler, "breach"), + ['break'] = create_boot_default_sequence(frame_num, cassette_handler, "Break"), + breaking = create_boot_default_sequence(frame_num, cassette_handler, "Breaking"), + brhouse = create_boot_default_sequence(frame_num, cassette_handler, "Brhouse"), + bubbler = create_boot_default_sequence(frame_num, cassette_handler, "Bubbler"), + bubler = create_boot_default_sequence(frame_num, cassette_handler, "Bubler"), + cache = create_boot_default_sequence(frame_num, cassette_handler, "Cache"), + cave = create_boot_default_sequence(frame_num, cassette_handler, "Cave"), + cavedoc = create_boot_default_sequence(frame_num, cassette_handler, "Cave_doc"), + caveman = create_boot_default_sequence(frame_num, cassette_handler, "Cave_man"), + caveres = create_boot_default_sequence(frame_num, cassette_handler, "Cave_res"), + chaser = create_boot_default_sequence(frame_num, cassette_handler, "Chaser"), + checkers = create_boot_default_sequence(frame_num, cassette_handler, "Checkers"), + chess07 = create_boot_default_sequence(frame_num, cassette_handler, "Chess07"), + chess1 = create_boot_default_sequence(frame_num, cassette_handler, "Chess1"), + chess2 = create_boot_default_sequence(frame_num, cassette_handler, "Chess2"), + chess3 = create_boot_default_sequence(frame_num, cassette_handler, "Chess3"), + chess4 = create_boot_default_sequence(frame_num, cassette_handler, "Chess4"), + circler = create_boot_default_sequence(frame_num, cassette_handler, "CIRCLER"), + columns = create_boot_default_sequence(frame_num, cassette_handler, "Columns"), + columns2 = create_boot_default_sequence(frame_num, cassette_handler, "Columns2"), + comic = create_boot_default_sequence(frame_num, cassette_handler, "Comic"), + cosmic = create_boot_default_sequence(frame_num, cassette_handler, "COSMIC"), + cosmicb = create_boot_default_sequence(frame_num, cassette_handler, "Cosmic_b"), + courier = create_boot_default_sequence(frame_num, cassette_handler, "Courier"), + covox = create_boot_default_sequence(frame_num, cassette_handler, "covox"), + crack = create_boot_default_sequence(frame_num, cassette_handler, "Crack"), + dama = create_boot_default_sequence(frame_num, cassette_handler, "Dama"), + demsl = create_boot_default_sequence(frame_num, cassette_handler, "Demsl"), + demsl1 = create_boot_default_sequence(frame_num, cassette_handler, "Demsl1"), + demsl2 = create_boot_default_sequence(frame_num, cassette_handler, "Demsl2"), + demsl3 = create_boot_default_sequence(frame_num, cassette_handler, "Demsl3"), + desan = create_boot_default_sequence(frame_num, cassette_handler, "Desan"), + desandoc = create_boot_default_sequence(frame_num, cassette_handler, "Desandoc"), + desant = create_boot_default_sequence(frame_num, cassette_handler, "Desant"), + diamond = create_boot_default_sequence(frame_num, cassette_handler, "Diamond"), + digger = create_boot_default_sequence(frame_num, cassette_handler, "Digger"), + divers3 = create_boot_default_sequence(frame_num, cassette_handler, "Divers3"), + dragon = create_boot_default_sequence(frame_num, cassette_handler, "DRAGON.BIN"), + flier = create_boot_default_sequence(frame_num, cassette_handler, "FLIER"), + font = create_boot_default_sequence(frame_num, cassette_handler, "FONT"), + hobbitovl = create_boot_default_sequence(frame_num, cassette_handler, "HOBBIT.OVL"), + hobbit = create_boot_default_sequence(frame_num, cassette_handler, "HOBBIT"), + horror = create_boot_default_sequence(frame_num, cassette_handler, "Horror"), + horrors = create_boot_default_sequence(frame_num, cassette_handler, "Horror_s"), + house1 = create_boot_default_sequence(frame_num, cassette_handler, "House1"), + house2 = create_boot_default_sequence(frame_num, cassette_handler, "House2"), + indjon = create_boot_default_sequence(frame_num, cassette_handler, "Indjon"), + jetman = create_boot_default_sequence(frame_num, cassette_handler, "Jetman"), + joebla = create_boot_default_sequence(frame_num, cassette_handler, "Joebla"), + john = create_boot_default_sequence(frame_num, cassette_handler, "John"), + johnny = create_boot_default_sequence(frame_num, cassette_handler, "Johnny"), + jokey = create_boot_default_sequence(frame_num, cassette_handler, "Jokey"), + jones = create_boot_default_sequence(frame_num, cassette_handler, "Jones"), + jones1 = create_boot_default_sequence(frame_num, cassette_handler, "Jones1"), + jones2 = create_boot_default_sequence(frame_num, cassette_handler, "Jones2"), + jones3 = create_boot_default_sequence(frame_num, cassette_handler, "Jones3"), + jungle = create_boot_default_sequence(frame_num, cassette_handler, "Jungle"), + karado = create_boot_default_sequence(frame_num, cassette_handler, "Karado"), + karate = create_boot_default_sequence(frame_num, cassette_handler, "Karate"), + klad = create_boot_default_sequence(frame_num, cassette_handler, "Klad"), + kurier = create_boot_default_sequence(frame_num, cassette_handler, "Kurier"), + ladderovl = create_boot_default_sequence(frame_num, cassette_handler, "ladder.ovl"), + ladder = create_boot_default_sequence(frame_num, cassette_handler, "ladder"), + lrunnergms = create_boot_default_sequence(frame_num, cassette_handler, "LRUNNER.GMS"), + lrunner = create_boot_default_sequence(frame_num, cassette_handler, "LRUNNER"), + othello = create_boot_default_sequence(frame_num, cassette_handler, "OTHELLO"), + otl9 = create_boot_default_sequence(frame_num, cassette_handler, "otl9"), + p10k = create_boot_default_sequence(frame_num, cassette_handler, "p10k"), + pacman = create_boot_default_sequence(frame_num, cassette_handler, "PACMAN"), + perevoro = create_boot_default_sequence(frame_num, cassette_handler, "PEREVOROT"), + popo = create_boot_default_sequence(frame_num, cassette_handler, "POPO"), + raceovl = create_boot_default_sequence(frame_num, cassette_handler, "RACE.OVL"), + race = create_boot_default_sequence(frame_num, cassette_handler, "RACE"), + rever1 = create_boot_default_sequence(frame_num, cassette_handler, "Rever1"), + rever2 = create_boot_default_sequence(frame_num, cassette_handler, "Rever2"), + rotate = create_boot_default_sequence(frame_num, cassette_handler, "ROTATE"), + rtype = create_boot_default_sequence(frame_num, cassette_handler, "RTYPE"), + rtype1 = create_boot_default_sequence(frame_num, cassette_handler, "RTYPE1.LAB"), + rtype2 = create_boot_default_sequence(frame_num, cassette_handler, "RTYPE2.LAB"), + sokoban = create_boot_default_sequence(frame_num, cassette_handler, "SOKOBAN"), + stalker = create_boot_default_sequence(frame_num, cassette_handler, "Stalker"), + tetr3 = create_boot_default_sequence(frame_num, cassette_handler, "TETR3"), + tetris = create_boot_default_sequence(frame_num, cassette_handler, "TETRIS"), + tetro = create_boot_default_sequence(frame_num, cassette_handler, "Tetro"), + xonix1 = create_boot_default_sequence(frame_num, cassette_handler, "XONIX1"), + xonix5 = create_boot_default_sequence(frame_num, cassette_handler, "XONIX5"), + zoom = create_boot_default_sequence(frame_num, cassette_handler, "ZOOM"), +} + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + --- DEBUG: Print current frame number every 100 frames --- + common_autoboot.debug_frame_num(frame_num) + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(frame_num, cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/c64_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/c64_cass.lua new file mode 100644 index 00000000000..edb070f3c11 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/c64_cass.lua @@ -0,0 +1,52 @@ +-- to get cassette device name: +-- [MAME]> for k,v in pairs(manager.machine.cassettes) do +-- [MAME]>> print(k) +-- [MAME]>> end + + +local frame_num = 0 +local load_done_frame_num = 0 +local motor_state_false_frame_num = 0 +local function process_frame() + frame_num = frame_num + 1 + + if frame_num == 1 then + emu.keypost('LOAD\n') + manager.machine.cassettes[":tape:c1530:cassette"]:play() + end + + -- Workaround, sometimes the first "load" is misspelled + if frame_num == 150 then + emu.keypost('LOAD\n') + manager.machine.cassettes[":tape:c1530:cassette"]:play() + end + + if frame_num > 300 then + if motor_state_false_frame_num == 0 then + if manager.machine.cassettes[":tape:c1530:cassette"].motor_state == false then + motor_state_false_frame_num = frame_num + end + else + if frame_num > motor_state_false_frame_num + 60 then + if load_done_frame_num == 0 then + load_done_frame_num = frame_num + emu.keypost('RUN\n') + end + end + end + end + + if manager.machine.cassettes[":tape:c1530:cassette"].motor_state == true then + motor_state_false_frame_num = 0 + end + + if manager.machine.cassettes[":tape:c1530:cassette"].is_stopped == false and manager.machine.cassettes[":tape:c1530:cassette"].motor_state == true then + manager.machine.video.throttled = false + manager.machine.video.frameskip = 12 + else + manager.machine.video.throttled = true + manager.machine.video.frameskip = 0 + end +end + +subscription=emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/c64_flop.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/c64_flop.lua new file mode 100644 index 00000000000..09106307586 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/c64_flop.lua @@ -0,0 +1 @@ +emu.keypost('LOAD "*" ,8,1\n') diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/camplynx_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/camplynx_cass.lua new file mode 100644 index 00000000000..2aff44f2e94 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/camplynx_cass.lua @@ -0,0 +1,142 @@ +-- camplynx_cass.lua +-- +-- Camputers Lynx cassette autoboot with header-based type detection. +-- +-- CampLynx .tap byte format: +-- 0x22 opening quote +-- ASCII string (variable length) +-- 0x22 closing quote +-- 0x42 ('B') BASIC program → LOAD "name"\n + RUN\n after motor off +-- 0x4D ('M') machine code → MLOAD "name"\n (auto-runs after load) +-- + +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") +local zip_util = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_zip.lua") + +local TAP_SCAN_BYTES = 256 + +local TAPE_TYPE_BASIC = 0 +local TAPE_TYPE_MACHINE = 1 + +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local CASSETTE_SLOT = 1 +local CASSETTE_DEVICE_TAG = manager.machine.images:at(CASSETTE_SLOT).device.tag + +local button = {} +local frame_num = 0 +common_autoboot.populate_buttons(button) + +local function find_cassette_path() + for _, cass in pairs(manager.machine.cassettes) do + if cass.exists and cass.filename and #cass.filename > 0 then + print("[CampLynx Autoboot] Cassette device: " .. cass.filename) + return cass.filename + end + end + for _, img in pairs(manager.machine.images) do + if img.exists and img.filename and #img.filename > 0 then + local fn = img.filename:lower() + if fn:find("%.tap$") or fn:find("%.cas$") or fn:find("%.wav$") then + print("[CampLynx Autoboot] Image device cassette: " .. img.filename) + return img.filename + end + end + end + return nil +end + +-- ── CampLynx header parser ──────────────────────────────────────────────────── +-- +-- Format: "filename"... +-- 0x22 ... 0x22 quoted filename +-- 0x42 ('B') BASIC +-- 0x4D ('M') machine code + +local function parse_tap_header(data) + if not data or #data < 4 then return nil end + if data:byte(1) ~= 0x22 then return nil end + + local end_pos = nil + for i = 2, #data do + if data:byte(i) == 0x22 then + end_pos = i + break + end + end + if not end_pos or end_pos + 1 > #data then return nil end + + local filename = data:sub(2, end_pos - 1) + local type_byte = data:byte(end_pos + 1) + + if type_byte == 0x4D then + print(string.format("[CampLynx Autoboot] Header: MACHINE name='%s'", filename)) + return { file_type = TAPE_TYPE_MACHINE, filename = filename } + else + print(string.format("[CampLynx Autoboot] Header: BASIC name='%s'", filename)) + return { file_type = TAPE_TYPE_BASIC, filename = filename } + end +end + +local function detect_tape_info() + print("[CampLynx Autoboot] --- Tape type detection ---") + local path = find_cassette_path() + if not path then + print("[CampLynx Autoboot] No cassette found, defaulting to BASIC.") + return { file_type = TAPE_TYPE_BASIC, filename = "" } + end + local data = zip_util.read_bytes(path, TAP_SCAN_BYTES) + if not data then + print("[CampLynx Autoboot] Could not read cassette, defaulting to BASIC.") + return { file_type = TAPE_TYPE_BASIC, filename = "" } + end + local info = parse_tap_header(data) + if info then return info end + print("[CampLynx Autoboot] No valid header found, defaulting to BASIC.") + return { file_type = TAPE_TYPE_BASIC, filename = "" } +end + +-- ── Boot functions ──────────────────────────────────────────────────────────── + +local cassette_handler = common_autoboot.create_cassette_handler(CASSETTE_DEVICE_TAG) +local tape_info = nil + +local function boot_basic() + common_autoboot.type_at_frame(frame_num, 'LOAD "' .. tape_info.filename .. '"\n', 100, BUTTON_PRESS_DURATION) + common_autoboot.play_cassette_at_frame(frame_num, CASSETTE_DEVICE_TAG, 200) + + if cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) then + emu.keypost("RUN\n") + end +end + +local function boot_machine() + -- MLOAD auto-runs after loading; no post-load command needed. + common_autoboot.type_at_frame(frame_num, 'MLOAD "' .. tape_info.filename .. '"\n', 100, BUTTON_PRESS_DURATION) + common_autoboot.play_cassette_at_frame(frame_num, CASSETTE_DEVICE_TAG, 200) + + cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) +end + +-- ── Main ────────────────────────────────────────────────────────────────────── + +local function process_frame() + frame_num = frame_num + 1 + + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + common_autoboot.print_image_info() + tape_info = detect_tape_info() + end + + common_autoboot.debug_frame_num(frame_num) + + if tape_info and tape_info.file_type == TAPE_TYPE_MACHINE then + boot_machine() + else + boot_basic() + end +end + +subscription = emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/cdi.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/cdi.lua new file mode 100644 index 00000000000..9d22c1a5450 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/cdi.lua @@ -0,0 +1,38 @@ +local button = {} + +for i, j in pairs(manager.machine.ioport.ports) do + for field_name, field in pairs(j.fields) do + id = field.port.tag .. ',' .. field.mask .. ',' .. field.type + print(field_name,": ", id) + button[id] = field + end +end + +local boot_end_frame = 700 +local frame_num = 0 +local previous_throttled = manager.machine.video.throttled +local previous_frameskip = manager.machine.video.frameskip + +local function process_frame() + frame_num = frame_num + 1 + + if frame_num == 1 then + manager.machine.video.throttled = false + manager.machine.video.frameskip = 12 + end + + if frame_num == boot_end_frame then + manager.machine.video.throttled = previous_throttled + manager.machine.video.frameskip = previous_frameskip + + button[":MOUSEBTN,1,64"]:set_value(1) + end + + if frame_num == boot_end_frame + 20 then + button[":MOUSEBTN,1,64"]:set_value(0) + end +end + +subscription=emu.add_machine_frame_notifier(process_frame) + + diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/cgenie_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/cgenie_cass.lua new file mode 100644 index 00000000000..37bb37aae33 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/cgenie_cass.lua @@ -0,0 +1,163 @@ +-- cgenie_cass.lua +-- +-- Colour Genie cassette autoboot with header-based type detection. +-- +-- CGenie .cas byte format (after optional 36-byte ASCII text header): +-- 0x66 sync byte +-- 0x55 header/name block marker → machine-code program +-- [0..5] filename (6 bytes ASCII, 0x20-padded) +-- 0x3C data block follows +-- ... +-- +-- 0x66 sync byte +-- BASIC tokenised data follows → BASIC program +-- +-- Boot sequences: +-- BASIC → \n · CLOAD\n · play · RUN\n after motor off +-- machine code→ \n · SYSTEM\n · \n · play · /\n after motor off + +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") +local zip_util = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_zip.lua") + +local CAS_SCAN_BYTES = 4096 + +local TAPE_TYPE_BASIC = 0 +local TAPE_TYPE_DATA = 1 +local TAPE_TYPE_MACHINE = 2 + +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local button = {} +local frame_num = 0 +common_autoboot.populate_buttons(button) + +local function find_cassette_path() + for _, cass in pairs(manager.machine.cassettes) do + if cass.exists and cass.filename and #cass.filename > 0 then + print("[CGenie Autoboot] Cassette device: " .. cass.filename) + return cass.filename + end + end + for _, img in pairs(manager.machine.images) do + if img.exists and img.filename and #img.filename > 0 then + local fn = img.filename:lower() + if fn:find("%.cas$") or fn:find("%.wav$") then + print("[CGenie Autoboot] Image device cassette: " .. img.filename) + return img.filename + end + end + end + return nil +end + +-- ── CGenie header parser ────────────────────────────────────────────────────── +-- +-- Scan for the 0x66 sync byte. The byte immediately following it determines +-- the file type: +-- 0x55 → machine-code (SYSTEM) program; next 6 bytes are the filename. +-- other → BASIC (CLOAD) program; no filename needed. + +local function parse_cgenie_header(data) + if not data or #data < 4 then return nil end + + for i = 1, #data - 2 do + if data:byte(i) == 0x66 then + local next_byte = data:byte(i + 1) + + if next_byte == 0x55 then + -- Machine-code header: read 6-byte filename + if i + 7 > #data then return nil end + local raw = {} + for j = 0, 5 do + raw[j + 1] = data:byte(i + 2 + j) + end + -- Strip trailing spaces and NULs to get the name SYSTEM expects + local name_end = 6 + while name_end >= 1 and (raw[name_end] == 0x20 or raw[name_end] == 0x00) do + name_end = name_end - 1 + end + local filename = "" + for j = 1, name_end do + filename = filename .. string.char(raw[j]) + end + print(string.format("[CGenie Autoboot] Header: MACHINE name='%s'", filename)) + return { file_type = TAPE_TYPE_MACHINE, filename = filename } + else + -- No name block → BASIC program + print("[CGenie Autoboot] Header: BASIC") + return { file_type = TAPE_TYPE_BASIC, filename = "" } + end + end + end + + return nil +end + +local function detect_tape_info() + print("[CGenie Autoboot] --- Tape type detection ---") + local path = find_cassette_path() + if not path then + print("[CGenie Autoboot] No cassette found, defaulting to BASIC.") + return { file_type = TAPE_TYPE_BASIC, filename = "" } + end + local data = zip_util.read_bytes(path, CAS_SCAN_BYTES) + if not data then + print("[CGenie Autoboot] Could not read cassette, defaulting to BASIC.") + return { file_type = TAPE_TYPE_BASIC, filename = "" } + end + local info = parse_cgenie_header(data) + if info then return info end + print("[CGenie Autoboot] No valid header found, defaulting to BASIC.") + return { file_type = TAPE_TYPE_BASIC, filename = "" } +end + +-- ── Boot functions ──────────────────────────────────────────────────────────── + +local cassette_handler = common_autoboot.create_cassette_handler(":cassette") +local tape_info = nil + +local function boot_basic() + common_autoboot.type_at_frame(frame_num, "\n", 50, BUTTON_PRESS_DURATION) + common_autoboot.type_at_frame(frame_num, "CLOAD\n", 200, BUTTON_PRESS_DURATION) + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 300) + + if cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) then + emu.keypost("RUN\n") + end +end + +local function boot_machine() + -- SYSTEM prompts "*? " for the tape name, then loads from tape, + -- then prompts "*/ " for the start address; "/" runs from default. + common_autoboot.type_at_frame(frame_num, "\n", 50, BUTTON_PRESS_DURATION) + common_autoboot.type_at_frame(frame_num, "SYSTEM\n", 150, BUTTON_PRESS_DURATION) + common_autoboot.type_at_frame(frame_num, tape_info.filename .. "\n", 200, BUTTON_PRESS_DURATION) + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 300) + + if cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) then + emu.keypost("/\n") + end +end + +-- ── Main ────────────────────────────────────────────────────────────────────── + +local function process_frame() + frame_num = frame_num + 1 + + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + common_autoboot.print_image_info() + tape_info = detect_tape_info() + end + + common_autoboot.debug_frame_num(frame_num) + + if tape_info and tape_info.file_type == TAPE_TYPE_MACHINE then + boot_machine() + else + boot_basic() + end +end + +subscription = emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/coco_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/coco_cass.lua new file mode 100644 index 00000000000..bdb63a815c6 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/coco_cass.lua @@ -0,0 +1,81 @@ +-- vtech2_cass.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +common_autoboot.populate_buttons(button) + +-- Print the button table contents for debugging +-- common_autoboot.print_buttons(button) + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function boot_default(cassette_handler) + -- common_autoboot.type_at_frame(frame_num, "CLOAD:RUN\n", 100, BUTTON_PRESS_DURATION) + + common_autoboot.type_at_frame(frame_num, "CLOADM:EXEC\n", 100, BUTTON_PRESS_DURATION) + + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 400) -- need to wait at least 300 frames after CLOAD cmd, otherwise will have LOADING ERROR! + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + emu.keypost('RUN\n') + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(1).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + ["default"] = boot_default, +} + +-- --- Cassette Loading Handler Setup --- +local cassette_handler = common_autoboot.create_cassette_handler(":cassette") + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + -- --- Print current frame number every 100 frames --- + if frame_num % 100 == 0 then -- The modulo operator (%) gives the remainder of a division + emu.print_info("Current Frame: " .. frame_num) + end + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/coco_flop.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/coco_flop.lua new file mode 100644 index 00000000000..ee4f869a375 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/coco_flop.lua @@ -0,0 +1,130 @@ +cpu = manager.machine.devices[":maincpu"] +mem = cpu.spaces["program"] +base_addr = 0x0400 +base_file_name_size = 9 +ext_file_name_size = 3 +next_file = 32 +file_index = 0 +dir_frame = 0 +try_run = 0 +type_buffer = {} +type_qty = 0 +memory_clean_frame = 0 +character_mask = 0x3F + +local function filter_char(char) + ret_char = char + if char >= 0x60 then + ret_char = char & character_mask + end + + return ret_char +end + +local function stack_char(char) + table.insert(type_buffer, 1, char) + type_qty = type_qty + 1 +end + +local function dir(frame) + stack_char("d") + stack_char("i") + stack_char("r") + stack_char(" ") + stack_char("0") + stack_char("\n") + dir_frame = frame +end + +local function is_extension_allowed() + addr = base_addr + file_index * next_file + base_file_name_size + + ext = {} + for c = 0, (ext_file_name_size-1) do + ext[c+1] = mem:read_u8(addr + c) + end + + allowed_ext = { string.byte('B'), string.byte('A'), string.byte('S')} + + allowed = 0 + + for c = 1, 3 do + if allowed_ext[c] == ext[c] then + allowed = allowed + 1 + end + end + + return (allowed == 3) +end + +local function run_file() + print("file index", file_index) + if is_extension_allowed() == false then + file_index = file_index + 1 + return + end + + stack_char("r") + stack_char("u") + stack_char("n") + stack_char("\"") + for c = 0, base_file_name_size-1 do + addr = base_addr + file_index * next_file + c + char = filter_char(mem:read_u8(addr)) + if char ~= 0x20 then + stack_char(string.char(char)) + end + end + + stack_char("\"\n") + try_run = 1 +end + +local function wait_for_clean_memory(frame) + if memory_clean_frame ~= 0 then + if frame > memory_clean_frame + 25 then + try_run = 0 + dir_frame = 0 + memory_clean_frame = 0 + file_index = file_index + 1 + end + else + start_file = mem:read_u8(base_addr + file_index * next_file) + if start_file == 0 then + memory_clean_frame = frame + end + end +end + +local function unstack_char() + if type_qty > 0 then + char = table.remove(type_buffer) + type_qty = type_qty - 1 + emu.keypost(char) + end +end + +frame_num = 0 +local function process_frame() + frame_num = frame_num + 1 + + if dir_frame == 0 then + if frame_num > 90 then + dir(frame_num) + end + else + if try_run == 0 then + if frame_num > dir_frame + 350 then + run_file() + end +-- else +-- wait_for_clean_memory(frame_num) + end + end + + if frame_num % 5 == 0 then + unstack_char() + end +end + +subscription=emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/coco_sha1_map.json b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/coco_sha1_map.json new file mode 100644 index 00000000000..ff61421180b --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/coco_sha1_map.json @@ -0,0 +1,10570 @@ +{ + "72a3531037168ae46d805ef62a02c71c4fd70570": { + "filename": "3D Tic Tac Toe (Oelrich Publications).zip", + "disk0": "3DTTT.DSK", + "basic": "LOADM\"3DTTT\":EXEC\n" + }, + "53f7ad1015ee0f3eca0bbfb94a1e7d93d6a0abb9": { + "filename": "3D Brickaway (Avalon Hill).zip", + "disk0": "3DBRICK.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"3DBRICK\":EXEC\n" + }, + "0667c50f611bac17e30026a4a10c2fa461970f67": { + "filename": "3D Ghostmania (Randy S. Johnson).zip", + "disk0": "3DGHOST.DSK", + "basic": "LOADM\"3D GHOST\":EXEC\n" + }, + "c19bf3d6ee2527c06ff5b5f4566f928dc2d54ed3": { + "filename": "10 Meter Diving (Tammy Jones).zip", + "disk0": "PFRMDIVE.DSK", + "basic": "RUN\"PFRMDIVE\"\n" + }, + "e04701223cf599e898059e074c0010953b0d6df3": { + "filename": "3D Space Wars (Newson Consultants).zip", + "disk0": "3DWAR.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"3DWAR\":EXEC\n" + }, + "f911ec9658dfc52a325245ec2e295a22fb4f5610": { + "filename": "5000 (Gary James) (Coco 3).zip", + "machine": "coco3", + "disk0": "5000.DSK", + "basic": "RUN\"5000\"\n" + }, + "92be86e96cb4cf75a0151cb611e0c465f82997f2": { + "filename": "5-Line Fruit Slot Machine (Tom Mix Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "5LINE.DSK", + "basic": "LOADM\"5LINE\":EXEC\n" + }, + "05d63de44dce98928091044496fcc25628fb58ae": { + "filename": "4 Mile Island Adventure (Owls Nest Software).zip", + "disk0": "4MILE.DSK", + "basic": "RUN\"4MILE\"\n" + }, + "4a5e1d4d0d8062d413a4729da2060e3309ae8f67": { + "filename": "2048 (George Janssen) (Coco 3).zip", + "machine": "coco3", + "disk0": "2048.DSK", + "basic": "LOADM\"2048\":EXEC\n" + }, + "d391b85bdea188ea096289fb6339095e5bcb6c49": { + "filename": "666 The Haunted House (C. Hofsetz & G. Castro).zip", + "disk0": "666thh.dsk", + "basic": "RUN\"666\"\n" + }, + "9f37e05606037db6b9bbb6080d815d848c94b3a5": { + "filename": "5 Player Poker (T&D Software).zip", + "disk0": "POKER5.DSK", + "basic": "RUN\"POKER5\"\n" + }, + "f92a4c2868a8617bf011fc4d683dc3d9e153a59c": { + "filename": "Able Builders (T&D Software).zip", + "disk0": "ABLE.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"ABLE\":EXEC\n" + }, + "0e53b3ad87b29bf9125d48282cf762e2feb18de2": { + "filename": "7 Card Stud (Tandy).zip", + "disk0": "7CARD.DSK", + "basic": "LOADM\"7CARD\":EXEC\n" + }, + "9375ed622eb483b42c95c474e3062e90cb01fe16": { + "filename": "Across the Rubicon (Ark Royal Games).zip", + "disk0": "rubicon.dsk", + "basic": "RUN\"RUBICON\"\n" + }, + "16ee3a269b22636159633e93c758b10ce125acc2": { + "filename": "8-Ball (Anteco Software).zip", + "disk0": "8BALL.DSK", + "joy-left": "mjoy0", + "basic": "LOADM\"8BALL\":EXEC\n" + }, + "a456fdc2e0129a7f7a8642c9204dd6c219970f5d": { + "filename": "Aandark II (Fred D. Provoncha).zip", + "disk0": "AANDARK2.DSK", + "basic": "RUN\"INTRO\"\n" + }, + "b0ff710a6db6b36630ad0770252814c530714636": { + "filename": "A BASIC Adventure (Kevin Davidson).zip", + "disk0": "BASICADV.DSK", + "basic": "RUN\"BASICADV\"\n" + }, + "f78a204938fef27604198c70c977480f0fc62c35": { + "filename": "A day at the Races (George Bodiroga).zip", + "disk0": "RACES.DSK", + "basic": "RUN\"RACES\"\n" + }, + "bd7bb528b478944e7276ced11546882cef503597": { + "filename": "Advanced Star Trench Warfare (Fred B. Scerbo).zip", + "disk0": "TRENCH.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"TRENCH\"\n" + }, + "7a95fc695ffeb1011a343df2ac4336072c61e33c": { + "filename": "Adventure in Mythology (Saguaro Software) (SSC).zip", + "disk0": "MYTHOLGY.DSK", + "basic": "LOADM\"MYTHOLGY\":EXEC\n" + }, + "11cce148d19dcba2997520fab189c0834ae07037": { + "filename": "Adventure in Wonder Land (Prickly Pear Software).zip", + "disk0": "ALICE.DSK", + "basic": "LOADM\"ALICE\":EXEC\n" + }, + "5acf6f014a81abca627fd08966d74de8501fe135": { + "filename": "Adventure One - Land That Time Forgot (Mike Lustig).zip", + "disk0": "landadv.dsk", + "basic": "RUN\"LAND-ADV\"\n" + }, + "8b80cc96a74a3301f69602ee8a5b7ad0534bca70": { + "filename": "Adventures of Johnny Zero, The (Mark and Mike Anderson).zip", + "disk0": "JOHNNY0.DSK", + "basic": "RUN\"JOHNNY 0\"\n" + }, + "61bb3bf2d9caa01436287b5042a28963ee3399f9": { + "filename": "Adventure (Stuart Rayner).zip", + "disk0": "ADVENT.DSK", + "basic": "RUN\"ADV 32K\"\n" + }, + "737e09c08a0055dca9d1122d30fb0d0490288e9e": { + "filename": "Aerial Attack (Challenge Software) (SG-24 intro).zip", + "disk0": "AERIAL.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"AERIAL\":EXEC\n" + }, + "ae616d3bf8b3f6a76315743be5f5249498f7cd4f": { + "filename": "Adventure Trilogy (Softlaw Corp.).zip", + "disk0": "Trlgyadv.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"TRLGYADV\":EXEC\n" + }, + "9368ee1fa61d276de323be67884e43e5736faeae": { + "filename": "Air Attack (T&D Software).zip", + "disk0": "AIR.DSK", + "basic": "LOADM\"AIR\":EXEC\n" + }, + "c0a1d297c9179dc1c1aa92dd0410513a2144d303": { + "filename": "Airline (Adventure International).zip", + "disk0": "AIRLINE.DSK", + "basic": "LOADM\"AIRLINE\":EXEC\n" + }, + "2cb75936d1167ec937fb08add8cb249d8a80f10a": { + "filename": "Aftermath of the Asimovian Disaster, The (Tim Hartnell) (Coco 3).zip", + "machine": "coco3", + "disk0": "AFTERMAT.DSK", + "basic": "RUN\"AFTERMAT\"\n" + }, + "37167f0be6310906cbabf016205783a93bbef922": { + "filename": "Airball (Microdeal).zip", + "disk0": "AIRBALL.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"AIRBALL\":EXEC\n" + }, + "162031777ecccc9a3cb34891b12adcba361b8d4f": { + "filename": "Alchemist's Laboratory, The (Real Software Company).zip", + "disk0": "ALCHEM.DSK", + "basic": "RUN\"ALCHEM\"\n" + }, + "cca762ff97399849054f2f5f6ff9697b6a344903": { + "filename": "Air Traffic (Betasoft Systems).zip", + "disk0": "AIRTRAF.DSK", + "basic": "LOADM\"AIRTRAF\":EXEC\n" + }, + "ede875a6f2ad368a63182c34d072b3104db61d21": { + "filename": "Alcatraz II (Spectral Associates).zip", + "disk0": "ALCATRAZ.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"ALCATRAZ\"\n" + }, + "8abe25e595c94d60388b5db1c383d876cb5d96e6": { + "filename": "Amazing (Rad Hewko).zip", + "disk0": "AMAZING.DSK", + "basic": "RUN\"AMAZING\"\n" + }, + "f244f0d0ffe871d63d926408c580f3ff342a5aaa": { + "filename": "Amphibia (The Rainbow).zip", + "disk0": "AMPHIBIA.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"BOOT\"\n" + }, + "9fd86667d26cb377f8dcf8a20d3b8d0ef190395d": { + "filename": "Aldaron (Jade Products).zip", + "disk0": "ALDARON.DSK", + "basic": "LOADM\"ALDARON\":EXEC\n" + }, + "a106c65e63d4d2a5b725081ec39f10a49d4b56c6": { + "filename": "A Mazing World of Malcom Mortar (Tandy) (Coco 3).zip", + "machine": "coco3", + "disk0": "MALCOM.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MALCOM\":EXEC\n" + }, + "ceef8436a404dacd1c5ab49038decdf037704fe0": { + "filename": "Andrea Coco, The (Saguard Software).zip", + "disk0": "ANDREA.DSK", + "basic": "RUN\"ANDREA\"\n" + }, + "977f3ed2274d585510c7357c4f042a89e5be96e6": { + "filename": "Android Attack (Spectral Associates).zip", + "disk0": "ANDATCK.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ANDATCK\":EXEC\n" + }, + "ea9b12583101890a7db2fe6aa52fd5e685f9e46a": { + "filename": "Annihilator (Chromasette).zip", + "disk0": "ANNIHILA.DSK", + "basic": "LOADM\"ANNIHILA\":EXEC\n" + }, + "046d8de78bddba12dad659c38ee6c3e60fcfbf21": { + "filename": "Androne (Tandy).zip", + "disk0": "ANDRONE.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"ANDRONE\":EXEC\n" + }, + "1e9cdf6ec5c2e7d2f8914cd606c33afc4478913a": { + "filename": "Anti-Ballistic Missile Command (CLOAD).zip", + "disk0": "ABM.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"ABM\"\n" + }, + "eb651ca25f681e826ca743809d4d75c980c23ec7": { + "filename": "Arcadia (Flipper Action).zip", + "disk0": "ARCADIA.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"ARCADIA\"\n" + }, + "28ba51f5c2960953c0cd00b3c010302402dc1cfa": { + "filename": "Alternate Reality - The City (Datasoft) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "CITYBOOT.DSK", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "ac4fbd2cb7ca2680ce3129f26847d0b691b03cbe": { + "filename": "Alternate Reality - The City (Datasoft) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "CITYBOOT.DSK", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "525daa84553d665d75a1bff115433926fcdecaec": { + "filename": "Alternate Reality - The City (Datasoft) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "CITYBOOT.DSK", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "e79c218a9ccdc8c0a62f76afd2b3eb2a23112edb": { + "filename": "Arcade Factory, The (B&B Software).zip", + "disk0": "ARCADFCT.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ARCADE\":EXEC\n" + }, + "ec005a315070f4c04a26917bb0bed9e17a9000f2": { + "filename": "Apples (Computerware).zip", + "disk0": "APPLES.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"APPLES\":EXEC\n" + }, + "4e66e8135391df23027fb2db59281c1b4f2cd276": { + "filename": "Arconiax Assignment, The (The Rainbow).zip", + "disk0": "ARCON32K.DSK", + "basic": "RUN\"ARCON32K\"\n" + }, + "50198639edfc1238e27d3eee794850e317971195": { + "filename": "Arctic Adventure (Harry McCracken) (Coco port).zip", + "disk0": "ARCTIC.DSK", + "basic": "RUN\"ARCTIC\"\n" + }, + "c857448d76cea56673f451c7ece7f6866132a6d7": { + "filename": "Arena of Skill (Chuck Nivision) (Coco 3).zip", + "machine": "coco3", + "disk0": "arena.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"ARENA\"\n" + }, + "2299aa882cc25d600dca31c33800d03147b97642": { + "filename": "Arex (Adventure International).zip", + "disk0": "AREX.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"AREX\":EXEC\n" + }, + "71eaf55ca268d2b556fca15401aa287d2f8c801d": { + "filename": "Arthur (Yves & Marc).zip", + "disk0": "ARTHUR.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ARTHUR\":EXEC\n" + }, + "68976c3148d97f503fa7f0cb39e882019ae6c5dc": { + "filename": "Armchair Admiral (Eversoft Games) (Coco 3).zip", + "machine": "coco3", + "disk0": "ARMCHAIR.DSK", + "basic": "RUN\"ADMIRAL\"\n" + }, + "fd3f51429c7b61c14c0acb68cb430d0e02d48084": { + "filename": "Artillery v2.01 (Jordan Ellenberg).zip", + "disk0": "artil201.dsk", + "basic": "RUN\"ARTIL\"\n" + }, + "132f88817e247549a422a6235d447cf5b1a28968": { + "filename": "Arkanoid (Tandy) (Coco 1-2) (Coco 3).zip", + "machine": "coco3", + "disk0": "ARKANOID.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"ARKANOID\"\n" + }, + "aa25f3fd2a3258beeeea9f8c4357f3af46d33e1b": { + "filename": "Asimov Awards 2006.zip", + "machine": "coco3", + "disk0": "AA2006.DSK", + "basic": "RUN\"RUN ME\"\n" + }, + "5f39e0648be8385dde7b59193ae8a69c6c26416a": { + "filename": "Asimov Awards 2008.zip", + "machine": "coco3", + "disk0": "AA2008.DSK", + "basic": "RUN\"RUN ME\"\n" + }, + "c05d6a00649345787dd18eb9281ac674c3945c6f": { + "filename": "Assasin (Michael Freeman).zip", + "disk0": "ASSASIN.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ASSASIN\":EXEC\n" + }, + "a7d37476610908ee64350c6dd1bc83372667671e": { + "filename": "Asimov Awards 2007.zip", + "machine": "coco3", + "disk0": "AA2007.DSK", + "basic": "RUN\"RUN ME\"\n" + }, + "e85f0aab16d6c51fbc7fb186d312d11dc0966067": { + "filename": "Assignment 45 (80 Micro).zip", + "disk0": "ASS-45.DSK", + "basic": "RUN\"ASS-45\"\n" + }, + "6eb8f1c066020c80dcffd65b8330cd17cb0c6287": { + "filename": "Asteroids RX (Allan Turvey and Pere Serrat).zip", + "disk0": "ASTRX.DSK", + "basic": "LOADM\"ASTRX\":EXEC\n" + }, + "ce73a7c00a21343fb215464c98f4c5adc0f87ca9": { + "filename": "Atom (Tandy).zip", + "disk0": "ATOM.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ATOM\":EXEC\n" + }, + "56c3b93be31975570b9aac14ac3ac9af4cbedfbd": { + "filename": "Athletyx (Microdeal Cornwall).zip", + "disk0": "ATHLETYX.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ATHLETYX\":EXEC\n" + }, + "16106a7dc9d5c8c1897f56fcb2f90d267e44dc44": { + "filename": "ATC Simulator (Tom Mix Software).zip", + "disk0": "ATCSIM.DSK", + "basic": "RUN\"ATCSIM\"\n" + }, + "b73ff206aa3f681324a7b5b48961a6ad605b9e18": { + "filename": "Astro Blast (Chromasette).zip", + "disk0": "ASTBLAST.DSK", + "basic": "RUN\"ASTBLAST\"\n" + }, + "5922f247531d50d4a89c61279eb638c54785b838": { + "filename": "Astro Blast (Mark Data Products) (SG-8 intro).zip", + "disk0": "ASTRO.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ASTRO\":EXEC\n" + }, + "4159ab26097f1091da0aea5d8083d02361d047c3": { + "filename": "At Risk (Rick Ulland) (Coco 3).zip", + "machine": "coco3", + "disk0": "ATRISK.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"RISK\"\n" + }, + "7ae2108cda00dd01bd808cf493e37da5c284861e": { + "filename": "Avenger (The Cornsoft Group).zip", + "disk0": "AVENGER.DSK", + "basic": "LOADM\"AVENGER\":EXEC\n" + }, + "dc549e68dd221f29420d345c0afa722212b8d205": { + "filename": "Autobahn (Sigma Software) (SG-8) (Coco 1-2).zip", + "disk0": "AUTOBAHN.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"AUTOBAHN\":EXEC\n" + }, + "e75a2437de28f5e51c68bcd758c66e08292758c7": { + "filename": "Awari (HLO).zip", + "machine": "coco2bus", + "disk0": "AWARIv2.DSK", + "basic": "RUN\"AWARI2\"\n" + }, + "62a3589a9293be39d1ba51d51a3508cebd9076fd": { + "filename": "B-Zone (Jim Jewett).zip", + "disk0": "B-Zone.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"B-ZONE\"\n" + }, + "7e8db90e4a7cc449e97b5debaf5d27e4c1a2a7ba": { + "filename": "Baccarat (T&D Software).zip", + "disk0": "BACCARAT.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"BACCARAT\"\n" + }, + "305d6fdffc0f52b060f44c91f31395d1595b0afc": { + "filename": "Backgammon (Tandy).zip", + "disk0": "BACKGAMN.DSK", + "basic": "LOADM\"BACKGAMN\":EXEC\n" + }, + "6532531276d655ec6fafa7f2fddf107adee6d14e": { + "filename": "B-1 Nuclear Bomber (Avalon Hill) (Coco port).zip", + "disk0": "B1BOMBER.DSK", + "basic": "RUN\"B1BOMBER\"\n" + }, + "0b199481b5bf2431a269e273b9e26a05ff4870bb": { + "filename": "A Warlock's Revenge (Snailsoft Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "WARLOCK.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"AUTOEXEC\"\n" + }, + "2e9072011b8efd3c64c08ecf5f5ce1c5312e7589": { + "filename": "Balloon (Jamie Cho) (Coco 3).zip", + "machine": "coco3", + "disk0": "Balloon.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"BALLOON\"\n" + }, + "d9e6d1d385856da322db9ca1f8f1f90072a90060": { + "filename": "Balloon Fire (T&D Software).zip", + "disk0": "BALLFIRE.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"BALLFIRE\":EXEC\n" + }, + "a494b101158e09bd9c60b396fa69f906b4e0c01c": { + "filename": "Back Track (Incentive Software) (Coco port).zip", + "disk0": "BTRACK.DSK", + "basic": "LOADM\"BTRACK\":EXEC\n" + }, + "b717022d2d22c6fe68b3cf44929844c2cccacbe1": { + "filename": "Balldozer (Kouga Software) (Coco port).zip", + "disk0": "BALLDOZE.DSK", + "basic": "LOADM\"BALLDOZE\":EXEC\n" + }, + "4c4bff6356ea0091f194240ea43fc605fdf5c7ad": { + "filename": "Balloon Attack (T&D Software).zip", + "disk0": "BALLATCK.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"BALLATCK\":EXEC\n" + }, + "2e303ee4ae2dcf739d021dccc6f60d38ab03d36e": { + "filename": "Bagitman (Aardvark).zip", + "disk0": "BAGITMAN.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"BAGITMAN\":EXEC\n" + }, + "2121d488895ea6ff4b615fc65a11425447ef2dd7": { + "filename": "Balm (Joab C. Jackson).zip", + "disk0": "BALM.DSK", + "basic": "RUN\"BALM\"\n" + }, + "d6245a964dea312da305986efb7a2ac63c043b0a": { + "filename": "Barrier to Entry 1.0 - A Quiz About CoCoTalk In-Jokes (Jason Reighard).zip", + "disk0": "QUIZ.DSK", + "basic": "RUN\"QUIZ\"\n" + }, + "d7c4d411822944a57df506ff48ad1ef1e1e26b35": { + "filename": "Baseball (Tandy).zip", + "disk0": "BASEBALL.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"BASEBALL\":EXEC\n" + }, + "51b6193c3ddcdbc7fa016fa45da61ed35f911d47": { + "filename": "Barbarossa (Ark Royal Games).zip", + "disk0": "barbarosa.dsk", + "basic": "RUN\"GO\"\n" + }, + "574fa15b628c164fe38b56b4616122c5de8fb41a": { + "filename": "Bar 5 Video Slot Machine (Tom Mix Software).zip", + "disk0": "BAR5.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"BAR5\":EXEC\n" + }, + "c885b63896d4e3abcdbadd495846701b280e9cbb": { + "filename": "Bash 1.00.00 (SRB Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "BASH.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"BASH\":EXEC\n" + }, + "227708614daa06d2110d5185182f25cddb70087b": { + "filename": "Bash 3.00.00 (SRB Software) (Coco 1-2) (Coco 3).zip", + "machine": "coco3", + "disk0": "bash3.dsk", + "joy-right": "mjoy0", + "basic": "DOS\n" + }, + "5798c5c72dfa67b54bad6d2ea1484f2ff1409a0a": { + "filename": "Basic Dungeons & Dragons (Snailsoft) (Coco 3).zip", + "machine": "coco3", + "disk0": "BASICD&D.DSK", + "basic": "RUN\"AUTOEXEC\"\n" + }, + "41a18568295189209736095b343312d32408f367": { + "filename": "Basic Pong v1.11 (Richard Kelly).zip", + "disk0": "PONG111.DSK", + "basic": "RUN\"PONG-111\"\n" + }, + "39379d427c184a69f8858736d1510d934db95c01": { + "filename": "Bats and Bugs (Bill Franks).zip", + "disk0": "BATS.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"BATS\"\n" + }, + "2179bc2cf5c0e81a7cc998040a06ecb3966771c0": { + "filename": "Basic Pac-Man 2.0 (CoCo-Synthesis) (Coco 3).zip", + "machine": "coco3", + "disk0": "PACMAN.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"PAC-MAN\"\n" + }, + "870555581b6955f25565d2a3f024e7ec755f4d80": { + "filename": "Battle of Gettysburg (Softwride).zip", + "disk0": "GETTYSBG.DSK", + "basic": "RUN\"GETTYSBG\"\n" + }, + "d9971832bc49e158fab6384bed106a0a39f17ad9": { + "filename": "Battle for Tunis (Ark Royal Games).zip", + "disk0": "tunis.dsk", + "basic": "RUN\"TUNIS\"\n" + }, + "8fe1133ccb540dbbfb27b40403d76a03d7a72311": { + "filename": "Battle Hymn - The Battle of Gettysburg (Ark Royal Software).zip", + "disk0": "hymn.dsk", + "basic": "LOADM\"G\":EXEC\n" + }, + "db923900a1cd76a408267837aceb3ac0a4996c37": { + "filename": "Battle Of The Bulge (Ark Royal Games).zip", + "disk0": "BULGE.DSK", + "basic": "RUN\"BULGE\"\n" + }, + "d088ca564e5386d9a54ade35945d62a5d0d42295": { + "filename": "Battle of Midway, The (Ark Royal Games).zip", + "disk0": "MIDWAY.DSK", + "basic": "RUN\"MIDWAY\"\n" + }, + "473e5a86ea7e30ddc3bee7ed8cdb4cfdbc69a0da": { + "filename": "Battle Stations (Tom Mix Software).zip", + "disk0": "bstations.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"BATTLE\"\n" + }, + "af30753f8dd9cc97cc14b169503a6f1ec029b44f": { + "filename": "BC Bill (Imagine Software).zip", + "disk0": "BCBILL.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"BCBILL\":EXEC\n" + }, + "0c2754a536e5477fdc1a6f2c03dbed9eb14da60e": { + "filename": "Battle Tank Demo (Kenneth Del Signore).zip", + "disk0": "BATLTANK.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"BATLTANK\":EXEC\n" + }, + "b75b5668c2fb6c24eb908d1506ed64f637d6ce3f": { + "filename": "Beam Rider (Spectral Associates).zip", + "disk0": "BEAM.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"BEAM\":EXEC\n" + }, + "d004f908e8498f8dd38a3ed84d3c8baec74df19a": { + "filename": "Beanstalker (Microvision) (Coco port).zip", + "disk0": "BEANSTLK.DSK", + "basic": "LOADM\"BEANSTLK\":EXEC\n" + }, + "754ead3391c947bdd34ef484dfd6603700a582bb": { + "filename": "Bedlam (Tandy).zip", + "disk0": "BEDLAM.DSK", + "basic": "LOADM\"BEDLAM\":EXEC\n" + }, + "1ebf725a8a4367dc86a82a3de3d60b5cbbb4e1b4": { + "filename": "Berserk (Mark Data Products) (SG-8 intro).zip", + "disk0": "BERSERK.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"BERSERK\":EXEC\n" + }, + "0053a1aebf79a8cd9e7119320c9aa90cb3819b92": { + "filename": "Beyond the Cimeeon Moon (Nelson Software Systems).zip", + "disk0": "CIMEEON.DSK", + "basic": "LOADM\"CIMEEON\":EXEC\n" + }, + "f388984b1854d3ef363e1203bbea694086cef375": { + "filename": "Binary Adventure (Retro Rick).zip", + "disk0": "BINARY.DSK", + "basic": "RUN\"BINARY\"\n" + }, + "ffe185d069ab56077104d98907548a2a303f651d": { + "filename": "Beware the KBB (Retro Rick).zip", + "disk0": "KBBV110.DSK", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "19845fd55284179d2306e35ca1cb21edc25049e8": { + "filename": "Big Business (Guilbert Murray).zip", + "disk0": "BUSINESS.DSK", + "basic": "RUN\"BUSINESS\"\n" + }, + "a8dabfe71a2ba35a4ba829b6e5fc630893294cd1": { + "filename": "Biosphere (Tandy).zip", + "disk0": "Biosphere.dsk", + "basic": "DOS\n" + }, + "2c786f3d5b8ea83b8ece8677ddc78e292e53c80c": { + "filename": "Birds (Tom Mix Software).zip", + "disk0": "BIRDS.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"BIRDS\":EXEC\n" + }, + "1f88e17c785a25623ecddc645e54201050646639": { + "filename": "Black Grid (SPORTware) (Coco 3).zip", + "machine": "coco3", + "disk0": "BLKGRID.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"BLK GRID\"\n" + }, + "0f1f59367280db03739ac117e7d4278f041b9e35": { + "filename": "Blackbeard's Island (Novasoft).zip", + "disk0": "blckbrd.dsk", + "basic": "LOADM\"BLACKB\":EXEC\n", + "tv-input": "redblue" + }, + "78ebec6b610423412751e4872488243686ef4a4f": { + "filename": "Black Hole (T&D Software).zip", + "disk0": "BLAKHOLE.DSK", + "basic": "RUN\"BLAKHOLE\"\n" + }, + "3a4305b772e6cd4a0eef794d59f00328b2f8918b": { + "filename": "Black Jack Royale (Second City Software).zip", + "disk0": "BJR.DSK", + "basic": "RUN\"BJR\"\n" + }, + "156e91b3219633bc8177e9f283517efb8a884daa": { + "filename": "BLACKJACKPRO (Skillware Corporation).zip", + "disk0": "BJPRO.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"COUNTING/L1\"\n" + }, + "452a9639744d82c8e833291c48227ea4f9cfe099": { + "filename": "Blackjack (Steve Kincade).zip", + "disk0": "BLACKJAK.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"BLACKJAK\"\n" + }, + "e081f7823448a17ee4c874a396b19ee17a6d1037": { + "filename": "Blackjack (Tandy).zip", + "disk0": "BLACKJAK.DSK", + "basic": "RUN\"BLACKJAK\"\n" + }, + "b4d3b22e45f432b6deeb1b39173783b926f5971c": { + "filename": "Black Sanctum, The (Mark Data Products).zip", + "disk0": "SANCTUM.DSK", + "basic": "LOADM\"SANCTUM\":EXEC\n", + "tv-input": "redblue" + }, + "e06bc3689eda75f78d59e5e97578e656ec2797b9": { + "filename": "Blackjack (Tom Mix Software).zip", + "disk0": "BLAKJAK.DSK", + "basic": "LOADM\"BLAKJAK\":EXEC\n" + }, + "b06d1716470df50030e8c474f0b14115b05d3c81": { + "filename": "Black Sanctum, The (Text) (Mark Data Products).zip", + "disk0": "SANCTUM.DSK", + "basic": "LOADM\"SANCTUM\":EXEC\n" + }, + "7a04ff673b90b5771c14751c32d57bea1e630f0d": { + "filename": "Blak Jak (Cload).zip", + "disk0": "BLAKJAK.DSK", + "basic": "RUN\"BLAKJAK\"\n" + }, + "c56c89c593ea7514d448e5ecae836b137921091a": { + "filename": "Blitz (George Phillips).zip", + "disk0": "BLITZ.DSK", + "basic": "LOADM\"BLITZ\":EXEC\n" + }, + "beb8d0b62b3f142d43a812dc33ca732a5af787bf": { + "filename": "Bleep (CLOAD).zip", + "disk0": "BLEEP.DSK", + "basic": "RUN\"BLEEP\"\n" + }, + "ba704ad28443f0c962a4e63457a54c32fd494f40": { + "filename": "Block Buster (Chromasette).zip", + "disk0": "BLCKBST.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"BLCKBST\"\n" + }, + "930949f4ac27489cf3e44aa38630d4fe984d9ddd": { + "filename": "Blockade (Chromasette).zip", + "disk0": "BLOCKADE.DSK", + "joy-left": "kjoy0", + "basic": "RUN\"BLOCKADE\"\n" + }, + "34442f82ce56fbf0b2566f8bbf38f9e380e91843": { + "filename": "Blockade (J.R. Applegate).zip", + "disk0": "BLOCKADE.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"BLOCKADE\":EXEC\n" + }, + "404e8895e3a7de0a2800af2a5670798c5c831c9b": { + "filename": "Bloc Head (Computerware).zip", + "disk0": "BLOCHEAD.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"BLOCHEAD\":EXEC\n" + }, + "23542a4919dc0efcbf82b825718304d958d830e0": { + "filename": "Blox (Hyper Tech Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "BLOX.DSK", + "basic": "LOADM\"BLOX\":EXEC\n" + }, + "798cdd4fc45741ef2ff108464696b90ae88b1b66": { + "filename": "Bob and the Alien Fireflies (8bitsinthebasement).zip", + "disk0": "CocoBob.dsk", + "joy-left": "kjoy0", + "basic": "LOADM\"COCOBOB\":EXEC\n" + }, + "e74a3298178384807a0c4d5edc8fd55e0f01e0b9": { + "filename": "Body Parts (Elite Software).zip", + "disk0": "BODYPTS.DSK", + "basic": "LOADM\"BODYPTS\":EXEC\n" + }, + "6011f8c0950ec7204f9f00d0ba7510b471aa0465": { + "filename": "Bomber Command (Ark Royal Games).zip", + "disk0": "BOMBER.DSK", + "basic": "RUN\"BOMBER\"\n" + }, + "ef8990d2a68f854ec77fed7dec4b8f3f4414849c": { + "filename": "Bonka (J. Morrison Micros) (Coco Port) (SG-8 intro).zip", + "disk0": "BONKA.DSK", + "basic": "LOADM\"BONKA\":EXEC\n" + }, + "fdf06212c89ff2fa4faef4e7afc1aa3c9c5057c3": { + "filename": "Boris the Bold (Blaby) (Coco port).zip", + "disk0": "BORIS.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"BORIS\":EXEC\n" + }, + "966085882948c57c5e2624b446d910e2c6e42986": { + "filename": "Bouncing Boulders (Diecom Products).zip", + "disk0": "BOULDERS.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"BOULDERS\":EXEC\n", + "tv-input": "redblue" + }, + "522c7be62af43d18b265cd16db2a42c2cbfd9546": { + "filename": "Bowling (A. J. Pomerantz).zip", + "disk0": "BOWL.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"BOWL\"\n" + }, + "3e2220e4ac7b10ae37d16b127180fb2b3d065e36": { + "filename": "Bonk! (Color Software Systems) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "bonk.dsk", + "joy-right": "mjoy0", + "basic": "DOS\n" + }, + "b9b0f93a0e885d1099cb6c580cd219c6ec07efc4": { + "filename": "Box Shoot (Chromasette).zip", + "disk0": "BOXSHOOT.DSK", + "joy-left": "mjoy0", + "joy-right": "kjoy0", + "basic": "LOADM\"BOXSHOOT\":EXEC\n" + }, + "d48b3df5719c6e0600d57019f6b461c1d530c304": { + "filename": "Boxing (Tim Jones).zip", + "disk0": "BOXING.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"BOXING\"\n" + }, + "1da6e454e73146684b80e39391ad8fc00c689872": { + "filename": "Breakthru (Avalon Hill).zip", + "disk0": "BREAKTHR.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"BREAKTHR\":EXEC\n" + }, + "344c9eb5d3f4e10118a822608cce8a63f903cfa0": { + "filename": "Brew Master (Novasoft).zip", + "disk0": "BREW.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"BREW\":EXEC\n" + }, + "e3b987ff0a2fe8f433508775e25fc9270d6c5764": { + "filename": "Brick Pong (T&D Software).zip", + "disk0": "BRIKPONG.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"BRIKPONG\":EXEC\n" + }, + "3915624b547c6ed68fe435511ef13764eabc67ba": { + "filename": "Bridge Tutor (Tandy).zip", + "disk0": "BRIDGE.DSK", + "basic": "LOADM\"BRIDGE\":EXEC\n" + }, + "55a7a0307e89318e4ef2eb4f5114f2e28520814c": { + "filename": "Bubble Buster (T&D Software).zip", + "disk0": "BUBBLE.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"BUBBLE\":EXEC\n" + }, + "b7db692333f8d648fe80d0ca3e78cd2beb68adda": { + "filename": "Buggle (Mystery Glass House Software).zip", + "disk0": "BUGGLE.DSK", + "basic": "RUN\"BUGGLE\"\n" + }, + "c7e51db58afd16c0cd9404fe4968a8c8b9a20d65": { + "filename": "Bugs-II (Four Star Software).zip", + "disk0": "BUGS-II.DSK", + "basic": "LOADM\"BUGS-II\":EXEC\n" + }, + "756e63015ada0a3d5ad5a53f1a3c6d80072ab01c": { + "filename": "Bugs (Color Computer Magazine).zip", + "disk0": "BUGS.DSK", + "basic": "RUN\"BUGS\"\n" + }, + "95ee7fee673eb1e078972cb5b99a52830790a764": { + "filename": "Bumpers (Mark Data Products).zip", + "disk0": "BUMPERS.DSK", + "joy-left": "mjoy0", + "basic": "LOADM\"BUMPERS\":EXEC\n" + }, + "9a5cbeedb8f5c61648906f729297aab10a6a1b64": { + "filename": "Butterfly Patrol (Spectral Associates).zip", + "disk0": "BFPATROL.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"BFPATROL\":EXEC\n" + }, + "4aac210099b77ef2da00c0658cc05b8460c2e132": { + "filename": "Buried Buxx (Jeff Robinson).zip", + "disk0": "BIGBUCKS.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"BIGBUCKS\"\n" + }, + "4691a9ee01983f9d17ff89640a401c525af99d11": { + "filename": "Bustout (Tandy).zip", + "disk0": "BUSTOUT.DSK", + "joy-left": "mjoy0", + "basic": "LOADM\"BUSTOUT\":EXEC\n" + }, + "0607055c0efa0a0323fa0e3dcd61952fb8cc6a8d": { + "filename": "Buzzard Bait (Tom Mix Software).zip", + "disk0": "BUZZARD.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"BUZZARD\":EXEC\n" + }, + "8bb4b6e2424a7bcb4fe063d3dbcc59dcda84b801": { + "filename": "Buzzworm (Tom Mix Software).zip", + "disk0": "BUZZWORM.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"BUZZWORM\":EXEC\n", + "tv-input": "redblue" + }, + "d846c3a1823b93c72d801945aadca8e5fcf3f528": { + "filename": "Caladuril (Diecom Products).zip", + "disk0": "caladuri.dsk", + "basic": "LOADM\"CAL\":EXEC\n" + }, + "fb14ddd3df1bd56114be70265269ede7de4d25f5": { + "filename": "Calixto Island (Text) (Mark Data Products).zip", + "disk0": "CALIXTO.DSK", + "basic": "LOADM\"CALIXTO\":EXEC\n" + }, + "e870598c7eebac95130143f0d12d6f7067bc6bc3": { + "filename": "Camel (Paul Shoemaker).zip", + "disk0": "CAMEL.DSK", + "basic": "LOADM\"CAMEL\":EXEC\n" + }, + "67bf479749edb3e9789df9638aa827b93ff220dc": { + "filename": "Calixto Island (Mark Data Products).zip", + "disk0": "CALIXTO.DSK", + "basic": "LOADM\"CALIXTO\":EXEC\n", + "tv-input": "redblue" + }, + "a8e74f25b9a06bf987486a8113be06c1974a91e8": { + "filename": "Candy Co (Intracolor).zip", + "disk0": "CANDYCO.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"CANDYCO\":EXEC\n", + "tv-input": "redblue" + }, + "fc786aed43d957778c80f02aaf68132940a4e23a": { + "filename": "Canfield (Compute!) (Coco 3).zip", + "machine": "coco3", + "disk0": "CANFIELD.DSK", + "basic": "RUN\"CANFIELD\"\n" + }, + "1504abd07ec5aa59e9cf2017f1defa75dbde8445": { + "filename": "Canyon Climber (Tandy).zip", + "disk0": "CANYON.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CANYON\":EXEC\n" + }, + "3a94c57a6e8569d67b37451fb07b916c2c35a347": { + "filename": "Card King (David A. Mills) (SSC).zip", + "disk0": "CARDKING.DSK", + "basic": "RUN\"CARDKING\"\n" + }, + "b37577c4af549cda98c87c82e6a86373c62e21eb": { + "filename": "Card Games (Tandy).zip", + "disk0": "cards.dsk", + "basic": "DIR\n" + }, + "7873dcc80076ebdd24dac64d104a30f38e125e56": { + "filename": "Cartel (T&D Software).zip", + "disk0": "CARTEL.DSK", + "basic": "RUN\"CARTEL\"\n" + }, + "75774f10736a1e7cf0f2fcafc36cc781b4e49bf4": { + "filename": "Cashman (Computer Shack).zip", + "disk0": "CASHMAN.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"CASHMAN\":EXEC\n", + "tv-input": "redblue" + }, + "9776d4431279476efc18ee9f44487ed4a75d25e4": { + "filename": "Castle Guard (Tandy).zip", + "disk0": "CASTLE.DSK", + "joy-left": "mjoy0", + "basic": "LOADM\"CASTLE\":EXEC\n" + }, + "543cf7565d8eb4faa1dbf353d696a176f72d38a7": { + "filename": "Castle of Tharoggad (Tandy) (Coco 3).zip", + "machine": "coco3", + "disk0": "THAROGAD.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"THAROGAD\":EXEC\n" + }, + "774669e4f30601afed9848c004c475109b420272": { + "filename": "Castle Ragoona (Family Computers).zip", + "disk0": "ragoona.dsk", + "basic": "RUN\"RAGOONA\"\n" + }, + "00ff6ea6b877c2cb3913567876a0bbf6bc024ce2": { + "filename": "Castle Zhagwhar (Keith Schuler).zip", + "disk0": "CASTLE1.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"CASTLE1\"\n" + }, + "750ae97bf51be80e7e7846f6e28ae96a4874a52e": { + "filename": "Castle Thuudo (The Rainbow).zip", + "disk0": "thuudo.dsk", + "basic": "RUN\"THUUDO\"\n", + "tv-input": "redblue" + }, + "eefd25e2f64c592837e3a9f88c19b83989da2282": { + "filename": "Catacombs (L. Miller) (Coco 3).zip", + "machine": "coco3", + "disk0": "CATACOMB.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CATACOMB\":EXEC\n" + }, + "27553a7056ea7018476a8d566814c3c64f353a62": { + "filename": "Catacomb (Oregon Color Computer Systems).zip", + "disk0": "CATACOMB.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CATACOMB\":EXEC\n" + }, + "b995031621a9a310ac545f22518445ceb773d00a": { + "filename": "Catalyst (Computer Shack).zip", + "disk0": "CATALYST.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CATALYST\":EXEC\n" + }, + "42f18561081ea775b93b5f039cd16b7b3ce9708e": { + "filename": "Catch 'em (Aadvark-80).zip", + "disk0": "CATCHEM.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"CATCHEM\":EXEC\n" + }, + "af159c18717c92b5342487963f6944b1d3b3c4e2": { + "filename": "Caterpillar (Aadvark-80).zip", + "disk0": "CATRPILR.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"CATRPILR\":EXEC\n" + }, + "e5a11c83773d8d88bb294916f59f5402d36ad410": { + "filename": "Caterpillar Cave (T&D Software).zip", + "disk0": "CATCAVE.DSK", + "basic": "LOADM\"CATCAVE\":EXEC\n" + }, + "acc1bb1f460dd3b2103ebf159e899df635a47a1b": { + "filename": "Caterpillar (David Crandall).zip", + "disk0": "CATERDAV.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CATERDAV\":EXEC\n" + }, + "91212fc1996ed01b64a24cb1dfc6dbc4f85d46cd": { + "filename": "Cave Fighter (Cable Software) (Coco port).zip", + "disk0": "CAVEFGHT.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CAVEFGHT\":EXEC\n" + }, + "ef2ab3091c8b5edbf52221795541cd74bebc0a8c": { + "filename": "Cave Hunter (Mark Data Products) (SG-24) (Coco 1-2).zip", + "disk0": "HUNTER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"HUNTER\":EXEC\n" + }, + "33f49b7412d801b466a1ecac56c8aabb59072947": { + "filename": "Caverns of Narzod, The (Max Bettridge).zip", + "disk0": "NARZOD.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"NARZOD\"\n" + }, + "999959f61c12cd6bd2ccb22f50f19778d8e9fba5": { + "filename": "Cavehunt (Hot Coco).zip", + "disk0": "CAVEHUNT.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"CAVEHUNT\"\n" + }, + "9b1b540ca0c523c8d11649fc3ac8e787b4af2be1": { + "filename": "Caviator (T&D Software).zip", + "disk0": "caviator.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"CAVIATOR\"\n" + }, + "b62d08eb49f1325e0ca03042e9b1c2e0a184cf4d": { + "filename": "Cave Walker (OS-9) (Tandy).zip", + "disk0": "CAVEWALK.DSK", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "8e0b3ff1b423d954e2986be94698234dd4801fdd": { + "filename": "Caves of the Unwashed Heathen (Bug fixed) (Aaron Oliver).zip", + "machine": "coco3", + "disk0": "Caves (coco 3).dsk", + "basic": "RUN\"HEATHEN\"\n" + }, + "267655a6b6d85f286c04c57ef36de69d2bc106ea": { + "filename": "Caves of the Unwashed Heathen (Bug fixed) (Aaron Oliver).zip", + "machine": "coco3", + "disk0": "Caves (coco 3).dsk", + "basic": "RUN\"HEATHEN\"\n" + }, + "81525ab6d036c32ad0fd764b0e5241bf2b530deb": { + "filename": "Caves of the Unwashed Heathen (Paul Shoemaker).zip", + "disk0": "caves2.dsk", + "basic": "RUN\"HEATHEN\"\n" + }, + "aa9243db907145427b33d383e7ab3b7692c593a9": { + "filename": "Caves of the Unwashed Heathen (Paul Shoemaker).zip", + "disk0": "caves2.dsk", + "basic": "RUN\"HEATHEN\"\n" + }, + "5c76505600a9c2cd37029ccfa0b72a9183ee1c64": { + "filename": "CC Space Trek (Color Computer Magazine).zip", + "disk0": "STREK2.DSK", + "basic": "RUN\"STREK2\"\n" + }, + "0f4dd6687560857ebd1b086e70f95551a42458db": { + "filename": "CC-Thello (Spectral Associates).zip", + "disk0": "CCTHELLO.DSK", + "joy-left": "mjoy0", + "basic": "LOADM\"CCTHELLO\":EXEC\n" + }, + "63ef14df567829caeb28d670d403c011e3df4337": { + "filename": "Chambers (Tom Mix Software).zip", + "disk0": "CHAMBERS.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CHAMBERS\":EXEC\n" + }, + "524c3461649a850aabccce42f03f60ead67328c2": { + "filename": "Chambers (1984) (Tom Mix Software).zip", + "disk0": "CHAMB84.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CHAMBERS\":EXEC\n" + }, + "e9115c1041af0460adabb9d8dcb73c4f32b0571c": { + "filename": "Chatwin Manor (Goldsoft).zip", + "disk0": "Chatwin Manor.dsk", + "basic": "RUN\"START\"\n" + }, + "057fa375c48986eb0fc4756c88b9b35c4647067a": { + "filename": "Champion (Mark Data Products).zip", + "disk0": "champion.dsk", + "joy-right": "mjoy0", + "basic": "LOADM\"BOOT\":EXEC\n" + }, + "b5c833c82a072861776e92504a576cad4ee01528": { + "filename": "C-Hawk Ball (Stephen Macri) (Coco 3).zip", + "machine": "coco3", + "disk0": "CHAWK3.DSK", + "basic": "RUN\"CHAWK3\"\n" + }, + "2b8dfe8561752bea4901bab440a5e6c3f46531a8": { + "filename": "Checker King (PMODE 4) (Tandy).zip", + "disk0": "CHEKRSBW.DSK", + "basic": "LOADM\"CHEKRSBW\":EXEC\n" + }, + "3cb825e87529f629b87e3ebc02bf20de2b1a0392": { + "filename": "Checker King (Tandy).zip", + "disk0": "CHECKERS.DSK", + "basic": "LOADM\"CHECKERS\":EXEC\n" + }, + "7ec16df5096f65454d2b339f4613b371b716473e": { + "filename": "Checkers (Tood Burns).zip", + "disk0": "CHECKERS.DSK", + "basic": "RUN\"CHECKERS\"\n" + }, + "9287876f83d29296b3625e2a5d20b9fb43bbf37c": { + "filename": "Checkers (R. Young).zip", + "disk0": "CHECKR.DSK", + "basic": "RUN\"D\"\n" + }, + "118ab34fb989a1a1d2393afc318bb7eaec4d4166": { + "filename": "ChesSD (Software Dynamics).zip", + "disk0": "CHESSD.DSK", + "basic": "RUN\"CHESS\"\n" + }, + "66362c0b10f2b3905dd31d2c10c602c5e90bd26f": { + "filename": "Chess (R. Young).zip", + "disk0": "CHESSR.DSK", + "basic": "RUN\"CHESS\"\n" + }, + "8ea9e06d3000b45f348491e5c51607fbfc8bc588": { + "filename": "Chess (R. Young).zip", + "disk0": "CHESSR.DSK", + "basic": "RUN\"CHESS\"\n" + }, + "22790f1cd45b9edf792f856dc02ae7a9caf638fb": { + "filename": "Chess Set (Microsoft).zip", + "disk0": "CHESS.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"CHESS\"\n" + }, + "6f6fba697a95e89d04eded5dad3d291fa8d47f17": { + "filename": "Chopper Rescue (Prism Software).zip", + "disk0": "chopper.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"CHOPPER\"\n" + }, + "29d21519d28e5d973731ef8ab81d1a9aabd6f21d": { + "filename": "Chopper Strike (Computer Shack-Michtron).zip", + "disk0": "CHOPPER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CHOPPER\":EXEC\n" + }, + "54bda01fd5c21e4cbb4548780e64c53d52ccd44b": { + "filename": "Christmas Match (Paul Shoemaker).zip", + "machine": "coco3", + "disk0": "XMASMTCH.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"MATCHCC3\":EXEC\n" + }, + "d30afec941d86c7108468287e0c3bcfab8737ab3": { + "filename": "Chuckie Egg (A&F Software) (Coco port).zip", + "disk0": "CHUCKIE.DSK", + "basic": "LOADM\"CHUCKIE\":EXEC\n" + }, + "7992c66adc3a007ba80126d2a64b1ac14713333b": { + "filename": "Citadel of Pershu, The (Tim Hartnell) (Coco 3).zip", + "machine": "coco3", + "disk0": "CITADEL.DSK", + "basic": "RUN\"CITADEL\"\n" + }, + "6e9c506ae57a6ffb47b8de0b7bf16b013b6f3949": { + "filename": "City (T&D Software).zip", + "disk0": "CITY.DSK", + "basic": "LOADM\"CITY\":EXEC\n" + }, + "f8bf822d60e324c3c50150a192538a5d79d9e420": { + "filename": "City War (Prickly-Pear Software).zip", + "disk0": "CITYWAR.DSK", + "basic": "RUN\"CITY WAR\"\n" + }, + "7ea20684579f79f99e75c046213867870243c430": { + "filename": "City Bomber (The Saint John Gallery).zip", + "disk0": "CITYBMBR.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"BOOT\"\n" + }, + "02543cf611c676b300c2f153f3f5f58c19739fe3": { + "filename": "Classic Solitaire (Eversoft Games) (fixed for 1 and 2MB RAM) (Coco 3).zip", + "machine": "coco3", + "disk0": "KLONDIKE.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"BOOT\"\n" + }, + "1d1757a5e629348c0661aec12a851aec3bdbf3f4": { + "filename": "Classic Solitaire (Eversoft Games) (Coco 3).zip", + "machine": "coco3", + "disk0": "KLONDIKE.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"BOOT\"\n" + }, + "7fb8bfc412e3645449ba9a22595672bf6d05db85": { + "filename": "Clickomania! v1.0 (Todd Wallace) (Coco 3).zip", + "machine": "coco3", + "disk0": "click.dsk", + "joy-right": "mjoy0", + "basic": "LOADM\"CLICK\":EXEC\n" + }, + "4a157c64d337c2b431555c5f1310ece47b75afd6": { + "filename": "Cliffhanger (INPUT).zip", + "disk0": "cliffhgr.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"CLIFFHGR\"\n" + }, + "8d55d7b6f7e1e97af07d192ca909fb6f104eb147": { + "filename": "Climb (CLOAD).zip", + "disk0": "climb.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"CLIMB\":EXEC\n" + }, + "b27936cc9a73883db9b84aa48651e40d8fd0ea0d": { + "filename": "Clowns & Balloons (Tandy).zip", + "disk0": "CLOWNS.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"CLOWNS\":EXEC\n" + }, + "2f4fbb0e2e5b567645dcd8bcb0bc06e2e74e471d": { + "filename": "Coco 3 Solitaire (Paul Shoemaker) (Coco 3).zip", + "machine": "coco3", + "disk0": "KLONDKE3.DSK", + "basic": "RUN\"KLONDKE3\"\n" + }, + "c9563213e544681bfcf5191dd800214947eabde8": { + "filename": "CoCo 3-D Rat Maze (Retro Rick).zip", + "disk0": "RATMAZE.DSK", + "basic": "RUN\"RATMAZE\"\n" + }, + "15e24e362f7ecbdd33f1b975a82d954f44c36d23": { + "filename": "Coco 3 Cribbage (Bob van der Poel) (Coco 3).zip", + "machine": "coco3", + "disk0": "CC3CRIB.DSK", + "basic": "RUN\"CRIBBAGE\"\n" + }, + "385bc7fd130eab0ecb35392fa5388b9d57cbcd73": { + "filename": "Coco 3 Video Poker (CoCo Brothers) (Coco 3).zip", + "machine": "coco3", + "disk0": "VIDEOPKR.DSK", + "basic": "RUN\"BOOT\"\n" + }, + "ec7e8c9da2f7c1f45749b3fdae27f98a5a4c22f3": { + "filename": "Coco 3 Yahtzee Game (Keith Morabeto) (Coco 3).zip", + "machine": "coco3", + "disk0": "YAT3.DSK", + "basic": "RUN\"YAT3\"\n" + }, + "10bc7e20a1d8e203029c9cade7c80c2c98dc88d0": { + "filename": "Coco Championship Golf (The Rainbow).zip", + "disk0": "COCOGOLF.DSK", + "basic": "RUN\"COCOGOLF\"\n" + }, + "2d93237bc18a359b42d4a23ffa9a3d38b285a42e": { + "filename": "Coco Craps (Anthony Morris) (Coco 3).zip", + "machine": "coco3", + "disk0": "CRAPS3.DSK", + "basic": "RUN\"CRAPS3\"\n" + }, + "32533789ba4245f14ab374963fc080bf13fdd6f9": { + "filename": "CocoGROW (Jay Searle) (Coco 3).zip", + "machine": "coco3", + "disk0": "COCOGROW.DSK", + "basic": "LOADM\"COCOGROW\":EXEC\n" + }, + "adeb6d3cf5fa104831ea62f879880258af3bb5dc": { + "filename": "COCOdle (Rick Adams) (Coco 3).zip", + "machine": "coco3", + "disk0": "cocole.dsk", + "basic": "RUN\"COCOLE\"\n" + }, + "96155aaa83db3dc43d9d461d4b05a28cde667dc7": { + "filename": "Cocolife (Paul Ripke).zip", + "disk0": "cocolife.dsk", + "basic": "LOADM\"LIFEG1R\":EXEC\n" + }, + "c513d7ed2c9bf83ccb63f03b5264fb208d8be832": { + "filename": "Coco-III Solitaire (The Rainbow) (Coco 3).zip", + "machine": "coco3", + "disk0": "cc3sol.dsk", + "basic": "RUN\"SOLITAIR\"\n" + }, + "3c42873c6e263c8008bf9de301fd4fad02edb121": { + "filename": "Coco-Pong (Chris Pedersen).zip", + "disk0": "PONG.DSK", + "basic": "RUN\"PONG\"\n" + }, + "493110b8be67e8a00a188b677ab3ad7e25c1b079": { + "filename": "Coco-Q (The Rainbow) (Coco 3).zip", + "machine": "coco3", + "disk0": "COCO-Q.DSK", + "basic": "RUN\"COCO-Q\"\n" + }, + "42fe89fe2016d145df52ac0bed9eceabad702fe3": { + "filename": "Coco Miniature Golf (The Rainbow).zip", + "disk0": "MINIGOLF.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"MINIGOLF\"\n" + }, + "248ac9f69593710e47af6ef23e832753fb353112": { + "filename": "CoCo's Bowling Alley (Floyd Keirnan).zip", + "disk0": "BOWLING.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"BOWLING\"\n" + }, + "60f7013dbd6959ab54e759fb35a40cf82002eef0": { + "filename": "Coco Solitaire (Paul Shoemaker).zip", + "disk0": "SOLITARE.DSK", + "basic": "RUN\"SOLITARE\"\n" + }, + "fa588f95896705ff0fbef78af90a5824d3536824": { + "filename": "CoCoStud (CoCo Brothers Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "COCOSTUD.DSK", + "basic": "RUN\"BOOT\"\n" + }, + "c8d87ff447989c867ce781de350f9abb3e07a29c": { + "filename": "Coco-Terrestrial (ET) (T&D Software).zip", + "disk0": "ET.DSK", + "basic": "RUN\"ET\"\n" + }, + "763dabc2c28af742da51b00f56cd0f6d78ab699a": { + "filename": "CoCothello (ColorSystems) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "othello.dsk", + "joy-right": "mjoy0", + "basic": "DOS\n" + }, + "7499d11006f9f056e9876210fde5eeb538b01562": { + "filename": "Coco Yahtzee (Patrick Leabo) (Coco 3).zip", + "machine": "coco3", + "disk0": "YAHTZEE.DSK", + "basic": "RUN\"YAHTZEE\"\n" + }, + "6e9aa0c072327ea9906abfe43ad46d58f147927e": { + "filename": "CoCoYahtzee (ColorSystems) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "yahtzee.dsk", + "joy-right": "mjoy0", + "basic": "DOS\n" + }, + "b5aeb5b1b261e589cef1008275073e2537dafca7": { + "filename": "Color Blackjack (The Rainbow).zip", + "disk0": "BLACKJAC.DSK", + "basic": "RUN\"BLACKJAC\"\n" + }, + "d953e3f13da1d52000e5adad1364230824e0602b": { + "filename": "Coco Zone (The Rainbow).zip", + "disk0": "cocozone.dsk", + "basic": "RUN\"COCOBOOT\"\n" + }, + "26db3afd91fec18f507dfb476c5be27f33658390": { + "filename": "Color Bowl Football (Computerware).zip", + "disk0": "COLRBOWL.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"COLRBOWL\":EXEC\n" + }, + "401a779ebbba18c182bbc33d47bc845b68ada5df": { + "filename": "Color Blast (Challenge Software) (SG-24 intro).zip", + "disk0": "COBLAST.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"COBLAST\":EXEC\n" + }, + "d77609a0ed2011764c3ff32d7ffa498921ec6578": { + "filename": "Color Car Action (Novasoft) (6809 optimized).zip", + "disk0": "CLRCAR68.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"COLORCAR\":EXEC\n" + }, + "1493e8a05431510a2702dc2a49787669821e2d98": { + "filename": "Color Caterpillar (Soft Sector Marketing Inc.).zip", + "disk0": "CATERPIL.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"CATERPIL\":EXEC\n" + }, + "3c31efa3fd1424e1a6881c015454fe47d7ad7640": { + "filename": "Color Computer 3 Karate (Nigel Fredericks) (Coco 3).zip", + "machine": "coco3", + "disk0": "3KARATE.DSK", + "basic": "LOADM\"3KARATE\":EXEC\n" + }, + "670c8f41cdfb4378c0492b462eb3d3fd9f815b1e": { + "filename": "Color Car Action (Novasoft).zip", + "disk0": "COLORCAR.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"COLORCAR\":EXEC\n" + }, + "d03aa2ba90d1524efc946a099a1505b451410e2a": { + "filename": "Color Computer Clue (2018) (LDG Free Software).zip", + "disk0": "CLUE.DSK", + "basic": "RUN\"CLUE\"\n" + }, + "87b530c2da2412826f42a55acaedab4134e47b7f": { + "filename": "Color Computer Clue (LDG Free Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "cc3clue.dsk", + "basic": "RUN\"CC3CLUE\"\n" + }, + "3e0589daec6606aec9a71c4fa0cb86a3fa7fd583": { + "filename": "Color Cubes (Tandy).zip", + "disk0": "CUBES.DSK", + "basic": "LOADM\"CUBES\":EXEC\n" + }, + "19f5cff7e2fb6298ab24db3af7d1ef70d9262d7d": { + "filename": "Color Computer Clue (LDG Free Software).zip", + "disk0": "CLUE.DSK", + "basic": "PCLEAR1:RUN\"CLUE\"\n" + }, + "f9fa7c37699aefb454e803a4a890446b86fda162": { + "filename": "Color Dot (CLOAD Publications Inc.).zip", + "disk0": "COLORDOT.DSK", + "joy-left": "mjoy0", + "joy-right": "mjoy0", + "basic": "RUN\"COLORDOT\"\n" + }, + "675bfbb55eb774bb2ee65a4443d21c4282c0458d": { + "filename": "Color Eights (Pierre Sarrazin).zip", + "disk0": "color8-0.1.12.dsk", + "basic": "RUN\"COLOR8\"\n" + }, + "046a9ea82b334b23c10bafebf66c544a80f06858": { + "filename": "Colordle (Paul Ripke).zip", + "disk0": "colordle.dsk", + "basic": "RUN\"COLORDLE\"\n" + }, + "e3edeb2b85bbde8fbc125daf3be51365ce352a40": { + "filename": "Color Invaders (Computerware).zip", + "disk0": "COLORINV.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"COLORINV\":EXEC\n" + }, + "b18cd57dda5ce787259e0da1a72bc684729f1362": { + "filename": "Color Golf III (Tom Mix Software).zip", + "disk0": "GOLF.DSK", + "basic": "RUN\"GOLF\"\n" + }, + "f65c64dc1ac4daa446a92599fd79863afdaf9b47": { + "filename": "Color Meteroids (Spectral Associates).zip", + "disk0": "METEORS.DSK", + "joy-left": "mjoy0", + "joy-right": "kjoy0", + "basic": "LOADM\"METEORS\":EXEC\n" + }, + "aab545c5160cd66188f0b3ad337ba6044dbd47da": { + "filename": "Color Modem Chess (Double Density Software).zip", + "disk0": "MODCHESS.DSK", + "basic": "RUN\"MODCHESS\"\n" + }, + "e5daf3a86799a8a62217206930c22d1e0a100b67": { + "filename": "Colorout (Spectral Associates).zip", + "disk0": "COLOROUT.DSK", + "basic": "LOADM\"COLOROUT\":EXEC\n" + }, + "1489131a49699ab90393f0e95e06db1ae97a48cf": { + "filename": "Color Panic (Spectral Associate).zip", + "disk0": "CLRPANIC.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CLRPANIC\":EXEC\n" + }, + "546f9e7884ec99db57e4cbc7b8168795b2383423": { + "filename": "Color Planet Invasion 1.1 (Spectral Associates).zip", + "disk0": "INVASION.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"INVASION\":EXEC\n" + }, + "2270b2c7332f524fd4c89ab5d1d38f6438755c9f": { + "filename": "Color Planet Invasion (Spectral Associates).zip", + "disk0": "INVASION.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"INVASION\":EXEC\n" + }, + "ae4fcafc06e0cd72cfbe7727e106fb41286870d0": { + "filename": "Colorpede (Intracolor).zip", + "disk0": "CPEDE.DSK", + "joy-left": "mjoy0", + "basic": "LOADM\"CPEDE\":EXEC\n" + }, + "0372bafeaa0ab93f8445f9a022868fe4e71c0c6f": { + "filename": "Color Poker (The Rainbow).zip", + "disk0": "POKER.DSK", + "basic": "RUN\"POKER\"\n" + }, + "1bb67f6603d74d9dfdf3061d2fca66defc7370a2": { + "filename": "Color Robot Battle (Tandy).zip", + "disk0": "ROBOT.DSK", + "basic": "LOADM\"ROBOT\":EXEC\n" + }, + "c5c3403fb50393e71c4cccecf314761495e20277": { + "filename": "Color Space Invaders (PMODE 4) (Spectral Associates).zip", + "disk0": "NEW-INV.DSK", + "basic": "LOADM\"NEW-INV\":EXEC\n" + }, + "ddf2d3534fb8d88495a7b4988f4229ccb1d0d58b": { + "filename": "Color Space Invaders (Spectral Associates).zip", + "disk0": "INVADERS.DSK", + "basic": "LOADM\"INVADERS\":EXEC\n" + }, + "613ab27851e44276390e0547b6501ad7722e369c": { + "filename": "Color Space Traders (Spectral Associates).zip", + "disk0": "TRADERS.DSK", + "basic": "RUN\"TRADERS\"\n" + }, + "9f96db912be81145de1431f2756385a7f726d2a1": { + "filename": "Color-Trek (Spectral Associates).zip", + "disk0": "TREK.DSK", + "basic": "LOADM\"TREK\":EXEC\n" + }, + "3183d3e3a48c2eae7d6d272acde2ef04829ca95e": { + "filename": "Colorzap (Spectral Associates).zip", + "disk0": "COLORZAP.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"COLORZAP\":EXEC\n" + }, + "19ed5144a6d470b9af7141308635e94ca1676776": { + "filename": "Colossal Cave (CRL) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "colossal.dsk", + "basic": "DOS\n" + }, + "d6eb0dbd327a9cb5fa5b2fa02e07ad3bc75e6ea4": { + "filename": "Company Commander 1.1 (Ark Royal Games).zip", + "disk0": "COMPANY.DSK", + "basic": "RUN\"COMPANY\"\n" + }, + "09830a14fee61fe67514ab58ad357ac4bce15514": { + "filename": "Company Commander 2.0 (Ark Royal Games).zip", + "disk0": "COMPANY2.DSK", + "basic": "RUN\"COMPANY\"\n" + }, + "d78ba6e96326b8cb6c321c1f14bfe49da523dfe0": { + "filename": "Copta Snatch (Blaby Computer Games) (Coco port) (SG-8).zip", + "disk0": "copta.dsk", + "basic": "LOADM\"COPTA\"\n" + }, + "8e1f6403a3ba9c634594e938bd8b94d95f2deaf4": { + "filename": "Concentrate! (Eric A. Wolf) (Coco 3).zip", + "machine": "coco3", + "disk0": "CCTRATE.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"CCTRATE\"\n" + }, + "6944fe58735598cdec5b73083ed6416a05ad01de": { + "filename": "Conflict (Soft Sector Marketing).zip", + "disk0": "conflict.dsk", + "basic": "RUN\"CONFLICT\"\n" + }, + "8d64e6456c3e1215a24eebf01646cd9a01b65320": { + "filename": "Conquering Armies (Mitchell Software).zip", + "disk0": "ARMIES.DSK", + "basic": "RUN\"ARMIES\"\n" + }, + "cd897573a114d99be90dd15d8f4c640eaa49b8d9": { + "filename": "Controllers, The (The Rainbow) (Coco 3).zip", + "machine": "coco3", + "disk0": "CONTROL.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"CONTROL\"\n" + }, + "47bb42937e34a0f4522a2bf6ab8f304beacb8a75": { + "filename": "Cosmic Ambush (Nick Marentes) (Coco 3).zip", + "machine": "coco3", + "disk0": "cambush.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"CAMBUSH\"\n" + }, + "4d36d5cd3fd4103e43021c37d4a4925ecb7aa290": { + "filename": "Cosmic Clones (Mark Data Products).zip", + "disk0": "CLONES.DSK", + "basic": "LOADM\"CLONES\":EXEC\n" + }, + "4f7936e852e3130cef5d549631d1008199bd956f": { + "filename": "Cosmic Cruiser (Imagine) (Coco port).zip", + "disk0": "CRUISER.DSK", + "basic": "LOADM\"CRUISER\":EXEC\n" + }, + "c24a4932878c0c33aa62535a40aa7f2599e9c261": { + "filename": "Cosmic Crusader (Blaby) (Coco port).zip", + "disk0": "CRUSADER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CRUSADER\":EXEC\n" + }, + "e604fbe33d580f83b5540ce00f0a5b86fb43fcfd": { + "filename": "Cosmic Sweeper (T&D Software).zip", + "disk0": "COSMIC.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"COSMIC\":EXEC\n" + }, + "844f44dfd48bf44dedcf8515b9d7e998a91bd287": { + "filename": "Cosmic Superbowl (Spectral Associates).zip", + "disk0": "SUPRBOWL.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SUPRBOWL\":EXEC\n" + }, + "89fe30673be225ef6b8df39314482b875f085745": { + "filename": "Crash (Tom Mix Software).zip", + "disk0": "CRASH.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CRASH\":EXEC\n" + }, + "22a94e8079baf6773faabe98ba694e06b4d13b30": { + "filename": "Crawler (T&D Software).zip", + "disk0": "CRAWLER.DSK", + "basic": "LOADM\"CRAWLER\":EXEC\n" + }, + "b9c003f369775af61f7acda69cbba2bbf26c6cc1": { + "filename": "Crazy 8's (Eversoft Games) (Coco 3).zip", + "machine": "coco3", + "disk0": "CRAZY8S.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"CRAZY8\"\n" + }, + "7f0cdce10bb8f90fd3849f6baa1feb1888682acf": { + "filename": "Creature Feature (Color Software) (SG-24 intro).zip", + "disk0": "CREATURE.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CREATURE\":EXEC\n" + }, + "a2a70382b43fc35a730f2411aa0f24716b812c0f": { + "filename": "Crazy Painter (The Cornsoft Group).zip", + "disk0": "CRAZPNTR.DSK", + "basic": "LOADM\"CRAZPNTR\":EXEC\n" + }, + "2b4711aa9e25a959659cc7daeda61d07131f5a2e": { + "filename": "Cribbage (John Griggs).zip", + "disk0": "CRIBBAGE.DSK", + "basic": "RUN\"CRIBBAGE\"\n" + }, + "eca44ccd9d4bf90c62cddfb99640344fb9f0c2e4": { + "filename": "Croaker (Color Horizon Software).zip", + "disk0": "CROAKER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CROAKER\":EXEC\n" + }, + "adda1266818d1bac5a222c4491b6f6e7287089df": { + "filename": "Croid 2.0 - Eliza (Spectral Associates).zip", + "disk0": "CROID.DSK", + "basic": "LOADM\"CROID\":EXEC\n" + }, + "8140972bc99da4954fddb7e3c500bccb5d03f921": { + "filename": "Crosswords (Tandy).zip", + "disk0": "CROSWORD.DSK", + "basic": "LOADM\"CROSWORD\":EXEC\n" + }, + "3bb04d28769366e778c89aa2735f5a51471219ba": { + "filename": "Croid (Andrew Simpson) (Coco 3).zip", + "machine": "coco3", + "disk0": "croid.dsk", + "basic": "RUN\"CROID\"\n" + }, + "932f4f076e6d53cbe50250ce73ec35074f7f6099": { + "filename": "Crown of Merro, The (Jeff Craig).zip", + "disk0": "MERRO.DSK", + "basic": "RUN\"MERRO\"\n" + }, + "dda92a511cbc13e17a6ee4ebf7d5e3991afd4153": { + "filename": "Crystal Revenge (Owlware).zip", + "disk0": "Crystal Revenge.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"CRYSTAL\"\n" + }, + "30c57acd03e2418a20989143beb2d0d99658053d": { + "filename": "Cuber (PMODE 4) (Tom Mix Software).zip", + "disk0": "CUBER4.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CUBER4\":EXEC\n" + }, + "221c3343ba24f371d1daa9f3479222f979486534": { + "filename": "Crystle Castles (Thundervision).zip", + "disk0": "CRYSTLE.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CRYSTAL\":EXEC\n" + }, + "ec5d12e7047b972908acff161e6b3f78b3cf0794": { + "filename": "Cubix (Spectral Associates).zip", + "disk0": "CUBIX.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CUBIX\":EXEC\n" + }, + "122f731fd9a7d3e09cce798e0567b24de987de72": { + "filename": "Cuber (Tom Mix Software).zip", + "disk0": "CUBER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CUBER\":EXEC\n" + }, + "69452b01e025da7e0cde64eff63ad42706431c58": { + "filename": "Currillian Cruiser (Glenn Calafati).zip", + "disk0": "CRUCRZR.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"START\"\n" + }, + "b56d19f43b525bf69196edac96c3e025663616f8": { + "filename": "Cuthbert and the Golden Chalice (Microdeal).zip", + "disk0": "CHALICE.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CUTHBERT\":EXEC\n" + }, + "1bba7c19f5cbf78e1d615ef6c4a6a8dc74493f9c": { + "filename": "Curse of Crowley Manor, The (Adventure International).zip", + "disk0": "crowley.dsk", + "basic": "LOADM\"CROWLEY\":EXEC\n" + }, + "5d90f2708bc07a34b5a99ee276505711be8ed965": { + "filename": "Cuthbert Goes Digging (Microdeal Cornwall).zip", + "disk0": "CUTHDIG.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CUTHDIG\":EXEC\n" + }, + "aa2a7526f1b97de465604b12be0d41d243ddbf66": { + "filename": "Cuthbert in Space (Tandy).zip", + "disk0": "CUTHSPAC.DSK", + "basic": "LOADM\"CUTHSPAC\":EXEC\n" + }, + "ee89584415ecae2f2d53e6ba3640e5263acc6273": { + "filename": "Cuthbert Goes Walkabout (Tom Mix Software).zip", + "disk0": "CUTHWALK.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CUTHWALK\":EXEC\n" + }, + "94015eb4b11db04c7b6ed6ded413c5f18eeca71b": { + "filename": "Cuthbert in the Cooler (Microdeal Cornwall).zip", + "disk0": "COOLER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"COOLER\":EXEC\n" + }, + "0c158bb6bc83d5c27f2ae44407ddb16b984e1346": { + "filename": "Cuthbert in the Mines (Microdeal Cornwall).zip", + "disk0": "CUTHMINE.DSK", + "basic": "LOADM\"CUTHMINE\":EXEC\n" + }, + "35a9c81ad1a24dbfe9753f6fa22844f27081a206": { + "filename": "Cyber Tank (Mark Data Products).zip", + "disk0": "CYBRTANK.DSK", + "basic": "LOADM\"CYBRTANK\":EXEC\n" + }, + "de33d485f7107e3a43680b1ce15943e4a2e99892": { + "filename": "Cyberwar (Bumblebee Software).zip", + "disk0": "CYBERWAR.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CYBERWAR\":EXEC\n" + }, + "f33636788aff14e365364045db03fb7ebdeccdef": { + "filename": "Cyclops (Romik) (Coco port) (SG-24) (Coco 1-2).zip", + "disk0": "CYCLOPS.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CYCLOPS\":EXEC\n" + }, + "dfabe6eefc3d2c929039fb25347eaa31520a8869": { + "filename": "Cyrus (Tandy).zip", + "disk0": "CYRUS.DSK", + "basic": "LOADM\"CYRUS\":EXEC\n" + }, + "37b6b8c7943fd0f1e6535fa591ca29508fe1bd5c": { + "filename": "Dancing Devil (Tom Mix Software).zip", + "disk0": "DDEVIL.DSK", + "basic": "LOADM\"DDEVIL\":EXEC\n" + }, + "19ed0464f7cfa00c56c89f3326430eb2e9f5303d": { + "filename": "Cyrus Chess (Burke & Burke) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "cyrus.dsk", + "basic": "DOS\n" + }, + "25309ed15416476165801357d55305fd062ae87c": { + "filename": "Cyrus Chess (Burke & Burke) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "cyrus.dsk", + "basic": "DOS\n" + }, + "752196e97b9c8a99c8c8b341cb175bfdf5ca9286": { + "filename": "Danger Ranger (Med Systems, Screenplay).zip", + "disk0": "RANGER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"RANGER\":EXEC\n" + }, + "2434821aab336fc44124f0fca5065f7f12796138": { + "filename": "Dallas Quest, The (Tandy).zip", + "disk0": "DALLAS.DSK", + "basic": "RUN\"DALLAS\"\n" + }, + "fe513715ace8a89fe0abeecddefb9ef3dc0b299e": { + "filename": "Dark Castle (Darin Andersen).zip", + "disk0": "DKCASTLE.DSK", + "basic": "RUN\"DKCASTLE\"\n" + }, + "1cfe593b04cc28dae33d5946c420837f1a0e9544": { + "filename": "Dark Castle Game System (David Lionell Dawson).zip", + "disk0": "DARKCSTL.DSK", + "basic": "RUN\"DARKCAST\"\n" + }, + "bcac6b0219bb5a4fdcba1f8a92bf3f8728ecfe87": { + "filename": "Dark Pit, The (Microdeal Cornwall) (NTSC).zip", + "disk0": "DARKPIT.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"DARKPIT\":EXEC\n" + }, + "9d2d23dc63c59252562726891fca9314681ab5ca": { + "filename": "Dark Pit, The (Microdeal Cornwall) (PAL).zip", + "machine": "coco", + "disk0": "DARKPIT.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"DARKPIT\":EXEC\n" + }, + "1cdf128371a1ed5810a0633c5743eb2f05f9eef1": { + "filename": "Dark Star (Design Design) (NTSC).zip", + "disk0": "DARKSTAR.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"DARKSTAR\"\n" + }, + "6272b308c4c4c47ebf8be11d2024a9ad44ed47c6": { + "filename": "Darkmoor Hold (Prickly-Pear Software).zip", + "disk0": "Darkmoor.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"MBOOT\"\n" + }, + "90e98e2bc2e6074dd4b93931d30c23b0f9009a0e": { + "filename": "Darkmoor Hold (Prickly-Pear Software).zip", + "disk0": "Darkmoor.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"MBOOT\"\n" + }, + "67ab24229e70bb5bda64f8ea421d78ca12defcc9": { + "filename": "Dartboard (Kenneth M. Fine).zip", + "disk0": "DARTS.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"DARTS\"\n" + }, + "f4b5e1b4a16b3f60172051382042b235176ef7a3": { + "filename": "DBreak (Bryan Larsen).zip", + "disk0": "DBREAK.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"DBREAK\":EXEC\n" + }, + "fee6b877ce280f93d2c81422b336d7a500009acd": { + "filename": "Dark Star (Design Design) (PAL).zip", + "machine": "coco", + "disk0": "DARKSTAR.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"DARKSTAR\"\n" + }, + "8c0391873ddb9fea9bbdacd88e73c2753507051e": { + "filename": "Data Fall (T&D Software).zip", + "disk0": "DATAFALL.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"DATAFALL\":EXEC\n" + }, + "bb17ab33917f1e0c360347c7cc7fd02ab801516d": { + "filename": "Deadly Dungeon, The (Sector Software).zip", + "disk0": "DEADLYD.DSK", + "basic": "RUN\"DEADLY D\"\n" + }, + "e34cab9e2605d74b110bce85e4de4e3630d358a3": { + "filename": "Death Trap (Soft Sector Marketing).zip", + "disk0": "DEATH.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"DEATH\":EXEC\n" + }, + "d84de681c66f3c618a08e7bc2ffa33558fd0a06e": { + "filename": "Deathchase (James McKay).zip", + "disk0": "dchs.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"D\"\n" + }, + "aad711adf6c222b51f0938da669469b1358ffbf1": { + "filename": "Death Ship (Aardvark Technical Services).zip", + "disk0": "DSHIP.DSK", + "basic": "RUN\"DSHIP\"\n" + }, + "45030e8081cc321c2fc29f56b535bb937adaf21c": { + "filename": "Decathlon (Spectral Associates).zip", + "disk0": "DECATH.DSK", + "basic": "LOADM\"DECATH\":EXEC\n" + }, + "414d8d6f27ba531db92427fb06e9ffb78e2cc33d": { + "filename": "Decipher (Prickly-Pear Software).zip", + "disk0": "DECIPHER.DSK", + "basic": "LOADM\"DECIPHER\":EXEC\n", + "tv-input": "redblue" + }, + "839d7db61d4f3178b7990302fc291ff2acb7c315": { + "filename": "Defend (T&D Software).zip", + "disk0": "DEFEND.DSK", + "joy-left": "mjoy0", + "basic": "RUN\"DEFEND\"\n" + }, + "2f035ce4b5c5865019511dae22c5a5e3cfcf71ea": { + "filename": "Defender of Castle Darwin (Chris Spry) (Coco 3).zip", + "machine": "coco3", + "disk0": "darwin.dsk", + "joy-right": "mjoy0", + "basic": "RUN\"BOOT\"\n" + }, + "ce84b04430f8ee1924069dc89835c1518f41ad36": { + "filename": "Demolition Derby (Tandy).zip", + "disk0": "DERBY.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"DERBY\":EXEC\n" + }, + "846548fcfe857d61b65e6d17016b90813806ddbf": { + "filename": "Defense (Spectral Associates).zip", + "disk0": "DEFENSE.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"DEFENSE\":EXEC\n" + }, + "bf2b633888dac9d49d0467f027dd7c4a96000021": { + "filename": "Demon Attack (Tandy).zip", + "disk0": "DEMON.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"DEMON\":EXEC\n" + }, + "433370516ceaaeb8e002e087541179b6b50f286e": { + "filename": "Demon Fire (Steven Dufresne).zip", + "disk0": "DEMON.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"DEMON\":EXEC\n" + }, + "0c39769e3dc690a64bc00877b2965d4fad689319": { + "filename": "Demon Seed (Computer Shack-Michtron).zip", + "disk0": "DEMON.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"DEMON\":EXEC\n" + }, + "1df2b380292bca334169c4345b7b35b0ffdc4182": { + "filename": "Deserted Barracks, The (Raleigh Rivers).zip", + "disk0": "BARRACKS.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"BARRACKS\":EXEC\n" + }, + "ea4191022a6b1e27ce969dc5640354ceb7d30877": { + "filename": "Desert Golf (John Zivic).zip", + "disk0": "DESGOLF.DSK", + "basic": "RUN\"LOADER\"\n" + }, + "01830ecda268402d4e147af1a81cb638dea3ea97": { + "filename": "Desert Patrol (Arcade Animation Inc.).zip", + "disk0": "PATROL.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"PATROL\":EXEC\n" + }, + "15dcba1d56e85469466bcf3dce50aa85e93d34bd": { + "filename": "Devil Assault (Tom Mix Software).zip", + "disk0": "DEVIL.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"DEVIL\":EXEC\n" + }, + "da69dfe20523223978fde5356298126662391e2e": { + "filename": "Devious (Spectral Associates).zip", + "disk0": "DEVIOUS.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"DEVIOUS\":EXEC\n" + }, + "7db5bc6ffab7961eac56f25fb759dd90b8bb4f9a": { + "filename": "Destiny (Sean Stuckless) (Coco 3).zip", + "machine": "coco3", + "disk0": "WOF.DSK", + "basic": "RUN\"BOOT\"\n" + }, + "30eb571e169199946d82a896e2a184cc93bf48c9": { + "filename": "Desert Rider (Tandy).zip", + "disk0": "DESERT.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"RIDER\"\n" + }, + "47da358587671bd8eaf357647b567e80b4a427c6": { + "filename": "Desert Rider (Tandy).zip", + "disk0": "DESERT.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"RIDER\"\n" + }, + "420bd91b961c009a4c73d19d5191a11bdca56f15": { + "filename": "Digger (Hyper-Tech Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "DIGGER.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"DIGGER\":EXEC\n" + }, + "927292a69f7f8d2e07f2c620ddb92a2723e48b95": { + "filename": "Dig (T&D Software).zip", + "disk0": "DIG.DSK", + "basic": "LOADM\"DIG\":EXEC\n" + }, + "e945785e72708115182bde394a5fd1bddebab34c": { + "filename": "Digger III Holiday Preview (Chet Simpson & Paul Thayer) (Coco 3).zip", + "machine": "coco3", + "disk0": "D3-V101a.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"D3\":EXEC\n" + }, + "5099a5e88ab6b025ec7d0adaadbba7fb95c2c285": { + "filename": "Dinowars (Tandy).zip", + "disk0": "DINOWARS.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"DINOWARS\":EXEC\n" + }, + "cb4c3f50f525d7867e006b9ed2392ca43ff2488c": { + "filename": "Dodgem (Tino Delbourgo).zip", + "disk0": "DODGEM.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"DODGEM\":EXEC\n" + }, + "582bb6adeb61bbb42033b024731788b33628b1db": { + "filename": "Domination (HAWKSoft) (Coco 3).zip", + "machine": "coco3", + "disk0": "domination.dsk", + "joy-right": "mjoy0", + "basic": "RUN\"DOMINATE\"\n" + }, + "df3329adbe95ed1f520bfd0f63490af3a7a3a4f8": { + "filename": "Dock Master (Diego Barizo).zip", + "disk0": "Dock.dsk", + "basic": "RUN\"DOCK\"\n" + }, + "5e8823d065fb0b893e82bb41a93800341a4e4e1b": { + "filename": "Digger III (HyperTech Gaming) (Coco 3).zip", + "machine": "coco3", + "disk0": "D3RGB.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"D3\":EXEC\n" + }, + "2d8456482b160ec3333c8405f4aee7262328f8bb": { + "filename": "Digger III (HyperTech Gaming) (Coco 3).zip", + "machine": "coco3", + "disk0": "D3RGB.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"D3\":EXEC\n" + }, + "231f49107a03ceca4486ecad03e00b0b4727faa7": { + "filename": "Donkey King (Tom Mix Software).zip", + "disk0": "DONKEY.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"DONKEY\":EXEC\n", + "tv-input": "redblue" + }, + "61f6dcc9192679f3a09313a34994f32131697dc4": { + "filename": "Donkey King XXX Hack (Tom Mix Software).zip", + "disk0": "KINGDONG.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"KINGDONG\":EXEC\n", + "tv-input": "redblue" + }, + "ee1584807eb8f28744e1f1c5fc1031abd80a0548": { + "filename": "Donkey Kong Remixed (John Kowalski) (Coco 3).zip", + "machine": "coco3", + "disk0": "DKRemix.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"DKREMIX\":EXEC\n" + }, + "1c0f9a0fd46fb8bcf857f1393f84f0999adb4ed8": { + "filename": "Don Pan (Tandy).zip", + "disk0": "DONPAN.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"DONPAN\":EXEC\n" + }, + "e9c1ac85150ed14ac81c854df13f6c09fa5b4748": { + "filename": "Donkey Kong Emulator (John Kowalski) (Coco 3).zip", + "machine": "coco3", + "disk0": "DK.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"DONKEY\"\n" + }, + "31782d95653d5f7beeff1ec27112653f4f391de6": { + "filename": "Donut Dilemma Coco 3 Version (Game Point Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "DONUT3.DSK", + "basic": "LOADM\"DONUT3\":EXEC\n" + }, + "78158411976cd576af339f64ee0d75cfb2ad39b2": { + "filename": "Donut Dilemma (Tandy, Game Point Software).zip", + "disk0": "donut.dsk", + "basic": "RUN\"DONUT\"\n" + }, + "cac22b6537f57a11a494d9a93fc5771127e6a9e5": { + "filename": "Double Back (Tandy).zip", + "disk0": "DBLBACK.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"DBLBACK\":EXEC\n" + }, + "8d228d7fd6c3d7bf8927273b271872b642a0b391": { + "filename": "Downland (Tandy).zip", + "disk0": "DOWNLAND.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"DOWNLAND\":EXEC\n" + }, + "0af5e3c8bb53faab6f0e7eb090cf12a98f9e9ba3": { + "filename": "Doodle Bug (Computerware).zip", + "disk0": "DOODLE.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"DOODLE\":EXEC\n" + }, + "65bec8822b8c250400c8b374ef259d5728d9cc09": { + "filename": "Draconian (Tom Mix Software).zip", + "disk0": "DRACO.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"DRACO\":EXEC\n" + }, + "62c294a77fd92172cebfdc5a3a4e0cc10ca02b53": { + "filename": "Dragon Castles (Charles Pelosi).zip", + "machine": "coco3", + "disk0": "dragon.dsk", + "basic": "RUN\"DRAGON\"\n" + }, + "e252a1b948f4238c94fa29bbfa4322d83ad7990d": { + "filename": "Dragon Lord (Australian Coco Magazine).zip", + "disk0": "DRAGLORD.DSK", + "basic": "RUN\"DRAGLORD\"\n" + }, + "cf6ea46f0d56a9bd331c8e671689fdeaa20f3a2b": { + "filename": "Dragon Blade (Prickly-Pear Software).zip", + "disk0": "drgnblde.dsk", + "basic": "LOADM\"BOOT\":EXEC\n" + }, + "c7339b2063a7f8fc76e90616a48abd1602631123": { + "filename": "Dragonfire (PAL 50Hz Coco 2) (Tandy).zip", + "machine": "coco", + "disk0": "DRAGFIR2.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"DRAGFIR2\":EXEC\n" + }, + "95ae06a3110f642673ec6aca9812d2d3d22cd6ff": { + "filename": "Dragons Castle, The (Steven C. Mitchell).zip", + "disk0": "DRAGONCS.DSK", + "basic": "RUN\"DRAGONCS\"\n" + }, + "fb9ddb90b185d5d7d25cd50f98940343e0dd2f76": { + "filename": "Dragon Slayer (Tom Mix Software).zip", + "disk0": "DRAGON.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"DRAGON\":EXEC\n" + }, + "8b8e42844973cb26bf718a9247eea48fc58c108e": { + "filename": "Dragonfire (Tandy).zip", + "disk0": "DRAGFIRE.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"DRAGFIRE\":EXEC\n" + }, + "5ce08508b1abe677f191e0823030b03c8114a904": { + "filename": "Dragon's Temple (Jade).zip", + "disk0": "Dragons Temple.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"GO\"\n" + }, + "9650344e2837e5ea71a7d0b842b7141c32ea84fa": { + "filename": "Drag Race (Stephen Macri) (Coco 3).zip", + "machine": "coco3", + "disk0": "DRAGRACE.DSK", + "basic": "RUN\"DRAGRACE\"\n" + }, + "49916be019e94821199fb7f43cd038c5c4805686": { + "filename": "Draw Poker (Gary James) (Coco 3).zip", + "machine": "coco3", + "disk0": "cc3poker.dsk", + "basic": "RUN\"POKER\"\n" + }, + "250daeac068c41ff04454dc20d4dda6a586dd97a": { + "filename": "Draw Poker (Mike Burton) (Coco 3).zip", + "machine": "coco3", + "disk0": "DRAWPO.DSK", + "basic": "RUN\"DRAWPO\"\n" + }, + "418d0fd78fc44f59d8b9be799e27cd65c2273ac8": { + "filename": "Dragster (Brian M.G.).zip", + "disk0": "DRAGSTER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"DRAGSTER\":EXEC\n" + }, + "c8b9465f0c2f6ef20a03b10cac9a91ace0192a5e": { + "filename": "Draw Poker (T&D Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "POKER3.DSK", + "basic": "RUN\"POKER3\"\n" + }, + "90a00285187fd6e105dc81681d66fdec8867e793": { + "filename": "Draw Poker (T&D Software).zip", + "disk0": "DRAWPOKR.DSK", + "basic": "RUN\"DRAWPOKR\"\n" + }, + "ca73173eddf644c26d587dd11f0ab02ade7626ae": { + "filename": "Draw Poker (Tom Mix Software).zip", + "disk0": "POKER.DSK", + "basic": "LOADM\"POKER\":EXEC\n" + }, + "cd8c7037b1081154411e566e4f6b58dfcf9a83ba": { + "filename": "Droid War (Public Domain).zip", + "disk0": "DROIDWAR.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"DROIDWAR\":EXEC\n" + }, + "2f6a2f85878605d2d1cc30cc525933895c9d3006": { + "filename": "DropPack (T&D Software).zip", + "disk0": "DROP.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"DROP\":EXEC\n" + }, + "7077d3162bdf909bfdc1eb860981e9294ef46d21": { + "filename": "Dr. Who (Prickly-Pear Software).zip", + "machine": "coco3", + "disk0": "DRWHO.DSK", + "basic": "RUN\"RUNME\"\n" + }, + "282063112fe62b7678bab37bd2df4bb89ea9d97e": { + "filename": "Dungeon of Death (Sugar Software).zip", + "disk0": "DUNDEATH.DSK", + "basic": "RUN\"PLAYER\"\n" + }, + "eb699de6444934d60dfb5ced5a5de283a3dd7525": { + "filename": "Dungeon Quest (Computerware) (alt).zip", + "disk0": "DGNQUEST.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"QUEST\"\n" + }, + "b9edbf1e9a2115fb5b64573cdbd593ed1683f81d": { + "filename": "Dungeon Quest (Prickly Pear Software).zip", + "disk0": "DUNQUEST.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"DUNQUEST\":EXEC\n" + }, + "5d33398fce394b6b0c6614ae54a58d145857a940": { + "filename": "Dungeon Raid (Microdeal UK).zip", + "disk0": "DUNGRAID.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"DUNGRAID\":EXEC\n" + }, + "1101bfac2304685ae23280c6d26015286fab6ac3": { + "filename": "Dungeons of Daggorath (Tandy).zip", + "disk0": "DAGGORAT.DSK", + "basic": "LOADM\"DAGGORAT\":EXEC\n" + }, + "a994afe76e98fdd59bf67de6b2b5bd86958158d8": { + "filename": "Dungeons of Daggorath (Shield Fix) (Aaron Oliver).zip", + "disk0": "DagShFix.dsk", + "basic": "RUN\"DAG\"\n" + }, + "aac3850bc704ee3a54178fdd5d50c02c30900aaa": { + "filename": "Dungeons of Despair, The (The Snail).zip", + "machine": "coco3", + "disk0": "DESPAIR.DSK", + "basic": "RUN\"BOOT\"\n" + }, + "063183498fcd5ca6eab1e69c2e007bea8b56c7ce": { + "filename": "Dungeons of Daggorath (Disk Patch) (Tandy).zip", + "disk0": "DAGGDISK.dsk", + "basic": "RUN\"DAGORATH\"\n" + }, + "116d40c58efb476aa8eccc3c86d3399935f73970": { + "filename": "Dungeons of Daggorath (Disk Patch) (Tandy).zip", + "disk0": "DAGGDISK.dsk", + "basic": "RUN\"DAGORATH\"\n" + }, + "dcec5ff1aa1525548d93f8462a9fd4bbf25ac783": { + "filename": "Dunjunz (2017) (Ciaran Anscomb).zip", + "disk0": "Dunjunz (2017) (Ciaran Anscomb).dsk", + "joy-right": "kjoy0", + "basic": "RUN\"DUNJUNZ\"\n", + "tv-input": "redblue" + }, + "efed7bcee9ef5d29d3ab813d3d06bbdf7339bb4c": { + "filename": "Dunjunz (2018) (Teipen Mwnci).zip", + "disk0": "Dunjunz (2018) (Teipen Mwnci).dsk", + "joy-right": "kjoy0", + "basic": "RUN\"DUNJUNZ\"\n", + "tv-input": "redblue" + }, + "d08fbbebe991f31b8b1ca5552a16c3b177ca474a": { + "filename": "Dunkey Monkey (Intellectronics).zip", + "disk0": "DUNKEYM.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"DUNKEYM\":EXEC\n" + }, + "2435173670ed46742300373906dda3503d68dd61": { + "filename": "Duo Deck Solitaire (Eversoft Games) (Coco 3).zip", + "machine": "coco3", + "disk0": "DUO.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"DUO\"\n" + }, + "e052fb73d5ef6e8381974f5c0fc6f9c425b1d39f": { + "filename": "Earth's Foundations, The (Paul Ruby Jr).zip", + "disk0": "FOUNDATE.DSK", + "basic": "RUN\"FOUNDATE\"\n" + }, + "bb473ed0055282284be1bde1c7255b8460891e65": { + "filename": "Eagle Lander (Saguaro Software).zip", + "disk0": "EAGLE.DSK", + "basic": "RUN\"EG\"\n" + }, + "ea49942e4fad404db1db9ee52d457af94a7a9ae0": { + "filename": "East-World Karate (The Saint John Gallery).zip", + "disk0": "karate.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"BOOT\"\n" + }, + "f37ab87699ae39dc0b9443341e08bca4062a072b": { + "filename": "Earthquake 1906 (Adventure International).zip", + "disk0": "earthquake1906.dsk", + "basic": "LOADM\"ERTHQAKE\":EXEC\n" + }, + "1dd08ae69019298d153e31746a766fe9a4e828f3": { + "filename": "Eggs (T&D Software).zip", + "disk0": "EGGS.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"EGGS\"\n", + "tv-input": "redblue" + }, + "5dc61b573f6d2dae1a41cff7e48d9c63e3ebbcfb": { + "filename": "El Bandito (Mark Data Products).zip", + "disk0": "BANDITO.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"BANDITO\":EXEC\n" + }, + "aef27a73458d22d794ca5448d97d80cf3f659f12": { + "filename": "El Diablero (Computerware).zip", + "disk0": "DIABLERO.DSK", + "basic": "LOADM\"DIABLERO\":EXEC\n" + }, + "b58e32ed5b3d93bbbed705e694cf0f2db56357ba": { + "filename": "Electron (Tom Mix Software).zip", + "disk0": "ELECTRON.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ELECTRON\":EXEC\n" + }, + "98157043faf95302f94ccbcaa21fd6ccc4ecef42": { + "filename": "Eliminator (Adventure International).zip", + "disk0": "ELIMNATE.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ELIMNATE\":EXEC\n" + }, + "6e07905a046f05d90e92d8f54e0194d7602de66c": { + "filename": "Empire (Shards Software).zip", + "disk0": "empire.dsk", + "basic": "LOADM\"EMPIRE\":EXEC\n" + }, + "df5301a3808c3949b71d45aa473c5d2684ca16b0": { + "filename": "Eliza (Tandy).zip", + "disk0": "ELIZA.DSK", + "basic": "RUN\"ELIZA\"\n" + }, + "5b3882bfb3398df386a9050a528f90dd0e2d1fb6": { + "filename": "Enchanted Forest, The (Genesis Software).zip", + "disk0": "ENCHANT.DSK", + "basic": "RUN\"ENC-FORT\"\n" + }, + "66ce75c069a17b4c745046ae194504d1e9986435": { + "filename": "Eno (Jarb Software).zip", + "disk0": "eno.dsk", + "basic": "RUN\"ENO\"\n" + }, + "def13421a435dd83515409a0106b35656eac6363": { + "filename": "Entity, The (Mike Snyder) (Coco 3).zip", + "machine": "coco3", + "disk0": "ENTITY.DSK", + "basic": "LOADM\"ENTITY1\":EXEC\n" + }, + "c4d0604b6bd9901645f6c4072e2d3f872fe505c2": { + "filename": "Escape 2012 (Computerware).zip", + "disk0": "ESCAPE2K.DSK", + "basic": "LOADM\"ESCAPE2K\":EXEC\n" + }, + "0b11fe35a678ac923f1eeef9786bd29dfd4663a9": { + "filename": "Erland (Prickly-Pear Software).zip", + "disk0": "ERLAND.DSK", + "basic": "LOADM\"ERLAND\":EXEC\n" + }, + "88daf6c5fc69e03bbe4237826788cc786466f2cd": { + "filename": "Erazor (Tino Delbourgo).zip", + "disk0": "ERAZOR.DSK", + "basic": "LOADM\"ERAZOR\":EXEC\n" + }, + "17c1f49fb48dca88d8d7bb02985e61e179825339": { + "filename": "Escape (Colorsoft Software).zip", + "disk0": "ESCAPE.DSK", + "basic": "LOADM\"ESCAPE\":EXEC\n" + }, + "43c655fbdb17d006ebc03417397d1fb1d95e97fc": { + "filename": "Escape (Matt Hazard).zip", + "disk0": "ESCAPE.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"ESCAPE\"\n" + }, + "1bd696b6a979850500ba9ae3b85b0d1cfad25c11": { + "filename": "Escape From Markessa (D&M Fighting Adventures).zip", + "disk0": "markessa.dsk", + "basic": "RUN\"MARK\"\n" + }, + "bbe64bcb6addeb7e7c8a50d49e94b86deb7af3a7": { + "filename": "Escape From Sparta (The Rainbow).zip", + "disk0": "SPARTA.DSK", + "basic": "RUN\"ESSPARTA\"\n" + }, + "f47a16fe26f334c46c8c7e52694917d31efcf72c": { + "filename": "Escape From SPECTRE (Tom Mix Software).zip", + "disk0": "SPECTRE.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"SPECTRE\"\n" + }, + "d05418b0cf634cc0f74885c93c103a6fa3731482": { + "filename": "Escape From Tut's Tomb (The Rainbow).zip", + "disk0": "ESCTUT.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"TUT1\":EXEC\n" + }, + "1d025714fe585e35c88931df3e36e3a8e87967a8": { + "filename": "Escape (Microdeal Cornwall).zip", + "disk0": "ESCAPE.DSK", + "basic": "LOADM\"ESCAPE\":EXEC\n" + }, + "2b0dc25b2cbde7b84feb5c55c94265769fb4c186": { + "filename": "Escape (T&D Software).zip", + "disk0": "ESCAPE.DSK", + "basic": "LOADM\"ESCAPE\":EXEC\n" + }, + "8a1601e7ce297a7cf891a563afbb29a948ea9f98": { + "filename": "Espionage Island (Owls Nest Software).zip", + "disk0": "ESPIONI.DSK", + "basic": "RUN\"ISLE\"\n" + }, + "c6b9e23c33d7f824a77ea819ed74cbbcdf738b1b": { + "filename": "Euchre (Chroma-Systems Group).zip", + "disk0": "euchre.dsk", + "basic": "RUN\"EUCHRE\"\n", + "tv-input": "redblue" + }, + "bf3c1e6683a645ce63a799019c0ef80cd4ddb024": { + "filename": "Euchre (Mike Pounds) (Coco 3).zip", + "machine": "coco3", + "disk0": "EUCH.DSK", + "basic": "RUN\"EUCH\"\n" + }, + "df992c56fda7e78eb2af7dd0193c3b15b7276d57": { + "filename": "Everest (Derek Sullivan).zip", + "disk0": "everest.dsk", + "basic": "RUN\"EVEREST\"\n" + }, + "687fe2c789b7446653e5de9f23de84433b1d1afd": { + "filename": "Evil Crypt (Curtis Keisler).zip", + "disk0": "EVILCRPT.DSK", + "basic": "RUN\"EVILCRPT\"\n" + }, + "f1ae2c7957e210b944f49a9a3f58c4962f503759": { + "filename": "Eversoft Games Product Catalog (Eversoft Games) (Coco 3).zip", + "machine": "coco3", + "disk0": "EVERSOFT.DSK", + "basic": "RUN\"MENU\"\n" + }, + "b43fc747848812d78cb617d6928b30af91056c1d": { + "filename": "Eye Spy (David Crandall).zip", + "disk0": "EYESPY.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"EYESPY\":EXEC\n" + }, + "148ab9dc6015c5b0de9a0803c69d9987b32cf26e": { + "filename": "Exeter (Tandy) (Coco 3).zip", + "machine": "coco3", + "disk0": "EXETER.DSK", + "basic": "RUN\"EXETER\"\n" + }, + "d7cfb45fc111ccb2102dfdc8497f2b75fdeaab83": { + "filename": "EZ Ski (Chromassette).zip", + "disk0": "EZSKI.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"EZSKI\":EXEC\n" + }, + "88e593b2b1fac3bfdc51d3a400faaa488683505f": { + "filename": "F-15 Ground Assault Simulator (The Rainbow) (Coco 3).zip", + "machine": "coco3", + "disk0": "F15EAGLE.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"F15EAGLE\"\n" + }, + "75ae66ee472c9f7400d14d85ca91197da5adbf5f": { + "filename": "F-16 High Performance Instrument Flight Simulator (Ken Elder-Randy Wright).zip", + "disk0": "F16SIM.DSK", + "joy-left": "kjoy0", + "basic": "RUN\"F16\"\n" + }, + "0ded26233a5af85ad2bcbad130aeadab8e10d434": { + "filename": "Fahrfall (Alpha-3) (John W. Linville).zip", + "disk0": "fahrfall.dsk", + "joy-left": "kjoy0", + "basic": "RUN\"FAHRFALL\"\n" + }, + "82fea4df992a508a0edea2dba024f97453aa88ca": { + "filename": "Fahrfall (Beta 3) (John W. Linville).zip", + "disk0": "fahrfall.dsk", + "joy-left": "kjoy0", + "basic": "RUN\"FAHRFALL\"\n" + }, + "8065110d2158d84e7838def23f41c8def5c8e2d5": { + "filename": "F-16 Assault (Diecom Products) (SSC).zip", + "disk0": "F16.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"F-16\":EXEC\n", + "tv-input": "redblue" + }, + "a53e6ad8689ad71fcac957d3fba14460d2772d1e": { + "filename": "F-16 Assault (Diecom Products) (SSC).zip", + "disk0": "F16.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"F-16\":EXEC\n", + "tv-input": "redblue" + }, + "4704dc9efe79c3b12a66c7ed03376aaea65ed1b7": { + "filename": "Fangman (Tom Mix Software).zip", + "disk0": "FANGMAN.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"FANGMAN\":EXEC\n" + }, + "8dd2fa48f78840c2269ce1b3155f197e5f49c6a9": { + "filename": "Fantasy Gamer's 32K Package (Prickly-Pear Software).zip", + "disk0": "FANTASY.DSK", + "basic": "RUN\"MENU\"\n" + }, + "ee5a679fe3905635b6403d37f28781e6d0d5603e": { + "filename": "Fearless Freddy (Pocket Money Software).zip", + "disk0": "fearless.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"FEARLESS\":EXEC\n" + }, + "aa741beda912617fd2772b1d1ab942a149dc66bc": { + "filename": "Feuer And Gasse (Picosoft).zip", + "disk0": "FIRE&GAS.DSK", + "basic": "PCLEAR1:RUN\"FIRE&GAS\"\n" + }, + "ee7323229ebf64033dd33c26451a4ded91e4d7bb": { + "filename": "Fembot's Revenge (Nelson Software Systems).zip", + "disk0": "FEMBOTS.DSK", + "basic": "LOADM\"FEMBOTS\":EXEC\n" + }, + "f5bd2e5b1a0a5dcff3525dd93b995c0234d9f6fc": { + "filename": "Fighter Pilot (Saguaro Software).zip", + "disk0": "FIGHTER.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"FIGHTER\":EXEC\n" + }, + "5bd54e63ec7f61471c0658f5068147dbfc1970e8": { + "filename": "Final Countdown, The (Bill Cook).zip", + "disk0": "FINALCNT.DSK", + "basic": "RUN\"FINALCNT\"\n" + }, + "ee63ea5665415e6be8d0574478b77a2ad09cdfa1": { + "filename": "Final Frontier, The (Ark Royal Software).zip", + "disk0": "FINALFRN.DSK", + "basic": "RUN\"FRONTIER\"\n" + }, + "1abc3ad0a519ef1115ad8bb98dc1943617e73c6e": { + "filename": "Fireball (M.C. Ironmonger).zip", + "disk0": "fireball.dsk", + "basic": "RUN\"FIREBALL\"\n" + }, + "7e45ceecf7a94d7cea82d31a3a50f07360c435e0": { + "filename": "Firefox (Max Bettridge).zip", + "disk0": "FIREFOX.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"FIREFOX\"\n" + }, + "17b1c67ff5749cefc473dacb152951706cf8e80d": { + "filename": "Fire Force (Quickbeam Software) (Coco port).zip", + "disk0": "FFORCE.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"FFORCE\":EXEC\n" + }, + "45cfcb40040f07ce9b2a6c48cca8318d79906f72": { + "filename": "Fire Copter (Adventure International).zip", + "disk0": "FIRECOPT.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"FIRECOPT\":EXEC\n" + }, + "2d73a8f8c472b91735cbcb2aba735b96373866da": { + "filename": "Fire Runner (T&D Software).zip", + "disk0": "FIRERUNR.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"FIRERUNR\":EXEC\n", + "tv-input": "redblue" + }, + "fec075e119dc5dddfe94b8c4e5b47d2d77967e95": { + "filename": "Flagon Bird (Bosco).zip", + "disk0": "FLAGON.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"FLAGON\":EXEC\n" + }, + "f059a5f0ef1584729184d55dc8bec5efa2a69428": { + "filename": "Fire One (Ark Royal Games) (Coco 3).zip", + "machine": "coco3", + "disk0": "FIREONE.DSK", + "basic": "RUN\"GO\"\n" + }, + "f37726ab3bdfd7f6f5b8b9bd93979cfaefd9c416": { + "filename": "Flight 16 (Tom Mix Software).zip", + "disk0": "flt16.dsk", + "joy-left": "mjoy0", + "basic": "LOADM\"RICH-VA\":LOADM\"FLT16\":EXEC\n" + }, + "e29fcb05c811260a51be8235d2766fd0853999c4": { + "filename": "Flags (Rick's Computer Enterprise) (Coco 3).zip", + "machine": "coco3", + "disk0": "CC3FLAGS.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"M\"\n" + }, + "2394ef33ee3237e99fc7294c62a22ced9706cdfb": { + "filename": "Flight Control (Skipp McKenzie).zip", + "disk0": "FLIGHT.DSK", + "basic": "RUN\"FLIGHT\"\n" + }, + "d1b7a4d05c070af3973c55d6f9f236921917e520": { + "filename": "Flight Sim I (Tandy).zip", + "disk0": "FLTSIM.DSK", + "basic": "LOADM\"FLTSIM\":EXEC\n" + }, + "7b3c3cfb31767983e21d6fc72311e8d89cd2f918": { + "filename": "Flight (Prickly-Pear Software).zip", + "disk0": "Flight Path.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"FLIGHT\"\n" + }, + "3f9d69c7349e9fff04d0bbc73a83740e94af607c": { + "filename": "Flight (Prickly-Pear Software).zip", + "disk0": "Flight Path.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"FLIGHT\"\n" + }, + "4a8dfcff0c94efc2151693a3c69ef869d76426fe": { + "filename": "Flight Simulator (Quark Data).zip", + "disk0": "FLIGHT.DSK", + "basic": "RUN\"FLIGHT\"\n" + }, + "d8e4fa6133b2a032003077ca701ec236e83d55f0": { + "filename": "Flipper (Anteco Software).zip", + "disk0": "FLIPPER.DSK", + "basic": "RUN\"FLIPPER\"\n" + }, + "cccb2c86740fc0e24c753d233e0cc1e3c807505e": { + "filename": "Flight Simulator (T&D Software).zip", + "disk0": "flghtsim.dsk", + "basic": "RUN\"FLGHTSIM\"\n" + }, + "81245e1c69d38dda9bcd072025f233317d184964": { + "filename": "Flippy (T&D Software).zip", + "disk0": "FLIPPY.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"FLIPPY\":EXEC\n", + "tv-input": "redblue" + }, + "bc10580ee093386b5142f046e01263f78e968338": { + "filename": "Fly By (Chromasette).zip", + "disk0": "FLYBY.DSK", + "basic": "LOADM\"FLYBY\":EXEC\n" + }, + "e9a4347d04fefbbea7979c7936b519bd2f61c103": { + "filename": "Flood It! (Evan C. Wright).zip", + "disk0": "FLOODIT.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"FLOODIT\":EXEC\n" + }, + "7f7cedc72c75ffdf2d16d94aaa4af59eca1f93e5": { + "filename": "Fly (Color Computer Magazine).zip", + "disk0": "FLY.DSK", + "basic": "LOADM\"FLY\":EXEC\n" + }, + "2ddf97faf6158af96a134b344498969651e92caf": { + "filename": "Foodwar (Arcade Animation Inc.).zip", + "disk0": "FOODWAR.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"FOODWAR\":EXEC\n" + }, + "f388fe89088a461a2622eab68bc7774d153769bc": { + "filename": "Flying Tigers (Sugar Software).zip", + "disk0": "TIGERS.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"TIGERS\":EXEC\n" + }, + "b5c26cbc6b58b6d4334e0104386b8e2cec01e8a5": { + "filename": "Football (Tandy).zip", + "disk0": "FOOTBALL.DSK", + "joy-left": "kjoy0", + "joy-right": "mjoy0", + "basic": "LOADM\"FOOTBALL\":EXEC\n" + }, + "44ad0b0d9cb86876cff23532aa640c98215b80d3": { + "filename": "Footrace (T&D Software).zip", + "disk0": "FOOTRACE.DSK", + "joy-left": "mjoy0", + "joy-right": "kjoy0", + "basic": "LOADM\"FOOTRACE\":EXEC\n", + "tv-input": "redblue" + }, + "a8fb19aa69f0e981d78856d8e1203c5a30eb8e4b": { + "filename": "Force, The ( Anteco Software).zip", + "disk0": "FORCE.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"FORCE\":EXEC\n" + }, + "881debac08d3fa14398cd3e0589e3d0fcd28c368": { + "filename": "Force Field (T&D Software).zip", + "disk0": "FORCFELD.DSK", + "basic": "LOADM\"FORCFELD\":EXEC\n" + }, + "3f7973a43d1361da599593a9dd0e030d5920a04d": { + "filename": "Forest Adventure (Public Domain).zip", + "disk0": "FOREST.DSK", + "basic": "LOADM\"FOREST\":EXEC\n" + }, + "801fcd6e3f7733975b9925fcc762c929006100ed": { + "filename": "Fortress of Mutant Waffles (T&D Software).zip", + "disk0": "WAFFLES.DSK", + "basic": "LOADM\"WAFFLES\":EXEC\n" + }, + "fe490e3138c3519c248505173360db45b2d55085": { + "filename": "Forgotten Pyramid, The (Chris Schneider).zip", + "disk0": "pyramid.dsk", + "basic": "DOS\n" + }, + "1ccaa66e82473beca21b0317953470d7a06963c5": { + "filename": "Four Cube (Novasoft).zip", + "disk0": "FOURCUBE.DSK", + "basic": "LOADM\"FOURCUBE\":EXEC\n" + }, + "e2c8a3deb65a450e230cf4c64b92322a1bd7a235": { + "filename": "Flight Simulator II (subLOGIC) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Flight Simulator II with scenery files.dsk", + "basic": "DOS\n" + }, + "fae519cef873200b11b88061178efb840a5bb267": { + "filename": "Flight Simulator II (subLOGIC) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Flight Simulator II with scenery files.dsk", + "basic": "DOS\n" + }, + "9a34e7722e857e7c81eff5b3958fc3edb13cf346": { + "filename": "Flight Simulator II (subLOGIC) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Flight Simulator II with scenery files.dsk", + "basic": "DOS\n" + }, + "006c9e74c3eb521a3526282ac79b9c6a6cd0195d": { + "filename": "Flight Simulator II (subLOGIC) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Flight Simulator II with scenery files.dsk", + "basic": "DOS\n" + }, + "0b5951f300bc49e28cf0167b8e127bc9ce73f67c": { + "filename": "Flight Simulator II (subLOGIC) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Flight Simulator II with scenery files.dsk", + "basic": "DOS\n" + }, + "dd7f7132ea631c2f5a56892e3b3c250f5643034b": { + "filename": "Frogday Afternoon (K-Soft) (Coco 3).zip", + "machine": "coco3", + "disk0": "FROGDAY.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"FROGDAY\":EXEC\n" + }, + "6047a8d708f7db7ee0d5f742f56348e8a7504745": { + "filename": "Franchise! (Computerware).zip", + "disk0": "FRANK.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"FRANK\"\n", + "tv-input": "redblue" + }, + "e8adae992158cc1cfbb6328d2c963bb33e7d863b": { + "filename": "Frogger (The Cornsoft Group).zip", + "disk0": "FROGGER.DSK", + "basic": "LOADM\"FROGGER\":EXEC\n" + }, + "4142cae4f087c56a7d7e413e036ffdc3d59021ac": { + "filename": "Froggie (Spectral Associates) (SSC).zip", + "disk0": "FROGGIE.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"FROGGIE\":EXEC\n" + }, + "ec419d80ace180fc95e851e0cff10fe6a37015f7": { + "filename": "Frog Master (Darren Ottery).zip", + "machine": "coco3", + "disk0": "frogmast.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"FROGMAST\"\n" + }, + "b59b74a1cad0938d20cc92722d36f7fd6dfbd52b": { + "filename": "Frog, The (Tom Mix Software).zip", + "disk0": "THEFROG.DSK", + "basic": "LOADM\"THEFROG\":EXEC\n" + }, + "5920c219bf79d4c9be5fd838548d64b1c235b500": { + "filename": "Frog Trek (Oelrich Publications).zip", + "disk0": "FROGTREK.DSK", + "basic": "LOADM\"FROGTREK\":EXEC\n" + }, + "3b352412be3687570209da2bfd5f07e060862cd5": { + "filename": "Fruit Multi-Bars Slot Machine (Tom Mix Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "FRUITBAR.DSK", + "basic": "LOADM\"FRUITBAR\":EXEC\n" + }, + "de366deb5c968f7ad9056e2a19bc5b091a8d427f": { + "filename": "Fury (Computer Shack).zip", + "disk0": "FURY.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"FURY\":EXEC\n" + }, + "d5c72ea012f770384ea5fc258e746e73b890543b": { + "filename": "Furious Felines (Diego Barizo) (Coco 3).zip", + "machine": "coco3", + "disk0": "Furious Felines.dsk", + "basic": "RUN\"FELINES\"\n" + }, + "ff88992aee3fc4ff030430e66c7f66a2e132abeb": { + "filename": "Fyr-Draca (ColorQuest) (SG-24) (Coco 1-2).zip", + "disk0": "FYR-DRAC.DSK", + "basic": "LOADM\"FYR-DRAC\":EXEC\n" + }, + "9f339132ae0edb3197f7328bcb9b2a58270dc744": { + "filename": "Galacticans (Softek).zip", + "disk0": "GALACT.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"GALACT\":EXEC\n" + }, + "8660ae32881bebe197f4b70ef064e8d941ce78c3": { + "filename": "Galactic Attack (Tandy).zip", + "disk0": "GALACTIC.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"GALACTIC\":EXEC\n" + }, + "7ad0ffc1c37c26f4101ce71451ea9d1dae156a2c": { + "filename": "Galactic Conflict (The Rainbow).zip", + "disk0": "conflict.dsk", + "basic": "PCLEAR1:RUN\"GALACTIC\"\n" + }, + "f359e0711b04e6c61f01afc4ca50ba18e5cba902": { + "filename": "Galactic Trek (Color Computer News).zip", + "disk0": "GALTREK.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"GALTREK\"\n" + }, + "584eb006a79725170e259a5e6aad0381f202d4ee": { + "filename": "Galactic Conquest (James West).zip", + "disk0": "CONQUEST.DSK", + "basic": "RUN\"CONQ\"\n" + }, + "678b3560195dea9e23cbee65c956e18af18ae1e6": { + "filename": "Galactic Fighter (Four Star Software).zip", + "disk0": "GFIGHTER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"GFIGHTER\":EXEC\n", + "tv-input": "redblue" + }, + "aeef37e6f6c50d140e18294e233b88f42b193dc9": { + "filename": "Galactic Taipan (Ark Royal Games).zip", + "disk0": "GALTAIPN.DSK", + "basic": "RUN\"TAIPAN\"\n" + }, + "e8f4a5133da1278d7e66f899fc218977bc882aef": { + "filename": "Galactic Hangman (Sugar Software).zip", + "disk0": "GHANGMAN.DSK", + "basic": "RUN\"GHANGMAN\"\n" + }, + "20e22547a11ca7bb860a990e5d8202f2c2c8dcbb": { + "filename": "Galactic Revolution (James West).zip", + "disk0": "REVOLUT.DSK", + "basic": "RUN\"REVOLT\"\n" + }, + "807be18ebd37cce6f33456a7196df1bf572eb7dc": { + "filename": "Galax Attax Enhanced Graphics Edition (Spectral Associates, L. Curtis Boyle).zip", + "disk0": "GALAX3.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"GALAX3\":EXEC\n" + }, + "5360605493cff6f02c068ccb71c72f1ea123326c": { + "filename": "Galagon (Spectral Associates) (SSC).zip", + "disk0": "GALAGONV.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"GALAGONV\":EXEC\n" + }, + "c46e08c02c813d6a5743cd077fd36e8d882498f6": { + "filename": "Galagon (Spectral Associates).zip", + "disk0": "GALAGON.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"GALAGON\":EXEC\n" + }, + "8c8180798bad5457d0dca12a2f6a14c671e8525d": { + "filename": "Galax Attax (Spectral Associates).zip", + "disk0": "GALAX.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"GALAX\":EXEC\n" + }, + "c82e9f5206ecb36801335c5a98879c9c6cac1a42": { + "filename": "Game of Life (Jim Gerrie).zip", + "machine": "coco3", + "disk0": "life.dsk", + "basic": "RUN\"LIFE\"\n" + }, + "2235c54c22f92317491ac0d64da7c9a3916922f2": { + "filename": "Gang Buster (Prickly-Pear Software).zip", + "disk0": "GANGBUST.DSK", + "basic": "RUN\"GANGBUST\"\n" + }, + "20db8846370136647758588c817d6b8e25668caa": { + "filename": "Game of Life (Spectral Associates).zip", + "disk0": "GAMELIFE.DSK", + "basic": "LOADM\"GAMELIFE\":EXEC\n" + }, + "59a454029a4dc283e1a83df441e4f1a18229f589": { + "filename": "Game Point Software Demo Disk #1 (Game Point Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "GPSDEMO.DSK", + "basic": "RUN\"DEMO\"\n" + }, + "db4dc63e15535f2b72b4ac1108b5b2b40fe5919a": { + "filename": "Gantelet (Diecom Products) (SSC).zip", + "disk0": "GANTLET.DSK", + "basic": "LOADM\"GANTLET\":EXEC\n", + "tv-input": "redblue" + }, + "df3f9f392ecf104fde0ad81179c5812aee5190ca": { + "filename": "Gauntlet (Britt Monk, later Avalon Hill).zip", + "disk0": "GAUNTLET.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"GAUNTLET\"\n" + }, + "bd18924aaccec82c736f739a3907a0f379e6f91e": { + "filename": "Gate Crasher Demo (Nick Marentes) (Coco 3).zip", + "machine": "coco3", + "disk0": "GATEDEMO.DSK", + "basic": "RUN\"DEMO\"\n" + }, + "da7eda8d7b0faa767054d324aaffe4bcc2b384d9": { + "filename": "Gems 2 Demo (John Strong) (Coco 3).zip", + "machine": "coco3", + "disk0": "GEM2DEMO.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"GEMS2\"\n" + }, + "e3b720cff847ed13322f60e67ffde8c457f061a8": { + "filename": "Gazon (K&K Computerware).zip", + "disk0": "GAZON.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"GAZON\":EXEC\n" + }, + "4c5e5581a6aba3cc1b0caedd2526ac3dee902983": { + "filename": "Gem Search (T&D Software).zip", + "disk0": "gem.dsk", + "basic": "RUN\"GEMLOAD\"\n" + }, + "6bc76f3fdc2278ee6aef8007ca02a2a7120ad5b6": { + "filename": "Germ Warfare (Chromasette).zip", + "disk0": "GERM.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"GERM\":EXEC\n" + }, + "9d7ef0f6fa32f6e8ad2e6b05d7e29b4fe3cbc310": { + "filename": "Get Me Outta Here! (CoCo Brothers Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "ESCAPE.dsk", + "joy-right": "mjoy0", + "basic": "RUN\"BOOT\"\n" + }, + "22ad70762002598c0cff590d5e7d8a041826d084": { + "filename": "Geo Quiz (Spectral Associates).zip", + "disk0": "GEOQUIZ.dsk", + "basic": "RUN\"ASIA\"\n" + }, + "6df22ea2d508f74bcc840b082e8a7daecdbc5656": { + "filename": "Ghost Busters.zip", + "disk0": "GHOSTBTS.DSK", + "basic": "RUN\"GHOSTBTS\":EXEC\n" + }, + "ab6d607f825f538dcdc3910ca507fb3fc65ffb94": { + "filename": "GFL Championship Football II (Tandy) (Coco 3).zip", + "machine": "coco3", + "disk0": "FOOTBAL2.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"FOOTBAL2\"\n" + }, + "d51419c83914864df8d4e2acd743b11cdbe664d8": { + "filename": "GFL Championship Football II (Tandy) (Coco 3).zip", + "machine": "coco3", + "disk0": "FOOTBAL2.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"FOOTBAL2\"\n" + }, + "0b72e04d94b2a66ff59cfd0bef613e3b52a281d9": { + "filename": "Ghost Gobbler (Spectral Associates).zip", + "disk0": "GHOSTGOB.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"GGOBLR15\":EXEC\n" + }, + "c57a4a5124c8f1e8ed7fa8df054b1500c3d72fe5": { + "filename": "Ghana Bwana (Tandy) (SSC).zip", + "disk0": "Ghana Bwana.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n", + "tv-input": "redblue" + }, + "1e59a178495cb09d5f2e8e35764e1390486d3db8": { + "filename": "Ghana Bwana (Tandy) (SSC).zip", + "disk0": "Ghana Bwana.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n", + "tv-input": "redblue" + }, + "255fbc96fac09f9b02aa93d737a0f3682280cffa": { + "filename": "Ghana Bwana (Tandy) (SSC).zip", + "disk0": "Ghana Bwana.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n", + "tv-input": "redblue" + }, + "7891887d712233369f47876d30525579ba275c35": { + "filename": "Ghost Rush Halloween Edition (Paul Shoemaker).zip", + "disk0": "GHOSTRHW.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"GRHW\":EXEC\n", + "tv-input": "redblue" + }, + "8eed4a1f242f116fa08223ff44d3c9b2a5e55ce2": { + "filename": "Ghost Rush (Paul Shoemaker).zip", + "disk0": "GHSTRUSH.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"GHSTRUSH\":EXEC\n" + }, + "db65327e12e1e5f889fa7e177299f37253303f8b": { + "filename": "Ghost Rush Halloween Edition (Paul Shoemaker) (Coco 3).zip", + "machine": "coco3", + "disk0": "GR16HW.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"GR16HW\":EXEC\n" + }, + "66f129853a788ae2f99728868e03f0e3296aed0f": { + "filename": "Ghost Rush Winter Edition 2022 (Paul Shoemaker).zip", + "disk0": "GRWIN.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"GRWIN\":EXEC\n" + }, + "f5bd62374d65825447f54d3d44f6291614d83000": { + "filename": "Ghost Saga (CoCo Power Software).zip", + "disk0": "g-saga.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"G*SAGA\"\n" + }, + "27828cef43c7d70ed99f75d43e961d9d06d0c1bc": { + "filename": "Ghost Rush v2.0 (Paul Shoemaker).zip", + "disk0": "GHSTRUSH.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"GHSTRUSH\"\n" + }, + "3ff72027812becc8eb66cf875b2d95047c5610fb": { + "filename": "Ghost Rush v2.0 (Paul Shoemaker) (Coco 3).zip", + "machine": "coco3", + "disk0": "GHSTR16.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"GR16\":EXEC\n" + }, + "dca7c52f0b4bef21e6d61350dea6d93c6465a6ef": { + "filename": "Ghost Town (Peter Barella).zip", + "disk0": "ghosts.dsk", + "joy-right": "mjoy0", + "basic": "RUN\"GHOSTS\"\n" + }, + "39f3747b642e655bd0606dd553c33c9d2c5880b4": { + "filename": "Giligan's Island (Coco 3).zip", + "machine": "coco3", + "disk0": "giligan.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"START\"\n" + }, + "f4aaa28e3ed0d6e16ba6f3fe2ced8ec5e27670b3": { + "filename": "Glaxxons (Mark Data Products).zip", + "disk0": "GLAXXONS.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"GLAXXONS\":EXEC\n" + }, + "0172309080ccb780fe4050dcc8630b4651080de7": { + "filename": "Gin Champion (Tandy).zip", + "disk0": "GINCHAMP.DSK", + "basic": "LOADM\"GINCHAMP\":EXEC\n" + }, + "410a7192e523549c845086bd7fea566038d2a1d8": { + "filename": "Gliblibs (T&D Software).zip", + "disk0": "GLIBLIBS.DSK", + "basic": "RUN\"GLIBLIBS\"\n" + }, + "b8877ce15582e8f41bc7d95f8e05b26912bc6a02": { + "filename": "Global Thermonuclear War (T&D Software).zip", + "disk0": "NUCLRWAR.DSK", + "basic": "RUN\"NUCLRWAR\"\n" + }, + "0a736222a94c7f91e7ddf7443f3e1c69136957f8": { + "filename": "Glove (James McKay).zip", + "disk0": "glove.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"G\"\n" + }, + "fe985b17f609ff438aa464af0443f17f1b4be869": { + "filename": "Gobbler (David Crandall).zip", + "disk0": "GOBBLER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"GOBBLER\":EXEC\n" + }, + "8927070f512a61a697c5779021c704ac1e04931d": { + "filename": "Go Fish (Tandy).zip", + "disk0": "GOFISH.DSK", + "basic": "RUN\"GOFISH\"\n" + }, + "702074303e616edf063535a52b5417c6068fd808": { + "filename": "Gold Child (Luis Ricardo Blando).zip", + "machine": "coco3", + "disk0": "The-Gold-Child.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"DRIVER\"\n" + }, + "fac8b83e7d7e6e012a09fd1c34ea0cdea5a7475c": { + "filename": "Gold Finder (Tom Mix Software).zip", + "disk0": "GOLDFIND.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"GOLD\":EXEC\n", + "tv-input": "redblue" + }, + "d4496b08e1f4bbecb35ebac8758b03601eb5516b": { + "filename": "Gold Runner II (Diecom Products) (SSC).zip", + "disk0": "GOLDRUN2.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"GOLDRUN2\":EXEC\n", + "tv-input": "redblue" + }, + "aac617b8db1bf7e6516420b1ea975592351a3827": { + "filename": "Gold Runner (Tom Mix Software) (SSC).zip", + "disk0": "GOLDRUN.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"GOLDRUN\":EXEC\n", + "tv-input": "redblue" + }, + "298d2204a6c32f616658eb52722f120653402ad6": { + "filename": "Gomoku and Renju (Tandy) (SG-12 intro).zip", + "disk0": "GOMOKU.DSK", + "basic": "LOADM\"GOMOKU\":EXEC\n" + }, + "7cc10e6a980a040a9fd02dafc74e1c9502f28b04": { + "filename": "Golf (Aardvark-80).zip", + "disk0": "GOLFAARD.DSK", + "basic": "RUN\"GOLFAARD\"\n" + }, + "2fe38a0f5cde882c49a0cb1b1b0ae644e22db210": { + "filename": "Goop Rush (Paul Shoemaker).zip", + "machine": "coco3", + "disk0": "GOOPRUSH.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"GOOPRUSH\":EXEC\n" + }, + "60c5be4ebda61881487858b20eeab1e02c8259ae": { + "filename": "Gost Ship (Philip Courie).zip", + "disk0": "GOSTSHIP.DSK", + "basic": "RUN\"GOSTSHIP\"\n" + }, + "a9955301b4a4ce90caa070cb9a7b320b2e063f1e": { + "filename": "Gorf-Land (Graftographics) (Coco 3).zip", + "machine": "coco3", + "disk0": "GORFLAND.DSK", + "basic": "RUN\"GORFLAND\"\n" + }, + "98f854b216ea6861c9ed28891e01e923890c96df": { + "filename": "Grabber (Tom Mix Software) (6309 compatible).zip", + "disk0": "GRABBER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"GRABBER\":EXEC\n" + }, + "f7a717741d42b7c78d405c4c5fd91dbbc69a03d9": { + "filename": "Grabber (Tom Mix Software).zip", + "disk0": "GRABBER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"GRABBER\":EXEC\n" + }, + "7f0d3ae38db5caea0ff91c072027af03c3b84a4c": { + "filename": "Grand Prix Challenge (Diecom Products) (Coco 3).zip", + "machine": "coco3", + "disk0": "GRANDPRX.DSK", + "basic": "LOADM\"GRANDPRX\":EXEC\n" + }, + "1b60513e6eef6b318683406d6ed1e86f1b353f51": { + "filename": "Grand Prix (Intracolor).zip", + "disk0": "GRPRIX.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"GRPRIX\":EXEC\n" + }, + "ec5b52f93367a935f8e3217f098e137bd5705ccd": { + "filename": "Grand Slam Bridge (Greentree Software).zip", + "disk0": "BRIDGE.DSK", + "basic": "RUN\"BRIDGE\"\n" + }, + "7d371f46ca610177329eb30a9cedcc7f2803415e": { + "filename": "Graphic Mars (Aardvark Action Software).zip", + "disk0": "MARS.DSK", + "basic": "LOADM\"MARS\":EXEC\n" + }, + "1b3793c78b3d67555d61fee4438764d6388a9bc3": { + "filename": "Graphic Nine Card (T&D Software).zip", + "disk0": "NINECARD.DSK", + "basic": "RUN\"NINECARD\"\n" + }, + "14ef3a90360e157320372823f641b21496cc32df": { + "filename": "Graphic Pyramid (Aardvark-80).zip", + "disk0": "Graphic Pyramid.dsk", + "basic": "LOADM\"PYRAMID\":EXEC\n" + }, + "4129f1a4c198e390b7c7a69d7c2df6d1a97c3538": { + "filename": "Gravitor (William Bond) (alt).zip", + "disk0": "GRAVITOR.DSK", + "basic": "LOADM\"GRAVITOR\":EXEC\n" + }, + "876d045a5104e02335868e352ba613e70ea9113e": { + "filename": "Gravitor (L. Dos Santos).zip", + "disk0": "GRAVITOR.DSK", + "basic": "LOADM\"GRAVITOR\":EXEC\n" + }, + "18addf1d18ec3f878b7b3a9d8a9e6750cccd0eaf": { + "filename": "Gray Lady (Jarb Software).zip", + "disk0": "GRAYLADY.DSK", + "joy-left": "mjoy0", + "basic": "LOADM\"GRAYLADY\":EXEC\n", + "tv-input": "redblue" + }, + "cc92b85b99612a501e5120b8fd4b86c844e02ae1": { + "filename": "Gremlin (Chromasette).zip", + "disk0": "GREMLIN.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"GREMLIN\":EXEC\n" + }, + "3a2bf29b36ec0cc8123f751c176111506396bdac": { + "filename": "Greymoon (Computer Shack).zip", + "disk0": "GREYMOON.DSK", + "basic": "RUN\"GREY\"\n" + }, + "a454f642f480a2bde0ad511f75f0aa1ebf2aaac3": { + "filename": "Grid (Chromasette).zip", + "disk0": "GRID.DSK", + "joy-left": "mjoy0", + "joy-right": "kjoy0", + "basic": "LOADM\"GRID\":EXEC\n" + }, + "8588f2701d87d05244cf9df2a8971527023d9630": { + "filename": "Grid Runner (Salamander Software).zip", + "disk0": "GRIDRUNR.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"GRIDRUNR\":EXEC\n" + }, + "87a809e28e7a87feea78a82370e52bd8fdfaab4d": { + "filename": "Gridiron Strategy (Sportsware) (Coco 3).zip", + "machine": "coco3", + "disk0": "GRIDNFL.DSK", + "basic": "LOADM\"G\":EXEC\n" + }, + "0282a91d6e0e39d4ba81884ac7e61c37a8632d7c": { + "filename": "Gryphon (James Redmon).zip", + "disk0": "GRYPHON.DSK", + "basic": "RUN\"GRYPHON\"\n" + }, + "3515f6edb0d14a7023ad2ecbcd242f2bee4222ca": { + "filename": "Guadalcanal (Ark Royal Games).zip", + "disk0": "guadal.dsk", + "basic": "RUN\"GUADAL\"\n" + }, + "565bd4c36980a4e403ae94de6dca301cb058e1fe": { + "filename": "Guardian (Quasar Animations) (SG-24) (Coco 1-2).zip", + "disk0": "guardian.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"GUARDIAN\":EXEC\n" + }, + "82f6cd1ec5bdbbb2e17ef598bf90d9e291f99aea": { + "filename": "Guess The Animal (Elite Software).zip", + "disk0": "animal.dsk", + "basic": "LOADM\"ANIMAL32\":EXEC\n" + }, + "d29cdad0056947e23741925af599699c8fdd5b41": { + "filename": "Gun Fighter (T&D Software).zip", + "disk0": "GUNFIGHT.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"GUNFIGHT\":EXEC\n", + "tv-input": "redblue" + }, + "3e063309722d6c8c49a5d286fdc6938286f6127d": { + "filename": "Hang Man (Jon Ruhnow) (Coco 3).zip", + "machine": "coco3", + "disk0": "hangman3.dsk", + "basic": "RUN\"HANG\"\n" + }, + "b141444d654325b634b1e60cb9fc6541f25404da": { + "filename": "Hangman (Snailsoft) (Coco 3).zip", + "machine": "coco3", + "disk0": "HANGMAN.DSK", + "basic": "RUN\"HANGMAN\"\n" + }, + "ca7c65623d216387190611e4b3caf0f90e7d7115": { + "filename": "Haunted House (T&D Software).zip", + "disk0": "hauntedh.dsk", + "basic": "RUN\"HAUNTEDH\"\n" + }, + "82e4da2d8986e03f32dd40c101764de9c630367e": { + "filename": "Haunted House - Write your own Adventure Programs for your Microcomputer (Coco 3).zip", + "machine": "coco3", + "disk0": "HAUNTEDH.DSK", + "basic": "RUN\"HAUNTEDH\"\n" + }, + "a7dc8e114d0a692b94d27951ca4187b6bd6f1305": { + "filename": "Haywire (Mark Data Products).zip", + "disk0": "HAYWIRE.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"HAYWIRE\":EXEC\n" + }, + "8ae6c7be18ec1fc8e7b30e6984332bd9a8f7c955": { + "filename": "Head of the Beast (Mark Nelson).zip", + "disk0": "HEAD.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"HEAD\"\n" + }, + "7ea3ef65234c28c47ab0b2416275b36a6e42c196": { + "filename": "Helo Battle (Jarb Software).zip", + "disk0": "HELOBATL.DSK", + "joy-left": "mjoy0", + "joy-right": "kjoy0", + "basic": "RUN\"HELOBATL\"\n" + }, + "5acad24a54d9ed58be4e0b0449c29602ae8359cf": { + "filename": "Heist (Doug Thorsvik).zip", + "disk0": "HEIST.DSK", + "basic": "RUN\"HEIST\"\n" + }, + "88cea842ecc8ab435082428870b24e418667a487": { + "filename": "Hex (D.R. Owen).zip", + "disk0": "HEX.DSK", + "basic": "RUN\"HEX\"\n" + }, + "3f10894561eff28cc5233c9745945b0dc2a6ada4": { + "filename": "Hi-Lo Dice (T&D Software).zip", + "disk0": "HILODICE.DSK", + "basic": "RUN\"HILODICE\"\n" + }, + "78c667b7e19411aa71db780ac6410211af9da673": { + "filename": "Home Base (Cable Software) (Coco Port).zip", + "disk0": "HOMEBASE.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"HOMEBASE\":EXEC\n" + }, + "fdee90681d6b0ef95dbc5fa35ec400330f9e2b81": { + "filename": "Home Bingo (Williams Enterprises).zip", + "disk0": "BINGO.DSK", + "basic": "RUN\"BINGO\"\n" + }, + "c46d1809e248062d8e8c0250219c7ad88b4fa4a9": { + "filename": "Hopbopper (Public Domain).zip", + "disk0": "HOPBOP.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"HOPBOP\":EXEC\n" + }, + "d1d5a58329a48e7bacbf571c29969ad8aa8d05e7": { + "filename": "Horace Goes Skiing (Melbourne House).zip", + "disk0": "HORACESK.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"HORACESK\":EXEC\n" + }, + "5e9eba4d5a6e53ffcd4174bca84ac93e55f4b327": { + "filename": "Hornets (J. Morrison Micros).zip", + "disk0": "hornets.dsk", + "basic": "LOADM\"HORNETS\":EXEC\n" + }, + "60d6e19adc27725183f4c0597e566fdec800b920": { + "filename": "Hot Slot (Moreton Bay Software) (alt).zip", + "disk0": "HOTSLOT.DSK", + "basic": "RUN\"HOTSLOT\"\n" + }, + "48ea8b46a48563e5ae38580b738a5ee7f63b8042": { + "filename": "Hot Slot (Moreton Bay Software).zip", + "disk0": "HOTSLOT.DSK", + "basic": "LOADM\"HOTSLOT\":EXEC\n" + }, + "1e3b55dbdcccd37deed71a2c2586fdf5b2c131fa": { + "filename": "Hyper Zone (Computerware).zip", + "disk0": "HYPRZONE.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"HYPRZONE\":EXEC\n" + }, + "c93fbacaa1a0e68ee8f7fd0e5908e5eee4db44bb": { + "filename": "Hungry Horace (Melbourne House).zip", + "disk0": "HORACE.DSK", + "basic": "LOADM\"HORACE\":EXEC\n" + }, + "dd42a87efce33e95157a412748ee7458c57d79d0": { + "filename": "Ice Hockey (Computerware) (alt).zip", + "disk0": "HOCKEY.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"HOCKEY\":EXEC\n" + }, + "1b1917b4a626e9b3adfed07b61e302257c4fbdde": { + "filename": "Ice Bird (Crystal Software).zip", + "disk0": "ICEBIRD.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ICEBIRD\":EXEC\n" + }, + "c5f578c50654d5e66ce50177a46901828990035e": { + "filename": "Ice Hockey (Computerware).zip", + "disk0": "HOCKEY.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"HOCKEY\":EXEC\n" + }, + "e02e49f1b009e424175ea9f0b633a8bb305ea528": { + "filename": "Ice Master (Arcade Animation Inc.).zip", + "disk0": "ICEMSTR.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ICEMSTR\":EXEC\n" + }, + "08155b35dd8f87ef75e16057896e80ab267ecdd3": { + "filename": "Ice Hockey (Intellectronics).zip", + "disk0": "HOCKEY.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"HOCKEY\":EXEC\n" + }, + "964efda056ffd6e4358c1572f359deb7b7bce9b0": { + "filename": "Iconia (Carlos Eduardo Rocha).zip", + "disk0": "ICONIA.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"ICONIA\"\n" + }, + "0c3c44b569249d80fae1f33181bd3b34c4fc0551": { + "filename": "Icon of Naliphae, The (Adventureware).zip", + "disk0": "NALIPHAE.DSK", + "basic": "RUN\"BOOT\"\n" + }, + "19ca20a96c1a940aba9f8560cea4bdbd6114350b": { + "filename": "Identikit (The Rainbow).zip", + "disk0": "IDENTKIT.DSK", + "basic": "RUN\"IDENTKIT\"\n" + }, + "5b8ef6aa93fe5063c519abdb65cc46da58d2688a": { + "filename": "Impossiball! (Dragonfire Services) (Coco port).zip", + "disk0": "IBALL.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"IBALL\":EXEC\n" + }, + "71adb93a373bf743c281bb89db0063e1bba1a3e6": { + "filename": "Indoor Football (Quickbeam Software) (Coco port).zip", + "disk0": "INDFOOTY.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"INDFOOTY\":EXEC\n" + }, + "c1d7b0a14d28fbc32ca1439bc81b971a270da0f9": { + "filename": "Inspector Clueseau (Petrocci Freelance Associates).zip", + "disk0": "cluseau.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"CLUESEAU\"\n" + }, + "0d19b5aecea48e5d12dfecb8d6919f1b470418b5": { + "filename": "Intercept 4 (Computer Shack-Michtron).zip", + "disk0": "INTERC4.DSK", + "joy-left": "mjoy0", + "basic": "LOADM\"INTERC4\":EXEC\n" + }, + "d595b8eba5435b04efc452020eb78287730d30b4": { + "filename": "Interplanetary Trash Collector (The Rainbow) (Coco 3).zip", + "machine": "coco3", + "disk0": "trash.dsk", + "basic": "RUN\"TRASH\"\n" + }, + "0868dc8d7bebde7de0e5d4e3176a5acf8232c494": { + "filename": "Intersteller Themonuclear War (Coco 3).zip", + "machine": "coco3", + "disk0": "ITW.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"ITW\"\n" + }, + "e7e8d88eca678e6abccc5e5ef3dd087fb3abe4cd": { + "filename": "Invaders09 (Sub-Etha Software) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "INVADE09.DSK", + "joy-left": "kjoy0", + "basic": "DOS\n" + }, + "9827d80e7fb6b825d51764aefe8c4c5b154a9451": { + "filename": "Invader's Revenge (Med Systems-Screenplay).zip", + "disk0": "INVREV.DSK", + "basic": "LOADM\"INVREV\":EXEC\n" + }, + "9203f075cc890903ad7b13c69ff8c2c84e70eaa6": { + "filename": "Invasion (Creative Computing Software).zip", + "disk0": "INVASION.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"INVASION\":EXEC\n" + }, + "68ab8e92204e47f99208446b36cc9c9f02b08fbd": { + "filename": "Iron Cross (Computerware).zip", + "disk0": "ironcros.dsk", + "basic": "RUN\"IRON\"\n", + "tv-input": "redblue" + }, + "228f4c06af2fe2425e23e6062e6faa2fac4959cf": { + "filename": "Island of Dead (Joe Semenik).zip", + "disk0": "ISLAND.DSK", + "basic": "RUN\"ISLAND\"\n" + }, + "200439d2c319b11a42b4f28881093f3389289cd4": { + "filename": "Jackpot Poker (Jack & Pegi Tindle).zip", + "disk0": "JACKPOT.DSK", + "basic": "LOADM\"POKER\":EXEC\n", + "tv-input": "redblue" + }, + "9fc8049756a2952ae33cf1f629d41aed95ee0c5c": { + "filename": "Jaws (Michael Freeman).zip", + "disk0": "JAWS.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"JAWS\":EXEC\n" + }, + "58b534622da1f758940711a7e0c09caa92b4e986": { + "filename": "Jeopardy (T&D Software).zip", + "disk0": "jeopardy.dsk", + "joy-left": "mjoy0", + "joy-right": "mjoy0", + "basic": "RUN\"JEOP\"\n" + }, + "7123efbf733258c1517d1edd6983f3cf64782b09": { + "filename": "Jetpack Challenge (The Rainbow).zip", + "disk0": "JETPACK.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"JETPACK\"\n" + }, + "bdc0f593e64d20fd1a19759d86b04bab604278d7": { + "filename": "Jetset Willy (Software Projects) (Coco port).zip", + "disk0": "JETSET.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"JETSET\":EXEC\n" + }, + "549fb0d4cf554c1d6bd0cd149d37f3185ccf6a82": { + "filename": "Jeweled! (Roger Taylor) (Coco 3).zip", + "machine": "coco3", + "disk0": "jeweled.dsk", + "joy-left": "mjoy0", + "basic": "LOADM\"JEWELED\":EXEC\n" + }, + "dd2e0643d0298b3578fc544ba6af582d932976d4": { + "filename": "Jeweled! (Roger Taylor) (Coco 3).zip", + "machine": "coco3", + "disk0": "jeweled.dsk", + "joy-left": "mjoy0", + "basic": "LOADM\"JEWELED\":EXEC\n" + }, + "87b9afbd05d89a954c0b0a0cf78a8190df48a932": { + "filename": "Joker Poker (Coco 3) (The Rainbow).zip", + "machine": "coco3", + "disk0": "JOKERPKR.DSK", + "basic": "RUN\"JOKERPKR\"\n" + }, + "85ee88a9e95758e5686d77f0bd2b726c132b66d4": { + "filename": "Journey to Mt. Doom (Tom Mix Software).zip", + "disk0": "MTDOOM.DSK", + "basic": "RUN\"DOOM\"\n" + }, + "72b3b88eef1f61cba8d43ed6a828a773c4c703f8": { + "filename": "Joust v1.1 (Glen Hewlett) (Coco 3).zip", + "machine": "coco3", + "disk0": "JOUST.DSK", + "basic": "RUN\"JOUST\"\n" + }, + "4590a5fdbf59ff903a2509c249224ca8a50fd2c7": { + "filename": "Jubilex (GSW Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "jubilex.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"JUBILEX\":EXEC\n" + }, + "8f433958504041d2e794fc00e0318c1a3b9838a9": { + "filename": "Jumbo Jet (aka 747C Flight Simulator 3.6) (Prickly-Pear Software).zip", + "disk0": "JET747.DSK", + "basic": "RUN\"JET747\"\n" + }, + "62f1940161459ad1e3670838bf3357bbbe2d638e": { + "filename": "Jumpship (Alison deNu).zip", + "disk0": "JUMPSHIP.DSK", + "basic": "RUN\"JUMPSHIP\"\n" + }, + "3457bf302ee973f814901d3afd7fac17398fa552": { + "filename": "Jumpy (MatchyGames) (SG-12) (CoCo PSG).zip", + "disk0": "jumpy.dsk", + "basic": "RUN\"JUMPY\"\n" + }, + "b2fceb2860b75c6e54b46601f30df3c117b1db86": { + "filename": "Jungle Queen (Zoso Software).zip", + "disk0": "JUNGLE.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"JUNGLE\":EXEC:LOADM\"JUNGLE2\":EXEC\n" + }, + "318c212875e42755547fd325d088fd7b5fe18f50": { + "filename": "Jungle (T&D Software).zip", + "disk0": "jungle.dsk", + "basic": "RUN\"JUNGLE\"\n" + }, + "cef2ce7dc5f7cbf2b2da8a979870cd82168ea726": { + "filename": "Junior's Revenge (Computerware).zip", + "disk0": "JUNIOR.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"JUNIOR\":EXEC\n", + "tv-input": "redblue" + }, + "e932998ec17309506901c0707042ff74f12d3598": { + "filename": "Junk Food (The Rainbow) (SG-24) (Coco 1-2).zip", + "disk0": "JUNKFOOD.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"JUNKFOOD\":EXEC\n" + }, + "34f718b962527da1b2cc7ca43558070ab2dc314b": { + "filename": "Juno (Federal Hill).zip", + "disk0": "JUNO.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"JUNO\":EXEC\n" + }, + "4965cc882e68a130939bcbf29206bcd651463728": { + "filename": "Jupiter Patrol (Aardvark-80).zip", + "disk0": "JUPATROL.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"JUPATROL\":EXEC\n" + }, + "b40d933fded3d78929ebf8d191a465e557ed372c": { + "filename": "Juxtaposition (Wintersoft) (Coco port).zip", + "disk0": "JUXTA.DSK", + "basic": "LOADM\"JUXTA\":EXEC\n" + }, + "dc6f257ab22a2f39a46ba254f46b810d3188c4a7": { + "filename": "Kamikaze (Ark Royal Games).zip", + "disk0": "K-32.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"K32\"\n" + }, + "d066013154ed730b58cc0d09c779d3f8f96da159": { + "filename": "Karate (Diecom Products).zip", + "disk0": "KARATE.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"KARATE\":EXEC\n", + "tv-input": "redblue" + }, + "6449c16b400f5c3c8c5f9930d64993d73a0bef22": { + "filename": "Katerpillar Attack (Tom Mix Software).zip", + "disk0": "KATERPIL.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"KATERPIL\":EXEC\n" + }, + "ff36bc720439e7e88ef226558d33351ede2b9989": { + "filename": "Kellycheckers III (Dracman) (Coco 3).zip", + "machine": "coco3", + "disk0": "KELLYIII.DSK", + "basic": "RUN\"KELLYIII\"\n" + }, + "f6c10c0d8c247be89be0d5b5392900c1c0898737": { + "filename": "Keys of the Wizard (Spectral Associates) (SSC).zip", + "disk0": "WIZARD.DSK", + "basic": "LOADM\"WIZARD\":EXEC\n" + }, + "7c94c994c656fbaf55b37f2bc8d0346ce043a4c1": { + "filename": "Killer Mansion (T&D Software).zip", + "disk0": "KILLERM.DSK", + "basic": "RUN\"KILLERM\"\n" + }, + "eabcd8c2854ac15b13a4e9c29b8b0d48b1dd1517": { + "filename": "King Carlo (H. Allen Curtis) (Coco 3).zip", + "machine": "coco3", + "disk0": "KC.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"KC\"\n" + }, + "9ed761c8d5fc862be9a9d9e7168239a8f8fa7b2a": { + "filename": "King Cuthbert (Microdeal).zip", + "disk0": "KINGCUTH.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"KINGCUTH\":EXEC\n" + }, + "f1570f72e86f75b132c114e1c7e62e03504d37eb": { + "filename": "Kingdom of Bashan (Owls Nest Software).zip", + "disk0": "BASHAN.DSK", + "basic": "PCLEAR1:RUN\"BASHAN\"\n" + }, + "7c94f756faabaf0a563c6f040053c01db3f9991c": { + "filename": "Kingpede (T&D Software).zip", + "disk0": "KINGPEDE.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"KINGPEDE\":EXEC\n" + }, + "35bfdcda58b5ab83d36195658eac51ea2d3b1425": { + "filename": "King, The (Tom Mix Software).zip", + "disk0": "theking.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"THEKING\":EXEC\n", + "tv-input": "redblue" + }, + "cd2a32929047a1ad81c804eeeb4777b02641e2e3": { + "filename": "King Tut (DSL Computer Products).zip", + "disk0": "KINGTUT.DSK", + "joy-left": "kjoy0", + "basic": "RUN\"KING TUT\"\n" + }, + "74f90b5d43ce3ef35d74bc43373e9ed5c66b931a": { + "filename": "King Tut (Tandy).zip", + "disk0": "KINGTUT.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"KINGTUT\":EXEC\n" + }, + "f05c8d28cc94fba4f435bd17ce22aaebb4bcaf0a": { + "filename": "Klendathu (Tandy).zip", + "disk0": "KLENDATH.DSK", + "basic": "RUN\"KLENDATH\"\n" + }, + "4b99a657df5f77a1ffc4a2b3e49904781d9d5216": { + "filename": "Klondike Solitaire (ColorSystems) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "klondike.dsk", + "joy-right": "mjoy0", + "basic": "DOS\n" + }, + "3f774c1ff9e35650d771779611a9aebf63fe598b": { + "filename": "Komet Kaze (Thomas Czarnecki).zip", + "disk0": "KOMET.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"KOMET\":EXEC\n" + }, + "934af60804f09dbf85de2db91e77fa414e102a73": { + "filename": "Koronis Rift (Epyx) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "KORONIS.DSK", + "joy-left": "mkjoy0", + "basic": "DOS\n" + }, + "400865559a4b4b2904c6288c3fa62c9b6812c39b": { + "filename": "Kosmic Kamikaze (Illustrated Memory Banks).zip", + "disk0": "KOSMIC.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"KOSMIC\"\n" + }, + "81bb8086960adf33951b5f1ea0df3e76a3e687c2": { + "filename": "Kron (Oregon Color Computer Systems).zip", + "disk0": "KRON.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"KRON\":EXEC\n" + }, + "0deb8274818ba320e1a316df5c94cb0f0ac7fd87": { + "filename": "La Belle Lucie (Eversoft Games) (Coco 3).zip", + "machine": "coco3", + "disk0": "lucy.dsk", + "joy-right": "mjoy0", + "basic": "RUN\"START\"\n" + }, + "ac8adb2b3616213995a1194bbb0f871f41c98b58": { + "filename": "Kung-Fu Dude (Sundog Systems).zip", + "disk0": "KUNGFU.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"KUNGFU\":EXEC\n" + }, + "474f8f4bc518e5a523c483d0978356425aa7cb12": { + "filename": "Labyrinth (Aardvark-80).zip", + "disk0": "LABYRINT.DSK", + "basic": "RUN\"LABYRINT\"\n" + }, + "23e8174259797562836bb4e7a94be2952d00151b": { + "filename": "Labyrinth Master (T&D Software).zip", + "disk0": "LABMAS.DSK", + "basic": "LOADM\"LABMAS\":EXEC\n" + }, + "6bf601c06dbc5111445133425eef41ca7be14b83": { + "filename": "Ladderman 2 (Richard Kelly).zip", + "disk0": "LADDER2.DSK", + "basic": "RUN\"LADDER2\"\n", + "tv-input": "redblue" + }, + "1fc4cd8c4acaf510a7e469b6ac14ce973a1ed2de": { + "filename": "Lair of the Kraken, The (Beth Ann Norman).zip", + "disk0": "KRAKEN.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"KRAKEN\"\n" + }, + "58b0670c5a4beb9246efed69f388259ada70e9e1": { + "filename": "Lair, The (Freebooter Software).zip", + "disk0": "THELAIR.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"THELAIR\":EXEC\n" + }, + "982f191100a175cb32c0ac927be1f2440822e1ac": { + "filename": "Lancer (Spectral Associates).zip", + "disk0": "LANCER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"LANCER\":EXEC\n" + }, + "7ed72dbe2d91f18836d9725713b53124fe31db44": { + "filename": "Lady Buggy (David Crandall).zip", + "disk0": "LADYBUG.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"LADYBUG\":EXEC\n" + }, + "9930f099c4f804902339a434a4ac497046c4df25": { + "filename": "Lancer (Cheat) (Spectral Associates).zip", + "disk0": "LANCERTR.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"LANCERTR\":EXEC\n" + }, + "f1a30e3a29a455f9dcab5eb2fa7b3132630a18c1": { + "filename": "Lander (Duane D. Nelson).zip", + "disk0": "LANDER.DSK", + "basic": "LOADM\"LANDER\":EXEC\n" + }, + "692dc3a034b25e206498f799b7732b0284f4e670": { + "filename": "Lander (T&D Software).zip", + "disk0": "LANDER.DSK", + "basic": "LOADM\"LANDER\":EXEC\n" + }, + "09749155a7832a923d674949c90aef2bd4db1c7d": { + "filename": "Laser Blast (Reynold Wells).zip", + "disk0": "LASRBLST.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"LASRBLST\"\n" + }, + "c860da31618ad04c1ec01fa4a19d4236e733f067": { + "filename": "Laser Star (Jarb Software).zip", + "disk0": "LASRSTAR.DSK", + "joy-left": "kjoy0", + "joy-right": "mjoy0", + "basic": "RUN\"LASRSTAR\"\n" + }, + "69e2430585853654040623b8dab1e6f8152afd4e": { + "filename": "Laser Command (formerly Laser Attack) (Spectral Associates).zip", + "disk0": "LASERCMD.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"LASERCMD\"\n" + }, + "079b5ffc05aff1211e63733c9f3bffe1445406a3": { + "filename": "Laser Tank Duel (Renaissance Game Designs).zip", + "disk0": "TANKDUEL.DSK", + "basic": "LOADM\"TANKDUEL\":EXEC\n" + }, + "bdf7e6da37b420c1657f7076219e35ba9b71920c": { + "filename": "Laserworm & Firefly (Electrosoft Inc.).zip", + "disk0": "LASERWRM.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"LASERWRM\"\n" + }, + "15c2ef5533c5632e3f0410d7893bc06b97018c63": { + "filename": "Last Pirate (Tandy).zip", + "disk0": "PIRATE.DSK", + "basic": "RUN\"PIRATE\"\n" + }, + "b97186cb6115617d0ab40fed794b125ef3619dc8": { + "filename": "Lava Hero (Paul Shoemaker).zip", + "machine": "coco3", + "disk0": "LAVAHERO.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"LAVAHERO\":EXEC\n" + }, + "0a6f196d7d6bbcd0c5399a1dd2615ad6deab6243": { + "filename": "L-Berto (Phoenix).zip", + "disk0": "LBERTO.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"LBERTO\"\n" + }, + "f0939276d377e5732608eff46303e7e50490d494": { + "filename": "Leggit (Visual Imagine Software Ltd) (Coco port).zip", + "disk0": "LEGGIT.DSK", + "basic": "RUN\"LEGGIT\"\n" + }, + "d2809bf288481261b1200c6aae125d4aee202b1a": { + "filename": "Legend Quest (D&N Software).zip", + "disk0": "Legend Quest.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"LEGEND\"\n", + "tv-input": "redblue" + }, + "d5e44c2a06d1648351eb51ee314465594499f675": { + "filename": "Liberty Ship (T&D Software).zip", + "disk0": "LIBERTY.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"LIBERTY\":EXEC\n" + }, + "64cf2a10e559df707890b4c93286892a7c65eaa4": { + "filename": "Le Mans (Spectral Associates).zip", + "disk0": "LEMANS.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"LEMANS\":EXEC\n" + }, + "7e5a5e1149d44c5c55a851898e53e75c3ccc421d": { + "filename": "Life (T&D Software).zip", + "disk0": "LIFE.DSK", + "basic": "LOADM\"LIFE\":EXEC\n" + }, + "eb321e2d0eadf63749cf30df3f33f57827a6e315": { + "filename": "Little Runner (The Rainbow).zip", + "disk0": "SMURF.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"SMURF\"\n" + }, + "1fccac8305a1c955983fe1b70710f7531c14306c": { + "filename": "Lode Runner Beta 4.1 (Mark McDougall) (Coco 3).zip", + "machine": "coco3", + "disk0": "lrmono.dsk", + "basic": "RUN\"LR\"\n" + }, + "724bde4aa7a1298bec50f955f3ef575e44952169": { + "filename": "Lode Runner Beta 4.1 (Mark McDougall) (Coco 3).zip", + "machine": "coco3", + "disk0": "lrmono.dsk", + "basic": "RUN\"LR\"\n" + }, + "761cc18d30888650994e215fd4392be5ba15dbb6": { + "filename": "Life An Everyday Adventure (Stephen Berry) (Coco 3).zip", + "machine": "coco3", + "disk0": "LIFE.DSK", + "basic": "RUN\"BOOT\"\n" + }, + "564482df98596d6a96717a9a23ce16d97df15454": { + "filename": "Lokar's Magic Staff (Real Software Company).zip", + "disk0": "LOKAR.DSK", + "basic": "RUN\"LOKARSTF\"\n" + }, + "7207ef058d42182dc697536e1ebaa3e64ae74f0a": { + "filename": "Loopy (T&D Software).zip", + "disk0": "loopy.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"LOOPY\":EXEC\n" + }, + "267f2c801bf82b86f15e1d6bdfa24fb4265412d2": { + "filename": "Lost City, USA (Software Unlimited).zip", + "disk0": "LOSTCITY.DSK", + "basic": "RUN\"LOSTCITY\"\n" + }, + "9d1c1c2229c20389e7cc282516e4d040d70ffa1d": { + "filename": "Lucifer's Kingdom (Orange Software) (Coco Port) (6809 optimized).zip", + "disk0": "LUCIFR68.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"LUCIFER\":EXEC\n" + }, + "b54cc5502854ce98be2d5a8e244330a54ef51974": { + "filename": "Lost Dutchman, The (Marc Steinman) (OS-9).zip", + "disk0": "DUTCHMAN.DSK", + "basic": "DOS\n" + }, + "d5331aacd0b58955dbfa875151184d3076c219d1": { + "filename": "Lunar Lander (Greg Zumwalt).zip", + "disk0": "landergz.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"LANDER\"\n" + }, + "46c5f2e5772590a82fc9edc3f3a51a00cab276cf": { + "filename": "Lunar Lander (Public Domain).zip", + "disk0": "LUNAR.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"LUNAR\":EXEC\n" + }, + "7726806fdfd22f374e5a16d983108e5e00fdf359": { + "filename": "Lunar Lander (The Rainbow) (Coco 3).zip", + "machine": "coco3", + "disk0": "LANDER.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"LANDER\"\n" + }, + "38192e07dd5f5142838be625840053c8b1ff77f5": { + "filename": "Lunar Rescue (Clyde Johnson).zip", + "disk0": "RESCUE.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"RESCUE\"\n" + }, + "6c695525ac0775c6eb5981159a31ee6cba829233": { + "filename": "Lunar-Rover Patrol (Spectral Associates).zip", + "disk0": "ROVER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ROVER\":EXEC\n" + }, + "c477e7a4100e55ae85d2647680a248c916ba5edb": { + "filename": "Lunattack (Hewson Consultants Ltd) (Coco port).zip", + "disk0": "LUNATACK.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"LUNATACK\":EXEC\n" + }, + "b60959f3e8e321bf6cf5946e365b313f139a6566": { + "filename": "Lunchtime (Tom Mix Software).zip", + "disk0": "LUNCH.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"LUNCH\":EXEC\n" + }, + "8a4aaceef18f803ad9fbee162646c1df7597e755": { + "filename": "Lurkley Manor (The Rainbow).zip", + "disk0": "LURKLEY.DSK", + "basic": "RUN\"LURKLEY\"\n" + }, + "665c9f669d98b7805eed6aff91acd107a0cbb759": { + "filename": "Madness and the Minotaur (Tandy).zip", + "disk0": "MINOTAUR.DSK", + "basic": "LOADM\"MINOTAUR\":EXEC\n" + }, + "6647c30d4466d3a5286f8f5e7eb6e91248de9c55": { + "filename": "Madam Rosa's Massage Parlor (Softcore Software Company).zip", + "disk0": "MADAM.DSK", + "basic": "LOADM\"MADAM\":EXEC\n" + }, + "e770725edb1d1b065789010a9d8f99917644ce75": { + "filename": "Lutins du Mont Rigaud, Les (Louis Parson).zip", + "machine": "coco3", + "disk0": "lutins.dsk", + "basic": "RUN\"LELUTIN3\"\n", + "tv-input": "composite" + }, + "72a92d416668abe4edd6e8382cd3addb89babd03": { + "filename": "Magic (Aftamonow & Bernico).zip", + "disk0": "MAGIC.DSK", + "basic": "RUN\"MAGIC\"\n" + }, + "9ea3d5c15b31be51dc1db437ea1a0964c7aa4e0e": { + "filename": "Magic Stones (Floyd Resler) (Coco 3).zip", + "machine": "coco3", + "disk0": "STONES.DSK", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "077039e559f3d1cd92e5acf329c345c21f073550": { + "filename": "Manic Miner (Software Projects) (Coco port).zip", + "disk0": "MANIC.DSK", + "basic": "LOADM\"MANIC\":EXEC\n" + }, + "f2486cd8a176de56d00eb3e02b3fa4cc47e3f051": { + "filename": "Mansion Adventure (CLOAD).zip", + "disk0": "MANSION.DSK", + "basic": "RUN\"MANSION\"\n" + }, + "a31df7866a60786aa6aa1d871cf18391eafea58f": { + "filename": "Marathon (Afabear Software).zip", + "disk0": "MARATHON.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"MARATHON\"\n" + }, + "a1d8951ebb00baad376d86f4314c6e076c2834c3": { + "filename": "Marble Maze (Cheat) (Diecom Products).zip", + "disk0": "MARBLE.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"MARBLE\":EXEC\n" + }, + "60ff43afe0a340764b18e855e28b7d0411482767": { + "filename": "Marble Maze (Diecom Products).zip", + "disk0": "MARBLE.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"MARBLE\":EXEC\n" + }, + "94af98836344927c2d3deada93750833174ea86a": { + "filename": "Major Istar (Computerware).zip", + "disk0": "MISTAR.DSK", + "basic": "LOADM\"MISTAR\":EXEC\n", + "tv-input": "redblue" + }, + "f5a70f7c4b4ed58ef0454263146657420f292cf3": { + "filename": "Major Istar (Computerware).zip", + "disk0": "MISTAR.DSK", + "basic": "LOADM\"MISTAR\":EXEC\n", + "tv-input": "redblue" + }, + "6ad6412cfceff3cb542e58fcbf2c218250786dc0": { + "filename": "Major Istar (Computerware).zip", + "disk0": "MISTAR.DSK", + "basic": "LOADM\"MISTAR\":EXEC\n", + "tv-input": "redblue" + }, + "28cd16d2cd17e445688b67e00b2b1ad6c66c40fa": { + "filename": "Major Istar (Computerware).zip", + "disk0": "MISTAR.DSK", + "basic": "LOADM\"MISTAR\":EXEC\n", + "tv-input": "redblue" + }, + "99cc4921365ec4a5f41b8f64ac700b19786f7033": { + "filename": "Marooned (Saguaro Software).zip", + "disk0": "MAROONED.DSK", + "basic": "RUN\"MAROONED\"\n", + "tv-input": "redblue" + }, + "020ad9469bf4eb535c7ebb0a1f189e00f6b9c213": { + "filename": "Mars (Aardvark-80).zip", + "disk0": "mars.dsk", + "basic": "RUN\"MARS\"\n" + }, + "5aed1f751961928f4a148ee7a27f058e70ee61af": { + "filename": "Martian Crypt, The (Tom Mix Software) (SSC).zip", + "disk0": "MARTIAN.DSK", + "basic": "LOADM\"MARTIAN\":EXEC\n", + "tv-input": "redblue" + }, + "9594436ea0e5000b83374fc3be57899b9165831d": { + "filename": "Mary and the Bees (Roger Taylor) (Coco 3).zip", + "machine": "coco3", + "disk0": "MARYATB.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MARYATB\":EXEC\n" + }, + "cfcfb7f5307e5b410ce8f126534eee5e812e31cc": { + "filename": "Mary and the Butterflies Demo (Royer Taylor) (Coco 3).zip", + "machine": "coco3", + "disk0": "marydemo.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"MARYATB\":EXEC\n" + }, + "6f722c6827d980f7888acce3357c0979c6f50597": { + "filename": "Master Blaster (Ken Kalish).zip", + "disk0": "mblaster.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"MBLASTER\":EXEC\n" + }, + "5c4c0c8f132906a223b0272581deebbd61bf5427": { + "filename": "Master Handicapper (LNW Systems).zip", + "disk0": "MSTRHNDC.DSK", + "basic": "RUN\"FOOTBALL\"\n" + }, + "a76e46a80f4d4e50643814544eb91b26a9b94794": { + "filename": "Mastermind (Kim Bergman) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "masmind.dsk", + "basic": "DOS\n" + }, + "8b86cba40d529ab53e2d62bdbce0639eec35d12d": { + "filename": "Master the Cube! (ColorSystems) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "cubist.dsk", + "joy-right": "mjoy0", + "basic": "DOS\n" + }, + "d0815331413bd16e45704cc8d2a2b60570ea1094": { + "filename": "Match Game of Opposites (The Rainbow).zip", + "disk0": "MATCH.DSK", + "basic": "RUN\"MATCH1\"\n" + }, + "81a9c0b9a09e233c10b1017fc9c67b302a92ccc2": { + "filename": "Maui Vice (Tom Mix Software).zip", + "disk0": "MAUI.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"MAUI\":EXEC\n", + "tv-input": "redblue" + }, + "1dc9575925d78eb8f10b2c0cb6464534c43223cf": { + "filename": "Maximum (CLOAD).zip", + "disk0": "MAXIMUM.DSK", + "joy-left": "mjoy0", + "basic": "RUN\"MAXIMUM\"\n" + }, + "4b576e16e82ee6a64aefafa15d58526b65634ee8": { + "filename": "Maze, The (Chromasette).zip", + "disk0": "THEMAZE.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"MAZE\"\n" + }, + "f0966726bad5999b279091aab92a5b69977fe811": { + "filename": "Maze Escape (Spectral Associates).zip", + "disk0": "escape.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"ESCAPE\"\n" + }, + "303e39d80f5ace47d87e6255e6fcdf6ddd521035": { + "filename": "Maze Creator v1.00 (Retro Rick).zip", + "disk0": "MAZCREAT.DSK", + "basic": "RUN\"MAZE-GR\"\n" + }, + "6213aea719bd3487f8970a7afad14e7412d267bd": { + "filename": "Marty's Nightmare (SRB Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "Marty's Nightmare (SRB Software) (Coco 3)/marty.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "ad405a3bfb87630bc7fa3f8c519c0c5278ca0514": { + "filename": "Marty's Nightmare (SRB Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "Marty's Nightmare (SRB Software) (Coco 3)/marty.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "95b17b514cbd7cd38f53e72ad23df298f67e23ea": { + "filename": "Marty's Nightmare (SRB Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "Marty's Nightmare (SRB Software) (Coco 3)/marty.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "c9aebd7db1050d328b1580a23f4efd615725927b": { + "filename": "Marty's Nightmare (SRB Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "Marty's Nightmare (SRB Software) (Coco 3)/marty.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "608202d5181096d42e090c6d42de4d92933af272": { + "filename": "Marty's Nightmare (SRB Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "Marty's Nightmare (SRB Software) (Coco 3)/marty.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "a4766f752c792c992661639c2e4ccb30fd4dac29": { + "filename": "Marty's Nightmare (SRB Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "Marty's Nightmare (SRB Software) (Coco 3)/marty.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "6adbd33b6d5ad26c8fbfb82f93995d2a3c235c24": { + "filename": "Maze Land (Chromasette).zip", + "disk0": "MAZELAND.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"RMAZE-GR\"\n" + }, + "8f547e5a0c2408ec3627fd67f396b6ee8550e1ef": { + "filename": "Maze Maker v3.0 (Retro Rick).zip", + "disk0": "MAZMAK30.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"RMAZE-GR\"\n" + }, + "2cf88332c44f5b8485873d234cdb4c3b79189015": { + "filename": "Maze Maker v4.0 (Retro Rick).zip", + "disk0": "MAZMAK40.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"RMAZE-GR\"\n" + }, + "e3b14eb103ffe22ded15a20506ffff362268f612": { + "filename": "Maze Master (Dough Tuttle) (Coco 3).zip", + "machine": "coco3", + "disk0": "MMASTER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MMASTER\":EXEC\n" + }, + "19d14f1eeca4636151f99f5f39c827e3a56ccc3c": { + "filename": "Maze Race (Tom Mix Software).zip", + "disk0": "MAZERACE.DSK", + "joy-left": "mjoy0", + "joy-right": "kjoy0", + "basic": "RUN\"MAZERACE\"\n" + }, + "4e3393f17af9cce9b5d8f3f9042be7cd89b145a8": { + "filename": "Mazes, The (Infotop).zip", + "disk0": "THEMAZES.DSK", + "basic": "RUN\"THE MAZE\"\n" + }, + "243b638e7e0c045c2b4157338270e6b6aec96d8c": { + "filename": "Maze, The (Colin North) (Coco 3).zip", + "machine": "coco3", + "disk0": "CRYSTAL3.DSK", + "basic": "RUN\"CRYSTAL3\"\n" + }, + "f1101cbe2e08bb53270aa0b6455b6f587fb82f0e": { + "filename": "Mazey (T&D Software).zip", + "disk0": "MAZEY.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"MAZEY\"\n" + }, + "fb768b2f92ac3f80c74e5fefd13cf583d45520f0": { + "filename": "McCheckers (Greg Miller & Erik Gavriluk).zip", + "disk0": "MCCHECK.DSK", + "basic": "LOADM\"MCCHECK\":EXEC\n" + }, + "dc224dcf1c888f69e5c3a3a7373a6abdbdf0a09e": { + "filename": "Megabug (Tandy).zip", + "disk0": "MEGABUG.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MEGABUG\":EXEC\n" + }, + "45ad19f87ae2759e28885630c9be05c0b06da02d": { + "filename": "Megamunk (Color Connection Software).zip", + "disk0": "MEGAMUNK.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MEGAMUNK\":EXEC\n" + }, + "a29ef0c79e8ad2af56ae17ffe5edef92e8685f90": { + "filename": "Megapede (Computerware).zip", + "disk0": "MEGAPEDE.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MEGAPEDE\":EXEC\n" + }, + "a4cddc31005d86182437137c1dc19ae2b6a12fe3": { + "filename": "Mega Shield (Winefred Washington Jr.).zip", + "disk0": "MEGASHLD.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MEGASHLD\":EXEC\n" + }, + "f3a6b7919dd716866bf8a5772ac3a9956b16d36a": { + "filename": "Mega Tank (The Rainbow) (Coco 3).zip", + "machine": "coco3", + "disk0": "MEGATANK.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"MEGATANK\"\n" + }, + "bdc883afd99ad0006ec2f43c8becc89f743af53e": { + "filename": "Memory Game, The (RAM Electronics 1988) (Coco 3).zip", + "machine": "coco3", + "disk0": "MEMORY.DSK", + "basic": "RUN\"MEMORY\"\n" + }, + "b105d2b84288a7d9e0ba4aeda52da701af918258": { + "filename": "Mercenary Force (GOSUB International).zip", + "disk0": "MERCFORC.DSK", + "basic": "RUN\"MERCFORC\"\n" + }, + "81717c7d4ebdecd2049c41f6fbc2af8f3975cb6d": { + "filename": "Merchant to the Stars (Larry M. Paroubek) (Coco 3).zip", + "machine": "coco3", + "disk0": "STARMERC.DSK", + "basic": "RUN\"STARS\"\n" + }, + "f9de1bb9e14d8efb7cf46feaf085c19431cd2ee4": { + "filename": "Microbes (Tandy).zip", + "disk0": "MICROBES.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MICROBES\":EXEC\n" + }, + "be25a9b89b5d9df348edfa78468e2211c655c04f": { + "filename": "Micro Chess (Tandy).zip", + "disk0": "CHESS.DSK", + "basic": "LOADM\"CHESS\":EXEC\n" + }, + "e1f820a09b8cfdceb8c128edd3bd86b84eca6e99": { + "filename": "Micro Chess (PMODE 4) (Tandy).zip", + "disk0": "CHESSBW.DSK", + "basic": "LOADM\"CHESSBW\":EXEC\n" + }, + "e8affc2b71adccb0be44d206141693d47835df40": { + "filename": "Middle Kingdom (Computerware).zip", + "disk0": "KINGDOM.DSK", + "basic": "LOADM\"KINGDOM\":EXEC\n" + }, + "229c67da55a0d368d29386608c7fdf9d6ad8e8fe": { + "filename": "Midway Campaign (Avalon Hill).zip", + "disk0": "Midway.dsk", + "joy-right": "kjoy0", + "basic": "PCLEAR1:RUN\"MIDWAY\"\n" + }, + "dd96056074b21815c996f7de244785ba147a6f17": { + "filename": "Mille Bornes (HLO) (Coco port).zip", + "disk0": "MBv2.DSK", + "basic": "RUN\"MB2\"\n" + }, + "26b6e61ea4a7690cd5ffc606dd769bbec5016cff": { + "filename": "Milenium the Last Outpost (Tabaxi Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "milenium.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"X\"\n" + }, + "f02e5da5f08a25e87d279f0d1959bf256f44bf28": { + "filename": "Mind-Roll (Tandy) (Coco 1-2) (Coco 3).zip", + "machine": "coco3", + "disk0": "MINDROLL.DSK", + "joy-left": "kjoy0", + "basic": "RUN\"MINDROLL\"\n" + }, + "52fcc5fa564df55cb6a71144d255cfe369c8d980": { + "filename": "Mine Camp (Public Domain).zip", + "disk0": "MINECAMP.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"MINECAMP\"\n" + }, + "63f89a19583736cf0e564112efa6711507d83095": { + "filename": "Minecamp, the next mission (Diego Barizo) (Coco 3).zip", + "machine": "coco3", + "disk0": "MINECMP2.DSK", + "basic": "RUN\"MC2\"\n" + }, + "ab8e79653b90bcbb817a0d9f608c8ff956a13651": { + "filename": "Mined Out (Quicksilva).zip", + "disk0": "MINEDOUT.DSK", + "basic": "RUN\"MINEDOUT\"\n" + }, + "3533784820111999dec68c0c67a7b85576d6e311": { + "filename": "Minesweeper (Tim Franklin) (Coco 3).zip", + "machine": "coco3", + "disk0": "SWEEP.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"SWEEP\":EXEC\n" + }, + "0202f927dba882330044730533688fd31c47b8c2": { + "filename": "Minigolf 3 (T&D Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "MINIGOLF.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"MINIGOLF\"\n" + }, + "20123b5d753ddb6d8048df7157ef1038762ac867": { + "filename": "Mine Rescue (SRB Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "MINERESC.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MINERESC\"\n" + }, + "be292e1f1b43adc8ddbbda230c28ca4b9a0d0d1b": { + "filename": "Mine Rescue (SRB Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "MINERESC.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MINERESC\"\n" + }, + "97571bcd8ae1a2fbef938d90519a2bb2c0a8fa7f": { + "filename": "Mine Rescue (SRB Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "MINERESC.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MINERESC\"\n" + }, + "5938adb70bf0ee4f1f5e6e65b012a026aefe5740": { + "filename": "Mine Rescue (SRB Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "MINERESC.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MINERESC\"\n" + }, + "bdf6244fccdfdcd6baa28396073e8513aa0fce5d": { + "filename": "Mis-Adventures of Eddie, The (Novasoft).zip", + "disk0": "eddie.dsk", + "basic": "LOADM\"EDDIE\":EXEC\n", + "tv-input": "redblue" + }, + "15235c7146dfd81f41865a49cb31d334cffdddc3": { + "filename": "Miss Gobbler (Spectral Associates).zip", + "disk0": "MGOBBLER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MGOBBLER\":EXEC\n" + }, + "67c8765e7ad1326906b9634c07ba794e7a635627": { + "filename": "Mission Empire (Ark Royal Games).zip", + "disk0": "empire.dsk", + "basic": "RUN\"MISSIONE\"\n" + }, + "d0340dece9d7b1c11553088f0f9392670e6845f3": { + "filename": "Miss Gobbler (Spectral Associates) (SSC).zip", + "disk0": "MISSPACV.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MISSPACV\":EXEC\n" + }, + "06a62e7eb1d8f7a3e02d17dd4101e2fb1eebdbcc": { + "filename": "Mission of Vengeance (Saguaro Software).zip", + "disk0": "vengeanc.dsk", + "basic": "RUN\"START\"\n" + }, + "7b2a326f7cdceb89dee542b5270b74176595b712": { + "filename": "Mix-Up (Don Langkamp) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "mixup.dsk", + "joy-right": "mjoy0", + "basic": "DOS\n" + }, + "ee57813fc1ac5e07be1f6e52d2d5868046a93052": { + "filename": "Module Man (Spectral Associates) (SSC).zip", + "disk0": "MODULE.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MODULE\":EXEC\n" + }, + "03dd28ba82c960037c0619e9e50ee4ce2b3941fb": { + "filename": "Model Rocketry (David Matt).zip", + "disk0": "ROCKETRY.DSK", + "basic": "RUN\"ROCKETRY\"\n" + }, + "365702fa29d8433813e99ab5551a91ecd65cfb25": { + "filename": "Moneyopoly (Tom Mix Software).zip", + "disk0": "MONOPOLY.DSK", + "joy-left": "mjoy0", + "basic": "LOADM\"MONOPOLY\":EXEC\n" + }, + "d34fbb25c05f8e2385555cb2dbbf059be3d223a1": { + "filename": "Monkey Kong (Med Systems-Screenplay).zip", + "disk0": "MONKEYK.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MONKEYK\":EXEC\n" + }, + "d995d3b4745282e5c478f60cc7cfd1ee196babcf": { + "filename": "Monkey Shines (T&D Software).zip", + "disk0": "MSHINE.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"MONKEY\"\n" + }, + "8b3ab603910b744fd00d79c2a04a19c608a17833": { + "filename": "Monster Maze (Tandy).zip", + "disk0": "MMAZE.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MMAZE\":EXEC\n" + }, + "556fcee2d1eeb06de894f1c42c9e771e2c55d80a": { + "filename": "Monsters & Magic (Prickly-Pear Software).zip", + "disk0": "MONSTERS.DSK", + "basic": "RUN\"MONSTERS\"\n" + }, + "a7f746b46127a700ad9db91e69361983fe6eb9ee": { + "filename": "Montezumas Dungeons (T&D Software).zip", + "disk0": "MONTEZUM.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MONTEZUM\":EXEC\n" + }, + "59f51305bfef6be1a6968edee38cd5c6cde3259d": { + "filename": "Moon 1 (Pat Abramovitch) (Coco 3).zip", + "machine": "coco3", + "disk0": "MOON1.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"MOON1\"\n" + }, + "7a011954d14a9f069a6e2fe600a16e03674490ba": { + "filename": "Moon Cresta (Incentive Software) (Coco port).zip", + "disk0": "CRESTA.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CRESTA\":EXEC\n" + }, + "7e5459cf63ad2d3d5ee0fdb01de51d4e9f656e8f": { + "filename": "Moon Flight (Paul Griffit).zip", + "disk0": "MOONFL.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"MOONFL\"\n" + }, + "54861dfcf2da6605922fad61d0785436fe2ee0fd": { + "filename": "Moonhopper (Computerware).zip", + "disk0": "MOONHOP.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MOONHOP\":EXEC\n" + }, + "499669026e80653c24a92e9f8e7c6385a399bcdd": { + "filename": "Moon Lander (Tom Mix Software).zip", + "disk0": "MOONLAND.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"LANDER\"\n" + }, + "6eae0a918060439e05ef68d5cf2b03fcc243c314": { + "filename": "Moon Shuttle (Datasoft).zip", + "disk0": "MOONSHUT.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MOONSHUT\":EXEC\n" + }, + "467b8d9c3bba9780f028c2c1071fea3d063589f9": { + "filename": "Morocco GP (Computerware).zip", + "disk0": "MOROCCO.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MOROCCO\":EXEC\n" + }, + "a06a0c41cc180706306792e9fbc8da62b16155cf": { + "filename": "Mortar Command (Overseas Software).zip", + "disk0": "MORTAR.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"MORTAR\"\n" + }, + "8ec23a6eed58a68929655ec01d769c0d906e42c7": { + "filename": "Moria (Greg Olson).zip", + "machine": "coco3", + "disk0": "MORIA_CC3.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"START\"\n" + }, + "6dea7a981457b4a606be19cfe589e91d94ee45d3": { + "filename": "Moria (Greg Olson).zip", + "machine": "coco3", + "disk0": "MORIA_CC3.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"START\"\n" + }, + "a9f837cc67083fd7a4c7fc86687bdb335ce940ae": { + "filename": "Motorcycle Jump (CLOAD).zip", + "disk0": "motojump.dsk", + "basic": "RUN\"MOTOJUMP\"\n" + }, + "072904c17204893fc97732d0e5804ad686856855": { + "filename": "Mouse Maze (John Kowalski).zip", + "disk0": "mousemaz.dsk", + "basic": "RUN\"*\"\n" + }, + "7bfc7c0ea366c42451d86d2a4a5cefc52f60c1fe": { + "filename": "Mr. Dig (Computerware).zip", + "disk0": "MRDIG.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MRDIG\":EXEC\n", + "tv-input": "redblue" + }, + "c6e95b0293293077422da5402bc7ef24fba0fad6": { + "filename": "Mr. Munch (Chromasette).zip", + "disk0": "MRMUNCH.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"MRMUNCH\"\n" + }, + "6265ac3dc29c21e9219eed4fb4df545e98952d50": { + "filename": "Mr. Corey (Valkyrie Software).zip", + "disk0": "corey.dsk", + "basic": "LOADM\"COREY\":EXEC\n" + }, + "d7949533c899987effa8d2a8607edff5ebb366d0": { + "filename": "Mrs Pac (T&D Software).zip", + "disk0": "MRSPAC.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"MRSPAC\":EXEC\n" + }, + "2cb6825308eb93b7ed5d40cd3beef355f750e81f": { + "filename": "Ms. Paku (Paul Shoemaker).zip", + "disk0": "MSPAKU.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MSPAKU\":EXEC\n" + }, + "adbe4be7f6123f0531cad424ad2b38d0f5d0fa5a": { + "filename": "Ms. Maze (Tom Mix Software).zip", + "disk0": "MS-MAZE.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MS-MAZE\":EXEC\n" + }, + "97029a5219434f6f12e60db47d79628a9d69c639": { + "filename": "Ms. Paku (Paul Shoemaker) (Coco 3).zip", + "machine": "coco3", + "disk0": "MSPAKU3.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MSPAKU3\":EXEC\n" + }, + "018b427ea0bf3c947c45305315097d6078a77695": { + "filename": "Mudpies (Computer Shack-Michtron).zip", + "disk0": "MUDPIES.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MUDPIES\":EXEC\n", + "tv-input": "redblue" + }, + "35e3cb1327120820e57bbb6d21db164ffd20826f": { + "filename": "Multi-Bars Slot Machine (Tom Mix Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "MULTIBAR.DSK", + "basic": "LOADM\"MULTIBAR\":EXEC\n" + }, + "9ff1a573cf3d652d78493550e96257504092cd5b": { + "filename": "Munchkin Blaster (Steve Donald).zip", + "disk0": "BLASTER.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"BLASTER\"\n" + }, + "9336251a3cee54f14cb9a59c1e6b9c96ff24bd13": { + "filename": "Munchman (T&D Software).zip", + "disk0": "Munchman.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"MUNCHMAN\":EXEC\n" + }, + "0e2b5754e104d0eeeb994db793c9d27d74649368": { + "filename": "Mystery of the Java Star (Shards Software).zip", + "disk0": "JAVASTAR.DSK", + "basic": "RUN\"JAVASTAR\"\n" + }, + "28aedf818a9533ce96801b639a688e002dda8f88": { + "filename": "Nasa Pilot Training Program.zip", + "disk0": "NASA.DSK", + "basic": "RUN\"NASA\"\n" + }, + "9a3c1c1e730441d59e40b6257a3e8b622c7299ba": { + "filename": "Mystic Mansion.zip", + "disk0": "MysticM.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"MYSTIC\"\n" + }, + "3324bfd8bed5352f20b8e36f5009899641e9d212": { + "filename": "Naugus, The (Spectral Associates).zip", + "disk0": "NAUGUS.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"NAUGUS\":EXEC\n" + }, + "ad4e98c7a8b56fd6ca725b0934363d9775743efe": { + "filename": "Nerble Force (Computerware).zip", + "disk0": "NERBLE.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"NERBLE\":EXEC\n" + }, + "50a53257585dc75d0392bf1b712e7a9120313c06": { + "filename": "Neutroid II (Nick Marentes) (SG-12) (Coco 1-2).zip", + "disk0": "NEUTROID.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"NEUTROID\":EXEC\n" + }, + "689c55438a4e3821edb6eaf02981fc92bab249e2": { + "filename": "Night of the Ninja (Jay Braxmaier).zip", + "disk0": "NIGHT.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"NIGHT\":EXEC\n" + }, + "985fdca7ccedf2aae389ef2101dec254595627f4": { + "filename": "Nibbler (Nelson Software Systems).zip", + "disk0": "NIBBLER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"NIBBLER\":EXEC\n" + }, + "53aeb1ac3fb6e87884b5e304ed1f80cde00420c5": { + "filename": "Nightmare on Elm Street (Dan Larson) (Coco 3).zip", + "machine": "coco3", + "disk0": "FREDDIE.DSK", + "basic": "RUN\"FREDDIE\"\n" + }, + "b1035d15b5f636193dd021b5f4ab28001ffb9b7d": { + "filename": "Nine Card Choice (T&D Software).zip", + "disk0": "NINECARD.DSK", + "basic": "RUN\"NINECARD\"\n" + }, + "2576a8a5da2dc0e0f3698e9b834069edd78194f5": { + "filename": "Ninja Warrior (The Programmer's Guild).zip", + "disk0": "NINJA.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"NINJA\":EXEC\n" + }, + "9ba9eee7995ad4eaa39fff653fb8fbf7a64cca54": { + "filename": "Nort Chase (Alvin Kimball).zip", + "disk0": "NORT.DSK", + "basic": "RUN\"NORT\"\n" + }, + "7c949a7f2e0dbccf05f0de87e75d53d750f7d207": { + "filename": "Noids (T&D Software).zip", + "disk0": "noids.dsk", + "basic": "RUN\"NOIDLOAD\"\n" + }, + "62103e28d03d44dc0efcefae4dd8712c0bbc1908": { + "filename": "Not Another Expressway Ripoff! v1.10 (Retro Rick).zip", + "disk0": "NAER110.DSK", + "basic": "RUN\"NAER\"\n" + }, + "bdf2762fdd964705277555317fe697cb0fd1e783": { + "filename": "Nuclear Avenger (T&D Software).zip", + "disk0": "NUKEAVNG.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"NUKEAVNG\":EXEC\n" + }, + "d8c51fcb77a77b4ec4d4aa981cbd0c48fae94689": { + "filename": "Nuclear Reactor Simulator (The Rainbow).zip", + "disk0": "NUKESIM.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"NUKESIM\":EXEC\n" + }, + "f4bd2a75c5a71016c2ef905677153a08fab6602b": { + "filename": "Nova Pinball (Bumblebee Software).zip", + "disk0": "NOVA.DSK", + "basic": "LOADM\"NOVA\":EXEC\n" + }, + "01746b697b7b7040090ee9cd3c9498d7958a90d5": { + "filename": "Nuclear Submarine Adventure (Aardvark-80).zip", + "disk0": "NUCLRSUB.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"NUCLRSUB\":EXEC\n" + }, + "2f8a0847d4821a9fa5650f5939fd9bcb455ab36b": { + "filename": "Nukewar (Avalon Hill) (Coco port).zip", + "disk0": "NUKEWAR.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"NUKEWAR\":EXEC\n" + }, + "2a6b4b7536b18f7e533e3abb0eea8e37955769ef": { + "filename": "Ockywoky (Shooting Star Software).zip", + "disk0": "OCKYWOKY.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"OCKYWOKY\":EXEC\n" + }, + "e82209e86dd68d9c10f8c0ba18a8c9321d802131": { + "filename": "Offender (American Business Computers).zip", + "disk0": "OFFENDER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"OFFENDER\":EXEC\n" + }, + "12389a289a84b8f6427b7890dfe9f6e65f9723a9": { + "filename": "Olympic Decathlon (The Rainbow).zip", + "disk0": "OLYMPICS.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"OLYMPICS\":EXEC\n" + }, + "12aee8d25e4ea9cc93f14833d42224bc6ce9868b": { + "filename": "Omniverse (Computerware) (SSC).zip", + "disk0": "Omniverse (alt).dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"OMNIVERSE (ALT)\":EXEC\n" + }, + "7fbd9098c542f245bab35449c2b6e4eb40dde329": { + "filename": "Omniverse (Computerware) (SSC).zip", + "disk0": "Omniverse (alt).dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"OMNIVERSE (ALT)\":EXEC\n" + }, + "2f4d25078b83fad0756da5f5cd4946219a119bcf": { + "filename": "One on One (Electronic Arts).zip", + "disk0": "1on1.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"1ON1\":EXEC\n" + }, + "a1049e19baaa50bf0deef68f0f8ddbb8635b8bfd": { + "filename": "One on One (Electronic Arts).zip", + "disk0": "1on1.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"1ON1\":EXEC\n" + }, + "24bdbbb4da5bc4a7df2b56758dbcec16580013dd": { + "filename": "Ono (Charles Bartlett) (coco 3).zip", + "disk0": "UNO.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"UNO\":EXEC\n" + }, + "02bb470c11da7e304423cc96145006c7e90d72dc": { + "filename": "Ono (Charles Bartlett) (Coco 3).zip", + "machine": "coco3", + "disk0": "UNO.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"UNO\":EXEC\n" + }, + "86661d6fd061466372ff238887fc42f56a2112e8": { + "filename": "Oodles (Paul Shoemaker).zip", + "disk0": "OODLES.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"OODLES\":EXEC\n" + }, + "4a31714c9ef95b7dee757a90e1ba310f739b6333": { + "filename": "Operation Barbarossa (Victor Koss).zip", + "disk0": "OPERBARB.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"OPERBARB\":EXEC\n" + }, + "39dd28830e50aff4871c0c8f564b8617689a90cf": { + "filename": "Operation Dark Horse (Ark Royal Software).zip", + "disk0": "horse.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"HORSE\"\n" + }, + "57f507f0f75f4f40b6e1b3d4e98415a43337a736": { + "filename": "Operation Redstar.zip", + "disk0": "REDSTAR.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"REDSTAR\":EXEC\n" + }, + "68a3442f14793ddce74d680b421f1ba27d446699": { + "filename": "Nuke the Love Boat (Computerware ) (Coco 3).zip", + "machine": "coco3", + "disk0": "nuke2.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"NUKE2\":EXEC\n" + }, + "2490404ba2541b914f5d0d60003d6e003ada16e7": { + "filename": "Nuke the Love Boat (Computerware ) (Coco 3).zip", + "machine": "coco3", + "disk0": "nuke2.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"NUKE2\":EXEC\n" + }, + "1ebcfea9266bdae3e8ff600be1483c0a8b77c7c4": { + "filename": "Nuke the Love Boat (Computerware ) (Coco 3).zip", + "machine": "coco3", + "disk0": "nuke2.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"NUKE2\":EXEC\n" + }, + "dc80ab86c878eefdcf1d3a1348ca3198f2ddad5c": { + "filename": "Nuke the Love Boat (Computerware ) (Coco 3).zip", + "machine": "coco3", + "disk0": "nuke2.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"NUKE2\":EXEC\n" + }, + "63cc2690d51e7723b46da1881a06cb3f7a0bbc5e": { + "filename": "Nuke the Love Boat (Computerware ) (Coco 3).zip", + "machine": "coco3", + "disk0": "nuke2.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"NUKE2\":EXEC\n" + }, + "e27b7c278f04815b269f564eb987dd52be279667": { + "filename": "Orbitroids (Creative Computing Software).zip", + "disk0": "orbitor.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"ORBITOR\":EXEC\n" + }, + "0367e324e19dbeb4b90ad0aff24148f0d8934104": { + "filename": "Orbitron (AHL Computing).zip", + "disk0": "ORBITRON.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ORBITRON\":EXEC\n" + }, + "1bf9193789890e8274df2a152a8781b8bf16f958": { + "filename": "Oregon Trail (Chris Pedersen).zip", + "disk0": "OREGON.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"OREGON\":EXEC\n" + }, + "c39422e2379b4b0cacf9fdd223f49aae1dc3faea": { + "filename": "Othello (alt) (Public Domain).zip", + "disk0": "OTHELLO.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"OTHELLO\":EXEC\n" + }, + "620194f9508d015ac7b6e7b6a17c8673056f1a25": { + "filename": "Othello (Public Domain).zip", + "disk0": "OTHELLO.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"OTHELLO\":EXEC\n" + }, + "36a6d0988c68326f4e986d3beae490aa76859fea": { + "filename": "Otho 3.6 (Alain Dussault).zip", + "disk0": "OTHO36.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"OTHO36\":EXEC\n" + }, + "d1080ff1a73828e7c5984c40461fc7c0c616e0fc": { + "filename": "Outhouse (Computer Shack).zip", + "disk0": "OUTHOUSE.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"OUTHOUSE\":EXEC\n" + }, + "650210ccb4cb430415567065598fe2742cda5dc1": { + "filename": "Overlord (Oblique Triad) (Coco 3).zip", + "machine": "coco3", + "disk0": "overlord.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"OVERLORD\":EXEC\n" + }, + "6383f8e6efbac41f9ba16cbceeac0db51deb15ea": { + "filename": "Oxxo (Star Kits).zip", + "disk0": "OXXO.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"OXXO\":EXEC\n" + }, + "d8dc4f71882e88fd1cc6ca60c195c6f59741aead": { + "filename": "P-51 Mustang Attack (Tom Mix Software).zip", + "disk0": "P-51.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"P-51\":EXEC\n" + }, + "9d66c52928f696101938cfaf378abb9cec86239b": { + "filename": "Pac Rat (Steven Dufresne).zip", + "disk0": "pacrat.dsk", + "basic": "RUN\"PACRAT\"\n" + }, + "a6d9a804ad95caa269ad0f9721ba2d2767b2a82a": { + "filename": "Pac Droids (The Programmer's Guild) (SG-12 intro).zip", + "disk0": "PACDROID.DSK", + "basic": "LOADM\"PACDROID\":EXEC\n" + }, + "d532bbb63376234bdffdeade12807e09c97b2eef": { + "filename": "Pac Droids (The Programmer's Guild) (SG-12 intro).zip", + "disk0": "PACDROID.DSK", + "basic": "LOADM\"PACDROID\":EXEC\n" + }, + "239b9d2b23a57f628542be7bd1c82e48db9ffc65": { + "filename": "Pacdude Monster Maze 2.0A (Brian O'Neill) (Coco 3).zip", + "machine": "coco3", + "disk0": "pacdude2.dsk", + "joy-left": "kjoy0", + "basic": "LOADM\"PACDUDE2\":EXEC\n" + }, + "36160c75d4b1e28ea7e28ad04eaaf9233cb961b2": { + "filename": "Pacdude 1.0 (Brian O'Neill) (Coco 3).zip", + "machine": "coco3", + "disk0": "pacdude.dsk", + "joy-left": "kjoy0", + "basic": "LOADM\"PACDUDE\":EXEC\n" + }, + "2387320fa60807190be7d40649764f02543f316b": { + "filename": "Pacdude 1.0 (Brian O'Neill) (Coco 3).zip", + "machine": "coco3", + "disk0": "pacdude.dsk", + "joy-left": "kjoy0", + "basic": "LOADM\"PACDUDE\":EXEC\n" + }, + "091580496af6566a8d6312e31cb52e0667ccf7f5": { + "filename": "Pacdude 1.3 with source (Brian O'Neill) (Coco 3).zip", + "machine": "coco3", + "disk0": "PACDUDE.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"PACDUDE\":EXEC\n" + }, + "a5a233ba7eb8d315cd9ac7a32fe7af5c992ed563": { + "filename": "Packet Man (American Business Computers).zip", + "disk0": "PACKMAN.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"PACKMAN\":EXEC\n" + }, + "23d6c3ff93466922fde0bf497f5c7379273fd318": { + "filename": "Pack Maze (DSL Computer Products).zip", + "disk0": "PACKMAZE.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"PACKMAZE\":EXEC\n" + }, + "911f38cf2fee48077b55cf21db5793e8fe7447fa": { + "filename": "Pacdude Monster Maze 2.1A (Brian O'Neill) (Coco 3).zip", + "machine": "coco3", + "disk0": "PACDUDE2.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"PAC2\":EXEC\n" + }, + "cdb6479b1db36fe53e3ce332e7fbbbb6c1faed47": { + "filename": "Pacman (Bruce Mackenzie).zip", + "disk0": "PACMAN.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"PACMAN\":EXEC\n" + }, + "d60a10f049ab67cb7f5998a7d5d9f7cf3fd8cfee": { + "filename": "Pac-Man Demo (Nick Marentes) (Coco 3).zip", + "machine": "coco3", + "disk0": "pacdemo.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"PACDEMO\"\n" + }, + "08e7533612964cb159122117d2f61cfb08c9c1ba": { + "filename": "Pacman CoCo 3 Transcode (Glen Hewlett) (Coco 3).zip", + "machine": "coco3", + "disk0": "PACMAN.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"PACMAN\"\n" + }, + "05adfd262b5408f2dce93013f79e5df897fd0f4e": { + "filename": "Pacoman (S. Bernier & G. Poirier).zip", + "disk0": "PACOMAN.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"PACOMAN\":EXEC\n" + }, + "4c8bf1ded4cc0767d68626cb4afdf6aaf4b29f88": { + "filename": "Pac-Tac (Computerware) (SG-12) (Coco 1-2).zip", + "disk0": "PAC-TAC.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"PAC-TAC\":EXEC\n" + }, + "080ff52877e4aeb1940edd636e8be79b5380d46d": { + "filename": "Pac-Panic (Cougar Software).zip", + "disk0": "PAKPANIC.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"PAKPANIC\":EXEC\n" + }, + "b19325575fbdbb381824c5dceb4f114e6b0751c1": { + "filename": "Pac-Tac II (Computerware).zip", + "disk0": "PAC-TAC2.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"PAC-TAC2\":EXEC\n" + }, + "fa4e0bc2771f4899a6ba61533bf4145f19eeb8a0": { + "filename": "Paku Paku (Paul Shoemaker).zip", + "machine": "coco3", + "disk0": "PAKUPAKU.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"PAKUPAKU\":EXEC\n" + }, + "e81b4b0115dd3fd233b7a7e77d519d49fc4eedc4": { + "filename": "Pac-OS9 (Larry Olson) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "PACOS9.DSK", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "fb0b753576bba305080157b898ef452996ac744c": { + "filename": "Pac-OS9 (Larry Olson) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "PACOS9.DSK", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "c72432101940428382483aaeb0f8b62ecd83326d": { + "filename": "Panic Button (Tandy).zip", + "disk0": "PANIC.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"PANIC\":EXEC\n" + }, + "61b2dc1f8a59461343185d0eb5c8ae5cf9375d03": { + "filename": "Panic (Tom Mix Software).zip", + "disk0": "PANIC.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"PANIC TM\":EXEC\n" + }, + "7b0ba203ee1e531cb706ad8d83285b6a16d53685": { + "filename": "Paper Route (Diecom Products).zip", + "disk0": "PAPER.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"PAPER\":EXEC\n", + "tv-input": "redblue" + }, + "0f4f931c328d3fffd75282c415311c98427f7686": { + "filename": "Panzer (T&D Software).zip", + "disk0": "PANZER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"PANZER\":EXEC\n" + }, + "45bd4bd973af8f7bfea43d2855f832dee76a85a9": { + "filename": "Para-Jumper (The Rainbow).zip", + "disk0": "PARACHUT.DSK", + "basic": "RUN\"PARACHUT\"\n" + }, + "3558967c336167458218567cc7c1dd3c6db1ab71": { + "filename": "Patti-Pak (Petrocci Freelance Associates).zip", + "disk0": "PATTIPAK.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"PATTIPAK\":EXEC\n" + }, + "3263cf3d3e4b81d831d1c16f573c42ade1ce5fb6": { + "filename": "Peg Jump (T&D Software).zip", + "disk0": "PEGJUMP.DSK", + "basic": "RUN\"PEGJUMP\"\n" + }, + "ff0a2a0dd9e54137dea3bd8793c3b86d55f54749": { + "filename": "Pedro (Imagine).zip", + "disk0": "PEDRO.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"PEDRO\":EXEC\n" + }, + "79dbf68d38d20bdd9f6a6f2512425816370832f0": { + "filename": "Pegasus and the Phantom Riders (Tandy) (SSC).zip", + "disk0": "Pegasus.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"PEGASUS\"\n" + }, + "8ca38ccf954b3986f55d020103b98a86dc1663d3": { + "filename": "Pegasus and the Phantom Riders (Tandy) (SSC).zip", + "disk0": "Pegasus.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"PEGASUS\"\n" + }, + "3459df2b9288f7e6e0420fc985117082b93a951b": { + "filename": "Pelieti (Roger Taylor) (Coco 3).zip", + "machine": "coco3", + "disk0": "PELIETI.DSK", + "basic": "LOADM\"PELIETI\":EXEC\n" + }, + "683be58171844b25901b52814b51b7c82a016cb8": { + "filename": "Pendant of Death (Wayne Kely).zip", + "disk0": "Pendant.dsk", + "basic": "RUN\"PENDANTD\"\n" + }, + "0000c383d026eebb23abd8963b8839202b03bdd1": { + "filename": "Pengon (Spectral Associates).zip", + "disk0": "PENGON.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"PENGON\":EXEC\n", + "tv-input": "redblue" + }, + "6cb4af9ab99c358da89c5c04f42c0091cde2f68f": { + "filename": "Penguin Icarus (The Rainbow) (Coco 3).zip", + "machine": "coco3", + "disk0": "PENGUIN.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"PENGUIN\"\n" + }, + "0c02f54c55219fb46c71b46325dfb821df1b82bb": { + "filename": "Pennypede (Chromasette) (SG-6) (Coco 1-2).zip", + "disk0": "PENIPEDE.DSK", + "basic": "LOADM\"PENIPEDE\":EXEC\n" + }, + "3f5c7013e655aa31602e58445538079fdd27aeeb": { + "filename": "Penguin (The Rainbow).zip", + "disk0": "PENGUIN.DSK", + "basic": "RUN\"PENGUIN\"\n" + }, + "d8629257dd46355ebd43a8755f2f69dc5504374a": { + "filename": "Phantom Slayer (Med Systems).zip", + "disk0": "PHANTOMS.DSK", + "basic": "LOADM\"PHANTOMS\":EXEC\n" + }, + "2488ac04d42b566b9bd89ed2e9aba0c7f50b9fc6": { + "filename": "Petals Around the Rose (Aaron Sebold) (Coco 3).zip", + "machine": "coco3", + "disk0": "petals.dsk", + "basic": "RUN\"PETALS\"\n" + }, + "7bf02bac0e97700a9ec8080187b42595602abe76": { + "filename": "Petals Around the Rose (Aaron Sebold) (Coco 3).zip", + "machine": "coco3", + "disk0": "petals.dsk", + "basic": "RUN\"PETALS\"\n" + }, + "6be5b3a5e1f3c64cc80f66bc1ce45dd938eb5a31": { + "filename": "Phoenix Project, The (Donald S. Cathcart) (Coco 3).zip", + "machine": "coco3", + "disk0": "PHOENIX.DSK", + "basic": "RUN\"PHOENIX.INS\"\n" + }, + "cbc9f882a6acf5b02abf7789df5a17b5c028e749": { + "filename": "Pick Which (Spectral Associates).zip", + "disk0": "PWHICH.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"PWHICH\":EXEC\n" + }, + "3d596e65d81818d9fc41a9a6a9ba946dbd9f0566": { + "filename": "Picnic (Creative Computing Software).zip", + "disk0": "PICNIC.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"PICNIC\":EXEC\n" + }, + "a416b7c8d3ce9b397626c0fa0ab3e802391125aa": { + "filename": "Picture Puzzles (JR & JR Softstuff) (Coco 3).zip", + "machine": "coco3", + "disk0": "PPUZZ.DSK", + "basic": "LOADM\"PPUZZ\":EXEC\n" + }, + "c40008f838e9a216d1aadcc7b2bd6eab60167603": { + "filename": "Piggy (Spectral Associates).zip", + "disk0": "PIGGY.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"PIGGY\":EXEC\n" + }, + "66dd74ecdeab2552a47642f4d9bbf72276787865": { + "filename": "Pinball (Anteco).zip", + "disk0": "ANTECPIN.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ANTECPIN\":EXEC\n" + }, + "8196d572091fff5a597479774462ca07a31bf854": { + "filename": "Photon (Patched for emulators) (Sundog Systems) (Coco 3).zip", + "machine": "coco3", + "disk0": "Photon (Patched for emulators) (Sundog Systems) (Coco 3)/photon.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"PHOTON\"\n" + }, + "d33cba935a73250945f3ed48527ea739a101742e": { + "filename": "Photon (Patched for emulators) (Sundog Systems) (Coco 3).zip", + "machine": "coco3", + "disk0": "Photon (Patched for emulators) (Sundog Systems) (Coco 3)/photon.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"PHOTON\"\n" + }, + "c4a9663c41ddca1964109def5e3dc48ff62db7fc": { + "filename": "Pinball Factory (Michtron).zip", + "disk0": "PINBALL.DSK", + "basic": "RUN\"PINBALL\"\n" + }, + "151ac8a40230f1eb3e1890dcd19c6cbfcaa7e926": { + "filename": "Pirate Adventure.zip", + "disk0": "PIRATES.DSK", + "basic": "RUN\"PIRATES\"\n" + }, + "39f3f072f460c40d349617bdfad9cd5e19712b48": { + "filename": "Pit Fiend (Pocket Money Software).zip", + "disk0": "PITFIEND.DSK", + "basic": "LOADM\"PITFIEND\":EXEC\n" + }, + "6a5fd2a76fb09b4e4794041e39e1e5072be92aae": { + "filename": "Pirate's Treasure.zip", + "disk0": "Pirates Treasure.dsk", + "joy-right": "mjoy0", + "basic": "RUN\"PIRATE\"\n", + "tv-input": "redblue" + }, + "e6c23517484be8cfa51db4b2a271f05a9b5c72f0": { + "filename": "Pitstop 2 (Epyx).zip", + "disk0": "pitstop2.dsk", + "basic": "RUN\"*\"\n", + "tv-input": "redblue" + }, + "3b4bad31c4cd9eda399d5e23638b5152f0812f2f": { + "filename": "Planet Conquest (International Software).zip", + "disk0": "PLANCONQ.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"PLANCONQ\":EXEC\n" + }, + "2fe2fe689534e31339af0328de29faaf26c50fb6": { + "filename": "Planet Raider (Aardvark-80).zip", + "disk0": "PLNTRAID.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"PLNTRAID\":EXEC\n" + }, + "46bad782c9b97b2a905d166028f9d6216e915f43": { + "filename": "Pitfall 2 (Tandy) (SSC).zip", + "disk0": "pitfall2.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"PITFALL2\"\n", + "tv-input": "redblue" + }, + "6e2d2b22ab84d3e257789ea99ce93a0ffcfbb51f": { + "filename": "Pitfall 2 (Tandy) (SSC).zip", + "disk0": "pitfall2.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"PITFALL2\"\n", + "tv-input": "redblue" + }, + "e01baef95a5e1cbc05ca18159ea298ff6d8bec09": { + "filename": "Pitfall 2 (Tandy) (SSC).zip", + "disk0": "pitfall2.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"PITFALL2\"\n", + "tv-input": "redblue" + }, + "6e2c9fe33a3c1ea20da29c59454f613e08355e1b": { + "filename": "Pitfall 2 (Tandy) (SSC).zip", + "disk0": "pitfall2.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"PITFALL2\"\n", + "tv-input": "redblue" + }, + "b9acb9ec4a618527dcdc5685ecd36d107f4d36f0": { + "filename": "Planet X (Tony Stoneberger).zip", + "disk0": "PLANETX.DSK", + "basic": "RUN\"PLANET X\"\n" + }, + "b9fd6625de9ef912111ad88a85ecde19e42f9cbb": { + "filename": "Plateau of the Past (Zytek).zip", + "disk0": "plateau.dsk", + "basic": "LOADM\"POP\"\n", + "tv-input": "redblue" + }, + "52ed84e4dcaa539844e609ed064ec40cd3cc0fff": { + "filename": "Plunkit (Roger Taylor) (Coco 3).zip", + "machine": "coco3", + "disk0": "PLUNKIT.DSK", + "basic": "RUN\"PLUNKIT\"\n" + }, + "f66889f04466c1453658beb66e063e4df0cc6d9f": { + "filename": "Poker Squares (Original Edition) (Paul Shoemaker) (Coco 3).zip", + "machine": "coco3", + "disk0": "PSQUARES.DSK", + "basic": "RUN\"RUNME\"\n" + }, + "47fe89fac1574d5fae45fed2fe8fa7906fd82de2": { + "filename": "Poker Squares (Original Edition) (Paul Shoemaker).zip", + "disk0": "PSQUARE2.DSK", + "basic": "RUN\"RUNME\"\n" + }, + "ce7ab46840923477a8a5b0f02cc947a040a9c752": { + "filename": "Poker Squares (Paul Shoemaker) (Coco 3).zip", + "machine": "coco3", + "disk0": "PSQUARE5.DSK", + "basic": "RUN\"RUNME\"\n" + }, + "88f3b66a86d96cc4b55347970391c8161a418bcd": { + "filename": "Poker Squares (Paul Shoemaker).zip", + "disk0": "PSQUARE4.DSK", + "basic": "RUN\"RUNME\"\n" + }, + "5852be58e2857310ebbbe7e9bf28afb0dc32f100": { + "filename": "Polaris (Tandy).zip", + "disk0": "POLARIS.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"POLARIS\":EXEC\n" + }, + "be8e018ab157bdd338ff8c8b6cfcbd034dd09e4e": { + "filename": "Poltergeist (Tandy).zip", + "disk0": "POLTER.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"POLTER\":EXEC\n" + }, + "75872a744c6cfd6aea6de27d384a6b0f205d407e": { + "filename": "Pond, The (Tandy).zip", + "disk0": "ThePond.dsk", + "basic": "LOADM\"POND\":EXEC\n" + }, + "accb7f9a98e5fb682554186b6eca9baeb73a5c38": { + "filename": "Pong (Public Domain).zip", + "disk0": "PONG.DSK", + "joy-left": "mjoy0", + "joy-right": "kjoy0", + "basic": "LOADM\"PONG\":EXEC\n" + }, + "9b774810f7a2b87b44591457fb806b7f2b475668": { + "filename": "Ponk (Greg Helton) (Coco 3).zip", + "machine": "coco3", + "disk0": "PONK.DSK", + "joy-left": "mjoy0", + "joy-right": "kjoy0", + "basic": "LOADM\"PONK\":EXEC\n" + }, + "650f1f063c0eb4e14b09c03644d4dadd37e67f51": { + "filename": "Pooyan (Tandy).zip", + "disk0": "POOYAN.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"POOYAN\":EXEC\n" + }, + "c06173efe4024167c78d8fe2b7f266ca9f900807": { + "filename": "Pooyan (with intro) (Tandy).zip", + "disk0": "POOYAN.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"POOYAN\":EXEC\n" + }, + "2bcb3fe9ba35926830ce603b522610c4c97ea097": { + "filename": "Popcorn (Tandy).zip", + "disk0": "POPCORN.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"POPCORN\":EXEC\n" + }, + "5afccc0b076c18c2a2789e67c59ca05757c44df0": { + "filename": "Possum Run (Hot Coco).zip", + "disk0": "POSSUM.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"POSSUM\"\n" + }, + "eb2202854dae0f16caff88faf5533343c1e6958c": { + "filename": "Predator (Tandy) (Coco 3).zip", + "machine": "coco3", + "disk0": "predator.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"PRED\"\n" + }, + "63e9bc714330ef6577524d021eac0ccbe10dfbb9": { + "filename": "Power Stones of Ard, The (Three C's Projects) (Coco 3).zip", + "machine": "coco3", + "disk0": "STONES1.DSK", + "basic": "LOADM\"ARD\":EXEC\n" + }, + "50a946d2655b6f02803f4792f50e7ddb62db14f8": { + "filename": "Project Nebula (Tandy).zip", + "disk0": "NEBULA.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"NEBULA\":EXEC\n" + }, + "041de4d0de877b9ad95f5630180aa85cdc3d49e4": { + "filename": "Prospector (The Rainbow).zip", + "disk0": "PROSPECT.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"PROSPECT\":EXEC\n" + }, + "f73d9ae052cd1d235173b2016d95449de5451b9f": { + "filename": "Pro Golf (Computerware).zip", + "disk0": "PRO-GOLF-COMPUTERWARE.dsk", + "basic": "RUN\"GOLF\"\n", + "tv-input": "redblue" + }, + "2cc96d0a75be276e2d014c83714949171b9d1df8": { + "filename": "Pro Golf (Computerware).zip", + "disk0": "PRO-GOLF-COMPUTERWARE.dsk", + "basic": "RUN\"GOLF\"\n", + "tv-input": "redblue" + }, + "7c1f682f8d5315208170e6e8f223dae0cc5f238c": { + "filename": "Protector II (Synapse Software) (SG-24) (Coco 1-2).zip", + "disk0": "PROTECTR.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"PROTECTR\":EXEC\n" + }, + "79d6c6564d975f7e5d71174ef4d90a9035569046": { + "filename": "Proto 7 (Loren J. Howell) (Coco 3).zip", + "machine": "coco3", + "disk0": "PROTO7.DSK", + "basic": "RUN\"PROTO7\"\n" + }, + "ed175e5bdf50b0b05716e430e2703ed2b09c61da": { + "filename": "Protectors (Tom Mix Software).zip", + "disk0": "PROTECTO.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"PROTECTO\":EXEC\n" + }, + "83bdd31d441be79831bafbcf7006fd783d1ac897": { + "filename": "Pub Crawl (B&H Software).zip", + "disk0": "PUB.DSK", + "basic": "LOADM\"PUB\":EXEC\n" + }, + "ff0641faa48bdeb0ad3f64ee092fcc2c9b9ec298": { + "filename": "Pursuit (Tandy) (Coco 3).zip", + "machine": "coco3", + "disk0": "PURSUIT.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"PURSUIT\":EXEC\n" + }, + "9f2bfa95113cf51ce92b5a2e13b8b3bb7bdb1315": { + "filename": "Pumpman (Saguaro Software).zip", + "disk0": "PUMPMAN.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"PUMPMAN\":EXEC\n", + "tv-input": "redblue" + }, + "df0bb154f214159b5bc51e41512d290b5f39d3ab": { + "filename": "Puzzle Madness (TRS-80 Computing).zip", + "disk0": "puzlemad.dsk", + "basic": "RUN\"BOOT\"\n" + }, + "6fc867c458901200c7e2a17b81c1ef866e2243e4": { + "filename": "Puzzler (Color Connection Software).zip", + "disk0": "puzzler.dsk", + "basic": "LOADM\"PUZZLER\":EXEC\n" + }, + "ace8892bee5091f09cbfec5387047aa4bfb04731": { + "filename": "Puzzles (Rick's Computer Enterprise) (Coco 3).zip", + "machine": "coco3", + "disk0": "PUZZLES.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"PUZZLES\"\n" + }, + "7a7890dbcefb7149118bffdc4a920b7c9542a520": { + "filename": "Puzzle.zip", + "disk0": "puzzle.dsk", + "basic": "RUN\"PUZZLE\"\n" + }, + "580c973ad0898893152c9fce651b6bcbb0611a36": { + "filename": "Pyramid 2000 (Tandy).zip", + "disk0": "PYRAMID.DSK", + "basic": "LOADM\"PYRAMID\":EXEC\n" + }, + "b6bb5bd4e6aeff11621228f140fdd3e6739d5e59": { + "filename": "Pyramid (Aardvark-80).zip", + "disk0": "pyramid.dsk", + "basic": "RUN\"PYRAMID\"\n" + }, + "6ceababce4f414a72114bd17a057fd8eb91803fc": { + "filename": "Pyramid Solitaire (ColorSystems) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "pyramid.dsk", + "joy-right": "mjoy0", + "basic": "DOS\n" + }, + "1d170528e27e3daf878dbefb594e29d565f6bb6b": { + "filename": "Qazimodo (Cable Soft).zip", + "disk0": "QAZIMODO.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"QAZIMODO\":EXEC\n" + }, + "610e719c09ce02993568482574bfeffb94fe168b": { + "filename": "Pyramix (Colorventure) (Coco 3).zip", + "machine": "coco3", + "disk0": "PYRAMIX.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"PYRAMIX\":EXEC\n" + }, + "d71064b7d2919f69338b08d023f811fe25c71833": { + "filename": "Pyramix (Colorventure) (Coco 3).zip", + "machine": "coco3", + "disk0": "PYRAMIX.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"PYRAMIX\":EXEC\n" + }, + "2198d9784954d29b01ac4b0c7731f2414c4219f7": { + "filename": "QBee (Cload).zip", + "disk0": "QBEE.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"QBEE\"\n" + }, + "eed54d54d87716f5ba83e0609f976ff52502b815": { + "filename": "Q-Bert Redux (Dragon User) (Enhanced by sixxie).zip", + "disk0": "q-bert.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"Q*BERT%2B\"\n" + }, + "ef9db458e5490eaca6d3f8e8a92e66af4dd75064": { + "filename": "Qiks (Spectral Associates) (SSC).zip", + "disk0": "QIKSV.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"QIKSV\":EXEC\n" + }, + "f7724ad549fe919dd231a031f17ae23cdd617d6d": { + "filename": "Q-Man (Genesis Software).zip", + "disk0": "QMAN.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"QMAN\":EXEC\n" + }, + "17162fa4615607567d2ca4e3a3ef156646ffa928": { + "filename": "Quasar Commander (Tandy).zip", + "disk0": "QUASAR.DSK", + "joy-left": "mjoy0", + "joy-right": "kjoy0", + "basic": "LOADM\"QUASAR\":EXEC\n" + }, + "8965af68f1021219da9ecb52d74b680ace406dcf": { + "filename": "Que Bit (Mike Ro Products).zip", + "disk0": "QUEBIT.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"QUEBIT\":EXEC\n" + }, + "d4e3dbbf09aeaf68aa0d8022ddde087fb6b44d6b": { + "filename": "Quest (Aardvark).zip", + "disk0": "QUEST.DSK", + "joy-right": "kjoy0", + "basic": "PCLEAR1:RUN\"QUEST\"\n" + }, + "e410bbc21703ef186b219610b1e3944a04e518fe": { + "filename": "Quest (Dragon Data).zip", + "disk0": "QUEST.DSK", + "joy-right": "kjoy0", + "basic": "PCLEAR1:RUN\"QUEST\"\n" + }, + "9dc0b0c43f9858be57793298d15fc2d28965270e": { + "filename": "Quest for Fire (Sanyo and the CIP) (Coco port by JimG).zip", + "disk0": "FIREWAR.DSK", + "basic": "RUN\"FIREWAR\"\n" + }, + "b69e338e62665a5483e67fbb3e86b8622ff40369": { + "filename": "Quest (Aardvark) (alt).zip", + "disk0": "QUEST.DSK", + "joy-right": "kjoy0", + "basic": "PCLEAR1:RUN\"QUEST\"\n" + }, + "f9b9c3bdeff89cdd293e92df508ce1014941b720": { + "filename": "Quix (Tom Mix Software).zip", + "disk0": "QUIX.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"QUIX\":EXEC\n" + }, + "e4bc944b6757d1c7ac1928861c69d0ef9c903a30": { + "filename": "Raaka-Tu (Tandy).zip", + "disk0": "RAAKATU.DSK", + "basic": "LOADM\"RAAKATU\":EXEC\n" + }, + "d09f15d245fddf0b8f6a1a57aaf3c4f7dae0e515": { + "filename": "Racer Ball (Microdeal Ltd).zip", + "disk0": "RACEBALL.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"RACEBALL\":EXEC\n" + }, + "25a862d0547edbcd9c28bed99b74fe0c8171e244": { + "filename": "Radio Ball (Tandy).zip", + "disk0": "RAD-BALL.DSK", + "basic": "LOADM\"RAD-BALL\":EXEC\n" + }, + "0dd06ecb0941eaed13f0765c2b25d646900c31bb": { + "filename": "Rad Warrior (Epyx) (Coco 3).zip", + "machine": "coco3", + "disk0": "RAD.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"RAD\":EXEC\n" + }, + "4fc0f7d1b6f7bd713011f027ec621f21a2f759bb": { + "filename": "Rail Runner (Computerware) (SG-24) (Coco 1-2).zip", + "disk0": "RAILRUN.DSK", + "basic": "LOADM\"RAILRUN\":EXEC\n" + }, + "ed03fad96f5ec5c1a4684794974e5b85c6e1932d": { + "filename": "Rainbow Roach (The Rainbow).zip", + "disk0": "RBWROACH.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"ROACHD\"\n" + }, + "bc7fb735aea4aeb999d57132d819087b9dd10e4f": { + "filename": "Rally (Tino Delbourgo).zip", + "disk0": "RALLY.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"RALLY\":EXEC\n" + }, + "f33808357a4577a8d58f2a3fb79b866878de7b30": { + "filename": "Rambo (T&D Software).zip", + "disk0": "rambo.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"RAMBO\"\n" + }, + "b3e72f71a8ab6a70ccbd124f0236b4ba76437def": { + "filename": "Rampage (Tandy) (Coco 3).zip", + "machine": "coco3", + "disk0": "rampage.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"RAMPAGE\"\n" + }, + "75de6265012f33b3ffc9bc698e3ea312c6790d78": { + "filename": "Rat Attack (T&D Software).zip", + "disk0": "RAT.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"RAT\":EXEC\n" + }, + "ab2a18038f9f80114f066940a95c3c4600a7df35": { + "filename": "Reactoid (Tandy).zip", + "disk0": "REACTOID.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"REACTOID\":EXEC\n" + }, + "0bd2a2bc89ed89d298029ed8e4bfba0a44a748f1": { + "filename": "Realm of Nauga, The (Thomas E. Stephenson).zip", + "disk0": "NAUGA.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"NAUGAINS\"\n" + }, + "d510820c2ae5071a3c5432ec8982f869152d779d": { + "filename": "Rear Guard (Adventure International).zip", + "disk0": "REARGARD.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"REARGARD\":EXEC\n" + }, + "55025e961c55f38aea99ec9fe2c1501f4395b806": { + "filename": "Recochet.zip", + "disk0": "RECOCHET.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"RECOCHET\":EXEC\n" + }, + "3571d6db27cb87efe0ccf3212c07eec3bbb0cb5f": { + "filename": "Red Dog (T&D Software).zip", + "disk0": "REDDOG.DSK", + "basic": "RUN\"REDDOG\"\n" + }, + "9028081494111cf73117d64f6b973a3ccfae1f3f": { + "filename": "Rescue on Alpha II (The Rainbow).zip", + "disk0": "RESCUE.DSK", + "basic": "RUN\"BOOT\"\n" + }, + "f8b29cee35ead14aeae86cf33e4a3e158525fae0": { + "filename": "Rescue on Alpha II (The Rainbow).zip", + "disk0": "RESCUE.DSK", + "basic": "RUN\"BOOT\"\n" + }, + "da277419bee783560aaeeee40484edd2d7ca7830": { + "filename": "Rescue on Fractalus (Epyx) (OS-9) (6309 optimized) (Coco 3).zip", + "machine": "coco3h", + "disk0": "RESCUE-6309.DSK", + "joy-left": "kjoy0", + "basic": "DOS\n" + }, + "714e1c885c6d5e71a397bfa6ebbfe115063fea98": { + "filename": "Rescue on Fractalus (Epyx) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "RESCUE.DSK", + "joy-left": "kjoy0", + "basic": "DOS\n" + }, + "e964af77c7853c56598c84a5f94969e9a364c84d": { + "filename": "Rescue on Fractalus (Epyx) (OS-9) (6809 optimized) (Coco 3).zip", + "machine": "coco3", + "disk0": "RESCUE-6809.DSK", + "joy-left": "kjoy0", + "basic": "DOS\n" + }, + "966f6105e59ded257bc2d372f3ee2e10f149faf1": { + "filename": "Recue, The (Floyd Resler) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "tank.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "22efe7b5d7b6fe82c30a975ccb90aa77408f9835": { + "filename": "Recue, The (Floyd Resler) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "tank.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "2c13155641886723d9910acac57cc0a250bffe6e": { + "filename": "Recue, The (Floyd Resler) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "tank.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "3998d4dcee4b9e70bd200f576c08dd73e529084f": { + "filename": "Restaurant (Dabid Mann).zip", + "disk0": "RESTRANT.DSK", + "basic": "RUN\"RESTRANT\"\n" + }, + "4f265bd1c4173e6c8eb2b7be010857783abfe393": { + "filename": "Return of Junior’s Revenge (Computerware) (Coco 3).zip", + "machine": "coco3", + "disk0": "JUNIORS.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"JUNIORS\":EXEC\n" + }, + "36725f01c614032e900886550e04fb8b38ef0416": { + "filename": "Return of the Jet-I (Thundervision) (SG-8 intro).zip", + "disk0": "JET-I.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"JET-I\":EXEC\n" + }, + "81f006beaed58d1d585a8eb3113064fb3a9fc61e": { + "filename": "Revenge of the Alien Bongo Beast (Kouga) (Coco port).zip", + "disk0": "BONGO.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"BONGO\":EXEC\n" + }, + "45f88cad30db9f439af3298aa8b8f82cd56f6282": { + "filename": "Revenge of the Mutant Miners (JR & JR Softstuff) (Coco 3).zip", + "machine": "coco3", + "disk0": "REVMINER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"REVENGE\":EXEC\n" + }, + "d03dda8a6dfa20298e9fd590764ae1d4d720f434": { + "filename": "Revenge of the Germs (The Software System).zip", + "disk0": "GERMS.DSK", + "basic": "RUN\"GERMS\"\n" + }, + "0e086fde0f410cc7c0d6c32bd567fc36633945d2": { + "filename": "Reverse (Donald Clerk).zip", + "disk0": "REVERSE.DSK", + "basic": "RUN\"REVERSE\"\n" + }, + "7ddbd0f66114b48482e6a10f4dfc53c4fc2ae59e": { + "filename": "Reversi (Scott Nudds).zip", + "disk0": "REVERSI.DSK", + "basic": "RUN\"REVERSI\"\n" + }, + "42aeadec0bfc3d11e99320da2d65c6766ea0000f": { + "filename": "Revolution (InterAction).zip", + "disk0": "Revolution.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"%2B\"\n" + }, + "628866feab4abf470b0fea8ea8e8280f04cd6f74": { + "filename": "Riddle of Randomar, The (Robert Poppe).zip", + "disk0": "RANDOMAR.DSK", + "basic": "RUN\"BOOT\"\n" + }, + "abc159b315e9de0d3e65c15efbfa6ed0f449b491": { + "filename": "Ring Quest (L. Curtis Boyle).zip", + "disk0": "RNGQUEST.DSK", + "basic": "RUN\"BOOT\"\n" + }, + "82157da36fe6ebf03efe87858c3c43ad350144ce": { + "filename": "Ringquest (The Rainbow).zip", + "disk0": "RNGQUEST.DSK", + "basic": "RUN\"RNGQUEST\"\n" + }, + "05dbb9fff56260ff4f6400ddb7bcdcdda8b05940": { + "filename": "River of Fire (J. Morrison Micros) (Coco port).zip", + "disk0": "RIVER.DSK", + "basic": "LOADM\"RIVER\":EXEC\n" + }, + "b8c9eef2e5ea18773b6d93e373ccf86b47bfac81": { + "filename": "RL Video Slot Machine.zip", + "disk0": "RITELEFT.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"RITELEFT\":EXEC\n" + }, + "090eeb9a7dfda29643ab1650d536dab2cb8af79d": { + "filename": "Robin Hood (Pocket Money Software) (Coco port).zip", + "disk0": "ROBIN.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ROBIN\":EXEC\n" + }, + "ec80417a6343f9c9e549014bdeecbb869cd79480": { + "filename": "Robo Hang (The Peninsula Color Computer Club) (Coco 3).zip", + "machine": "coco3", + "disk0": "ROBOHANG.DSK", + "basic": "RUN\"BOOT\"\n" + }, + "497a7488fdacddd6b7905ebc2115e894b4150c34": { + "filename": "Robotack (Intracolor).zip", + "disk0": "ROBOTACK.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ROBOTACK\":EXEC\n" + }, + "5404c52e7f3cfd7a37a8695d78f960aa8e5e3a80": { + "filename": "Robotron (Glen Hewlett) (Coco Port) (Coco 3).zip", + "machine": "coco3", + "disk0": "ROBOTRON.DSK", + "joy-left": "kjoy0", + "joy-right": "mjoy0", + "basic": "RUN\"ROBOTRON\"\n" + }, + "297e0b8b487b626a743871e200d83b2cd3bd877f": { + "filename": "Robocop (Data East) (Coco 3).zip", + "machine": "coco3", + "disk0": "ROBOCOP.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"ROBOCOP\"\n" + }, + "82e06e1dd1b5f392580adf1f7409565a47766e52": { + "filename": "Robot Battle (Spectral Associates).zip", + "disk0": "ROBOT.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ROBOT\":EXEC\n" + }, + "cd6680148651c20f6be8a6b460bb16ceb2708153": { + "filename": "Robot Bomber (T&D Software).zip", + "disk0": "ROBOTBMR.DSK", + "joy-left": "mjoy0", + "joy-right": "kjoy0", + "basic": "LOADM\"ROBOTBMR\":EXEC\n" + }, + "8711e0d874c5caf71dd57b75bc735cdb57af9ffb": { + "filename": "Robots (T&D Software).zip", + "disk0": "ROBOTSTD.DSK", + "basic": "RUN\"ROBOTS\"\n" + }, + "a5117b4078879bedc9ed841ab2c72d5ad386bdd3": { + "filename": "Roman Checkers (Tandy).zip", + "disk0": "ROMAN.DSK", + "basic": "LOADM\"ROMAN\":EXEC\n" + }, + "964ac994349b50584ad6a8d344b8a5524334de78": { + "filename": "Roller Controller (Spectral Associates) (Coco 3).zip", + "machine": "coco3", + "disk0": "ROLLER.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"ROLLER\"\n" + }, + "c17462e8ceea4d47d684a3ee0a729f981b72806c": { + "filename": "Roller Controller (Spectral Associates) (Coco 3).zip", + "machine": "coco3", + "disk0": "ROLLER.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"ROLLER\"\n" + }, + "3a922761a7ec571381395013f5702085273cb07b": { + "filename": "Rogue (Tandy) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "ROGUE512.DSK", + "basic": "DOS\n" + }, + "9071a6e17fc33ff84cc3ff6afc858726c35a7c1a": { + "filename": "Rogue (Tandy) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "ROGUE512.DSK", + "basic": "DOS\n" + }, + "3aac28ae6f0e9c73bf726f14e2049b07ded53842": { + "filename": "Rommel 3D (Michtron).zip", + "disk0": "ROMMEL3D.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"ROMMEL\"\n", + "tv-input": "redblue" + }, + "14a1583a9a2f6813b55337f5267c48748d83e02d": { + "filename": "Rommel's Revenge (Design Design) (NTSC).zip", + "disk0": "ROMMELS.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ROMMELS\":EXEC\n" + }, + "a7bdc46388f3cecdd6c4cbad394b029f4026ae3a": { + "filename": "Rommel's Revenge (Design Design) (PAL).zip", + "machine": "coco", + "disk0": "ROMMELS.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ROMMELS\":EXEC\n" + }, + "e2e9fe79aa53d80a32cf79133ce78575567f3b6c": { + "filename": "Roulette (The Rainbow).zip", + "disk0": "roulette.dsk", + "basic": "RUN\"ROULETTE\"\n" + }, + "e31b87e00505865b4315e9a1ef20d67499f82482": { + "filename": "Rowboat (Chromasette).zip", + "disk0": "ROWBOAT.DSK", + "joy-left": "mjoy0", + "joy-right": "kjoy0", + "basic": "RUN\"ROWBOOT\"\n" + }, + "91aa5abb9cd100b84acc4b34b03c534929ac1a05": { + "filename": "Rubicon II (Ark Royal Games).zip", + "disk0": "RUBICON2.DSK", + "basic": "PCLEAR1:RUN\"RUBIIY\"\n" + }, + "9efdc88d8a3d2a791a7e3d05e8649af473faeca8": { + "filename": "Ruby Robba (Blaby) (Coco port).zip", + "disk0": "ROBBA.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ROBBA\":EXEC\n" + }, + "1499aff2fc7b82d3907349ba940828e3100ef84a": { + "filename": "Run Dino Run (Paul Fiscarelli) (Coco 3).zip", + "machine": "coco3", + "disk0": "DINORUN.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"DINORUN\":EXEC\n" + }, + "632cf8db261dc0b3f56e8b23b31c93fdc3b40343": { + "filename": "Roulette (T&D Software).zip", + "disk0": "RouletTD.dsk", + "basic": "RUN\"ROULETTE\"\n" + }, + "2349b4d2c36fdfe129b8b3e860f4fd85f8bc90d6": { + "filename": "Run For Your Life (The Rainbow).zip", + "disk0": "RUNLIFE.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"RUNLIFE\"\n" + }, + "9657f411a4a5d66943d28f2f8736f21b3adff303": { + "filename": "Rupert Rythm (Tandy, Game Point Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "RUPERT.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"RUPERT\"\n" + }, + "7241d80b92f8108ec8f12bc45c452f8a3cbfc82d": { + "filename": "Rush'n Assault (Diecom Products) (6809 optimized).zip", + "disk0": "RUSH69.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"RUSH\"\n", + "tv-input": "redblue" + }, + "0f71cdb5fa3537779e2d4361df0b8b0a51a98f7b": { + "filename": "Saigon (Adventure International).zip", + "disk0": "SAIGON.DSK", + "basic": "LOADM\"SAIGON\":EXEC\n" + }, + "5160bd11953ed49c8c10762ee28af73d358e8203": { + "filename": "Rush'n Assault (Diecom Products).zip", + "disk0": "RUSH.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"RUSH\"\n", + "tv-input": "redblue" + }, + "fe8a52212d7e3e3a6e60a411fe4a23a62f98d609": { + "filename": "Rush'n Assault (Diecom Products).zip", + "disk0": "RUSH.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"RUSH\"\n", + "tv-input": "redblue" + }, + "55aa2fdc3176ba003650dee1f7dabe5976262c16": { + "filename": "Sailor Man (Tom Mix Software).zip", + "disk0": "Sailor Man.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"SAILOR\"\n", + "tv-input": "redblue" + }, + "273cf37dca99ee9dc4dd6a1a4d72b142346b2abd": { + "filename": "Sailor Man (Tom Mix Software).zip", + "disk0": "Sailor Man.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"SAILOR\"\n", + "tv-input": "redblue" + }, + "7670847c05e45096b19278348195dea0fab5a002": { + "filename": "Sam Diamond PI (Moreton Bay Software).zip", + "disk0": "SAMDIAM.DSK", + "basic": "LOADM\"CRIME\":EXEC\n" + }, + "9159472767ed08e3ae5185caa89234db0bee3259": { + "filename": "Sand Rover (T&D Software).zip", + "disk0": "ROVER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ROVER\":EXEC\n" + }, + "9d30a819adb708a1217719c3485eee58f9b49498": { + "filename": "Sands of Egypt (Tandy).zip", + "disk0": "sands.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"EGYPT\"\n", + "tv-input": "redblue" + }, + "8fd28f2f2ce2b06b6aafac8bb3b6530db3da40b2": { + "filename": "Sands of Egypt (Tandy).zip", + "disk0": "sands.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"EGYPT\"\n", + "tv-input": "redblue" + }, + "246f3179c717536daba83e498e85763a1dd4320a": { + "filename": "Scarfman (The Cornsoft Group).zip", + "disk0": "SCARFMAN.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SCARFMAN\":EXEC\n" + }, + "6fa84fdf4ea74f8472d705bc176fda1a36db2cd8": { + "filename": "Sam Sleuth (Computerware).zip", + "disk0": "Sam Sleuth (alt 1).dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"SLEUTH1\":EXEC\n", + "tv-input": "redblue" + }, + "aaed6fc39909778afa48afe48e90bbaa6147f6b5": { + "filename": "Sam Sleuth (Computerware).zip", + "disk0": "Sam Sleuth (alt 1).dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"SLEUTH1\":EXEC\n", + "tv-input": "redblue" + }, + "9205fe43eaa8606bf7bf3739e0152f74aa807cab": { + "filename": "Sam Sleuth (Computerware).zip", + "disk0": "Sam Sleuth (alt 1).dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"SLEUTH1\":EXEC\n", + "tv-input": "redblue" + }, + "f84aed32b1c40d9073776008a262717a0d19b560": { + "filename": "Scepter of Kzirgla (Rainbow Connection Software).zip", + "disk0": "KZIRGLA.DSK", + "basic": "RUN\"SCEPTER\"\n" + }, + "fb93329d08828ae8aaefa328a9cb8fddd30dbda0": { + "filename": "Scrabble (Eversoft Games) (Coco 3).zip", + "machine": "coco3", + "disk0": "Scrabble.dsk", + "basic": "RUN\"SCRABBLE\"\n" + }, + "dba0d680b80149874d1f1117ef2db371f80e6296": { + "filename": "Scrabble (T&D Software).zip", + "disk0": "SCRABBLE.DSK", + "basic": "RUN\"SCRABBLE\"\n" + }, + "e5eff04e77566cdd45df354fe7c73becfc3775c0": { + "filename": "Scramble (Tom Mix Software).zip", + "disk0": "SCRAMBLE.DSK", + "basic": "LOADM\"SCRAMBLE\":EXEC\n" + }, + "f973be7174a8fc6fbe6e46852bc17622ac4b008f": { + "filename": "Scepter of Ursea (Prickly Pear Software).zip", + "disk0": "URSEA.DSK", + "basic": "RUN\"URSEA\"\n" + }, + "ddcf273816889e89ca56a0f382d99a2061871e79": { + "filename": "Scepter of Ursea (Prickly Pear Software).zip", + "disk0": "URSEA.DSK", + "basic": "RUN\"URSEA\"\n" + }, + "f03818d283741d789b32c481408fe77bdd5ff56e": { + "filename": "Scramble (Tom Mix Software) (alt).zip", + "disk0": "SKRAMBLE.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SKRAMBLE\":EXEC\n" + }, + "c0831b2d4e850a8a4230b79d8e5f5c8a68f1f932": { + "filename": "Sea Dragon (Adventure International) (alt).zip", + "disk0": "SEADRAGN.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SEADRAGN\":EXEC\n" + }, + "0a8ce0a26bf46a35a2fbbc2dccaa27d1c1ea0cf1": { + "filename": "Sea Quest (Mark Data Products).zip", + "disk0": "SEAQUEST.DSK", + "basic": "LOADM\"SEAQUEST\":EXEC\n", + "tv-input": "redblue" + }, + "0d6dadd7913c11a3914c55d8f7166e8d12c3355b": { + "filename": "Sea Dragon (Adventure International).zip", + "disk0": "SEADRAG.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SEADRAG\":EXEC\n" + }, + "11d16f91ddd9976be521a8d00fbafe8f29d9c05f": { + "filename": "Search for Almazar, The (Hot Coco).zip", + "disk0": "almazar.dsk", + "basic": "RUN\"ALMAZAR\"\n" + }, + "220dfca446a445386b1ab38e7ced763b09287cbf": { + "filename": "Searching for Daryl (Tim Hartnell) (Coco 3).zip", + "machine": "coco3", + "disk0": "DARYL.DSK", + "basic": "RUN\"DARYL\"\n" + }, + "07885083b6ac50eab8e639b5bded5fb7387c258b": { + "filename": "Sea Search (Mark Data Products).zip", + "disk0": "SEASEARC.DSK", + "basic": "LOADM\"SEASEARC\":EXEC\n", + "tv-input": "redblue" + }, + "e7ae301d2f670ad05d9016d3cc80a88eec0dbb13": { + "filename": "Secret Agent Man (David L. Dawson).zip", + "disk0": "AGENT.DSK", + "basic": "RUN\"AGENT\"\n" + }, + "3f60b201fc028d957e8b1ba1f28cc335918dc791": { + "filename": "Sea War (The Rainbow).zip", + "disk0": "SEAWAR.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"SEAWAR\"\n" + }, + "ed2324601b1aebcdba854ed27d822207d807104a": { + "filename": "Sex & Violence (Circle City Software).zip", + "disk0": "SEX&VIOL.DSK", + "basic": "RUN\"SEX&VIOL\"\n" + }, + "531f7aadccad134db6ba0f7373b803377a260b04": { + "filename": "Seiddab Attack (Hewson Consultants Ltd) (Coco port).zip", + "disk0": "SEIDDAB.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SEIDDAB\":EXEC\n" + }, + "657401fdc1d33700cb21c085c857af8a6b23cb4c": { + "filename": "Shaft (Prickly-Pear Software).zip", + "disk0": "SHAFT.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SHAFT\":EXEC\n" + }, + "4fb1f75680bd980775caeeae702f1c1664ec885d": { + "filename": "Shanghai (Tandy) (Coco 3).zip", + "machine": "coco3", + "disk0": "SHANGHAI.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"SHANGHAI\":EXEC\n" + }, + "108c23e9d74a82084736359c10b73ddae5c5a879": { + "filename": "Shamus (Tandy).zip", + "disk0": "SHAMUS.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SHAMUS\":EXEC\n" + }, + "a2f297180efbb636005fb635d05323c3693f0560": { + "filename": "Shamus (Tandy).zip", + "disk0": "SHAMUS.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SHAMUS\":EXEC\n" + }, + "bba008213ec975fc5c6d76c38118c303dc44035a": { + "filename": "Shark Treasure (Computerware).zip", + "disk0": "SHARK.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"SHARK\":EXEC\n" + }, + "90c8a9fa7c5f44ab3e6650ca9417bc91c3501e45": { + "filename": "Shenanigans (Mark Data Products).zip", + "disk0": "SHENANI.DSK", + "basic": "LOADM\"SHENANI\":EXEC\n", + "tv-input": "redblue" + }, + "64ea6b0bd7f582b021545b396bc39b4851fa41cf": { + "filename": "Shanghai (Earther Enterprises) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "shanghai.dsk", + "joy-right": "mjoy0", + "basic": "DOS\n" + }, + "4845d9ca909e69a4008a754d36fcae86ee53d5f6": { + "filename": "Shooting Gallery (Tandy).zip", + "disk0": "SHOOT.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SHOOT\":EXEC\n" + }, + "c33319a3cb17f2e9b8a73f767d1ad09921f8011d": { + "filename": "Shiphunt (Free Coco Software).zip", + "disk0": "SHIPHUNT.DSK", + "basic": "LOADM\"SHIPHUNT\":EXEC\n" + }, + "000da96d5f1436e8837fc5cc2584f0202bbc5c6d": { + "filename": "Shock Trooper (Cheat) (Mark Data Products).zip", + "disk0": "TROOPER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"TROOPER\":EXEC\n" + }, + "dac1cf81a705ad3eb8d6f1c7d2eb53ef10762ab5": { + "filename": "Shock Trooper (Mark Data Products).zip", + "disk0": "SHOCK.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SHOCK\":EXEC\n" + }, + "70021c33058f03a6d1a6f600c86c949b1d203c6f": { + "filename": "Shoot'n Range (Albert Marsh) (Coco 3).zip", + "machine": "coco3", + "disk0": "SHOOTN.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"SHOOTN\"\n" + }, + "208a31539c72c8baf13840bc016390254bb93134": { + "filename": "Shootout (Justin Lipton).zip", + "disk0": "SHOOTOUT.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SHOOTOUT\":EXEC\n" + }, + "353e7dee76a8000417f3453051663e71bb67a4ea": { + "filename": "Shootout at the OK Galaxy (Avalon Hill) (SG-8) (Coco 1-2).zip", + "disk0": "SHOOTOUT.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"BOOT\"\n" + }, + "425f5d2a676cb856629d3bd7d14ea0f22c7facb1": { + "filename": "Shuffle (Phil Beistel).zip", + "disk0": "SHUFFLE.DSK", + "basic": "RUN\"SHUFFLE\"\n" + }, + "b0426a6c7760a97128866bb62fbffaf430c33729": { + "filename": "Shuttle Simulator (Tom Mix Software).zip", + "disk0": "SHUTTLE.DSK", + "basic": "LOADM\"SHUTTLE\":EXEC\n" + }, + "3edd9a08264da9682deddb9a4e2d4e42c386b455": { + "filename": "Shrink (Star-Kits).zip", + "disk0": "SHRINK.DSK", + "basic": "LOADM\"SHRINK\":EXEC\n" + }, + "d9b6295083a6fc168094f19d7ce2aef42543d71b": { + "filename": "Sidney (KLG Systems) (Coco 3).zip", + "machine": "coco3", + "disk0": "sidney.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"SIDNEY\"\n" + }, + "ddd1f04ef690181e46cc548ef18df9e3d009346a": { + "filename": "Skiing (Tandy).zip", + "disk0": "SKIING.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SKIING\":EXEC\n" + }, + "2b9adf87f3ff54778a6db5a8672ce3416e092c16": { + "filename": "Skid-Row Adventures (Microdeal).zip", + "disk0": "skidrow.dsk", + "basic": "RUN\"SKID-ROW\"\n" + }, + "b0906eb7fcdcb1ff42c40d565b3a4fc99ff90bff": { + "filename": "Simply Better Blackjack (Alison deNu).zip", + "disk0": "SIMJACK2.DSK", + "basic": "RUN\"SIMJACK2\"\n" + }, + "650ccafa61e7a17f02ae8f2af68a61dfae4f9c06": { + "filename": "Sky-Defense (Quasar Animations).zip", + "disk0": "SKY-DEF.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"SKY-DEF\":EXEC\n" + }, + "3c182b14f4e3cad7a1e4e06cc784cacae4a3d95f": { + "filename": "Silpheed (Tandy) (Coco 3).zip", + "machine": "coco3", + "disk0": "SILPHEED.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"SILPHEED\"\n" + }, + "9007b389004a00f6f2d3e2c6884d2f2d7b12d255": { + "filename": "Skyway (Tom Mix Software).zip", + "disk0": "SKYWAY.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SKYWAY\":EXEC\n", + "tv-input": "redblue" + }, + "db7bdb477b15caff33c4bd9835d76044fcd51923": { + "filename": "Slashball (Aardvark).zip", + "disk0": "SLASH.DSK", + "basic": "RUN\"SBALL\":EXEC\n" + }, + "1d863c92af898849b04ef23e590da560332ccbcd": { + "filename": "Slay the Nereis (Tandy).zip", + "disk0": "NEREIS.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"NEREIS\":EXEC\n" + }, + "612534b9901048d3bf3c4c4181e3a288b8aa20f5": { + "filename": "Slither (Public Domain).zip", + "disk0": "SLITHER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SLITHER\":EXEC\n" + }, + "459a65fa278e70ec83f0f58b7f6d7592d61233e5": { + "filename": "Slots (Public Domain).zip", + "disk0": "SLOTS.DSK", + "basic": "LOADM\"SLOTS\":EXEC\n" + }, + "72589f1517f4f6552c148a4e2533b15b831880da": { + "filename": "Smash (T&D Software).zip", + "disk0": "SMASH.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SMASH\":EXEC\n" + }, + "12021e90311eb76a1e693f0426aae24923e73283": { + "filename": "Sluzzle (John W. Linville) (Coco 3).zip", + "machine": "coco3", + "disk0": "sluzzle.dsk", + "basic": "RUN\"SLUZZLE\"\n" + }, + "d9c4ad1b85e4d4eb2feaf01c21bcdd69023845e7": { + "filename": "Snafus (T&D Software).zip", + "disk0": "snafus.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"SNAFUS\":EXEC\n" + }, + "16ebf557e2faefc52ac9dadd8abe02310f62f4b2": { + "filename": "Slots & Cards (MicroDeal USA) (Coco 3).zip", + "machine": "coco3", + "disk0": "SLOTCRD3.DSK", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "389340745e5fe60819a1aa7a512f0f94b5f4a244": { + "filename": "Slots & Cards (MicroDeal USA) (Coco 3).zip", + "machine": "coco3", + "disk0": "SLOTCRD3.DSK", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "0d36b13968bdbcb8ff97a234af5bda30e5cd3683": { + "filename": "Slots & Cards (MicroDeal USA) (Coco 3).zip", + "machine": "coco3", + "disk0": "SLOTCRD3.DSK", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "cb646b4625b659fa1e86e48c83232c19d9910aae": { + "filename": "SOKO64+ (Emanuele Feronato & Marco Spedaletti).zip", + "disk0": "SOKO64.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"SOKO64\":EXEC\n" + }, + "27afd0ee9f7efb7151469229dac9d45d9665314d": { + "filename": "Sneaky Snake (Peter Kerckhoff).zip", + "disk0": "SNEAKY.DSK", + "joy-left": "kjoy0", + "basic": "RUN\"SNEAKY\"\n" + }, + "a3999a12ee1fe491a6447698fd826f15e8706617": { + "filename": "SnakeByte (Domenic Troilo) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "snakebyte.dsk", + "basic": "DOS\n" + }, + "e936b44be3c4217ba38621f195b0c435005be170": { + "filename": "Snak-Pac (Tom Mix Software).zip", + "disk0": "SNAKPAC.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SNAKPAC\":EXEC\n" + }, + "817277a8dd878a4279c50bc674aef5560c6e4233": { + "filename": "SOKO64+ (Emanuele Feronato & Marco Spedaletti) (Coco 3).zip", + "machine": "coco3", + "disk0": "SOKO64C3.DSK", + "joy-left": "kjoy0", + "basic": "RUN\"LOADER\"\n" + }, + "2e4837c50519129b9aa13625b1a4ddd86678c9d5": { + "filename": "Sokoban (Tandy) (Coco 1-2) (Coco 3).zip", + "machine": "coco3", + "disk0": "SOKOBAN.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SOKOBAN\":EXEC\n" + }, + "06aaf4e9ede4377fa4b19b24c09b60beb3e0f2a8": { + "filename": "Sokoban 1 (Wayne Campbell) (Coco 3).zip", + "machine": "coco3", + "disk0": "SOKOBAN.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"SOKOBAN\"\n" + }, + "a703afe8de47441e7f79b0a8492059416609952c": { + "filename": "Snake Pit (SRB Software).zip", + "disk0": "Snake Pit (SRB Software)/SNAKEPIT.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"SNAKE\":EXEC\n" + }, + "de176e7f4b343f1089f198d8e6f8bd998dc9d29a": { + "filename": "Snake Pit (SRB Software).zip", + "disk0": "Snake Pit (SRB Software)/SNAKEPIT.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"SNAKE\":EXEC\n" + }, + "d757673e90d3cad97c9374070f4a70a08d013842": { + "filename": "Solgan's Salvation (Craig Springett).zip", + "disk0": "SOLGAN.DSK", + "basic": "RUN\"BOOT\"\n" + }, + "fb7bf274165a08ddadbb92baf1a779d941d48f85": { + "filename": "Solitaire (Public Domain) (Coco 3).zip", + "machine": "coco3", + "disk0": "SOLITAIR.DSK", + "basic": "RUN\"SOLITAIR\"\n" + }, + "4d5b490dd355d1a35efb5e88253a0c90c50e34f8": { + "filename": "Solitaire (Tandy).zip", + "disk0": "SOLITARE.DSK", + "basic": "RUN\"SOLITARE\"\n" + }, + "ed783705237ff3baaa886633b9f4a5fc814d3a57": { + "filename": "Solo Poker (Tandy).zip", + "disk0": "SOLOPKR.DSK", + "basic": "RUN\"SOLOPKR\"\n" + }, + "81af7f89c54edcf8ce016f755a02052c973fe58d": { + "filename": "Solitaire (Torsten Dittel).zip", + "disk0": "solitair.dsk", + "joy-right": "mjoy0", + "basic": "RUN\"SOLITAIR\"\n" + }, + "fb81ea8b974d2c9c72dff0aecf883a26bae98d9b": { + "filename": "Solo Poker (T&D Software).zip", + "disk0": "SOLOPKR.DSK", + "basic": "RUN\"SOLOPKR\"\n" + }, + "fa8947f17872afa6e1a5e8dec5bd6d717903f430": { + "filename": "Solo Pool (Tom Mix Software).zip", + "disk0": "SOLOPOOL.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"SOLOPOOL\"\n" + }, + "49e6ee904f304c652e9c0eb4672633368dc109a5": { + "filename": "Soooper Pac (Bear Bones Software).zip", + "disk0": "SOOPER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SOOPER\":EXEC\n" + }, + "375f1774c5858703d4cbb9568c4e6d26330dd8ec": { + "filename": "Space Ace (CLOAD).zip", + "disk0": "SPACEACE.DSK", + "basic": "LOADM\"SPACEACE\":EXEC\n" + }, + "201bc2b4ba4adf2487cd9ce38ccb17988a7a1518": { + "filename": "Soviet Bloc Demo (Strongware) (Coco 3).zip", + "machine": "coco3", + "disk0": "BLOCDEMO.DSK", + "basic": "LOADM\"BLOCDEMO\":EXEC\n" + }, + "a1f75a3958e89fc2dc3006dc6f692c983e730f28": { + "filename": "Sokoban 1 (Wayne Campbell) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "sokoban1.dsk", + "joy-right": "mjoy0", + "basic": "DOS\n" + }, + "c1d6ef47775454ac78c7855dab60ba63870d631f": { + "filename": "Sokoban 1 (Wayne Campbell) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "sokoban1.dsk", + "joy-right": "mjoy0", + "basic": "DOS\n" + }, + "0c80f4beadf66a8c9630dc9b013110b0ab28f2c8": { + "filename": "Space Ambush (Computerware).zip", + "disk0": "AMBUSH.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"AMBUSH\":EXEC\n" + }, + "7dea7e95d7ea1761d6c511e462c53c86fda9f809": { + "filename": "Space Ambush Original Promotional Copy (Andy Kluck).zip", + "disk0": "AMBPROMO.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"AMBPROMO\":EXEC\n" + }, + "11e8b7be70503c61b8ad32a41b3676bc5d5ac557": { + "filename": "Space Assault (Tandy).zip", + "disk0": "ASSAULT.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"ASSAULT\":EXEC\n" + }, + "7b199930d286a25738b0e1158039f530c9ff908d": { + "filename": "Space Escape (Computer Hut Software).zip", + "disk0": "s-escape.dsk", + "basic": "RUN\"S-ESCAPE\"\n" + }, + "4068d531ffde75004dc2bfbb055a8d90b4d5d2f8": { + "filename": "Spaced Invaders (Stuart Wyss-Gallifent).zip", + "machine": "coco3", + "disk0": "SPACED.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SPACED\":EXEC\n" + }, + "619dee2288f1fa1cec6136196405f8fec6941821": { + "filename": "Space Intruders (Radio Shack, Game Point Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "spaceint.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"SPACE\"\n" + }, + "42eee9455730f646ea31fdf98389de71f277d0bc": { + "filename": "Space Hawk (Public Domain).zip", + "disk0": "HAWK.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"HAWK\":EXEC\n" + }, + "a49de54f9fba37b3d69939fa5550926332df7f4c": { + "filename": "Space Intruders (Adventure International).zip", + "disk0": "SPCINTR.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"INTRUDER\"\n" + }, + "bb47a5f42920b3f3b88e71f12e06c25a5bb2db88": { + "filename": "Space Bandits 0.16 (Jamie Cho) (Coco 3).zip", + "machine": "coco3h", + "disk0": "BNDT6309.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"BANDITS\":EXEC\n", + "tv-input": "bluered" + }, + "46227e5de67196934cd65041ee37e33e99c03e0f": { + "filename": "Space Bandits 0.16 (Jamie Cho) (Coco 3).zip", + "machine": "coco3h", + "disk0": "BNDT6309.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"BANDITS\":EXEC\n", + "tv-input": "bluered" + }, + "32eecf337ffda0e77bb7649a3545aad7e4a82fc5": { + "filename": "Space Marauder 1.0 (Tandy) (Coco 3).zip", + "machine": "coco3", + "disk0": "MARAUDER.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"MARAUDER\":EXEC\n" + }, + "108a45348a005c210ed30a84e71949986de0efc8": { + "filename": "Space Invaders 8080 to 6809 port (Glen Hewlett) (Coco 3).zip", + "machine": "coco3", + "disk0": "Disk.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"SI\":EXEC\n" + }, + "b84542df5f713d562637ac019ebc6c86b5a8daa5": { + "filename": "Space Marauder 2.0 (Tandy) (Coco 3).zip", + "machine": "coco3", + "disk0": "MARAUDER.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"MARAUDER\":EXEC\n" + }, + "538e7246b8d2e2057a83333364eed2f2e0c049c8": { + "filename": "Space Invaders Alpha v0.9 (Mark McDougall) (Coco 3).zip", + "machine": "coco3", + "disk0": "SPACEINV.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"SI\"\n" + }, + "09275805a90e369f2c64b2a76b4b7b5fedce40f7": { + "filename": "Space Merchant (GOSUB Internatonal).zip", + "disk0": "SPCEMERC.DSK", + "basic": "RUN\"SPCEMERC\"\n" + }, + "d56f1babfa8baa33d1cdd7dcd74dbf9f5e90d972": { + "filename": "Space Protector (Hewson Software).zip", + "disk0": "SPACPROT.DSK", + "basic": "LOADM\"SPACPROT\":EXEC\n" + }, + "d644b52ca2c325f704f19ce4d05a2d788a782836": { + "filename": "Space Race (Spectral Associates).zip", + "disk0": "SPACERAC.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SPACERAC\":EXEC\n" + }, + "a96153f2d42096218e5da850d194d898a090b9d4": { + "filename": "Space Raider (T&D Software).zip", + "disk0": "RAIDER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"RAIDER\":EXEC\n" + }, + "b931853defa47de9669ab9b883e3ed50a2fa8e3d": { + "filename": "Space Raiders (John Crawford).zip", + "disk0": "SRAIDERS.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SRAIDERS\":EXEC\n" + }, + "7789f1c91e48908befc8489085b44d52e2e2b606": { + "filename": "Space Raiders (Mark Data Products).zip", + "disk0": "SRAIDERS.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"SRAIDERS\":EXEC\n" + }, + "45a670007ee566c28eda13875afc2605a2b2c361": { + "filename": "Space Sentry (Spectral Associates).zip", + "disk0": "SENTRY.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SENTRY\":EXEC\n" + }, + "ce61607860440f13a3d1852a17d803714e6e09b8": { + "filename": "Spacewar! 1.0 (Rich Natili).zip", + "disk0": "SWDISK.dsk", + "basic": "LOADM\"SPWAR21\":EXEC\n" + }, + "183e7035876ae23781b446faa52a2dcdc4a36cda": { + "filename": "Spacewar (Jim Jewett).zip", + "disk0": "Spacewar.dsk", + "basic": "RUN\"SPACEWAR\"\n" + }, + "0888fd9b4d3fd9121f8bacb2b703fb0b65e7c908": { + "filename": "Space Zapper (Aardvark-80).zip", + "disk0": "ZAPPER.DSK", + "basic": "RUN\"ZAPPER\"\n" + }, + "41da83b418cc1134bfe0fc1e7b8493956e039593": { + "filename": "Spacewar! 2.0 (Rich Natili).zip", + "disk0": "swdisk2.dsk", + "basic": "LOADM\"SPWARV2\":EXEC\n" + }, + "2bb124abbe614a016998d5b8046ee85db6f5a71a": { + "filename": "Space War (ASBC).zip", + "disk0": "SPACEWAR.DSK", + "joy-left": "mjoy0", + "joy-right": "kjoy0", + "basic": "LOADM\"SPACEWAR\":EXEC\n" + }, + "ae39fbc59d4cf3e8f6b6787e7d936800457a46ae": { + "filename": "Space War (Spectral Associates).zip", + "disk0": "SPACEWAR.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SPACEWAR\":EXEC\n" + }, + "f8c123d3c6b9d516812439cf53130c981726b652": { + "filename": "Space Wrek (Spectral Associates) (SSC).zip", + "disk0": "WREK.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"WREK\":EXEC\n" + }, + "807328d5c7d933f0aa009c28150ea0be7df702ac": { + "filename": "Speed Racer (Michtron).zip", + "disk0": "S-RACER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"S-RACER\":EXEC\n" + }, + "145b19acc67f3965f7ff27fb6ca57767eae6806d": { + "filename": "Spectrum Adventure Generator (Spectrum Projects).zip", + "disk0": "ADV-GEN.DSK", + "basic": "RUN\"SAG\"\n" + }, + "49340c394aa4f609a7b764fbdc0cda857aff1edc": { + "filename": "Spellbound (Thor Software).zip", + "disk0": "SPELLBND.DSK", + "basic": "RUN\"S\"\n" + }, + "d6cdaece9c61f1468678c5945d617b8976ca7ef1": { + "filename": "Spidercide (Tandy).zip", + "disk0": "SPIDER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SPIDER\":EXEC\n" + }, + "570b280b3def4b5cdd1356ba2111e98487d5a1bf": { + "filename": "Spider-Hype (Roger Taylor) (Coco 3).zip", + "machine": "coco3", + "disk0": "SPIDER.DSK", + "basic": "LOADM\"SPIDER\":EXEC\n" + }, + "cbd1f8e5fa886153734f18d0df48b01fd6783c3c": { + "filename": "Spell Down (WKM Softwate) (Coco 3).zip", + "machine": "coco3", + "disk0": "spelld.dsk", + "basic": "RUN\"WORD\"\n" + }, + "69ed445e8d58dbb46a1c8605e90fdfdde987f9ce": { + "filename": "Spider-Hyper (Roger Taylor) (6309) (Coco 3).zip", + "machine": "coco3h", + "disk0": "SPID6309.DSK", + "basic": "LOADM\"SPID6309\":EXEC\n" + }, + "a3ba75b1b1aecc7f0bdcbdf22b7aa9efb173815f": { + "filename": "Splinter (Jamie Leecho) (Coco 3).zip", + "machine": "coco3", + "disk0": "Splinter1.dsk", + "basic": "RUN\"SPLINTER\"\n" + }, + "790d99b4f1355b60011b0c6f4a73a4f90f7e68ec": { + "filename": "Springster (Tandy) (Coco 3).zip", + "machine": "coco3", + "disk0": "SPRING.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SPRING\":EXEC\n" + }, + "3d08f20514508e3d79297bc91535df6aecab45c4": { + "filename": "Spy Against Spy (Pulser) (Coco port).zip", + "disk0": "SPY.DSK", + "joy-right": "kjoy0", + "basic": "CLEAR10:LOADM\"SPY\":EXEC\n" + }, + "7734213cc424d8e30244a8b148a671cd5c333ac1": { + "filename": "Spy Hunter v2 (Rich Natili).zip", + "disk0": "SPYHUNT.DSK", + "joy-right": "kjoy0", + "joy-left": "mjoy0", + "basic": "RUN\"SH20\"\n" + }, + "60a489d2d4d4a51ad2698adcdac20a666dcdd38a": { + "filename": "Spymaster (Scott McCleary).zip", + "disk0": "SPYMASTR.DSK", + "basic": "RUN\"BOOT\"\n" + }, + "73ac6f41ae35f3797fb877cbb6957dee5b7b7031": { + "filename": "Squares (T&D Software).zip", + "disk0": "SQUARE.DSK", + "basic": "LOADM\"SQUARE\":RUN\n" + }, + "8bb2fc0f54c6a4bc4731e083485e3a6c033497cf": { + "filename": "Squash (T&D Software).zip", + "disk0": "SQUASH.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"SQUASH\":EXEC\n" + }, + "c49426d9e1ebef8a5a74aabb5a5b3da9ede3a8ea": { + "filename": "Squeeze (Real Software Company).zip", + "disk0": "SQUEEZE.DSK", + "basic": "RUN\"SQUEEZE\"\n" + }, + "2d6025f320178633c1333c654229e60c1650be84": { + "filename": "SR-71 (Tom Mix Software).zip", + "disk0": "SR-71.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"SR71\"\n" + }, + "47d0c3d2fee03dc1bc24dac4bf6ba77e8f9e666b": { + "filename": "Stalin Grad (Ark Royal Software).zip", + "disk0": "STALIN.DSK", + "basic": "RUN\"RUSSIA\"\n", + "tv-input": "redblue", + "notes": "At the OK prompt type RUN and press ENTER." + }, + "344bd263cec54d5fc702c8490eb04e7d31270e4f": { + "filename": "Star Blaster (Micro Works).zip", + "disk0": "BLASTER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"BLASTER\":EXEC\n" + }, + "76cd53ab2c39d2265ce68d85fa5af8f24571511e": { + "filename": "Star Fighter (Aardvark Action Software).zip", + "disk0": "STRFIGHT.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"STRFIGHT\":EXEC\n" + }, + "8579a28623e2ae45de0beb0c46aa1b700a4e673b": { + "filename": "Star Blaze (Tandy).zip", + "disk0": "STARBLAZ.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"STARBLAZ\":EXEC\n" + }, + "469189d7ce12181402fb97c0e8a4e2f4d5d5c503": { + "filename": "Starbase Attack (Illustrated Memory Banks).zip", + "disk0": "STARBASE.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"STARBASE\"\n" + }, + "5a48d0dba63a83dd6a699346e32a592fe1265a4e": { + "filename": "Starfighter (John Morrison) (SG-8 intro).zip", + "disk0": "SFIGHTER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SFIGHTER\":EXEC\n" + }, + "504d97ea1d84f7c479a2210aea22b5d51f24a6f5": { + "filename": "Starblazer (Ark Royal Games).zip", + "disk0": "STARBLZR.DSK", + "basic": "RUN\"STAR\"\n" + }, + "c1f4402a691601c0606dfc5f05f377eced39b064": { + "filename": "Star Lanes (Martyn Phillips) (Coco 3).zip", + "machine": "coco3", + "disk0": "STARLANE.DSK", + "basic": "RUN\"STARLANE\"\n" + }, + "0f4ca570a9eb210536b009bfcdd51be9555ae0fb": { + "filename": "Starfire (Intellectronics).zip", + "disk0": "STARFIRE.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"STARFIRE\":EXEC\n" + }, + "ab531570beed9170552486cdf7e969ab081ad204": { + "filename": "Starship Chameleon (Computerware).zip", + "disk0": "STARSHIP.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"STARSHIP\":EXEC\n" + }, + "4ead175f81311287419f6e9f55b982c10f151c96": { + "filename": "Starship Control (Bill Barbe).zip", + "disk0": "STARSHIP.DSK", + "basic": "RUN\"STARSHIP\"\n" + }, + "2f186eb752050c6f8ff85fbfccb338f9685780a2": { + "filename": "Starship Falcon (Cer-Comp).zip", + "disk0": "STARFALC.DSK", + "basic": "RUN\"ADVENT\"\n" + }, + "8553f3044ec0473f767dccc53aec4e83d0746da7": { + "filename": "Star Skid (T&D Software).zip", + "disk0": "STARSKID.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"STARSKID\":EXEC\n" + }, + "5fa8c1f378805e212b99ab510daf8d26672d755a": { + "filename": "Star Swoop (Blaby Computer Games) (Coco port) (SG-8) (Coco 1-2).zip", + "disk0": "swoop.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"SWOOP\":EXEC\n" + }, + "4af4d30471a92347e9b177c591ea01ba1ce9ed59": { + "filename": "Star Spores (Spectral Associates) (alt).zip", + "disk0": "STARPORE.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"STARPORE\":EXEC\n" + }, + "87295942d52cdbfbb97e2fb6eaa88cc5aca6ed92": { + "filename": "Star Spores (Spectral Associates).zip", + "disk0": "SPORES.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SPORES\":EXEC\n" + }, + "1fd678dcc1929285b3a4c4ea1f8cd3e567e3c774": { + "filename": "Star Trek Adventure #2 (Howard F. Batie).zip", + "disk0": "TREKADV2.DSK", + "basic": "PCLEAR1:RUN\"TREKADV2\"\n" + }, + "230f5453aa3a1554a21494819f48e7125212a306": { + "filename": "Star Trader (Computerware).zip", + "disk0": "TRADER.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"TRADER\":EXEC\n" + }, + "770b196e034cd4a99dca1f98e937c2f7dc4b1a9d": { + "filename": "Star Trek Adventure.zip", + "disk0": "TREKADV.DSK", + "basic": "RUN\"TREKADV\"\n" + }, + "a73b7e393c381ed866b0b7bd5353653755a76216": { + "filename": "Star Trek III 4.00 (Adventure International).zip", + "disk0": "TREKIII.DSK", + "basic": "RUN\"TREKIIID\"\n" + }, + "0556042b07e8dc0a0817de8ac2e80e5508e98186": { + "filename": "Star Trek Mission Simulation (Binary Systems) (Coco 3).zip", + "machine": "coco3", + "disk0": "TREKSIM.DSK", + "basic": "RUN\"TREKKIE\"\n" + }, + "dc61b4e2c5c2f12b2625810466e46fc898401665": { + "filename": "Star Trek Trivia 2.0 (Chris Presley).zip", + "disk0": "TREK20.DSK", + "basic": "RUN\"TREK20\"\n" + }, + "b6291acb376fd58ad05b71628ee9727fcf03794d": { + "filename": "Star Trek Trivia (Chris Presley).zip", + "disk0": "TREKTRIV.DSK", + "basic": "RUN\"TREKTRIV\"\n" + }, + "75f3545de35b72f750dd59c545da37203447fa94": { + "filename": "Starwars (T&D Software).zip", + "disk0": "STARWARS.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"STARWARS\"\n" + }, + "eaa1380edb9db5e13efcfb9f743f7701a8cd7716": { + "filename": "Startrek (Tom Mix Software).zip", + "disk0": "STARTREK.DSK", + "basic": "RUN\"TREK-16\"\n" + }, + "4907219bee585604bde8f395de72b946753799a4": { + "filename": "Stellar Empire (Chromasette).zip", + "disk0": "STELLEMP.DSK", + "basic": "RUN\"STELLINS\"\n" + }, + "2c66765582498eb24b676e8c4d075fb443fe456c": { + "filename": "Stellar Lifeline (Tandy).zip", + "disk0": "LIFELINE.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"LIFELINE\":EXEC\n" + }, + "3980071b0f906d46aec7e8d243d8cf9a8c8f4efd": { + "filename": "Steps (T&D Software).zip", + "disk0": "STEPS.DSK", + "basic": "LOADM\"STEPS\":EXEC\n" + }, + "27266790db0f9e160ec8ff94fbf87595ca1c36c2": { + "filename": "Stellar Search (Owlware).zip", + "disk0": "stellar.dsk", + "basic": "RUN\"INTRO\":EXEC\n" + }, + "9a30208fa443859b37631a275f0a95083005a374": { + "filename": "Stinger (Eigen Systems).zip", + "disk0": "STINGER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"STINGER\":EXEC\n" + }, + "347d89282de77030e9a9def0f08ffd0869c63288": { + "filename": "Stockticker 88 (The Rainbow) (Coco 3).zip", + "machine": "coco3", + "disk0": "STOCK88.DSK", + "basic": "RUN\"STOCKS3\"\n" + }, + "eabc13ad70b9dda3c0c50aad72a054e1923b82a9": { + "filename": "Steve Ostrom Games (Steve Ostrom).zip", + "disk0": "OSTROM2.DSK", + "joy-right": "kjoy0", + "basic": "DIR\n" + }, + "ff1324b184965fe877749a4c1de055c709b25830": { + "filename": "Steve Ostrom Games (Steve Ostrom).zip", + "disk0": "OSTROM2.DSK", + "joy-right": "kjoy0", + "basic": "DIR\n" + }, + "67ea79710cd2b71f49ea9d89823da481d6a4acf9": { + "filename": "Stone Raider II (Microdeal Cornwall).zip", + "disk0": "STONRAID.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"STONRAID\":EXEC\n" + }, + "0277fc32cdf72b0f8f5a1dcb06b8f5fe6b32fb95": { + "filename": "Storm Arrows (Spectral Associates).zip", + "disk0": "SARROW.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SARROW\":EXEC\n" + }, + "8ed67da21863be7dbe2be017bb4f0d9eebeb1e79": { + "filename": "Starwars (John Frontuto & Christian Miller) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "starwars.dsk", + "basic": "DOS\n" + }, + "4b6d522233dfd4dc34e4b7aba7439373bc7aa480": { + "filename": "Starwars (John Frontuto & Christian Miller) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "starwars.dsk", + "basic": "DOS\n" + }, + "831835f7c5ad0e2c1bf13a8793276146f90b5886": { + "filename": "Starwars (John Frontuto & Christian Miller) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "starwars.dsk", + "basic": "DOS\n" + }, + "3674604f3ee9b424291c722a137c44cc4081ba6c": { + "filename": "Storm (Computerware) (SG-24) (Coco 1-2).zip", + "disk0": "STORM.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"STORM\":EXEC\n" + }, + "344392f1ee73cc50b9fe5a79e20a093cb9a47a17": { + "filename": "Strata (Michael Sirolly) (Coco 3).zip", + "machine": "coco3", + "disk0": "STRATA.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"STRATA\"\n" + }, + "f4e3aafad41d0f95aba4808bdb2a3a8f67c239e3": { + "filename": "Stranded (Shawn Driscoll) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "stranded.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "07c1ed8c2056567825b5a914d441f8fa2eb71e0d": { + "filename": "Strip Tails (Boudoir Software).zip", + "disk0": "STRIPTLS.DSK", + "joy-left": "mjoy0", + "joy-right": "kjoy0", + "basic": "RUN\"TAILS\"\n" + }, + "7ee150ed761fdc0d7d35fb6f71b5d8161ac7e8e7": { + "filename": "Styx (T&D Software).zip", + "disk0": "STYX.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"STYX\":EXEC\n" + }, + "ada7e557aae09b6248903b546db8c54c2381540b": { + "filename": "Stronghold (Computer Shack).zip", + "disk0": "STRGHOLD.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"STRGHOLD\":EXEC\n" + }, + "82a125482df97a9dff83e973d2bbb72ff9544fe9": { + "filename": "Strip Poker (Artworx) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "spoker.dsk", + "basic": "DOS\n" + }, + "c41d215bc457f707782e05e36d96f7ff15637d36": { + "filename": "Strip Tease (Britt Monk, CDP).zip", + "disk0": "STRIP-T.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"STRIP-T\":EXEC\n" + }, + "d8872712425476a15714ac8f3d6a3dfcb7f8bbce": { + "filename": "Strip Poker (Artworx) (Coco 3).zip", + "machine": "coco3", + "disk0": "STRIP1.DSK", + "basic": "RUN\"POKER\"\n" + }, + "9a79665416a13ff191f86068511958c051018c0f": { + "filename": "Strip Poker (Artworx) (Coco 3).zip", + "machine": "coco3", + "disk0": "STRIP1.DSK", + "basic": "RUN\"POKER\"\n" + }, + "237781c8169b6711a8d79d8e2e96bad01dbe6945": { + "filename": "Strip Poker (Artworx) (Coco 3).zip", + "machine": "coco3", + "disk0": "STRIP1.DSK", + "basic": "RUN\"POKER\"\n" + }, + "319a31b73735091bf8e06783cdfd6018241cd01b": { + "filename": "Super Master Mind (Bill Nobel & Darryl Hildebrandt) (Coco 3).zip", + "machine": "coco3", + "disk0": "SMSTRMND.DSK", + "basic": "RUN\"SMSTRMND\"\n" + }, + "6a6d61ab7efd1c7a87142599795db7d50e84fedb": { + "filename": "Superkid (Quickbeam).zip", + "disk0": "SUPERKID.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SUPERKID\":EXEC\n" + }, + "1ceb8e8e8665d29602c75772a1274aae31a7813c": { + "filename": "Sudoku 2.1 (Alex Gayer).zip", + "machine": "coco3", + "disk0": "sudoku.dsk", + "basic": "RUN\"SUDOKU\"\n" + }, + "386c1a2c0d46bcf1c9e7d4ba1e19c18b428d400f": { + "filename": "Super Pitfall (6309) (Tandy) (Coco 3).zip", + "machine": "coco3h", + "disk0": "PITFALL3.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"PITFALL3\":EXEC\n" + }, + "aab170dcbd418215032495b32b2563662c751396": { + "filename": "Super Poker II (Marc Quirion) (Coco 3).zip", + "machine": "coco3", + "disk0": "POKER2.DSK", + "basic": "RUN\"POKER2\"\n" + }, + "02aaf0ac23c74deccb68f42752c5af85211c0db3": { + "filename": "Super Pitfall (Tandy) (Coco 3).zip", + "machine": "coco3", + "disk0": "PITFALL.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"PITFALL\"\n" + }, + "bfb07670c45929a2dbd07485ed4c3ee7d4bb2320": { + "filename": "Super Rat (L. Becker).zip", + "disk0": "SUPERRAT.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SUPERRAT\":EXEC\n" + }, + "f78a36c70ed4f6467c4d595a5ad5db1e85bfd950": { + "filename": "Super Rooter (Mark Nelson).zip", + "disk0": "ROOTER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ROOTER\":EXEC\n" + }, + "cec6b606aa644cba5ca0fdd5656dc8b7c70479e9": { + "filename": "Super Star Trek II (Backyard Software).zip", + "disk0": "STREK-II.DSK", + "basic": "PCLEAR1:RUN\"STREK II\"\n" + }, + "1de7b7925f7b8af08b6e4b836b9d1853493a4e2e": { + "filename": "Super Vaders (T&D Software).zip", + "disk0": "VADERS.DSK", + "basic": "LOADM\"VADERS\":EXEC\n" + }, + "839145183d01eaddbc6450b8dbab5b6806f7cafa": { + "filename": "Swell Foop (Jim Gerrie).zip", + "disk0": "SWELLFOOP.DSK", + "basic": "RUN\"SWELFOOP\"\n" + }, + "1de5d0f996dd8bfa3f683815ba12bf3c14b20cd5": { + "filename": "Surface (The Rainbow).zip", + "disk0": "SURFACE.DSK", + "basic": "RUN\"SURFACE\"\n" + }, + "849459e22102acf64d978c2600cdf7ac1a632a09": { + "filename": "Syzygy v1.0 (Spectral Associates).zip", + "disk0": "SYZYGY.DSK", + "basic": "LOADM\"SYZYGY\":EXEC\n", + "tv-input": "redblue" + }, + "dfa72c12a1cabf0f8b69203b7fc40eb2d62856c3": { + "filename": "Syzygy v3.0 (Spectral Associates) (SSC).zip", + "disk0": "SYZYGY.DSK", + "basic": "LOADM\"SYZYGY\":EXEC\n", + "tv-input": "redblue" + }, + "09fb0d4b57fb3875c89f268a1431719c50a025f8": { + "filename": "Taipan (Megasoft) (English translation).zip", + "disk0": "TAIPAN.DSK", + "basic": "RUN\"TAIPAN\"\n" + }, + "81b39a574b1d94e3a626d8f5b41a3e443f92cb67": { + "filename": "Tales of Suburbia Demo v1.0 (TRS-80 Retro Programing).zip", + "disk0": "SUBURBIA.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"TALES\"\n" + }, + "40510d7bbcf2d54cec5c3515dbd0d74f9e375c0a": { + "filename": "Tanjali (The Software Guild).zip", + "disk0": "TANJALI.DSK", + "basic": "RUN\"TANJALI\"\n" + }, + "7a5ebc3a73d24ae2ed160984632f176a36e815a0": { + "filename": "Tank Out (MatchyGames) (SG-24) (CoCo PSG).zip", + "disk0": "tank_out.dsk", + "basic": "RUN\"R\"\n" + }, + "e911cdf70a76b567003ff7d9a623689a7f1f292e": { + "filename": "Tanglewood (Microdeal).zip", + "disk0": "TANGLE.DSK", + "basic": "LOADM\"TANGLE\":EXEC\n" + }, + "ad48b19e5c4d5472e5f7a4a087ef4fd36c94a388": { + "filename": "Tank (T&D Software).zip", + "disk0": "TANK.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"TANK\"\n" + }, + "eaf52fc49354b467a14668a822797829ea448a91": { + "filename": "Tanks (80 Micros Magazine).zip", + "disk0": "TANKS.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"TANKS\"\n" + }, + "3bed69b256ac0cb80ecf5962048c6b3fe107f6a7": { + "filename": "Tarot Cards (Amir Dimitri).zip", + "disk0": "TAROT.DSK", + "basic": "PCLEAR1:RUN\"TAROT\"\n" + }, + "916bd34a068b6756c3047a7e161733d405f8f371": { + "filename": "T&D Track (T&D Software).zip", + "disk0": "HORSRACE.DSK", + "basic": "RUN\"HORSRACE\"\n" + }, + "331e7335de18c95221346dc5cdc969fd63c0541a": { + "filename": "Teatime (Pocket Money Software).zip", + "disk0": "TEATIME.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"TEATIME\":EXEC\n" + }, + "8fae83561b084fc9bcc1947726984cc4fb3be844": { + "filename": "Teee-Offf (Prickly-Pear Software).zip", + "disk0": "TEEEOFFF.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"TEEEOFFF\":EXEC\n" + }, + "460b12d5a640da41fa0b9fcc37e1a0fbd3d39e71": { + "filename": "Telengard (Avalon Hill) (Coco port).zip", + "disk0": "TELNGARD.DSK", + "basic": "RUN\"TELNBOOT\"\n" + }, + "b8ad362eb258e888805a49bd47b939388c3e7ad4": { + "filename": "Temple of ROM (Tandy).zip", + "disk0": "TEMPLE.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"TEMPLE\":EXEC\n" + }, + "bec060cad30c4d63c1a58e54980bdcd5b84793c9": { + "filename": "Temple of the Lost Ark (SJG Inc.).zip", + "disk0": "The_Ark.dsk", + "basic": "RUN\"THE ARK\"\n" + }, + "4e19d6daa952cb608cb0281f6fad4af0cbb2f681": { + "filename": "Tennis (Tandy).zip", + "disk0": "TENNIS.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"TENNIS\":EXEC\n" + }, + "71a18be1d6b8afaa2b01cea5f0372b561cd74364": { + "filename": "Term Paper (Charles Farris) (Coco 3).zip", + "machine": "coco3", + "disk0": "TERMPAPR.DSK", + "basic": "RUN\"TITLE\"\n" + }, + "324633533636e4537493297c1b431c5751a806cb": { + "filename": "Terminator 2 (Australian Coco Magazine).zip", + "disk0": "TERMINR2.DSK", + "basic": "RUN\"TERMINR2\"\n" + }, + "6ee4622079f46a12c77c22b8ddcf3d396eabfbbc": { + "filename": "Terror on Floor 51 Demo (JTR Systems) (Coco 3).zip", + "machine": "coco3", + "disk0": "FLOOR51.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"BOOT\"\n" + }, + "99ff1b61a1329cfe7e66dda0efbd0a70c4f7aabb": { + "filename": "Tetra (Brian O'Neill) (Coco 3).zip", + "machine": "coco3", + "disk0": "TETRA.DSK", + "basic": "LOADM\"TETRA\":EXEC\n" + }, + "8e3903a17bf10c19897721a998a8cf86761e71d3": { + "filename": "Tetrapak (T&D Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "TETRAPAK.DSK", + "basic": "LOADM\"TETRAPAK\":EXEC\n" + }, + "76b175beb6939bfa99b9deabe0efb1b2d2abc0fb": { + "filename": "Tetra (Rick's Computer Enterprise) (Coco 3).zip", + "machine": "coco3", + "disk0": "TETRA.DSK", + "basic": "RUN\"TETRA\"\n" + }, + "79ac790428d1b108297b63f14600cfb7d363b00e": { + "filename": "Tetras (Paul Burgin) (Coco port).zip", + "disk0": "TETRAS.DSK", + "joy-left": "kjoy0", + "joy-right": "mjoy0", + "basic": "LOADM\"TETRAS\":EXEC\n" + }, + "ca1f79fba23986d927e3957ca63c260f996c4997": { + "filename": "Tetris (PSE Computers) (Coco Port) (SG-24) (Coco 1-2).zip", + "disk0": "tetris.dsk", + "basic": "RUN\"TETRIS\"\n" + }, + "29ebd4ebf6fc5442ec6c6965e93c1c970592f929": { + "filename": "Tetris (Tandy) (Coco 1-2) (Coco 3).zip", + "machine": "coco3", + "disk0": "TETRIS.DSK", + "basic": "LOADM\"TETRIS\":EXEC\n" + }, + "40a37d6dcb8be6fc0e6537557a743d90f964fb8f": { + "filename": "Thexder (Tandy) (Coco 3).zip", + "machine": "coco3", + "disk0": "THEXDER.DSK", + "basic": "LOADM\"THEXDER\":EXEC\n" + }, + "562a2b3400df13d1da4518762f5ba5dcf524b5de": { + "filename": "Thumb Puzzle (L. Todd Knudsen) (Coco 3).zip", + "machine": "coco3", + "disk0": "THUMBPUZ.DSK", + "joy-left": "mjoy0", + "basic": "LOADM\"TP\"\n" + }, + "8c85f63c315bc5abfa24d3d2fb8c3c87ebf245b6": { + "filename": "Tetris (Mike Sweet & Hug Nguyen) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "TETRIS.DSK", + "basic": "DOS\n" + }, + "23eab58ce3d467ba0b0b9bebc6c71a179bd23c7c": { + "filename": "Tetris (Mike Sweet & Hug Nguyen) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "TETRIS.DSK", + "basic": "DOS\n" + }, + "56cf274918290abc2a5d240ce32fed4ddfe0df0f": { + "filename": "Thunder Road Adventure (Programmer's Guild).zip", + "disk0": "THUNDER.DSK", + "basic": "RUN\"THUNDER\"\n" + }, + "66e9719524596912271b1b73cdceb2ef43297476": { + "filename": "Tic-Tac-Toe 3D (Bob Delbourgo).zip", + "disk0": "tictac3d.dsk", + "basic": "RUN\"TICTAC3D\"\n" + }, + "0be4f2fd55eff57fafc78cddb415e4c14e1d5b6f": { + "filename": "Timber Man 2019 Christmas Edition Demo (Coco Brothers Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "TMXMAS.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"TIMBER19\":EXEC\n" + }, + "3d23d23ce73a7972d97b4f7cd01e15033cf9ea60": { + "filename": "Time Bandit (Computer Shack).zip", + "disk0": "BANDIT.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"BANDIT\":EXEC\n" + }, + "7fe4121e5ba2bf5c00dcf6466b2a80cd673fd0e4": { + "filename": "Time Fighter (Mark Data Products).zip", + "disk0": "TIMEFGHT.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"TIMEFGHT\":EXEC\n" + }, + "c09477588ffb81ea6f10c976db04856864f3ec8e": { + "filename": "Time Patrol (Computerware).zip", + "disk0": "TMPATROL.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"TMPATROL\":EXEC\n" + }, + "b0e27b51144137e92d5322b77dbb98add57f77bb": { + "filename": "Toad in the Hole (John Day).zip", + "disk0": "JUMP-TOA.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"JUMP-TOA\"\n" + }, + "6cb2097295a387072bef1500d2aaf8ac4a3c8d1f": { + "filename": "Tiburon (Shark) (Pere Serrat).zip", + "disk0": "TIBURON.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"BOOT\"\n" + }, + "1d84e4b12f7893395e95087fbd0d1488a5f5bd94": { + "filename": "Tiburon (Shark) (Pere Serrat).zip", + "disk0": "TIBURON.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"BOOT\"\n" + }, + "c65d7274da7c2b90329781137c29e8dccb622ff8": { + "filename": "Tiburon (Shark) (Pere Serrat).zip", + "disk0": "TIBURON.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"BOOT\"\n" + }, + "8185d84a33855a78f6a1f4c09be35bbf68870b48": { + "filename": "Tim Love's Cricket (Peaksoft).zip", + "disk0": "CRICKET.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CRICKET\":EXEC\n" + }, + "f21a219944f14bd608a7f9dbd22526092c8405ce": { + "filename": "Tomb of T'ien (Valkyrie Software).zip", + "disk0": "T'ien.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"T'IEN\":EXEC\n" + }, + "e809238373ad41147f2f793a5b724ef800082fa2": { + "filename": "Touchstone, The (Tom Mix Software).zip", + "disk0": "TOUCH.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"TOUCH\":EXEC\n" + }, + "692ec6eb9a5c4d3d47daaeea0f42fe597eeffe48": { + "filename": "Tombs of Terror (C & K Springett).zip", + "disk0": "TOMBS.DSK", + "basic": "RUN\"TOMBS\"\n" + }, + "e540133681e822b46917487d4d45a2e63e961bde": { + "filename": "Tower of Fear (Programmer's Guild).zip", + "disk0": "TOWER.DSK", + "basic": "LOADM\"TOWER\":EXEC\n" + }, + "475d15278f0cd9cece44e7f31e6c023a1035b081": { + "filename": "Tour of the Knight, The (Earther Enterprises) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "knights.dsk", + "joy-right": "mjoy0", + "basic": "DOS\n" + }, + "f82a76a805e9019e4f780ba03e0bdc6236272627": { + "filename": "Town Atak.zip", + "disk0": "CITYBOM.DSK", + "basic": "RUN\"CITY BOM\"\n" + }, + "9ada8d1df5b051888d133d7d45157cf6d1e7a7f2": { + "filename": "Track Events (Baron Products).zip", + "disk0": "track.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"START\"\n" + }, + "40dadd40aced26535c6d68b695da0dafbd797f14": { + "filename": "Tower of Fear (Programmer's Guild) (alt).zip", + "disk0": "TOWERALT.DSK", + "basic": "RUN\"TOWER\"\n" + }, + "e1cbeaf31507a8b898b261ce138845f4257d695d": { + "filename": "Trap 'em (Color Computer Magazine).zip", + "disk0": "TRAPEM.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"TRAPEM\":EXEC\n" + }, + "d8367ac5f10a6c5e53b4e6d975cfc4a1b74102f4": { + "filename": "Trapfall (Tom Mix Software).zip", + "disk0": "TRAPFALL.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"TRAPFALL\":EXEC\n" + }, + "720481de8a38034922cf95dde81d5fb61c888fa6": { + "filename": "Trapfall 1.1 (Tom Mix Software).zip", + "disk0": "TRAPFALL.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"TRAPFALL\":EXEC\n" + }, + "865345e66e8a03b5d3f489c324a33042955820bc": { + "filename": "Treasure Hunt (Color Computer Programmer Monthly).zip", + "disk0": "TREASURE.DSK", + "basic": "RUN\"TREASURE\"\n" + }, + "53182529685f7629d2daffcc2e2a3bbb687944ef": { + "filename": "Treasure Hunt (Saguaro Software).zip", + "disk0": "TRHUNT.DSK", + "basic": "RUN\"TR\"\n" + }, + "6c7540895f812fb04271668404e69ee762abe240": { + "filename": "Treasure Island Defense v1.1 (Sheldon MacDonald) (CoCoVGA) (Coco 3).zip", + "machine": "coco3", + "disk0": "TID.DSK", + "joy-left": "mjoy0", + "basic": "LOADM\"TID\":EXEC\n" + }, + "929812fcd7d6b9ff1003149a81503e4f54e48b62": { + "filename": "Treasure of the Aztec (Computerware) (SSC).zip", + "disk0": "AZTEC-ALT.DSK", + "basic": "LOADM\"AZTECS\":EXEC\n", + "tv-input": "redblue" + }, + "917408da6600384c5509446af51a4480da5e25b3": { + "filename": "Treasure of the Aztec (Computerware) (SSC).zip", + "disk0": "AZTEC-ALT.DSK", + "basic": "LOADM\"AZTECS\":EXEC\n", + "tv-input": "redblue" + }, + "e08f664859148ee237cb69407b5a8de72d85695a": { + "filename": "Trekboer (Mark Data Products).zip", + "disk0": "TREKBOER.DSK", + "basic": "LOADM\"TREKBOER\":EXEC\n", + "tv-input": "redblue" + }, + "65b490ee95149579b2a5eb8b4d4fe771deff58d6": { + "filename": "Treasury Pak (Spectral Associates).zip", + "disk0": "Treasury2.dsk", + "joy-right": "kjoy0", + "basic": "DIR\n" + }, + "be653aaf398b83f5b6146f9b86a45b61235f4f24": { + "filename": "Treasury Pak (Spectral Associates).zip", + "disk0": "Treasury2.dsk", + "joy-right": "kjoy0", + "basic": "DIR\n" + }, + "69ebbd6d10a4a7c0564e76e0f637bd9364715d3d": { + "filename": "Trek Adventure (Aardvark Technical Services).zip", + "disk0": "TREK-ADV.DSK", + "basic": "RUN\"TREK-ADV\"\n" + }, + "dca885576bfec40560676f330055e7e90c594677": { + "filename": "Trubble (John Demchenko) (Coco 3).zip", + "machine": "coco3", + "disk0": "TRUBBLE.DSK", + "basic": "RUN\"TRUBBLE\"\n" + }, + "b26b5354b3ce10237041fff6dcf3cbf3b51f80a8": { + "filename": "Trickashay (AHL Computing).zip", + "disk0": "TRICKASH.DSK", + "joy-left": "mjoy0", + "joy-right": "kjoy0", + "basic": "LOADM\"TRICKASH\":EXEC\n" + }, + "c0dde3d280c5f5fdd9ca1884503ab96420d45072": { + "filename": "Trip, The (The Rainbow).zip", + "disk0": "THETRIP.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"BOOT\"\n" + }, + "754f599470d347013ae763d418b3fad2b95b2763": { + "filename": "Tube Frenzy (Aadvark-80).zip", + "disk0": "TUBFREN.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"TUBFREN\":EXEC\n" + }, + "d769dc0f2ae5d35673b3cf7a5d8dd26026dba4f4": { + "filename": "Tunnel Racer (T&D Software).zip", + "disk0": "TUNNEL.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"TUNNEL\":EXEC\n" + }, + "296283e443bfc9528ef585f78289170c9a3deba0": { + "filename": "Tube Way Army (Crystal Computing).zip", + "disk0": "TUBEARMY.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"TUBEARMY\":EXEC\n" + }, + "6dd7119450e30daea6d0877d7c508c1bcd6d19e6": { + "filename": "Turret (T&D Software).zip", + "disk0": "TURRET.DSK", + "basic": "RUN\"TURRET\"\n" + }, + "840c195caec69357de069aa4eda0c4724868031e": { + "filename": "Tunnel (Unknown author).zip", + "disk0": "TUNNEL.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"TUNNEL\":EXEC\n" + }, + "f84f9792ea12277762c238b561ef0d6e03db8bac": { + "filename": "Turtle Attack (Triple-C Software).zip", + "disk0": "TURTLE.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"TURTLE\":EXEC\n" + }, + "050d99cdc02160b5e79257d61356760e5a982aad": { + "filename": "Tut's Tomb (Mark Data Products).zip", + "disk0": "TUTSTOMB.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"TUTSTOMB\":EXEC\n" + }, + "8b5425e74ac893d8716c1213dddd12174183fa03": { + "filename": "Tutankam (Aadvark-80).zip", + "disk0": "TUTANKAM.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"TUTANKAM\":EXEC\n" + }, + "771c4c93c087a0ee1c92bcb6e70a887713ca8ca1": { + "filename": "U-Boat (Andrew McLintock).zip", + "disk0": "U-BOAT.DSK", + "basic": "RUN\"U-BOAT\"\n" + }, + "2fd04de98487f4bd00597c355c9b1b37f035244a": { + "filename": "Unatron (K. J. Dowd).zip", + "disk0": "Unatron.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"UNATRON\":EXEC\n" + }, + "cf16093d218d8599a971ffae99d8a62f7fc47671": { + "filename": "Ugh! (Softek International Limited).zip", + "disk0": "UGH.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"UGH!\":EXEC\n" + }, + "5f50d8be98c66916f317a941a5dfb83a16a751e7": { + "filename": "Usetown Annex Project (Paul French).zip", + "disk0": "USETOWN.DSK", + "basic": "RUN\"USETOWN\"\n" + }, + "b77715f585ac24934f749f9362dd9d28361a9f70": { + "filename": "Utopian (CLOAD).zip", + "disk0": "UTOPIAN.DSK", + "basic": "RUN\"UTOPIAN\"\n" + }, + "0fccc458d3287cc849abf1ed50fd6f95f2690612": { + "filename": "Vampire Castle Beta 4 (Richard Kelly) (Coco 3).zip", + "machine": "coco3", + "disk0": "VamCasB4.dsk", + "basic": "RUN\"VAMCASB4\"\n" + }, + "96721ea9995614dc7defe2f202ca4a26917cfc5f": { + "filename": "Vampire Castle (Aardvark).zip", + "disk0": "VCASTLE.DSK", + "basic": "RUN\"VCASTLE\"\n" + }, + "227419ab768a93d9bd09a5435f5aa138cb952982": { + "filename": "VC (Microcomputer Games).zip", + "disk0": "VC.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"VC\":EXEC\n" + }, + "9e9e649b0080a8e35dcc05b16c48d70494002ecb": { + "filename": "Vegas Gamepak (Nelson Software Systems).zip", + "disk0": "VEGAS.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"VEGAS\":EXEC\n" + }, + "1ab5c7ae70f4562087d12bec1d55305a9623c09b": { + "filename": "Varloc (Tandy).zip", + "disk0": "varloc.dsk", + "joy-right": "mjoy0", + "basic": "DOS\n" + }, + "f5095bd44cb2a4684a7a4f84061ae4437f69f6eb": { + "filename": "Varloc (Tandy).zip", + "disk0": "varloc.dsk", + "joy-right": "mjoy0", + "basic": "DOS\n" + }, + "4014936bd4dff47f6f082c090506edb73a644ba6": { + "filename": "Vegas Game Pak (Tom Mix Software).zip", + "disk0": "VEGAS.DSK", + "basic": "DIR\n" + }, + "b0ce0b1ad734dabcf460481b501ae1ee9aa69874": { + "filename": "Vegas Slots (Tom Mix Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "VEGAS.DSK", + "joy-right": "kjoy0", + "basic": "DIR\n" + }, + "b15b368512c5b23a81b5d8f5717b90e560f3e599": { + "filename": "Venturer (Aadvark-80).zip", + "disk0": "VENTURER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"VENTURER\":EXEC\n" + }, + "92defaf2f0bd66bef6be954eb802b1e7e52e45b8": { + "filename": "Video Cards and Keno (Tom Mix Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "CASINO.DSK", + "basic": "RUN\"DOS\"\n" + }, + "10eb1f0bfcad1efac3f9c54433acbb0ee5693e6f": { + "filename": "Vicious Vic (The Rainbow).zip", + "disk0": "VIC.DSK", + "basic": "RUN\"VIC\"\n" + }, + "342bfc659e7aedf10347ed491b8158e7ab83933f": { + "filename": "Video Keno (Tom Mix Software).zip", + "disk0": "KENO.DSK", + "basic": "LOADM\"KENO\":EXEC\n" + }, + "77f8fc221ce97715035c9ed70b5c945226546af6": { + "filename": "Video Pinball (Tandy).zip", + "disk0": "PINBALL.DSK", + "joy-left": "kjoy0", + "joy-right": "mjoy0", + "basic": "LOADM\"PINBALL\":EXEC\n" + }, + "e5a6b41dd08759c74e1b5189127ff9c6c3852e2e": { + "filename": "Video Poker Coco 3 Edition (Paul Shoemaker) (Coco 3).zip", + "machine": "coco3", + "disk0": "VPOKER3.DSK", + "basic": "LOADM\"VPOKER3\":EXEC\n" + }, + "55800515fb9ee0b5fb59c20eded9c0c07481d47f": { + "filename": "Video Poker Standard Edition (Paul Shoemaker).zip", + "disk0": "VPOKER.DSK", + "basic": "LOADM\"VPOKER\":EXEC\n" + }, + "23de6e0d0fd97f0bb63e9cfbc275ad940e382bac": { + "filename": "Viking II (Prickly-Pear Software).zip", + "disk0": "VIKINGII.DSK", + "basic": "RUN\"VIKINGII\"\n" + }, + "e1bf252d3b6d74c4d85f90ecf94db0f6cf0ce855": { + "filename": "Viper Force (Hot Coco).zip", + "disk0": "VIPER.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"VIPER\"\n", + "tv-input": "redblue" + }, + "c2c4ae1240eaf402023ccd553f6677855608b6a6": { + "filename": "Viking (Prickly-Pear Software).zip", + "disk0": "viking.dsk", + "basic": "RUN\"VIKING\"\n" + }, + "adda9deb0dd69cf33e25972da95750b1330923cc": { + "filename": "Vocab (Rick's Computer Enterprise) (Coco 3).zip", + "machine": "coco3", + "disk0": "VOCAB.DSK", + "basic": "RUN\"VOCAB\"\n" + }, + "d83509484531defa68bbe220ed8b0f055731fd12": { + "filename": "Vortex Factor, The (Mark Data Products).zip", + "disk0": "VORTEX.DSK", + "basic": "LOADM\"VORTEX\":EXEC\n", + "tv-input": "redblue" + }, + "8b5fa93fca29c6baa424b1fb90b77cf2b31408bd": { + "filename": "Vox Chess (Computerware).zip", + "disk0": "VOXCHESS.DSK", + "basic": "LOADM\"VOXCHESS\":EXEC\n" + }, + "51693ec622090df925cf7e22b8dc0836fa7fba3f": { + "filename": "Voyager I (Avalon Hill).zip", + "disk0": "VoyagerI.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"VOY-1\"\n" + }, + "903ecbe29b488b2b64914939b5b1256fb5ebd1a1": { + "filename": "Voyagers (Color Horizon Software).zip", + "disk0": "VOYAGERS.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"VOYAGERS\":EXEC\n" + }, + "a3a92ac820124166945a1dad53739b3cffedf3b1": { + "filename": "Voyage (The Rainbow).zip", + "disk0": "VOYAGE.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"BOOT\"\n" + }, + "ac5475dc69e107d042a2b19c7235474354a6bcb2": { + "filename": "Vultures (J. Morrison Micros) (SG-8 intro).zip", + "disk0": "VULTURES.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"VULTURES\":EXEC\n" + }, + "4483a835ae76c249550a6218698a0ea86e4a41f3": { + "filename": "Wacky Food (Arcade Animation Inc.).zip", + "disk0": "WCKYFOOD.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"WCKYFOOD\":EXEC\n" + }, + "8368a772025a57ae8b49b10561fc3f13abaa0fb2": { + "filename": "Wargame (T&D Software).zip", + "disk0": "wargame.dsk", + "basic": "RUN\"WARGAME\"\n" + }, + "06ecf15f1c34c0a22cca30cc1c2200d28ad9c8d1": { + "filename": "Wargame (T&D Software) (alt).zip", + "disk0": "WARGAME.DSK", + "basic": "RUN\"WARGAME\"\n" + }, + "d86d2cc4db309309b6452fffbe9fa08c3581a23e": { + "filename": "Warehouse Mutants (Tom Mix Software).zip", + "disk0": "MUTANT.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MUTANT\":EXEC\n" + }, + "14045d85a305642d269799f645a0039f1a55ea8d": { + "filename": "Warkings (Tom Mix Software).zip", + "disk0": "WARKINGS.DSK", + "joy-left": "mjoy0", + "joy-right": "kjoy0", + "basic": "LOADM\"WARKINGS\":EXEC\n" + }, + "0d836bf79f5b656752faf4fb21f7cc30159400be": { + "filename": "War of the Worlds 2 - The Quest (Triad Pictures Corporation).zip", + "disk0": "WOW2.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"WOW2\"\n" + }, + "b52be4382ed0b8018d4de5ffa2bdeedf5003e4e0": { + "filename": "War of the Worlds 1 - The Landing (Triad Pictures Corporation).zip", + "disk0": "WOW1.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"WOW1\"\n" + }, + "9346b372635dda28b4934eaf41afa15590b99f17": { + "filename": "War of the Worlds 3 - The Last Hope (Triad Pictures Corporation).zip", + "disk0": "WOW3.DSK", + "joy-right": "mjoy0", + "basic": "RUN\"WOW3\"\n" + }, + "c3fbd790cc2b373324ab4deffb6cb1b4b51d83c4": { + "filename": "Warp Fighter 3D (SRB Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "WARP3D.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"WARP3D\":EXEC\n" + }, + "533c2757a76657faeee18f2e261bb1378c6c3c04": { + "filename": "Warp Factor X (Prickly-Pear Software).zip", + "disk0": "WARPX.DSK", + "basic": "RUN\"WARP\"\n" + }, + "57d5799f37b8157c5239e1502fae6c26586d81eb": { + "filename": "Warp (T&D Software).zip", + "disk0": "WARP.DSK", + "basic": "RUN\"WARP\"\n" + }, + "c09a0ac12fa91c7abc33664cd4072419dbfd71f7": { + "filename": "War (Tandy).zip", + "disk0": "WAR.DSK", + "basic": "RUN\"WAR\"\n" + }, + "06329ba1beecee740532554d7ab22864c38aa67a": { + "filename": "Warrior (GOSUB International).zip", + "disk0": "WARRIOR.DSK", + "basic": "RUN\"WARRIOR\"\n" + }, + "934bae26dd3966879050aeb0cbb7c38983c9cb6e": { + "filename": "Waterfall (Nick Marentes) (SSC).zip", + "machine": "coco2bus", + "disk0": "WATRFALL.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"WATRFALL\"\n" + }, + "2fc5e96d827b57f8d6e1f83120bf46373cfe2391": { + "filename": "Waterloo (Ark Royal Games).zip", + "disk0": "WATERLOO.DSK", + "basic": "RUN\"WATERLOO\"\n" + }, + "b2e365140e89345d58dacb5d24e9569b90e62350": { + "filename": "Weirdo (T&D Software).zip", + "disk0": "WEIRDO.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"WEIRDO\":EXEC\n", + "tv-input": "redblue" + }, + "7c403332eead12225de4a1e7d5cc2cb0f460015a": { + "filename": "Werewolves and Wanderers (Tim Hartnell) (Coco 3).zip", + "machine": "coco3", + "disk0": "WEREWOLF.DSK", + "basic": "RUN\"WEREWOLF\"\n" + }, + "0174f4bf4129f3b60cf6ea5058ad7f8970d56101": { + "filename": "Wet T-Shirt Contest (Softcore Software Company).zip", + "disk0": "WETSHIRT.DSK", + "basic": "LOADM\"WETSHIRT\":EXEC\n" + }, + "21a3b9a98eb75bb6fae77ecf6eed0d983cd54345": { + "filename": "Welcome to the Jungle (Prickly-Pear Software).zip", + "disk0": "JUNGLE.DSK", + "basic": "RUN\"JUNGLE\"\n" + }, + "1e69afa5ecd61ec0347962b460fd5ba68009746f": { + "filename": "Whatzit (Randall A. Smith).zip", + "disk0": "WHATZIT.DSK", + "basic": "RUN\"WHATZIT\"\n" + }, + "1893f68833db59ec26bcd51b02fe1896e4293c1a": { + "filename": "Wheeler Dealer, The (Prototype) (L. Todd Knudsen) (Coco 3).zip", + "machine": "coco3", + "disk0": "WHEELER.DSK", + "basic": "RUN\"BOOT\"\n" + }, + "badd4b66819eb2529163c21994fe032665c63c6f": { + "filename": "Wheel of Fortune (SPORTSware) (Coco 3).zip", + "machine": "coco3", + "disk0": "WHEEL.DSK", + "basic": "RUN\"M\"\n" + }, + "726465107fcf4e06cf320ab39123f513160498b8": { + "filename": "Where's Santa's Landing (Joey Latimer).zip", + "disk0": "SANTA.DSK", + "basic": "RUN\"SANTA\"\n" + }, + "00a898ad72ba6f81a8c28af32edac1fbe4af821a": { + "filename": "Wheel of Money (David Richards) (Coco 3).zip", + "machine": "coco3", + "disk0": "WHEELOF.DSK", + "basic": "RUN\"WHEEL\"\n" + }, + "f74e49d679202560a06853b438723b0b1371e6cf": { + "filename": "Whirlybird Run (Spectral Associates).zip", + "disk0": "WHIRLY.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"WHIRLY\":EXEC\n" + }, + "34f0c3d22f963e70a311cbb48a66c727dcf0e2dc": { + "filename": "Wiggle Worm (Chromasette).zip", + "disk0": "WIGWORM.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"WIGWORM\":EXEC\n" + }, + "de65dd60aee6bf58da6300be315bacdec527b6f1": { + "filename": "Wiggle Worm (Chromasette) (Coco 3 fix).zip", + "disk0": "WIGWORM.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"WIGWORM\":EXEC\n" + }, + "35683d2baa5fa42415885eae4ad6640f622c93c6": { + "filename": "Wildcatting (Tandy).zip", + "disk0": "WILDCAT.DSK", + "joy-left": "mjoy0", + "basic": "LOADM\"WILDCAT\":EXEC\n" + }, + "34900e10479df3fd48d9a1befd3b95459c3a7624": { + "filename": "Willy's Warehouse (Intracolor).zip", + "disk0": "WAREHOUS.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"WAREHOUS\":EXEC\n", + "tv-input": "redblue" + }, + "f77394ed5446c6e8daf781bb1c1cf54ced403bde": { + "filename": "Wild Party (B&B Software).zip", + "disk0": "WILDPRTY.DSK", + "basic": "RUN\"WILDPRTY\"\n" + }, + "09db973f3c313a03dbf620ca4d0f1ed7d5b65d30": { + "filename": "Wimpy (Gregory Clark) (Coco 3).zip", + "machine": "coco3", + "disk0": "WIMPY.DSK", + "basic": "RUN\"WIMPY\"\n" + }, + "49290708f859baf4fb2ae10bb2794c918d507fd0": { + "filename": "White Fire of Eternity (Saguaro Software).zip", + "disk0": "Whitefire.dsk", + "basic": "LOADM\"BOOT\":EXEC\n" + }, + "82347bd942fc3d8586ed0db12c8fb9731f10d660": { + "filename": "White Fire of Eternity (Saguaro Software).zip", + "disk0": "Whitefire.dsk", + "basic": "LOADM\"BOOT\":EXEC\n" + }, + "d923304aa2c1948eea23511a764310b39971a13a": { + "filename": "White Fire of Eternity (Saguaro Software).zip", + "disk0": "Whitefire.dsk", + "basic": "LOADM\"BOOT\":EXEC\n" + }, + "ef70b91a8f4b0f5138e302f4a9de798ba5ffcc9e": { + "filename": "White Fire of Eternity (Saguaro Software).zip", + "disk0": "Whitefire.dsk", + "basic": "LOADM\"BOOT\":EXEC\n" + }, + "be0f65740a5bbb8510c786d51ca4a0321c626232": { + "filename": "Wizard Adventure (T&D Software).zip", + "disk0": "WIZARD.DSK", + "basic": "RUN\"WIZARD\"\n" + }, + "2711fc712e224b867d9bbcdfdc94bc187c8714c2": { + "filename": "Wizard's Castle (Spectral Associates) (OS-9) (SSC).zip", + "disk0": "WIZCASTL.DSK", + "basic": "DOS\n" + }, + "71c41fa6e9a188cd15d2090cd67b8b936afbc8f0": { + "filename": "Wizard's Castle, The (Public Domain).zip", + "disk0": "WIZCASTL.DSK", + "basic": "RUN\"WIZCASTL\"\n" + }, + "6fe07412cfb52e799eac96d1d1c49b9ae5abb35d": { + "filename": "Wizards II (David Lionell Dawson) (Coco 3).zip", + "machine": "coco3", + "disk0": "wizards.dsk", + "basic": "RUN\"WIZINS\"\n" + }, + "b7570d5349b0144e2577728f2e139f0ddeba65a1": { + "filename": "Wizard's Den (Tom Mix Software).zip", + "disk0": "WIZDEN.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"BOOT\"\n", + "tv-input": "redblue" + }, + "bdd00bf7ee171a57ab33cecaa31677743203bb2d": { + "filename": "Wizard's Quest (Microdeal Cornwall).zip", + "disk0": "WIZQUEST.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"WIZQUEST\":EXEC\n" + }, + "9d9cce9bf7f507600f3e176338d6beec4f050eb7": { + "filename": "Wizard's Tomb, The (Chris Hawks).zip", + "disk0": "WIZTOMB.DSK", + "basic": "RUN\"WIZDTOMB\"\n" + }, + "46ba87506afb37f8062e05decabfecfe277d6694": { + "filename": "Word Hunt (Jeffery A. Stipes) (Coco 3).zip", + "machine": "coco3", + "disk0": "WORDHU.DSK", + "basic": "RUN\"WORDHU\"\n" + }, + "7f7ff375a9970ffd57aef852a422b077c581c0f9": { + "filename": "Wizard's Tower, The (Aardvark).zip", + "disk0": "wiztower.dsk", + "basic": "RUN\"WIZARDS\"\n" + }, + "1e1a02bdb85fcc4e22ab1d9b54a549496465e515": { + "filename": "World Conquest (T&D Software).zip", + "disk0": "WORLDCON.DSK", + "basic": "RUN\"WORLDCON\"\n" + }, + "3a633ab3520bf1cb37ef3d86d805980cf01a7bf5": { + "filename": "World Class Cribbage (Bob van der Poel) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "CRIBOS-9.dsk", + "joy-right": "mjoy0", + "basic": "DOS\n" + }, + "c257c6c25dd2b018fbdee44784f8a4f97e717d33": { + "filename": "World Master II (Dough Tuttle) (Coco 3).zip", + "machine": "coco3", + "disk0": "WMASTER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"WMASTER\":EXEC\n" + }, + "4730c033a9dec7aa0ed260834c8e20087e94e841": { + "filename": "World Weight Lifting (Australian Coco Magazine) (SSC).zip", + "machine": "coco3", + "disk0": "WWFLIFT.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"WWFLIFT\"\n", + "tv-input": "bluered" + }, + "6c1490b19be94ae4ad665f33858472195b1d46f0": { + "filename": "Worlds of Flight (Tom Mix Software).zip", + "disk0": "WOF.DSK", + "joy-left": "mjoy0", + "basic": "LOADM\"WOF\":EXEC\n" + }, + "bee8c4eb718c25901773b671ea799661903faf2e": { + "filename": "Wormtube (John Bobst) (SG-24) (Coco 1-2).zip", + "disk0": "WORMTUBE.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"WORMTUBE\":EXEC\n" + }, + "39356118d650af19fdee8329afe9dfcd134f05d2": { + "filename": "Wrestle Maniac (Diecom Products).zip", + "disk0": "Wrestle Maniac.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"WRESTLE\":EXEC\n", + "tv-input": "redblue" + }, + "040d9df9f0b57aea219f59067da219303f14ba6e": { + "filename": "Wrestle Maniac (Diecom Products).zip", + "disk0": "Wrestle Maniac.dsk", + "joy-right": "kjoy0", + "basic": "LOADM\"WRESTLE\":EXEC\n", + "tv-input": "redblue" + }, + "67cd37e0c5e9d8efe7e6fc8b90d71b1621e9ea87": { + "filename": "Xenocide (Alison deNu).zip", + "disk0": "XENOCIDE.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"XENOCIDE\"\n" + }, + "35b39618f86d0e5e9c0b300b5274ef150a4d3cc0": { + "filename": "Xmas Rush (John Linville).zip", + "disk0": "xmasrush.dsk", + "joy-left": "kjoy0", + "basic": "LOADM\"XMASRUSH\":EXEC\n" + }, + "e00d3f96e292eab1d2f5565d1a655323c9318b70": { + "filename": "X-Rated Adventure Game (Y. K. Supersoft).zip", + "disk0": "X-ADVENT.DSK", + "basic": "RUN\"DR\"\n" + }, + "4a76272435fef9500c471d0c3a80ea2c9b1678ba": { + "filename": "Xygoid (Public Domain).zip", + "disk0": "XYGOID.DSK", + "basic": "LOADM\"XYGOID\":EXEC\n" + }, + "5cc67cf832d31a87f71d4c7608e31cbade15b11c": { + "filename": "YahtCC (Spectral Associates).zip", + "disk0": "YAHTCC.DSK", + "basic": "RUN\"YAHTCC\"\n" + }, + "240866515421aa198dfae9be40ce8a6c54f26094": { + "filename": "Yahtzee 3 (T&D Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "YAHTZEE3.DSK", + "basic": "RUN\"YAHTZEE3\"\n" + }, + "54bea95e59f3e73152c5211ac65fa3c3ddda2ebe": { + "filename": "Yahtzee (GOSUB International).zip", + "disk0": "YAHTZEE.DSK", + "basic": "RUN\"YAHTZEE\"\n" + }, + "b174c19248f1f8bf0253c078d71ee28fbe3cb855": { + "filename": "Yahtzee (Jim Peasley) (Coco 3).zip", + "machine": "coco3", + "disk0": "YAHTZEE.DSK", + "basic": "RUN\"YAHTZEE\"\n" + }, + "d0a6474bc842e50fbba1e67c67586792c94a0f31": { + "filename": "Yahtzee (Kevin Gowan).zip", + "disk0": "YAHTZEE.DSK", + "basic": "RUN\"YAHTZEE\"\n" + }, + "42b55ed7207bf82eb03582b9903a268a7ccdb9b6": { + "filename": "Yahtzee (T&D Software).zip", + "disk0": "YAHTZEE.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"YAHTZEE\"\n" + }, + "27de812de956927fe0ab8a01816e03248d381423": { + "filename": "Yellow Submarine (The Rainbow).zip", + "disk0": "YELLOW.DSK", + "basic": "RUN\"SUBINTRO\"\n" + }, + "35c6c11279750c17c4d77e444fc072fb3d300b97": { + "filename": "Z-89 v1.01 (Game Point Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "Z-89 v1.01 (Game Point Software) (Coco 3)/z89.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "140cbcaad396718789b17c0c51af6ad16a21888b": { + "filename": "Z-89 v1.01 (Game Point Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "Z-89 v1.01 (Game Point Software) (Coco 3)/z89.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "9f8b25499a2d88aca2d000d3f1d9a9aa039e1939": { + "filename": "Z-89 v1.03 (Game Point Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "Z-89 v1.03 (Game Point Software) (Coco 3)/z89.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "cd1cdad3a9e35c7d0d416cf7eeb076a6a52bec49": { + "filename": "Z-89 v1.03 (Game Point Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "Z-89 v1.03 (Game Point Software) (Coco 3)/z89.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "c317a547c21cef19c88aae41143d3eb078eae7df": { + "filename": "Z-89 v1.03 (Game Point Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "Z-89 v1.03 (Game Point Software) (Coco 3)/z89.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "d1a40a69897002e60dc64fd819df3877b7faad30": { + "filename": "Z-89 v1.03 (Game Point Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "Z-89 v1.03 (Game Point Software) (Coco 3)/z89.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "eb95b47f56a850913ba46a133f8dc61bfa762238": { + "filename": "Z-89 v1.03 (Game Point Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "Z-89 v1.03 (Game Point Software) (Coco 3)/z89.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "ac0f8c90bfb83fc4d4aa2e59ab48f4e5deddccc6": { + "filename": "Z-89 v1.03 (Game Point Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "Z-89 v1.03 (Game Point Software) (Coco 3)/z89.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "cc3cf2da6ad9f6d09bbf4c3f9394ee2e6ac79f4e": { + "filename": "Z-89 v1.03 (Game Point Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "Z-89 v1.03 (Game Point Software) (Coco 3)/z89.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "5ae392fc347b6e7a5740543b9d77a9181c88f9dc": { + "filename": "Z-89 v1.03 (Game Point Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "Z-89 v1.03 (Game Point Software) (Coco 3)/z89.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "c9669e2e1dd58f958032193f6312bb3b809e1317": { + "filename": "Z-89 v1.03 (Game Point Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "Z-89 v1.03 (Game Point Software) (Coco 3)/z89.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "6b88c32667f6ea6452a59164f16f0e21a20cac46": { + "filename": "Zaksund (Elite Software).zip", + "disk0": "ZAKSUND.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ZAKSUND\":EXEC\n" + }, + "adcead2aa696874b8e43145352ebb2d03d081ab3": { + "filename": "Zandar (K-Soft) (Coco 3).zip", + "machine": "coco3", + "disk0": "ZANDAR.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"ZANDAR\"\n" + }, + "c0822405cc68df8c3f450b778857d2fb857ff448": { + "filename": "Zaxxon (Datasoft).zip", + "disk0": "ZAXXON.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ZAXXON\":EXEC\n" + }, + "97f3022735c957f3d12634b3a12645ab0e0a6b30": { + "filename": "Zector Adventure (T&D Software).zip", + "disk0": "zector.dsk", + "basic": "LOADM\"ZECTOR\":EXEC\n" + }, + "971fba728fa3b3cdb6a7e6a797ee873887e18f37": { + "filename": "Zenix Demo (Gosub Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "ZENIXDEM.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"ZDEMO\"\n" + }, + "f6f2b7936c73cb9cfb4d72d59d14ee876b88b846": { + "filename": "Zenix (Gosub Software) (Coco 3).zip", + "machine": "coco3", + "disk0": "ZENIX.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ZENIX\":EXEC\n" + }, + "56902e36c2062f691260211386fc0abee6943443": { + "filename": "Zero-G (Chromasette).zip", + "disk0": "ZEROG.DSK", + "basic": "LOADM\"ZEROG\":EXEC\n" + }, + "6a6776666493124901aa0a100efaa7e96ae3e6a3": { + "filename": "Zeus (Aardvark-80).zip", + "disk0": "ZEUS.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ZEUS\":EXEC\n" + }, + "c1de292850f7af127fa4de4923f4dd09557645dd": { + "filename": "Zeus (Shattered score fix) (Aardvark-80).zip", + "disk0": "ZEUS_FX.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ZEUS\":EXEC\n" + }, + "62072b9785bd8ede8262ecd31c883f2b0bcbf0f9": { + "filename": "Zone 6 (Colorquest).zip", + "disk0": "ZONE6.DSK", + "basic": "LOADM\"ZONE6\":EXEC\n" + }, + "5ab66dea3c13e864a9b211aacba9681a2a404e19": { + "filename": "Zonerunner (Tandy) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "ZONERUN.DSK", + "joy-right": "mjoy0", + "basic": "DOS\n" + }, + "fdd3ef04a6e2fcc854a467ae735f2af43c838af2": { + "filename": "Zonx (The Rainbow).zip", + "disk0": "ZONX.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ZONX\":EXEC\n" + }, + "331e80d26885097388283f9534a9969bba929d68": { + "filename": "Action Réaction (French) (Coco 3).zip", + "machine": "coco3", + "disk0": "REACTION.DSK", + "basic": "LOADM\"ACTION\":EXEC\n" + }, + "801f57fae7799d191811b17419478dbb29ef4fa3": { + "filename": "Canyon Climber (Tandy) (French translation).zip", + "disk0": "CANYONF.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CANYONF\":EXEC\n" + }, + "8460d2f0671b4109c8c0c940a6779f603d7d3bd2": { + "filename": "Chateau (French).zip", + "disk0": "CHATEAU.DSK", + "basic": "RUN\"CHATEAU\"\n" + }, + "3f2372d97990f3d85714736e72da3e09b452972f": { + "filename": "Chickens (French translation).zip", + "disk0": "POULETS.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"POULETS\"\n" + }, + "f30ba9537af91215bd9466f5ef1961b494f636dd": { + "filename": "Clowns & Balloons (Tandy) (French translation).zip", + "disk0": "CLOWNSF.DSK", + "joy-right": "mjoy0", + "basic": "LOADM\"CLOWNSF\":EXEC\n" + }, + "db983568f52832f9cf8b686730886fb798cff54a": { + "filename": "Diggem (Chromasette) (French translation).zip", + "disk0": "DIGGEMF.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"DIGGEMF\"\n" + }, + "90eaf697b3300c4356137e521ebfa16ff89261e1": { + "filename": "East-World Karate (The Saint John Gallery) (French translation).zip", + "disk0": "Karate Special.dsk", + "joy-left": "kjoy0", + "basic": "RUN\"KARATSPE\"\n" + }, + "3e65cb3261b52c5e8bc4fbf26546b13e128d6199": { + "filename": "Echecs (CSS) (French).zip", + "disk0": "echecs.dsk", + "basic": "RUN\"ECHECS\"\n" + }, + "47452f732665c0c4b4eb4aa0cc3a45d0991b64e3": { + "filename": "Find That Capital Letter (French translation).zip", + "disk0": "FINDLETF.DSK", + "basic": "RUN\"FINDLETF\"\n" + }, + "a1f272238e0b039d4d7858b327187278e7cad0be": { + "filename": "Find That Number (French translation).zip", + "disk0": "FINDNUMF.DSK", + "basic": "RUN\"FINDNUMF\"\n" + }, + "110b9668e7bc186a0b18226cfcbdbe194cc3770f": { + "filename": "Fléau (Lomiq) (French).zip", + "disk0": "FLEAU.DSK", + "basic": "RUN\"*\n", + "tv-input": "redblue" + }, + "88422dfc5c39fff0af83a86b10f56e84fb41ec37": { + "filename": "Gold Runner II Level Editor (French).zip", + "disk0": "Gold Runner II.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"EDITRUN\"\n" + }, + "e37de61c9e60292cc1299eec2c127408f5eca1ef": { + "filename": "Gold Runner II Level Editor (French).zip", + "disk0": "Gold Runner II.dsk", + "joy-right": "kjoy0", + "basic": "RUN\"EDITRUN\"\n" + }, + "b2f42525f53405e0869f823207111b39272b9922": { + "filename": "Kiosque à limonade (Bill Batcher) (French).zip", + "disk0": "KIOSQUE2.DSK", + "basic": "RUN\"KIOSQUE2\"\n" + }, + "531a3d623bbe93c0250ae215bd416b8d2bc7bfc6": { + "filename": "Leo (Lomiq) (French).zip", + "disk0": "LEO.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"LEO\":EXEC\n" + }, + "315406060a401b78e4d5129bc2c2b8e30f260b5c": { + "filename": "Marble Maze (Diecom Products) (French translation).zip", + "disk0": "MARBLEF.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"MARBLEF\":EXEC\n" + }, + "e891ee9fe6a2abb7fbbfe471f147a76f9bcd9503": { + "filename": "Mastermind (Tom O'Brian) (French translation) (Coco 3).zip", + "machine": "coco3", + "disk0": "MASTERMF.DSK", + "basic": "RUN\"MASTERMF\"\n" + }, + "f3656717343ebbb9b2ce2993e0d155491ac00b77": { + "filename": "Miss Gobbler (Spectral Associates) (French translation).zip", + "disk0": "MISSGOBF.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MISSGOBF\":EXEC\n" + }, + "2109806767360b49765ab7ec524309d50ebb8020": { + "filename": "Moneyopoly (Tom Mix Software) (French Translation).zip", + "disk0": "MONOF.DSK", + "joy-left": "mjoy0", + "joy-right": "mjoy0", + "basic": "LOADM\"MONOF\":EXEC\n" + }, + "0072f25b5c1c6dfc352521a817d027de759dd825": { + "filename": "Mudpies (Computer Shack) (French translation).zip", + "disk0": "MUDPIEF.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MUDPIEF\":EXEC\n", + "tv-input": "redblue" + }, + "e98463183f48483a560a5d63c52be8c93262eaa5": { + "filename": "Nerble Force (Computerware) (French translation).zip", + "disk0": "NERBLEF.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"NERBLEF\":EXEC\n" + }, + "ecb36cb6ae22119749c4369f454885198cdfe9d5": { + "filename": "Pooyan (Tandy) (French translation).zip", + "disk0": "POOYANF.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"POOYANF\":EXEC\n" + }, + "e3c370c4afec501314f7baa880e28232fce889b8": { + "filename": "Quilles (Tropical Lanes) (T&D Software) (French translation).zip", + "disk0": "QUILLES.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"QUILLES\"\n" + }, + "b52d6e8d237caaf8e2e61885047cb523217d062b": { + "filename": "Rainbow Book of Adventures, The (French translation).zip", + "disk0": "RAINADVF.DSK", + "joy-right": "kjoy0", + "basic": "DIR\n" + }, + "84d82f4277cb5d07522be8fead0ba9ffece7e30b": { + "filename": "Route des pionniers (French).zip", + "disk0": "PIONIER2.DSK", + "basic": "RUN\"PIONIER2\"\n" + }, + "7456b1c003d63f9ab15e3157026aece3aae254bf": { + "filename": "Sailor Man (Tom Mix Software) (French translation).zip", + "disk0": "SAILORF.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SAILORF\":EXEC\n", + "tv-input": "redblue" + }, + "a3fa6aba4e2696e75143905ed914c5f1b543774b": { + "filename": "Shenanigans (Mark Data Products) (French translation).zip", + "disk0": "SHENAN-F.DSK", + "basic": "LOADM\"SHENAN-F\":EXEC\n" + }, + "cc359c5d52a779c906db7dca22153aa147462561": { + "filename": "Time Bandit (Computer Shack) (French translation).zip", + "disk0": "BANDITF.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"BANDITF\":EXEC\n" + }, + "b02d0acdc716f971827b34af3d56cecf8cce4454": { + "filename": "Annexion (Ediciel) (French).zip", + "disk0": "annexion.dsk", + "basic": "RUN\"ANNEXION\"\n" + }, + "922c3cab43c53d2da672bd0564338f3d6ae2ddc2": { + "filename": "Jeu de dames (Ediciel) (French).zip", + "disk0": "dame.dsk", + "basic": "RUN\"DAME\"\n" + }, + "1ad0e1e56149aa8295486deb727fa2af5378f3a6": { + "filename": "Télérama No. 1 (Vifi Nathan) (French).zip", + "disk0": "teleram1.dsk", + "basic": "DIR\n" + }, + "c61846225ed5b1d2e36d0c5bb5fe9f1e0830589b": { + "filename": "Télérama No. 2 (Vifi Nathan) (French).zip", + "disk0": "teleram2.dsk", + "basic": "DIR\n" + }, + "b03554a212e6f67bfcd6c9565cb6329b8a54aeb6": { + "filename": "Ballyhoo (Infocom).zip", + "disk0": "BALLYHOO.DSK", + "basic": "DOS\n" + }, + "298317131b2f7270ec66786d7436adb8a21e3d66": { + "filename": "Cutthroats (Infocom).zip", + "disk0": "CUTHROTS.DSK", + "basic": "DOS\n" + }, + "945242ebe1d1f9c7ccd022569a2055b8a4f527ec": { + "filename": "Deadline (Infocom).zip", + "disk0": "DEADLINE.DSK", + "basic": "DOS\n" + }, + "58c7f959305b138ff4529382822f7310b717c6c5": { + "filename": "Enchanter, The (Infocom).zip", + "disk0": "ENCHANTR.DSK", + "basic": "DOS\n" + }, + "9e654ecc42377d3954ea92c1063393d96c2360d3": { + "filename": "Four-In-One Sampler (Infocom).zip", + "disk0": "4-IN-1.DSK", + "basic": "DOS\n" + }, + "29644708ac3ff7966467207a43a616d83a0f0c84": { + "filename": "Hitchhiker's Guide to the Galaxy (Infocom).zip", + "disk0": "HTCHHKER.DSK", + "basic": "DOS\n" + }, + "4d8278d41685cd67e8ab3065eb9edba6d7a250a3": { + "filename": "Hollywood Hijinx (Infocom).zip", + "disk0": "HOLLYWD.DSK", + "basic": "DOS\n" + }, + "9705bc2eab35f108276fd75d8a39ad3231706c00": { + "filename": "Infidel (Infocom).zip", + "disk0": "INFIDEL.DSK", + "basic": "DOS\n" + }, + "a063da3197392b7f75ba47e05216f6dece63e428": { + "filename": "Leather Goddesses of Phobos (Infocom).zip", + "disk0": "LEATHER.DSK", + "basic": "DOS\n" + }, + "f49a5e4b1ce8d078c806ff891c06b5556e2d3e8e": { + "filename": "Lurking Horror, The (Infocom).zip", + "disk0": "LURKINGH.DSK", + "basic": "DOS\n" + }, + "86d10517c389021f5e5488cb6937251b64a66993": { + "filename": "Mini-ZORK (Infocom).zip", + "disk0": "MINIZORK.DSK", + "basic": "DOS\n" + }, + "10632e66cba333918e0e8577f5ecfab9a07fa010": { + "filename": "Moonmist (Infocom).zip", + "disk0": "MOONMIST.DSK", + "basic": "DOS\n" + }, + "d02ce3a20ef62cc8b79219038ddd12d1a93bf205": { + "filename": "Planetfall (Infocom).zip", + "disk0": "PLANETFL.DSK", + "basic": "DOS\n" + }, + "da704e6665875343c814ce820edc42c38bd20ce3": { + "filename": "Plundered Hearts (Infocom).zip", + "disk0": "HEARTS.DSK", + "basic": "DOS\n" + }, + "a2f101de9c6eb42fd86ee690a4afcdf61919b13b": { + "filename": "Sea Stalker (Infocom).zip", + "disk0": "SEASTALK.DSK", + "basic": "DOS\n" + }, + "3248bb2be5a898e29c584c6497c010ddb088a8b5": { + "filename": "Sorcerer (Infocom).zip", + "disk0": "SORCERER.DSK", + "basic": "DOS\n" + }, + "cedf073a1345f3b43312cb65b8799bab59772fc4": { + "filename": "Spellbreaker (Infocom).zip", + "disk0": "SPELLBRK.DSK", + "basic": "DOS\n" + }, + "b40a45d1029be6f1d14b321e0b76efa2487e3881": { + "filename": "StarCross (Infocom).zip", + "disk0": "STARCRSS.DSK", + "basic": "DOS\n" + }, + "1aa389f2b0f3530f531a4d5254ddc9b78b69c9b1": { + "filename": "Stationfall (Infocom).zip", + "disk0": "STATIONF.DSK", + "basic": "DOS\n" + }, + "4a9dfdc4832fa7f61af087f2cec6a25df3b43c63": { + "filename": "Suspect (Infocom).zip", + "disk0": "SUSPECT.DSK", + "basic": "DOS\n" + }, + "00258936e130efb6438044a6f2c0b01e5d250e39": { + "filename": "Suspended (Infocom).zip", + "disk0": "SUSPEND.DSK", + "basic": "DOS\n" + }, + "e42fae7c6fb0593f2d4ef67fcd617777e53a62ca": { + "filename": "Wishbringer (Infocom).zip", + "disk0": "WISHBRNG.DSK", + "basic": "DOS\n" + }, + "d3e02103050e7fd9b9a79f571da150c0d6d86449": { + "filename": "Witness, The (Infocom).zip", + "disk0": "WITNESS.DSK", + "basic": "DOS\n" + }, + "ad720c1402a53a846717b6aff65b1a165acd375d": { + "filename": "Zork III (Infocom).zip", + "disk0": "ZORK_III.DSK", + "basic": "DOS\n" + }, + "12f443fad8ccb7d232e6bc048e0a499d46c1d7e3": { + "filename": "Zork II (Infocom).zip", + "disk0": "ZORK_II.DSK", + "basic": "DOS\n" + }, + "1005612f871bcae5a5691da46c6657b922db390d": { + "filename": "Zork I (Infocom).zip", + "disk0": "ZORK_I.DSK", + "basic": "DOS\n" + }, + "8c563ae72fc182845b6d65065ac8ccd5f7439a56": { + "filename": "Ballyhoo (Infocom) (64 column) (Coco 3).zip", + "machine": "coco3", + "disk0": "BALLYHOO.DSK", + "basic": "DOS\n" + }, + "2214597507d267e7b5cd7449d5465aec97bec77b": { + "filename": "Cutthroats (Infocom) (64 column) (Coco 3).zip", + "machine": "coco3", + "disk0": "CUTHROTS.DSK", + "basic": "DOS\n" + }, + "13dcd1de5cdc801929cecbcafcb3f09ce677e3ff": { + "filename": "Deadline (Infocom) (64 column) (Coco 3).zip", + "machine": "coco3", + "disk0": "DEADLINE.DSK", + "basic": "DOS\n" + }, + "9d2e4083b356a422bdd66b177bf7d74d96140384": { + "filename": "Enchanter, The (Infocom) (64 column) (Coco 3).zip", + "machine": "coco3", + "disk0": "ENCHANTR.DSK", + "basic": "DOS\n" + }, + "d756f710cfcc1fec7d8470ff1a7825800434d99d": { + "filename": "Four-In-One Sampler (Infocom) (64 column) (Coco 3).zip", + "machine": "coco3", + "disk0": "4-IN-1.DSK", + "basic": "DOS\n" + }, + "3d630f54f4bf6b91ae627d9cfd22a338770cfc01": { + "filename": "Hitchhiker's Guide to the Galaxy (Infocom) (64 column) (Coco 3).zip", + "machine": "coco3", + "disk0": "HTCHHKER.DSK", + "basic": "DOS\n" + }, + "96235d1d1e18b674793c2f6a68ee300ade840f3e": { + "filename": "Hollywood Hijinx (Infocom) (64 column) (Coco 3).zip", + "machine": "coco3", + "disk0": "HOLLYWD.DSK", + "basic": "DOS\n" + }, + "e37fa206eb81dc115cfa6de99c2d523f7beaf5cd": { + "filename": "Infidel (Infocom) (64 column) (Coco 3).zip", + "machine": "coco3", + "disk0": "INFIDEL.DSK", + "basic": "DOS\n" + }, + "fad611814c9341cc4e4f2e28b58e129f1a634f0d": { + "filename": "Leather Goddesses of Phobos (Infocom) (64 column) (Coco 3).zip", + "machine": "coco3", + "disk0": "LEATHER.DSK", + "basic": "DOS\n" + }, + "1c4266439dcb399fa3754ddb402c95f8497780a7": { + "filename": "Lurking Horror, The (Infocom) (64 column) (Coco 3).zip", + "machine": "coco3", + "disk0": "LURKINGH.DSK", + "basic": "DOS\n" + }, + "b2daf01e2d1e4fb52b1b3c4a25e12aadef7bcd25": { + "filename": "Mini-ZORK (Infocom) (64 column) (Coco 3).zip", + "machine": "coco3", + "disk0": "MINIZORK.DSK", + "basic": "DOS\n" + }, + "9155b700f7281e59c1bc7c4683bce55ab4d28476": { + "filename": "Moonmist (Infocom) (64 column) (Coco 3).zip", + "machine": "coco3", + "disk0": "MOONMIST.DSK", + "basic": "DOS\n" + }, + "3ca1020e83bcb616634a8b63b958e1e18f8a3a1d": { + "filename": "Planetfall (Infocom) (64 column) (Coco 3).zip", + "machine": "coco3", + "disk0": "PLANETFL.DSK", + "basic": "DOS\n" + }, + "5171e71f23516f3957aa508e4a57fb8868da8346": { + "filename": "Plundered Hearts (Infocom) (64 column) (Coco 3).zip", + "machine": "coco3", + "disk0": "HEARTS.DSK", + "basic": "DOS\n" + }, + "e90242fac742b49b33384283017e0aa7e1534539": { + "filename": "Sea Stalker (Infocom) (64 column) (Coco 3).zip", + "machine": "coco3", + "disk0": "SEASTALK.DSK", + "basic": "DOS\n" + }, + "918e6fc6d4e9a9da0e4c82cd6d6852eec76978a0": { + "filename": "Sorcerer (Infocom) (64 column) (Coco 3).zip", + "machine": "coco3", + "disk0": "SORCERER.DSK", + "basic": "DOS\n" + }, + "1b9ed229e183dfe2490c4d9c951d5571f70166ba": { + "filename": "Spellbreaker (Infocom) (64 column) (Coco 3).zip", + "machine": "coco3", + "disk0": "SPELLBRK.DSK", + "basic": "DOS\n" + }, + "26787d71caac9bf11550ba726c10e56ac51da511": { + "filename": "StarCross (Infocom) (64 column) (Coco 3).zip", + "machine": "coco3", + "disk0": "STARCRSS.DSK", + "basic": "DOS\n" + }, + "968ad229d742ee45f0dfa96a76db3073a0c58fdc": { + "filename": "Stationfall (Infocom) (64 column) (Coco 3).zip", + "machine": "coco3", + "disk0": "STATIONF.DSK", + "basic": "DOS\n" + }, + "0f8d60e11773120a200745dae6ce5dbe802305b9": { + "filename": "Suspect (Infocom) (64 column) (Coco 3).zip", + "machine": "coco3", + "disk0": "SUSPECT.DSK", + "basic": "DOS\n" + }, + "b8ab0b44d989b1e9ca3e53d483fe866c467abd18": { + "filename": "Suspended (Infocom) (64 column) (Coco 3).zip", + "machine": "coco3", + "disk0": "SUSPEND.DSK", + "basic": "DOS\n" + }, + "3edce92cbf117327b0f99875421c56cea2baa460": { + "filename": "Wishbringer (Infocom) (64 column) (Coco 3).zip", + "machine": "coco3", + "disk0": "WISHBRNG.DSK", + "basic": "DOS\n" + }, + "8516dea9fa90e4ef999bd5041ee5346b1ef6261b": { + "filename": "Witness, The (Infocom) (64 column) (Coco 3).zip", + "machine": "coco3", + "disk0": "WITNESS.DSK", + "basic": "DOS\n" + }, + "b3f2fd85e36b6031d999dbf68979c14506ce4312": { + "filename": "Zork III (Infocom) (64 column) (Coco 3).zip", + "machine": "coco3", + "disk0": "ZORK_III.DSK", + "basic": "DOS\n" + }, + "f33b664a3e09fa2d67e00e45219433a63a3bb0d8": { + "filename": "Zork II (Infocom) (64 column) (Coco 3).zip", + "machine": "coco3", + "disk0": "ZORK_II.DSK", + "basic": "DOS\n" + }, + "b7ec43e4a4f7ea23371bd50f3bf41470fcbcd8d0": { + "filename": "Zork I (Infocom) (64 column) (Coco 3).zip", + "machine": "coco3", + "disk0": "ZORK_I.DSK", + "basic": "DOS\n" + }, + "521b5b9a0ecd44754529eeee9bb8eddb8869738b": { + "filename": "Aventura em San Quentin (Portuguese).zip", + "disk0": "SAN.DSK", + "basic": "RUN\"SAN\"\n" + }, + "65cc3d273eb090824d135ff9c4ca59ee608d4022": { + "filename": "Birds (Portuguese translation).zip", + "disk0": "PHOENIX.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"PHOENIX\":EXEC\n" + }, + "82806c2f21788ef86a1396d565a8dcbf6a93312e": { + "filename": "Blackjack (Tandy) (Portuguese Translation).zip", + "disk0": "21.DSK", + "basic": "RUN\"21\"\n" + }, + "c17320d08d0be5adaf81f5d6f96e532da5e69a7a": { + "filename": "Black Sanctum, The (Mark Data Products) (Portuguese translation).zip", + "disk0": "SANCTUMP.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SANCTUMP\":EXEC\n", + "tv-input": "redblue" + }, + "3590fb2567cc05325ed0f80443a92b0019ab3c41": { + "filename": "Blackbeard's Island (Novasoft) (Portuguese translation).zip", + "disk0": "BLACKBPT.DSK", + "basic": "LOADM\"BLACKBPT\":EXEC\n" + }, + "316c9bab1addcfc55d457e100e9f375c0f45715b": { + "filename": "Bomba (Henio Bazerra) (Portuguese).zip", + "disk0": "BRITANIA.DSK", + "basic": "RUN\"BRITANIA\"\n" + }, + "a695fb1f855578d16e236410e16180e713516a8f": { + "filename": "Brew Master (Novasoft) (Portuguese translation).zip", + "disk0": "BREWP.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"BREWP\":EXEC\n" + }, + "aa2e70cf55d8789eb65213bcf0916a19cec3fe33": { + "filename": "Caladuril (Diecom Products) (Portuguese translation).zip", + "disk0": "CALP.DSK", + "basic": "LOADM\"CALP\":EXEC\n" + }, + "90518e4388a85bc932b618aa655be22b3d42a583": { + "filename": "Calixto Island (Mark Data Products) (Portuguese translation).zip", + "disk0": "CALIXTOP.DSK", + "basic": "LOADM\"CALIXTOP\":EXEC\n", + "tv-input": "redblue" + }, + "b2da60420194d3025152de5cadaa36aecc5a0f5d": { + "filename": "Canyon Climber (Tandy) (Portuguese Translation).zip", + "disk0": "CANYONP.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CANYONP\":EXEC\n" + }, + "c4f468daed4acb894ec574d614acba9a7631f235": { + "filename": "Cashman (Computer Shack) (Portuguese Translation).zip", + "disk0": "CASHMANP.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"CASHMANP\":EXEC\n", + "tv-input": "redblue" + }, + "a2128fc68729cf2c5cdb9ea4ee24d9ffffab8ea3": { + "filename": "Castelo (Portuguese).zip", + "disk0": "CASTELO.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"CASTELO\"\n" + }, + "d0230716c1d51ee87136ca2ed9d80b5ecfc3fcb6": { + "filename": "Color Blackjack (The Rainbow) (Portuguese translation).zip", + "disk0": "BLKJACK.DSK", + "basic": "RUN\"BLK JACK\"\n" + }, + "b98d6dbe657fc5f269e7ad0ad9e614cd5bb5297f": { + "filename": "Color Car Action (Novasoft) (Portuguese translation).zip", + "disk0": "COLORCAR.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"COLORCAR\":EXEC\n" + }, + "646fe8963cc9c021208964e52591d95150ed4f25": { + "filename": "Color Golf (Plansoft) (Portuguese).zip", + "disk0": "CLRGOLF.DSK", + "basic": "RUN\"CLRGOLF\"\n" + }, + "f4950106845592ad9e2a7310835472a14c504cc3": { + "filename": "Color Meteroids (Portuguese translation).zip", + "disk0": "COLORMET.DSK", + "joy-left": "mjoy0", + "joy-right": "kjoy0", + "basic": "LOADM\"COLORMET\":EXEC\n" + }, + "f91fe6620b8413047b1a26eee83694d8cf1d1b7f": { + "filename": "Color Space Invaders (Portuguese translation) (Spectral Associates).zip", + "disk0": "INVADER.DSK", + "basic": "LOADM\"INVADER\":EXEC\n" + }, + "c39b9329b0ba742206f4de0028dcfab850f02dd3": { + "filename": "Cuber (Tom Mix Software) (Portuguese translation).zip", + "disk0": "CUBER.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CUBER\":EXEC\n" + }, + "c3cc5f3866adb7d5e2077e65b5029a6ee44709a5": { + "filename": "Demon Seed (Portuguese translation).zip", + "disk0": "DEMON.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"DEMON\":EXEC\n" + }, + "23094f22986ffb9e4bc7dd5aeff3a151b8aff6ba": { + "filename": "Desert Patrol (Arcade Animation Inc.) (Portuguese translation).zip", + "disk0": "PATROLP.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"PATROLP\":EXEC\n" + }, + "309430dfac94d0389bc98481931a9c02aae75cf1": { + "filename": "Desert Rider (Tandy) (Portuguese translation).zip", + "disk0": "DESERT2P.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"DESERT2P\":EXEC\n" + }, + "1a8c70fe3f3caa9681fc8f34c5cbade35a4c3404": { + "filename": "Desert Rider (Tandy) (Portuguese translation).zip", + "disk0": "DESERT2P.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"DESERT2P\":EXEC\n" + }, + "d238e6bd8903c6a628b60ffddd57f75674d88cfb": { + "filename": "Devious (Spectral Associates) (Portuguese translation).zip", + "disk0": "DEVIOUSP.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"DEVIOUSP\":EXEC\n" + }, + "cee36e649f5a5bebf7cdacd7cc3e77b4b35a7ad8": { + "filename": "Downland (Tandy) (Portuguese translation).zip", + "disk0": "DOWNLAND.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"DOWNLAND\":EXEC\n" + }, + "4244c573d87d4699fa19c84d91fa7c12747b6274": { + "filename": "Dunkey Monkey (Intellectronics) (Portuguese Translation).zip", + "disk0": "DONKEYM.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"DUNKEYM\":EXEC\n" + }, + "da63342d3fe6a32d34dfc05f0ad7acc04fe03256": { + "filename": "Excalibur (Portuguese).zip", + "disk0": "EXCALIBU.DSK", + "basic": "RUN\"EXCALIBU\"\n" + }, + "4e595f2aa08ffd035593306e52886d09eefe3e35": { + "filename": "F-16 Assault (Diecom Products) (SSC) (Portuguese translation).zip", + "disk0": "F16P.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"F16 P\":EXEC\n", + "tv-input": "redblue" + }, + "7451dcbe44366f95660afeb0217f1679572ffcdb": { + "filename": "F-16 Assault (Diecom Products) (SSC) (Portuguese translation).zip", + "disk0": "F16P.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"F16 P\":EXEC\n", + "tv-input": "redblue" + }, + "4270fbcc6fb55c80f6469d7aa88d4dfcde9f8179": { + "filename": "Froggie (Spectral Associates) (SSC) (Portuguese translation).zip", + "disk0": "FROGGIEP.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"FROGGIEP\":EXEC\n" + }, + "4ce47ce369a6a17ba92f7421f403a9dff6ff57b9": { + "filename": "Fury (Computer Shack) (Portuguese translation).zip", + "disk0": "FURYP.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"FURYP\":EXEC\n" + }, + "56f3425dd11595bcd5a7cf23b13c7bbdbdfc76ca": { + "filename": "Galactic Attack (Tandy) (Portuguese translation).zip", + "disk0": "GALACTIP.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"GALACTIP\":EXEC\n" + }, + "50a03f4a05fc5269647353b196cb3abc2df067c4": { + "filename": "Galactic Fighter (Four Star Software) (Portuguese translation).zip", + "disk0": "GFIGHTEP.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"GFIGHTEP\":EXEC\n" + }, + "571c29eb28985c312e9052d31071614c0ab02bdd": { + "filename": "Galatic Wars (Lynn Davis) (Portuguese).zip", + "disk0": "GALATIC.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"GALATIC\"\n" + }, + "9fd14d8b98114fab587b0b56721ea9e92b763bc2": { + "filename": "Ghana Bwana (Tandy) (SSC) (Portuguese translation).zip", + "disk0": "GHANAP.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"GHANAP\"\n" + }, + "0ae2325a559e4025261f29246b1638b0890ebe3c": { + "filename": "Guardian (Portuguese translation).zip", + "disk0": "GUARDIAN.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"GUARDIAN\":EXEC\n" + }, + "5d362f578de64255a884135e4af1d90ee5312671": { + "filename": "Juno (Federal Hill) (Portuguese translation).zip", + "disk0": "JUNOP.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"JUNOP\":EXEC\n" + }, + "05f7cdf880960d5f9130fc79e2e88a70d111f282": { + "filename": "Jupiter Patrol (Aardvark-80) (Portuguese translation).zip", + "disk0": "JUPATROP.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"JUPATROP\":EXEC\n" + }, + "5f8259194ab18ba0bec1b6f64aa05869ad797444": { + "filename": "Labirinto (Portuguese).zip", + "disk0": "LABIRINT.DSK", + "basic": "RUN\"LABIRINT\"\n" + }, + "1fbe0a0a2b576ba8cb4fb18431bd101391e58fcc": { + "filename": "Lunchtime (Tom Mix Software) (Portuguese translation).zip", + "disk0": "LUNCHP.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"LUNCHP\":EXEC\n" + }, + "d04a1060a97a275f78df84999ea158f671726afb": { + "filename": "Mansion Adventure (Portuguese translation).zip", + "disk0": "MANSAO.DSK", + "basic": "RUN\"MANSAO\"\n" + }, + "e790050caaa005e89c60715ac649c01c590c5de4": { + "filename": "Major Istar (Computerware) (Portuguese translation).zip", + "disk0": "MISTARPT.DSK", + "basic": "LOADM\"MISTARPT\":EXEC\n" + }, + "b3d876d4e60a719a5c78df547204244345436cc6": { + "filename": "Marooned (Saguaro Sotware) (Portuguese translation).zip", + "disk0": "MAROONEP.DSK", + "basic": "RUN\"MAROONEP\"\n", + "tv-input": "redblue" + }, + "a6b650885153759a5c31242b945171dab9ef3948": { + "filename": "Martian Crypt, The (Tom Mix Software) (Portuguese Translation).zip", + "disk0": "CRIPTAPT.DSK", + "basic": "LOADM\"CRIPTAPT\":EXEC\n", + "tv-input": "redblue" + }, + "de695334032be072a1f63b5d769fa919e8f24017": { + "filename": "Megamunk (Color Connection Software) (Portuguese).zip", + "disk0": "MEGAMUNK.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MEGAMUNK\":EXEC\n" + }, + "29f92d723802b039b7ce57982f2844216fcc6792": { + "filename": "Module Man (Spectral Associates) (SSC) (Portuguese translation).zip", + "disk0": "MODULEP.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MODULEP\":EXEC\n" + }, + "fdd3ba0aebd651f9b0cfc5dd48bb52176b2999a3": { + "filename": "Moon Cresta (Incentive Software) (Coco port) (Portuguese translation).zip", + "disk0": "CRESTAP.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"CRESTAP\":EXEC\n" + }, + "d19ffa332ada1254ee2b4e8b53edfa5ed3e3db33": { + "filename": "Monopoly (Portuguese).zip", + "disk0": "MONOPOLY.DSK", + "basic": "RUN\"MONOPOLY\"\n" + }, + "3b4635fc4053b77378ada10e5e626110622f1f22": { + "filename": "Mudpies (Computer Shack-Michtron) (Portuguese translation).zip", + "disk0": "MUDPIESP.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"MUDPIESP\":EXEC\n", + "tv-input": "redblue" + }, + "9f55345da6a3ba5f69c217485e7aae817830ea40": { + "filename": "Olho (Portuguese).zip", + "disk0": "OLHO.DSK", + "basic": "RUN\"OLHO\"\n" + }, + "b847447a3da4bf46e70e3522b91a96527781511f": { + "filename": "Outhouse (Computer Shack) (Portuguese translation).zip", + "disk0": "OUTHOUSP.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"OUTHOUSP\":EXEC\n" + }, + "7c6f865914459d36a5069bb169ab6c51b3901a20": { + "filename": "O Resgate (Daniel Scherer) (Portuguese).zip", + "disk0": "RESGATE.DSK", + "basic": "RUN\"BOOT\"\n" + }, + "cf9e629dc1ee0af3a65ca146edfe59d0a7699f57": { + "filename": "Panic Button (Tandy) (Portuguese translation).zip", + "disk0": "PANICP.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"PANICP\":EXEC\n" + }, + "48bd11345201533d7604cf43bf4a5b805ddb80d0": { + "filename": "Paper Route (Diecom Products) (Portuguese translation).zip", + "disk0": "PAPERP.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"PAPERP\":EXEC\n" + }, + "5d7dfe1db00da0a7d03973a362bafa69ca07e541": { + "filename": "Pengon (Spectral Associates) (Portuguese translation).zip", + "disk0": "PENGONP.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"PENGONP\":EXEC\n", + "tv-input": "redblue" + }, + "56efe14542db2fab36c09d59ab8bd07909a46ab4": { + "filename": "Pooyan (Tandy) (Portuguese Translation).zip", + "disk0": "POOYANP.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"POOYANP\":EXEC\n" + }, + "e917ff168c311760f5e223e856df23f9be963a1b": { + "filename": "Pouso Lunar (Portuguese).zip", + "disk0": "LANDER.DSK", + "basic": "RUN\"LANDER\"\n" + }, + "7bfa3712a5255272114579f23c4f53bbc45b8b81": { + "filename": "Ralli (Portuguese).zip", + "disk0": "RALLI.DSK", + "basic": "RUN\"RALLI\"\n" + }, + "24599ebc78737244aff2cf18c4547397834c87da": { + "filename": "Sailor Man (Tom Mix Software) (Portuguese translation).zip", + "disk0": "SAILORP.DSK", + "joy-right": "kjoy0", + "basic": "RUN\"SAILORP\"\n", + "tv-input": "redblue" + }, + "98fd3eb07152a2f811784765b6b4ea19a92c64ff": { + "filename": "Sam Sleuth (Computerware) (Portuguese translation).zip", + "disk0": "SLEUTHP.DSK", + "basic": "LOADM\"SLEUTH1P\":EXEC\n" + }, + "22ea520d5ab521ef8e2f0cb9654880abafee5dff": { + "filename": "Sea Dragon (Adventure International) (Portuguese Translation).zip", + "disk0": "SEADRAGP.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SEADRAGP\":EXEC\n" + }, + "122bc689c5fae874207cf2bbe1bb63a29dcbea6d": { + "filename": "Shenanigans (Mark Data Products) (Portuguese translation).zip", + "disk0": "SHENPORT.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SHENPORT\":EXEC\n", + "tv-input": "redblue" + }, + "13af879d87ab5dab9c42a13799f53de154f011c8": { + "filename": "Sea Quest (Mark Data Products) (Portuguese translation).zip", + "disk0": "SEAQPORT.DSK", + "basic": "LOADM\"SEAQPORT\":EXEC\n", + "tv-input": "redblue" + }, + "f8fe238265822cb75034746421bdb1cddd918a7a": { + "filename": "Skyway (Tom Mix Software) (Portuguese translation).zip", + "disk0": "SKYWAYP.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"SKYWAYP\":EXEC\n", + "tv-input": "redblue" + }, + "7dd41b63b9c5de71d36379ec2a9ffceb6181fb11": { + "filename": "Stone Raider II (Microdeal Cornwall) (Portuguese translation).zip", + "disk0": "STONRAIP.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"STONRAIP\":EXEC\n" + }, + "2be0d8b984241670fa0e41a89c72241ae8df41f2": { + "filename": "Super Startrek (KJM) (Portuguese).zip", + "disk0": "SUPETREK.DSK", + "basic": "RUN\"SUPETREK\"\n" + }, + "8c4e752c916fa73e4b577c1d4fd2b722b1bba8b1": { + "filename": "Taipan (Megasoft) (Portuguese).zip", + "disk0": "TAIPAN.DSK", + "basic": "RUN\"TAIPAN\"\n" + }, + "726a184df92117f713537939676ccfbaf204a734": { + "filename": "The Frog (Portuguese translation).zip", + "disk0": "FROG.DSK", + "basic": "LOADM\"FROG\":EXEC\n" + }, + "1b5e2b437498b29fa79983099a252a4f13338056": { + "filename": "Time Bandit (Computer Shack) (Portuguese translation).zip", + "disk0": "BANDITP.DSK", + "joy-left": "kjoy0", + "basic": "LOADM\"BANDITP\":EXEC\n" + }, + "e8392c2f68cc6bf0c949227d1343355f83918890": { + "filename": "Trekboer (Mark Data Products) (Portuguese Translation).zip", + "disk0": "TREKPORT.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"TREKPORT\":EXEC\n", + "tv-input": "redblue" + }, + "727293ce95679c16054751eeb1d0d2549aebc861": { + "filename": "Torres (Tower of Hanoi) (Portuguese).zip", + "disk0": "TORRES.DSK", + "basic": "RUN\"TORRES\"\n" + }, + "8e6c00f8f5dcc8a7d39df45a6918ae8293bb2a55": { + "filename": "Vortex Factor, The (Mark Data Products) (Portuguese Translation).zip", + "disk0": "VORTEXPT.DSK", + "basic": "LOADM\"VORTEXPT\":EXEC\n", + "tv-input": "redblue" + }, + "225ee1ac0f5e280fcd77a149ddcc32ce63b89801": { + "filename": "Zaxxon (Datasoft) (Portuguse translation).zip", + "disk0": "ZAXXON.DSK", + "joy-right": "kjoy0", + "basic": "LOADM\"ZAXXON\":EXEC\n" + }, + "2e8aed5e19469433ec105a1b7b7061b6ced02631": { + "filename": "Adventure #10 - Savage Island Part 1 (Adventure International) (6847T1).zip", + "machine": "coco2bus", + "disk0": "SAVAGE1.DSK", + "basic": "LOADM\"SAVAGE1\":EXEC\n" + }, + "ee9a1b762f757b45bc7006ff8bc4a08c0372ed2a": { + "filename": "Adventure #12 - The Golden Voyage (Adventure International) (6847T1).zip", + "machine": "coco2bus", + "disk0": "VOYAGE.DSK", + "basic": "LOADM\"VOYAGE\":EXEC\n" + }, + "b455e8e4d2067394c6c0447fba2077b4aa8e5eb7": { + "filename": "Adventure #11 - Savage Island Part 2 (Adventure International) (6847T1).zip", + "machine": "coco2bus", + "disk0": "SAVAGE2.DSK", + "basic": "LOADM\"SAVAGE2\":EXEC\n" + }, + "b889ddf333a64f687575fcb6c0969a7e95be9e25": { + "filename": "Adventure #13 - Sorcerer of Claymorgue Castle (Adventure International) (6847T1).zip", + "machine": "coco2bus", + "disk0": "SORCERER.DSK", + "basic": "LOADM\"SORCERER\":EXEC\n" + }, + "b5ddfdc65e0fb946451bb8ba858bf3d1694fab9d": { + "filename": "Adventure #1 - Adventureland (Adventure International) (6847T1).zip", + "machine": "coco2bus", + "disk0": "ADVENTUR.DSK", + "basic": "LOADM\"ADVENTUR\":EXEC\n" + }, + "9be0df3281023bf8fcccc51e8277c0a0bd3d4b7f": { + "filename": "Adventure #2 - Pirate Adventure (Adventure International) (6847T1).zip", + "machine": "coco2bus", + "disk0": "PIRATE.DSK", + "basic": "LOADM\"PIRATE\":EXEC\n" + }, + "6e19aab5547b08eae81c204ac76c5674bff82beb": { + "filename": "Adventure #3 - Secret Mission (Adventure International) (6847T1).zip", + "machine": "coco2bus", + "disk0": "MISSION.DSK", + "basic": "LOADM\"MISSION\":EXEC\n" + }, + "c2f7586573004bdb54c008fd2fdac6b86d4561da": { + "filename": "Adventure #4 - Voodoo Castle (Adventure International) (6847T1).zip", + "machine": "coco2bus", + "disk0": "VOODOO.DSK", + "basic": "LOADM\"VOODOO\":EXEC\n" + }, + "671d9147d24e12e6f64ab65f0350c0deae35ce5c": { + "filename": "Adventure #6 - Strange Odyssey (Adventure International) (6847T1).zip", + "machine": "coco2bus", + "disk0": "ODYSSEY.DSK", + "basic": "LOADM\"ODYSSEY\":EXEC\n" + }, + "e5cd09ed68cc4d772d3849c8bb5658147753e5dd": { + "filename": "Adventure #7 - Mystery Fun House (Adventure International) (6847T1).zip", + "machine": "coco2bus", + "disk0": "FUNHOUSE.DSK", + "basic": "LOADM\"FUNHOUSE\":EXEC\n" + }, + "3165b173d7d2ae7645f1a7515eab378d3ffac668": { + "filename": "Adventure #8 - Pyramid of Doom (Adventure International) (6847T1).zip", + "machine": "coco2bus", + "disk0": "PYRAMID.DSK", + "basic": "LOADM\"PYRAMID\":EXEC\n" + }, + "5a93c4ecce176b71bfe9305962f62e7e1fac7a3e": { + "filename": "Adventure #9 - Ghost Town (Adventure International) (6847T1).zip", + "machine": "coco2bus", + "disk0": "GHOST.DSK", + "basic": "LOADM\"GHOST\":EXEC\n" + }, + "5dd92035d5a83539907c99c56338a7d8efdf7ede": { + "filename": "QuestProbe #1 - The Hulk (Adventure International) (6847T1).zip", + "machine": "coco2bus", + "disk0": "HULK.DSK", + "basic": "LOADM\"HULK\":EXEC\n" + }, + "ada9fa117aba3db231dc2063b0d5c9691b2a6aef": { + "filename": "AGI Quest I (Juha Terho) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/agiquest.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "d85ff0b2917be41d830c01221825f88bd0a8147d": { + "filename": "AGI Quest I (Juha Terho) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/agiquest.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "7b549d53b0ae85ae9c44efa245dc2a4469468071": { + "filename": "AGI Quest I (Juha Terho) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/agiquest.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "e888b2862573ee06f192569b7ed05a7e739b8f9e": { + "filename": "AGI Quest I (Juha Terho) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/agiquest.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "33496337cb30fa0315a47690255b0303b7ca4358": { + "filename": "Black Cauldron, The (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/bc-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "d548e8726f097e1425d2491dc23eb5e0a25d125c": { + "filename": "Black Cauldron, The (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/bc-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "700f67b561442900239a00d1baedecb0672071f5": { + "filename": "Black Cauldron, The (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/bc-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "a5152ec2f2c972cc8b6efb96636553a79958d1f0": { + "filename": "Black Cauldron, The (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/bc-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "2d68d55a43d52168016c672428fea04473b8bc8b": { + "filename": "Black Cauldron, The (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/bc-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "6e32cb9df7022f8b8459181f87722f05607d3a8d": { + "filename": "Black Cauldron, The (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/bc-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "774f5a75834954558d11ecf54f6422e477d837fa": { + "filename": "Caitlyn's Destiny (Corby Lacroix) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/caitlyn-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "632723a5df5fe2e0401b0348de8a5779f5635e91": { + "filename": "Caitlyn's Destiny (Corby Lacroix) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/caitlyn-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "583eb95ab4e0303811f762a49b86e162dd16f670": { + "filename": "Caitlyn's Destiny (Corby Lacroix) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/caitlyn-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "407c3baaff2a1d75fd55a9c1ada3a3f26fe81972": { + "filename": "Caitlyn's Destiny (Corby Lacroix) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/caitlyn-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "4bfa7cb1b341e2ac952194b88b66bfdb3bd8555b": { + "filename": "Caitlyn's Destiny (Corby Lacroix) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/caitlyn-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "3bb89a7a2d2ec1022bf724f701f95554784b7557": { + "filename": "Caitlyn's Destiny (Corby Lacroix) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/caitlyn-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "1049237115e7ae0faaae2e605bdf0e4a25286a34": { + "filename": "Caitlyn's Destiny (Corby Lacroix) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/caitlyn-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "d28cf636e396421f605b1eb9bedcb72526f7b90b": { + "filename": "Caitlyn's Destiny (Corby Lacroix) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/caitlyn-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "56ea1e75978c1942a70d13ed3738c3565be6f6cc": { + "filename": "Caitlyn's Destiny (Corby Lacroix) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/caitlyn-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "b8e998b349e7c4248b3dc58559985fed0d94e08b": { + "filename": "Caitlyn's Destiny (Corby Lacroix) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/caitlyn-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "8d0301c76d92daa136596d3918a39937cc6c0d40": { + "filename": "Caitlyn's Destiny (Corby Lacroix) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/caitlyn-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "a5abf7e2533bc081de7ba2634ab565102c4c2216": { + "filename": "Caitlyn's Destiny (Corby Lacroix) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/caitlyn-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "40a787ec873a9f0d22418059624c55be721a0c3c": { + "filename": "Caitlyn's Destiny (Corby Lacroix) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/caitlyn-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "93ba947c9a9ffecc635481efd6434da586f704de": { + "filename": "Enclosure (Femo Duo Entertainment) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/enclos-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "26fbf4025e0b2cc3f17335bf2a2aa90350647e1b": { + "filename": "Enclosure (Femo Duo Entertainment) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/enclos-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "2367fe31180da3e67d87fc9d907ffe67afb8c97a": { + "filename": "Enclosure (Femo Duo Entertainment) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/enclos-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "10bb515a813a7d2655ab2e92ebb1c2229eb40ea0": { + "filename": "Enclosure (Femo Duo Entertainment) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/enclos-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "399b2ab1fe580e29271c230b0d84ddc8ed497c13": { + "filename": "Enclosure (Femo Duo Entertainment) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/enclos-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "6f2f052ab128e658f60d46f807ca3ac731dbedd0": { + "filename": "Enclosure (Femo Duo Entertainment) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/enclos-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "24da338bd476545698faa72555a2a2bcffa9afbc": { + "filename": "Enclosure (Femo Duo Entertainment) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/enclos-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "9dee02ecf3040d375ffdc6327ec5804982f63514": { + "filename": "Enclosure (Femo Duo Entertainment) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/enclos-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "ce63fa6c922656d0ff674f8a458f0e33de8ed2e1": { + "filename": "Gold Rush! (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/gr-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "d94a706e677ddc60bfc9b75dc9ce683e76416e51": { + "filename": "Gold Rush! (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/gr-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "711c6ff48db181ffd5c54cefbc2267fe300e2855": { + "filename": "Gold Rush! (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/gr-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "9c9d688bd3a2acd5240d9464f6c289d40370105e": { + "filename": "Gold Rush! (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/gr-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "e4fbf921bb656c4fbd6a59ac910d55958748e2bd": { + "filename": "Gold Rush! (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/gr-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "3ee17510edbcb7724bc73500c87a9a5c8651586b": { + "filename": "Gold Rush! (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/gr-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "75f83d2d55e98dbd956417295925bc528e33bfee": { + "filename": "Gold Rush! (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/gr-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "e6e0784c75b4ca61170fdac7f9f6b0e3e366246f": { + "filename": "Gold Rush! (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/gr-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "6ddb18b62f9a894dceae7ec9a1e83931dce9e892": { + "filename": "Gold Rush! (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/gr-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "74bd13b5f2fc306923e5caac280cea923fb0f536": { + "filename": "Gold Rush! (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/gr-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "815eaa09d8bf66f9b144241b7b8b221b47dcc651": { + "filename": "Gold Rush! (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/gr-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "77a57fb3012962d3437dc1a7db533772192226ed": { + "filename": "Gold Rush! (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/gr-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "4b7477b0b88668f42530c954d316f80126fda0f6": { + "filename": "Gold Rush! (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/gr-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "2148be2ecd559d797d1347f69523202f01940377": { + "filename": "King's Quest III (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/kq3-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "997a4b51fd36da36da9a1209f1207bce46ce6516": { + "filename": "King's Quest III (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/kq3-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "23f076f81804fc52f6277eda014ef23281e9ca91": { + "filename": "King's Quest III (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/kq3-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "4277ec4ea0d57d66505fc370701793515c2b7cb6": { + "filename": "King's Quest III (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/kq3-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "341f9f69e3bfcc539e44665ce44f1ccd37191e8b": { + "filename": "King's Quest III (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/kq3-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "99d981902a8025068316020dd1e0aad5a5453ea2": { + "filename": "King's Quest III (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/kq3-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "869e9875949325968423da32f55f9633adfbc5a9": { + "filename": "King's Quest III (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/kq3-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "118ec75c1c42abe787f7dd43211dfdf3d67bde03": { + "filename": "King's Quest III (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/kq3-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "3564eb0b175764db1d415abf47e709ec1c4f5138": { + "filename": "King's Quest III (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/kq3-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "42f1813d00f3284b43356dc229a409a8073a1839": { + "filename": "King's Quest III (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/kq3-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "4b1e13beb0418a2c38f55ff51aed584cecb6cc60": { + "filename": "King's Quest III (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/kq3-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "8e6599e1444aea19b0c47fcd74da91c0b6cd42dd": { + "filename": "King's Quest III (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/kq3-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "4009eebe8b9d878bac23391812d53c5debd943ee": { + "filename": "King's Quest III (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/kq3-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "80f9621f748aaab8bb7208b59d179e9291b3ca4a": { + "filename": "King's Quest III (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/kq3-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "eca05ca67d9aef88668b001b304a8ba7d2cd3dd8": { + "filename": "King's Quest III (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/kq3-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "d837a7e1255f7c848d807175f44153a1688f2e37": { + "filename": "King's Quest III (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/kq3-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "07fcbe1fc986155bb2e7cda8bf902e387b5a1d9e": { + "filename": "King's Quest II (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/kq2.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "855886c906e7b43912c6761e50ffa25dc6108dc9": { + "filename": "King's Quest II (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/kq2.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "cb9d3663fe5062b40708bbee35ebbb6300c5f243": { + "filename": "King's Quest II (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/kq2.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "3b65d9121e8ba10c51235ff6ede350c4f40b172c": { + "filename": "King's Quest II (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/kq2.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "119faa489726e48cae7300b025effcf2432b7214": { + "filename": "King's Quest II (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/kq2.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "7a7cf4090b950b10e52ea42a0fd4655d327d76af": { + "filename": "King's Quest II (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/kq2.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "006611b160a8df0d16478acc7d9b5ca8efc296ec": { + "filename": "King's Quest II (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/kq2.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "ff833548208bc60da639353d4fe2b32ecb2e55e5": { + "filename": "King's Quest I (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/kq1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "797d880d1466ad61da783445a3d4dc8998204848": { + "filename": "King's Quest I (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/kq1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "e4f57283332c1036887a3bb37233d259f414d6fb": { + "filename": "King's Quest I (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/kq1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "bb77881216c85e423007a83473c66d79ad5d8469": { + "filename": "King's Quest I (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/kq1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "ef9db5601a137d70df81e38e1e4bd6cec0fab235": { + "filename": "King's Quest I (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/kq1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "ba96f2825c42751d3046af719a38f9eb5620c5b4": { + "filename": "King's Quest IV (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/kq4-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "8fb58da00ce6f9e4938d1a5db63bb5a085237c76": { + "filename": "King's Quest IV (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/kq4-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "93417304046a0792e33fa7ef4403e933c785825a": { + "filename": "King's Quest IV (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/kq4-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "68a44e79de9fd8eac6797122e862801c0f28484b": { + "filename": "King's Quest IV (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/kq4-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "bd9d16b65ca7682efffff29ad24d95e51fc3ca19": { + "filename": "King's Quest IV (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/kq4-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "5e39a37d78a356930fc9eefb662f3c95002bc495": { + "filename": "King's Quest IV (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/kq4-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "c2c5d93695aad49ec6507bf9ae381e29ff9f6e75": { + "filename": "King's Quest IV (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/kq4-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "3be477db3bf4ef2abdeb61d86169abc01ced6de2": { + "filename": "King's Quest IV (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/kq4-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "3553c1f139b0c6b9b6b933835de19d53c8330640": { + "filename": "King's Quest IV (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/kq4-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "679a69d87c00ddd49fccb9bfde91dda2c9c2f025": { + "filename": "King's Quest IV (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/kq4-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "78232ef8e8d5200c74c598d97fa6791774fb906d": { + "filename": "King's Quest IV (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/kq4-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "8434f89d2c1d6038a447fa1f0676131635e5a548": { + "filename": "King's Quest IV (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/kq4-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "f59a555e8032b078aa84ce419e4c3ae833c35268": { + "filename": "King's Quest IV (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/kq4-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "b5526bceffdebc56002c93fe34f42e8c9c9ac5a0": { + "filename": "King's Quest IV (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/kq4-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "1906d2a8cf3446a08dfefbe2c91cbe780aa7426c": { + "filename": "Leisure Suit Larry (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/lsl-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "085877afb36803b58b73fcf46ff4366f8120dd68": { + "filename": "Leisure Suit Larry (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/lsl-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "51253bb098220c6b3319cf43058dab419cfad636": { + "filename": "Leisure Suit Larry (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/lsl-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "d8302af015fcace30766e4d96e2f15c9d9072bd1": { + "filename": "Leisure Suit Larry (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/lsl-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "71f1d6aaec42fbe81bdf45debdbac3c08f11c2f6": { + "filename": "Leisure Suit Larry (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/lsl-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "0f19035455ab6eca902c12ccc79f4cc13fbfcf36": { + "filename": "Leisure Suit Larry (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/lsl-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "0e2dc0ba79971ab8545d49a7da54cbf7fe3c3c7c": { + "filename": "Leisure Suit Larry (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/lsl-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "5e4444df89883eefaf078b30a75f322204d0ce57": { + "filename": "Leisure Suit Larry (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/lsl-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "8bea7bca0424f7e3c5edf1fe19a7ca1570c7c27e": { + "filename": "Manhunter 1 - New York (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "370d0f63d71f168102de441a7732d48d2d833045": { + "filename": "Manhunter 1 - New York (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "216a158a17fd2816ef532831b0f57b8d746b5650": { + "filename": "Manhunter 1 - New York (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "3b32772fe3a9cec9a471cda25505dee5484786df": { + "filename": "Manhunter 1 - New York (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "dce1f53d81c3cbfea9389b23aa84eac6154a8986": { + "filename": "Manhunter 1 - New York (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "139179d53ae0f581b5f4f493d3ac24a0e1977105": { + "filename": "Manhunter 1 - New York (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "099c37715a16cc16046658c8e4e197cd076104fa": { + "filename": "Manhunter 1 - New York (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "950eb55dba751e7040e1d3e7c3d4f7cea97da8a8": { + "filename": "Manhunter 1 - New York (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "30b2a45621d55713ae86060acc72b207e5c0ca1d": { + "filename": "Manhunter 1 - New York (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "1f2b30bb53e4a2eebdc7a58e2565179d3582fbb0": { + "filename": "Manhunter 1 - New York (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "f2dd73402f82248eeadd664d41f7686880c716a9": { + "filename": "Manhunter 1 - New York (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "cea1ce98cd1373c012cebadb674f20e96ce19364": { + "filename": "Manhunter 1 - New York (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "9ffff1e29a9814bf09146636d937092f5fec0a7c": { + "filename": "Manhunter 1 - New York (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "6412716d1107fc512a19fc6249278105120e85aa": { + "filename": "Manhunter 1 - New York (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "9544cad56a66449c5f68d0e0bf68c0060c73cf13": { + "filename": "Operation Recon Demo (Dykstra-Budin Production) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/recon.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "55fc9043ac97b802e48923c972d097b7e15f29d8": { + "filename": "Operation Recon Demo (Dykstra-Budin Production) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/recon.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "f1a7494a7bd066e4c10e3ce8ddf30f5f12249c4d": { + "filename": "Operation Recon Demo (Dykstra-Budin Production) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/recon.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "9d6010242db6d194cbd149689e65b843fb08274d": { + "filename": "Operation Recon Demo (Dykstra-Budin Production) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/recon.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "ff59539ce83b0ab9b28ea02947ded41f83db976c": { + "filename": "Mixed-Up Mother Goose (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/mg-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "5cd883074d81bf6b184a35212442135d46e8af33": { + "filename": "Mixed-Up Mother Goose (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/mg-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "84676c117fad060458b5344253a785a53d6af4f9": { + "filename": "Mixed-Up Mother Goose (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/mg-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "fcf63719a9f425cac935e6a4074481b96b360dcf": { + "filename": "Mixed-Up Mother Goose (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/mg-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "94d1524dd58bdf8baad247d32f77961729f04b06": { + "filename": "Mixed-Up Mother Goose (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/mg-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "a4ccaa60a6e36e57afe5fb1415b5d5896bb78962": { + "filename": "Space Quest 1 (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/sq1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "44a3c6431126062ba845f42fbb149f161644559c": { + "filename": "Space Quest 1 (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/sq1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "e4d18e70219f59b973dc5e7f7fdd3d4ddcc138de": { + "filename": "Space Quest 1 (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/sq1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "b45460cc10cb9859c75ad0798f88f75b991b733a": { + "filename": "Space Quest 1 (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/sq1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "b998f7e275bf9c055f96fd914f55d7cbb92fd123": { + "filename": "Space Quest 1 (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/sq1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "5762dfebe2adb7cfea689397de1c86c087ea1fde": { + "filename": "Space Quest 1 (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/sq1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "52988e993ca0b650765a4c949ada2d62368f20aa": { + "filename": "Police Quest 1 (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/pq1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "c812d2dd739b7c00be9966fbde026b2743b8a6f6": { + "filename": "Police Quest 1 (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/pq1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "b35a4a2ca1b4d5e8c160ba46980cdc4f02fa95bb": { + "filename": "Police Quest 1 (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/pq1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "d075fad395f7d74a73167127076f36a7fefedfe7": { + "filename": "Police Quest 1 (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/pq1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "ebdfe6246cfb49d492b362ba06cb983498e57b6c": { + "filename": "Police Quest 1 (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/pq1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "9b7f0c9515f9609452385086e598c8f49b3a718b": { + "filename": "Police Quest 1 (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/pq1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "e48342c953a9fb505dbd24461c0ee2a834b59bf9": { + "filename": "Police Quest 1 (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/pq1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "16d7f9dae8107ba6c47e8b155886ba48e65262ec": { + "filename": "Police Quest 1 (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/pq1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "5ecc60e1d2909510f2ce599d25f35e5afd4e99ee": { + "filename": "Police Quest 1 (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/pq1-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "e69f191b6cd27ce6afc97a5b1c812e5d0dd065ea": { + "filename": "Space Quest 0 (Jefferson Stewart) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/sq0-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "5bb6a11c7d7758e1ac38a99c47d7bbd972c97797": { + "filename": "Space Quest 0 (Jefferson Stewart) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/sq0-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "abc4f1aee4804b7462b6a4dc71d20d6a11b34a85": { + "filename": "Space Quest 0 (Jefferson Stewart) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/sq0-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "17ae36dcfdae43694b9ab5671ade303292666db2": { + "filename": "Space Quest 0 (Jefferson Stewart) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/sq0-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "a783468d637e37370111ec33f7b6d5ee5faf8e57": { + "filename": "Space Quest 0 (Jefferson Stewart) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/sq0-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "8f6cc23a3109a68a44ea9ca5627cb364b6babc0b": { + "filename": "Space Quest 0 (Jefferson Stewart) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/sq0-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "c2e6fe70d3504686285bfcccd7316bec4670571e": { + "filename": "Space Quest 0 (Jefferson Stewart) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/sq0-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "4616ab407d8ba62f84fa96b27dff7db9a09b8738": { + "filename": "Space Quest 0 (Jefferson Stewart) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/sq0-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "6171d73e6c9f69bd334a4cb8e85c64a715e2b540": { + "filename": "Space Quest 2 (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/sq2-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "6823d5b818222acc99723fde56004217bc1c81a1": { + "filename": "Space Quest 2 (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/sq2-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "6013aaefc96a6330e652146187b1e9fb1c26f5c0": { + "filename": "Space Quest 2 (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/sq2-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "c9b3b77655d0640296235ba43d3d271fd7d6a8e1": { + "filename": "Space Quest 2 (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/sq2-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "ddf8749eb96f2a2f840c602843c78592dd70acfb": { + "filename": "Space Quest 2 (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/sq2-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "d4c8910b5720e4e50955b4c147b7be7744b9716f": { + "filename": "Space Quest 2 (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/sq2-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "4e3c10425ca878dbc85666084cd738b7bffa4115": { + "filename": "Space Quest 2 (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/sq2-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "ff6ec8c208feedefabe0a54e98c1b1c4927a6354": { + "filename": "Time Quest (Chad Goulding) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/tq.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "e2f933a2de507955a27a360f9ee18b1d398f03a0": { + "filename": "Time Quest (Chad Goulding) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/tq.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "41f63d67c7860182b70ff8b0b10eea0837a6d25e": { + "filename": "Time Quest (Chad Goulding) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/tq.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "b8eed0817069b8d23f4a109078d821bd90654668": { + "filename": "Time Quest (Chad Goulding) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/tq.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "c15251df18ce63eebebd58490380a7fd094e25d8": { + "filename": "Time Quest (Chad Goulding) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/tq.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "17a561c3b552ebe2ed2ed7850448382429d01797": { + "filename": "Voodoo Girl - Queen of the Darned (Andrew Baker) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/vg.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "42c6909d276676bcb885fab339b177d7dbd549a9": { + "filename": "Voodoo Girl - Queen of the Darned (Andrew Baker) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/vg.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "1f46e1ea1e6b941bc335abaf7b62c4303e8fdc79": { + "filename": "Voodoo Girl - Queen of the Darned (Andrew Baker) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/vg.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "f747ba781e94926a893351d876def491e44798f1": { + "filename": "Voodoo Girl - Queen of the Darned (Andrew Baker) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/vg.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "cc02f1d070bad3260352e946fa4a5f04ff04acd8": { + "filename": "Voodoo Girl - Queen of the Darned (Andrew Baker) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/vg.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "af0d91d8ce5a433ae5a6aa75bb0c4ea86b51b385": { + "filename": "Voodoo Girl - Queen of the Darned (Andrew Baker) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/vg.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "61804f84e3cfd617f1e89297512c3a257d958052": { + "filename": "Manhunter 2 - San Francisco (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh2-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "a1c1358c3c0ecc3321528eebd992c2980ed050f7": { + "filename": "Manhunter 2 - San Francisco (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh2-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "ea508324b3468ca6ea7d6616eaf98d7e7bd29f06": { + "filename": "Manhunter 2 - San Francisco (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh2-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "d443af95755811f88f0760ca1c832c86929a6ed6": { + "filename": "Manhunter 2 - San Francisco (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh2-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "8d431ec39e626f0bd0494b3ffbf53a443e614bf8": { + "filename": "Manhunter 2 - San Francisco (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh2-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "0c15700aa053dc61e7806c904935b03ea2c05f22": { + "filename": "Manhunter 2 - San Francisco (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh2-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "2e75bdce7ba055a7e9ef6f33718fe618ebdf37ed": { + "filename": "Manhunter 2 - San Francisco (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh2-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "fb30a44a57397e28e1d3072eb7ef205d647c7e2d": { + "filename": "Manhunter 2 - San Francisco (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh2-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "c6aebaf58ef7b437b8e79f58ad129e79e32f96ff": { + "filename": "Manhunter 2 - San Francisco (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh2-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "14ef39ebabdcad78241f9e155de1ab06dc4b202b": { + "filename": "Manhunter 2 - San Francisco (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh2-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "0adf1d233f7c353afafdc90fcf50247f2fe5c756": { + "filename": "Manhunter 2 - San Francisco (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh2-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "df33a1cfb794a85fe0ed27a5bd4fc8d5459b60ad": { + "filename": "Manhunter 2 - San Francisco (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh2-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "c516c314e3d6d397a0db665e9d979d7ebe6a8e21": { + "filename": "Manhunter 2 - San Francisco (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh2-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "a0a2f1ced65c34f6d1ff7702f466cf33c37e8f88": { + "filename": "Manhunter 2 - San Francisco (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh2-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "d24955b9b51d18354eb9145c57b9d1a0645c63f1": { + "filename": "Manhunter 2 - San Francisco (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh2-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "fc3f7b64a178c578197eedc9feefeebf9749cc5f": { + "filename": "Manhunter 2 - San Francisco (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh2-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "7d88d516ea0b9bf637ea478a31f31b50de059b3d": { + "filename": "Manhunter 2 - San Francisco (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh2-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "ce0e25c7b51c749da9e9af9ea914c14264120509": { + "filename": "Manhunter 2 - San Francisco (Sierra On-Line) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/mh2-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "1ee3908aeb5dcdad2f9956ffd7c243b11db46f9e": { + "filename": "Star Commander I (Coyle Home Studios) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/starcom.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "5f4cf5a7af4c113d1fd42617041482954de73c40": { + "filename": "Star Commander I (Coyle Home Studios) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/starcom.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "21037feb4adf0a5a7848653f7a44ca993841615d": { + "filename": "Star Commander I (Coyle Home Studios) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/starcom.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "fb2aad6cb8c82dc1ef1bcd6e15e0561e90ea69a8": { + "filename": "Star Commander I (Coyle Home Studios) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/starcom.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "b7e4c4574e125b4d4868a43355d6f00d34c52374": { + "filename": "Star Commander I (Coyle Home Studios) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/starcom.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "ede7abb9640c037e742ba00dd81d87c14602c630": { + "filename": "Star Commander I (Coyle Home Studios) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/starcom.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "8698bc14cf9dfb05f40aab2b4ca15c461de118c1": { + "filename": "Star Commander I (Coyle Home Studios) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/starcom.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "221d40b8844c501ba33e3d0d882cde0d58b498aa": { + "filename": "Star Commander I (Coyle Home Studios) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/starcom.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "6f235f9f92ee88b7cba9a252dd609872979b53ad": { + "filename": "Star Commander I (Coyle Home Studios) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/starcom.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "a183810bbe406349c249d42b0e651d383bbc8a0b": { + "filename": "V - The Graphic Adventure (Brainburst Interactive) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/v-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "971ca3da3bcdd052489a079a28e29227d5e1ded9": { + "filename": "V - The Graphic Adventure (Brainburst Interactive) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/v-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "dd97148cf63eef85c5876dee0ebfcc077eac8095": { + "filename": "V - The Graphic Adventure (Brainburst Interactive) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/v-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "12367fbacdfe3043a0e57e0d52fec820ae3f6d73": { + "filename": "V - The Graphic Adventure (Brainburst Interactive) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/v-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "ba4df95fb2e344ae24203a74a2c192eb7fad5481": { + "filename": "V - The Graphic Adventure (Brainburst Interactive) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/v-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "5dae9d559624f72052537d4f3b2e6d4956a4c337": { + "filename": "V - The Graphic Adventure (Brainburst Interactive) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/v-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "154e633b221f3d4dcf651d20ba65b8db95ed5253": { + "filename": "V - The Graphic Adventure (Brainburst Interactive) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 360K/v-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "68ed2c834078eca5b7dc38bfb29019f927581b2f": { + "filename": "Space Quest - The Lost Chapter (Vonster) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/sqtlc-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "15bffe703db7aed0300a815283508f8b52c6394b": { + "filename": "Space Quest - The Lost Chapter (Vonster) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/sqtlc-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "ba8e8bc3a7dc4b50b3c4d942cbbd2d7d2c0b0b85": { + "filename": "Space Quest - The Lost Chapter (Vonster) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/sqtlc-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "53b87a186db8925169c69e554fb3cf902b6f66b1": { + "filename": "Space Quest - The Lost Chapter (Vonster) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/sqtlc-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "a91f32270b2043d557837373ce7148d123522648": { + "filename": "Space Quest - The Lost Chapter (Vonster) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/sqtlc-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "e8f88230bd7eaef808b76649110764348d6c658c": { + "filename": "Space Quest - The Lost Chapter (Vonster) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/sqtlc-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "02d799ab9ac39cecf55006ccd5e4cde7078369c0": { + "filename": "Space Quest - The Lost Chapter (Vonster) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/sqtlc-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "a2692b901d3c931e9c9b14215e5ac90cb7b8384b": { + "filename": "Space Quest - The Lost Chapter (Vonster) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/sqtlc-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "ce50144db793454fafc9deb3c0d7f1c128bd62b6": { + "filename": "Space Quest - The Lost Chapter (Vonster) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/sqtlc-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "e6d79b376f20f8cafd2844571393ac5a2773d329": { + "filename": "Space Quest - The Lost Chapter (Vonster) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/sqtlc-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "2325140c8f6e377227a8d1e74a586b7fa54a582f": { + "filename": "Space Quest - The Lost Chapter (Vonster) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/sqtlc-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + }, + "4dd4d0fc73e789df85a76d22ab0e02243ba56052": { + "filename": "Space Quest - The Lost Chapter (Vonster) (OS-9) (Coco 3).zip", + "machine": "coco3", + "disk0": "Floppy 720K/sqtlc-1.dsk", + "joy-right": "kjoy0", + "basic": "DOS\n" + } +} \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/cpc_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/cpc_cass.lua new file mode 100644 index 00000000000..9a8119018b4 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/cpc_cass.lua @@ -0,0 +1,78 @@ +-- cpc_cass.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +-- --- Cassette Loading Handler Setup --- +local CASSETTE_SLOT = 3 +local CASSETTE_DEVICE_TAG = manager.machine.images:at(CASSETTE_SLOT).device.tag +local cassette_handler = common_autoboot.create_cassette_handler(CASSETTE_DEVICE_TAG) + +common_autoboot.populate_buttons(button) + +common_autoboot.print_image_info() + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function boot_default(cassette_handler) + common_autoboot.type_at_frame(frame_num, "RUN\"\n", 100) + common_autoboot.play_cassette_at_frame(frame_num, CASSETTE_DEVICE_TAG, 200) + common_autoboot.type_at_frame(frame_num, "\n", 250) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + -- emu.keypost('RUN\n') + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(CASSETTE_SLOT).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + ['default'] = boot_default, +} + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + --- DEBUG: Print current frame number every 100 frames --- + common_autoboot.debug_frame_num(frame_num) + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/cpc_flop.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/cpc_flop.lua new file mode 100644 index 00000000000..dfd24739d92 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/cpc_flop.lua @@ -0,0 +1,122 @@ +cpu = manager.machine.devices[":maincpu"] +mem = cpu.spaces["program"] +base_addr = 0x9E7D +base_file_name_size = 8 +ext_file_name_size = 3 +next_file = 14 +file_index = 0 +cat_frame = 0 +try_run = 0 +type_buffer = {} +type_qty = 0 +memory_clean_frame = 0 + +local function stack_char(char) + table.insert(type_buffer, 1, char) + type_qty = type_qty + 1 +end + +local function cat(frame) + stack_char("c") + stack_char("a") + stack_char("t") + stack_char("\n") + cat_frame = frame +end + +local function is_extension_allowed() + addr = base_addr + file_index * next_file + base_file_name_size + + ext = {} + for c = 0, 2 do + ext[c+1] = mem:read_u8(addr + c) & 0x7F + end + + forbidden_ext = { string.byte('T'), string.byte('X'), string.byte('T')} + + allowed = 0 + + for c = 1, 3 do + if forbidden_ext[c] ~= ext[c] then + allowed = 1 + break + end + end + + return allowed +end + + +local function run_file() + if is_extension_allowed() == 0 then + file_index = file_index + 1 + return + end + + stack_char("r") + stack_char("u") + stack_char("n") + stack_char("\"") + for c = 0, base_file_name_size-1 do + addr = base_addr + file_index * next_file + c + char = mem:read_u8(addr) + if char ~= 0x20 then + char = char & 0x7F + stack_char(string.char(char)) + end + end + + stack_char("\n") + try_run = 1 +end + +local function wait_for_clean_memory(frame) + if memory_clean_frame ~= 0 then + if frame > memory_clean_frame + 25 then + try_run = 0 + cat_frame = 0 + memory_clean_frame = 0 + file_index = file_index + 1 + end + else + start_file = mem:read_u8(base_addr + file_index * next_file) + if start_file == 0 then + memory_clean_frame = frame + end + end +end + +local function unstack_char() + if type_qty > 0 then + char = table.remove(type_buffer) + type_qty = type_qty - 1 + emu.keypost(char) + end +end + +frame_num = 0 +local function process_frame() + frame_num = frame_num + 1 + + if cat_frame == 0 then + if frame_num > 250 then + cat(frame_num) + end + else + if try_run == 0 then + if frame_num > cat_frame + 250 then + run_file() + end + else + wait_for_clean_memory(frame_num) + end + end + + if frame_num % 5 == 0 then + unstack_char() + end +end + +emu.keypost("|disc\n") +emu.keypost("run\"disc\n") +subscription=emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/crvision.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/crvision.lua new file mode 100644 index 00000000000..0fb78679f32 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/crvision.lua @@ -0,0 +1,69 @@ +-- _cass.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +-- --- Map all buttons --- +common_autoboot.populate_buttons(button) + +-- --- Print Info --- +common_autoboot.print_image_info() +-- common_autoboot.print_buttons(button) + +local CARTRIDGE_SLOT = 3 +local current_software_name = manager.machine.images:at(CARTRIDGE_SLOT).filename + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION + +-- Press F10, then R +local function boot_default() + common_autoboot.press_and_release(button, frame_num, "Reset", 200, 10) + common_autoboot.type_at_frame(frame_num, "R", 300) +end + +-- --- Main Script Logic --- + +-- Map software names to their respective boot functions +boot_sequences = { + ['default'] = boot_default, +} + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + --- DEBUG: Print current frame number every 100 frames --- + common_autoboot.debug_frame_num(frame_num) + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function() + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/dai_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/dai_cass.lua new file mode 100644 index 00000000000..f89d319d833 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/dai_cass.lua @@ -0,0 +1,97 @@ +-- dai_cass.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +-- --- Map all buttons --- +common_autoboot.populate_buttons(button) + +-- --- Print Info --- +common_autoboot.print_image_info() +-- common_autoboot.print_buttons(button) + +-- --- Cassette Loading Handler Setup --- +local CASSETTE_SLOT = 1 +local CASSETTE_DEVICE_TAG = manager.machine.images:at(CASSETTE_SLOT).device.tag +local cassette_handler = common_autoboot.create_cassette_handler(CASSETTE_DEVICE_TAG) + + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function boot_default(cassette_handler) + common_autoboot.type_at_frame(frame_num, "\n", 100) + common_autoboot.type_at_frame(frame_num, "LOAD\n", 200) + common_autoboot.play_cassette_at_frame(frame_num, CASSETTE_DEVICE_TAG, 300) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + emu.keypost('RUN\n') + end +end + +local function boot_acrobat(cassette_handler) + common_autoboot.type_at_frame(frame_num, "\n", 100) + common_autoboot.type_at_frame(frame_num, "UT\n", 200) + common_autoboot.type_at_frame(frame_num, "Z3\n", 300) + common_autoboot.type_at_frame(frame_num, "R\n", 400) + common_autoboot.play_cassette_at_frame(frame_num, CASSETTE_DEVICE_TAG, 500) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + emu.keypost('G400\n') + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(CASSETTE_SLOT).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + ['default'] = boot_default, + acrobat = boot_acrobat, +} + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + --- DEBUG: Print current frame number every 100 frames --- + common_autoboot.debug_frame_num(frame_num) + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/dragon_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/dragon_cass.lua new file mode 100644 index 00000000000..84e1db4a7cf --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/dragon_cass.lua @@ -0,0 +1,330 @@ +-- dragon_cass.lua +-- +-- Dragon cassette autoboot with CoCo/Dragon CAS header parsing. +-- This is a safer default than blind CLOAD/RUN: +-- type 0 (BASIC) -> CLOAD, then RUN after load completes +-- type 2 (machine) -> CLOADM:EXEC when load >= $01A9, else CLOADM +-- +-- RUN is sent via whichever fires first: +-- a) Hardware cassette motor turns off (works for CAS with EOF block + raw audio) +-- b) Dragon BASIC "OK" prompt detected on screen (fallback for CAS without EOF block) + +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") +local zip_util = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_zip.lua") + +local CAS_SCAN_BYTES = 4096 + +local TAPE_TYPE_BASIC = 0 +local TAPE_TYPE_DATA = 1 +local TAPE_TYPE_MACHINE = 2 + +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +-- Dragon video RAM: 0x0400-0x05FF, 32 cols x 16 rows +local DRAGON_SCREEN_RAM = 0x0400 +local DRAGON_SCREEN_COLS = 32 +local DRAGON_SCREEN_ROWS = 16 + +local button = {} +local frame_num = 0 + +common_autoboot.populate_buttons(button) + +local function be16(data, pos) + local hi = data:byte(pos) or 0 + local lo = data:byte(pos + 1) or 0 + return (hi << 8) | lo +end + +local function find_cassette_path() + for _, cass in pairs(manager.machine.cassettes) do + if cass.exists and cass.filename and #cass.filename > 0 then + print("[Dragon Autoboot] Cassette device: " .. cass.filename) + return cass.filename + end + end + + for _, img in pairs(manager.machine.images) do + if img.exists and img.filename and #img.filename > 0 then + local fn = img.filename:lower() + if fn:find("%.cas$") or fn:find("%.wav$") then + print("[Dragon Autoboot] Image device cassette: " .. img.filename) + return img.filename + end + end + end + + return nil +end + +local function parse_cas_header(data) + if not data or #data < 20 then + return nil + end + + local i = 1 + local saw_leader = false + + while i <= #data do + local b = data:byte(i) + if b == 0x55 then + saw_leader = true + i = i + 1 + elseif b == 0x3C and saw_leader then + local base = i + 1 + if base + 16 > #data then + return nil + end + + local block_type = data:byte(base) + local block_size = data:byte(base + 1) + + if block_type == 0x00 and block_size >= 15 then + local dstart = base + 2 + local file_type = data:byte(dstart + 8) + local start_address = be16(data, dstart + 11) + local load_address = be16(data, dstart + 13) + local name = {} + + for fi = 0, 7 do + local c = data:byte(dstart + fi) + if c and c ~= 0x20 and c ~= 0x00 then + table.insert(name, string.char(c)) + end + end + + print(string.format( + "[Dragon Autoboot] CAS header: file='%s' type=%d load=0x%04X exec=0x%04X", + table.concat(name), file_type or -1, load_address, start_address)) + + return { + file_type = file_type, + load_address = load_address, + start_address = start_address, + } + end + + saw_leader = false + i = i + 1 + else + saw_leader = false + i = i + 1 + end + end + + return nil +end + +local function detect_tape_info() + print("[Dragon Autoboot] --- Tape type detection ---") + + local path = find_cassette_path() + if not path then + print("[Dragon Autoboot] No cassette image found.") + return { file_type = TAPE_TYPE_BASIC, load_address = 0 } + end + + local data = zip_util.read_bytes(path, CAS_SCAN_BYTES) + if not data then + print("[Dragon Autoboot] Could not read cassette data, defaulting to BASIC.") + return { file_type = TAPE_TYPE_BASIC, load_address = 0 } + end + + local info = parse_cas_header(data) + if info then + return info + end + + print("[Dragon Autoboot] No valid CAS header found, defaulting to BASIC.") + return { file_type = TAPE_TYPE_BASIC, load_address = 0 } +end + +-- ── Low-level helpers ───────────────────────────────────────────────────────── + +local function vram_read(addr) + local cpu = manager.machine.devices[":maincpu"] + if not cpu then return nil end + local mem = cpu.spaces["program"] + if not mem then return nil end + return mem:read_u8(addr) +end + +-- Returns true if bytes b1,b2 look like Dragon BASIC's "OK" string. +-- Dragon MC6847 alphanumeric: 'A'=0x01…'Z'=0x1A (ASCII minus 0x40). +-- 'O'=0x0F, 'K'=0x0B +-- Some Dragon 64 ROMs may write raw ASCII values instead: +-- 'O'=0x4F, 'K'=0x4B +local function is_ok_bytes(b1, b2) + return (b1 == 0x0F and b2 == 0x0B) or -- MC6847 native + (b1 == 0x4F and b2 == 0x4B) -- raw ASCII +end + +-- Scan entire video RAM; return a table of {addr=true} for every "OK" found. +local function collect_ok_addrs() + local found = {} + for row = 0, DRAGON_SCREEN_ROWS - 1 do + for col = 0, DRAGON_SCREEN_COLS - 2 do + local addr = DRAGON_SCREEN_RAM + row * DRAGON_SCREEN_COLS + col + local b1 = vram_read(addr) + local b2 = vram_read(addr + 1) + if b1 and b2 and is_ok_bytes(b1, b2) then + found[addr] = true + end + end + end + return found +end + +-- Dump a single row of video RAM as hex for diagnostics. +local function dump_vram_row(row) + local bytes = {} + for col = 0, DRAGON_SCREEN_COLS - 1 do + local b = vram_read(DRAGON_SCREEN_RAM + row * DRAGON_SCREEN_COLS + col) + table.insert(bytes, b and string.format("%02X", b) or "??") + end + print(string.format("[Dragon Autoboot] VRAM row %2d: %s", row, table.concat(bytes, " "))) +end + +-- ── Boot state ──────────────────────────────────────────────────────────────── + +local ok_baseline = {} -- OK addresses present before tape plays +local ok_baseline_done = false +local ok_seen_frame = 0 +local motor_was_on = false +local motor_off_start = 0 +local run_sent = false +local cassette_handler = common_autoboot.create_cassette_handler(":cassette") +local tape_info = nil + +local function send_run() + print("[Dragon Autoboot] Sending RUN at frame " .. frame_num) + manager.machine.video.throttled = true + manager.machine.video.frameskip = 0 + emu.keypost("RUN\n") + run_sent = true +end + +-- ── boot_basic ──────────────────────────────────────────────────────────────── + +local function boot_basic() + common_autoboot.type_at_frame(frame_num, "CLOAD\n", 200, BUTTON_PRESS_DURATION) + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 300) + + if run_sent then return end + + -- Hold throttle OFF from the moment the tape starts until completion. + -- We manage this directly rather than relying on cassette_handler so that + -- brief motor toggles between blocks don't stutter back to normal speed. + if frame_num >= 300 then + manager.machine.video.throttled = false + manager.machine.video.frameskip = 12 + end + + -- ── Baseline capture ─────────────────────────────────────────────────── + -- Snapshot any "OK" already on screen (from the Dragon BASIC startup banner) + -- just after CLOAD is typed but well before the tape data arrives. + if frame_num == 350 then + ok_baseline = collect_ok_addrs() + ok_baseline_done = true + local n = 0 + for _ in pairs(ok_baseline) do n = n + 1 end + print(string.format("[Dragon Autoboot] Baseline: %d OK addr(s) in VRAM", n)) + -- Dump first 4 rows for diagnosis + for r = 0, 3 do dump_vram_row(r) end + end + + -- ── Periodic diagnostics ────────────────────────────────────────────── + if frame_num % 600 == 0 and frame_num > 300 then + local cass = manager.machine.cassettes[":cassette"] + local ms = cass and tostring(cass.motor_state) or "n/a" + local ist = cass and tostring(cass.is_stopped) or "n/a" + local b0 = vram_read(DRAGON_SCREEN_RAM) + print(string.format("[Dragon Autoboot] frame=%d motor=%s is_stopped=%s vram[0]=0x%s", + frame_num, ms, ist, b0 and string.format("%02X", b0) or "??")) + end + + -- ── Method 1: hardware motor turns off ──────────────────────────────── + -- Track when motor was on, then detect it going off with a short debounce. + if frame_num > 360 then + local cass = manager.machine.cassettes[":cassette"] + local motor = cass and cass.motor_state or nil + if motor == true then + motor_was_on = true + motor_off_start = 0 + elseif motor == false and motor_was_on then + if motor_off_start == 0 then + motor_off_start = frame_num + print("[Dragon Autoboot] Motor OFF at frame " .. frame_num) + elseif frame_num >= motor_off_start + CASSETTE_MOTOR_OFF_DELAY_FRAMES then + print("[Dragon Autoboot] Motor off confirmed → RUN") + send_run() + return + end + end + end + + -- ── Method 2: "OK" prompt on screen ─────────────────────────────────── + -- Dragon BASIC always prints "OK" when returning to the command prompt. + -- Check every 30 frames to keep overhead low. + if ok_baseline_done and frame_num >= 400 and frame_num % 30 == 0 then + local new_ok = false + local current = collect_ok_addrs() + for addr in pairs(current) do + if not ok_baseline[addr] then + local row = math.floor((addr - DRAGON_SCREEN_RAM) / DRAGON_SCREEN_COLS) + local col = (addr - DRAGON_SCREEN_RAM) % DRAGON_SCREEN_COLS + local b1 = vram_read(addr) + print(string.format("[Dragon Autoboot] New OK row=%d col=%d addr=0x%04X b1=0x%02X frame=%d", + row, col, addr, b1 or 0, frame_num)) + new_ok = true + break + end + end + + if new_ok then + if ok_seen_frame == 0 then + ok_seen_frame = frame_num + -- Dump last rows when we first see it, to verify encoding + for r = 12, 15 do dump_vram_row(r) end + elseif frame_num >= ok_seen_frame + 30 then + print("[Dragon Autoboot] Screen OK confirmed → RUN") + send_run() + end + else + ok_seen_frame = 0 + end + end +end + +local function boot_machine() + local need_exec = (tape_info.load_address or 0) >= 0x01A9 + local cmd = need_exec and "CLOADM:EXEC\n" or "CLOADM\n" + + common_autoboot.type_at_frame(frame_num, cmd, 200, BUTTON_PRESS_DURATION) + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 300) + + cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) +end + +local function process_frame() + frame_num = frame_num + 1 + + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + common_autoboot.print_image_info() + tape_info = detect_tape_info() + end + + common_autoboot.debug_frame_num(frame_num) + + if not tape_info or tape_info.file_type == TAPE_TYPE_DATA then + boot_basic() + elseif tape_info.file_type == TAPE_TYPE_MACHINE then + boot_machine() + else + boot_basic() + end +end + +subscription = emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/einstein.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/einstein.lua new file mode 100644 index 00000000000..14980cf4d6e --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/einstein.lua @@ -0,0 +1,76 @@ +-- einstein.lua +-- Most titles require DIR then run the .COM. Some titles are automatically run, esp. those that boot using XTALDOS 2.0 +-- WIP: need to go through each games and see the .COM file + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +-- --- Map all buttons --- +common_autoboot.populate_buttons(button) + +-- --- Print Info --- +common_autoboot.print_image_info() +-- common_autoboot.print_buttons(button) + +local FLOPPY_SLOT = 2 + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function boot_default(title_to_type) + return function() + common_autoboot.type_at_frame(frame_num, title_to_type .. "\n", 300) + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(FLOPPY_SLOT).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + alice = boot_default("ALICE.COM"), + chuckie = boot_default("CHUCKIE.COM"), + pakman = boot_default("PAKMAN.COM"), +} + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + --- DEBUG: Print current frame number every 100 frames --- + common_autoboot.debug_frame_num(frame_num) + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/electron_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/electron_cass.lua new file mode 100644 index 00000000000..645d88c0f01 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/electron_cass.lua @@ -0,0 +1,79 @@ +-- electron_cass.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +common_autoboot.populate_buttons(button) + +-- Print the button table contents for debugging +-- common_autoboot.print_buttons(button) + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function boot_default(cassette_handler) + common_autoboot.type_at_frame(frame_num, "*TAPE\n", 50, BUTTON_PRESS_DURATION) + common_autoboot.type_at_frame(frame_num, "CHAIN\"\"\n", 100, BUTTON_PRESS_DURATION) + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 300) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + -- emu.keypost('RUN\n') + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(1).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + ["default"] = boot_default, +} + +-- --- Cassette Loading Handler Setup --- +local cassette_handler = common_autoboot.create_cassette_handler(":cassette") + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + -- --- Print current frame number every 100 frames --- + if frame_num % 100 == 0 then -- The modulo operator (%) gives the remainder of a division + emu.print_info("Current Frame: " .. frame_num) + end + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/electron_flop.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/electron_flop.lua new file mode 100644 index 00000000000..cdc48a6b7a7 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/electron_flop.lua @@ -0,0 +1,79 @@ +-- electron_flop.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +common_autoboot.populate_buttons(button) + +-- Print the button table contents for debugging +-- common_autoboot.print_buttons(button) + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function boot_default(cassette_handler) + common_autoboot.type_at_frame(frame_num, "*CAT\n", 50, BUTTON_PRESS_DURATION) + common_autoboot.type_at_frame(frame_num, "*EXEC !BOOT\n", 250, BUTTON_PRESS_DURATION) + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 300) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + -- emu.keypost('RUN\n') + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(1).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + ["default"] = boot_default, +} + +-- --- Cassette Loading Handler Setup --- +local cassette_handler = common_autoboot.create_cassette_handler(":cassette") + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + -- --- Print current frame number every 100 frames --- + if frame_num % 100 == 0 then -- The modulo operator (%) gives the remainder of a division + emu.print_info("Current Frame: " .. frame_num) + end + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/famicom_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/famicom_cass.lua new file mode 100644 index 00000000000..a9fab2a4d19 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/famicom_cass.lua @@ -0,0 +1,97 @@ +--local button = {} +--print("=== Ports ===") +--for i, j in pairs(manager.machine.ioport.ports) do +-- for field_name, field in pairs(j.fields) do +-- id = field.port.tag .. ',' .. field.mask .. ',' .. field.type +-- print(field_name,": ", id) +-- button[id] = field +-- end +--end + +print("") +print("=== Cassettes ===") +for i, j in pairs(manager.machine.cassettes) do + print(i) +end + +print("") +print("=== Images ===") +for i, j in pairs(manager.machine.images) do + print(i) +end + +part = {} +table.insert(part, os.getenv("RANDOMAME_PART_1")) +table.insert(part, os.getenv("RANDOMAME_PART_2")) +--table.insert(part, os.getenv("RANDOMAME_PART_3")) + +feature = {} +table.insert(feature, os.getenv("RANDOMAME_PART_FEATURE_1")) +table.insert(feature, os.getenv("RANDOMAME_PART_FEATURE_2")) +--table.insert(feature, os.getenv("RANDOMAME_PART_FEATURE_3")) + +commands = {} + +for i,p in ipairs(part) do + my_feature = table.remove(feature,1) + if my_feature == nil then + table.insert(commands, "LOAD") + else + if my_feature == 'part_id:BG Data' then + table.insert(commands, "LOADS") + else + table.insert(commands, "LOAD") + end + end +end + +local frame_num = 0 +local current_command = nil +local run_end_frame = 0 + +local function process_frame() + frame_num = frame_num + 1 + + if frame_num > run_end_frame + 100 then + if current_command == nil then + current_command = table.remove(commands,1) + if current_command == "LOADS" then + manager.machine.images[":exp:fc_keyboard:tape"]:load_software(table.remove(part,1)) + emu.keypost("LOADS\n") + manager.machine.cassettes[":exp:fc_keyboard:tape"]:play() + elseif current_command == "LOAD" then + manager.machine.images[":exp:fc_keyboard:tape"]:load_software(table.remove(part,1)) + emu.keypost("LOAD\n") + manager.machine.cassettes[":exp:fc_keyboard:tape"]:play() + end + end + end + + if manager.machine.cassettes[":exp:fc_keyboard:tape"].is_stopped == false and manager.machine.cassettes[":exp:fc_keyboard:tape"].motor_state == true then + manager.machine.video.throttled = false + manager.machine.video.frameskip = 12 + else + manager.machine.video.throttled = true + manager.machine.video.frameskip = 0 + + if current_command ~= nil then + if current_command == "LOADS" then + current_command = nil + elseif current_command == "LOAD" then + current_command = nil + -- if next command is a "LOAD", issue a "RUN" and wait for its execution + if commands[1] == "LOAD" then + emu.keypost("RUN\n") + run_end_frame = frame_num + 800 + end + end + + -- if last command, issue a "RUN" + if commands[1] == nil then + emu.keypost("RUN\n") + end + end + end +end + +subscription=emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/fm7_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/fm7_cass.lua new file mode 100644 index 00000000000..22792d7c740 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/fm7_cass.lua @@ -0,0 +1,40 @@ +local frame_num = 0 +local load_done_frame_num = 0 +local motor_state_false_frame_num = 0 +local function process_frame() + frame_num = frame_num + 1 + + if frame_num == 1 then + emu.keypost('LOAD\n') + manager.machine.cassettes[":cassette"]:play() + end + + if frame_num > 150 then + if motor_state_false_frame_num == 0 then + if manager.machine.cassettes[":cassette"].motor_state == false then + motor_state_false_frame_num = frame_num + end + else + if frame_num > motor_state_false_frame_num + 60 then + if load_done_frame_num == 0 then + load_done_frame_num = frame_num + emu.keypost('RUN\n') + end + end + end + end + + if manager.machine.cassettes[":cassette"].motor_state == true then + motor_state_false_frame_num = 0 + end + + if manager.machine.cassettes[":cassette"].is_stopped == false and manager.machine.cassettes[":cassette"].motor_state == true then + manager.machine.video.throttled = false + manager.machine.video.frameskip = 12 + else + manager.machine.video.throttled = true + manager.machine.video.frameskip = 0 + end +end + +subscription=emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/galaxy.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/galaxy.lua new file mode 100644 index 00000000000..74911ccf35f --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/galaxy.lua @@ -0,0 +1,78 @@ +-- galaxy.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +-- Print Info +common_autoboot.print_image_info() + +-- --- Cassette Loading Handler Setup --- +local CASSETTE_SLOT = 2 +local CASSETTE_DEVICE_TAG = manager.machine.images:at(CASSETTE_SLOT).device.tag +local cassette_handler = common_autoboot.create_cassette_handler(CASSETTE_DEVICE_TAG) + +common_autoboot.populate_buttons(button) + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function boot_default(cassette_handler) + common_autoboot.type_at_frame(frame_num, "OLD\n", 100) + common_autoboot.play_cassette_at_frame(frame_num, CASSETTE_DEVICE_TAG, 200) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + emu.keypost('RUN\n') + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(CASSETTE_SLOT).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + ['default'] = boot_default, +} + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + --- DEBUG: Print current frame number every 100 frames --- + common_autoboot.debug_frame_num(frame_num) + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/io_base.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/io_base.lua new file mode 100644 index 00000000000..a9c76e08350 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/io_base.lua @@ -0,0 +1,19 @@ +local io_base = {} + +function io_base.get() + button = {} + for i, j in pairs(manager.machine.ioport.ports) do + for field_name, field in pairs(j.fields) do + --print(field_name) + --print(" tag", field.port.tag) + --print(" mask", field.mask) + --print(" type", field.type) + id = field.port.tag .. ',' .. field.mask .. ',' .. field.type + print(field_name,'=',id) + button[id] = field + end + end + return button +end + +return io_base diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/juku.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/juku.lua new file mode 100644 index 00000000000..508adf290fc --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/juku.lua @@ -0,0 +1,53 @@ +button = {} + +for i, j in pairs(manager.machine.ioport.ports) do + for field_name, field in pairs(j.fields) do + id = field.port.tag .. ',' .. field.mask .. ',' .. field.type + print(field_name,": ", id) + button[id] = field + end +end + +local frame_num = 0 +local function process_frame() + frame_num = frame_num + 1 + + if frame_num == 200 then + button[":COL.4,8,49"]:set_value(1) -- T + elseif frame_num == 205 then + button[":COL.4,8,49"]:set_value(0) -- T + + elseif frame_num == 250 then + button[":COL.6,32,49"]:set_value(1) -- D + elseif frame_num == 255 then + button[":COL.6,32,49"]:set_value(0) -- D + + elseif frame_num == 300 then + button[":COL.6,32,49"]:set_value(1) -- D + elseif frame_num == 305 then + button[":COL.6,32,49"]:set_value(0) -- D + + elseif frame_num == 600 then + button[":COL.6,32,49"]:set_value(1) -- D + elseif frame_num == 605 then + button[":COL.6,32,49"]:set_value(0) -- D + + elseif frame_num == 610 then + button[":COL.14,8,49"]:set_value(1) -- I + elseif frame_num == 615 then + button[":COL.14,8,49"]:set_value(0) -- I + + elseif frame_num == 620 then + button[":COL.2,8,49"]:set_value(1) -- R + elseif frame_num == 625 then + button[":COL.2,8,49"]:set_value(0) -- R + + elseif frame_num == 630 then + button[":COL.8,32,49"]:set_value(1) -- RETURN + elseif frame_num == 635 then + button[":COL.8,32,49"]:set_value(0) -- RETURN + + end +end + +subscription=emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/jupace_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/jupace_cass.lua new file mode 100644 index 00000000000..660d4530e7c --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/jupace_cass.lua @@ -0,0 +1,173 @@ +-- jupace_cass.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +-- --- Map all buttons --- +common_autoboot.populate_buttons(button) + +-- --- Print Info --- +common_autoboot.print_image_info() +-- common_autoboot.print_buttons(button) + +-- --- Cassette Loading Handler Setup --- +local CASSETTE_SLOT = 1 +local CASSETTE_DEVICE_TAG = manager.machine.images:at(CASSETTE_SLOT).device.tag +local cassette_handler = common_autoboot.create_cassette_handler(CASSETTE_DEVICE_TAG) + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +-- local function boot_default(title_to_type) +-- return function() +-- common_autoboot.type_at_frame(frame_num, title_to_type .. "\n", 100) +-- end +-- end + +local function boot_default(title_to_type) + return function(cassette_handler_arg) + common_autoboot.type_at_frame(frame_num, title_to_type .. "\n", 100) + + common_autoboot.play_cassette_at_frame(frame_num, CASSETTE_DEVICE_TAG, 300) + local cassette_load_done = cassette_handler_arg(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + -- emu.keypost('/\n') + end + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(CASSETTE_SLOT).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + ['3dmaze'] = boot_default("load 3dmaze 3dmaze"), + ['avoider'] = boot_default("load avoider run"), + ['acecase'] = boot_default("load case"), + ['demotape'] = boot_default("load banner"), + ['graphics'] = boot_default("load ?plot"), + ['graphicsa'] = boot_default("load ?plot"), + ['aceinvad'] = boot_default("load graphics gr load run run"), + ['invader1'] = boot_default("load GR load GR load GR load GM load GM load GM z p"), + ['acemines'] = boot_default("load mines mines"), + ['acestar'] = boot_default("0 0 bload astar 16384 call"), + ['acevocab'] = boot_default("load listv"), + ['acevader'] = boot_default("load gr load acevaders gr r"), + ['adventa'] = boot_default("0 0 bload adva 16384 call"), + ['aliendef'] = boot_default("load defender g"), + ['aswarm'] = boot_default("load gr load swarm gr go"), + ['amazmaze'] = boot_default("load maze g"), + ['amisound'] = boot_default("load amisndkit go"), + ['asmdasm'] = boot_default("load a1"), + ['astrian'] = boot_default("load Lander run"), + ['aticraid'] = boot_default("load atic go"), + ['blackisl'] = boot_default("load black island"), + ['bomber'] = boot_default("load bomber play"), + ['breakout'] = boot_default("load breakout b"), + ['calendar'] = boot_default("load calendar"), + ['callisto'] = boot_default("8930 0 bload callisto"), + ['cavern'] = boot_default("load graphics load run gr run"), + ['cenipede'] = boot_default("load centipede go"), + ['m_champs'] = boot_default("0 0 bload mines 11272 64 bload g load m 7 jeu"), + ['chase'] = boot_default("load chase chase"), + ['chess'] = boot_default("load chess run"), + ['schess2'] = boot_default("load chess run"), + ['cygnus'] = boot_default("load cygnus g"), + ['database'] = boot_default("load database"), + ['dodge'] = boot_default("load Dodger game"), + ['dotman'] = boot_default("load s load run s run"), + ['ducksht'] = boot_default("11272 0 bload dchars load duckshoot d"), + ['firebird'] = boot_default("load FIREBIRD run"), + ['frogger'] = boot_default("load frogger go"), + ['frogger1'] = boot_default("load frogger g"), + ['fungle'] = boot_default("load FU run"), + ['gobbgook'] = boot_default("load gobblegook gobblegook"), + ['grandprx'] = boot_default("load grandprix g"), + ['grexfrog'] = boot_default("load graphics load run grf run"), + ['guessing'] = boot_default("load game game"), + ['hdrmon'] = boot_default("load HDRMON go"), + ['invaders'] = boot_default("load invaders g"), + ['jumpman'] = boot_default("load jumpman start"), + ['kkong'] = boot_default("load CHARACTERS CHARACTERS load KONG run"), + ['life'] = boot_default("load life13 life"), + ['lightrac'] = boot_default("load LightRacer run"), + ['loader'] = boot_default("load loader"), + ['llander'] = boot_default("load ll ll"), + ['memstars'] = boot_default("load run run"), + ['meteor'] = boot_default("load gr meteor load meteor game"), + ['metracer'] = boot_default("load GR load GR load GR load GM load GM z p"), + ['meteors'] = boot_default("load asteroids g"), + ['micromaz'] = boot_default("load graphics load run s run"), + ['minefld'] = boot_default("11272 0 bload mchars load minefield m"), + ['moonbugg'] = boot_default("load moonbuggy g"), + ['morsecod'] = boot_default("load morse_tuto go"), + ['othello'] = boot_default("load othello 11272 0 bload pieces go"), + ['owler'] = boot_default("load owler loading"), + ['quickdrw'] = boot_default("load quick-draw go"), + ['quickdrp'] = boot_default("load Qdraw run"), + ['robohnch'] = boot_default("load robohench g"), + ['robohunt'] = boot_default("load robohunt g"), + ['sailhorn'] = boot_default("load hornpipe hornpipe"), + ['sambombs'] = boot_default("load sam g"), + ['scramblr'] = boot_default("load scrambler"), + ['sokoace'] = boot_default("load sokoace play"), + ['sacemap'] = boot_default("load sokoed ed"), + ['sbattle'] = boot_default("load graphics load run gr run"), + ['spreadsh'] = boot_default("load s"), + ['startrek'] = boot_default("load startrek g"), + ['sudoku'] = boot_default("load sudoku sudoku"), + ['surround'] = boot_default("load surround go"), + ['tankbatl'] = boot_default("load tankbattle g"), + ['teach'] = boot_default("load forth"), + ['tetris'] = boot_default("load tetris tetris"), + ['turbo'] = boot_default("load turbo 0 0 bload track turbo"), + ['hanoi'] = boot_default("load hanoi hanoi"), + ['words'] = boot_default("load words"), + ['wrd'] = boot_default("load wrd"), + ['zapem'] = boot_default("11272 0 bload zchars load zapem z"), + ['zombies'] = boot_default("load zombpot zombpot"), + ['zxprint'] = boot_default("load zx-printer"), +} + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + --- DEBUG: Print current frame number every 100 frames --- + common_autoboot.debug_frame_num(frame_num) + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/jupace_snap.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/jupace_snap.lua new file mode 100644 index 00000000000..188ff6e91ff --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/jupace_snap.lua @@ -0,0 +1,80 @@ +-- jupace_snap.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +-- --- Map all buttons --- +common_autoboot.populate_buttons(button) + +-- --- Print Info --- +common_autoboot.print_image_info() +-- common_autoboot.print_buttons(button) + +-- --- Cassette Loading Handler Setup --- +local SOFTWARE_SLOT = 3 + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION + +local function boot_default() + common_autoboot.type_at_frame(frame_num, "\n", 200) +end + +local function boot_milliped() + common_autoboot.type_at_frame(frame_num, "milliped\n", 200) +end + +local function boot_pacman() + common_autoboot.type_at_frame(frame_num, "run\n", 200) +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(SOFTWARE_SLOT).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + ['default'] = boot_default, + milliped = boot_milliped, + pacman = boot_pacman, +} + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + --- DEBUG: Print current frame number every 100 frames --- + common_autoboot.debug_frame_num(frame_num) + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function() + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/m5_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/m5_cass.lua new file mode 100644 index 00000000000..59941f420fc --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/m5_cass.lua @@ -0,0 +1,76 @@ +-- m5_cass.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +-- --- Cassette Loading Handler Setup --- +local CASSETTE_DEVICE_TAG = manager.machine.images:at(2).device.tag +local cassette_handler = common_autoboot.create_cassette_handler(CASSETTE_DEVICE_TAG) + +common_autoboot.populate_buttons(button) + +common_autoboot.print_image_info() + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function boot_default(cassette_handler) + common_autoboot.type_at_frame(frame_num, "CHAIN\n", 100) + common_autoboot.play_cassette_at_frame(frame_num, CASSETTE_DEVICE_TAG, 200) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + -- emu.keypost('RUN\n') + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(1).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + ['default'] = boot_default, +} + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + --- DEBUG: Print current frame number every 100 frames --- + common_autoboot.debug_frame_num(frame_num) + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mc10_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mc10_cass.lua new file mode 100644 index 00000000000..4728f1c9c28 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mc10_cass.lua @@ -0,0 +1,231 @@ +-- mc10_cass.lua +-- +-- Dedicated MC-10 cassette autoboot. This follows XRoar's basic autorun +-- heuristic more closely than trs80_cass.lua: +-- type 0 (BASIC) -> CLOAD, then RUN after tape stops +-- type 2 (machine) -> CLOADM:EXEC only when load >= $01A9, else CLOADM +-- +-- MC-10 tapes don't have the same remote motor-control behaviour as CoCo/TRS-80 +-- setups, so load completion is tracked from cassette play/stop state rather +-- than motor_state. + +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") +local zip_util = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_zip.lua") + +local CAS_SCAN_BYTES = 4096 + +local TAPE_TYPE_BASIC = 0 +local TAPE_TYPE_DATA = 1 +local TAPE_TYPE_MACHINE = 2 + +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_STOP_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local button = {} +local frame_num = 0 + +common_autoboot.populate_buttons(button) + +local function be16(data, pos) + local hi = data:byte(pos) or 0 + local lo = data:byte(pos + 1) or 0 + return (hi << 8) | lo +end + +local function find_cassette_image() + for _, cass in pairs(manager.machine.cassettes) do + if cass.exists and cass.filename and #cass.filename > 0 then + return cass.filename, cass.device and cass.device.tag or ":cassette" + end + end + + for _, img in pairs(manager.machine.images) do + if img.exists and img.filename and #img.filename > 0 then + local fn = img.filename:lower() + if fn:find("%.cas$") or fn:find("%.c10$") then + return img.filename, img.device and img.device.tag or ":cassette" + end + end + end + + return nil, ":cassette" +end + +local function parse_tape_header(data) + if not data or #data < 20 then + return nil + end + + local i = 1 + local saw_leader = false + + while i <= #data do + local b = data:byte(i) + + if b == 0x55 then + saw_leader = true + i = i + 1 + elseif b == 0x3C and saw_leader then + local base = i + 1 + if base + 16 > #data then + return nil + end + + local block_type = data:byte(base) + local block_size = data:byte(base + 1) + + if block_type == 0x00 and block_size >= 15 then + local dstart = base + 2 + local name = {} + for j = 0, 7 do + local c = data:byte(dstart + j) + if c and c ~= 0x00 and c ~= 0x20 then + table.insert(name, string.char(c)) + end + end + + local file_type = data:byte(dstart + 8) + local start_address = be16(data, dstart + 11) + local load_address = be16(data, dstart + 13) + + print(string.format( + "[MC-10 Autoboot] Header name='%s' type=%d load=0x%04X exec=0x%04X", + table.concat(name), file_type or -1, load_address, start_address)) + + return { + file_type = file_type, + load_address = load_address, + start_address = start_address, + } + end + + saw_leader = false + i = i + 1 + else + saw_leader = false + i = i + 1 + end + end + + return nil +end + +local function detect_tape_info() + local path = find_cassette_image() + if not path then + print("[MC-10 Autoboot] No cassette image found.") + return { file_type = TAPE_TYPE_BASIC, load_address = 0 } + end + + print("[MC-10 Autoboot] Tape path: " .. path) + local data = zip_util.read_bytes(path, CAS_SCAN_BYTES) + if not data then + print("[MC-10 Autoboot] Could not read tape header, defaulting to BASIC.") + return { file_type = TAPE_TYPE_BASIC, load_address = 0 } + end + + local info = parse_tape_header(data) + if info then + return info + end + + print("[MC-10 Autoboot] No valid header found, defaulting to BASIC.") + return { file_type = TAPE_TYPE_BASIC, load_address = 0 } +end + +local function create_mc10_cassette_handler(cassette_device_tag) + local stop_frame = 0 + local seen_playing = false + local load_done = false + + return function(current_frame_num, delay_frames_after_stop) + local cassette_device = manager.machine.cassettes[cassette_device_tag] + if not cassette_device then + print("[MC-10 Autoboot] Cassette device not found: " .. cassette_device_tag) + return false + end + + if cassette_device.is_stopped == false then + manager.machine.video.throttled = false + manager.machine.video.frameskip = 12 + seen_playing = true + else + manager.machine.video.throttled = true + manager.machine.video.frameskip = 0 + if seen_playing and stop_frame == 0 then + stop_frame = current_frame_num + print("[MC-10 Autoboot] Cassette stop detected at frame " .. current_frame_num) + end + end + + if not load_done and stop_frame ~= 0 and current_frame_num > stop_frame + delay_frames_after_stop then + load_done = true + print("[MC-10 Autoboot] Cassette load complete at frame " .. current_frame_num) + return true + end + + return false + end +end + +local function play_cassette(cassette_tag, start_frame) + if frame_num == start_frame then + local cassette_device = manager.machine.cassettes[cassette_tag] + if cassette_device then + cassette_device:play() + print("[MC-10 Autoboot] Playing cassette at frame " .. frame_num) + else + print("[MC-10 Autoboot] Cassette device not found for play: " .. cassette_tag) + end + end +end + +local tape_info = nil +local cassette_tag = ":cassette" +local cassette_handler = nil + +local function boot_basic() + common_autoboot.type_at_frame(frame_num, "CLOAD\n", 140, BUTTON_PRESS_DURATION) + play_cassette(cassette_tag, 260) + + if cassette_handler and cassette_handler(frame_num, CASSETTE_STOP_DELAY_FRAMES) then + emu.keypost("RUN\n") + end +end + +local function boot_machine() + local need_exec = (tape_info.load_address or 0) >= 0x01A9 + local cmd = need_exec and "CLOADM:EXEC\n" or "CLOADM\n" + + common_autoboot.type_at_frame(frame_num, cmd, 140, BUTTON_PRESS_DURATION) + play_cassette(cassette_tag, 260) + + if cassette_handler then + cassette_handler(frame_num, CASSETTE_STOP_DELAY_FRAMES) + end +end + +local function process_frame() + frame_num = frame_num + 1 + + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + common_autoboot.print_image_info() + local _, detected_tag = find_cassette_image() + cassette_tag = detected_tag or ":cassette" + cassette_handler = create_mc10_cassette_handler(cassette_tag) + tape_info = detect_tape_info() + end + + common_autoboot.debug_frame_num(frame_num) + + if not tape_info or tape_info.file_type == TAPE_TYPE_DATA then + boot_basic() + elseif tape_info.file_type == TAPE_TYPE_MACHINE then + boot_machine() + else + boot_basic() + end +end + +subscription = emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/megacd.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/megacd.lua new file mode 100644 index 00000000000..fd5e06bb0a9 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/megacd.lua @@ -0,0 +1,32 @@ +button = {} + +for i, j in pairs(manager.machine.ioport.ports) do + for field_name, field in pairs(j.fields) do + id = field.port.tag .. ',' .. field.mask .. ',' .. field.type + print(field_name,": ", id) + button[id] = field + end +end + +frame_num=0 +function process_frame() + frame_num = frame_num + 1 + + if frame_num == 1 then + -- P1 start + button[":ctrl1:mdpad:PAD,128,46"]:set_value(1) + end + if frame_num == 40 then + button[":ctrl1:mdpad:PAD,128,46"]:set_value(0) + end + if frame_num == 80 then + -- P1 start + button[":ctrl1:mdpad:PAD,128,46"]:set_value(1) + end + if frame_num == 120 then + button[":ctrl1:mdpad:PAD,128,46"]:set_value(0) + end +end + +subscription = emu.add_machine_frame_notifier(process_frame) + diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mo5_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mo5_cass.lua new file mode 100644 index 00000000000..96191e81009 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mo5_cass.lua @@ -0,0 +1,23 @@ +local function process_frame() + if manager.machine.cassettes[":cassette"].is_stopped == false and manager.machine.cassettes[":cassette"].motor_state == true then + manager.machine.video.throttled = false + manager.machine.video.frameskip = 12 + else + manager.machine.video.throttled = true + manager.machine.video.frameskip = 0 + end +end + +info_usage = os.getenv("RANDOMAME_INFO_USAGE") + +command = "" +if info_usage == "Load with LOADM" then + command = 'LOADM\n' +else + command = 'RUN"\n' +end + +emu.keypost(command) +manager.machine.cassettes[":cassette"]:play() + +subscription=emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mo6_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mo6_cass.lua new file mode 100644 index 00000000000..c552dda04fa --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mo6_cass.lua @@ -0,0 +1,76 @@ +-- mo6_cass.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +common_autoboot.populate_buttons(button) + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function boot_default(cassette_handler) + common_autoboot.type_at_frame(frame_num, "1\n", 100, BUTTON_PRESS_DURATION) + common_autoboot.type_at_frame(frame_num, "RUN\"CASS:\n", 200, BUTTON_PRESS_DURATION) + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 300) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + -- emu.keypost('RUN\n') + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(3).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + ["default"] = boot_default, +} + +-- --- Cassette Loading Handler Setup --- +local cassette_handler = common_autoboot.create_cassette_handler(":cassette") + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + --- Print current frame number every 100 frames --- + if frame_num % 100 == 0 then -- The modulo operator (%) gives the remainder of a division + emu.print_info("Current Frame: " .. frame_num) + end + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/msx1_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/msx1_cass.lua new file mode 100644 index 00000000000..f9d132a56fa --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/msx1_cass.lua @@ -0,0 +1,199 @@ +-- msx1_cass.lua +-- +-- MSX1 cassette autoboot with header-based file-type detection. +-- +-- MSX .cas block layout: +-- Offset 0-7 : sync header 1F A6 DE BA CC 13 7D 74 +-- Offset 8-17 : type indicator (10 identical bytes) +-- 0xD3 x10 → tokenised BASIC (CSAVE) → CLOAD, then RUN after motor off +-- 0xD0 x10 → binary / machine code (BSAVE) → BLOAD"CAS:",R +-- 0xEA x10 → ASCII BASIC (SAVE) → RUN"CAS:" +-- Offset 18-23 : filename (6 ASCII bytes, space-padded) +-- +-- Load commands (ref: http://www.msxblue.com/manual/runningcas_c.htm): +-- CSAVE files (0xD3) : CLOAD → RUN after motor off +-- BSAVE files (0xD0) : BLOAD"CAS:",R (auto-executes, no post-command) +-- SAVE files (0xEA) : LOAD"CAS:" → RUN after motor off +-- (RUN"CAS:" fails on MSX2 DISK-BASIC: it doesn't block for the motor signal) +-- +-- Reference: MSX2 Technical Handbook chapter 5a; blueMSX source (ducasp/blueMSX). + +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") +local zip_util = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_zip.lua") + +local CAS_SCAN_BYTES = 4096 + +local TAPE_TYPE_BASIC = 0 +local TAPE_TYPE_MACHINE = 1 +local TAPE_TYPE_ASCII = 2 + +local MSX_CAS_SYNC = { 0x1F, 0xA6, 0xDE, 0xBA, 0xCC, 0x13, 0x7D, 0x74 } + +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local CASSETTE_DEVICE_TAG = ":cassette" + +local button = {} +local frame_num = 0 +common_autoboot.populate_buttons(button) + +local function find_cassette_path() + for _, cass in pairs(manager.machine.cassettes) do + if cass.exists and cass.filename and #cass.filename > 0 then + print("[MSX1 Cass Autoboot] Cassette device: " .. cass.filename) + return cass.filename + end + end + for _, img in pairs(manager.machine.images) do + if img.exists and img.filename and #img.filename > 0 then + local fn = img.filename:lower() + if fn:find("%.cas$") or fn:find("%.wav$") then + print("[MSX1 Cass Autoboot] Image device cassette: " .. img.filename) + return img.filename + end + end + end + return nil +end + +-- ── MSX .cas header parser ──────────────────────────────────────────────────── +-- +-- Scan for the 8-byte sync sequence, then inspect the 10 type bytes that follow. + +local function find_sync(data) + if not data or #data < 18 then return nil end + for i = 1, #data - 17 do + local ok = true + for j = 1, 8 do + if data:byte(i + j - 1) ~= MSX_CAS_SYNC[j] then + ok = false; break + end + end + if ok then return i end + end + return nil +end + +local function parse_cas_header(data) + local sync_pos = find_sync(data) + if not sync_pos then return nil end + + -- 10 type-indicator bytes follow the 8-byte sync + local type_base = sync_pos + 8 + if type_base + 9 > #data then return nil end + + local type_byte = data:byte(type_base) + local uniform = true + for i = 1, 9 do + if data:byte(type_base + i) ~= type_byte then + uniform = false; break + end + end + if not uniform then return nil end + + -- 6-byte filename follows the type indicator + local name_base = type_base + 10 + local filename = "" + if name_base + 5 <= #data then + local chars = {} + for i = 0, 5 do + local c = data:byte(name_base + i) + if c and c ~= 0x00 and c ~= 0x20 then + table.insert(chars, string.char(c)) + end + end + filename = table.concat(chars) + end + + if type_byte == 0xD3 then + print(string.format("[MSX1 Cass Autoboot] Header: BASIC name='%s'", filename)) + return { file_type = TAPE_TYPE_BASIC, filename = filename } + elseif type_byte == 0xD0 then + print(string.format("[MSX1 Cass Autoboot] Header: MACHINE name='%s'", filename)) + return { file_type = TAPE_TYPE_MACHINE, filename = filename } + elseif type_byte == 0xEA then + print(string.format("[MSX1 Cass Autoboot] Header: ASCII name='%s'", filename)) + return { file_type = TAPE_TYPE_ASCII, filename = filename } + end + + print(string.format("[MSX1 Cass Autoboot] Unknown type byte 0x%02X, defaulting to BASIC.", type_byte)) + return { file_type = TAPE_TYPE_BASIC, filename = filename } +end + +local function detect_tape_info() + print("[MSX1 Cass Autoboot] --- Tape type detection ---") + local path = find_cassette_path() + if not path then + print("[MSX1 Cass Autoboot] No cassette found, defaulting to BASIC.") + return { file_type = TAPE_TYPE_BASIC, filename = "" } + end + local data = zip_util.read_bytes(path, CAS_SCAN_BYTES) + if not data then + print("[MSX1 Cass Autoboot] Could not read cassette, defaulting to BASIC.") + return { file_type = TAPE_TYPE_BASIC, filename = "" } + end + local info = parse_cas_header(data) + if info then return info end + print("[MSX1 Cass Autoboot] No valid header found, defaulting to BASIC.") + return { file_type = TAPE_TYPE_BASIC, filename = "" } +end + +-- ── Boot functions ──────────────────────────────────────────────────────────── + +local cassette_handler = common_autoboot.create_cassette_handler(CASSETTE_DEVICE_TAG) +local tape_info = nil + +local function boot_basic() + -- Tokenised BASIC saved with CSAVE (0xD3): CLOAD, then RUN after motor off + common_autoboot.type_at_frame(frame_num, "CLOAD\n", 150, BUTTON_PRESS_DURATION) + common_autoboot.play_cassette_at_frame(frame_num, CASSETTE_DEVICE_TAG, 250) + + if cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) then + emu.keypost("RUN\n") + end +end + +local function boot_machine() + -- Binary saved with BSAVE (0xD0): BLOAD"CAS:",R — auto-executes, no post-load command + common_autoboot.type_at_frame(frame_num, 'BLOAD"CAS:",R\n', 150, BUTTON_PRESS_DURATION) + common_autoboot.play_cassette_at_frame(frame_num, CASSETTE_DEVICE_TAG, 250) + + cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) +end + +local function boot_ascii() + -- ASCII BASIC saved with SAVE"CAS:",A (0xEA): LOAD"CAS:" waits for motor like CLOAD, + -- then RUN after tape stops. RUN"CAS:" returns "bad file name" on MSX2 DISK-BASIC + -- because it doesn't block for the motor signal before timing out. + common_autoboot.type_at_frame(frame_num, 'LOAD"CAS:"\n', 150, BUTTON_PRESS_DURATION) + common_autoboot.play_cassette_at_frame(frame_num, CASSETTE_DEVICE_TAG, 250) + + if cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) then + emu.keypost("RUN\n") + end +end + +-- ── Main ────────────────────────────────────────────────────────────────────── + +local function process_frame() + frame_num = frame_num + 1 + + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + common_autoboot.print_image_info() + tape_info = detect_tape_info() + end + + common_autoboot.debug_frame_num(frame_num) + + if tape_info.file_type == TAPE_TYPE_MACHINE then + boot_machine() + elseif tape_info.file_type == TAPE_TYPE_ASCII then + boot_ascii() + else + boot_basic() + end +end + +subscription = emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mtx_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mtx_cass.lua new file mode 100644 index 00000000000..b873c87d3d8 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mtx_cass.lua @@ -0,0 +1,135 @@ +-- mtx_cass.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +-- --- Cassette Loading Handler Setup --- +local CASSETTE_SLOT = 4 +local CASSETTE_DEVICE_TAG = manager.machine.images:at(CASSETTE_SLOT).device.tag +local cassette_handler = common_autoboot.create_cassette_handler(CASSETTE_DEVICE_TAG) + +common_autoboot.populate_buttons(button) + +common_autoboot.print_image_info() + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +-- Detect MTX500-only games by filename. +-- Returns "mtx500_run" if the game needs POKE+NEW+LOAD+RUN, +-- "mtx500" if the game needs POKE+NEW+LOAD (no RUN), +-- "default" otherwise. +local function detect_game_type(filename) + local lower = string.lower(filename) + if lower:find("mtx500") or lower:find("mtx 500") then + -- filename convention: (poke 64122,0--new--load--run) or (poke 64122,0--new--load) + if lower:find("load%-%-run") or lower:find("load%-run") then + return "mtx500_run" + else + return "mtx500" + end + end + return "default" +end + +local function boot_default(cassette_handler) + common_autoboot.type_at_frame(frame_num, "LOAD\"\"\n", 100) + common_autoboot.play_cassette_at_frame(frame_num, CASSETTE_DEVICE_TAG, 200) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + -- emu.keypost('RUN\n') + end +end + +-- MTX500-only games: ROM at 0xFA00-0xFFFF must be banked out before loading. +-- POKE 64122,0 disables the MTX ROM overlay and maps RAM in its place. + +-- Persistent state for motor detection and RUN scheduling +local mtx500_motor_was_on = false +local mtx500_motor_off_frame = 0 +local mtx500_run_sent = false +local RUN_DELAY_FRAMES = 120 + +local function boot_mtx500_base(cassette_handler, with_run) + common_autoboot.type_at_frame(frame_num, "POKE 64122,0\n", 100) + common_autoboot.type_at_frame(frame_num, "NEW\n", 200) + common_autoboot.type_at_frame(frame_num, "LOAD\"\"\n", 300) + common_autoboot.play_cassette_at_frame(frame_num, CASSETTE_DEVICE_TAG, 400) + + -- Use cassette_handler for throttle management only + cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if frame_num < 400 then return end + + -- Direct cassette state monitoring (independent of cassette_handler) + local cass = manager.machine.cassettes[CASSETTE_DEVICE_TAG] + if not cass then return end + + local playing = (cass.is_stopped == false) and (cass.motor_state == true) + + if playing then + mtx500_motor_was_on = true + mtx500_motor_off_frame = 0 -- reset if motor comes back on (inter-block gap) + elseif mtx500_motor_was_on and mtx500_motor_off_frame == 0 then + mtx500_motor_off_frame = frame_num + end + + if with_run and not mtx500_run_sent + and mtx500_motor_off_frame > 0 + and frame_num >= mtx500_motor_off_frame + RUN_DELAY_FRAMES then + manager.machine.video.throttled = true + manager.machine.video.frameskip = 0 + emu.keypost("RUN\n") + mtx500_run_sent = true + end +end + +local function boot_mtx500(cassette_handler) + boot_mtx500_base(cassette_handler, false) +end + +local function boot_mtx500_run(cassette_handler) + boot_mtx500_base(cassette_handler, true) +end + +-- --- Main Script Logic --- + +local current_software_name = manager.machine.images:at(CASSETTE_SLOT).filename +local game_type = detect_game_type(current_software_name) + +local boot_sequences = { + ['default'] = boot_default, + ['mtx500'] = boot_mtx500, + ['mtx500_run'] = boot_mtx500_run, +} + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + emu.print_info("--- Detected game type: " .. game_type .. " ---") + end + + --- DEBUG: Print current frame number every 100 frames --- + common_autoboot.debug_frame_num(frame_num) + + local boot_function = boot_sequences[game_type] or boot_sequences["default"] + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mz2000_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mz2000_cass.lua new file mode 100644 index 00000000000..40123c775d5 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mz2000_cass.lua @@ -0,0 +1,25 @@ +local frame_num = 0 + +local function process_frame() + frame_num = frame_num + 1 + + if frame_num == 150 then + emu.keypost('C') + end + + if frame_num == 200 then + manager.machine.cassettes[":cassette"]:play() + end + + if manager.machine.cassettes[":cassette"].is_stopped == false and manager.machine.cassettes[":cassette"].motor_state == true then + manager.machine.video.throttled = false + manager.machine.video.frameskip = 12 + else + manager.machine.video.throttled = true + manager.machine.video.frameskip = 0 + end +end + +subscription=emu.add_machine_frame_notifier(process_frame) + + diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mz700_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mz700_cass.lua new file mode 100644 index 00000000000..c4922cbe307 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mz700_cass.lua @@ -0,0 +1,81 @@ +-- bbc_cass.lua + +-- WIP: Some games require *RUN instead of CHAIN, WIP WIP!! + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +common_autoboot.populate_buttons(button) + +-- Print the button table contents for debugging +-- common_autoboot.print_buttons(button) + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function boot_default(cassette_handler) + common_autoboot.type_at_frame(frame_num, "LOAD\n", 50, BUTTON_PRESS_DURATION) +-- common_autoboot.type_at_frame(frame_num, "CHAIN\"\"\n", 100, BUTTON_PRESS_DURATION) + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 100) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + -- emu.keypost('RUN\n') + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(1).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + ["default"] = boot_default, +} + +-- --- Cassette Loading Handler Setup --- +local cassette_handler = common_autoboot.create_cassette_handler(":cassette") + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + -- --- Print current frame number every 100 frames --- + if frame_num % 100 == 0 then -- The modulo operator (%) gives the remainder of a division + emu.print_info("Current Frame: " .. frame_num) + end + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mz800_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mz800_cass.lua new file mode 100644 index 00000000000..40123c775d5 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mz800_cass.lua @@ -0,0 +1,25 @@ +local frame_num = 0 + +local function process_frame() + frame_num = frame_num + 1 + + if frame_num == 150 then + emu.keypost('C') + end + + if frame_num == 200 then + manager.machine.cassettes[":cassette"]:play() + end + + if manager.machine.cassettes[":cassette"].is_stopped == false and manager.machine.cassettes[":cassette"].motor_state == true then + manager.machine.video.throttled = false + manager.machine.video.frameskip = 12 + else + manager.machine.video.throttled = true + manager.machine.video.frameskip = 0 + end +end + +subscription=emu.add_machine_frame_notifier(process_frame) + + diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mz80k_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mz80k_cass.lua new file mode 100644 index 00000000000..86c7cde0d6d --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/mz80k_cass.lua @@ -0,0 +1,33 @@ +local frame_num = 0 +local function process_frame() + frame_num = frame_num + 1 + if frame_num == 10 then + emu.keypost('L') + end + if frame_num == 50 then + emu.keypost('O') + end + if frame_num == 100 then + emu.keypost('A') + end + if frame_num == 150 then + emu.keypost('D') + end + if frame_num == 200 then + emu.keypost('\n') + end + if frame_num == 250 then + manager.machine.cassettes[":cassette"]:play() + end + if manager.machine.cassettes[":cassette"].is_stopped == false and manager.machine.cassettes[":cassette"].motor_state == true then + manager.machine.video.throttled = false + manager.machine.video.frameskip = 12 + else + manager.machine.video.throttled = true + manager.machine.video.frameskip = 0 + end +end + +subscription=emu.add_machine_frame_notifier(process_frame) + + diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/ngp.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/ngp.lua new file mode 100644 index 00000000000..ce4c4c1b151 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/ngp.lua @@ -0,0 +1,23 @@ +local button = {} +local ports = manager.machine.ioport.ports[":Controls"] +for field_name, field in pairs(ports.fields) do + button[field_name] = field +end + +local frame_num = 0 +local function process_frame() + frame_num = frame_num + 1 + + if frame_num < 100 * 6 then + if frame_num % 2 == 0 then + button["Button A"]:set_value(1) + else + button["Button A"]:set_value(0) + end + end +end + +subscription=emu.add_machine_frame_notifier(process_frame) + + + diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/orao_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/orao_cass.lua new file mode 100644 index 00000000000..a50ce109fc7 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/orao_cass.lua @@ -0,0 +1,24 @@ +local frame_num = 0 +local function process_frame() + frame_num = frame_num + 1 + + if frame_num == 40 then + emu.keypost('BC\n') + elseif frame_num == 90 then + emu.keypost('\n') + elseif frame_num == 190 then + emu.keypost('LMEM""\n') + elseif frame_num == 220 then + manager.machine.cassettes[":cassette"]:play() + end + + if manager.machine.cassettes[":cassette"].is_stopped == false and manager.machine.cassettes[":cassette"].motor_state == true then + manager.machine.video.throttled = false + manager.machine.video.frameskip = 12 + else + manager.machine.video.throttled = true + manager.machine.video.frameskip = 0 + end +end + +subscription=emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/oric1_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/oric1_cass.lua new file mode 100644 index 00000000000..1c079751fa2 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/oric1_cass.lua @@ -0,0 +1,76 @@ +-- oric1_cass.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +-- Load buttons +common_autoboot.populate_buttons(button) + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function boot_default(cassette_handler) + common_autoboot.type_at_frame(frame_num, "CLOAD\"\"\n", 200, BUTTON_PRESS_DURATION) + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 300) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + -- emu.keypost('RUN\n') + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(2).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + ["default"] = boot_default, +} + +-- --- Cassette Loading Handler Setup --- +local cassette_handler = common_autoboot.create_cassette_handler(":cassette") + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + --- Print current frame number every 100 frames --- + if frame_num % 100 == 0 then -- The modulo operator (%) gives the remainder of a division + emu.print_info("Current Frame: " .. frame_num) + end + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/orion_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/orion_cass.lua new file mode 100644 index 00000000000..e6bf0d41bbb --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/orion_cass.lua @@ -0,0 +1,152 @@ +-- orion_cass.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +-- --- Load butons --- +common_autoboot.populate_buttons(button) + +-- --- Print Info --- +common_autoboot.print_image_info() +common_autoboot.print_buttons(button) + +-- --- Cassette Loading Handler Setup --- +local CASSETTE_SLOT = 1 +local CASSETTE_DEVICE_TAG = manager.machine.images:at(CASSETTE_SLOT).device.tag +local cassette_handler = common_autoboot.create_cassette_handler(CASSETTE_DEVICE_TAG) + + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = 100 -- common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function create_boot_default_sequence(frame_num, cassette_monitor_func) -- 'cassette_monitor_func' is the per-frame callable handler + local sequence_state = 0 + -- Define states for clarity + local STATES = { + INIT_PRE_LOAD_ACTIONS = 0, -- Initial actions before CLOAD/PLAY + PLAY_CASS_INITIATED = 1, -- CLOAD/PLAY commands sent, waiting for motor to spin up + LOADING_CASS = 2, -- Cassette motor is ON, monitoring for completion + CASS_LOAD_DONE = 3, -- Cassette has finished loading, waiting for post-load actions + POST_LOAD_ACTIONS = 4, -- Executing actions after cassette load + COMPLETE = 5 -- Sequence finished + } + + local post_load_start_frame = 0 -- Frame at which post-load actions began + + return function(current_frame_num) -- This inner function runs every frame + -- Always call cassette_monitor_func once we are in a state where loading should be active. + -- This ensures continuous monitoring, throttling, and detection of load completion. + if sequence_state >= STATES.LOADING_CASS and sequence_state < STATES.CASS_LOAD_DONE then + local cassette_load_done = cassette_monitor_func(current_frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + if cassette_load_done then + sequence_state = STATES.CASS_LOAD_DONE -- Transition directly to CASS_LOAD_DONE + post_load_start_frame = current_frame_num -- Mark start for relative timing of post-actions + emu.print_info("Boot Default: Cassette loading is complete (triggered by handler). Transitioning to post-load actions.") + return -- Exit early for this frame after state change, to prevent double-execution + end + end + + -- --- State Machine Logic --- + if sequence_state == STATES.INIT_PRE_LOAD_ACTIONS then + -- Schedule initial pre-load actions + common_autoboot.press_and_release(button, current_frame_num, "Cursor Down", 100, 1) + common_autoboot.press_and_release(button, current_frame_num, "Cursor Down", 110, 1) + common_autoboot.press_and_release(button, current_frame_num, "Cursor Down", 120, 1) + common_autoboot.press_and_release(button, current_frame_num, "Enter", 150, BUTTON_PRESS_DURATION) + common_autoboot.type_at_frame(current_frame_num, "A\n", 200) + + common_autoboot.play_cassette_at_frame(current_frame_num, CASSETTE_DEVICE_TAG, 350) + + -- Transition to PLAY_CASS_INITIATED after these actions are scheduled (at the last target frame or beyond) + if current_frame_num >= 350 then + sequence_state = STATES.PLAY_CASS_INITIATED + emu.print_info("Boot Default: Pre-load actions scheduled. Waiting for cassette motor to engage.") + end + + elseif sequence_state == STATES.PLAY_CASS_INITIATED then + -- Wait for the cassette motor to actually spin up + local cassette_device = manager.machine.cassettes[CASSETTE_DEVICE_TAG] + if cassette_device and cassette_device.motor_state == true then + sequence_state = STATES.LOADING_CASS + emu.print_info("Boot Default: Cassette motor confirmed ON. Beginning continuous monitoring.") + end + + -- If sequence_state becomes CASS_LOAD_DONE (from the monitor above), this block is skipped, + -- and the logic will fall through to the next `elseif` for POST_LOAD_ACTIONS in the subsequent frame. + + elseif sequence_state == STATES.CASS_LOAD_DONE then + -- This state is primarily a transition point. + -- The 'RUN' command is NOT issued here. It's issued by the cassette_monitor_func internally. + -- We transition immediately to POST_LOAD_ACTIONS after load is detected. + sequence_state = STATES.POST_LOAD_ACTIONS + emu.print_info("Boot Default: Transitioning to post-load actions.") + + elseif sequence_state == STATES.POST_LOAD_ACTIONS then + -- --- Actions to perform AFTER cassette load is done --- + -- Use `post_load_start_frame` for relative timing + common_autoboot.press_and_release(button, current_frame_num, "F4", post_load_start_frame + 300, 1) + common_autoboot.press_and_release(button, current_frame_num, "Cursor Right", post_load_start_frame + 400, 1) + common_autoboot.press_and_release(button, current_frame_num, "Cursor Down", post_load_start_frame + 410, 1) + common_autoboot.press_and_release(button, current_frame_num, "Enter", post_load_start_frame + 420, BUTTON_PRESS_DURATION) + + -- Check if all post-load actions are completed + if current_frame_num >= post_load_start_frame + 1000 + BUTTON_PRESS_DURATION then + sequence_state = STATES.COMPLETE + emu.print_info("Boot Default: All post-load actions completed. Sequence finished.") + end + + elseif sequence_state == STATES.COMPLETE then + -- Do nothing, sequence is finished. + end + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(CASSETTE_SLOT).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + ['default'] = create_boot_default_sequence(frame_num, cassette_handler), +} + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + --- DEBUG: Print current frame number every 100 frames --- + common_autoboot.debug_frame_num(frame_num) + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(frame_num, cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/pc6001_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/pc6001_cass.lua new file mode 100644 index 00000000000..7e7884d2bd7 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/pc6001_cass.lua @@ -0,0 +1,50 @@ +local frame_num = 0 +local throttle_asked = 0 +local throttle_qty = 0 +local command + +local function process_frame() + frame_num = frame_num + 1 + + --if manager.machine.cassettes[":cassette"].is_stopped == false and manager.machine.cassettes[":cassette"].motor_state == true then + -- if throttle_asked == 0 then + -- throttle_qty = throttle_qty + 1 + -- throttle_asked = 1 + + -- manager.machine.video.throttled = false + -- manager.machine.video.frameskip = 12 + -- end + --else + -- if throttle_asked == 1 then + -- throttle_asked = 0 + + -- manager.machine.video.throttled = true + -- manager.machine.video.frameskip = 0 + + -- emu.keypost("RUN\n") + -- end + --end + + if frame_num == 200 then + emu.keypost(command_page) + elseif frame_num == 250 then + emu.keypost("CLOAD\n") + end +end + +command_page = '' + +info_usage = os.getenv("RANDOMAME_INFO_USAGE") +if info_usage ~= nil and info_usage ~= "" then + if string.find(info_usage, "Page 1") then + command_page = "1\n" + elseif string.find(info_usage, "Page 2") then + command_page = "2\n" + elseif string.find(info_usage, "Page 3") then + command_page = "3\n" + elseif string.find(info_usage, "Page 4") then + command_page = "4\n" + end +end + +subscription=emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/pc6001mk2_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/pc6001mk2_cass.lua new file mode 100644 index 00000000000..147333351ee --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/pc6001mk2_cass.lua @@ -0,0 +1,67 @@ +local frame_num = 0 +local throttle_asked = 0 +local throttle_qty = 0 +local command + +local function process_frame() + frame_num = frame_num + 1 + + --if manager.machine.cassettes[":cas_hack"].is_stopped == false and manager.machine.cassettes[":cas_hack"].motor_state == true then + -- if throttle_asked == 0 then + -- throttle_qty = throttle_qty + 1 + -- throttle_asked = 1 + + -- manager.machine.video.throttled = false + -- manager.machine.video.frameskip = 12 + -- end + --else + -- if throttle_asked == 1 then + -- throttle_asked = 0 + + -- manager.machine.video.throttled = true + -- manager.machine.video.frameskip = 0 + + -- emu.keypost("RUN\n") + -- end + --end + + if frame_num == 200 then + print("Mode: ",command_mode) + emu.keypost(command_mode) + elseif frame_num == 250 then + print("Page: ",command_page) + emu.keypost(command_page) + elseif frame_num == 300 then + emu.keypost("CLOAD\n") + end +end + +command_page = '' +command_mode = '' + +info_usage = os.getenv("RANDOMAME_INFO_USAGE") +if info_usage ~= nil and info_usage ~= "" then + if string.find(info_usage, "Page 1") then + command_page = "1\n" + elseif string.find(info_usage, "Page 2") then + command_page = "2\n" + elseif string.find(info_usage, "Page 3") then + command_page = "3\n" + elseif string.find(info_usage, "Page 4") then + command_page = "4\n" + end + + if string.find(info_usage, "Mode 1") then + command_mode = "1" + elseif string.find(info_usage, "Mode 2") then + command_mode = "2" + elseif string.find(info_usage, "Mode 3") then + command_mode = "3" + elseif string.find(info_usage, "Mode 4") then + command_mode = "4" + elseif string.find(info_usage, "Mode 5") then + command_mode = "5" + end +end + +subscription=emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/pcecd.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/pcecd.lua new file mode 100644 index 00000000000..944dd86fa64 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/pcecd.lua @@ -0,0 +1,26 @@ +local button = {} + +for i, j in pairs(manager.machine.ioport.ports) do + for field_name, field in pairs(j.fields) do + id = field.port.tag .. ',' .. field.mask .. ',' .. field.type + print(field_name,"->", id) + button[id] = field + end +end + + +local frame_num = 0 +local function process_frame() + frame_num = frame_num + 1 + + if frame_num == 25 then + button[":ctrl:joypad2:BUTTONS,8,46"]:set_value(1) + elseif frame_num == 30 then + button[":ctrl:joypad2:BUTTONS,8,46"]:set_value(0) + end +end + +subscription=emu.add_machine_frame_notifier(process_frame) + + + diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/pecom_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/pecom_cass.lua new file mode 100644 index 00000000000..e8a55ae721d --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/pecom_cass.lua @@ -0,0 +1,113 @@ +-- pecom_cass.lua + +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +local frame_num = 0 + +-- Build button table keyed by "port_tag,mask,type" for direct key presses (juku.lua style) +local button = {} +for _, port in pairs(manager.machine.ioport.ports) do + for _, field in pairs(port.fields) do + button[field.port.tag .. "," .. field.mask .. "," .. field.type] = field + end +end + +common_autoboot.print_image_info() + +local CASSETTE_DEVICE_TAG = ":cassette" +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +-- RUN key IDs (port_tag, mask, IPT_KEYBOARD=49) +-- Source: src/mame/sfrj/pecom.cpp +local KEY = { + R = ":LINE19,1,49", + U = ":LINE20,2,49", + N = ":LINE17,1,49", + RETURN = ":LINE0,1,49", +} +local KEY_DURATION = 5 +local KEY_GAP = 10 + +local function press_key(id, press_frame) + if not button[id] then return end + if frame_num == press_frame then + button[id]:set_value(1) + elseif frame_num == press_frame + KEY_DURATION then + button[id]:set_value(0) + end +end + +-- is_stopped-based handler: works even when the Pecom does not assert motor_state. +-- Mirrors the approach used in mc10_cass.lua. +local function create_pecom_cassette_handler(tag) + local stop_frame = 0 + local seen_playing = false + local load_done = false + + return function(current_frame_num, delay) + local dev = manager.machine.cassettes[tag] + if not dev then + emu.print_info("WARNING: Cassette device '" .. tag .. "' not found!") + return false + end + + if dev.is_stopped == false then + manager.machine.video.throttled = false + manager.machine.video.frameskip = 12 + seen_playing = true + else + manager.machine.video.throttled = true + manager.machine.video.frameskip = 0 + if seen_playing and stop_frame == 0 then + stop_frame = current_frame_num + emu.print_info("[Pecom] Cassette stopped at frame " .. current_frame_num) + end + end + + if not load_done and stop_frame ~= 0 and current_frame_num > stop_frame + delay then + load_done = true + emu.print_info("[Pecom] Cassette load complete at frame " .. current_frame_num) + return true + end + + return false + end +end + +local cassette_handler = create_pecom_cassette_handler(CASSETTE_DEVICE_TAG) +local post_load_frame = nil + +local function boot_default() + common_autoboot.type_at_frame(frame_num, "PLOAD\n", 50) + common_autoboot.play_cassette_at_frame(frame_num, CASSETTE_DEVICE_TAG, 150) + + if cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) then + post_load_frame = frame_num + end + + -- Type RUN + Return via direct key presses to avoid natural-keyboard case issues + if post_load_frame then + local base = post_load_frame + 10 + press_key(KEY.R, base) + press_key(KEY.U, base + (KEY_DURATION + KEY_GAP)) + press_key(KEY.N, base + (KEY_DURATION + KEY_GAP) * 2) + press_key(KEY.RETURN, base + (KEY_DURATION + KEY_GAP) * 3) + end +end + +local current_software_name = manager.machine.images:at(1).filename + +local function process_frame() + frame_num = frame_num + 1 + + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software: " .. current_software_name) + end + + common_autoboot.debug_frame_num(frame_num) + + boot_default() +end + +subscription = emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/radio86_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/radio86_cass.lua new file mode 100644 index 00000000000..ab824ba9580 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/radio86_cass.lua @@ -0,0 +1,78 @@ +-- radio86_cass.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +-- --- Print Info --- +common_autoboot.print_image_info() + +-- --- Cassette Loading Handler Setup --- +local CASSETTE_SLOT = 1 +local CASSETTE_DEVICE_TAG = manager.machine.images:at(CASSETTE_SLOT).device.tag +local cassette_handler = common_autoboot.create_cassette_handler(CASSETTE_DEVICE_TAG) + +common_autoboot.populate_buttons(button) + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function boot_default(cassette_handler) + common_autoboot.type_at_frame(frame_num, "I\n", 100) + common_autoboot.play_cassette_at_frame(frame_num, CASSETTE_DEVICE_TAG, 200) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + emu.keypost('G\n') + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(CASSETTE_SLOT).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + ['default'] = boot_default, +} + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + --- DEBUG: Print current frame number every 100 frames --- + common_autoboot.debug_frame_num(frame_num) + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/rx78_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/rx78_cass.lua new file mode 100644 index 00000000000..f4cf0dd8da2 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/rx78_cass.lua @@ -0,0 +1,92 @@ +-- rx78_cass.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +common_autoboot.populate_buttons(button) + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function boot_graphmaths(cassette_handler) + common_autoboot.type_at_frame(frame_num, "MON\n", 100) + common_autoboot.type_at_frame(frame_num, "L\n", 200) + common_autoboot.type_at_frame(frame_num, "GRM\n", 300) + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 400) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + emu.keypost('RUN\n') + end +end + +local function boot_yellowcab(cassette_handler) + -- common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 100) + common_autoboot.type_at_frame(frame_num, "MON\n", 100) + common_autoboot.type_at_frame(frame_num, "L\n", 200) + common_autoboot.type_at_frame(frame_num, "CAB\n", 300) + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 400) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + -- emu.keypost('CAB\n') + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(2).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + graphmaths = boot_graphmaths, + yellowcab = boot_yellowcab, +} + +-- --- Cassette Loading Handler Setup --- +local cassette_handler = common_autoboot.create_cassette_handler(":cassette") + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + --- Print current frame number every 100 frames --- + if frame_num % 100 == 0 then -- The modulo operator (%) gives the remainder of a division + emu.print_info("Current Frame: " .. frame_num) + end + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/samcoupe_flop.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/samcoupe_flop.lua new file mode 100644 index 00000000000..71778841fca --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/samcoupe_flop.lua @@ -0,0 +1 @@ +emu.keypost('\nboot\n') diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/saturn.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/saturn.lua new file mode 100644 index 00000000000..cd49e0632bf --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/saturn.lua @@ -0,0 +1,40 @@ +local button = {} + +for i, j in pairs(manager.machine.ioport.ports) do + for field_name, field in pairs(j.fields) do + id = field.port.tag .. ',' .. field.mask .. ',' .. field.type + print(field_name,"->", id) + button[id] = field + end +end + + +local frame_num = 0 +local start_frame = 1000 +local function process_frame() + frame_num = frame_num + 1 + + -- Up + if frame_num == start_frame + 0 then + button[":ctrl1:joypad:JOY,4096,51"]:set_value(1) + elseif frame_num == start_frame + 10 then + button[":ctrl1:joypad:JOY,4096,51"]:set_value(0) + -- Up + elseif frame_num == start_frame + 20 then + button[":ctrl1:joypad:JOY,4096,51"]:set_value(1) + elseif frame_num == start_frame + 30 then + button[":ctrl1:joypad:JOY,4096,51"]:set_value(0) + -- left + elseif frame_num == start_frame + 40 then + button[":ctrl1:joypad:JOY,16384,53"]:set_value(1) + elseif frame_num == start_frame + 50 then + button[":ctrl1:joypad:JOY,16384,53"]:set_value(0) + -- Button A + elseif frame_num == start_frame + 60 then + button[":ctrl1:joypad:JOY,1024,64"]:set_value(1) + elseif frame_num == start_frame + 70 then + button[":ctrl1:joypad:JOY,1024,64"]:set_value(0) + end +end + +subscription=emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/sc3000_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/sc3000_cass.lua new file mode 100644 index 00000000000..8eb54915a26 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/sc3000_cass.lua @@ -0,0 +1,77 @@ +-- sc3000_cass.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +-- --- Cassette Loading Handler Setup --- +local CASSETTE_SLOT = 1 +local CASSETTE_DEVICE_TAG = manager.machine.images:at(CASSETTE_SLOT).device.tag +local cassette_handler = common_autoboot.create_cassette_handler(CASSETTE_DEVICE_TAG) + +common_autoboot.populate_buttons(button) + +common_autoboot.print_image_info() + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function boot_default(cassette_handler) + common_autoboot.type_at_frame(frame_num, "LOAD\n", 300) + common_autoboot.play_cassette_at_frame(frame_num, CASSETTE_DEVICE_TAG, 400) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + emu.keypost('RUN\n') + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(CASSETTE_SLOT).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + ['default'] = boot_default, +} + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + --- DEBUG: Print current frame number every 100 frames --- + common_autoboot.debug_frame_num(frame_num) + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/sorcerer_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/sorcerer_cass.lua new file mode 100644 index 00000000000..4f5fecabeb9 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/sorcerer_cass.lua @@ -0,0 +1,158 @@ +-- sorcerer_cass.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +common_autoboot.populate_buttons(button) + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function boot_default(cassette_handler) + common_autoboot.type_at_frame(frame_num, "CLOAD\n", 300, BUTTON_PRESS_DURATION) + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 400) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + emu.keypost('RUN\n') + end +end + +local function create_boot_type_1_sequence() + return function(cassette_handler_arg) + common_autoboot.type_at_frame(frame_num, "BYE\n", 300) + common_autoboot.type_at_frame(frame_num, "LOG\n", 400) + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 500) + + local cassette_load_done = cassette_handler_arg(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + -- emu.keypost('/\n') + end + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(3).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + adv1 = create_boot_type_1_sequence(), + adv2 = create_boot_type_1_sequence(), + adv3 = create_boot_type_1_sequence(), + adv4 = create_boot_type_1_sequence(), + adv5 = create_boot_type_1_sequence(), + adv6 = create_boot_type_1_sequence(), + adv7 = create_boot_type_1_sequence(), + adv8 = create_boot_type_1_sequence(), + adv9 = create_boot_type_1_sequence(), + amaze = create_boot_type_1_sequence(), + apatrol = create_boot_type_1_sequence(), + arith = create_boot_type_1_sequence(), + arrow = create_boot_type_1_sequence(), + arrow2 = create_boot_type_1_sequence(), + ast = create_boot_type_1_sequence(), + aster = create_boot_type_1_sequence(), + astro = create_boot_type_1_sequence(), + atc = create_boot_type_1_sequence(), + atc1 = create_boot_type_1_sequence(), + biochart = create_boot_type_1_sequence(), + biorhythm = create_boot_type_1_sequence(), + blackj = create_boot_type_1_sequence(), + cadas = create_boot_type_1_sequence(), + char = create_boot_type_1_sequence(), + chess1 = create_boot_type_1_sequence(), + chess2 = create_boot_type_1_sequence(), + chomp = create_boot_type_1_sequence(), + com48 = create_boot_type_1_sequence(), + cosmc = create_boot_type_1_sequence(), + crash = create_boot_type_1_sequence(), + debug = create_boot_type_1_sequence(), + defcm = create_boot_type_1_sequence(), + dfndr = create_boot_type_1_sequence(), + disas2 = create_boot_type_1_sequence(), + dterm = create_boot_type_1_sequence(), + dybug = create_boot_type_1_sequence(), + ezy = create_boot_type_1_sequence(), + fgam = create_boot_type_1_sequence(), + flip = create_boot_type_1_sequence(), + flite = create_boot_type_1_sequence(), + galax = create_boot_type_1_sequence(), + galx = create_boot_type_1_sequence(), + grotnik = create_boot_type_1_sequence(), + homerun = create_boot_type_1_sequence(), + hpad = create_boot_type_1_sequence(), + interceptor = create_boot_type_1_sequence(), + invad2 = create_boot_type_1_sequence(), + invaders = create_boot_type_1_sequence(), + kalid = create_boot_type_1_sequence(), + killerg = create_boot_type_1_sequence(), + kilo = create_boot_type_1_sequence(), + kilopede = create_boot_type_1_sequence(), + l2x = create_boot_type_1_sequence(), + landarc = create_boot_type_1_sequence(), + ldg = create_boot_type_1_sequence(), + magicmaze = create_boot_type_1_sequence(), + midas = create_boot_type_1_sequence(), + minva = create_boot_type_1_sequence(), + misil = create_boot_type_1_sequence(), + mmind = create_boot_type_1_sequence(), + munch = create_boot_type_1_sequence(), + nike2 = create_boot_type_1_sequence(), + robot = create_boot_type_1_sequence(), + spider = create_boot_type_1_sequence(), + starf = create_boot_type_1_sequence(), + sword = create_boot_type_1_sequence(), + wumpus = create_boot_type_1_sequence(), + zetu = create_boot_type_1_sequence(), + + ["default"] = boot_default, +} + +-- --- Cassette Loading Handler Setup --- +local cassette_handler = common_autoboot.create_cassette_handler(":cassette1") + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + --- Print current frame number every 100 frames --- + if frame_num % 100 == 0 then -- The modulo operator (%) gives the remainder of a division + emu.print_info("Current Frame: " .. frame_num) + end + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/specpls3_flop.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/specpls3_flop.lua new file mode 100644 index 00000000000..2791876398e --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/specpls3_flop.lua @@ -0,0 +1,3 @@ +emu.keypost('\n') + + diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/spectrum_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/spectrum_cass.lua new file mode 100644 index 00000000000..3cc215bd01e --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/spectrum_cass.lua @@ -0,0 +1,15 @@ +local function process_frame() + if manager.machine.cassettes[":cassette"].is_stopped == false and manager.machine.cassettes[":cassette"].motor_state == true then + manager.machine.video.throttled = false + manager.machine.video.frameskip = 12 + else + manager.machine.video.throttled = true + manager.machine.video.frameskip = 0 + end +end + +subscription=emu.add_machine_frame_notifier(process_frame) + +emu.keypost('\nj""\n') +manager.machine.cassettes[":cassette"]:play() + diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/super80_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/super80_cass.lua new file mode 100644 index 00000000000..dd2b94bbb67 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/super80_cass.lua @@ -0,0 +1,284 @@ +-- super80_cass.lua + +-- WIP: need to figure out how to load games with usage + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +common_autoboot.populate_buttons(button) + +common_autoboot.print_image_info() + +-- Print the button table contents for debugging +-- common_autoboot.print_buttons(button) + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function boot_default(cassette_handler) + common_autoboot.type_at_frame(frame_num, "CLOAD\n", 100, BUTTON_PRESS_DURATION) + + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 400) -- need to wait at least 300 frames after CLOAD cmd, otherwise will have LOADING ERROR! + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + emu.keypost('RUN\n') + end +end + +local function create_boot_type_1_sequence(title_to_type) + return function(cassette_handler_arg) + common_autoboot.type_at_frame(frame_num, "L\n", 100) + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 200) + + local cassette_load_done = cassette_handler_arg(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + emu.keypost(title_to_type .. '\n') + end + end +end + +local function create_boot_type_2_sequence() + return function(cassette_handler_arg) + common_autoboot.type_at_frame(frame_num, "GD000\n", 100) -- GD000 to enter BASIC MODE + common_autoboot.type_at_frame(frame_num, "LOAD\n", 200) + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 300) + + local cassette_load_done = cassette_handler_arg(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + emu.keypost('RUN\n') + end + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(3).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + aim = create_boot_type_2_sequence(), + accounts = create_boot_type_2_sequence(), + add = create_boot_type_2_sequence(), + basic = create_boot_type_1_sequence("G100"), + basic1 = create_boot_type_1_sequence("G100"), + bio = create_boot_type_2_sequence(), + bunny = create_boot_type_2_sequence(), + camel = create_boot_type_2_sequence(), + cap = create_boot_type_2_sequence(), + carrace = create_boot_type_2_sequence(), + cavemon = create_boot_type_2_sequence(), + cavemon4 = create_boot_type_2_sequence(), + cavepit = create_boot_type_2_sequence(), + chase = create_boot_type_2_sequence(), + chomp = create_boot_type_2_sequence(), + chucka = create_boot_type_2_sequence(), + crash = create_boot_type_2_sequence(), + crashj = create_boot_type_2_sequence(), + crazym = create_boot_type_1_sequence("G0"), + crazymj = create_boot_type_1_sequence("G0"), + crosfire = create_boot_type_2_sequence(), + cvoicec = create_boot_type_2_sequence(), + cvoicei = create_boot_type_2_sequence(), + debug = create_boot_type_1_sequence("G100"), + debug4 = create_boot_type_1_sequence("G100"), + dungeon = create_boot_type_2_sequence(), + dungeon4 = create_boot_type_2_sequence(), + edasm = create_boot_type_1_sequence("G8000"), + eldraw = create_boot_type_1_sequence("G100"), + epromp = create_boot_type_2_sequence(), + epromr = create_boot_type_2_sequence(), + findword = create_boot_type_2_sequence(), + hangman = create_boot_type_2_sequence(), + horserac = create_boot_type_2_sequence(), + horserace4 = create_boot_type_2_sequence(), + horseracem = create_boot_type_2_sequence(), + hydrax = create_boot_type_2_sequence(), + hydraxj = create_boot_type_2_sequence(), + inva = create_boot_type_1_sequence("G400"), + inva1 = create_boot_type_1_sequence("G400"), + inva1j = create_boot_type_1_sequence("G400"), + inva2 = create_boot_type_1_sequence("G400"), + inva2j = create_boot_type_1_sequence("G400"), + invanal = create_boot_type_2_sequence(), + juggle = create_boot_type_2_sequence(), + lcxf = create_boot_type_2_sequence(), + life = create_boot_type_1_sequence("G0"), + loancalc = create_boot_type_2_sequence(), + lunar1 = create_boot_type_2_sequence(), + lunar2 = create_boot_type_2_sequence(), + lunar3 = create_boot_type_2_sequence(), + lwriter = create_boot_type_2_sequence(), + lwriter4 = create_boot_type_2_sequence(), + l2basic = create_boot_type_1_sequence("G0"), + masterm = create_boot_type_2_sequence(), + matchmat = create_boot_type_2_sequence(), + maths = create_boot_type_2_sequence(), + mem = create_boot_type_2_sequence(), + meteor = create_boot_type_2_sequence(), + meteorj = create_boot_type_2_sequence(), + minitype = create_boot_type_1_sequence("G8000"), + minit1 = create_boot_type_1_sequence("GB700"), + minit3 = create_boot_type_1_sequence("G8000"), + missile = create_boot_type_2_sequence(), + missile4 = create_boot_type_2_sequence(), + missile4j = create_boot_type_2_sequence(), + moneytst = create_boot_type_2_sequence(), + monopoly = create_boot_type_2_sequence(), + moorads = create_boot_type_2_sequence(), + morse = create_boot_type_2_sequence(), + mortor1 = create_boot_type_2_sequence(), + mortor2 = create_boot_type_2_sequence(), + mortor4 = create_boot_type_2_sequence(), + onearm = create_boot_type_2_sequence(), + onearm4 = create_boot_type_2_sequence(), + opposite = create_boot_type_2_sequence(), + othello = create_boot_type_2_sequence(), + pelatron = create_boot_type_1_sequence("G100"), + petrol = create_boot_type_2_sequence(), + pi = create_boot_type_2_sequence(), + planet = create_boot_type_2_sequence(), + pontoon = create_boot_type_2_sequence(), + puzzle = create_boot_type_2_sequence(), + riverboa = create_boot_type_2_sequence(), + riverboatj = create_boot_type_2_sequence(), + rotate = create_boot_type_2_sequence(), + russroul = create_boot_type_2_sequence(), + s80solit = create_boot_type_2_sequence(), + sets = create_boot_type_2_sequence(), + shell = create_boot_type_2_sequence(), + shell4 = create_boot_type_2_sequence(), + shootgal = create_boot_type_2_sequence(), + shootgal1 = create_boot_type_2_sequence(), + sinv = create_boot_type_2_sequence(), + sinvj = create_boot_type_2_sequence(), + skier = create_boot_type_2_sequence(), + smart = create_boot_type_1_sequence("G100"), + snake = create_boot_type_2_sequence(), + snakej = create_boot_type_2_sequence(), + solit = create_boot_type_2_sequence(), + soundemo = create_boot_type_2_sequence(), + stopwatc = create_boot_type_2_sequence(), + suprtrek = create_boot_type_2_sequence(), + sword = create_boot_type_2_sequence(), + takeaway = create_boot_type_2_sequence(), + tenpin = create_boot_type_2_sequence(), + thisisbu = create_boot_type_2_sequence(), + thisisbu4 = create_boot_type_2_sequence(), + tibetian = create_boot_type_2_sequence(), + tictac = create_boot_type_2_sequence(), + treasure = create_boot_type_2_sequence(), + vonshrin = create_boot_type_2_sequence(), + x6845p = create_boot_type_2_sequence(), + x4inarow = create_boot_type_2_sequence(), + xaa = create_boot_type_1_sequence("G100"), + xaaj = create_boot_type_1_sequence("G100"), + xadvland = create_boot_type_1_sequence("G3DE0"), + xaster = create_boot_type_1_sequence("G100"), + xasterj = create_boot_type_1_sequence("G100"), + xastp = create_boot_type_1_sequence("G349B"), + xastp3 = create_boot_type_1_sequence("G349B"), + xastp3j = create_boot_type_1_sequence("G349B"), + xastro = create_boot_type_1_sequence("G100"), + xastroj = create_boot_type_1_sequence("G100"), + xatc = create_boot_type_1_sequence("G0"), + xbemon = create_boot_type_1_sequence("G6000"), + xbeez80 = create_boot_type_1_sequence("GA00"), + xcdes = create_boot_type_1_sequence("G100"), + xcstrek = create_boot_type_1_sequence("G100"), + xcaliens = create_boot_type_1_sequence("G100"), + xcharp = create_boot_type_2_sequence(), + xchomp = create_boot_type_1_sequence("G100"), + xchompj = create_boot_type_1_sequence("G100"), + xcorral = create_boot_type_2_sequence(), + xdemon = create_boot_type_1_sequence("G0"), + xdefend = create_boot_type_1_sequence("G100"), + xexmon = create_boot_type_1_sequence("GAA00"), + xexmon3 = create_boot_type_1_sequence("GAA00"), + xfgam = create_boot_type_1_sequence("G1F0"), + xgalax2j = create_boot_type_1_sequence("G100"), + xgalaxj = create_boot_type_1_sequence("G100"), + xgrtkitf = create_boot_type_2_sequence(), + xhangman = create_boot_type_2_sequence(), + xhoh = create_boot_type_2_sequence(), + xhoh3 = create_boot_type_2_sequence(), + xkadath = create_boot_type_2_sequence(), + xkilo = create_boot_type_1_sequence("G1C0A"), + xkilo1 = create_boot_type_1_sequence("G1C0A"), + xkilo1j = create_boot_type_1_sequence("G1C0A"), + xkiloj = create_boot_type_1_sequence("G1C0A"), + xmart = create_boot_type_1_sequence("G0"), + xmart1j = create_boot_type_1_sequence("G0"), + xmerlin = create_boot_type_2_sequence(), + xmerlin2 = create_boot_type_2_sequence(), + xmidas = create_boot_type_1_sequence("G200"), + xmission = create_boot_type_1_sequence("G3C80"), + xpenetr = create_boot_type_1_sequence("G100"), + xpenetrj = create_boot_type_1_sequence("G100"), + xpinegap = create_boot_type_2_sequence(), + xschess1 = create_boot_type_1_sequence("G100"), + xschess2 = create_boot_type_1_sequence("G4040"), + xsupinv = create_boot_type_2_sequence(), + xsupinvj = create_boot_type_2_sequence(), + xvalley = create_boot_type_2_sequence(), + xvalley3 = create_boot_type_2_sequence(), + xvalley3a = create_boot_type_2_sequence(), + xwbee = create_boot_type_1_sequence("G9000"), + xwbee2 = create_boot_type_1_sequence("G9000"), + xbreak = create_boot_type_2_sequence(), + xbreakj = create_boot_type_2_sequence(), + xmsinv = create_boot_type_1_sequence("G1000"), + xmsinvj = create_boot_type_1_sequence("G1000"), + xmsinv2 = create_boot_type_1_sequence("G1000"), + xmsinv2j = create_boot_type_1_sequence("G1000"), + xsub = create_boot_type_2_sequence(), +} + +-- --- Cassette Loading Handler Setup --- +local cassette_handler = common_autoboot.create_cassette_handler(":cassette") + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + -- --- Print current frame number every 100 frames --- + -- if frame_num % 100 == 0 then -- The modulo operator (%) gives the remainder of a division + -- emu.print_info("Current Frame: " .. frame_num) + -- end + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/svi318_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/svi318_cass.lua new file mode 100644 index 00000000000..796d8310c04 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/svi318_cass.lua @@ -0,0 +1,94 @@ +-- sv318_cass.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 +local bload_frame = -1 + +common_autoboot.populate_buttons(button) + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function boot_ninja(cassette_handler) + common_autoboot.type_at_frame(frame_num, "CLOAD\n", 200, BUTTON_PRESS_DURATION) + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 300) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + bload_frame = frame_num + 50 + + if bload_frame == frame_num then + manager.machine.cassettes[":cassette"]:seek(0.0,"set") + emu.keypost('BLOAD "CAS:",R\n') + manager.machine.cassettes[":cassette"]:play() + end + end +end + +local function boot_default(cassette_handler) + common_autoboot.type_at_frame(frame_num, "CLOAD\n", 200, BUTTON_PRESS_DURATION) + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 300) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + emu.keypost('RUN\n') + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(1).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + ninja = boot_ninja, + ["default"] = boot_default, +} + +-- --- Cassette Loading Handler Setup --- +local cassette_handler = common_autoboot.create_cassette_handler(":cassette") + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + -- --- Print current frame number every 100 frames --- + if frame_num % 100 == 0 then -- The modulo operator (%) gives the remainder of a division + emu.print_info("Current Frame: " .. frame_num) + end + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/templates/cassette.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/templates/cassette.lua new file mode 100644 index 00000000000..09ceaca5729 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/templates/cassette.lua @@ -0,0 +1,82 @@ +-- _cass.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +-- --- Map all buttons --- +common_autoboot.populate_buttons(button) + +-- --- Print Info --- +common_autoboot.print_image_info() +-- common_autoboot.print_buttons(button) + +-- --- Cassette Loading Handler Setup --- +local CASSETTE_SLOT = 3 +local CASSETTE_DEVICE_TAG = manager.machine.images:at(CASSETTE_SLOT).device.tag +local cassette_handler = common_autoboot.create_cassette_handler(CASSETTE_DEVICE_TAG) + + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function boot_default(cassette_handler) + common_autoboot.type_at_frame(frame_num, "\n", 300) + common_autoboot.type_at_frame(frame_num, "LOAD\n", 400) + common_autoboot.play_cassette_at_frame(frame_num, CASSETTE_DEVICE_TAG, 500) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + -- emu.keypost('RUN\n') + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(CASSETTE_SLOT).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + ['default'] = boot_default, +} + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + --- DEBUG: Print current frame number every 100 frames --- + common_autoboot.debug_frame_num(frame_num) + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/tg16cd.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/tg16cd.lua new file mode 100644 index 00000000000..ea23fd41132 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/tg16cd.lua @@ -0,0 +1,26 @@ +local button = {} + +for i, j in pairs(manager.machine.ioport.ports) do + for field_name, field in pairs(j.fields) do + id = field.port.tag .. ',' .. field.mask .. ',' .. field.type + print(field_name,"->", id) + button[id] = field + end +end + + +local frame_num = 0 +local function process_frame() + frame_num = frame_num + 1 + + if frame_num == 25 then + button[":ctrl:joypad2_turbo:BUTTONS,8,46"]:set_value(1) + elseif frame_num == 30 then + button[":ctrl:joypad2_turbo:BUTTONS,8,46"]:set_value(0) + end +end + +subscription=emu.add_machine_frame_notifier(process_frame) + + + diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/timex_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/timex_cass.lua new file mode 100644 index 00000000000..64d91b03d4b --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/timex_cass.lua @@ -0,0 +1,82 @@ +-- timex_cass.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +common_autoboot.populate_buttons(button) + +-- --- Print Info --- +common_autoboot.print_buttons(button) +common_autoboot.print_image_info() + +-- --- Cassette Loading Handler Setup --- +local CASSETTE_SLOT = 3 +local CASSETTE_DEVICE_TAG = manager.machine.images:at(CASSETTE_SLOT).device.tag +local cassette_handler = common_autoboot.create_cassette_handler(CASSETTE_DEVICE_TAG) + + + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function boot_default(cassette_handler) + common_autoboot.type_at_frame(frame_num, "j\n", 100) + common_autoboot.type_at_frame(frame_num, "\"\"\n", 200) + common_autoboot.play_cassette_at_frame(frame_num, CASSETTE_DEVICE_TAG, 300) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + -- emu.keypost('RUN\n') + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(CASSETTE_SLOT).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + ['default'] = boot_default, +} + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + --- DEBUG: Print current frame number every 100 frames --- + common_autoboot.debug_frame_num(frame_num) + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/to_flop.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/to_flop.lua new file mode 100644 index 00000000000..4f6caf3d924 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/to_flop.lua @@ -0,0 +1 @@ +emu.keypost('B') diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/to_flop_to9.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/to_flop_to9.lua new file mode 100644 index 00000000000..ac100ec2652 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/to_flop_to9.lua @@ -0,0 +1 @@ +emu.keypost('D') diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/trs80_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/trs80_cass.lua new file mode 100644 index 00000000000..9e62928a321 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/trs80_cass.lua @@ -0,0 +1,326 @@ +-- trs80_cass.lua + +local zip_util = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_zip.lua") + +-- ── Configuration ───────────────────────────────────────────────────────────── +local CAS_SCAN_BYTES = 4096 -- bytes to read from CAS for header search + +-- ── Tape type constants (XRoar tape.h) ──────────────────────────────────────── +local TAPE_TYPE_BASIC = 0 -- CLOAD\r + RUN\r +local TAPE_TYPE_DATA = 1 -- no autorun +local TAPE_TYPE_MACHINE = 2 -- CLOADM\r + EXEC\r + +-- ── State machine ───────────────────────────────────────────────────────────── +local STATE_IDLE = 0 +local STATE_BOOTING = 1 +local STATE_TYPING_LOAD = 2 +local STATE_WAITING = 3 +local STATE_TYPING_RUN = 4 +local STATE_DONE = 5 + +-- ── Runtime state ───────────────────────────────────────────────────────────── +local state = STATE_IDLE +local frame_counter = 0 +local tape_file_type = nil +local load_command = nil +local run_command = nil +local cmd_queue = {} +local load_start_frame = 0 + + +-- ── CAS header parser ───────────────────────────────────────────────────────── + +--- Scan a raw Lua byte-string for a valid CoCo CAS file header. +--- Mirrors XRoar's tape_file_next() / tape_autorun() in tape.c. +--- Returns the file-type byte (0/1/2) on success, nil if not found. +local function parse_cas_header(data) + if not data or #data < 20 then return nil end + + local i = 1 + local saw_leader = false + + while i <= #data do + local b = data:byte(i) + + if b == 0x55 then + saw_leader = true + i = i + 1 + + elseif b == 0x3C and saw_leader then + -- Sync byte after leader sequence → header block follows + local base = i + 1 + if base + 16 > #data then return nil end + + local block_type = data:byte(base) + local block_size = data:byte(base + 1) + + if block_type == 0x00 and block_size >= 15 then + local dstart = base + 2 + if dstart + 8 <= #data then + local file_type = data:byte(dstart + 8) + -- Log the filename (bytes 0-7 of block data) + local fname = "" + for fi = 0, 7 do + local c = data:byte(dstart + fi) + if c and c ~= 0x20 and c ~= 0x00 then + fname = fname .. string.char(c) + end + end + print(string.format( + "[CoCo Autoboot] CAS header: file='%s' type=%d", + fname, file_type)) + return file_type + end + else + -- Malformed block after sync; keep scanning + saw_leader = false + i = i + 1 + end + + else + saw_leader = false + i = i + 1 + end + end + + return nil +end + + +-- ── Cassette path discovery ─────────────────────────────────────────────────── + +--- Find the mounted cassette image filename via MAME's image API. +local function find_cassette_path() + -- First try the specific cassette device enumerator + for _, cass in pairs(manager.machine.cassettes) do + if cass.exists and cass.filename and #cass.filename > 0 then + print("[CoCo Autoboot] Cassette device: " .. cass.filename) + return cass.filename + end + end + -- Fallback: scan all image devices for .cas extension + for _, img in pairs(manager.machine.images) do + if img.exists and img.filename and #img.filename > 0 then + local fn = img.filename:lower() + if fn:find("%.cas$") then + print("[CoCo Autoboot] Image device (.cas): " .. img.filename) + return img.filename + end + end + end + return nil +end + +--- Top-level detection. +local function detect_tape_type() + print("[CoCo Autoboot] --- Tape type detection ---") + + local path = find_cassette_path() + if not path then + print("[CoCo Autoboot] No cassette image found.") + return nil + end + print("[CoCo Autoboot] Path: " .. path) + + local data = zip_util.read_bytes(path, CAS_SCAN_BYTES) + if not data then + print("[CoCo Autoboot] Could not read CAS data — defaulting to BASIC.") + return TAPE_TYPE_BASIC + end + + local ft = parse_cas_header(data) + if ft ~= nil then return ft end + + print("[CoCo Autoboot] No valid CAS header found — defaulting to BASIC.") + return TAPE_TYPE_BASIC +end + + + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +common_autoboot.populate_buttons(button) + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function boot_default_basic(cassette_handler) + common_autoboot.type_at_frame(frame_num, "CLOAD\n", 100, BUTTON_PRESS_DURATION) + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 200) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + emu.keypost('RUN\n') + end +end + +local function boot_default_machine(cassette_handler) + common_autoboot.type_at_frame(frame_num, "CLOADM:EXEC\n", 100, BUTTON_PRESS_DURATION) + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 200) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + +end + +local function create_boot_type_1_sequence(title_to_type) -- New name for clarity + return function(cassette_handler_arg) -- This is the function that process_frame will call every frame + common_autoboot.type_at_frame(frame_num, "L\n", 100) + common_autoboot.type_at_frame(frame_num, "\n", 200) + common_autoboot.type_at_frame(frame_num, "SYSTEM\n", 300) + common_autoboot.type_at_frame(frame_num, title_to_type .. "\n", 400) + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 500) + + local cassette_load_done = cassette_handler_arg(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + emu.keypost('/\n') + end + end +end + +local function create_boot_type_2_sequence() -- New name for clarity + return function(cassette_handler_arg) -- This is the function that process_frame will call every frame + common_autoboot.type_at_frame(frame_num, "L\n", 100) + common_autoboot.type_at_frame(frame_num, "\n", 200) + common_autoboot.type_at_frame(frame_num, "CLOAD\n", 300) + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 400) + + local cassette_load_done = cassette_handler_arg(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + emu.keypost('RUN\n') + end + end +end + +local function boot_dtrap(cassette_handler) + common_autoboot.type_at_frame(frame_num, "L\n", 100, BUTTON_PRESS_DURATION) + common_autoboot.type_at_frame(frame_num, "\n", 200, BUTTON_PRESS_DURATION) + common_autoboot.type_at_frame(frame_num, "32640\n", 300, BUTTON_PRESS_DURATION) + common_autoboot.type_at_frame(frame_num, "CLOAD\n", 400, BUTTON_PRESS_DURATION) + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 500) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + emu.keypost('RUN\n') + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(1).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + adv03 = create_boot_type_1_sequence("MISSIO"), + adv10 = create_boot_type_1_sequence("SAVAGE"), + android = create_boot_type_2_sequence(), + baccarat = create_boot_type_2_sequence(), + backgamm = create_boot_type_2_sequence(), + blakjack = create_boot_type_2_sequence(), + chess = create_boot_type_1_sequence("SARGON"), + colliss = create_boot_type_2_sequence(), + cosmic = create_boot_type_1_sequence("COSMIC"), + craps = create_boot_type_2_sequence(), + dddd = create_boot_type_1_sequence("DANDEM"), + defense = create_boot_type_2_sequence("DEFENS"), + dtrap = boot_dtrap, + eliza = create_boot_type_1_sequence("ELIZA"), + env = create_boot_type_1_sequence("ENV"), + escape = create_boot_type_1_sequence("ESCAPE"), + galaxy1 = create_boot_type_1_sequence("GALAXY"), + galaxy2 = create_boot_type_1_sequence("GALAXY"), + headon = create_boot_type_1_sequence("HEADON"), + heliko = create_boot_type_1_sequence("HELIKO"), + hoppy = create_boot_type_1_sequence("HG"), + invaders = create_boot_type_1_sequence("INVADE"), + invasion = create_boot_type_1_sequence("INVADE"), + keno = create_boot_type_2_sequence(), + kinghill = create_boot_type_1_sequence("R"), + meteor2 = create_boot_type_1_sequence("METEOR"), + microply = create_boot_type_2_sequence(), + penetr = create_boot_type_1_sequence("PENETR"), + pinball = create_boot_type_2_sequence(), + pyrmd = create_boot_type_1_sequence("PYRMD"), + qwatson = create_boot_type_2_sequence(), + robot = create_boot_type_1_sequence("ROBOT"), + roulette = create_boot_type_2_sequence(), + scarfman = create_boot_type_1_sequence("SCARFM"), + scripsit = create_boot_type_1_sequence("SCRIPS"), + seadragon = create_boot_type_1_sequence("SEADRA"), + slot = create_boot_type_2_sequence(), + spaceinv = create_boot_type_1_sequence("INVADE"), + spcinv = create_boot_type_1_sequence("SPCINV"), + spcwarp = create_boot_type_1_sequence("SPWAR"), + starfi = create_boot_type_1_sequence("STARFI"), + starsm = create_boot_type_1_sequence("STARSM"), + startrek = create_boot_type_2_sequence(), + starwar = create_boot_type_2_sequence(), + swamp = create_boot_type_1_sequence("SWAMP"), + taipan = create_boot_type_2_sequence(), + trollcru = create_boot_type_2_sequence(), + wheel = create_boot_type_2_sequence(), + zchess = create_boot_type_1_sequence("ZCHESS"), + + ["default_basic"] = boot_default_basic, + ["default_machine"] = boot_default_machine, +} + +-- --- Cassette Loading Handler Setup --- +local cassette_handler = common_autoboot.create_cassette_handler(":cassette") + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + + tape_file_type = detect_tape_type() + end + + -- --- Print current frame number every 100 frames --- + if frame_num % 100 == 0 then -- The modulo operator (%) gives the remainder of a division + emu.print_info("Current Frame: " .. frame_num) + end + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + + if not boot_function then -- If specific function not found + + if tape_file_type == TAPE_TYPE_MACHINE then + boot_function = boot_sequences["default_machine"] -- Assign the default function + elseif tape_file_type == TAPE_TYPE_BASIC then + boot_function = boot_sequences["default_basic"] -- Assign the default function + else + boot_function = boot_sequences["default_basic"] -- Assign the default function + end + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/trs80_flop.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/trs80_flop.lua new file mode 100644 index 00000000000..2aa82a25578 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/trs80_flop.lua @@ -0,0 +1,413 @@ +-- trs80_flop.lua +-- Autoboot for CoCo floppy disks: compute SHA1 of the disk image, +-- look up the "basic" command in coco_sha1_map.json, and type it. + +local SHA1_MAP_PATH = "/usr/share/batocera/configgen/data/mame/autoboot_scripts/coco_sha1_map.json" + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") +local zip_util = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_zip.lua") + +local frame_num = 0 +local boot_command = nil + + +-- ── Path helpers ────────────────────────────────────────────────────────────── + +local function has_os9_name_hint(path) + local lower = path:lower() + return lower:find("%(os%-9%)", 1, false) ~= nil +end + + + +-- ── SHA1 computation ────────────────────────────────────────────────────────── + +local function sha1_of_file(filepath) + local fq = filepath:gsub("'", "'\\''") + local pipe = io.popen(string.format("sha1sum '%s' 2>/dev/null", fq), "r") + if not pipe then return nil end + local line = pipe:read("*l") + pipe:close() + return line and line:match("^(%x+)") +end + +local function sha1_of_bytes(data) + local tmp = "/tmp/coco_sha1_tmp.bin" + local f = io.open(tmp, "wb") + if not f then return nil end + f:write(data) + f:close() + local pipe = io.popen("sha1sum '" .. tmp .. "' 2>/dev/null", "r") + if not pipe then os.remove(tmp); return nil end + local line = pipe:read("*l") + pipe:close() + os.remove(tmp) + return line and line:match("^(%x+)") +end + +local function compute_sha1(mame_filename) + local kind, zippath, entrypath = zip_util.parse_mame_path(mame_filename) + if kind == "zip" then + print(string.format("[CoCo Flop] ZIP: '%s' entry: '%s'", zippath, entrypath)) + local data = zip_util.read_entry_from_zip(zippath, entrypath, nil) + if not data then return nil end + return sha1_of_bytes(data) + else + return sha1_of_file(entrypath) + end +end + + +-- ── JSON lookup ─────────────────────────────────────────────────────────────── + +-- Decode a JSON string value (handles \n \r \t \" \\ escapes). +local function decode_json_string(json_str, start_pos) + local result = {} + local i = start_pos -- points to the char after the opening " + while i <= #json_str do + local c = json_str:sub(i, i) + if c == "\\" then + i = i + 1 + local e = json_str:sub(i, i) + if e == "n" then table.insert(result, "\n") + elseif e == "r" then table.insert(result, "\r") + elseif e == "t" then table.insert(result, "\t") + elseif e == '"' then table.insert(result, '"') + elseif e == "\\" then table.insert(result, "\\") + else table.insert(result, e) + end + elseif c == '"' then + break -- end of JSON string + else + table.insert(result, c) + end + i = i + 1 + end + return table.concat(result) +end + +-- Extract the value of a JSON key from a small JSON object string. +local function json_get_string(block, key) + local search = '"' .. key:gsub("([%(%)%.%%%+%-%*%?%[%^%$])", "%%%1") .. '"' + local kpos = block:find(search, 1, true) + if not kpos then return nil end + -- skip past key, optional whitespace, colon, optional whitespace, opening quote + local qpos = block:find('"', kpos + #search + 1) -- +1 for the colon + if not qpos then return nil end + return decode_json_string(block, qpos + 1) +end + +-- Load coco_sha1_map.json and return the "basic" field for the given sha1, or nil. +local function lookup_sha1(sha1) + local f = io.open(SHA1_MAP_PATH, "r") + if not f then + print("[CoCo Flop] Cannot open SHA1 map: " .. SHA1_MAP_PATH) + return nil + end + local content = f:read("*a") + f:close() + + local key_start = content:find('"' .. sha1 .. '"', 1, true) + if not key_start then + print("[CoCo Flop] SHA1 not in map: " .. sha1) + return nil + end + + -- Extract the balanced {} block for this entry + local brace_start = content:find("{", key_start) + if not brace_start then return nil end + local depth, i = 0, brace_start + while i <= #content do + local c = content:sub(i, i) + if c == "{" then depth = depth + 1 + elseif c == "}" then + depth = depth - 1 + if depth == 0 then + return json_get_string(content:sub(brace_start, i), "basic") + end + end + i = i + 1 + end + return nil +end + + +-- ── Floppy image discovery ──────────────────────────────────────────────────── + +local function find_dsk_in_zip(zippath) + return zip_util.find_zip_entry(zippath, function(n) return n:lower():match("%.dsk$") end) +end + +local function find_floppy_path() + for _, img in pairs(manager.machine.images) do + if img.exists and img.filename and #img.filename > 0 then + local fn = img.filename:lower() + if fn:find("%.dsk") or fn:find("%.dmk") or fn:find("%.vdk") then + print("[CoCo Flop] Floppy image: " .. img.filename) + return img.filename + end + -- Bare .zip: resolve the DSK entry name and return a virtual path + if fn:match("%.zip$") then + local dsk = find_dsk_in_zip(img.filename) + if dsk then + local vpath = img.filename .. "/" .. dsk + print("[CoCo Flop] Floppy image (zip): " .. vpath) + return vpath + end + end + end + end + return nil +end + + +-- ── RSDOS directory parser ──────────────────────────────────────────────────── +-- Standard CoCo JVC disk: 35 tracks, 18 sectors/track, 256 bytes/sector. +-- Directory starts at track 17 (0-based), sector index 2 (sector 3, 1-based). +-- Each 32-byte entry: bytes 0-7 name, 8-10 extension, 11 file type +-- type 0=BASIC tokenized type 1=data type 2=machine code type 3=ASCII BASIC + +local RSDOS_DIR_OFFSET = (17 * 18 + 2) * 256 -- 78848 + +-- Detect OS-9 disk via LSN0 (track 0, sector 1, offset 0) field values. +-- OS-9 stores DD.TKS (sectors/track) at byte 3; CoCo standard = 0x12 (18). +-- DD.TOT (total sectors, 3 bytes big-endian) at bytes 0-2 is > 0 and byte 0 = 0x00. +-- RSDOS disks have 0xFF at byte 0 (blank sector) so this is unambiguous. +-- A dual-format disk may have both OS-9 LSN0 and a valid RSDOS directory; +-- RSDOS is preferred in that case (BASIC boots first on a dual-format disk). +local function is_os9_disk(disk_data) + if #disk_data < 4 then return false end + local b0 = disk_data:byte(1) -- DD.TOT high byte (0x00 for any sane floppy) + local tks = disk_data:byte(4) -- DD.TKS = sectors per track + return b0 == 0x00 and tks == 0x12 +end + +local function parse_rsdos_dir_data(data) + local all_ff = true -- every slot is 0xFF (no directory at all) + local first_cmd = nil -- first runnable entry found + local boot_cmd = nil -- entry named BOOT (takes priority) + + for idx = 0, 71 do + local off = idx * 32 + 1 -- 1-based Lua index + if off + 31 > #data then break end + + local first = data:byte(off) + if first == 0x00 then + all_ff = false + + -- Some real-world images contain 0x00-prefixed garbage/deleted slots + -- before later valid entries. Only treat an all-zero slot as true + -- end-of-directory; otherwise skip and keep scanning. + local all_zero = true + for i = 1, 31 do + if data:byte(off + i) ~= 0x00 then + all_zero = false + break + end + end + if all_zero then + break + end + + print(string.format("[CoCo Flop] Dir[%d]: skipping 0x00-prefixed slot", idx)) + goto continue + end + + if first ~= 0xFF then + all_ff = false + + -- Non-ASCII first byte: garbled entry (OS-9 data, copy-protection, etc.) — skip it. + if first > 0x7E or first < 0x20 then + print(string.format("[CoCo Flop] Dir[%d]: skipping garbled entry (first=0x%02x)", idx, first)) + goto continue + end + + -- Collect all 8 name bytes up to NUL, then rtrim spaces. + -- Mid-name spaces are valid (e.g. "3D GHOST"); only trailing padding stripped. + local name = {} + local garbled = false + for i = 0, 7 do + local c = data:byte(off + i) + if c == 0x00 then break end + if c > 0x7E then garbled = true; break end + table.insert(name, string.char(c)) + end + if garbled then + print(string.format("[CoCo Flop] Dir[%d]: skipping garbled name", idx)) + goto continue + end + local name_str = table.concat(name):match("^(.-)%s*$") + + local ext = {} + local ext_garbled = false + for i = 8, 10 do + local c = data:byte(off + i) + if c == 0x00 then break end + -- Extension must be alphanumeric or space; anything else is OS-9 data + if not ((c >= 0x30 and c <= 0x39) or (c >= 0x41 and c <= 0x5A) + or (c >= 0x61 and c <= 0x7A) or c == 0x20) then + ext_garbled = true; break + end + table.insert(ext, string.char(c)) + end + if ext_garbled then + print(string.format("[CoCo Flop] Dir[%d]: skipping garbled extension", idx)) + goto continue + end + local ext_str = table.concat(ext):match("^(.-)%s*$") + + local file_type = data:byte(off + 11) + + -- Valid RSDOS file types: 0=BASIC tokenized, 1=data, 2=machine code, 3=ASCII BASIC. + -- Any other value means this is not a real RSDOS directory entry. + if file_type > 3 then + print(string.format("[CoCo Flop] Dir[%d]: skipping invalid ftype=%d", idx, file_type)) + goto continue + end + + if #name_str > 0 and file_type ~= 1 then + -- Infocom Z-machine disks store the interpreter as GAME.BIN but boot via DOS + if name_str == "GAME" and ext_str == "BIN" and file_type == 2 then + print("[CoCo Flop] GAME.BIN detected → DOS") + return "DOS\n" + end + + local cmd + if file_type == 0 or file_type == 3 or ext_str == "BAS" then + cmd = 'RUN "' .. name_str .. '"\n' + else + cmd = 'LOADM "' .. name_str .. '":EXEC\n' + end + + print(string.format( + "[CoCo Flop] Dir[%d]: '%s.%s' type=%d cmd=%s", + idx, name_str, ext_str, file_type, cmd:gsub("\n", "\\n"))) + + if name_str == "BOOT" then + boot_cmd = cmd + elseif first_cmd == nil then + first_cmd = cmd + end + end + end + ::continue:: + end + + -- All 72 slots were 0xFF: no RSDOS directory — likely a bootable disk (e.g. Infocom Z-machine) + if all_ff then + print("[CoCo Flop] All-0xFF directory: bootable disk → DOS") + return "DOS\n" + end + + local cmd = boot_cmd or first_cmd + if cmd then + if boot_cmd then + print("[CoCo Flop] Using BOOT entry: " .. cmd:gsub("\n", "\\n")) + end + return cmd + end + + print("[CoCo Flop] No runnable program found in disk directory.") + return nil +end + +local function read_disk_dir_command(mame_filename) + local kind, zippath, entrypath = zip_util.parse_mame_path(mame_filename) + local disk_data, dir_data + + if (kind == "zip" and zippath and has_os9_name_hint(zippath)) or has_os9_name_hint(entrypath) then + print("[CoCo Flop] OS-9 filename hint detected → DOS") + return "DOS\n" + end + + if kind == "zip" then + disk_data = zip_util.read_entry_from_zip(zippath, entrypath, nil) + if disk_data and #disk_data > RSDOS_DIR_OFFSET then + dir_data = disk_data:sub(RSDOS_DIR_OFFSET + 1, RSDOS_DIR_OFFSET + 72 * 32) + end + else + local f = io.open(entrypath, "rb") + if not f then + print("[CoCo Flop] Cannot open disk: " .. entrypath) + return nil + end + disk_data = f:read("*a") + f:close() + if disk_data and #disk_data > RSDOS_DIR_OFFSET then + dir_data = disk_data:sub(RSDOS_DIR_OFFSET + 1, RSDOS_DIR_OFFSET + 72 * 32) + end + end + + if not dir_data or #dir_data == 0 then + print("[CoCo Flop] Could not read directory sector from disk.") + return nil + end + + local cmd = parse_rsdos_dir_data(dir_data) + if cmd then return cmd end + + -- No valid RSDOS directory found — check OS-9 sector at LSN0 + if disk_data and is_os9_disk(disk_data) then + print("[CoCo Flop] OS-9 disk signature detected → DOS") + return "DOS\n" + end + + return nil +end + + +-- ── Boot command detection ──────────────────────────────────────────────────── + +local function detect_boot_command() + print("[CoCo Flop] --- Boot detection ---") + + local path = find_floppy_path() + if not path then + print("[CoCo Flop] No floppy image found.") + return nil + end + print("[CoCo Flop] Path: " .. path) + + local sha1 = compute_sha1(path) + if sha1 then + print("[CoCo Flop] SHA1: " .. sha1) + local cmd = lookup_sha1(sha1) + if cmd then + print("[CoCo Flop] SHA1 match: " .. cmd:gsub("\n", "\\n"):gsub("\r", "\\r")) + return cmd + end + print("[CoCo Flop] Not in SHA1 map — parsing disk directory.") + else + print("[CoCo Flop] Could not compute SHA1 — parsing disk directory.") + end + + return read_disk_dir_command(path) +end + + +-- ── Main frame callback ─────────────────────────────────────────────────────── + +local function process_frame() + frame_num = frame_num + 1 + + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + boot_command = detect_boot_command() + if boot_command then + emu.print_info("[CoCo Flop] Autoboot: " .. boot_command:gsub("\n", "\\n")) + else + emu.print_info("[CoCo Flop] No autoboot.") + end + end + + if frame_num % 100 == 0 then + emu.print_info("Current Frame: " .. frame_num) + end + + if boot_command then + common_autoboot.type_at_frame(frame_num, boot_command, 150) + end +end + +subscription = emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/tvc_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/tvc_cass.lua new file mode 100644 index 00000000000..76b51990b29 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/tvc_cass.lua @@ -0,0 +1,78 @@ +-- tvc_cass.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +-- --- Cassette Loading Handler Setup --- +local CASSETTE_SLOT = 3 +local CASSETTE_DEVICE_TAG = manager.machine.images:at(CASSETTE_SLOT).device.tag +local cassette_handler = common_autoboot.create_cassette_handler(CASSETTE_DEVICE_TAG) + +common_autoboot.populate_buttons(button) + +common_autoboot.print_image_info() + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function boot_default(cassette_handler) + common_autoboot.type_at_frame(frame_num, "\n", 300) + common_autoboot.type_at_frame(frame_num, "LOAD\n", 400) + common_autoboot.play_cassette_at_frame(frame_num, CASSETTE_DEVICE_TAG, 500) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + -- emu.keypost('RUN\n') + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(CASSETTE_SLOT).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + ['default'] = boot_default, +} + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + --- DEBUG: Print current frame number every 100 frames --- + common_autoboot.debug_frame_num(frame_num) + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/tvc_flop.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/tvc_flop.lua new file mode 100644 index 00000000000..e6696e9f2f9 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/tvc_flop.lua @@ -0,0 +1,71 @@ +-- tvc_flop.lua +-- +-- TVC floppy autoboot (HBF expansion). +-- +-- From MAME softlist notes: +-- Most titles can be run in BASIC with LOAD"*" +-- If the program does not start automatically, follow with RUN +-- +-- Boot sequence: +-- 1. Clear any initial prompt / splash (Enter at frame 300) +-- 2. Type LOAD"*" to load the first program from the floppy +-- 3. Wait a fixed delay for the disk to finish loading +-- 4. Type RUN to start the program + +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +local button = {} +local frame_num = 0 + +common_autoboot.populate_buttons(button) +common_autoboot.print_image_info() + +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION + +-- With the HBF expansion active the image order is: +-- 1: printout 2: cartridge 3: floppydisk1 4: floppydisk2 5: cassette 6: quickload +local FLOP_SLOT = 3 + +-- Frames to wait after issuing LOAD"*" before sending RUN. +-- TVC floppy loads at ~300 RPM; a typical game takes up to ~20 s. +-- 1200 frames @ 50 fps = 24 s, which covers the vast majority of titles. +local FLOPPY_LOAD_DELAY_FRAMES = 1200 + +local LOAD_START_FRAME = 400 +local RUN_FRAME = LOAD_START_FRAME + FLOPPY_LOAD_DELAY_FRAMES + +local current_software_name = manager.machine.images:at(FLOP_SLOT).filename + +local function boot_default() + common_autoboot.type_at_frame(frame_num, "\n", 300, BUTTON_PRESS_DURATION) + common_autoboot.type_at_frame(frame_num, 'LOAD"*"\n', LOAD_START_FRAME, BUTTON_PRESS_DURATION) + common_autoboot.type_at_frame(frame_num, "RUN\n", RUN_FRAME, BUTTON_PRESS_DURATION) +end + +local boot_sequences = { + ['default'] = boot_default, +} + +local function process_frame() + frame_num = frame_num + 1 + + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name: " .. current_software_name) + + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game-specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + common_autoboot.debug_frame_num(frame_num) + + local boot_function = boot_sequences[current_software_name] or boot_sequences["default"] + if boot_function then + boot_function() + end +end + +subscription = emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/vector06_flop.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/vector06_flop.lua new file mode 100644 index 00000000000..9cb2af7f6b5 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/vector06_flop.lua @@ -0,0 +1,101 @@ +-- vector06_flop.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +-- Populate the 'button' table using the common function +common_autoboot.populate_buttons(button) + +-- Print the button table contents for debugging +common_autoboot.print_buttons(button) + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION + +-- --- Game-Specific Boot Sequence Functions --- + +-- Boot sequence for "komrab" software +local function boot_komrab() + common_autoboot.press_and_release(button, frame_num, "AP2", 100, BUTTON_PRESS_DURATION) + common_autoboot.type_at_frame(frame_num, "KOMRAB\n\n", 300) +end + +-- Boot sequence for "cdpacman" software +local function boot_cdpacman() + common_autoboot.press_and_release(button, frame_num, "AP2", 100, BUTTON_PRESS_DURATION) + common_autoboot.press_and_release(button, frame_num, "Rus/Lat", 300, BUTTON_PRESS_DURATION) + common_autoboot.press_and_release(button, frame_num, "2 \"", 600, BUTTON_PRESS_DURATION) +end + +-- Boot sequence for "card" software +local function boot_card() + common_autoboot.press_and_release(button, frame_num, "AP2", 100, BUTTON_PRESS_DURATION) + common_autoboot.press_and_release(button, frame_num, "Space", 300, BUTTON_PRESS_DURATION) + common_autoboot.press_and_release(button, frame_num, "Enter", 600, BUTTON_PRESS_DURATION) +end + +local function boot_gt() + common_autoboot.press_and_release(button, frame_num, "AP2", 100, BUTTON_PRESS_DURATION) + common_autoboot.type_at_frame(frame_num, "GT\n", 800, BUTTON_PRESS_DURATION) + common_autoboot.type_at_frame(frame_num, "Y\n", 1400, BUTTON_PRESS_DURATION) +end + +-- Default boot sequence for software that do not have specific boot sequences +local function boot_default() + common_autoboot.press_and_release(button, frame_num, "AP2", 100, BUTTON_PRESS_DURATION) +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(2).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + komrab = boot_komrab, + cdpacman = boot_cdpacman, + card = boot_card, + gt = boot_gt, + ["default"] = boot_default +} + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + -- --- Print current frame number every 100 frames --- + if frame_num % 100 == 0 then -- The modulo operator (%) gives the remainder of a division + emu.print_info("Current Frame: " .. frame_num) + end + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function() + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/vg5k.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/vg5k.lua new file mode 100644 index 00000000000..ccd3358628b --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/vg5k.lua @@ -0,0 +1,72 @@ +-- vg5k.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +common_autoboot.populate_buttons(button) + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(1).filename + +-- Map software names to their respective boot functions +local boot_sequences = { +} + +-- --- Cassette Loading Handler Setup --- +local cassette_handler = common_autoboot.create_cassette_handler(":cassette") + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + common_autoboot.type_at_frame(frame_num, "CLOAD\n", 100, BUTTON_PRESS_DURATION) + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 200) + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + emu.keypost('RUN\n') + end + + -- --- Print current frame number every 100 frames --- + if frame_num % 100 == 0 then -- The modulo operator (%) gives the remainder of a division + emu.print_info("Current Frame: " .. frame_num) + end + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function() + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/vtech2_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/vtech2_cass.lua new file mode 100644 index 00000000000..52479893286 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/vtech2_cass.lua @@ -0,0 +1,79 @@ +-- vtech2_cass.lua + +-- Load common autoboot functions +local common_autoboot = dofile("/usr/share/batocera/configgen/data/mame/autoboot_scripts/autoboot_common.lua") + +-- Script-wide variables +local button = {} +local frame_num = 0 + +common_autoboot.populate_buttons(button) + +-- Print the button table contents for debugging +-- common_autoboot.print_buttons(button) + +-- --- Constants for this specific script --- +local BUTTON_PRESS_DURATION = common_autoboot.DEFAULT_BUTTON_PRESS_DURATION +local CASSETTE_MOTOR_OFF_DELAY_FRAMES = common_autoboot.DEFAULT_CASSETTE_MOTOR_OFF_DELAY_FRAMES + +local function boot_default(cassette_handler) + common_autoboot.type_at_frame(frame_num, "CLOAD\n", 100, BUTTON_PRESS_DURATION) + + common_autoboot.play_cassette_at_frame(frame_num, ":cassette", 400) -- need to wait at least 300 frames after CLOAD cmd, otherwise will have LOADING ERROR! + + local cassette_load_done = cassette_handler(frame_num, CASSETTE_MOTOR_OFF_DELAY_FRAMES) + + if cassette_load_done then + emu.keypost('RUN\n') + end +end + +-- --- Main Script Logic --- + +-- Determine the currently loaded software name +local current_software_name = manager.machine.images:at(1).filename + +-- Map software names to their respective boot functions +local boot_sequences = { + ["default"] = boot_default, +} + +-- --- Cassette Loading Handler Setup --- +local cassette_handler = common_autoboot.create_cassette_handler(":cassette") + +-- MAME machine frame notification callback +local function process_frame() + frame_num = frame_num + 1 + + -- Initial setup/info display at frame 1 + if frame_num == 1 then + emu.print_info("System Driver: " .. emu.romname()) + emu.print_info("Loaded Software Name (from image filename): " .. current_software_name) + + -- Determine which profile will be used + if boot_sequences[current_software_name] then + emu.print_info("--- Booting using game specific profile: " .. current_software_name .. " ---") + else + emu.print_info("--- Booting using default profile ---") + end + end + + -- --- Print current frame number every 100 frames --- + if frame_num % 100 == 0 then -- The modulo operator (%) gives the remainder of a division + emu.print_info("Current Frame: " .. frame_num) + end + + -- Execute the relevant boot sequence based on the loaded software + local boot_function = boot_sequences[current_software_name] + + if not boot_function then -- If specific function not found + boot_function = boot_sequences["default"] -- Assign the default function + end + + if boot_function then + boot_function(cassette_handler) + end +end + +-- Subscribe to machine frame notifications +subscription = emu.add_machine_frame_notifier(process_frame) \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/zx81_cass.lua b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/zx81_cass.lua new file mode 100644 index 00000000000..7a1e0442b1f --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/autoboot_scripts/zx81_cass.lua @@ -0,0 +1,48 @@ +button = {} + +for i, j in pairs(manager.machine.ioport.ports) do + for field_name, field in pairs(j.fields) do + id = field.port.tag .. ',' .. field.mask .. ',' .. field.type + print(field_name,": ", id) + button[id] = field + end +end + +local frame_num = 0 +local function process_frame() + frame_num = frame_num + 1 + + if frame_num == 200 then + button[":ROW6,8,49"]:set_value(1) -- J + elseif frame_num == 205 then + button[":ROW6,8,49"]:set_value(0) -- J + elseif frame_num == 215 then + button[":ROW0,1,49"]:set_value(1) -- shift + button[":ROW5,1,49"]:set_value(1) -- P + elseif frame_num == 220 then + button[":ROW0,1,49"]:set_value(0) -- shift + button[":ROW5,1,49"]:set_value(0) -- P + elseif frame_num == 230 then + button[":ROW0,1,49"]:set_value(1) -- shift + button[":ROW5,1,49"]:set_value(1) -- P + elseif frame_num == 235 then + button[":ROW0,1,49"]:set_value(0) -- shift + button[":ROW5,1,49"]:set_value(0) -- P + elseif frame_num == 245 then + button[":ROW6,1,49"]:set_value(1) -- enter + elseif frame_num == 250 then + button[":ROW6,1,49"]:set_value(0) -- enter + elseif frame_num == 300 then + manager.machine.cassettes[":cassette"]:play() + end + + if manager.machine.cassettes[":cassette"].is_stopped == false and manager.machine.cassettes[":cassette"].motor_state == true then + manager.machine.video.throttled = false + manager.machine.video.frameskip = 12 + else + manager.machine.video.throttled = true + manager.machine.video.frameskip = 0 + end +end + +subscription=emu.add_machine_frame_notifier(process_frame) diff --git a/package/batocera/core/batocera-configgen/data/mame/camplynx_cass_autoload.csv b/package/batocera/core/batocera-configgen/data/mame/camplynx_cass_autoload.csv deleted file mode 100644 index 68c916bb9e0..00000000000 --- a/package/batocera/core/batocera-configgen/data/mame/camplynx_cass_autoload.csv +++ /dev/null @@ -1,66 +0,0 @@ -3dmoncrz;MLOAD "3D MONSTER" -backgmmn;LOAD "BACKGAMMON" -battlbrk;LOAD "BATTLEBRICK" -centiped;MLOAD "CENTIPEDE" -colossal;LOAD "COLOSSAL" -dambustr;LOAD "DAM BUSTER" -deathball;LOAD "DEATHBALL" -diggerman;MLOAD "DIGGERMAN" -dungeon;LOAD "DUNGEON" -floydbank;MLOAD "FLOYDS BANK" -gamepak4;MLOAD "GEMPACK 4" -gobblspk;MLOAD "SPOOK" -hangman;LOAD "HANGMAN" -labyrinth;LOAD "LABYRINTHE" -logichess;MLOAD "ECHECS" -invaders;MLOAD "INVADERS" -mastermnd;LOAD "MASTERMIND" -mazeman;MLOAD "MAZEMAN" -minedout;LOAD "MINEDOUTGOOD" -moonfallf;LOAD "Moonfall2" -moonfall;LOAD "MOONFALL" -muncher;LOAD "MUNCHER" -nuclear;LOAD "NUCLEAR" -numerons;LOAD "NUMERONS" -asterix;LOAD "ASTERIX" -ohmummy;MLOAD "OH MUMMY" -panik;LOAD "PANIK" -pengo;MLOAD "PENGO" -pwrblastr;MLOAD "POWER BLASTER" -racer;LOAD "RACER" -rocketman;LOAD "ROCKETMAN" -spellbnd;LOAD "SPELLBOUND" -scrablynx;LOAD "SCRABLYNX" -siege;MLOAD "SIEGE ATTACK" -spactrek;LOAD "TREK" -sairraid;LOAD "SUPER AIR RAID" -treasisld;LOAD "TREASURE" -twinkle;MLOAD "TWINKLE" -worm;LOAD "THE WORM" -wormf;LOAD "THE WORM" -ynxvader;MLOAD "YNXVADERS" -zombie;LOAD "ZombiePanic" -aide;LOAD "AIDE" -cardindx;LOAD "CARD INDEX" -composer;LOAD "COMPOSER" -disassmbf;LOAD "DES.IMP" -disassmb;LOAD "DESASS" -genbasic;LOAD "GENEBASIC" -gencarac;LOAD "GENECAR" -wordproc;MLOAD "LIONTEXT" -moder80;MLOAD "CODE" -musicmstr;LOAD "MUSIC MASTER" -6845p;LOAD "6845P" -chopin;LOAD "CHOPIN" -cinema;LOAD "CINEMA" -forest;LOAD "THE FOREST" -gridtrap;LOAD "GRIDTRAP" -hilo;LOAD "CARDS" -inteltab;LOAD "INTELTABLYNX" -maximots;LOAD "MAXI-MOTS" -planets;LOAD "PLANETS" -risingmn;LOAD "CP FP" -scrndmp;LOAD "RPENROSE" -starover;LOAD "SR" -triangle;LOAD "BRUMBELOW" -tronblkr;LOAD "TRON BLOCKER" \ No newline at end of file diff --git a/package/batocera/core/batocera-configgen/data/mame/coco_archive_fetch.py b/package/batocera/core/batocera-configgen/data/mame/coco_archive_fetch.py new file mode 100644 index 00000000000..9d1f5866ac0 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/coco_archive_fetch.py @@ -0,0 +1,223 @@ +#!/usr/bin/env python3 +""" +Fetch xroar_config from colorcomputerarchive.com pages, download each zip, +compute SHA1 of the disk0 file inside, and produce a JSON indexed by SHA1. +""" + +import argparse +import hashlib +import io +import json +import re +import sys +import urllib.parse +import urllib.request +import zipfile +from concurrent.futures import ThreadPoolExecutor, as_completed +from pathlib import Path + +URLS = [ + "https://colorcomputerarchive.com/repo/Disks/Games/", + "https://colorcomputerarchive.com/repo/Disks/Games/French/", + "https://colorcomputerarchive.com/repo/Disks/Games/French/Alice%20Software/", + "https://colorcomputerarchive.com/repo/Disks/Games/Infocom%20Adventures/", + "https://colorcomputerarchive.com/repo/Disks/Games/Infocom%20Adventures/64%20column%20(Coco%203)/", + "https://colorcomputerarchive.com/repo/Disks/Games/Inufuto/", + "https://colorcomputerarchive.com/repo/Disks/Games/Portuguese/", + "https://colorcomputerarchive.com/repo/Disks/Games/Scott%20Adams%20Adventures/", + "https://colorcomputerarchive.com/repo/Disks/Games/Sierra%20Games/" + # "https://colorcomputerarchive.com/repo/Disks/Applications/", +] + +OUTPUT = Path("coco_sha1_map.json") +CACHE_DIR = Path("coco_zip_cache") + +WORKERS = 8 # parallel downloads + + +def fetch_text(url: str) -> str: + req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"}) + with urllib.request.urlopen(req, timeout=30) as resp: + return resp.read().decode("utf-8", errors="replace") + + +def download_zip(url: str, dest: Path) -> None: + req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"}) + with urllib.request.urlopen(req, timeout=60) as resp: + dest.write_bytes(resp.read()) + + +def sha1_of_bytes(data: bytes) -> str: + return hashlib.sha1(data).hexdigest() + + +def extract_xroar_config(html: str) -> list[dict]: + match = re.search(r"xroar_config\s*=\s*(\{)", html) + if not match: + raise ValueError("xroar_config not found in page") + data, _ = json.JSONDecoder().raw_decode(html, match.start(1)) + files = data.get("files", []) + if not isinstance(files, list): + raise ValueError(f"xroar_config.files is not a list: {type(files)}") + return files + + +def decode_basic(value: str) -> str: + return value.replace("%5Cr", "\n").replace("%5cr", "\n").replace("%22", '"') + + +def process_entry(base_url: str, entry: dict) -> list[tuple[str, dict]]: + """Download zip, compute SHA1 for every DSK inside, return list of (sha1, entry).""" + zip_filename = entry.get("filename") + if not zip_filename or not entry.get("disk0"): + return [] + + zip_url = base_url + urllib.parse.quote(zip_filename) + zip_path = CACHE_DIR / zip_filename + + # Download (use cache if already present) + if not zip_path.exists(): + try: + download_zip(zip_url, zip_path) + except Exception as exc: + print(f" DOWNLOAD ERROR {zip_filename}: {exc}", file=sys.stderr) + return [] + + # Build decoded entry once (basic field URL-decoding) + base_entry = {**entry} + if "basic" in base_entry: + base_entry["basic"] = decode_basic(base_entry["basic"]) + + # Hash every DSK file found in the zip + results: list[tuple[str, dict]] = [] + try: + with zipfile.ZipFile(zip_path, "r") as zf: + dsk_names = [n for n in zf.namelist() + if Path(n).suffix.lower() == ".dsk" and not n.endswith("/")] + if not dsk_names: + print(f" NO DSK in zip {zip_filename}", file=sys.stderr) + return [] + for name in dsk_names: + try: + data = zf.read(name) + sha1 = sha1_of_bytes(data) + results.append((sha1, base_entry)) + except Exception as exc: + print(f" READ ERROR {zip_filename}/{name}: {exc}", file=sys.stderr) + except Exception as exc: + print(f" ZIP ERROR {zip_filename}: {exc}", file=sys.stderr) + return [] + + return results + + +def flatten_zip(zip_path: Path) -> bool: + """Rewrite zip so all DSK files are at root (no subdirectory prefix). + Returns True if the zip was modified, False if already flat or no DSKs found.""" + try: + with zipfile.ZipFile(zip_path, "r") as zf: + names = zf.namelist() + dsk_names = [n for n in names + if Path(n).suffix.lower() == ".dsk" and not n.endswith("/")] + if not dsk_names: + return False + # Check if any DSK is nested, has directory entries, or is not deflated + nested = [n for n in dsk_names if "/" in n] + has_dir_entries = any(n.endswith("/") for n in names) + not_deflated = any(i.compress_type != zipfile.ZIP_DEFLATED + for i in zf.infolist() if not i.filename.endswith("/")) + if not nested and not has_dir_entries and not not_deflated: + return False # already flat, clean, and compressed + + # Build new zip in memory: keep non-DSK entries as-is, + # write DSK entries at root (basename only) + buf = io.BytesIO() + with zipfile.ZipFile(buf, "w", compression=zipfile.ZIP_DEFLATED, compresslevel=9) as out: + for info in zf.infolist(): + if info.filename.endswith("/"): + continue # skip directory entries + data = zf.read(info.filename) + if Path(info.filename).suffix.lower() == ".dsk": + flat_name = Path(info.filename).name + out.writestr(flat_name, data) + else: + out.writestr(info, data) + + zip_path.write_bytes(buf.getvalue()) + return True + except Exception as exc: + print(f" FLATTEN ERROR {zip_path.name}: {exc}", file=sys.stderr) + return False + + +def flatten_dir(target_dir: Path) -> None: + """Flatten all zips in target_dir that have DSK files in subdirectories.""" + zips = sorted(target_dir.glob("*.zip")) + print(f"Scanning {len(zips)} zip files in {target_dir} …", file=sys.stderr) + modified = 0 + for zip_path in zips: + if flatten_zip(zip_path): + modified += 1 + print(f" Flattened: {zip_path.name}", file=sys.stderr) + print(f"\nDone. {modified}/{len(zips)} zips flattened.", file=sys.stderr) + + +def main(): + parser = argparse.ArgumentParser(description="Fetch CoCo disk archive and build SHA1 map.") + parser.add_argument("--flatten", metavar="DIR", nargs="?", const=str(CACHE_DIR), + help="Flatten DSK files to zip root in DIR (default: cache dir). " + "Does not fetch or hash — just rewrites zips.") + args = parser.parse_args() + + if args.flatten is not None: + flatten_dir(Path(args.flatten)) + return + + CACHE_DIR.mkdir(exist_ok=True) + + # Collect all entries from all URLs + all_entries: list[tuple[str, dict]] = [] # (base_url, entry) + for url in URLS: + print(f"Fetching {url} …", file=sys.stderr) + try: + html = fetch_text(url) + files = extract_xroar_config(html) + except Exception as exc: + print(f" ERROR: {exc}", file=sys.stderr) + continue + print(f" {len(files)} entries", file=sys.stderr) + for entry in files: + if entry.get("disk0"): + all_entries.append((url, entry)) + else: + print(f" SKIP (no disk0): {entry.get('filename', '?')}", file=sys.stderr) + + print(f"\nDownloading & hashing {len(all_entries)} zips with {WORKERS} workers …", file=sys.stderr) + + result: dict[str, dict] = {} + conflicts = 0 + done = 0 + + with ThreadPoolExecutor(max_workers=WORKERS) as pool: + futures = {pool.submit(process_entry, base_url, entry): entry + for base_url, entry in all_entries} + for future in as_completed(futures): + done += 1 + if done % 100 == 0 or done == len(all_entries): + print(f" {done}/{len(all_entries)}", file=sys.stderr) + for sha1, entry in future.result(): + if sha1 in result: + conflicts += 1 + print( + f" SHA1 CONFLICT {sha1}: {result[sha1]['filename']!r} vs {entry['filename']!r}", + file=sys.stderr, + ) + else: + result[sha1] = entry + + print(f"\n{len(result)} SHA1 entries ({conflicts} conflict(s)) written to {OUTPUT}", file=sys.stderr) + OUTPUT.write_text(json.dumps(result, indent=2, ensure_ascii=False)) + + +if __name__ == "__main__": + main() diff --git a/package/batocera/core/batocera-configgen/data/mame/messSoftlistMap.json b/package/batocera/core/batocera-configgen/data/mame/messSoftlistMap.json new file mode 100644 index 00000000000..c10de4db5a6 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/messSoftlistMap.json @@ -0,0 +1,3613 @@ +{ + "_comment": "Maps MAME softlist names to machine/media/autoboot configuration. lua_script paths are relative to the autoboot_script/ subdirectory shipped with this data.", + "32x": { + "machine": "32x", + "media": "cart" + }, + "3do": { + "machine": "3do_fz10", + "media": "cdrom" + }, + "3do_m2": { + "machine": "3do_fz10", + "media": "cdrom" + }, + "a2600": { + "machine": "a2600", + "media": "cart" + }, + "a2600_cass": { + "machine": "a2600", + "media": "cassa" + }, + "a5200": { + "machine": "a5200", + "media": "cart" + }, + "a7800": { + "machine": "a7800", + "media": "cart" + }, + "a800": { + "machine": "a800xl", + "config_args": [ + { + "key": "ramsize", + "type": "int", + "skip_if": 0, + "args": [ + "-ramsize", + "{value}M" + ] + } + ], + "media": "cart" + }, + "a800_cass": { + "machine": "a800xl", + "config_args": [ + { + "key": "ramsize", + "type": "int", + "skip_if": 0, + "args": [ + "-ramsize", + "{value}M" + ] + } + ], + "media": "cass1" + }, + "a800_flop": { + "machine": "a800xl", + "lua_script": "a800_flop.lua", + "config_args": [ + { + "key": "ramsize", + "type": "int", + "skip_if": 0, + "args": [ + "-ramsize", + "{value}M" + ] + } + ], + "media": "flop1" + }, + "abc1600_flop": { + "machine": "abc1600", + "media": "flop1" + }, + "abc1600_hdd": { + "machine": "abc1600", + "media": "hdd" + }, + "abc800_hdd": { + "machine": "abc800c", + "media": "hdd" + }, + "abc806_flop": { + "machine": "abc806", + "media": "flop" + }, + "abc80_cass": { + "machine": "abc80", + "media": "cass1" + }, + "abc80_flop": { + "machine": "abc80", + "media": "flop1" + }, + "abc80_rom": { + "machine": "abc80", + "media": "rom" + }, + "abc830_flop": { + "machine": "abc800c", + "media": "flop" + }, + "abc832_flop": { + "machine": "abc800c", + "media": "flop" + }, + "abc838_flop": { + "machine": "abc800c", + "media": "flop" + }, + "acrnsys_flop": { + "machine": "acrnsys3", + "media": "flop1" + }, + "acrnsys_rom": { + "machine": "acrnsys3", + "media": "rom1" + }, + "adam_cart": { + "machine": "adam", + "extra_args": [ + "-skip_gameinfo" + ], + "media": "cart" + }, + "adam_cass": { + "machine": "adam", + "extra_args": [ + "-skip_gameinfo" + ], + "media": "cass1" + }, + "adam_flop": { + "machine": "adam", + "lua_script": "adam_flop.lua", + "extra_args": [ + "-skip_gameinfo" + ], + "media": "flop1" + }, + "advantage": { + "machine": "no_machine_found", + "media": "flop1" + }, + "advision": { + "machine": "advision", + "media": "cart" + }, + "aim65_cart": { + "machine": "aim65", + "media": "z24" + }, + "aleste": { + "machine": "al520ex", + "media": "flop1" + }, + "alice32": { + "machine": "alice90", + "lua_script": "alice90.lua", + "extra_args": [ + "-skip_gameinfo" + ], + "media": "cass1" + }, + "alice90": { + "machine": "alice90", + "lua_script": "alice90.lua", + "extra_args": [ + "-skip_gameinfo" + ], + "media": "cass" + }, + "alphasmart_kapps": { + "machine": "asma3k", + "media": "kapp" + }, + "alphatro_cart": { + "machine": "alphatro", + "media": "cart" + }, + "alphatro_flop": { + "machine": "alphatro", + "media": "flop1" + }, + "altos5": { + "machine": "altos5", + "media": "flop1" + }, + "altos586": { + "machine": "altos586", + "media": "flop1" + }, + "altos8600": { + "machine": "altos8600", + "media": "flop1" + }, + "amiga_amix": { + "machine": "a3000", + "media": "flop1" + }, + "amiga_apps": { + "machine": "a1200", + "media": "flop1" + }, + "amiga_cd": { + "machine": "cd32", + "media": "cdrom" + }, + "amiga_demos": { + "machine": "a1200", + "media": "flop1" + }, + "amiga_flop": { + "machine": "a1200", + "media": "flop1" + }, + "amiga_hardware": { + "machine": "a1200", + "media": "flop1" + }, + "amiga_hdd": { + "machine": "a1200", + "media": "hdd" + }, + "amiga_workbench": { + "machine": "a1200", + "media": "kickstart" + }, + "amigaaga_flop": { + "machine": "a1200", + "media": "flop1" + }, + "amigaecs_flop": { + "machine": "a1200", + "media": "flop1" + }, + "amigaocs_flop": { + "machine": "a1200", + "media": "flop1" + }, + "ampro": { + "machine": "ampro", + "media": "flop1" + }, + "apc": { + "machine": "apc", + "media": "flop1" + }, + "apexc_cyl": { + "machine": "apexc", + "media": "cyl" + }, + "apfimag_cass": { + "machine": "apfimag", + "media": "cass" + }, + "apfm1000": { + "machine": "apfm1000", + "media": "cart" + }, + "apogee": { + "machine": "apogee", + "lua_script": "apogee.lua", + "media": "cass" + }, + "apollo_ctape": { + "machine": "dn3500", + "media": "cass1" + }, + "apple1": { + "machine": "apple1", + "media": "cass" + }, + "apple2_cass": { + "machine": "apple2p", + "config_args": [ + { + "key": "ramsize", + "type": "int", + "skip_if": 0, + "args": [ + "-ramsize", + "{value}M" + ] + }, + { + "key": "gameio", + "type": "str", + "default": "none", + "skip_if": "none", + "args": [ + "-gameio", + "{value}" + ], + "value_machine_restriction": { + "joyport": [ + "apple2p" + ] + } + } + ], + "media": "cass" + }, + "apple2_flop_clcracked": { + "machine": "apple2", + "media": "flop1" + }, + "apple2_flop_misc": { + "machine": "apple2ee", + "config_args": [ + { + "key": "ramsize", + "type": "int", + "skip_if": 0, + "args": [ + "-ramsize", + "{value}M" + ] + }, + { + "key": "gameio", + "type": "str", + "default": "none", + "skip_if": "none", + "args": [ + "-gameio", + "{value}" + ], + "value_machine_restriction": { + "joyport": [ + "apple2p" + ] + } + } + ], + "rom_ext_args": [ + { + "extensions": [ + ".hdv", + ".2mg", + ".chd", + ".iso", + ".bin", + ".cue" + ], + "args": [ + "-sl7", + "cffa202" + ] + } + ], + "media": "flop1" + }, + "apple2_flop_orig": { + "machine": "apple2", + "media": "flop1" + }, + "apple2gs_flop_clcracked": { + "machine": "apple2gsr3p", + "media": "flop1" + }, + "apple2gs_flop_misc": { + "machine": "apple2gsr3p", + "config_args": [ + { + "key": "ramsize", + "type": "int", + "skip_if": 0, + "args": [ + "-ramsize", + "{value}M" + ] + }, + { + "key": "gameio", + "type": "str", + "default": "none", + "skip_if": "none", + "args": [ + "-gameio", + "{value}" + ], + "value_machine_restriction": { + "joyport": [ + "apple2p" + ] + } + } + ], + "media": "flop1" + }, + "apple2gs_flop_orig": { + "machine": "apple2gsr3p", + "config_args": [ + { + "key": "ramsize", + "type": "int", + "skip_if": 0, + "args": [ + "-ramsize", + "{value}M" + ] + }, + { + "key": "gameio", + "type": "str", + "default": "none", + "skip_if": "none", + "args": [ + "-gameio", + "{value}" + ], + "value_machine_restriction": { + "joyport": [ + "apple2p" + ] + } + } + ], + "media": "flop1" + }, + "apple3": { + "machine": "apple3", + "media": "flop1" + }, + "applix_flop": { + "machine": "applix", + "media": "flop1" + }, + "apricot_flop": { + "machine": "apricot", + "media": "flop1" + }, + "apxen_flop": { + "machine": "apxen", + "media": "flop1" + }, + "aquarius_cart": { + "machine": "aquarius", + "media": "cart1" + }, + "aquarius_cass": { + "machine": "aquarius", + "media": "cass1", + "lua_script": "aquarius_cass.lua" + }, + "arb": { + "machine": "arb", + "media": "cart" + }, + "arcadia": { + "machine": "arcadia", + "media": "cart" + }, + "archimedes": { + "machine": "aa4401", + "config_args": [ + { + "key": "ramsize", + "type": "int", + "skip_if": 0, + "args": [ + "-ramsize", + "{value}M" + ] + } + ], + "media": "flop" + }, + "archimedes_hdd": { + "machine": "aa310", + "media": "hdd" + }, + "archimedes_rom": { + "machine": "aa310", + "media": "rom" + }, + "astrocde": { + "machine": "astrocde", + "media": "cart" + }, + "atom_cass": { + "machine": "atom", + "media": "cass1" + }, + "atom_flop": { + "machine": "atom", + "media": "flop1", + "lua_script": "atom_flop.lua" + }, + "atom_rom": { + "machine": "atom", + "media": "cart" + }, + "attache": { + "machine": "attache", + "media": "flop1" + }, + "aussiebyte": { + "machine": "aussieby", + "media": "flop1" + }, + "b2m": { + "machine": "b2m", + "media": "disk" + }, + "basf7100": { + "machine": "basf7120", + "media": "flop1" + }, + "bbc_cass": { + "machine": "bbcb", + "lua_script": "bbc_cass.lua", + "config_args": [ + { + "key": "sticktype", + "type": "str", + "default": "none", + "skip_if": "none", + "args": [ + "-analogue", + "{value}" + ] + } + ], + "extra_args": [ + "-skip_gameinfo" + ], + "media": "cass" + }, + "bbc_flop_32016": { + "machine": "acw443", + "media": "flop1" + }, + "bbc_flop_6502": { + "machine": "bbcmt", + "media": "flop1" + }, + "bbc_flop_68000": { + "machine": "no_machine_found", + "media": "flop1" + }, + "bbc_flop_80186": { + "machine": "bbcm512", + "media": "flop1" + }, + "bbc_flop_arm": { + "machine": "bbcmarm", + "media": "flop1", + "extra_args": [ + "-tube", + "arm " + ] + }, + "bbc_flop_hybrid": { + "machine": "no_machine_found", + "media": "flop1" + }, + "bbc_flop_torch": { + "machine": "torch725", + "media": "flop1" + }, + "bbc_flop_z80": { + "machine": "abc110", + "media": "flop1" + }, + "bbc_hdd": { + "machine": "bbcb", + "media": "hdd" + }, + "bbc_rom": { + "machine": "bbcb", + "config_args": [ + { + "key": "sticktype", + "type": "str", + "default": "none", + "skip_if": "none", + "args": [ + "-analogue", + "{value}" + ] + } + ], + "media": "rom1" + }, + "bbc_vsm": { + "machine": "bbcb", + "media": "rom" + }, + "bbcb_flop": { + "machine": "bbcb", + "lua_script": "bbcb_flop.lua", + "config_args": [ + { + "key": "sticktype", + "type": "str", + "default": "none", + "skip_if": "none", + "args": [ + "-analogue", + "{value}" + ] + } + ], + "extra_args": [ + "-skip_gameinfo" + ], + "media": "flop1" + }, + "bbcb_flop_orig": { + "machine": "bbcb", + "lua_script": "bbcb_flop_orig.lua", + "config_args": [ + { + "key": "sticktype", + "type": "str", + "default": "none", + "skip_if": "none", + "args": [ + "-analogue", + "{value}" + ] + } + ], + "extra_args": [ + "-skip_gameinfo" + ], + "media": "flop1" + }, + "bbcb_flop_us": { + "machine": "bbcb_us", + "lua_script": "bbcb_flop.lua", + "config_args": [ + { + "key": "sticktype", + "type": "str", + "default": "none", + "skip_if": "none", + "args": [ + "-analogue", + "{value}" + ] + } + ], + "media": "flop1" + }, + "bbcbc": { + "machine": "bbcbc", + "media": "cart" + }, + "bbcm_cart": { + "machine": "bbcm", + "media": "cart" + }, + "bbcm_flop": { + "machine": "bbcm", + "media": "flop1" + }, + "bbcmc_flop": { + "machine": "bbcmc", + "media": "flop1" + }, + "bdesignm_design_cart": { + "machine": "bdesignm", + "media": "cart" + }, + "bdesignm_game_cart": { + "machine": "bdesignm", + "media": "cart" + }, + "bingobear": { + "machine": "bbear", + "media": "cart" + }, + "bk0010": { + "machine": "bk001001", + "lua_script": "bk0010.lua", + "media": "cass" + }, + "bkrankp_cart": { + "machine": "bkrankp", + "media": "cart" + }, + "bmjr_cass": { + "machine": "bmjr", + "media": "cass" + }, + "bml3_cass": { + "machine": "bml3", + "media": "cass" + }, + "bml3_flop": { + "machine": "bml3", + "media": "flop1" + }, + "brother_pn": { + "machine": "pn8800", + "media": "flop1" + }, + "bungo_flop": { + "machine": "mini5sx", + "media": "flop1" + }, + "buzztime_cart": { + "machine": "buzztime", + "media": "cart" + }, + "bw12": { + "machine": "bw12", + "media": "flop1" + }, + "bw14": { + "machine": "bw14", + "media": "flop1" + }, + "bw2": { + "machine": "bw2", + "media": "flop1" + }, + "bx256hp_flop": { + "machine": "bx256hp", + "media": "flop1" + }, + "c128_cart": { + "machine": "c128", + "media": "cart" + }, + "c128_flop": { + "machine": "c128", + "media": "flop1" + }, + "c128_rom": { + "machine": "c128", + "media": "rom" + }, + "c2color_cart": { + "machine": "c2color", + "media": "cart" + }, + "c64_cart": { + "machine": "c64", + "media": "cart" + }, + "c64_cass": { + "machine": "c64", + "lua_script": "c64_cass.lua", + "media": "cass1" + }, + "c64_flop_misc": { + "machine": "c64", + "lua_script": "c64_flop.lua", + "media": "flop1" + }, + "c64_flop_orig": { + "machine": "c64", + "lua_script": "c64_flop.lua", + "media": "flop1" + }, + "c65_flop": { + "machine": "c65", + "media": "flop1" + }, + "camplynx_cass": { + "machine": "lynx128k", + "lua_script": "camplynx_cass.lua", + "extra_args": [ + "-skip_gameinfo", + "-ram", + "128k" + ], + "media": "cass" + }, + "camplynx_flop": { + "machine": "lynx128k", + "media": "flop1" + }, + "carbeena": { + "machine": "beena", + "media": "rom" + }, + "casio_rompack": { + "machine": "casiorom", + "media": "cart" + }, + "casloopy": { + "machine": "casloopy", + "media": "cart" + }, + "cassvisn_cart": { + "machine": "cassvisn", + "media": "cart" + }, + "cbm2_cart": { + "machine": "b256", + "media": "cart" + }, + "cbm2_flop": { + "machine": "b256", + "media": "flop1" + }, + "cbm8096_flop": { + "machine": "cbm8096", + "media": "flop1" + }, + "cbm8296_flop": { + "machine": "cbm8296", + "media": "flop1" + }, + "cc40_cart": { + "machine": "cc40", + "media": "cart" + }, + "cd32": { + "machine": "cd32", + "media": "cdrom" + }, + "cdi": { + "machine": "cdimono1", + "lua_script": "cdi.lua", + "media": "cdrm" + }, + "cdtv": { + "machine": "cdtv", + "media": "cdrom1" + }, + "cecflop": { + "machine": "cec2000", + "media": "flop1" + }, + "cgenie_cass": { + "machine": "cgenie", + "lua_script": "cgenie_cass.lua", + "extra_args": [ + "-ram", + "32k" + ], + "media": "cass" + }, + "cgenie_flop_rom": { + "machine": "cgenie_fdc", + "media": "rom" + }, + "challenge_gear_cart": { + "machine": "chalgear", + "media": "cart" + }, + "channelf": { + "machine": "channelf", + "media": "cart" + }, + "chessking_cart": { + "machine": "chesskng", + "media": "cart" + }, + "chessmstdm": { + "machine": "chessmstdm", + "media": "cart" + }, + "chip8_quik": { + "machine": "d6800", + "media": "quik" + }, + "clickstart_cart": { + "machine": "clikstrt", + "media": "cart" + }, + "clipper_flop": { + "machine": "clipper", + "media": "flop1" + }, + "coco_cart": { + "machine": "coco3", + "media": "cart" + }, + "coco_cass": { + "machine": "coco3", + "lua_script": "trs80_cass.lua", + "config_args": [ + { + "key": "ramsize", + "type": "int", + "skip_if": 0, + "args": [ + "-ramsize", + "{value}M" + ] + } + ], + "media": "cass" + }, + "coco_flop": { + "machine": "coco3", + "lua_script": "trs80_flop.lua", + "config_args": [ + { + "key": "ramsize", + "type": "int", + "skip_if": 0, + "args": [ + "-ramsize", + "{value}M" + ] + } + ], + "media": "flop1" + }, + "coleco": { + "machine": "coleco", + "media": "cart" + }, + "coleco_homebrew": { + "machine": "coleco", + "media": "cart" + }, + "compclr2_flop": { + "machine": "compclr2", + "media": "flop1" + }, + "compis": { + "machine": "compis", + "media": "flop1" + }, + "comx35_flop": { + "machine": "comx35p", + "media": "flop1" + }, + "conchess": { + "machine": "conc", + "media": "cart" + }, + "copera": { + "machine": "copera", + "media": "cart" + }, + "cpc_cass": { + "machine": "cpc464", + "lua_script": "cpc_cass.lua", + "config_args": [ + { + "key": "ramsize", + "type": "int", + "skip_if": 0, + "args": [ + "-ramsize", + "{value}M" + ] + } + ], + "media": "cass1" + }, + "cpc_flop": { + "machine": "cpc6128", + "lua_script": "cpc_flop.lua", + "config_args": [ + { + "key": "ramsize", + "type": "int", + "skip_if": 0, + "args": [ + "-ramsize", + "{value}M" + ] + } + ], + "media": "flop1" + }, + "crvision": { + "machine": "crvision", + "lua_script": "crvision.lua", + "media": "cart" + }, + "ctvboy": { + "machine": "ctvboy", + "media": "cart" + }, + "cubieboard4": { + "machine": "cubibrd4", + "media": "image" + }, + "cx3000tc": { + "machine": "cx3000tc", + "media": "cart" + }, + "cz1_cart": { + "machine": "cz1", + "media": "cart" + }, + "dai_cass": { + "machine": "dai", + "lua_script": "dai_cass.lua", + "media": "cass1" + }, + "database": { + "machine": "database", + "media": "cart" + }, + "dc": { + "machine": "dc", + "media": "cdrom" + }, + "dgnalpha_flop": { + "machine": "dgnalpha", + "media": "flop1" + }, + "dgnbeta_flop": { + "machine": "dgnbeta", + "media": "flop1" + }, + "digiblast_cart": { + "machine": "digiblst", + "media": "cart" + }, + "digilog320": { + "machine": "digilog320", + "media": "flop1" + }, + "dim68k": { + "machine": "dim68k", + "media": "flop1" + }, + "dmv": { + "machine": "dmv", + "media": "flop" + }, + "dps1": { + "machine": "dps1", + "media": "flop1" + }, + "dragon_cart": { + "machine": "dragon64", + "config_args": [ + { + "key": "ramsize", + "type": "int", + "skip_if": 0, + "args": [ + "-ramsize", + "{value}M" + ] + } + ], + "media": "cart" + }, + "dragon_cass": { + "machine": "dragon64", + "lua_script": "dragon_cass.lua", + "config_args": [ + { + "key": "ramsize", + "type": "int", + "skip_if": 0, + "args": [ + "-ramsize", + "{value}M" + ] + } + ], + "media": "cass" + }, + "dragon_flex": { + "machine": "dragon64", + "media": "flop1" + }, + "dragon_flop": { + "machine": "dragon64", + "config_args": [ + { + "key": "ramsize", + "type": "int", + "skip_if": 0, + "args": [ + "-ramsize", + "{value}M" + ] + } + ], + "media": "flop1" + }, + "dragon_os9": { + "machine": "dragon64", + "media": "flop1" + }, + "duelmast_cart": { + "machine": "duelmast", + "media": "cart" + }, + "easy_karaoke_cart": { + "machine": "easykara", + "media": "cart" + }, + "ec1841": { + "machine": "ec1841", + "media": "flop1" + }, + "einstein": { + "machine": "einst256", + "lua_script": "einstein.lua", + "media": "flop1" + }, + "einstein_rom": { + "machine": "einstein", + "media": "rom" + }, + "ekara_cart": { + "machine": "ekara", + "media": "cart" + }, + "electron_cart": { + "machine": "electron", + "extra_args": [ + "-skip_gameinfo" + ], + "media": "cart" + }, + "electron_cass": { + "machine": "electron", + "lua_script": "electron_cass.lua", + "extra_args": [ + "-skip_gameinfo" + ], + "media": "cass" + }, + "electron_flop": { + "machine": "electron", + "lua_script": "electron_flop.lua", + "extra_args": [ + "-skip_gameinfo" + ], + "media": "flop1" + }, + "electron_rom": { + "machine": "electron", + "media": "rom" + }, + "entex_sag": { + "machine": "sag", + "media": "cart" + }, + "ep64_cart": { + "machine": "ep64", + "media": "cart" + }, + "ep64_cass": { + "machine": "ep64", + "media": "cass1" + }, + "ep64_flop": { + "machine": "ep64", + "media": "flop1" + }, + "epson_cpm": { + "machine": "ehx20", + "media": "flop1" + }, + "eti660_quik": { + "machine": "eti660", + "media": "quik" + }, + "evio": { + "machine": "evio", + "media": "cart" + }, + "ews286_flop": { + "machine": "ews286", + "media": "flop1" + }, + "excalibur64": { + "machine": "excali64", + "media": "flop1" + }, + "exl100": { + "machine": "exl100", + "media": "cart" + }, + "famibox": { + "machine": "famicom", + "media": "cart" + }, + "famicom_cass": { + "machine": "famicom", + "lua_script": "famicom_cass.lua", + "media": "cass" + }, + "famicom_flop": { + "machine": "famicom", + "media": "flop1" + }, + "fidel_msc": { + "machine": "miniscc", + "media": "cart" + }, + "fidel_sc6": { + "machine": "fscc6", + "media": "cart" + }, + "fidel_scc": { + "machine": "feag", + "media": "cart" + }, + "fm77av": { + "machine": "fm77av", + "media": "flop1" + }, + "fm7_cass": { + "machine": "fm7", + "lua_script": "fm7_cass.lua", + "media": "cass" + }, + "fm7_disk": { + "machine": "fm7", + "media": "flop1" + }, + "fm8_cass": { + "machine": "fm8", + "media": "cass1" + }, + "fmtowns_cd": { + "machine": "fmtowns", + "media": "cdrm" + }, + "fmtowns_flop_cracked": { + "machine": "fmtowns", + "media": "flop1" + }, + "fmtowns_flop_misc": { + "machine": "fmtowns", + "media": "flop1" + }, + "fmtowns_flop_orig": { + "machine": "fmtowns", + "media": "flop1" + }, + "fp1100_cass": { + "machine": "fp1100", + "media": "cass1" + }, + "gaelco_ds5002fp_rom": { + "machine": "gaelcods", + "media": "cart" + }, + "galaxy": { + "machine": "galaxy", + "lua_script": "galaxy.lua", + "media": "cass1" + }, + "gamate": { + "machine": "gamate", + "media": "cart" + }, + "gameboy": { + "machine": "gameboy", + "media": "cart" + }, + "gamecom": { + "machine": "gamecom", + "media": "cart1" + }, + "gamegear": { + "machine": "gamegear", + "media": "cart" + }, + "gameking": { + "machine": "gameking", + "media": "cart" + }, + "gameking3": { + "machine": "gamekin3", + "media": "cart" + }, + "gamepock": { + "machine": "gamepock", + "media": "cart" + }, + "gba": { + "machine": "gba", + "media": "cart" + }, + "gbcolor": { + "machine": "gbcolor", + "media": "cart" + }, + "gcslottv": { + "machine": "gcslottv", + "media": "cart" + }, + "generic_cdrom": { + "machine": "generic", + "media": "cdrom" + }, + "generic_flop_525": { + "machine": "generic", + "media": "flop1" + }, + "ggm": { + "machine": "ggm", + "media": "cart" + }, + "gimix": { + "machine": "gimix", + "media": "flop1" + }, + "gj4000": { + "machine": "gj4000", + "media": "rom" + }, + "gjmovie": { + "machine": "gjmovie", + "media": "rom" + }, + "gjrstar": { + "machine": "gjrstar", + "media": "rom" + }, + "gl2000": { + "machine": "gl2000", + "media": "rom" + }, + "gl6000sl": { + "machine": "gl6000sl", + "media": "rom" + }, + "glcolor": { + "machine": "glcolor", + "media": "rom" + }, + "glcx": { + "machine": "gl6600cx", + "media": "rom" + }, + "gln": { + "machine": "gln", + "media": "rom" + }, + "gls": { + "machine": "gls", + "media": "rom" + }, + "gmaster": { + "machine": "gmaster", + "media": "cart" + }, + "gp32": { + "machine": "gp32", + "media": "memc", + "extra_args": [ + "-bios", + "166m" + ] + }, + "guab": { + "machine": "guab", + "media": "flop1" + }, + "gx4000": { + "machine": "gx4000", + "media": "cart" + }, + "h21": { + "machine": "h21", + "media": "cart" + }, + "h88_cass": { + "machine": "h88", + "media": "cass" + }, + "hikara": { + "machine": "hikara", + "media": "cart" + }, + "horizon": { + "machine": "nshrz2mhz", + "media": "flop1" + }, + "hp85_rom": { + "machine": "hp85", + "media": "rom" + }, + "hp86_rom": { + "machine": "hp86b", + "media": "rom" + }, + "hp9825_rom": { + "machine": "hp9825b", + "media": "rom" + }, + "hp9831_rom": { + "machine": "hp9831", + "media": "rom" + }, + "hp9835a_rom": { + "machine": "hp9835a", + "media": "rom" + }, + "hp9845a_rom": { + "machine": "hp9845a", + "media": "rom" + }, + "hp9845b_rom": { + "machine": "hp9845b", + "media": "rom" + }, + "hp98x6_rom": { + "machine": "hp9836c", + "media": "rom" + }, + "hp9k3xx_cdrom": { + "machine": "hp9k380", + "media": "cdrom1" + }, + "hp9k3xx_flop": { + "machine": "hp9k380", + "media": "bas4sys" + }, + "hp9k3xx_hdd": { + "machine": "hp9k380", + "media": "hdd" + }, + "hp_ipc": { + "machine": "hp_ipc", + "media": "flop1" + }, + "hp_ipc_rom": { + "machine": "hp_ipc", + "media": "rom" + }, + "ht68k": { + "machine": "ht68k", + "media": "flop1" + }, + "hx20_rom": { + "machine": "ehx20", + "media": "rom" + }, + "hyperscan": { + "machine": "hyprscan", + "media": "cdrom" + }, + "hyperscan_card": { + "machine": "hyprscan", + "media": "card" + }, + "i7000_card": { + "machine": "i7000", + "media": "card" + }, + "ibm5140": { + "machine": "ibm5140", + "media": "flop1" + }, + "ibm5150": { + "machine": "ibm5150", + "media": "flop1" + }, + "ibm5150_cass": { + "machine": "ibm5150", + "media": "cass1" + }, + "ibm5150_hdd": { + "machine": "ibm5150", + "media": "hdd" + }, + "ibm5170": { + "machine": "ibm5170", + "media": "flop1" + }, + "ibm5170_cdrom": { + "machine": "ibm5170", + "media": "cdrom1" + }, + "ibm5170_hdd": { + "machine": "ibm5170", + "media": "hdd" + }, + "ibm6580": { + "machine": "ibm6580", + "media": "flop1" + }, + "ibmpcjr_cart": { + "machine": "ibmpcjr", + "media": "cart" + }, + "ibmpcjr_flop": { + "machine": "ibmpcjr", + "media": "flop1" + }, + "ibmpcjx": { + "machine": "ibmpcjx", + "media": "flop1" + }, + "icanguit": { + "machine": "icanguit", + "media": "cart" + }, + "icanpian": { + "machine": "icanpian", + "media": "cart" + }, + "intellect02": { + "machine": "intel02", + "media": "cart" + }, + "interact": { + "machine": "interact", + "media": "cass" + }, + "interpro": { + "machine": "ip6800", + "media": "disc1" + }, + "intv": { + "machine": "intv", + "media": "cart" + }, + "intvecs": { + "machine": "intvecs", + "media": "cart" + }, + "iq128": { + "machine": "iq128", + "media": "rom" + }, + "iq151_cart": { + "machine": "iq151", + "media": "cart" + }, + "iq151_flop": { + "machine": "iq151", + "media": "flop1" + }, + "ique": { + "machine": "no_machine_found", + "media": "cart" + }, + "iqunlim_cart": { + "machine": "iqunlim", + "media": "cart" + }, + "itt3030": { + "machine": "itt3030", + "media": "flop1" + }, + "jaguar": { + "machine": "jaguar", + "media": "cart" + }, + "jakks_gamekey_dp": { + "machine": "jak_dpr", + "media": "cart" + }, + "jakks_gamekey_dy": { + "machine": "jak_disf", + "media": "cart" + }, + "jakks_gamekey_mv": { + "machine": "jak_spdm", + "media": "cart" + }, + "jakks_gamekey_nk": { + "machine": "jak_dora", + "media": "cart" + }, + "jakks_gamekey_nm": { + "machine": "jak_mpac", + "media": "cart" + }, + "jakks_gamekey_sw": { + "machine": "jak_sith", + "media": "cart" + }, + "jaminator": { + "machine": "jaminator", + "media": "cart" + }, + "jazz": { + "machine": "mmr4000be", + "media": "hdd" + }, + "jb3000_flop": { + "machine": "jb3000", + "media": "flop1" + }, + "juicebox": { + "machine": "juicebox", + "extra_args": [ + "-skip_gameinfo" + ], + "media": "memc" + }, + "juku": { + "machine": "juku", + "lua_script": "juku.lua", + "media": "flop1" + }, + "jupace_cass": { + "machine": "jupace", + "lua_script": "jupace_cass.lua", + "extra_args": [ + "-ram", + "48k" + ], + "media": "cass1" + }, + "jupace_snap": { + "machine": "jupace", + "lua_script": "jupace_snap.lua", + "extra_args": [ + "-ram", + "48k" + ], + "media": "snap" + }, + "k28": { + "machine": "k28", + "media": "cart" + }, + "k28o": { + "machine": "k28o", + "media": "cart" + }, + "kaypro": { + "machine": "kaypro484", + "media": "flop1" + }, + "kc_cart": { + "machine": "kc85_2", + "media": "cart" + }, + "kc_cass": { + "machine": "kc85_2", + "media": "cass" + }, + "kc_flop": { + "machine": "kc85_2", + "media": "flop" + }, + "kim1_cass": { + "machine": "kim1", + "media": "cass" + }, + "kisssite_cd": { + "machine": "kisssite", + "media": "cdrom" + }, + "korvet_flop": { + "machine": "korvet", + "media": "flop1" + }, + "kpython2": { + "machine": "gtrfrkv3j", + "media": "dvdrom1" + }, + "lanteach": { + "machine": "lanteach", + "media": "cart" + }, + "lantrans": { + "machine": "lantrans", + "media": "cart" + }, + "laser2001_cart": { + "machine": "lasr2001", + "media": "cart" + }, + "laser2001_flop": { + "machine": "lasr2001", + "media": "flop1" + }, + "leapfrog_didj_cart": { + "machine": "didj", + "media": "cart" + }, + "leapfrog_iquest_cart": { + "machine": "iquest", + "media": "cart" + }, + "leapfrog_leappad_cart": { + "machine": "leappad", + "media": "cart" + }, + "leapfrog_ltleappad_cart": { + "machine": "ltleappad", + "media": "cart" + }, + "leapfrog_mfleappad_cart": { + "machine": "mfleappad", + "media": "cart" + }, + "leapfrog_zippity_cart": { + "machine": "zippity", + "media": "cart" + }, + "leapster": { + "machine": "leapster", + "media": "cart" + }, + "leapster_explorer_cart": { + "machine": "leapexpr", + "media": "cart" + }, + "lisa": { + "machine": "lisa", + "media": "flop1" + }, + "lisa2": { + "machine": "no_machine_found", + "media": "flop1" + }, + "lk3000": { + "machine": "lk3000", + "media": "cart" + }, + "lnux4004": { + "machine": "lnux4004", + "media": "linux4004" + }, + "lviv": { + "machine": "lviv", + "media": "cass1" + }, + "lynx": { + "machine": "lynx", + "media": "cart" + }, + "m20": { + "machine": "m20", + "media": "flop1" + }, + "m24": { + "machine": "m24", + "media": "flop1" + }, + "m3": { + "machine": "m3", + "media": "flop1" + }, + "m5_cart": { + "machine": "m5", + "media": "cart" + }, + "m5_cass": { + "machine": "m5", + "lua_script": "m5_cass.lua", + "extra_args": [ + "-cart1", + "basici" + ], + "media": "cass1" + }, + "m5_flop": { + "machine": "m5p_brno", + "media": "flop1", + "extra_args": [ + "-cart1", + "basici" + ] + }, + "mac_cdrom": { + "machine": "maclc475", + "media": "cdrom1" + }, + "mac_flop": { + "machine": "macsefd", + "config_args": [ + { + "key": "ramsize", + "type": "int", + "skip_if": 0, + "args": [ + "-ramsize", + "{value}M" + ], + "only_machines": [ + "maciix", + "maclc3" + ], + "machine_overrides": { + "maclc3": { + "value_map": { + "2": 4 + }, + "max": 80 + }, + "maciix": { + "value_map": { + "16": 32, + "48": 64 + } + } + } + } + ], + "media": "flop1" + }, + "mac_flop_clcracked": { + "machine": "mac", + "media": "flop1" + }, + "mac_flop_orig": { + "machine": "mac", + "media": "flop1" + }, + "mac_hdd": { + "machine": "maclc3", + "config_args": [ + { + "key": "ramsize", + "type": "int", + "skip_if": 0, + "args": [ + "-ramsize", + "{value}M" + ], + "only_machines": [ + "maciix", + "maclc3" + ], + "machine_overrides": { + "maclc3": { + "value_map": { + "2": 4 + }, + "max": 80 + }, + "maciix": { + "value_map": { + "16": 32, + "48": 64 + } + } + } + } + ], + "media": "hdd" + }, + "mac_hdflop": { + "machine": "maclc3", + "media": "flop1" + }, + "mbc200": { + "machine": "mbc200", + "media": "flop1" + }, + "mbc55x": { + "machine": "mbc55x", + "media": "flop1" + }, + "mbee_cart": { + "machine": "mbee", + "media": "cart" + }, + "mbee_cass": { + "machine": "mbee", + "media": "cass" + }, + "mbee_flop": { + "machine": "mbee256", + "media": "flop1" + }, + "mbee_quik": { + "machine": "mbee", + "media": "quik" + }, + "mc10": { + "machine": "mc10", + "lua_script": "mc10_cass.lua", + "extra_args": [ + "-ram", + "20k" + ], + "media": "cass" + }, + "mc1000_cass": { + "machine": "mc1000", + "media": "cass1" + }, + "mc1502_flop": { + "machine": "mc1502", + "media": "flop1" + }, + "md2_flop": { + "machine": "md2", + "media": "flop1" + }, + "megacd": { + "machine": "megacd", + "lua_script": "megacd.lua", + "media": "cdrom" + }, + "megadriv": { + "machine": "megadriv", + "media": "cart" + }, + "megaduck": { + "machine": "megaduck", + "media": "cart" + }, + "megapc": { + "machine": "megapc", + "media": "flop1" + }, + "megatech": { + "machine": "no_machine_found", + "media": "cart" + }, + "mephisto_mm1": { + "machine": "mm1", + "media": "cart" + }, + "mephisto_mm2": { + "machine": "mm2", + "media": "cart" + }, + "mephisto_mm4": { + "machine": "mm4", + "media": "cart" + }, + "mephisto_mm5": { + "machine": "mm5", + "media": "cart" + }, + "mephisto_smondial2": { + "machine": "smondial2", + "media": "cart" + }, + "microbox2_flop": { + "machine": "microbx2", + "media": "flop1" + }, + "microvision": { + "machine": "microvsn", + "media": "cart" + }, + "midi_flop": { + "machine": "a486sv1", + "media": "flop1" + }, + "mikro80": { + "machine": "mikro80", + "media": "cass1" + }, + "mikrosha_cart": { + "machine": "mikrosha", + "media": "cart" + }, + "mikrosha_cass": { + "machine": "mikrosha", + "media": "cass" + }, + "mindset_flop": { + "machine": "mindset", + "media": "flop1" + }, + "misterx": { + "machine": "misterx", + "media": "cart" + }, + "mk14_quik": { + "machine": "mk14", + "media": "quik" + }, + "mm1_flop": { + "machine": "mm1m7", + "media": "flop1" + }, + "mm2_flop": { + "machine": "mm2m35d", + "media": "flop1" + }, + "mo5_cart": { + "machine": "mo5", + "media": "cart" + }, + "mo5_cass": { + "machine": "mo5", + "lua_script": "mo5_cass.lua", + "media": "cass1" + }, + "mo5_flop": { + "machine": "mo5", + "media": "flop1" + }, + "mo5_qd": { + "machine": "mo5", + "media": "cart" + }, + "mo6_cass": { + "machine": "mo6", + "lua_script": "mo6_cass.lua", + "media": "cass1" + }, + "mo6_flop": { + "machine": "mo6", + "media": "flop1" + }, + "mobigo_cart": { + "machine": "mobigo", + "media": "cart" + }, + "monon_color": { + "machine": "mononcol", + "media": "cart" + }, + "mpc3000_flop": { + "machine": "mpc3000", + "media": "disk1" + }, + "mpf1_rom": { + "machine": "mpf1", + "media": "rom" + }, + "mpu1000": { + "machine": "mpu1000", + "media": "cart" + }, + "mpz80": { + "machine": "mpz80", + "media": "flop" + }, + "msx1_bee_card": { + "machine": "hx10", + "media": "cart2", + "extra_args": [ + "-cartslot1", + "beepack" + ] + }, + "msx1_cart": { + "machine": "hx10", + "media": "cart1" + }, + "msx1_cass": { + "machine": "hx10", + "media": "cass1", + "lua_script": "msx1_cass.lua" + }, + "msx1_flop": { + "machine": "nms8250", + "media": "flop1" + }, + "msx1_flop_525": { + "machine": "hx10", + "media": "flop1", + "extra_args": [ + "-cart1", + "cdx2" + ] + }, + "msx2_cart": { + "machine": "nms8250", + "media": "cart1" + }, + "msx2_cass": { + "machine": "nms8250", + "media": "cass1", + "lua_script": "msx1_cass.lua" + }, + "msx2_flop": { + "machine": "nms8250", + "media": "flop1" + }, + "msx2p_cart": { + "machine": "fsa1gt", + "media": "cart1" + }, + "msx2p_flop": { + "machine": "fsa1gt", + "media": "flop1" + }, + "msx_softcard": { + "machine": "no_machine_found", + "media": "cart" + }, + "msx_yamaha_minicart": { + "machine": "cx5m128", + "media": "cart" + }, + "msxr_cart": { + "machine": "fsa1gt", + "media": "cart" + }, + "msxr_flop": { + "machine": "fsa1gt", + "media": "flop1" + }, + "mt65_cass": { + "machine": "mt65", + "media": "cass1" + }, + "mt65_rom": { + "machine": "mt65", + "media": "rom1" + }, + "mt65_snap": { + "machine": "mt65", + "media": "snap" + }, + "mtu130_flop": { + "machine": "mtu130", + "media": "flop1" + }, + "mtx_cart": { + "machine": "mtx512", + "media": "cart" + }, + "mtx_cass": { + "machine": "mtx512", + "lua_script": "mtx_cass.lua", + "extra_args": [ + "-skip_gameinfo" + ], + "media": "cass1" + }, + "mtx_flop": { + "machine": "mtx512", + "media": "flop" + }, + "mtx_hdd": { + "machine": "mtx512", + "media": "hdd" + }, + "mtx_rom": { + "machine": "mtx512", + "media": "rom" + }, + "myvision": { + "machine": "myvision", + "media": "cart" + }, + "mz2000_cass": { + "machine": "mz2000", + "lua_script": "mz2000_cass.lua", + "media": "cass" + }, + "mz2000_flop": { + "machine": "mz2000", + "media": "flop1" + }, + "mz2000_snap": { + "machine": "mz2000", + "media": "snap" + }, + "mz2500_flop": { + "machine": "mz2500", + "media": "flop1" + }, + "mz5500_flop": { + "machine": "mz5500", + "media": "flop1" + }, + "mz700_cass": { + "machine": "mz700", + "lua_script": "mz700_cass.lua", + "media": "cass" + }, + "mz800_cass": { + "machine": "mz800", + "lua_script": "mz800_cass.lua", + "media": "cass" + }, + "mz800_rom": { + "machine": "no_machine_found", + "media": "rom" + }, + "mz80b_cass": { + "machine": "mz80b", + "media": "cass1" + }, + "mz80b_flop": { + "machine": "mz80b", + "media": "flop1" + }, + "mz80k_cass": { + "machine": "mz80k", + "lua_script": "mz80k_cass.lua", + "media": "cass" + }, + "n64": { + "machine": "n64", + "media": "cart" + }, + "n64_lodgenet": { + "machine": "n64_lodgenet", + "media": "cart" + }, + "n64dd": { + "machine": "n64dd", + "media": "disk" + }, + "nascom_flop": { + "machine": "nascom2", + "media": "flop1" + }, + "nascom_snap": { + "machine": "nascom2", + "media": "snap" + }, + "nascom_socket": { + "machine": "nascom2", + "media": "socket" + }, + "neocd": { + "machine": "neocd", + "media": "cdrom" + }, + "neogeo": { + "machine": "aes", + "media": "cart" + }, + "nes": { + "machine": "nes", + "media": "cart" + }, + "nes_ade": { + "machine": "nes", + "media": "cart" + }, + "nes_datach": { + "machine": "nes", + "media": "cart" + }, + "nes_kstudio": { + "machine": "nes", + "media": "cart" + }, + "nes_ntbrom": { + "machine": "nes", + "media": "cart" + }, + "nes_vt_cart": { + "machine": "timetp25", + "media": "cart" + }, + "next": { + "machine": "nextst", + "media": "flop1" + }, + "next_cdrom": { + "machine": "next", + "media": "cdrom" + }, + "next_hdd": { + "machine": "next", + "media": "hdd" + }, + "ngp": { + "machine": "ngp", + "lua_script": "ngp.lua", + "media": "cart" + }, + "ngpc": { + "machine": "ngpc", + "lua_script": "ngp.lua", + "media": "cart" + }, + "nimbus": { + "machine": "nimbus", + "media": "flop1" + }, + "novag_ssensor4": { + "machine": "ssensor4", + "media": "exrom" + }, + "nuon": { + "machine": "n501", + "media": "dvdrom" + }, + "octopus": { + "machine": "octopus", + "media": "flop1" + }, + "ondra": { + "machine": "ondrat", + "media": "cass" + }, + "orao": { + "machine": "orao", + "media": "cass1" + }, + "oric1_cass": { + "machine": "oric1", + "lua_script": "oric1_cass.lua", + "media": "cass" + }, + "orina_stylish_plus_cart": { + "machine": "orinasp", + "media": "cart" + }, + "orion_cart": { + "machine": "orion128", + "media": "cart" + }, + "orion_cass": { + "machine": "orionzms", + "lua_script": "orion_cass.lua", + "extra_args": [ + "-cart", + "romdisk" + ], + "media": "cass1" + }, + "orion_flop": { + "machine": "orion128", + "media": "disk" + }, + "orionpro_flop": { + "machine": "orionpro", + "media": "disk" + }, + "osborne1": { + "machine": "osborne1", + "media": "flop1" + }, + "osborne2": { + "machine": "osbexec", + "media": "flop1" + }, + "p500_flop": { + "machine": "p500", + "media": "flop1" + }, + "partner_cass": { + "machine": "partner", + "media": "cass" + }, + "partner_flop": { + "machine": "partner", + "media": "disk" + }, + "pasogo": { + "machine": "pasogo", + "media": "cart" + }, + "pasopia7_cass": { + "machine": "pasopia7", + "media": "cass1" + }, + "pasopia_cass": { + "machine": "pasopia", + "media": "cass1" + }, + "pb2000c": { + "machine": "pb2000c", + "media": "cart" + }, + "pc1000": { + "machine": "pc1000", + "media": "rom" + }, + "pc100_flop": { + "machine": "pc100", + "media": "flop1" + }, + "pc1512_flop": { + "machine": "pc1512", + "media": "flop1" + }, + "pc1512_hdd": { + "machine": "pc1512", + "media": "hdd" + }, + "pc1640_flop": { + "machine": "pc1640", + "media": "flop1" + }, + "pc1640_hdd": { + "machine": "pc1640", + "media": "hdd" + }, + "pc200": { + "machine": "pc200", + "media": "flop1" + }, + "pc6001_cart": { + "machine": "pc6001", + "media": "cart1" + }, + "pc6001_cass": { + "machine": "pc6001", + "lua_script": "pc6001_cass.lua", + "media": "cart" + }, + "pc6001mk2_cass": { + "machine": "pc6001mk2", + "lua_script": "pc6001mk2_cass.lua", + "media": "cart" + }, + "pc8001_flop": { + "machine": "pc8001", + "media": "flop1" + }, + "pc8001mk2_flop": { + "machine": "pc8001mk2", + "media": "flop1" + }, + "pc8001mk2sr_flop": { + "machine": "pc8001mk2sr", + "media": "flop1" + }, + "pc8201": { + "machine": "pc8201", + "media": "cart" + }, + "pc8801_cass": { + "machine": "pc8801", + "media": "cass1" + }, + "pc8801_cdrom": { + "machine": "pc8801mc", + "media": "cdrom" + }, + "pc8801_flop": { + "machine": "pc8801mk2sr", + "media": "flop1" + }, + "pc88va": { + "machine": "pc88va", + "media": "flop1" + }, + "pc98": { + "machine": "pc9821", + "media": "flop1" + }, + "pc98_cd": { + "machine": "pc9821", + "media": "cdrom" + }, + "pc98_flop_orig": { + "machine": "pc9821", + "media": "flop1" + }, + "pc98_hdd": { + "machine": "pc9821", + "media": "hdd" + }, + "pcd_flop": { + "machine": "pcd", + "media": "flop1" + }, + "pce": { + "machine": "pce", + "media": "cart" + }, + "pce_tourvision": { + "machine": "no_machine_found", + "media": "cart" + }, + "pcecd": { + "machine": "pce", + "lua_script": "pcecd.lua", + "media": "cdrom" + }, + "pcfx": { + "machine": "pcfx", + "media": "cdrom" + }, + "pcw": { + "machine": "pcw8256", + "media": "flop" + }, + "pcw16": { + "machine": "pcw16", + "media": "flop1" + }, + "pcx_flop": { + "machine": "pcx", + "media": "flop1" + }, + "pda600": { + "machine": "pda600", + "media": "card" + }, + "pdp1_ptp": { + "machine": "pdp1", + "media": "ptp" + }, + "pecom_cass": { + "machine": "pecom64", + "media": "cass1", + "lua_script": "pecom_cass.lua" + }, + "pegasus_cart": { + "machine": "pegasus", + "media": "cart" + }, + "pencil2": { + "machine": "pencil2", + "media": "cart" + }, + "pencil2_cass": { + "machine": "pencil2", + "media": "cass1" + }, + "pentagon_cass": { + "machine": "pentagon", + "media": "cass" + }, + "pet_cass": { + "machine": "cbm8296", + "media": "cass" + }, + "pet_flop": { + "machine": "pet", + "media": "flop1" + }, + "pet_hdd": { + "machine": "cbm8296", + "media": "hdd" + }, + "pet_quik": { + "machine": "cbm8296", + "media": "quik" + }, + "pet_rom": { + "machine": "cbm8296", + "media": "rom" + }, + "phc25_cass": { + "machine": "phc25", + "media": "cass" + }, + "photo_cd": { + "machine": "cd32", + "media": "cdrom" + }, + "pi_storyreader_cart": { + "machine": "pi_stry", + "media": "cart" + }, + "pi_storyreader_v2_cart": { + "machine": "pi_stry2", + "media": "cart" + }, + "picno": { + "machine": "picno", + "media": "cart" + }, + "pico": { + "machine": "pico", + "media": "cart" + }, + "pippin": { + "machine": "pippin", + "media": "cdrom" + }, + "pippin_flop": { + "machine": "no_machine_found", + "media": "flop1" + }, + "pixter_cart": { + "machine": "pixtermu", + "media": "cart" + }, + "playmaker": { + "machine": "playmaker", + "media": "cart" + }, + "pls1000_cart": { + "machine": "pls1000", + "media": "cart" + }, + "plus4_cart": { + "machine": "plus4", + "media": "cart" + }, + "plus4_cass": { + "machine": "plus4", + "media": "cass1" + }, + "plus4_flop": { + "machine": "plus4", + "media": "flop1" + }, + "pmd85_cass": { + "machine": "pmd851", + "media": "cass1" + }, + "pockchalv2": { + "machine": "pockchv2", + "media": "cart" + }, + "pockchalw": { + "machine": "pockchal", + "media": "cart" + }, + "pofo": { + "machine": "pofo", + "media": "card" + }, + "poisk1_flop": { + "machine": "poisk1", + "media": "flop1" + }, + "pokemini": { + "machine": "pokemini", + "media": "cart" + }, + "poly_flop": { + "machine": "poly1", + "media": "flop1" + }, + "polysix": { + "machine": "polysix", + "media": "a" + }, + "princ": { + "machine": "princ", + "media": "rom" + }, + "pro128_cart": { + "machine": "pro128", + "media": "cart" + }, + "pro128_cass": { + "machine": "pro128", + "media": "cass1" + }, + "pro128_flop": { + "machine": "pro128", + "media": "flop1" + }, + "pro128s_flop": { + "machine": "pro128s", + "media": "flop1" + }, + "prof180": { + "machine": "prof180x", + "media": "flop1" + }, + "prof80": { + "machine": "prof80", + "media": "flop1" + }, + "psi98": { + "machine": "psi98", + "media": "flop1" + }, + "psion1": { + "machine": "psion1", + "media": "cart" + }, + "psion2": { + "machine": "psioncm", + "media": "cart" + }, + "psion_flop": { + "machine": "mc600", + "media": "flop1" + }, + "psion_ssd": { + "machine": "psion3", + "media": "cart" + }, + "psx": { + "machine": "psj", + "media": "cdrom" + }, + "pt68k2": { + "machine": "pt68k2", + "media": "flop1" + }, + "pv1000": { + "machine": "pv1000", + "media": "cart" + }, + "pv2000": { + "machine": "pv2000", + "media": "cart" + }, + "px4_cart": { + "machine": "px4", + "media": "cart" + }, + "px8_cart": { + "machine": "px8", + "media": "cart1" + }, + "pyl601": { + "machine": "pyl601", + "media": "disk" + }, + "ql_cart": { + "machine": "ql", + "media": "cart" + }, + "ql_cass": { + "machine": "ql", + "media": "cass1" + }, + "ql_flop": { + "machine": "ql", + "media": "flop1" + }, + "quizwiz": { + "machine": "quizwizc", + "media": "cart" + }, + "qx10_flop": { + "machine": "qx10", + "media": "flop1" + }, + "r8_card": { + "machine": "r8", + "media": "card" + }, + "r9751": { + "machine": "r9751", + "media": "flop1" + }, + "radio86_cart": { + "machine": "radiorom", + "media": "cart" + }, + "radio86_cass": { + "machine": "radio86", + "lua_script": "radio86_cass.lua", + "media": "cass" + }, + "rainbow": { + "machine": "rainbow", + "media": "flop1" + }, + "ramstar": { + "machine": "ramstar", + "media": "rom" + }, + "roland_tnsc1": { + "machine": "rlndtnsc1", + "media": "cart" + }, + "roland_tnsc2": { + "machine": "rlndtnsc2", + "media": "cart" + }, + "rwtrntcs": { + "machine": "rwtrntcs", + "media": "cart" + }, + "rx78_cart": { + "machine": "rx78", + "media": "cart" + }, + "rx78_cass": { + "machine": "rx78", + "lua_script": "rx78_cass.lua", + "media": "cass" + }, + "rz1_cass": { + "machine": "rz1", + "media": "sidea" + }, + "s2000_flop": { + "machine": "s2000", + "media": "disk1" + }, + "s3000_cdrom": { + "machine": "s3000", + "media": "cdrom1" + }, + "sagafox": { + "machine": "sagafox", + "media": "flop1" + }, + "sage2": { + "machine": "sage2", + "media": "flop1" + }, + "saitek_egr": { + "machine": "corona", + "media": "extrom" + }, + "saitek_kso": { + "machine": "tstar432", + "media": "extrom" + }, + "saitek_schess": { + "machine": "schess", + "media": "cart" + }, + "samcoupe_cass": { + "machine": "samcoupe", + "media": "cass" + }, + "samcoupe_flop": { + "machine": "samcoupe", + "lua_script": "samcoupe_flop.lua", + "config_args": [ + { + "key": "ramsize", + "type": "int", + "skip_if": 0, + "args": [ + "-ramsize", + "{value}M" + ] + } + ], + "extra_args": [ + "-skip_gameinfo" + ], + "media": "flop1" + }, + "sat_cart": { + "machine": "saturn", + "media": "cart" + }, + "sat_vccart": { + "machine": "no_machine_found", + "media": "cart" + }, + "saturn": { + "machine": "saturn", + "lua_script": "saturn.lua", + "media": "cdrom" + }, + "sawatte": { + "machine": "sawatte", + "media": "cart" + }, + "sbrain": { + "machine": "sbrain", + "media": "flop1" + }, + "sc3000_cart": { + "machine": "sc3000", + "media": "cart" + }, + "sc3000_cass": { + "machine": "sc3000", + "lua_script": "sc3000_cass.lua", + "extra_args": [ + "-cart", + "basic3e" + ], + "media": "cass" + }, + "scv": { + "machine": "scv", + "media": "cart" + }, + "sd132_flop": { + "machine": "sd132", + "media": "flop" + }, + "sd1_flop": { + "machine": "sd1", + "media": "flop" + }, + "sdk85": { + "machine": "sdk85", + "media": "prom" + }, + "sega_beena_cart": { + "machine": "beena", + "media": "cart" + }, + "segaai": { + "machine": "segaai", + "media": "card" + }, + "sf7000": { + "machine": "sf7000", + "media": "flop1" + }, + "sg1000": { + "machine": "sg1000", + "media": "cart" + }, + "sgi_mips": { + "machine": "indy_4610", + "media": "cdrom" + }, + "sgi_mips_hdd": { + "machine": "indy_4610", + "media": "hdd" + }, + "sgx": { + "machine": "sgx", + "media": "cart" + }, + "singingstarkaraoke_cart": { + "machine": "sstarkar", + "media": "cart" + }, + "sitcom": { + "machine": "sitcom", + "media": "san" + }, + "smartcycle_cart": { + "machine": "smartcyc", + "media": "cart" + }, + "smarttv_cart": { + "machine": "smartvad", + "media": "cart" + }, + "smc777": { + "machine": "smc777", + "media": "flop1" + }, + "sms": { + "machine": "sms", + "media": "cart" + }, + "snes": { + "machine": "snes", + "media": "cart" + }, + "snes_bspack": { + "machine": "snes", + "media": "cart" + }, + "snes_strom": { + "machine": "snes", + "media": "cart" + }, + "snes_vkun": { + "machine": "no_machine_found", + "media": "cdrom" + }, + "snotec": { + "machine": "snotec", + "media": "rom" + }, + "snread": { + "machine": "snread", + "media": "cart" + }, + "snspell": { + "machine": "snspell", + "media": "cart" + }, + "socrates": { + "machine": "socrates", + "media": "cart" + }, + "softbox": { + "machine": "softbox", + "media": "flop1" + }, + "sol20_cass": { + "machine": "sol20", + "media": "cass1" + }, + "sony_news": { + "machine": "nws5000x", + "media": "hdd" + }, + "sorcerer_cart": { + "machine": "sorcerer2", + "media": "cart" + }, + "sorcerer_cass": { + "machine": "sorcerer2", + "lua_script": "sorcerer_cass.lua", + "extra_args": [ + "-cart", + "basicpac" + ], + "media": "cass" + }, + "sorcerer_flop": { + "machine": "sorcererd", + "media": "flop1" + }, + "spc1000_cass": { + "machine": "spc1000", + "media": "cass1" + }, + "spc1500_cass": { + "machine": "spc1500", + "media": "cass" + }, + "special_cass": { + "machine": "special", + "media": "cass" + }, + "special_flop": { + "machine": "specimx", + "media": "disk" + }, + "specnext_sd": { + "machine": "tbblue", + "media": "card" + }, + "specpls3_flop": { + "machine": "specpls3", + "lua_script": "specpls3_flop.lua", + "media": "flop1" + }, + "spectrum_betadisc_flop": { + "machine": "tsconf", + "media": "flop1" + }, + "spectrum_cart": { + "machine": "no_machine_found", + "media": "cart" + }, + "spectrum_cass": { + "machine": "spectrum", + "lua_script": "spectrum_cass.lua", + "config_args": [ + { + "key": "ramsize", + "type": "int", + "skip_if": 0, + "args": [ + "-ramsize", + "{value}M" + ] + } + ], + "media": "cass" + }, + "spectrum_flop_opus": { + "machine": "no_machine_found", + "media": "flop1" + }, + "spectrum_mgt_flop": { + "machine": "no_machine_found", + "media": "flop1" + }, + "spectrum_microdrive": { + "machine": "no_machine_found", + "media": "cass" + }, + "spectrum_wafadrive": { + "machine": "no_machine_found", + "media": "cass" + }, + "sprachmg": { + "machine": "sprachmg", + "media": "rom" + }, + "squale_cart": { + "machine": "squale", + "media": "cart" + }, + "ssem_quik": { + "machine": "ssem", + "media": "quik" + }, + "st_cart": { + "machine": "st", + "media": "cart" + }, + "st_flop": { + "machine": "st", + "media": "flop1" + }, + "st_flop_demos": { + "machine": "st", + "media": "flop1" + }, + "stepone_flop": { + "machine": "stepone", + "media": "flop1" + }, + "studio2": { + "machine": "studio2", + "media": "cart" + }, + "stv": { + "machine": "no_machine_found", + "media": "cart" + }, + "sun_sparc": { + "machine": "e250", + "media": "cdrom1" + }, + "super6": { + "machine": "super6", + "media": "flop1" + }, + "super80_cass": { + "machine": "super80", + "lua_script": "super80_cass.lua", + "media": "cass" + }, + "super80_flop": { + "machine": "super80v", + "extra_args": [ + "-skip_gameinfo" + ], + "media": "flop1" + }, + "super_tv_pc_cart": { + "machine": "suprtvpc", + "media": "cart" + }, + "superpet_flop": { + "machine": "superpet", + "media": "flop1" + }, + "supracan": { + "machine": "supracan", + "media": "cart" + }, + "sv8000": { + "machine": "sv8000", + "media": "cart" + }, + "svi318_cart": { + "machine": "svi318", + "media": "cart" + }, + "svi318_cass": { + "machine": "svi318", + "lua_script": "svi318_cass.lua", + "media": "cass1" + }, + "svi318_flop": { + "machine": "no_machine_found", + "media": "flop1" + }, + "svision": { + "machine": "svision", + "media": "cart" + }, + "svmu": { + "machine": "svmu", + "media": "quik" + }, + "t1000": { + "machine": "t1000", + "media": "flop1" + }, + "takara_daigunder_dx_cart": { + "machine": "tak_daig", + "media": "cart" + }, + "tandy200": { + "machine": "tandy200", + "media": "cart" + }, + "tandy2k": { + "machine": "tandy2k", + "media": "flop1" + }, + "tandy6k": { + "machine": "no_machine_found", + "media": "flop1" + }, + "tc4": { + "machine": "tc4", + "media": "cart" + }, + "tdv2324": { + "machine": "tdv2324", + "media": "flop" + }, + "tek4052_cart": { + "machine": "tek4052a", + "media": "cart" + }, + "telestory_cart": { + "machine": "telestry", + "media": "cart" + }, + "teradrive_flop": { + "machine": "teradrive", + "media": "flop1" + }, + "teradrive_hdd": { + "machine": "teradrive", + "media": "hdd" + }, + "tg16": { + "machine": "tg16", + "media": "cart" + }, + "thinkpad8xx": { + "machine": "tpad850", + "media": "cdrom1" + }, + "ti74_cart": { + "machine": "ti74", + "media": "cart" + }, + "ti95_cart": { + "machine": "ti95", + "media": "cart" + }, + "ti99_cart": { + "machine": "ti99_4a", + "extra_args": [ + "-ioport", + "peb" + ], + "config_args": [ + { + "key": "ti99_32kram", + "type": "bool", + "default": true, + "if_true": [ + "-ioport:peb:slot2", + "32kmem" + ] + }, + { + "key": "ti99_speech", + "type": "bool", + "default": true, + "if_true": [ + "-ioport", + "speechsyn" + ] + } + ], + "media": "cart" + }, + "tiki100": { + "machine": "tiki100", + "media": "flop1" + }, + "timex_cass": { + "machine": "ts2068", + "lua_script": "timex_cass.lua", + "media": "cass" + }, + "timex_dock": { + "machine": "ts2068", + "media": "cart" + }, + "tmc600_quik": { + "machine": "tmc600s2", + "media": "quik" + }, + "tntell": { + "machine": "tntell", + "media": "cart" + }, + "to770_cart": { + "machine": "to770", + "media": "cart" + }, + "to770a_cart": { + "machine": "to770a", + "media": "cart" + }, + "to7_cart": { + "machine": "to7", + "media": "cart" + }, + "to7_cass": { + "machine": "to7", + "media": "cass1" + }, + "to7_qd": { + "machine": "to7", + "media": "flop1" + }, + "to8_cass": { + "machine": "to8", + "media": "cass1" + }, + "to8_qd": { + "machine": "to8", + "media": "flop1" + }, + "to_flop": { + "machine": "to8", + "lua_script": "to_flop.lua", + "media": "flop1" + }, + "triton_rom": { + "machine": "triton72", + "media": "rom" + }, + "trs80_cass": { + "machine": "trs80m3", + "lua_script": "trs80_cass.lua", + "media": "cass" + }, + "trs80_flop": { + "machine": "trs80m3", + "media": "flop1" + }, + "trs80_quik": { + "machine": "trs80m3", + "config_args": [ + { + "key": "ramsize", + "type": "int", + "skip_if": 0, + "args": [ + "-ramsize", + "{value}M" + ] + } + ], + "media": "quik" + }, + "trs80m2": { + "machine": "trs80m2", + "media": "flop1" + }, + "trsm100": { + "machine": "trsm100", + "media": "cart" + }, + "tsconf_betadisc_flop": { + "machine": "tsconf", + "media": "flop1" + }, + "ttwist_brainquest_cart": { + "machine": "ttwistbq", + "media": "cart" + }, + "turboextreme_cart": { + "machine": "turboex", + "media": "cart" + }, + "tutor": { + "machine": "tutor", + "media": "cart" + }, + "tvc_cart": { + "machine": "tvc64p", + "media": "cart" + }, + "tvc_cass": { + "machine": "tvc64p", + "lua_script": "tvc_cass.lua", + "media": "cass" + }, + "tvc_flop": { + "machine": "tvc64p", + "media": "flop1", + "lua_script": "tvc_flop.lua", + "extra_args": [ + "-exp1", + "hbf" + ] + }, + "tvdear": { + "machine": "tvdear", + "media": "cart" + }, + "tvgogo": { + "machine": "tvgogo", + "media": "cart" + }, + "tvochken": { + "machine": "tvochken", + "media": "card1" + }, + "tx0_ptp": { + "machine": "tx0_8kw", + "media": "ptp" + }, + "u110_card": { + "machine": "cm32p", + "media": "card" + }, + "unichamp": { + "machine": "unichamp", + "media": "cart" + }, + "ut88": { + "machine": "ut88", + "media": "cass" + }, + "uzebox": { + "machine": "uzebox", + "media": "cart" + }, + "v1050_flop": { + "machine": "v1050", + "media": "flop1" + }, + "v1050_hdd": { + "machine": "v1050", + "media": "hdd" + }, + "vbaby_cart": { + "machine": "vbaby", + "media": "cart" + }, + "vboy": { + "machine": "vboy", + "media": "cart" + }, + "vc4000": { + "machine": "vc4000", + "media": "cart" + }, + "vector06_cart": { + "machine": "vector06", + "media": "cart" + }, + "vector06_flop": { + "machine": "vector06", + "lua_script": "vector06_flop.lua", + "media": "flop1" + }, + "vectrex": { + "machine": "vectrex", + "media": "cart" + }, + "vfxsd_flop": { + "machine": "vfxsd", + "media": "flop" + }, + "vg5k": { + "machine": "vg5k", + "lua_script": "vg5k.lua", + "extra_args": [ + "-skip_gameinfo" + ], + "media": "cass" + }, + "vgmplay": { + "machine": "vgmplay", + "media": "quik" + }, + "vic10": { + "machine": "vic10", + "media": "cart" + }, + "vic1001_cart": { + "machine": "vic1001", + "media": "cart" + }, + "vic1001_cass": { + "machine": "vic1001", + "media": "cass1" + }, + "vic1001_flop": { + "machine": "vic1001", + "media": "flop1" + }, + "victor9k_flop": { + "machine": "victor9k", + "media": "flop1" + }, + "vidbrain": { + "machine": "vidbrain", + "media": "cart" + }, + "videoart": { + "machine": "videoart", + "media": "cart" + }, + "videopac": { + "machine": "videopac", + "media": "cart" + }, + "vii": { + "machine": "vii", + "media": "cart" + }, + "vip": { + "machine": "vip", + "media": "cass1" + }, + "vis": { + "machine": "vis", + "media": "cdrom" + }, + "visicom": { + "machine": "visicom", + "media": "cart" + }, + "vixen": { + "machine": "vixen", + "media": "flop1" + }, + "vsmile_cart": { + "machine": "vsmile", + "media": "cart" + }, + "vsmile_cd": { + "machine": "vsmilpro", + "media": "cdrom" + }, + "vsmileb_cart": { + "machine": "vsmileb", + "media": "cart" + }, + "vsmilem_cart": { + "machine": "vsmilem", + "media": "cart" + }, + "vtech2_cass": { + "machine": "laser700", + "lua_script": "vtech2_cass.lua", + "media": "cass1" + }, + "vtech_innotab_cart": { + "machine": "innotab2", + "media": "cart" + }, + "vtech_innotv_cart": { + "machine": "innotv", + "media": "cart" + }, + "vtech_storio_cart": { + "machine": "vreader", + "media": "cart" + }, + "vz_cass": { + "machine": "laser310", + "media": "cass1" + }, + "vz_snap": { + "machine": "laser310", + "media": "snap" + }, + "wangpc": { + "machine": "wangpc", + "media": "flop1" + }, + "waveterm": { + "machine": "waveterm", + "media": "flop1" + }, + "wicat": { + "machine": "wicat", + "media": "flop1" + }, + "wizard_cart": { + "machine": "iq7000", + "media": "cart" + }, + "wmbullet": { + "machine": "wmbullet", + "media": "flop1" + }, + "wren_flop": { + "machine": "wren", + "media": "flop1" + }, + "wscolor": { + "machine": "wscolor", + "media": "cart" + }, + "wswan": { + "machine": "wswan", + "media": "cart" + }, + "x07_card": { + "machine": "x07", + "media": "card" + }, + "x07_cass": { + "machine": "x07", + "media": "cass" + }, + "x1_cass": { + "machine": "x1", + "media": "cass" + }, + "x1_flop": { + "machine": "x1", + "media": "flop1" + }, + "x37_flop": { + "machine": "x37", + "media": "flop1" + }, + "x68k_flop": { + "machine": "x68000", + "media": "flop1" + }, + "xegs": { + "machine": "xegs", + "media": "cart" + }, + "xerox820": { + "machine": "bigboard", + "media": "flop1" + }, + "xerox820ii": { + "machine": "x820ii", + "media": "flop1" + }, + "z80clock": { + "machine": "z80clock", + "media": "u12" + }, + "z80ne_cass": { + "machine": "z80net", + "media": "cass1" + }, + "z80ne_flop": { + "machine": "z80netf", + "media": "flop1" + }, + "z88_cart": { + "machine": "z88", + "media": "cart1" + }, + "zorba": { + "machine": "zorba", + "media": "flop1" + }, + "zx80_cass": { + "machine": "zx80", + "media": "cass1" + }, + "zx81_cass": { + "machine": "zx81", + "lua_script": "zx81_cass.lua", + "media": "cass1" + } +} diff --git a/package/batocera/core/batocera-configgen/data/mame/messSystems.csv b/package/batocera/core/batocera-configgen/data/mame/messSystems.csv deleted file mode 100644 index e9593b158c4..00000000000 --- a/package/batocera/core/batocera-configgen/data/mame/messSystems.csv +++ /dev/null @@ -1,65 +0,0 @@ -adam;adam;cass; -advision;advision;cart; -beena;beena;cart; -apfm1000;apfm1000;cart; -apple2;apple2ee;flop1; -apple2gs;apple2gs;flop3; -arcadia;arcadia;cart; -archimedes;aa4401;flop; -astrocade;astrocde;cart; -atom;atom;flop1;'\n*DOS\n*DIR\n*CAT\n*RUN"' -bbcmicro;bbcb;flop1; -pcw;pcw8256;flop; -bk;bk001001;cass;'LOAD\n' -camplynx;lynx48k;cass;'mload""' -loopy;casloopy;cart; -cdi;cdimono1;cdrm; -cgenie;cgenie;cass;'\n\nCLOAD\n' -coco;coco3;cart; -dragon64;dragon64;cart; -mc10;mc10;cass;'CLOAD\n' -crvision;crvision;cart; -ctvboy;ctvboy;cart; -electron;electron64;cass;'*T.\nCH.""\n' -enterprise;ep128;flop; -tvc;tvc64p;cass;'LOAD\n' -fm7;fm7;flop1; -fmtowns;fmtmarty;cdrm; -gamate;gamate;cart; -gameandwatch;;; -gamecom;gamecom;cart1; -gamepock;gamepock;cart; -gmaster;gmaster;cart; -gp32;gp32;memc; -laser310;laser310;dump; -lcdgames;;; -macintosh;maclc3;flop1; -megaduck;megaduck;cart; -mz2000;mz2000;cass;'L\n' -mz2500;mz2500;flop1; -mz700;mz700;cass;'L\n' -mz800;mz800;cass;'L\n' -mz80k;mz80k;cass;'L\n' -oricatmos;orica;cass;'\nCLOAD\"\"\n' -pc60;pc6001;cart1; -pdp1;pdp1;ptap1; -pv1000;pv1000;cart; -pv2000;pv2000;cart; -pc80;pc8001mk2sr;flop1; -rx78;rx78;cart; -samcoupe;samcoupe;flop1; -sc3000;sc3000;cart; -segaai;segaai;card; -socrates;socrates;cart; -sv8000;sv8000;cart; -supracan;supracan;cart; -ti99;ti99_4a;cart; -trs80;trs80m3;quik; -tutor;tutor;cart; -tvgames;;; -uzebox;uzebox;cart; -vc4000;vc4000;cart; -vectrex;vectrex;cart; -vgmplay;vgmplay;quik; -vsmile;vsmile;cart; -xegs;xegs;cart; diff --git a/package/batocera/core/batocera-configgen/data/mame/messSystems.json b/package/batocera/core/batocera-configgen/data/mame/messSystems.json new file mode 100644 index 00000000000..b0487876498 --- /dev/null +++ b/package/batocera/core/batocera-configgen/data/mame/messSystems.json @@ -0,0 +1,345 @@ +{ + "adam": { + ".ddp": "adam_cass", + ".dsk": "adam_flop", + "*": "adam" + }, + "advision": { + ".bin": "advision", + "*": "advision" + }, + "apfm1000": { + ".bin": "apfm1000", + ".rom": "apfm1000", + "*": "apfm1000" + }, + "apple2": { + "*": "apple2" + }, + "apple2gs": { + "*": "apple2gs" + }, + "aquarius": { + ".caq": "aquarius_cass", + ".bin": "aquarius_cart", + ".rom": "aquarius_cart", + "*": "aquarius_cart" + }, + "arcadia": { + ".bin": "arcadia", + "*": "arcadia" + }, + "archimedes": { + ".adf": "archimedes", + ".apd": "archimedes", + "*": "archimedes" + }, + "astrocade": { + ".bin": "astrocde", + "*": "astrocde" + }, + "atom": { + ".1dd": "atom_flop", + ".40t": "atom_flop", + ".cqi": "atom_flop", + ".cqm": "atom_flop", + ".d77": "atom_flop", + ".d88": "atom_flop", + ".dfi": "atom_flop", + ".dsk": "atom_flop", + ".hfe": "atom_flop", + ".imd": "atom_flop", + ".mfi": "atom_flop", + ".mfm": "atom_flop", + ".td0": "atom_flop", + "*": "atom" + }, + "bbcmicro": { + ".uef": "bbc_cass", + ".adl": "bbcb_flop", + ".ads": "bbcb_flop", + ".dsd": "bbcb_flop", + ".ssd": "bbcb_flop", + "*": "bbcb_flop" + }, + "beena": { + "*": "beena" + }, + "bk": { + ".wav": "bk0010", + "*": "bk0010" + }, + "camplynx": { + ".tap": "camplynx_cass", + "*": "camplynx_cass" + }, + "cdi": { + "*": "cdi" + }, + "cgenie": { + ".cas": "cgenie_cass", + "*": "cgenie_cass" + }, + "coco": { + ".dsk": "coco_flop", + ".cas": "coco_cass", + "*": "coco_cart" + }, + "crvision": { + ".bin": "crvision", + "*": "crvision" + }, + "ctvboy": { + "*": "ctvboy" + }, + "dragon64": { + ".cas": "dragon_cass", + ".wav": "dragon_cass", + ".dmk": "dragon_flop", + ".dsk": "dragon_flop", + ".vdk": "dragon_flop", + ".1": "dragon_cart", + ".2": "dragon_cart", + ".ic1": "dragon_cart", + ".ic2": "dragon_cart", + ".rom": "dragon_cart", + "*": "dragon_cart" + }, + "electron": { + ".uef": "electron_cass", + "*": "electron_cass" + }, + "enterprise": { + "*": "ep128" + }, + "fm7": { + ".t77": "fm7_cass", + "*": "fm7_flop" + }, + "fmtowns": { + "*": "fmtowns_cd" + }, + "gamate": { + ".bin": "gamate", + "*": "gamate" + }, + "gamecom": { + ".bin": "gamecom", + "*": "gamecom" + }, + "gamepock": { + ".bin": "gamepock", + "*": "gamepock" + }, + "gmaster": { + ".bin": "gmaster", + "*": "gmaster" + }, + "gp32": { + ".smc": "gp32", + "*": "gp32" + }, + "laser310": { + "*": "laser310" + }, + "loopy": { + "*": "loopy" + }, + "macintosh": { + ".image": "mac_flop", + ".img": "mac_flop", + "*": "mac_flop" + }, + "mc10": { + ".cas": "mc10", + ".c10": "mc10", + "*": "mc10" + }, + "megaduck": { + ".bin": "megaduck", + "*": "megaduck" + }, + "msx1": { + ".cas": "msx1_cass", + ".wav": "msx1_cass", + ".dmk": "msx1_flop", + ".dsk": "msx1_flop", + ".bin": "msx1_cart", + ".mx1": "msx1_cart", + ".rom": "msx1_cart", + "*": "msx1_cart" + }, + "msx2": { + ".cas": "msx2_cass", + ".dmk": "msx2_flop", + ".dsk": "msx2_flop", + ".bin": "msx2_cart", + ".mx2": "msx2_cart", + ".rom": "msx2_cart", + "*": "msx2_cart" + }, + "msx2+": { + ".dsk": "msx2p_flop", + ".bin": "msx2p_cart", + ".rom": "msx2p_cart", + "*": "msx2p_cart" + }, + "msxturbor": { + ".dsk": "msxr_flop", + ".bin": "msxr_cart", + ".rom": "msxr_cart", + "*": "msxr_cart" + }, + "mtx512": { + ".wav": "mtx_cass", + ".imd": "mtx_flop", + ".rom": "mtx_rom", + "*": "mtx_cass" + }, + "mz2000": { + ".flac": "mz2000_cass", + ".mzt": "mz2000_cass", + ".wav": "mz2000_cass", + "*": "mz2000_cass" + }, + "mz2500": { + ".d88": "mz2500_flop", + ".hdm": "mz2500_flop", + ".mfi": "mz2500_flop", + "*": "mz2500_flop" + }, + "mz700": { + ".mzf": "mz700_cass", + ".wav": "mz700_cass", + "*": "mz700_cass" + }, + "mz800": { + ".mzf": "mz800_cass", + "*": "mz800_cass" + }, + "mz80k": { + ".m12": "mz80k_cass", + ".mzf": "mz80k_cass", + ".wav": "mz80k_cass", + "*": "mz80k_cass" + }, + "oricatmos": { + ".mp3": "oric1_cass", + ".tap": "oric1_cass", + ".wav": "oric1_cass", + "*": "oric1_cass" + }, + "pc60": { + ".12": "pc6001_cart", + ".bin": "pc6001_cart", + ".rom": "pc6001_cart", + "*": "pc6001_cart" + }, + "pc80": { + ".d80": "pc8801_flop", + ".d88": "pc8801_flop", + ".img": "pc8801_flop", + ".mfm": "pc8801_flop", + "*": "pc8801_flop" + }, + "pcw": { + ".dsk": "pcw", + "*": "pcw" + }, + "pdp1": { + "*": "pdp1" + }, + "pv1000": { + ".bin": "pv1000", + ".rom": "pv1000", + "*": "pv1000" + }, + "pv2000": { + ".bin": "pv2000", + ".rom": "pv2000", + "*": "pv2000" + }, + "rx78": { + ".bin": "rx78_cart", + "*": "rx78_cart" + }, + "samcoupe": { + ".dsk": "samcoupe_flop", + ".mgt": "samcoupe_flop", + "*": "samcoupe_flop" + }, + "sc3000": { + ".bin": "sc3000_cart", + ".sg": "sc3000_cart", + ".wav": "sc3000_cass", + "*": "sc3000_cart" + }, + "segaai": { + ".bin": "segaai", + ".flac": "segaai", + "*": "segaai" + }, + "socrates": { + ".u1": "socrates", + "*": "socrates" + }, + "supracan": { + ".bin": "supracan", + "*": "supracan" + }, + "sv8000": { + ".bin": "sv8000", + "*": "sv8000" + }, + "ti99": { + ".rpk": "ti99_cart", + "*": "ti99_cart" + }, + "trs80": { + ".cas": "trs80_cass", + ".wav": "trs80_cass", + ".cmd": "trs80_quik", + "*": "trs80_quik" + }, + "tutor": { + ".bin": "tutor", + ".ic1": "tutor", + ".u1": "tutor", + "*": "tutor" + }, + "tvc": { + ".cas": "tvc_cass", + ".dsk": "tvc_flop", + "*": "tvc_cass" + }, + "uzebox": { + ".bin": "uzebox", + ".uze": "uzebox", + "*": "uzebox" + }, + "vc4000": { + ".bin": "vc4000", + "*": "vc4000" + }, + "vectrex": { + ".bin": "vectrex", + "*": "vectrex" + }, + "vgmplay": { + ".vgm": "vgmplay", + ".vgz": "vgmplay", + ".txt": "vgmplay", + "*": "vgmplay" + }, + "vis": { + "*": "vis" + }, + "vsmile": { + "*": "vsmile" + }, + "xegs": { + ".bin": "xegs", + ".rom": "xegs", + "*": "xegs" + } +} diff --git a/package/batocera/emulationstation/batocera-es-system/es_systems.yml b/package/batocera/emulationstation/batocera-es-system/es_systems.yml index 8e534ee30bd..622b59cd1c6 100644 --- a/package/batocera/emulationstation/batocera-es-system/es_systems.yml +++ b/package/batocera/emulationstation/batocera-es-system/es_systems.yml @@ -625,9 +625,9 @@ sc3000: theme: sc-3000 emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | SC-3000 cartridges are compatible with SG-1000. Cassette tapes (.wav, .cas, .bit) are SC-3000 exclusive. @@ -642,9 +642,9 @@ segaai: theme: segaai emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | BIOS: segaai.zip in bios/mame/ Software on Sega My Cards (.bin) or cassette tapes (.wav, .flac, .cas). @@ -659,9 +659,9 @@ beena: theme: beena emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | BIOS: beena.zip in bios/mame/ Successor to the Sega Pico. Cartridge-based educational console. @@ -1135,9 +1135,9 @@ xegs: group: atari8bit emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires MAME BIOS file xegs.zip Software list mode recommended @@ -1484,9 +1484,9 @@ vectrex: emulators: libretro: vecx: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_VECX] } - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } lutro: @@ -1604,9 +1604,9 @@ pcw: extensions: [mfi, dfi, mfm, td0, imd, 86f, d77, d88, 1dd, cqm, cqi, dsk, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires MAME BIOS files pcw8256.zip (and pcw9512.zip for the 9512 model). Games are floppy disk images (.dsk). Most games are self-booting and don't require a separate system disk. @@ -1626,6 +1626,8 @@ msx1: openmsx: { requireAnyOf: [BR2_PACKAGE_OPENMSX], incompatible_extensions: [m3u] } clk: clk: { requireAnyOf: [BR2_PACKAGE_CLK], incompatible_extensions: [ 7z ] } + mame: + mess: { requireAnyOf: [BR2_PACKAGE_MAME], incompatible_extensions: [ogv, openmsx } comment_en: | ## BIOS ## @@ -1825,6 +1827,8 @@ msx2+: fmsx: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_FMSX], incompatible_extensions: [openmsx] } openmsx: openmsx: { requireAnyOf: [BR2_PACKAGE_OPENMSX], incompatible_extensions: [m3u] } + mame: + mess: { requireAnyOf: [BR2_PACKAGE_MAME], incompatible_extensions: [ogv, openmsx } comment_en: | ## BIOS ## @@ -1922,6 +1926,8 @@ msxturbor: bluemsx: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_BLUEMSX], incompatible_extensions: [openmsx] } openmsx: openmsx: { requireAnyOf: [BR2_PACKAGE_OPENMSX] } + mame: + mess: { requireAnyOf: [BR2_PACKAGE_MAME], incompatible_extensions: [ogv, openmsx } mz2000: name: Sharp MZ-2000 @@ -1931,9 +1937,9 @@ mz2000: extensions: [mzf, mzt, m12, wav, d88, dsk, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires MAME BIOS file mz2000.zip Using software list mode is recommended. @@ -1946,9 +1952,9 @@ mz2500: extensions: [d88, dsk, mfi, dfi, hfe, mfm, td0, imd, d77, 1dd, cqm, cqi, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires MAME BIOS file mz2500.zip Using software list mode is recommended. @@ -1961,9 +1967,9 @@ mz700: extensions: [mzf, mzt, m12, wav, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires MAME BIOS file mz700.zip Using software list mode is recommended. @@ -1976,9 +1982,9 @@ mz800: extensions: [mzf, mzt, m12, wav, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires MAME BIOS file mz800.zip Using software list mode is recommended. @@ -1991,9 +1997,9 @@ mz80k: extensions: [mzf, mzt, m12, wav, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires MAME BIOS file mz80k.zip Using software list mode is recommended. @@ -2046,9 +2052,9 @@ bk: emulators: libretro: bk: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_BK] } - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | BK-0010/0011 was a Soviet home computer series from Elektronika. Supports BK-0010, BK-0010.01, BK-0011(M) and Terak 8510/a emulation. @@ -2143,10 +2149,10 @@ apple2: extensions: [nib, do, po, dsk, mfi, dfi, rti, edd, woz, wav, zip, 7z, chd, hdv, 2mg] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } applewin: { requireAnyOf: [BR2_PACKAGE_APPLEWIN] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } gsplus: gsplus: { requireAnyOf: [BR2_PACKAGE_GSPLUS], incompatible_extensions: [mfi, dfi, rti, edd, woz, wav, zip, 7z, chd, hdv, 2mg] } applewin: @@ -2622,9 +2628,9 @@ fmtowns: platform: fmtowns emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME], incompatible_extensions: [xdf, m3u] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME], incompatible_extensions: [xdf, m3u] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME], incompatible_extensions: [xdf, m3u] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME], incompatible_extensions: [xdf, m3u] } tsugaru: tsugaru: { requireAnyOf: [BR2_PACKAGE_TSUGARU], incompatible_extensions: [chd, toc, nrg, gdi, cdr, mfi, dfi, hfe, mfm, td0, imd, 1dd, cqm, cqi, dsk, zip, 7z] } @@ -3296,9 +3302,9 @@ uzebox: emulators: libretro: uzem: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_UZEM], incompatible_extensions: [bin, zip] } - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } cdi: name: CD-i @@ -3309,9 +3315,9 @@ cdi: emulators: libretro: same_cdi: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_SAME_CDI], incompatible_extensions: [cue, toc, nrg, gdi, cdr] } - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires MAME BIOS file cdimono1.zip comment_br: | @@ -3325,9 +3331,9 @@ advision: extensions: [bin, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires MAME BIOS file advision.zip comment_br: | @@ -3353,10 +3359,10 @@ megaduck: extensions: [bin, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } sameduck: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_SAMEDUCK] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } pv1000: name: PV-1000 @@ -3366,9 +3372,9 @@ pv1000: extensions: [bin, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } pv2000: name: PV-2000 @@ -3378,9 +3384,9 @@ pv2000: extensions: [bin, cas, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires MAME BIOS file pv2000.zip comment_br: | @@ -3394,9 +3400,9 @@ pc80: extensions: [d77, d88, 1dd, dsk, n80, bin, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires MAME BIOS file pc8001mk2sr.zip comment_br: | @@ -3410,9 +3416,9 @@ gamate: extensions: [bin, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires MAME BIOS file gamate.zip comment_br: | @@ -3427,9 +3433,9 @@ crvision: extensions: [bin, rom, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires MAME BIOS file crvision.zip comment_br: | @@ -3443,9 +3449,9 @@ ctvboy: extensions: [bin, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | MAME 0.262+ required @@ -3457,9 +3463,9 @@ laser310: extensions: [vz, wav, cas, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires MAME BIOS file laser310.zip Using snapshot (.vz) files is recommended. @@ -3475,9 +3481,9 @@ socrates: extensions: [bin, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires MAME BIOS file socrates.zip Software list mode recommended @@ -3509,9 +3515,9 @@ supracan: extensions: [bin, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Sound support is preliminary comment_br: | @@ -3525,9 +3531,9 @@ gamecom: extensions: [bin, tgc, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires MAME BIOS file gamecom.zip comment_br: | @@ -3541,9 +3547,9 @@ gamepock: extensions: [bin, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires MAME BIOS file gamepock.zip comment_br: | @@ -3557,9 +3563,9 @@ fm7: extensions: [wav, t77, mfi, dfi, hfe, mfm, td0, imd, d77, d88, 1dd, cqm, cqi, dsk, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires MAME BIOS file fm7.zip, and optionally fm77av.zip for FM-77AV support. comment_br: | @@ -3574,9 +3580,9 @@ archimedes: extensions: [mfi, dfi, hfe, mfm, td0, imd, d77, d88, 1dd, cqm, cqi, dsk, ima, img, ufi, 360, ipf, adf, apd, jfd, ads, adm, adl, ssd, bbc, dsd, st, msa, chd, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } clk: clk: { requireAnyOf: [BR2_PACKAGE_CLK], incompatible_extensions: [ 7z ] } comment_en: | @@ -3596,9 +3602,9 @@ atom: extensions: [wav, tap, csw, uef, mfi, dfi, hfe, mfm, td0, imd, d77, d88, 1dd, cqm, cqi, dsk, 40t, atm, bin, rom, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires MAME BIOS file atom.zip Using software list mode is recommended. Software list cassettes don't work but floppies do. @@ -3616,9 +3622,9 @@ electron: extensions: [wav, csw, uef, mfi, dfi, hfe, mfm, td0, imd, d77, d88, 1dd, cqm, cqi, dsk, ssd, bbc, img, dsd, adf, ads, adm, adl, rom, bin, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } clk: clk: { requireAnyOf: [BR2_PACKAGE_CLK], incompatible_extensions: [ 7z ] } comment_en: | @@ -3638,9 +3644,9 @@ apfm1000: extensions: [bin, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires MAME BIOS file apfm1000.zip comment_br: | @@ -3655,9 +3661,9 @@ bbcmicro: extensions: [mfi, dfi, hfe, mfm, td0, imd, d77, d88, 1dd, cqm, cqi, dsk, ima, img, ufi, 360, ipf, ssd, bbc, dsd, adf, ads, adm, adl, fsd, wav, tap, bin, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } clk: clk: { requireAnyOf: [BR2_PACKAGE_CLK] } comment_en: | @@ -3676,9 +3682,9 @@ camplynx: extensions: [wav, tap, ldf, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires MAME BIOS files lynx128k.zip, lynx96k.zip, lynx48k.zip Using software list mode is recommended. @@ -3694,9 +3700,9 @@ adam: extensions: [wav, ddp, mfi, dfi, hfe, mfm, td0, imd, d77, d88, 1dd, cqm, cqi, dsk, rom, col, bin, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires the following MAME BIOS files: adam.zip, adam_ddp.zip, adam_fdc.zip, adam_kb.zip, & adam_prn.zip @@ -3712,9 +3718,9 @@ arcadia: extensions: [bin, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } sv8000: name: Super Vision 8000 @@ -3724,9 +3730,9 @@ sv8000: extensions: [bin, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } gmaster: name: Game Master @@ -3736,9 +3742,9 @@ gmaster: extensions: [bin, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires MAME BIOS file gmaster.zip comment_br: | @@ -3753,9 +3759,9 @@ astrocade: extensions: [bin, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires MAME BIOS file astrocde.zip comment_br: | @@ -3769,9 +3775,9 @@ ti99: extensions: [rpk, wav, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires MAME BIOS file ti99_4a.zip Cartridges need to be in .rpk format and unzipped if not using software lists. @@ -3787,9 +3793,9 @@ tutor: extensions: [bin, wav, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires MAME BIOS file tutor.zip To get through the loading menu, R1 will move down and A/East will select. @@ -3805,9 +3811,9 @@ coco: extensions: [wav, cas, dsk, ccc, rom, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } xroar: xroar: { requireAnyOf: [BR2_PACKAGE_XROAR] } comment_en: | @@ -3841,9 +3847,9 @@ cgenie: extensions: [cas, wav, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | MAME requires BIOS file cgenie.zip comment_br: | @@ -3857,9 +3863,9 @@ dragon64: extensions: [wav, cas, dsk, dmk, ccc, rom, bin, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } xroar: xroar: { requireAnyOf: [BR2_PACKAGE_XROAR] } comment_en: | @@ -3890,9 +3896,9 @@ mc10: extensions: [wav, cas, rom, bin, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } xroar: xroar: { requireAnyOf: [BR2_PACKAGE_XROAR] } comment_en: | @@ -3909,9 +3915,9 @@ trs80: extensions: [cmd, cas, dsk, dmk, bas, wav, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | MAME requires BIOS file trs80.zip (Model I), trs80m3.zip (Model III), or trs80m4.zip (Model 4) @@ -3938,9 +3944,9 @@ vc4000: extensions: [bin, rom, pgm, tvc, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } vgmplay: name: Video Game Music Player @@ -3950,9 +3956,9 @@ vgmplay: extensions: [vgm, vgz, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Software lists recommended. QSound can be CPU-intensive. Use the File Manager in the MAME menu to change tracks. @@ -4154,9 +4160,9 @@ samcoupe: samcoupe: samcoupe: { requireAnyOf: [BR2_PACKAGE_SIMCOUPE] } libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mes: { requireAnyOf: [BR2_PACKAGE_MAME] } abuse: name: Abuse @@ -4225,9 +4231,9 @@ macintosh: emulators: libretro: minivmac: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MINIVMAC], incompatible_extensions: [7z, mfi, dfi, hfe, mfm, td0, imd, d77, d88, 1dd, cqm, cqi, dsk, ima, img, ufi, ipf, dc42, woz, 2mg, 360, chd, cue, toc, nrg, gdi, iso, cdr, hd, hdv, 2mg, hdi] } - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } clk: clk: { requireAnyOf: [BR2_PACKAGE_CLK], incompatible_extensions: [ 7z ] } comment_en: | @@ -4528,9 +4534,9 @@ pdp1: extensions: [zip, 7z, tap, rim, drm] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Use Control-Enter or Start to start after loading. Loading may take some time, if the green lights are blinking, it is loading. @@ -4606,9 +4612,9 @@ gp32: extensions: [smc, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires MAME BIOS file gp32.zip comment_br: | @@ -5295,7 +5301,9 @@ vis: extensions: [chd, cue, toc, nrg, gdi, iso, cdr] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mame: + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } vpinball: name: Visual Pinball X @@ -5757,9 +5765,9 @@ rx78: extensions: [bin, zip, 7z] emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } commanderx16: name: Commander X16 @@ -5973,9 +5981,9 @@ oricatmos: clk: clk: { requireAnyOf: [BR2_PACKAGE_CLK] } libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Emulator for Oric Atmos (and Oric 1) @@ -6168,9 +6176,9 @@ loopy: theme: loopy emulators: libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires MAME BIOS file: bios/mame/casloopy.zip @@ -6189,9 +6197,9 @@ pc60: extensions: [bin, cas, p6, d77, d88, dsk, 1dd, mfi, dfi, mfm, td0, imd, cqm, cqi, xdf, hdm, 2hd, fdi, zip, 7z] emulators: mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } libretro: - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } comment_en: | Requires MAME BIOS files (depending on model): bios/pc6001.zip (PC-6001) @@ -6218,9 +6226,9 @@ enterprise: clk: { requireAnyOf: [BR2_PACKAGE_CLK], incompatible_extensions: [img,dsk,tap,dtf,trn,128,cas,cdt,tzx] } libretro: ep128emu-core: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_EP128EMU_CORE] } - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires ep128emu BIOS files: bios/ep128emu/roms/exos21.rom (Expandible OS 2.1) @@ -6262,9 +6270,9 @@ tvc: emulators: libretro: ep128emu-core: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_EP128EMU_CORE] } - mame: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_LIBRETRO_MAME] } mame: - mame: { requireAnyOf: [BR2_PACKAGE_MAME] } + mess: { requireAnyOf: [BR2_PACKAGE_MAME] } comment_en: | Requires ep128emu BIOS files: bios/ep128emu/roms/tvc22_sys.rom (TVC system BIOS)