# Standard Library import os from gettext import gettext as _ # Lutris Modules from lutris import settings from lutris.exceptions import GameConfigError, MisconfigurationError, MissingExecutableError, MissingGameExecutableError from lutris.runners.runner import Runner from lutris.util import system from lutris.util.log import logger class vice(Runner): description = _("Commodore Emulator") human_name = _("Vice") # flatpak_id = "net.sf.VICE" # needs adjustments platforms = [ _("Commodore 64"), _("Commodore 128"), _("Commodore VIC20"), _("Commodore PET"), _("Commodore Plus/4"), _("Commodore CBM II"), ] machine_choices = [ ("C64", "c64"), ("C128", "c128"), ("vic20", "vic20"), ("PET", "pet"), ("Plus/4", "plus4"), ("CBM-II", "cbmii"), ] game_options = [ { "option": "main_file", "type": "file", "label": _("ROM file"), "help": _( "The game data, commonly called a ROM image.\n" "Supported formats: X64, D64, G64, P64, D67, D71, D81, " "D80, D82, D1M, D2M, D4M, T46, P00 and CRT." ), } ] runner_options = [ {"option": "joy", "type": "bool", "label": _("Use joysticks"), "default": False}, { "option": "fullscreen", "type": "bool", "section": _("Graphics"), "label": _("Fullscreen"), "default": False, }, { "option": "double", "type": "bool", "section": _("Graphics"), "label": _("Scale up display by 2"), "default": True, }, { "option": "aspect_ratio", "type": "bool", "section": _("Graphics"), "label": _("Preserve aspect ratio"), "default": True, }, { "option": "renderer", "type": "choice", "section": _("Graphics"), "label": _("Graphics renderer"), "choices": [("OpenGL", "opengl"), (_("Software"), "software")], "default": "opengl", }, { "option": "drivesound", "type": "bool", "label": _("Enable sound emulation of disk drives"), "default": False, }, { "option": "machine", "type": "choice", "label": _("Machine"), "choices": machine_choices, "default": "c64", }, ] def get_platform(self): machine = self.game_config.get("machine") if machine: for index, choice in enumerate(self.machine_choices): if choice[1] == machine: return self.platforms[index] return self.platforms[0] # Default to C64 def get_executable(self, machine: str = None) -> str: if not machine: machine = "c64" executables = { "c64": "x64", "c128": "x128", "vic20": "xvic", "pet": "xpet", "plus4": "xplus4", "cbmii": "xcbm2", } try: executable = executables[machine] exe = os.path.join(settings.RUNNER_DIR, "vice/bin/%s" % executable) if not os.path.isfile(exe): raise MissingExecutableError(_("The executable '%s' could not be found.") % exe) return exe except KeyError as ex: raise MisconfigurationError("Invalid machine '%s'" % machine) from ex def install(self, install_ui_delegate, version=None, callback=None): def on_runner_installed(*args): config_path = system.create_folder("~/.vice") lib_dir = os.path.join(settings.RUNNER_DIR, "vice/lib/vice") if not system.path_exists(lib_dir): lib_dir = os.path.join(settings.RUNNER_DIR, "vice/lib64/vice") if not system.path_exists(lib_dir): logger.error("Missing lib folder in the Vice runner") else: system.merge_folders(lib_dir, config_path) if callback: callback() super().install(install_ui_delegate, version, on_runner_installed) def get_roms_path(self, machine=None): if not machine: machine = "c64" paths = { "c64": "C64", "c128": "C128", "vic20": "VIC20", "pet": "PET", "plus4": "PLUS4", "cmbii": "CBM-II", } root_dir = os.path.dirname(os.path.dirname(self.get_executable())) return os.path.join(root_dir, "lib64/vice", paths[machine]) @staticmethod def get_option_prefix(machine): prefixes = { "c64": "VICII", "c128": "VICII", "vic20": "VIC", "pet": "CRTC", "plus4": "TED", "cmbii": "CRTC", } return prefixes[machine] @staticmethod def get_joydevs(machine): joydevs = {"c64": 2, "c128": 2, "vic20": 1, "pet": 0, "plus4": 2, "cmbii": 0} return joydevs[machine] @staticmethod def get_rom_args(machine, rom): args = [] if rom.endswith(".crt"): crt_option = { "c64": "-cartcrt", "c128": "-cartcrt", "vic20": "-cartgeneric", "pet": None, "plus4": "-cart", "cmbii": None, } if crt_option[machine]: args.append(crt_option[machine]) args.append(rom) return args def play(self): machine = self.runner_config.get("machine") rom = self.game_config.get("main_file") if not rom: raise GameConfigError(_("No rom provided")) if not system.path_exists(rom): raise MissingGameExecutableError(filename=rom) params = [self.get_executable(machine)] rom_dir = os.path.dirname(rom) params.append("-chdir") params.append(rom_dir) option_prefix = self.get_option_prefix(machine) if self.runner_config.get("fullscreen"): params.append("-{}full".format(option_prefix)) if self.runner_config.get("double"): params.append("-{}dsize".format(option_prefix)) if self.runner_config.get("renderer"): params.append("-sdl2renderer") params.append(self.runner_config["renderer"]) if not self.runner_config.get("aspect_ratio", True): params.append("-sdlaspectmode") params.append("0") if self.runner_config.get("drivesound"): params.append("-drivesound") if self.runner_config.get("joy"): for dev in range(self.get_joydevs(machine)): params += ["-joydev{}".format(dev + 1), "4"] params.extend(self.get_rom_args(machine, rom)) return {"command": params}