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)
Ejemplo n.º 2
0
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)
Ejemplo n.º 3
0
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)
Ejemplo n.º 4
0
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)
Ejemplo n.º 5
0
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)
Ejemplo n.º 6
0
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)
Ejemplo n.º 7
0
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)
Ejemplo n.º 8
0
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)