From 033adceb6f554c157e63fd322125e6d153d20804 Mon Sep 17 00:00:00 2001 From: Fabian Dill Date: Mon, 13 Sep 2021 01:32:32 +0200 Subject: [PATCH] LttP: move some simple Toggle options over to new system --- BaseClasses.py | 18 +-------- Generate.py | 18 +-------- Main.py | 12 +----- WebHostLib/generate.py | 3 +- worlds/alttp/EntranceRandomizer.py | 39 ++++--------------- worlds/alttp/Options.py | 60 ++++++++++++++++++++++++++++++ worlds/alttp/Rom.py | 2 +- worlds/alttp/__init__.py | 2 +- 8 files changed, 74 insertions(+), 80 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index ba14dcda..2532aaf8 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -77,7 +77,6 @@ class MultiWorld(): set_player_attr('shuffle', "vanilla") set_player_attr('logic', "noglitches") set_player_attr('mode', 'open') - set_player_attr('swordless', False) set_player_attr('difficulty', 'normal') set_player_attr('item_functionality', 'normal') set_player_attr('timer', False) @@ -1127,7 +1126,7 @@ class Spoiler(): 'tile_shuffle': self.world.tile_shuffle, 'bush_shuffle': self.world.bush_shuffle, 'beemizer': self.world.beemizer, - 'shufflepots': self.world.shufflepots, + 'pot_shuffle': self.world.pot_shuffle, 'players': self.world.players, 'progression_balancing': self.world.progression_balancing, 'triforce_pieces_available': self.world.triforce_pieces_available, @@ -1193,13 +1192,7 @@ class Spoiler(): outfile.write('Logic: %s\n' % self.metadata['logic'][player]) outfile.write('Dark Room Logic: %s\n' % self.metadata['dark_room_logic'][player]) - outfile.write('Restricted Boss Drops: %s\n' % - bool_to_text(self.metadata['restrict_dungeon_item_on_boss'][player])) - outfile.write('Mode: %s\n' % self.metadata['mode'][player]) - outfile.write('Retro: %s\n' % - ('Yes' if self.metadata['retro'][player] else 'No')) - outfile.write('Swordless: %s\n' % ('Yes' if self.metadata['swordless'][player] else 'No')) outfile.write('Goal: %s\n' % self.metadata['goal'][player]) if "triforce" in self.metadata["goal"][player]: # triforce hunt outfile.write("Pieces available for Triforce: %s\n" % @@ -1225,18 +1218,9 @@ class Spoiler(): outfile.write('Custom Potion Shop: %s\n' % bool_to_text("w" in self.metadata["shop_shuffle"][player])) outfile.write('Boss shuffle: %s\n' % self.metadata['boss_shuffle'][player]) - outfile.write( - 'Enemy shuffle: %s\n' % bool_to_text(self.metadata['enemy_shuffle'][player])) outfile.write('Enemy health: %s\n' % self.metadata['enemy_health'][player]) outfile.write('Enemy damage: %s\n' % self.metadata['enemy_damage'][player]) - outfile.write(f'Killable thieves: {bool_to_text(self.metadata["killable_thieves"][player])}\n') - outfile.write(f'Shuffled tiles: {bool_to_text(self.metadata["tile_shuffle"][player])}\n') - outfile.write(f'Shuffled bushes: {bool_to_text(self.metadata["bush_shuffle"][player])}\n') - outfile.write( - 'Hints: %s\n' % ('Yes' if self.metadata['hints'][player] else 'No')) outfile.write('Beemizer: %s\n' % self.metadata['beemizer'][player]) - outfile.write('Pot shuffle %s\n' - % ('Yes' if self.metadata['shufflepots'][player] else 'No')) outfile.write('Prize shuffle %s\n' % self.metadata['shuffle_prizes'][player]) if self.entrances: diff --git a/Generate.py b/Generate.py index 7980d299..8e44968d 100644 --- a/Generate.py +++ b/Generate.py @@ -121,10 +121,9 @@ def main(args=None, callback=ERmain): f"A mix is also permitted.") erargs = parse_arguments(['--multi', str(args.multi)]) erargs.seed = seed - erargs.create_spoiler = args.spoiler > 0 erargs.glitch_triforce = options["generator"]["glitch_triforce_room"] + erargs.spoiler = args.spoiler erargs.race = args.race - erargs.skip_playthrough = args.spoiler < 2 erargs.outputname = seed_name erargs.outputpath = args.outputpath @@ -587,8 +586,6 @@ def roll_alttp_settings(ret: argparse.Namespace, weights, plando_options): if ret.dark_room_logic not in {"lamp", "torches", "none"}: raise ValueError(f"Unknown Dark Room Logic: \"{ret.dark_room_logic}\"") - ret.restrict_dungeon_item_on_boss = get_choice_legacy('restrict_dungeon_item_on_boss', weights, False) - entrance_shuffle = get_choice_legacy('entrance_shuffle', weights, 'vanilla') if entrance_shuffle.startswith('none-'): ret.shuffle = 'vanilla' @@ -628,11 +625,6 @@ def roll_alttp_settings(ret: argparse.Namespace, weights, plando_options): ret.shop_shuffle = '' ret.mode = get_choice_legacy("mode", weights) - ret.retro = get_choice_legacy("retro", weights) - - ret.hints = get_choice_legacy('hints', weights) - - ret.swordless = get_choice_legacy('swordless', weights, False) ret.difficulty = get_choice_legacy('item_pool', weights) @@ -641,12 +633,6 @@ def roll_alttp_settings(ret: argparse.Namespace, weights, plando_options): boss_shuffle = get_choice_legacy('boss_shuffle', weights) ret.shufflebosses = get_plando_bosses(boss_shuffle, plando_options) - ret.enemy_shuffle = bool(get_choice_legacy('enemy_shuffle', weights, False)) - - ret.killable_thieves = get_choice_legacy('killable_thieves', weights, False) - ret.tile_shuffle = get_choice_legacy('tile_shuffle', weights, False) - ret.bush_shuffle = get_choice_legacy('bush_shuffle', weights, False) - ret.enemy_damage = {None: 'default', 'default': 'default', 'shuffled': 'shuffled', @@ -656,8 +642,6 @@ def roll_alttp_settings(ret: argparse.Namespace, weights, plando_options): ret.enemy_health = get_choice_legacy('enemy_health', weights) - ret.shufflepots = get_choice_legacy('pot_shuffle', weights) - ret.beemizer = int(get_choice_legacy('beemizer', weights, 0)) ret.timer = {'none': False, diff --git a/Main.py b/Main.py index 3c3a2ad4..aeddad8f 100644 --- a/Main.py +++ b/Main.py @@ -63,24 +63,17 @@ def main(args, seed=None): world.customitemarray = args.customitemarray world.accessibility = args.accessibility.copy() - world.retro = args.retro.copy() - - world.hints = args.hints.copy() world.open_pyramid = args.open_pyramid.copy() world.boss_shuffle = args.shufflebosses.copy() world.enemy_shuffle = args.enemy_shuffle.copy() world.enemy_health = args.enemy_health.copy() world.enemy_damage = args.enemy_damage.copy() - world.killable_thieves = args.killable_thieves.copy() - world.bush_shuffle = args.bush_shuffle.copy() - world.tile_shuffle = args.tile_shuffle.copy() world.beemizer = args.beemizer.copy() world.timer = args.timer.copy() world.countdown_start_time = args.countdown_start_time.copy() world.red_clock_time = args.red_clock_time.copy() world.blue_clock_time = args.blue_clock_time.copy() world.green_clock_time = args.green_clock_time.copy() - world.shufflepots = args.shufflepots.copy() world.dungeon_counters = args.dungeon_counters.copy() world.triforce_pieces_available = args.triforce_pieces_available.copy() world.triforce_pieces_required = args.triforce_pieces_required.copy() @@ -93,7 +86,6 @@ def main(args, seed=None): world.plando_texts = args.plando_texts.copy() world.plando_connections = args.plando_connections.copy() world.er_seeds = getattr(args, "er_seeds", {}) - world.restrict_dungeon_item_on_boss = args.restrict_dungeon_item_on_boss.copy() world.required_medallions = args.required_medallions.copy() world.game = args.game.copy() world.set_options(args) @@ -346,11 +338,11 @@ def main(args, seed=None): logger.info(f'Generating output files ({i}/{len(output_file_futures)}).') future.result() - if not args.skip_playthrough: + if args.spoiler > 1: logger.info('Calculating playthrough.') create_playthrough(world) - if args.create_spoiler: + if args.spoiler: world.spoiler.to_file(os.path.join(temp_dir, '%s_Spoiler.txt' % outfilebase)) zipfilename = output_path(f"AP_{world.seed_name}.zip") diff --git a/WebHostLib/generate.py b/WebHostLib/generate.py index 99af0d39..bfb711d0 100644 --- a/WebHostLib/generate.py +++ b/WebHostLib/generate.py @@ -74,9 +74,8 @@ def gen_game(gen_options, race=False, owner=None, sid=None): erargs = parse_arguments(['--multi', str(playercount)]) erargs.seed = seed erargs.name = {x: "" for x in range(1, playercount + 1)} # only so it can be overwrittin in mystery - erargs.create_spoiler = not race + erargs.spoiler = 0 if race else 2 erargs.race = race - erargs.skip_playthrough = race erargs.outputname = seedname erargs.outputpath = target.name erargs.teams = 1 diff --git a/worlds/alttp/EntranceRandomizer.py b/worlds/alttp/EntranceRandomizer.py index 5bd01299..02efe463 100644 --- a/worlds/alttp/EntranceRandomizer.py +++ b/worlds/alttp/EntranceRandomizer.py @@ -20,7 +20,6 @@ def parse_arguments(argv, no_defaults=False): multiargs, _ = parser.parse_known_args(argv) parser = argparse.ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter) - parser.add_argument('--create_spoiler', help='Output a Spoiler File', action='store_true') parser.add_argument('--logic', default=defval('noglitches'), const='noglitches', nargs='?', choices=['noglitches', 'minorglitches', 'owglitches', 'hybridglitches', 'nologic'], help='''\ Select Enforcement of Item Requirements. (default: %(default)s) @@ -46,17 +45,6 @@ def parse_arguments(argv, no_defaults=False): Requires the moon pearl to be Link in the Light World instead of a bunny. ''') - parser.add_argument('--swordless', action='store_true', - help='''\ - Toggles Swordless Mode - Swordless: No swords. Curtains in Skull Woods and Agahnim\'s - Tower are removed, Agahnim\'s Tower barrier can be - destroyed with hammer. Misery Mire and Turtle Rock - can be opened without a sword. Hammer damages Ganon. - Ether and Bombos Tablet can be activated with Hammer - (and Book). Bombos pads have been added in Ice - Palace, to allow for an alternative to firerod. - ''') parser.add_argument('--goal', default=defval('ganon'), const='ganon', nargs='?', choices=['ganon', 'pedestal', 'bosses', 'triforcehunt', 'localtriforcehunt', 'ganontriforcehunt', 'localganontriforcehunt', 'crystals', 'ganonpedestal'], help='''\ @@ -206,10 +194,6 @@ def parse_arguments(argv, no_defaults=False): time). ''', type=int) - parser.add_argument('--retro', default=defval(False), help='''\ - Keys are universal, shooting arrows costs rupees, - and a few other little things make this more like Zelda-1. - ''', action='store_true') parser.add_argument('--local_items', default=defval(''), help='Specifies a list of items that will not spread across the multiworld (separated by commas)') parser.add_argument('--non_local_items', default=defval(''), @@ -223,9 +207,6 @@ def parse_arguments(argv, no_defaults=False): Locations: You will be able to reach every location in the game. None: You will be able to reach enough locations to beat the game. ''') - parser.add_argument('--hints', default=defval(False), help='''\ - Make telepathic tiles and storytellers give helpful hints. - ''', action='store_true') # included for backwards compatibility parser.add_argument('--shuffleganon', help=argparse.SUPPRESS, action='store_true', default=defval(True)) parser.add_argument('--no-shuffleganon', help='''\ @@ -243,18 +224,13 @@ def parse_arguments(argv, no_defaults=False): parser.add_argument('--gui', help='Launch the GUI', action='store_true') parser.add_argument('--progression_balancing', action='store_true', default=defval(False), help="Enable Multiworld Progression balancing.") - parser.add_argument('--skip_playthrough', action='store_true', default=defval(False)) parser.add_argument('--enemizercli', default=defval('EnemizerCLI/EnemizerCLI.Core')) parser.add_argument('--shufflebosses', default=defval('none'), choices=['none', 'basic', 'normal', 'chaos', "singularity"]) - parser.add_argument('--enemy_shuffle', action='store_true') - parser.add_argument('--killable_thieves', action='store_true') - parser.add_argument('--tile_shuffle', action='store_true') - parser.add_argument('--bush_shuffle', action='store_true') + parser.add_argument('--enemy_health', default=defval('default'), choices=['default', 'easy', 'normal', 'hard', 'expert']) parser.add_argument('--enemy_damage', default=defval('default'), choices=['default', 'shuffled', 'chaos']) - parser.add_argument('--shufflepots', default=defval(False), action='store_true') parser.add_argument('--beemizer', default=defval(0), type=lambda value: min(max(int(value), 0), 4)) parser.add_argument('--shop_shuffle', default='', help='''\ combine letters for options: @@ -272,7 +248,6 @@ def parse_arguments(argv, no_defaults=False): For unlit dark rooms, require the Lamp to be considered in logic by default. Torches means additionally easily accessible Torches that can be lit with Fire Rod are considered doable. None means full traversal through dark rooms without tools is considered doable.''') - parser.add_argument('--restrict_dungeon_item_on_boss', default=defval(False), action="store_true") parser.add_argument('--multi', default=defval(1), type=lambda value: min(max(int(value), 1), 255)) parser.add_argument('--names', default=defval('')) parser.add_argument('--outputpath') @@ -307,19 +282,19 @@ def parse_arguments(argv, no_defaults=False): for player in range(1, multiargs.multi + 1): playerargs = parse_arguments(shlex.split(getattr(ret, f"p{player}")), True) - for name in ['logic', 'mode', 'swordless', 'goal', 'difficulty', 'item_functionality', + for name in ['logic', 'mode', 'goal', 'difficulty', 'item_functionality', 'shuffle', 'open_pyramid', 'timer', 'countdown_start_time', 'red_clock_time', 'blue_clock_time', 'green_clock_time', - 'local_items', 'non_local_items', 'retro', 'accessibility', 'hints', 'beemizer', - 'shufflebosses', 'enemy_shuffle', 'enemy_health', 'enemy_damage', 'shufflepots', + 'local_items', 'non_local_items', 'accessibility', 'beemizer', + 'shufflebosses', 'enemy_health', 'enemy_damage', 'sprite', "progression_balancing", "triforce_pieces_available", "triforce_pieces_required", "shop_shuffle", "required_medallions", "start_hints", "plando_items", "plando_texts", "plando_connections", "er_seeds", - 'dungeon_counters', 'killable_thieves', - 'tile_shuffle', 'bush_shuffle', 'shuffle_prizes', 'sprite_pool', 'dark_room_logic', - 'restrict_dungeon_item_on_boss', 'game']: + 'dungeon_counters', + 'shuffle_prizes', 'sprite_pool', 'dark_room_logic', + 'game']: value = getattr(defaults, name) if getattr(playerargs, name) is None else getattr(playerargs, name) if player == 1: setattr(ret, name, {1: value}) diff --git a/worlds/alttp/Options.py b/worlds/alttp/Options.py index 93225e05..c6a2f87b 100644 --- a/worlds/alttp/Options.py +++ b/worlds/alttp/Options.py @@ -126,6 +126,59 @@ class Progressive(Choice): return random.choice([True, False]) if self.value == self.option_grouped_random else bool(self.value) +class Swordless(Toggle): + """No swords. Curtains in Skull Woods and Agahnim\'s + Tower are removed, Agahnim\'s Tower barrier can be + destroyed with hammer. Misery Mire and Turtle Rock + can be opened without a sword. Hammer damages Ganon. + Ether and Bombos Tablet can be activated with Hammer + (and Book).""" + displayname = "Swordless" + + +class Retro(Toggle): + """Zelda-1 like mode. You have to purchase a quiver to shoot arrows using rupees + and there are randomly placed take-any caves that contain one Sword and choices of Heart Container/Blue Potion.""" + displayname = "Retro" + + +class RestrictBossItem(Toggle): + """Don't place dungeon-native items on the dungeon's boss.""" + displayname = "Prevent Dungeon Item on Boss" + + +class Hints(DefaultOnToggle): + """Put item and entrance placement hints on telepathic tiles and some NPCs. + Additionally King Zora and Bottle Merchant say what they're selling.""" + displayname = "Hints" + + +class EnemyShuffle(Toggle): + """Randomize every enemy spawn. + If mode is Standard, Hyrule Castle is left out (may result in visually wrong enemy sprites in that area.)""" + displayname = "Enemy Shuffle" + + +class KillableThieves(Toggle): + """Makes Thieves killable.""" + displayname = "Killable Thieves" + + +class BushShuffle(Toggle): + """Randomize chance that a bush contains an enemy as well as which enemy may spawn.""" + displayname = "Bush Shuffle" + + +class TileShuffle(Toggle): + """Randomize flying tiles floor patterns.""" + displayname = "Tile Shuffle" + + +class PotShuffle(Toggle): + """Shuffle contents of pots within "supertiles" (item will still be nearby original placement).""" + displayname = "Pot Shuffle" + + class Palette(Choice): option_default = 0 option_good = 1 @@ -226,6 +279,13 @@ alttp_options: typing.Dict[str, type(Option)] = { "compass_shuffle": compass_shuffle, "map_shuffle": map_shuffle, "progressive": Progressive, + "swordless": Swordless, + "hints": Hints, + "restrict_dungeon_item_on_boss": RestrictBossItem, + "pot_shuffle": PotShuffle, + "enemy_shuffle": EnemyShuffle, + "killable_thieves": KillableThieves, + "bush_shuffle": BushShuffle, "shop_item_slots": ShopItemSlots, "ow_palettes": OWPalette, "uw_palettes": UWPalette, diff --git a/worlds/alttp/Rom.py b/worlds/alttp/Rom.py index a1cd2b9b..434eba67 100644 --- a/worlds/alttp/Rom.py +++ b/worlds/alttp/Rom.py @@ -323,7 +323,7 @@ def patch_enemizer(world, player: int, rom: LocalRom, enemizercli, output_direct 'GrayscaleMode': False, 'GenerateSpoilers': False, 'RandomizeLinkSpritePalette': False, - 'RandomizePots': world.shufflepots[player], + 'RandomizePots': world.pot_shuffle[player], 'ShuffleMusic': False, 'BootlegMagic': True, 'CustomBosses': False, diff --git a/worlds/alttp/__init__.py b/worlds/alttp/__init__.py index fd04cd47..45917640 100644 --- a/worlds/alttp/__init__.py +++ b/worlds/alttp/__init__.py @@ -258,7 +258,7 @@ class ALTTPWorld(World): try: use_enemizer = (world.boss_shuffle[player] != 'none' or world.enemy_shuffle[player] or world.enemy_health[player] != 'default' or world.enemy_damage[player] != 'default' - or world.shufflepots[player] or world.bush_shuffle[player] + or world.pot_shuffle[player] or world.bush_shuffle[player] or world.killable_thieves[player]) rom = LocalRom(world.alttp_rom)