Пример #1
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 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 Sprite.get_sprite_from_name(sprite)
            for sprite in args.sprite.values()
    ]):
        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)

    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 = get_seed()
    else:
        main(seed=args.seed, args=args)
Пример #2
0
def main():
    parser = argparse.ArgumentParser(
        formatter_class=ArgumentDefaultsHelpFormatter)

    parser.add_argument('--rom',
                        default='ER_base.sfc',
                        help='Path to an ALttP 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', 'puke', 'classic',
                            'grayscale', 'negative', 'dizzy', 'sick'
                        ])
    parser.add_argument('--link_palettes',
                        default='default',
                        choices=[
                            'default', 'random', 'blackout', 'puke', 'classic',
                            'grayscale', 'negative', 'dizzy', 'sick'
                        ])
    parser.add_argument('--shield_palettes',
                        default='default',
                        choices=[
                            'default', 'random', 'blackout', 'puke', 'classic',
                            'grayscale', 'negative', 'dizzy', 'sick'
                        ])
    parser.add_argument('--sword_palettes',
                        default='default',
                        choices=[
                            'default', 'random', 'blackout', 'puke', 'classic',
                            'grayscale', 'negative', 'dizzy', 'sick'
                        ])
    parser.add_argument('--hud_palettes',
                        default='default',
                        choices=[
                            'default', 'random', 'blackout', 'puke', 'classic',
                            'grayscale', 'negative', 'dizzy', 'sick'
                        ])
    parser.add_argument('--uw_palettes',
                        default='default',
                        choices=[
                            'default', 'random', 'blackout', 'puke', 'classic',
                            'grayscale', 'negative', 'dizzy', 'sick'
                        ])
    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 Sprite.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_2", args)
Пример #3
0
def main(args=None, callback=ERmain):
    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}"
    )

    if args.race:
        random.seed()  # reset to time-based random source

    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} >> "
            f"{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} >> "
                    f"{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.create_diff = args.create_diff
    erargs.glitch_triforce = args.glitch_triforce
    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]

    if args.log_output_path:
        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 = ''

        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, args.plando) 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

    name_counter = Counter()
    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], args.plando)
                if settings.sprite and not os.path.isfile(
                        settings.sprite) and not Sprite.get_sprite_from_name(
                            settings.sprite):
                    logging.warning(
                        f"Warning: The chosen sprite, \"{settings.sprite}\", for yaml \"{path}\", does not exist."
                    )
                if args.pre_roll:
                    import yaml
                    if path == args.weights:
                        settings.name = f"Player{player}"
                    elif not settings.name:
                        settings.name = os.path.splitext(
                            os.path.split(path)[-1])[0]

                    if "-" not in settings.shuffle and settings.shuffle != "vanilla":
                        settings.shuffle += f"-{random.randint(0, 2 ** 64)}"

                    pre_rolled = dict()
                    pre_rolled["original_seed_number"] = seed
                    pre_rolled["original_seed_name"] = seedname
                    pre_rolled["pre_rolled"] = vars(settings).copy()
                    if "plando_items" in pre_rolled["pre_rolled"]:
                        pre_rolled["pre_rolled"]["plando_items"] = [
                            item.to_dict() for item in pre_rolled["pre_rolled"]
                            ["plando_items"]
                        ]
                    if "plando_connections" in pre_rolled["pre_rolled"]:
                        pre_rolled["pre_rolled"]["plando_connections"] = [
                            connection.to_dict() for connection in
                            pre_rolled["pre_rolled"]["plando_connections"]
                        ]

                    with open(
                            os.path.join(
                                args.outputpath if args.outputpath else ".",
                                f"{os.path.split(path)[-1].split('.')[0]}_pre_rolled.yaml"
                            ), "wt") as f:
                        yaml.dump(pre_rolled, f)
                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 path == args.weights:  # if name came from the weights file, just use base player name
            erargs.name[player] = f"Player{player}"
        elif not erargs.name[
                player]:  # if name was not specified, generate it from filename
            erargs.name[player] = os.path.splitext(os.path.split(path)[-1])[0]
        erargs.name[player] = handle_name(erargs.name[player], player,
                                          name_counter)
        logging.info(erargs.name[player])
    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 all(
                        type(value) != list
                        for value in player_settings.values()):
                    if len(player_settings.values()) > 1:
                        important[option] = {
                            player: value
                            for player, value in player_settings.items()
                            if player <= args.yaml_output
                        }
                    elif len(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)
    callback(erargs, seed)
Пример #4
0
def main():
    parser = argparse.ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter)

    parser.add_argument('--rom', default='ER_base.sfc', help='Path to an ALttP 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('--triforcehud', default='hide_goal', const='hide_goal', nargs='?', choices=['normal', 'hide_goal', 'hide_required', 'hide_both'],
                    help='''\
                            Hide the triforce hud in certain circumstances.
                            hide_goal will hide the hud until finding a triforce piece, hide_required will hide the total amount needed to win
                            (Both can be revealed when speaking to Murahalda)
                            (default: %(default)s)
                            ''')
    parser.add_argument('--enableflashing', help='Reenable flashing animations (unfriendly to epilepsy, always disabled in race roms)', action='store_false', dest="reduceflashing")
    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','puke','classic','grayscale','negative','dizzy','sick'])
    parser.add_argument('--link_palettes', default='default', choices=['default', 'random', 'blackout','puke','classic','grayscale','negative','dizzy','sick'])
    parser.add_argument('--shield_palettes', default='default', choices=['default', 'random', 'blackout','puke','classic','grayscale','negative','dizzy','sick'])
    parser.add_argument('--sword_palettes', default='default', choices=['default', 'random', 'blackout','puke','classic','grayscale','negative','dizzy','sick'])
    parser.add_argument('--hud_palettes', default='default', choices=['default', 'random', 'blackout','puke','classic','grayscale','negative','dizzy','sick'])
    parser.add_argument('--uw_palettes', default='default', choices=['default', 'random', 'blackout','puke','classic','grayscale','negative','dizzy','sick'])
    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()

    # 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 not os.path.isfile(args.rom):
        adjustGUI()
    else:
        if args.sprite is not None and not os.path.isfile(args.sprite) and not Sprite.get_sprite_from_name(args.sprite):
            input('Could not find link sprite sheet at given location. \nPress Enter to exit.')
            sys.exit(1)

        args, path = adjust(args=args)
        from Utils import persistent_store
        if isinstance(args.sprite, Sprite):
            args.sprite = args.sprite.name
        persistent_store("adjuster", "last_settings_3", args)