From 6003d40ce20013777e51f46941418f7a683f3f63 Mon Sep 17 00:00:00 2001 From: compiling <8335770+compiling@users.noreply.github.com> Date: Thu, 19 Mar 2020 18:49:41 +1100 Subject: [PATCH] Update inverted big bomb rules. Add checks that will not allow unexpected entrances to get east dark world logic. --- Rules.py | 185 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 103 insertions(+), 82 deletions(-) diff --git a/Rules.py b/Rules.py index 576bcd56..0ae6ff61 100644 --- a/Rules.py +++ b/Rules.py @@ -414,7 +414,7 @@ def global_rules(world, player): else: forbid_item(world.get_location('Ganons Tower - Map Chest', player), 'Small Key (Ganons Tower)', player) - # It is possible to need more than 2 keys to get through this entance if you spend keys elsewhere. We reflect this in the chest requirements. + # It is possible to need more than 2 keys to get through this entrance if you spend keys elsewhere. We reflect this in the chest requirements. # However we need to leave these at the lower values to derive that with 3 keys it is always possible to reach Bob and Ice Armos. set_rule(world.get_entrance('Ganons Tower (Double Switch Room)', player), lambda state: state.has_key('Small Key (Ganons Tower)', player, 2)) # It is possible to need more than 3 keys .... @@ -1311,6 +1311,7 @@ def set_big_bomb_rules(world, player): # -> (M and Mitts) or ((Mitts or Flute or (M and P and West Dark World access)) and BR) add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: (state.can_lift_heavy_rocks(player) and state.has_Mirror(player)) or ((state.can_lift_heavy_rocks(player) or state.has('Ocarina', player) or (state.can_reach('West Dark World', 'Region', player) and state.has_Pearl(player) and state.has_Mirror(player))) and basic_routes(state))) + def set_inverted_big_bomb_rules(world, player): bombshop_entrance = world.get_region('Inverted Big Bomb Shop', player).entrances[0] Normal_LW_entrances = ['Blinds Hideout', @@ -1328,9 +1329,7 @@ def set_inverted_big_bomb_rules(world, player): 'Fortune Teller (Light)', 'Snitch Lady (East)', 'Snitch Lady (West)', - 'Bush Covered House', 'Tavern (Front)', - 'Light World Bomb Hut', 'Kakariko Shop', 'Mini Moldorm Cave', 'Long Fairy Cave', @@ -1341,7 +1340,6 @@ def set_inverted_big_bomb_rules(world, player): 'Bonk Rock Cave', 'Library', 'Potion Shop', - 'Waterfall of Wishing', 'Dam', 'Lumberjack House', 'Lake Hylia Fortune Teller', @@ -1357,22 +1355,42 @@ def set_inverted_big_bomb_rules(world, player): 'Two Brothers House (East)', 'Sanctuary', 'Hyrule Castle Entrance (South)', - 'Hyrule Castle Secret Entrance Stairs'] - LW_walkable_entrances = ['Dark Lake Hylia Ledge Fairy', - 'Dark Lake Hylia Ledge Spike Cave', - 'Dark Lake Hylia Ledge Hint', - 'Mire Shed', - 'Dark Desert Hint', - 'Dark Desert Fairy', - 'Misery Mire'] + 'Hyrule Castle Secret Entrance Stairs', + 'Hyrule Castle Entrance (West)', + 'Hyrule Castle Entrance (East)', + 'Inverted Ganons Tower', + 'Cave 45', + 'Checkerboard Cave', + 'Inverted Big Bomb Shop'] + Isolated_LW_entrances = ['Old Man Cave (East)', + 'Old Man House (Bottom)', + 'Old Man House (Top)', + 'Death Mountain Return Cave (East)', + 'Spectacle Rock Cave Peak', + 'Tower of Hera', + 'Death Mountain Return Cave (West)', + 'Paradox Cave (Top)', + 'Fairy Ascension Cave (Top)', + 'Spiral Cave', + 'Paradox Cave (Bottom)', + 'Paradox Cave (Middle)', + 'Hookshot Fairy', + 'Spiral Cave (Bottom)', + 'Mimic Cave', + 'Fairy Ascension Cave (Bottom)', + 'Desert Palace Entrance (West)', + 'Desert Palace Entrance (North)', + 'Desert Palace Entrance (South)'] + Eastern_DW_entrances = ['Palace of Darkness', + 'Palace of Darkness Hint', + 'Dark Lake Hylia Fairy', + 'East Dark World Hint'] Northern_DW_entrances = ['Brewery', 'C-Shaped House', 'Chest Game', 'Dark World Hammer Peg Cave', - 'Red Shield Shop', - 'Dark Sanctuary Hint', + 'Inverted Dark Sanctuary', 'Fortune Teller (Dark)', - 'Dark World Shop', 'Dark World Lumberjack Shop', 'Thieves Town', 'Skull Woods First Section Door', @@ -1380,16 +1398,14 @@ def set_inverted_big_bomb_rules(world, player): Southern_DW_entrances = ['Hype Cave', 'Bonk Fairy (Dark)', 'Archery Game', - 'Inverted Big Bomb Shop', + 'Inverted Links House', 'Dark Lake Hylia Shop', 'Swamp Palace'] Isolated_DW_entrances = ['Spike Cave', 'Cave Shop (Dark Death Mountain)', 'Dark Death Mountain Fairy', - 'Mimic Cave', 'Skull Woods Second Section Door (West)', 'Skull Woods Final Section', - 'Ice Palace', 'Turtle Rock', 'Dark Death Mountain Ledge (West)', 'Dark Death Mountain Ledge (East)', @@ -1400,42 +1416,23 @@ def set_inverted_big_bomb_rules(world, player): 'Turtle Rock Isolated Ledge Entrance', 'Hookshot Cave Back Entrance', 'Inverted Agahnims Tower'] - Isolated_LW_entrances = ['Capacity Upgrade', - 'Tower of Hera', - 'Death Mountain Return Cave (West)', - 'Paradox Cave (Top)', - 'Fairy Ascension Cave (Top)', - 'Spiral Cave', - 'Desert Palace Entrance (East)'] - West_LW_DM_entrances = ['Old Man Cave (East)', - 'Old Man House (Bottom)', - 'Old Man House (Top)', - 'Death Mountain Return Cave (East)', - 'Spectacle Rock Cave Peak', - 'Spectacle Rock Cave', - 'Spectacle Rock Cave (Bottom)'] - East_LW_DM_entrances = ['Paradox Cave (Bottom)', - 'Paradox Cave (Middle)', - 'Hookshot Fairy', - 'Spiral Cave (Bottom)'] - Mirror_from_SDW_entrances = ['Two Brothers House (West)', - 'Cave 45'] - Castle_ledge_entrances = ['Hyrule Castle Entrance (West)', - 'Hyrule Castle Entrance (East)', - 'Inverted Ganons Tower'] - Desert_mirrorable_ledge_entrances = ['Desert Palace Entrance (West)', - 'Desert Palace Entrance (North)', - 'Desert Palace Entrance (South)', - 'Checkerboard Cave',] - Desert_ledge_entrances = ['Desert Palace Entrance (West)', - 'Desert Palace Entrance (North)', - 'Desert Palace Entrance (South)'] - - set_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.can_reach('East Dark World', 'Region', player) and state.can_reach('Inverted Big Bomb Shop', 'Region', player) and state.has('Crystal 5', player) and state.has('Crystal 6', player)) + LW_walkable_entrances = ['Dark Lake Hylia Ledge Fairy', + 'Dark Lake Hylia Ledge Spike Cave', + 'Dark Lake Hylia Ledge Hint', + 'Mire Shed', + 'Dark Desert Hint', + 'Dark Desert Fairy', + 'Misery Mire', + 'Red Shield Shop'] + LW_bush_entrances = ['Bush Covered House', + 'Light World Bomb Hut', + 'Graveyard Cave'] + LW_inaccessible_entrances = ['Desert Palace Entrance (East)', + 'Spectacle Rock Cave', + 'Spectacle Rock Cave (Bottom)'] - #crossing peg bridge starting from the southern dark world - def cross_peg_bridge(state): - return state.has('Hammer', player) + set_rule(world.get_entrance('Pyramid Fairy', player), + lambda state: state.can_reach('East Dark World', 'Region', player) and state.can_reach('Inverted Big Bomb Shop', 'Region', player) and state.has('Crystal 5', player) and state.has('Crystal 6', player)) # Key for below abbreviations: # P = pearl @@ -1443,42 +1440,66 @@ def set_inverted_big_bomb_rules(world, player): # H = hammer # M = Mirror # G = Glove - if bombshop_entrance.name in Normal_LW_entrances: + if bombshop_entrance.name in Eastern_DW_entrances: + # Just walk to the pyramid + pass + elif bombshop_entrance.name in Normal_LW_entrances: + # Just walk to the castle and mirror. add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.has_Mirror(player)) - elif bombshop_entrance.name in LW_walkable_entrances: - add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.can_flute(player)) - elif bombshop_entrance.name in Northern_DW_entrances: - add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.can_flute or (state.can_lift_heavy_rocks(player) and (cross_peg_bridge(state) or (state.has_Mirror(player) and state.has('Beat Agahnim 1', player))))) - elif bombshop_entrance.name == 'Bumper Cave (Bottom)': - add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.can_flute or (state.can_lift_heavy_rocks(player) and (cross_peg_bridge(state) or state.has_Mirror(player) and state.has('Beat Agahnim 1', player)))) - elif bombshop_entrance.name in Southern_DW_entrances: - add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: cross_peg_bridge(state) or state.can_flute(player) or (state.has_Mirror(player) and state.has('Beat Agahnim 1', player))) - elif bombshop_entrance.name in Isolated_DW_entrances: - add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.can_flute(player)) elif bombshop_entrance.name in Isolated_LW_entrances: + # For these entrances, you cannot walk to the castle/pyramid and thus must use Mirror and then Flute. add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.can_flute(player) and state.has_Mirror(player)) - elif bombshop_entrance.name in West_LW_DM_entrances: - add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.can_flute(player) and state.has_Mirror(player)) - elif bombshop_entrance.name in East_LW_DM_entrances: - add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.can_flute(player) and state.has_Mirror(player)) - elif bombshop_entrance.name == 'Fairy Ascension Cave (Bottom)': - add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.can_flute(player) and state.has_Mirror(player)) - elif bombshop_entrance.name in Castle_ledge_entrances: - add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.has_Mirror(player)) - elif bombshop_entrance.name in Desert_ledge_entrances: - add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.has_Mirror(player) and state.can_flute(player)) - elif bombshop_entrance.name == 'Checkerboard Cave': - add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.has_Mirror(player)) + elif bombshop_entrance.name in Northern_DW_entrances: + # You can just fly with the Flute, you can take a long walk with Mitts and Hammer, + # or you can leave a Mirror portal nearby and then walk to the castle to Mirror again. + add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.can_flute or (state.can_lift_heavy_rocks(player) and state.has('Hammer', player)) or (state.has_Mirror(player) and state.can_reach('Light World', 'Region', player))) + elif bombshop_entrance.name in Southern_DW_entrances: + # This is the same as north DW without the Mitts rock present. + add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.has('Hammer', player) or state.can_flute(player) or (state.has_Mirror(player) and state.can_reach('Light World', 'Region', player))) + elif bombshop_entrance.name in Isolated_DW_entrances: + # There's just no way to escape these places with the bomb and no Flute. + add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.can_flute(player)) + elif bombshop_entrance.name in LW_walkable_entrances: + # You can fly with the flute, or leave a mirror portal and walk through the light world + add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.can_flute(player) or (state.has_Mirror(player) and state.can_reach('Light World', 'Region', player))) + elif bombshop_entrance.name in LW_bush_entrances: + # These entrances are behind bushes in LW so you need either Pearl or the tools to solve NDW bomb shop locations. + add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.has_Mirror(player) and (state.can_flute(player) or state.has_Pearl(player) or (state.can_lift_heavy_rocks(player) and state.has('Hammer', player)))) + elif bombshop_entrance.name == 'Dark World Shop': + # This is mostly the same as NDW but the Mirror path requires the Pearl, or using the Hammer + add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.can_flute or (state.can_lift_heavy_rocks(player) and state.has('Hammer', player)) or (state.has_Mirror(player) and state.can_reach('Light World', 'Region', player) and (state.has_Pearl(player) or state.has('Hammer', player)))) + elif bombshop_entrance.name == 'Bumper Cave (Bottom)': + # This is mostly the same as NDW but the Mirror path requires being able to lift a rock. + add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.can_flute or (state.can_lift_heavy_rocks(player) and state.has('Hammer', player)) or (state.has_Mirror(player) and state.can_lift_rocks(player) and state.can_reach('Light World', 'Region', player))) elif bombshop_entrance.name == 'Old Man Cave (West)': - add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.has_Mirror(player) and ((state.can_lift_rocks(player) and cross_peg_bridge(state)) or state.can_flute(player))) - elif bombshop_entrance.name == 'Graveyard Cave': - add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.has_Mirror(player)) - elif bombshop_entrance.name in Mirror_from_SDW_entrances: - add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.has_Mirror(player) and (state.can_flute(player) or cross_peg_bridge(state))) + # The three paths back are Mirror and DW walk, Mirror and Flute, or LW walk and then Mirror. + add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.has_Mirror(player) and ((state.can_lift_heavy_rocks(player) and state.has('Hammer', player)) or (state.can_lift_rocks(player) and state.has_Pearl(player)) or state.can_flute(player))) elif bombshop_entrance.name == 'Dark World Potion Shop': + # You either need to Flute to 5 or cross the rock/hammer choice pass to the south. add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.can_flute(player) or state.has('Hammer', player) or state.can_lift_rocks(player)) elif bombshop_entrance.name == 'Kings Grave': - add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.can_lift_heavy_rocks(player) and state.has_Mirror(player)) + # Either lift the rock and walk to the castle to Mirror or Mirror immediately and Flute. + add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: (state.can_flute(player) or (state.has_Pearl(player) and state.can_lift_heavy_rocks(player))) and state.has_Mirror(player)) + elif bombshop_entrance.name == 'Two Brothers House (West)': + # First you must Mirror. Then you can either Flute, cross the peg bridge, or use the Agah 1 portal to Mirror again. + add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: (state.can_flute(player) or state.has('Hammer', player) or state.has('Beat Agahnim 1', player)) and state.has_Mirror(player)) + elif bombshop_entrance.name == 'Waterfall of Wishing': + # You absolutely must be able to swim to return it from here. + add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.has('Flippers', player) and state.has_Pearl(player) and state.has_Mirror(player)) + elif bombshop_entrance.name == 'Ice Palace': + # You can swim to the dock or use the Flute to get off the island. + add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.has('Flippers', player) or state.can_flute(player)) + elif bombshop_entrance.name == 'Capacity Upgrade': + # You must Mirror but then can use either Ice Palace return path. + add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: (state.has('Flippers', player) or state.can_flute(player)) and state.has_Mirror(player)) + elif bombshop_entrance.name in LW_inaccessible_entrances: + # You can't get to the pyramid from these entrances without bomb duping. + raise Exception('No valid path to open Pyramid Fairy. (Could not route from %s)' % bombshop_entrance.name) + elif bombshop_entrance.name == 'Pyramid Fairy': + # Self locking. The shuffles don't put the bomb shop here, but doesn't lock anything important. + set_rule(world.get_entrance('Pyramid Fairy', player), lambda state: False) + else: + raise Exception('No logic found for routing from %s to the pyramid.' % bombshop_entrance.name) def set_bunny_rules(world, player):