def start(): args = parse_arguments(None) if is_bundled() and len(sys.argv) == 1: # for the bundled builds, if we have no arguments, the user # probably wants the gui. Users of the bundled build who want the command line # interface shouuld specify at least one option, possibly setting a value to a # default if they like all the defaults from Gui import guiMain close_console() guiMain() sys.exit(0) # ToDo: Validate files further than mere existance if not args.jsonout and not os.path.isfile(args.rom): input( 'Could not find valid base rom for patching at expected path %s. Please run with -h to see help for further information. \nPress Enter to exit.' % args.rom) sys.exit(1) if any([ sprite is not None and not os.path.isfile(sprite) and not get_sprite_from_name(sprite) for sprite in args.sprite.values() ]): if not args.jsonout: input( 'Could not find link sprite sheet at given location. \nPress Enter to exit.' ) sys.exit(1) else: raise IOError('Cannot find sprite file at %s' % args.sprite) # set up logger loglevel = { 'error': logging.ERROR, 'info': logging.INFO, 'warning': logging.WARNING, 'debug': logging.DEBUG }[args.loglevel] logging.basicConfig(format='%(message)s', level=loglevel) if args.gui: from Gui import guiMain guiMain(args) elif args.count is not None: seed = args.seed for _ in range(args.count): main(seed=seed, args=args) seed = random.randint(0, 999999999) else: main(seed=args.seed, args=args)
def start(): parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('--create_spoiler', help='Output a Spoiler File', action='store_true') parser.add_argument('--ignore_unsolvable', help='Do not abort if seed is deemed unsolvable.', action='store_true') parser.add_argument('--rom', default='Zelda no Densetsu - Kamigami no Triforce (Japan).sfc', help='Path to an ALttP JAP(1.0) rom to use as a base.') parser.add_argument('--loglevel', default='info', const='info', nargs='?', choices=['error', 'info', 'warning', 'debug'], help='Select level of logging for output.') parser.add_argument('--seed', help='Define seed number to generate.', type=int) parser.add_argument('--fastmenu', default='normal', const='normal', nargs='?', choices=['normal', 'instant', 'double', 'triple', 'quadruple', 'half'], help='''\ Select the rate at which the menu opens and closes. (default: %(default)s) ''') parser.add_argument('--quickswap', help='Enable quick item swapping with L and R.', action='store_true') parser.add_argument('--disablemusic', help='Disables game music.', action='store_true') parser.add_argument('--heartbeep', default='normal', const='normal', nargs='?', choices=['normal', 'half', 'quarter', 'off'], help='Select the rate at which the heart beep sound is played at low health.') parser.add_argument('--heartcolor', default='red', const='red', nargs='?', choices=['red', 'blue', 'green', 'yellow'], help='Select the color of Link\'s heart meter. (default: %(default)s)') parser.add_argument('--ow_palettes', default='default', choices=['default', 'random', 'blackout']) parser.add_argument('--uw_palettes', default='default', choices=['default', 'random', 'blackout']) parser.add_argument('--sprite', help='Path to a sprite sheet to use for Link. Needs to be in binary format and have a length of 0x7000 (28672) bytes.') parser.add_argument('--plando', help='Filled out template to use for setting up the rom.') args = parser.parse_args() # ToDo: Validate files further than mere existance if not os.path.isfile(args.rom): input('Could not find valid base rom for patching at expected path %s. Please run with -h to see help for further information. \nPress Enter to exit.' % args.rom) sys.exit(1) if not os.path.isfile(args.plando): input('Could not find Plandomizer distribution at expected path %s. Please run with -h to see help for further information. \nPress Enter to exit.' % args.plando) sys.exit(1) if args.sprite is not None and not os.path.isfile(args.sprite) and not get_sprite_from_name(args.sprite): input('Could not find link sprite sheet at given location. \nPress Enter to exit.') sys.exit(1) # set up logger loglevel = {'error': logging.ERROR, 'info': logging.INFO, 'warning': logging.WARNING, 'debug': logging.DEBUG}[args.loglevel] logging.basicConfig(format='%(message)s', level=loglevel) main(args=args)
def main(args=None): if not args: args = mystery_argparse() seed = get_seed(args.seed) random.seed(seed) seedname = "M" + (f"{random.randint(0, pow(10, seeddigits) - 1)}".zfill(seeddigits)) print(f"Generating mystery for {args.multi} player{'s' if args.multi > 1 else ''}, {seedname} Seed {seed}") weights_cache = {} if args.weights: try: weights_cache[args.weights] = get_weights(args.weights) except Exception as e: raise ValueError(f"File {args.weights} is destroyed. Please fix your yaml.") from e print(f"Weights: {args.weights} >> {get_choice('description', weights_cache[args.weights], 'No description specified')}") if args.meta: try: weights_cache[args.meta] = get_weights(args.meta) except Exception as e: raise ValueError(f"File {args.meta} is destroyed. Please fix your yaml.") from e meta_weights = weights_cache[args.meta] print(f"Meta: {args.meta} >> {get_choice('meta_description', meta_weights, 'No description specified')}") if args.samesettings: raise Exception("Cannot mix --samesettings with --meta") for player in range(1, args.multi + 1): path = getattr(args, f'p{player}') if path: try: if path not in weights_cache: weights_cache[path] = get_weights(path) print(f"P{player} Weights: {path} >> {get_choice('description', weights_cache[path], 'No description specified')}") except Exception as e: raise ValueError(f"File {path} is destroyed. Please fix your yaml.") from e erargs = parse_arguments(['--multi', str(args.multi)]) erargs.seed = seed erargs.name = {x: "" for x in range(1, args.multi + 1)} # only so it can be overwrittin in mystery erargs.create_spoiler = args.create_spoiler erargs.race = args.race erargs.skip_playthrough = args.skip_playthrough erargs.outputname = seedname erargs.outputpath = args.outputpath erargs.teams = args.teams erargs.progression_balancing = {} # set up logger if args.loglevel: erargs.loglevel = args.loglevel loglevel = {'error': logging.ERROR, 'info': logging.INFO, 'warning': logging.WARNING, 'debug': logging.DEBUG}[erargs.loglevel] import sys class LoggerWriter(object): def __init__(self, writer): self._writer = writer self._msg = '' def write(self, message): self._msg = self._msg + message while '\n' in self._msg: pos = self._msg.find('\n') self._writer(self._msg[:pos]) self._msg = self._msg[pos + 1:] def flush(self): if self._msg != '': self._writer(self._msg) self._msg = '' if args.log_output_path: log = logging.getLogger("stderr") log.addHandler(logging.StreamHandler()) sys.stderr = LoggerWriter(log.error) os.makedirs(args.log_output_path, exist_ok=True) logging.basicConfig(format='%(message)s', level=loglevel, filename=os.path.join(args.log_output_path, f"{seed}.log")) else: logging.basicConfig(format='%(message)s', level=loglevel) if args.rom: erargs.rom = args.rom if args.enemizercli: erargs.enemizercli = args.enemizercli settings_cache = {k: (roll_settings(v) if args.samesettings else None) for k, v in weights_cache.items()} player_path_cache = {} for player in range(1, args.multi + 1): player_path_cache[player] = getattr(args, f'p{player}') if getattr(args, f'p{player}') else args.weights if args.meta: for player, path in player_path_cache.items(): weights_cache[path].setdefault("meta_ignore", []) meta_weights = weights_cache[args.meta] for key in meta_weights: option = get_choice(key, meta_weights) if option is not None: for player, path in player_path_cache.items(): players_meta = weights_cache[path].get("meta_ignore", []) if key not in players_meta: weights_cache[path][key] = option elif type(players_meta) == dict and players_meta[key] and option not in players_meta[key]: weights_cache[path][key] = option for player in range(1, args.multi + 1): path = player_path_cache[player] if path: try: settings = settings_cache[path] if settings_cache[path] else roll_settings(weights_cache[path]) if settings.sprite is not None and not os.path.isfile(settings.sprite) and not get_sprite_from_name(settings.sprite): logging.warning( f"Warning: The chosen sprite, \"{settings.sprite}\", for yaml \"{path}\", does not exist.") for k, v in vars(settings).items(): if v is not None: getattr(erargs, k)[player] = v except Exception as e: raise ValueError(f"File {path} is destroyed. Please fix your yaml.") from e else: raise RuntimeError(f'No weights specified for player {player}') if not erargs.name[player]: erargs.name[player] = os.path.split(path)[-1].split(".")[0] if args.weights: erargs.names = "" else: erargs.names = ",".join(erargs.name[i] for i in range(1, args.multi + 1)) del (erargs.name) if args.yaml_output: import yaml important = {} for option, player_settings in vars(erargs).items(): if type(player_settings) == dict: if len(set(player_settings.values())) > 1: important[option] = {player: value for player, value in player_settings.items() if player <= args.yaml_output} elif len(set(player_settings.values())) > 0: important[option] = player_settings[1] else: logging.debug(f"No player settings defined for option '{option}'") else: if player_settings != "": # is not empty name important[option] = player_settings else: logging.debug(f"No player settings defined for option '{option}'") if args.outputpath: os.makedirs(args.outputpath, exist_ok=True) with open(os.path.join(args.outputpath if args.outputpath else ".", f"mystery_result_{seed}.yaml"), "wt") as f: yaml.dump(important, f) erargs.skip_progression_balancing = {player: not balanced for player, balanced in erargs.progression_balancing.items()} del (erargs.progression_balancing) ERmain(erargs, seed)
def main(): parser = argparse.ArgumentParser( formatter_class=ArgumentDefaultsHelpFormatter) parser.add_argument('--rom', default='ER_base.sfc', help='Path to an ALttPR rom to adjust.') parser.add_argument( '--baserom', default='Zelda no Densetsu - Kamigami no Triforce (Japan).sfc', help='Path to an ALttP JAP(1.0) rom to use as a base.') parser.add_argument('--loglevel', default='info', const='info', nargs='?', choices=['error', 'info', 'warning', 'debug'], help='Select level of logging for output.') parser.add_argument( '--fastmenu', default='normal', const='normal', nargs='?', choices=['normal', 'instant', 'double', 'triple', 'quadruple', 'half'], help='''\ Select the rate at which the menu opens and closes. (default: %(default)s) ''') parser.add_argument('--quickswap', help='Enable quick item swapping with L and R.', action='store_true') parser.add_argument('--disablemusic', help='Disables game music.', action='store_true') parser.add_argument('--heartbeep', default='normal', const='normal', nargs='?', choices=['double', 'normal', 'half', 'quarter', 'off'], help='''\ Select the rate at which the heart beep sound is played at low health. (default: %(default)s) ''') parser.add_argument( '--heartcolor', default='red', const='red', nargs='?', choices=['red', 'blue', 'green', 'yellow', 'random'], help='Select the color of Link\'s heart meter. (default: %(default)s)') parser.add_argument('--ow_palettes', default='default', choices=['default', 'random', 'blackout']) parser.add_argument('--uw_palettes', default='default', choices=['default', 'random', 'blackout']) parser.add_argument('--sprite', help='''\ Path to a sprite sheet to use for Link. Needs to be in binary format and have a length of 0x7000 (28672) bytes, or 0x7078 (28792) bytes including palette data. Alternatively, can be a ALttP Rom patched with a Link sprite that will be extracted. ''') parser.add_argument('--names', default='', type=str) args = parser.parse_args() # ToDo: Validate files further than mere existance if not os.path.isfile(args.rom): input( 'Could not find valid rom for patching at expected path %s. Please run with -h to see help for further information. \nPress Enter to exit.' % args.rom) sys.exit(1) if args.sprite is not None and not os.path.isfile( args.sprite) and not get_sprite_from_name(args.sprite): input( 'Could not find link sprite sheet at given location. \nPress Enter to exit.' ) sys.exit(1) # set up logger loglevel = { 'error': logging.ERROR, 'info': logging.INFO, 'warning': logging.WARNING, 'debug': logging.DEBUG }[args.loglevel] logging.basicConfig(format='%(message)s', level=loglevel) args, path = adjust(args=args) from Utils import persistent_store persistent_store("adjuster", "last_settings", args)
def loadcliargs(gui, args, settings=None): if args is not None: # for k, v in vars(args).items(): # if type(v) is dict: # setattr(args, k, v[1]) # only get values for player 1 for now # load values from commandline args # set up options to get # Page::Subpage::GUI-id::param-id options = CONST.SETTINGSTOPROCESS for mainpage in options: for subpage in options[mainpage]: for widget in options[mainpage][subpage]: arg = options[mainpage][subpage][widget] gui.pages[mainpage].pages[subpage].widgets[ widget].storageVar.set(args[arg]) if subpage == "gameoptions" and not widget == "hints": hasSettings = settings is not None hasWidget = ( "adjust." + widget) in settings if hasSettings else None if hasWidget is None: gui.pages["adjust"].content.widgets[ widget].storageVar.set(args[arg]) gui.pages["randomizer"].pages["enemizer"].enemizerCLIpathVar.set( args["enemizercli"]) gui.pages["randomizer"].pages["generation"].romVar.set(args["rom"]) if args["multi"]: gui.pages["randomizer"].pages["multiworld"].widgets[ "worlds"].storageVar.set(str(args["multi"])) if args["seed"]: gui.frames["bottom"].seedVar.set(str(args["seed"])) if args["count"]: gui.frames["bottom"].widgets["generationcount"].storageVar.set( str(args["count"])) gui.outputPath.set(args["outputpath"]) def sprite_setter(spriteObject): gui.pages["randomizer"].pages["gameoptions"].widgets["sprite"][ "spriteObject"] = spriteObject if args["sprite"] is not None: sprite_obj = args.sprite if isinstance( args["sprite"], Sprite) else get_sprite_from_name( args["sprite"]) set_sprite(sprite_obj, False, spriteSetter=sprite_setter, spriteNameVar=gui.pages["randomizer"]. pages["gameoptions"].widgets["sprite"]["spriteNameVar"], randomSpriteVar=gui.randomSprite) def sprite_setter_adj(spriteObject): gui.pages["adjust"].content.sprite = spriteObject if args["sprite"] is not None: sprite_obj = args.sprite if isinstance( args["sprite"], Sprite) else get_sprite_from_name( args["sprite"]) set_sprite( sprite_obj, False, spriteSetter=sprite_setter_adj, spriteNameVar=gui.pages["adjust"].content.spriteNameVar2, randomSpriteVar=gui.randomSprite)
def start(): args = parse_arguments(None) if is_bundled() and len(sys.argv) == 1: # for the bundled builds, if we have no arguments, the user # probably wants the gui. Users of the bundled build who want the command line # interface shouuld specify at least one option, possibly setting a value to a # default if they like all the defaults from Gui import guiMain close_console() guiMain() sys.exit(0) # ToDo: Validate files further than mere existance if not args.jsonout and not os.path.isfile(args.rom): input( 'Could not find valid base rom for patching at expected path %s. Please run with -h to see help for further information. \nPress Enter to exit.' % args.rom) sys.exit(1) if any([ sprite is not None and not os.path.isfile(sprite) and not get_sprite_from_name(sprite) for sprite in args.sprite.values() ]): if not args.jsonout: input( 'Could not find link sprite sheet at given location. \nPress Enter to exit.' ) sys.exit(1) else: raise IOError('Cannot find sprite file at %s' % args.sprite) # set up logger loglevel = { 'error': logging.ERROR, 'info': logging.INFO, 'warning': logging.WARNING, 'debug': logging.DEBUG }[args.loglevel] logging.basicConfig(format='%(message)s', level=loglevel) if args.gui: from Gui import guiMain guiMain(args) elif args.count is not None: seed = args.seed or random.randint(0, 999999999) failures = [] logger = logging.getLogger('') for _ in range(args.count): try: main(seed=seed, args=args) logger.info('Finished run %s', _ + 1) except (FillError, Exception, RuntimeError) as err: failures.append((err, seed)) logger.warning('Generation failed: %s', err) seed = random.randint(0, 999999999) for fail in failures: logger.info('%s seed failed with: %s', fail[1], fail[0]) fail_rate = 100 * len(failures) / args.count success_rate = 100 * (args.count - len(failures)) / args.count fail_rate = str(fail_rate).split('.') success_rate = str(success_rate).split('.') logger.info('Generation fail rate: ' + str(fail_rate[0]).rjust(3, " ") + '.' + str(fail_rate[1]).ljust(6, '0') + '%') logger.info('Generation success rate: ' + str(success_rate[0]).rjust(3, " ") + '.' + str(success_rate[1]).ljust(6, '0') + '%') else: main(seed=args.seed, args=args)
def main(): parser = argparse.ArgumentParser(add_help=False) parser.add_argument('--multi', default=1, type=lambda value: min(max(int(value), 1), 255)) multiargs, _ = parser.parse_known_args() parser = argparse.ArgumentParser() parser.add_argument( '--weights', help= 'Path to the weights file to use for rolling game settings, urls are also valid' ) parser.add_argument( '--samesettings', help='Rolls settings per weights file rather than per player', action='store_true') parser.add_argument('--seed', help='Define seed number to generate.', type=int) parser.add_argument('--multi', default=1, type=lambda value: min(max(int(value), 1), 255)) parser.add_argument('--teams', default=1, type=lambda value: max(int(value), 1)) parser.add_argument('--create_spoiler', action='store_true') parser.add_argument('--skip_playthrough', action='store_true') parser.add_argument('--rom') parser.add_argument('--enemizercli') parser.add_argument('--outputpath') parser.add_argument('--race', action='store_true') parser.add_argument('--meta', default=None) parser.add_argument('--log_output_path', help='Path to store output log') parser.add_argument('--loglevel', default='info', help='Sets log level') parser.add_argument( '--yaml_output', default=0, type=lambda value: min(max(int(value), 0), 255), help= 'Output rolled mystery results to yaml up to specified number (made for async multiworld)' ) for player in range(1, multiargs.multi + 1): parser.add_argument(f'--p{player}', help=argparse.SUPPRESS) args = parser.parse_args() if args.seed is None: random.seed(None) seed = random.randint(0, 999999999) else: seed = args.seed random.seed(seed) seedname = "M" + (f"{random.randint(0, 999999999)}".zfill(9)) print( f"Generating mystery for {args.multi} player{'s' if args.multi > 1 else ''}, {seedname} Seed {seed}" ) weights_cache = {} if args.weights: try: weights_cache[args.weights] = get_weights(args.weights) except Exception as e: raise ValueError( f"File {args.weights} is destroyed. Please fix your yaml." ) from e print( f"Weights: {args.weights} >> {weights_cache[args.weights]['description']}" ) if args.meta: try: weights_cache[args.meta] = get_weights(args.meta) except Exception as e: raise ValueError( f"File {args.meta} is destroyed. Please fix your yaml.") from e meta_weights = weights_cache[args.meta] print(f"Meta: {args.meta} >> {meta_weights['meta_description']}") if args.samesettings: raise Exception("Cannot mix --samesettings with --meta") for player in range(1, args.multi + 1): path = getattr(args, f'p{player}') if path: try: if path not in weights_cache: weights_cache[path] = get_weights(path) print( f"P{player} Weights: {path} >> {weights_cache[path]['description']}" ) except Exception as e: raise ValueError( f"File {path} is destroyed. Please fix your yaml.") from e erargs = parse_arguments(['--multi', str(args.multi)]) erargs.seed = seed erargs.name = {x: "" for x in range(1, args.multi + 1) } # only so it can be overwrittin in mystery erargs.create_spoiler = args.create_spoiler erargs.race = args.race erargs.skip_playthrough = args.skip_playthrough erargs.outputname = seedname erargs.outputpath = args.outputpath erargs.teams = args.teams erargs.progression_balancing = {} # set up logger if args.loglevel: erargs.loglevel = args.loglevel loglevel = { 'error': logging.ERROR, 'info': logging.INFO, 'warning': logging.WARNING, 'debug': logging.DEBUG }[erargs.loglevel] import sys class LoggerWriter(object): def __init__(self, writer): self._writer = writer self._msg = '' def write(self, message): self._msg = self._msg + message while '\n' in self._msg: pos = self._msg.find('\n') self._writer(self._msg[:pos]) self._msg = self._msg[pos + 1:] def flush(self): if self._msg != '': self._writer(self._msg) self._msg = '' if args.log_output_path: log = logging.getLogger("stderr") log.addHandler(logging.StreamHandler()) sys.stderr = LoggerWriter(log.error) os.makedirs(args.log_output_path, exist_ok=True) logging.basicConfig(format='%(message)s', level=loglevel, filename=os.path.join(args.log_output_path, f"{seed}.log")) else: logging.basicConfig(format='%(message)s', level=loglevel) if args.rom: erargs.rom = args.rom if args.enemizercli: erargs.enemizercli = args.enemizercli settings_cache = { k: (roll_settings(v) if args.samesettings else None) for k, v in weights_cache.items() } player_path_cache = {} for player in range(1, args.multi + 1): player_path_cache[player] = getattr(args, f'p{player}') if getattr( args, f'p{player}') else args.weights if args.meta: for player, path in player_path_cache.items(): weights_cache[path].setdefault("meta_ignore", []) meta_weights = weights_cache[args.meta] for key in meta_weights: option = get_choice(key, meta_weights) if option is not None: for player, path in player_path_cache.items(): players_meta = weights_cache[path].get("meta_ignore", []) if key not in players_meta: weights_cache[path][key] = option elif type(players_meta) == dict and players_meta[ key] and option not in players_meta[key]: weights_cache[path][key] = option for player in range(1, args.multi + 1): path = player_path_cache[player] if path: try: settings = settings_cache[path] if settings_cache[ path] else roll_settings(weights_cache[path]) if settings.sprite is not None and not os.path.isfile( settings.sprite) and not get_sprite_from_name( settings.sprite): logging.warning( f"Warning: The chosen sprite, \"{settings.sprite}\", for yaml \"{path}\", does not exist." ) for k, v in vars(settings).items(): if v is not None: getattr(erargs, k)[player] = v except Exception as e: raise ValueError( f"File {path} is destroyed. Please fix your yaml.") from e else: raise RuntimeError(f'No weights specified for player {player}') if not erargs.name[player]: erargs.name[player] = os.path.split(path)[-1].split(".")[0] if args.weights: erargs.names = "" else: erargs.names = ",".join(erargs.name[i] for i in range(1, args.multi + 1)) del (erargs.name) if args.yaml_output: import yaml important = {} for option, player_settings in vars(erargs).items(): if type(player_settings) == dict: if len(set(player_settings.values())) > 1: important[option] = { player: value for player, value in player_settings.items() if player <= args.yaml_output } elif len(set(player_settings.values())) > 0: important[option] = player_settings[1] else: logging.debug( f"No player settings defined for option '{option}'") else: if player_settings != "": # is not empty name important[option] = player_settings else: logging.debug( f"No player settings defined for option '{option}'") if args.outputpath: os.makedirs(args.outputpath, exist_ok=True) with open( os.path.join(args.outputpath if args.outputpath else ".", f"mystery_result_{seed}.yaml"), "wt") as f: yaml.dump(important, f) erargs.skip_progression_balancing = { player: not balanced for player, balanced in erargs.progression_balancing.items() } del (erargs.progression_balancing) ERmain(erargs, seed)
def main(): parser = argparse.ArgumentParser(add_help=False) parser.add_argument('--multi', default=1, type=lambda value: min(max(int(value), 1), 255)) multiargs, _ = parser.parse_known_args() parser = argparse.ArgumentParser() parser.add_argument('--weights', help='Path to the weights file to use for rolling game settings, urls are also valid') parser.add_argument('--samesettings', help='Rolls settings per weights file rather than per player', action='store_true') parser.add_argument('--seed', help='Define seed number to generate.', type=int) parser.add_argument('--multi', default=1, type=lambda value: min(max(int(value), 1), 255)) parser.add_argument('--teams', default=1, type=lambda value: max(int(value), 1)) parser.add_argument('--create_spoiler', action='store_true') parser.add_argument('--rom') parser.add_argument('--enemizercli') parser.add_argument('--outputpath') parser.add_argument('--race', action='store_true') parser.add_argument('--meta', default=None) for player in range(1, multiargs.multi + 1): parser.add_argument(f'--p{player}', help=argparse.SUPPRESS) args = parser.parse_args() if args.seed is None: random.seed(None) seed = random.randint(0, 999999999) else: seed = args.seed random.seed(seed) seedname = "M"+(f"{random.randint(0, 999999999)}".zfill(9)) print(f"Generating mystery for {args.multi} player{'s' if args.multi > 1 else ''}, {seedname} Seed {seed}") weights_cache = {} if args.weights: try: weights_cache[args.weights] = get_weights(args.weights) except Exception as e: raise ValueError(f"File {args.weights} is destroyed. Please fix your yaml.") from e print(f"Weights: {args.weights} >> {weights_cache[args.weights]['description']}") if args.meta: try: weights_cache[args.meta] = get_weights(args.meta) except Exception as e: raise ValueError(f"File {args.meta} is destroyed. Please fix your yaml.") from e print(f"Meta: {args.meta} >> {weights_cache[args.meta]['meta_description']}") if args.samesettings: raise Exception("Cannot mix --samesettings with --meta") for player in range(1, args.multi + 1): path = getattr(args, f'p{player}') if path: try: if path not in weights_cache: weights_cache[path] = get_weights(path) print(f"P{player} Weights: {path} >> {weights_cache[path]['description']}") except Exception as e: raise ValueError(f"File {path} is destroyed. Please fix your yaml.") from e erargs = parse_arguments(['--multi', str(args.multi)]) erargs.seed = seed erargs.name = {x: "" for x in range(1, args.multi + 1)} # only so it can be overwrittin in mystery erargs.create_spoiler = args.create_spoiler erargs.race = args.race erargs.outputname = seedname erargs.outputpath = args.outputpath erargs.teams = args.teams # set up logger loglevel = {'error': logging.ERROR, 'info': logging.INFO, 'warning': logging.WARNING, 'debug': logging.DEBUG}[erargs.loglevel] logging.basicConfig(format='%(message)s', level=loglevel) if args.rom: erargs.rom = args.rom if args.enemizercli: erargs.enemizercli = args.enemizercli settings_cache = {k: (roll_settings(v) if args.samesettings else None) for k, v in weights_cache.items()} player_path_cache = {} for player in range(1, args.multi + 1): player_path_cache[player] = getattr(args, f'p{player}') if getattr(args, f'p{player}') else args.weights if args.meta: for player, path in player_path_cache.items(): weights_cache[path].setdefault("meta_ignore", []) meta_weights = weights_cache[args.meta] for key in meta_weights: option = get_choice(key, meta_weights) if option is not None: for player, path in player_path_cache.items(): players_meta = weights_cache[path]["meta_ignore"] if key not in players_meta: weights_cache[path][key] = option elif type(players_meta) == dict and option not in players_meta[key]: weights_cache[path][key] = option for player in range(1, args.multi + 1): path = player_path_cache[player] if path: try: settings = settings_cache[path] if settings_cache[path] else roll_settings(weights_cache[path]) if settings.sprite is not None and not os.path.isfile(settings.sprite) and not get_sprite_from_name(settings.sprite): logging.warning( f"Warning: The chosen sprite, \"{settings.sprite}\", for yaml \"{path}\", does not exist.") for k, v in vars(settings).items(): if v is not None: getattr(erargs, k)[player] = v except Exception as e: raise ValueError(f"File {path} is destroyed. Please fix your yaml.") from e else: raise RuntimeError(f'No weights specified for player {player}') if not erargs.name[player]: erargs.name[player] = os.path.split(path)[-1].split(".")[0] if args.samesettings: erargs.names = "" else: erargs.names = ",".join(erargs.name[i] for i in range(1, args.multi + 1)) del (erargs.name) ERmain(erargs, seed)