From ce4179abb9d425e1477dad45c6ba42a4064d09a7 Mon Sep 17 00:00:00 2001 From: aerinon Date: Wed, 3 Jan 2024 16:24:35 -0700 Subject: [PATCH] feat: updated maze race/hobo clips refactor: bunny pocket assumes a connector/dungeon_revive entrance is available, for now fix: mirrorless_moat_rule no longer allows flippers in swamp fix: problems from merge --- EntranceShuffle.py | 2 +- OverworldGlitchRules.py | 148 +++++++++++---------------- Rules.py | 30 ++---- UnderworldGlitchRules.py | 1 + source/overworld/EntranceShuffle2.py | 2 +- test/NewTestSuite.py | 2 +- 6 files changed, 73 insertions(+), 112 deletions(-) diff --git a/EntranceShuffle.py b/EntranceShuffle.py index 95cf696f..84caaaf1 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -2146,7 +2146,7 @@ default_connections = [('Lost Woods Gamble', 'Lost Woods Gamble'), ('Paradox Cave (Top)', 'Paradox Cave'), ('Paradox Cave Exit (Bottom)', 'East Death Mountain (Bottom)'), ('Paradox Cave Exit (Middle)', 'East Death Mountain (Bottom)'), - ('Paradox Cave Exit (Top)', 'East Death Mountain (Top)'), + ('Paradox Cave Exit (Top)', 'East Death Mountain (Top East)'), ('Waterfall of Wishing', 'Waterfall of Wishing'), ('Fortune Teller (Light)', 'Fortune Teller (Light)'), ('Bonk Rock Cave', 'Bonk Rock Cave'), diff --git a/OverworldGlitchRules.py b/OverworldGlitchRules.py index 7e03b64c..aab2ddda 100644 --- a/OverworldGlitchRules.py +++ b/OverworldGlitchRules.py @@ -115,81 +115,77 @@ open_non_mandatory_exits = [ # Special Light World region exits that require boots clips. - -inverted_boots_clip_exits_lw = [ - ("Light World DMA Clip Spot", "Light World", "West Death Mountain (Bottom)"), - ("Hera Ascent", "West Death Mountain (Bottom)", "West Death Mountain (Top)"), - ("Death Mountain Return Ledge Clip Spot", "Light World", "Death Mountain Return Ledge"), - ("Death Mountain Entrance Clip Spot", "Light World", "Death Mountain Entrance"), - ("Death Mountain Glitched Bridge", "West Death Mountain (Bottom)", "East Death Mountain (Top)"), - ("Zora Descent Clip Spot", "East Death Mountain (Top)", "Zoras Domain"), - ("Desert Northern Cliffs", "Light World", "Desert Northern Cliffs"), - ("Desert Ledge Dropdown", "Desert Northern Cliffs", "Desert Ledge"), - ("Desert Palace Entrance Dropdown", "Desert Northern Cliffs", "Desert Palace Entrance (North) Spot"), - ("Lake Hylia Island Clip Spot", "Light World", "Lake Hylia Island"), - ("Death Mountain Descent", "West Death Mountain (Bottom)", "Light World"), - ("Kings Grave Clip Spot", "West Death Mountain (Bottom)", "Kings Grave Area"), +boots_clip_exits_lw = [ + ('Lumberjack DMA Clip', 'Lumberjack Area', 'West Death Mountain (Bottom)'), + ('Spectacle Rock Clip', 'West Death Mountain (Top)', 'Spectacle Rock Ledge'), + ('Hera Ascent Clip', 'West Death Mountain (Bottom)', 'West Death Mountain (Top)'), + ('Death Mountain Glitched Bridge Clip', 'West Death Mountain (Bottom)', 'East Death Mountain (Top East)'), + ('Sanctuary DMD Clip', 'West Death Mountain (Bottom)', 'Sanctuary Area'), + ('Graveyard Ledge Clip', 'West Death Mountain (Bottom)', 'Graveyard Ledge'), + ('Kings Grave Clip', 'West Death Mountain (Bottom)', 'Kings Grave Area'), + ('Floating Island Clip', 'East Death Mountain (Top East)', 'Death Mountain Floating Island'), + ('Zora DMD Clip', 'Death Mountain TR Pegs Area', 'Zoras Domain'), + ('TR Pegs Ledge Clip', 'Death Mountain TR Pegs Area', 'Death Mountain TR Pegs Ledge'), + ('Mountain Pass Ledge Clip', 'Mountain Pass Area', 'Mountain Pass Ledge'), + ('Mountain Pass Entry Clip', 'Kakariko Pond Area', 'Mountain Pass Entry'), + ('Bat Cave River Clip', 'Blacksmith Area', 'Blacksmith Ledge'), + ('Desert Keep Clip', 'Maze Race Area', 'Desert Ledge Keep'), + ('Desert Ledge Clip', 'Maze Race Area', 'Desert Ledge'), + ('Maze Race Prize Clip', 'Maze Race Area', 'Maze Race Prize'), + ('Stone Bridge To Cliff Clip', 'Stone Bridge South Area', 'Central Cliffs'), + ('Hobo Clip', 'Stone Bridge South Area', 'Stone Bridge Water'), + ('Bombos Tablet Clip', 'Desert Area', 'Bombos Tablet Ledge'), + ('Desert Teleporter Clip', 'Desert Area', 'Desert Teleporter Ledge'), + ('Cave 45 Clip', 'Flute Boy Approach Area', 'Cave 45 Ledge'), + ('Desert Northern Cliffs Clip', 'Flute Boy Approach Area', 'Desert Northern Cliffs') ] -open_boots_clip_exits_lw = [ - ("Graveyard Ledge Clip Spot", "West Death Mountain (Bottom)", "Graveyard Ledge"), - ("Desert Ledge (Northeast) Dropdown", "Desert Northern Cliffs", "Desert Checkerboard Ledge"), - ("Spectacle Rock Clip Spot", "West Death Mountain (Top)", "Spectacle Rock"), - ("Bombos Tablet Clip Spot", "Light World", "Bombos Tablet Ledge"), - ("Floating Island Clip Spot", "East Death Mountain (Top)", "Death Mountain Floating Island"), - ("Cave 45 Clip Spot", "Light World", "Cave 45 Ledge"), -] + inverted_boots_clip_exits_lw - # Special Dark World region exits that require boots clips. boots_clip_exits_dw = [ - ("Dark World DMA Clip Spot", "West Dark World", "West Dark Death Mountain (Bottom)"), - ("Bumper Cave Ledge Clip Spot", "West Dark World", "Bumper Cave Ledge"), - ("Bumper Cave Entrance Clip Spot", "West Dark World", "Bumper Cave Entrance"), - ("Catfish Descent", "Dark Death Mountain (Top)", "Catfish Area"), - ("Hammer Pegs River Clip Spot", "East Dark World", "Hammer Peg Area"), - ("Dark Lake Hylia Ledge Clip Spot", "East Dark World", "Southeast Dark World"), - ("Dark Desert Cliffs Clip Spot", "South Dark World", "Dark Desert"), - ("DW Floating Island Clip Spot", "East Dark Death Mountain (Bottom)", "Dark Death Mountain Floating Island"), + ('Dark World DMA Clip', 'Dark Lumberjack Area', 'West Dark Death Mountain (Bottom)'), + ('Dark Death Mountain Descent', 'West Dark Death Mountain (Bottom)', 'Dark Chapel Area'), + ('Ganons Tower Ascent', 'West Dark Death Mountain (Bottom)', 'GT Stairs'), # This only gets you to the GT entrance + ('Dark Death Mountain Glitched Bridge', 'West Dark Death Mountain (Bottom)', 'East Dark Death Mountain (Top)'), + ('DW Floating Island Clip', 'East Dark Death Mountain (Bottom)', 'Dark Death Mountain Floating Island'), + ('Turtle Rock (Top) Clip', 'Turtle Rock Area', 'Turtle Rock Ledge'), + ('Catfish DMD', 'Turtle Rock Area', 'Catfish Area'), + ('Bumper Cave Ledge Clip', 'Bumper Cave Area', 'Bumper Cave Ledge'), + ('Bumper Cave Entry Clip', 'Outcast Pond Area', 'Bumper Cave Entry'), + ('Broken Bridge Hammer Rock Skip Clip', 'Qirn Jump East Bank', 'Broken Bridge Area'), + ('Dark Witch Rock Skip Clip', 'Dark Witch Area', 'Dark Witch Northeast'), + ('Hammer Pegs River Clip', 'Dark Dunes Area', 'Hammer Pegs Area'), + ('Hammer Bridge To Cliff Clip', 'Hammer Bridge South Area', 'Dark Central Cliffs'), + ('Mire Cliffs Clip', 'Stumpy Approach Area', 'Mire Northern Cliffs'), + ('Dark Lake Hylia Ledge Clip', 'Darkness Nook Area', 'Shopping Mall Area'), + ('Mire Teleporter Clip', 'Mire Area', 'Mire Teleporter Ledge') ] -open_boots_clip_exits_dw = [ - ("Dark Death Mountain Descent", "West Dark Death Mountain (Bottom)", "West Dark World"), - ("Ganons Tower Ascent", "West Dark Death Mountain (Bottom)", "Dark Death Mountain (Top)"), - ("Dark Death Mountain Glitched Bridge", "West Dark Death Mountain (Bottom)", "Dark Death Mountain (Top)"), - ("Turtle Rock (Top) Clip Spot", "Dark Death Mountain (Top)", "Turtle Rock (Top)"), -] + boots_clip_exits_dw - -inverted_boots_clip_exits_dw = [ - ("Dark Desert Teleporter Clip Spot", "Dark Desert", "Dark Desert Ledge") -] + boots_clip_exits_dw - # Dark World drop-down ledges that require glitched speed. glitched_speed_drops_dw = [ - ("Dark Death Mountain Ledge Clip Spot", "Dark Death Mountain (Top)", "Dark Death Mountain Ledge") + ('Dark Death Mountain Ledge Clip', 'East Dark Death Mountain (Top)', 'Dark Death Mountain Ledge') ] # Out of bounds transitions using the mirror mirror_clip_spots_dw = [ - ("Dark Death Mountain Bunny Descent Mirror Spot", "West Dark Death Mountain (Bottom)", "West Dark World"), + ('Bunny DMD Mirror Spot', 'West Dark Death Mountain (Bottom)', 'Qirn Jump Area'), ( - "Dark Death Mountain Bunny Mirror To East Jump", - "West Dark Death Mountain (Bottom)", - "East Dark Death Mountain (Bottom)", + 'Dark Death Mountain Bunny Mirror To East Jump', + 'West Dark Death Mountain (Bottom)', + 'East Dark Death Mountain (Bottom)', ), - ("Desert East Mirror Clip", "Dark Desert", "Desert Palace Mouth"), + ('Desert East Mirror Clip', 'Mire Area', 'Desert Mouth'), ] # Mirror shenanigans placing a mirror portal with a broken camera -mirror_offset_spots_dw = [("Dark Death Mountain Offset Mirror", "West Dark Death Mountain (Bottom)", "East Dark World")] +mirror_offset_spots_dw = [('Dark Death Mountain Offset Mirror', 'West Dark Death Mountain (Bottom)', 'Pyramid Area')] # Mirror shenanigans placing a mirror portal with a broken camera - mirror_offset_spots_lw = [ - ("Death Mountain Offset Mirror", "West Death Mountain (Bottom)", "Light World"), - ("Death Mountain Uncle Offset Mirror", "West Death Mountain (Bottom)", "Hyrule Castle Secret Entrance Area"), - ("Death Mountain Castle Ledge Offset Mirror", "West Death Mountain (Bottom)", "Hyrule Castle Ledge"), + ('Death Mountain Offset Mirror', 'West Death Mountain (Bottom)', 'Hyrule Castle Area'), + ('Death Mountain Uncle Offset Mirror', 'West Death Mountain (Bottom)', 'Hyrule Castle Courtyard Northeast'), + ('Death Mountain Castle Ledge Offset Mirror', 'West Death Mountain (Bottom)', 'Hyrule Castle Ledge'), ] @@ -199,20 +195,19 @@ def create_owg_connections(world, player): """ if world.mode[player] == "inverted": connections = ( - inverted_boots_clip_exits_dw - + inverted_boots_clip_exits_lw + boots_clip_exits_dw + + boots_clip_exits_lw + glitched_speed_drops_dw + mirror_offset_spots_lw ) else: connections = ( - open_boots_clip_exits_dw - + open_boots_clip_exits_lw + boots_clip_exits_dw + + boots_clip_exits_lw + glitched_speed_drops_dw + mirror_clip_spots_dw + mirror_offset_spots_dw ) - create_no_logic_connections(player, world, connections) @@ -223,13 +218,13 @@ def overworld_glitches_rules(world, player): set_owg_rules( player, world, - inverted_boots_clip_exits_lw if inverted else open_boots_clip_exits_lw, + boots_clip_exits_lw, lambda state: state.can_boots_clip_lw(player), ) set_owg_rules( player, world, - inverted_boots_clip_exits_dw if inverted else open_boots_clip_exits_dw, + boots_clip_exits_dw, lambda state: state.can_boots_clip_dw(player), ) # Glitched speed drops. @@ -239,10 +234,10 @@ def overworld_glitches_rules(world, player): glitched_speed_drops_dw, lambda state: state.can_get_glitched_speed_dw(player), ) - # Dark Death Mountain Ledge Clip Spot also accessible with mirror. + # Dark Death Mountain Ledge Clip also accessible with mirror. if not inverted: add_alternate_rule( - world.get_entrance("Dark Death Mountain Ledge Clip Spot", player), lambda state: state.has_Mirror(player) + world.get_entrance('Dark Death Mountain Ledge Clip', player), lambda state: state.has_Mirror(player) ) # Mirror clip spots. @@ -264,45 +259,26 @@ def overworld_glitches_rules(world, player): # Regions that require the boots and some other stuff. if not inverted: - world.get_entrance("Turtle Rock Teleporter", player).access_rule = lambda state: ( - state.can_boots_clip_lw(player) or state.can_lift_heavy_rocks(player) - ) and state.has("Hammer", player) - add_alternate_rule( - world.get_entrance("Waterfall Fairy Access", player), + world.get_entrance('Zora Waterfall Approach', player), lambda state: state.has_Pearl(player) or state.has_Boots(player), ) # assumes access to Waterwalk ability (boots case) else: - add_alternate_rule(world.get_entrance("Waterfall Fairy Access", player), lambda state: state.has_Pearl(player)) + add_alternate_rule( + world.get_entrance('Zora Waterfall Approach', player), + lambda state: state.has_Pearl(player) + ) - world.get_entrance("Dark Desert Teleporter", player).access_rule = lambda state: ( - state.can_flute(player) or state.can_boots_clip_dw(player) - ) and state.can_lift_heavy_rocks(player) - - add_alternate_rule( - world.get_entrance("Dark Witch Rock (North)", player), lambda state: state.can_boots_clip_dw(player) - ) - add_alternate_rule( - world.get_entrance("Broken Bridge Pass (Top)", player), lambda state: state.can_boots_clip_dw(player) - ) add_alternate_rule( world.get_location("Zora's Ledge", player), lambda state: state.can_boots_clip_lw(player) ) # assumes access to Waterwalk ability - add_alternate_rule( - world.get_location('Maze Race', player), lambda state: state.can_boots_clip_lw(player) - ) - - # This is doable even with bad enemies - add_alternate_rule(world.get_location("Hobo", player), lambda state: state.can_boots_clip_lw(player)) - # Bunny pocket if not inverted: add_alternate_rule(world.get_entrance("Skull Woods Final Section", player), lambda state: state.can_bunny_pocket(player) and state.has("Fire Rod", player)) add_alternate_rule(world.get_entrance("Dark World Shop", player), lambda state: state.can_bunny_pocket(player) and state.has("Hammer", player)) - def add_alternate_rule(entrance, rule): old_rule = entrance.access_rule entrance.access_rule = lambda state: old_rule(state) or rule(state) diff --git a/Rules.py b/Rules.py index 136c433d..d125d765 100644 --- a/Rules.py +++ b/Rules.py @@ -84,6 +84,9 @@ def set_rules(world, player): if not world.swamp_patch_required[player]: add_rule(world.get_entrance('Swamp Lobby Moat', player), lambda state: state.has_Mirror(player)) + if world.logic[player] in ['owglitches', 'hybridglitches']: + overworld_glitches_rules(world, player) + set_bunny_rules(world, player, world.mode[player] == 'inverted') # These rules go here because the overwrite/add to some of the above rules @@ -2050,22 +2053,6 @@ def set_bunny_rules(world, player, inverted): else: return region.is_light_world - # Is it possible to do bunny pocket here - def can_bunny_pocket_skull_woods(world, player): - return world.get_entrance( - "Skull Woods Second Section Door (West)", player - ).connected_region.type == RegionType.Dungeon or ( - world.state.can_reach_from("Skull Woods Forest (West)", "Light World", 1) - and world.state.can_reach_from("Light World", "Skull Woods Forest (West)", 1) - ) - - def can_bunny_pocket_voo_shop(world, player): - return ( - world.state.can_reach_from("West Dark World", "Light World", 1) - and world.state.can_reach_from("Light World", "West Dark World", 1) - ) - - def get_rule_to_add(region, location=None, connecting_entrance=None): # In OWG, a location can potentially be superbunny-mirror accessible or # bunny revival accessible. @@ -2105,10 +2092,8 @@ def set_bunny_rules(world, player, inverted): if region.type == RegionType.Dungeon and new_region.type != RegionType.Dungeon: if entrance.name in OverworldGlitchRules.invalid_mirror_bunny_entrances: continue - # Is this a bunny pocketable entrance? - if entrance.name == 'Skull Woods Final Section' and not can_bunny_pocket_skull_woods(world, player) or \ - entrance.name == 'Dark World Shop' and not can_bunny_pocket_voo_shop(world, player): - continue + # todo - Is this a bunny pocketable entrance? + # Is there an entrance reachable to arm bunny pocket? For now, assume there is if entrance.name in drop_dungeon_entrances: lobby = entrance.connected_region else: @@ -2124,9 +2109,8 @@ def set_bunny_rules(world, player, inverted): elif region.type == RegionType.Cave and new_region.type != RegionType.Cave: if entrance.name in OverworldGlitchRules.invalid_mirror_bunny_entrances: continue - if entrance.name == 'Skull Woods Final Section' and not can_bunny_pocket_skull_woods(world, player) or \ - entrance.name == 'Dark World Shop' and not can_bunny_pocket_voo_shop(world, player): - continue + # todo - Is this a bunny pocketable entrance? + # Is there an entrance reachable to arm bunny pocket? For now, assume there is if region.name in OverworldGlitchRules.sword_required_superbunny_mirror_regions: possible_options.append(path_to_access_rule(new_path + [lambda state: state.has_Mirror(player) and state.has_sword(player)], entrance)) elif region.name in OverworldGlitchRules.boots_required_superbunny_mirror_regions: diff --git a/UnderworldGlitchRules.py b/UnderworldGlitchRules.py index 7ddfa792..c01e242f 100644 --- a/UnderworldGlitchRules.py +++ b/UnderworldGlitchRules.py @@ -220,6 +220,7 @@ def underworld_glitches_rules(world, player): def mirrorless_moat_rule(state): return ( state.can_reach("Old Man S&Q", "Entrance", player) + and state.has("Flippers", player) and mire_clip(state) and (hera_rule(state) or gt_rule(state)) ) diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index 2a80d82d..dcaf2daa 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -2194,7 +2194,7 @@ default_connections = {'Lost Woods Gamble': 'Lost Woods Gamble', 'Paradox Cave (Top)': 'Paradox Cave', 'Paradox Cave Exit (Bottom)': 'East Death Mountain (Bottom)', 'Paradox Cave Exit (Middle)': 'East Death Mountain (Bottom)', - 'Paradox Cave Exit (Top)': 'East Death Mountain (Top)', + 'Paradox Cave Exit (Top)': 'East Death Mountain (Top East)', 'Waterfall of Wishing': 'Waterfall of Wishing', 'Fortune Teller (Light)': 'Fortune Teller (Light)', 'Bonk Rock Cave': 'Bonk Rock Cave', diff --git a/test/NewTestSuite.py b/test/NewTestSuite.py index aca4e796..8e7b9e1c 100644 --- a/test/NewTestSuite.py +++ b/test/NewTestSuite.py @@ -28,7 +28,7 @@ def main(args=None): def test(test_name: str, command: str, test_file: str): tests[test_name] = [command] - base_command = f"python3.8 DungeonRandomizer.py --suppress_rom --suppress_spoiler" + base_command = f"python3 DungeonRandomizer.py --suppress_rom --suppress_spoiler" def gen_seed(): task_command = base_command + " " + command