Merge branch 'OverworldShuffleDev' into OverworldShuffle

This commit is contained in:
codemann8
2021-11-06 04:45:19 -05:00
10 changed files with 133 additions and 477 deletions

View File

@@ -1581,15 +1581,71 @@ class Entrance(object):
self.player = player
self.door = None
self.hide_path = False
self.temp_path = []
def can_reach(self, state):
if self.parent_region.can_reach(state) and self.access_rule(state):
if not self.hide_path and not self in state.path:
state.path[self] = (self.name, state.path.get(self.parent_region, (self.parent_region.name, None)))
return True
# Destination Pickup OW Only No Ledges Can S&Q
multi_step_locations = { 'Pyramid Crack': ('Big Bomb', True, True, False),
'Missing Smith': ('Frog', True, False, True),
'Middle Aged Man': ('Dark Blacksmith Ruins', True, False, True) }
if self.name in multi_step_locations:
if self not in state.path:
world = self.parent_region.world if self.parent_region else None
step_location = world.get_location(multi_step_locations[self.name][0], self.player)
if step_location.can_reach(state) and self.can_reach_thru(state, step_location.parent_region, multi_step_locations[self.name][1], multi_step_locations[self.name][2], multi_step_locations[self.name][3]) and self.access_rule(state):
if not self in state.path:
path = state.path.get(step_location.parent_region, (step_location.parent_region.name, None))
item_name = step_location.item.name if step_location.item else 'Pick Up Item'
path = (f'{step_location.parent_region.name} Exit', (item_name, path))
while len(self.temp_path):
exit = self.temp_path.pop(0)
path = (exit.name, (exit.parent_region.name, path))
item_name = self.connected_region.locations[0].item.name if self.connected_region.locations[0].item else 'Deliver Item'
path = (item_name, (self.parent_region.name, path))
state.path[self] = (self.name, path)
return True
else:
return True
else:
if self.parent_region.can_reach(state) and self.access_rule(state):
if not self.hide_path and not self in state.path:
state.path[self] = (self.name, state.path.get(self.parent_region, (self.parent_region.name, None)))
return True
return False
def can_reach_thru(self, state, start_region, ignore_underworld=False, ignore_ledges=False, allow_save_quit=False):
def explore_region(region, path = []):
nonlocal found
if region not in explored_regions or len(explored_regions[region]) > len(path):
explored_regions[region] = path
for exit in region.exits:
if exit.connected_region and (not ignore_ledges or exit.spot_type != 'Ledge') \
and exit.connected_region.name not in ['Dig Game Area'] \
and exit.access_rule(state):
if exit.connected_region == self.parent_region:
found = True
explored_regions[self.parent_region] = path + [exit]
elif not ignore_underworld or region.type == exit.connected_region.type or exit.connected_region.type not in [RegionType.Cave, RegionType.Dungeon]:
explore_region(exit.connected_region, path + [exit])
found = False
explored_regions = {}
explore_region(start_region.entrances[0].parent_region)
if found:
self.temp_path = explored_regions[self.parent_region]
elif allow_save_quit:
world = self.parent_region.world if self.parent_region else None
exit = world.get_entrance('Links House S&Q', self.player)
explore_region(exit.connected_region, [exit])
if found:
self.temp_path = explored_regions[self.parent_region]
#TODO: Implement residual mirror portal placing for the previous leg, to be used for the final destination
return found
def connect(self, region, addresses=None, target=None, vanilla=None):
self.connected_region = region
self.target = target
@@ -2851,7 +2907,7 @@ class Spoiler(object):
outfile.write('\n\nBottle Refills:\n\n')
for fairy, bottle in self.bottles.items():
outfile.write(f'\n{fairy}: {bottle}')
outfile.write(f'{fairy}: {bottle}\n')
if self.overworlds:
# overworlds: overworld transitions;

View File

@@ -1,5 +1,10 @@
# Changelog
### 0.2.2.0
- Delivering Big Red Bomb is now in logic
- Smith/Purple Chest have proper dynamic pathing to fix logical issues
- Fixed issue with bomb walls in OW not requiring moon pearl in DW
### 0.2.1.3
- New fake flipper handling to allow S+Q rather than insta-kill
- Fixed whirlpools in Crossed OW

View File

@@ -557,10 +557,10 @@ def link_entrances(world, player):
if world.logic[player] in ['noglitches', 'minorglitches'] or (invFlag != (0x1b in world.owswaps[player][0] and world.owMixed[player])):
bomb_shop_doors = [e for e in entrance_pool if e not in ['Pyramid Fairy']]
bomb_shop = random.choice(bomb_shop_doors)
pool.remove(bomb_shop)
connect_entrance(world, bomb_shop, 'Big Bomb Shop', player)
# shuffle connectors
pool = [e for e in pool if e in entrance_pool]
connect_caves(world, pool, [], caves, player)
# place remaining doors
@@ -2184,6 +2184,7 @@ mandatory_connections = [('Links House S&Q', 'Links House'),
('Fairy Ascension Cave Climb', 'Fairy Ascension Cave (Top)'),
('Fairy Ascension Cave Pots', 'Fairy Ascension Cave (Bottom)'),
('Fairy Ascension Cave Drop', 'Fairy Ascension Cave (Drop)'),
('Missing Smith', 'Missing Smith'),
('Superbunny Cave Climb', 'Superbunny Cave (Top)'),
('Hookshot Cave Front to Middle', 'Hookshot Cave (Middle)'),
('Hookshot Cave Middle to Front', 'Hookshot Cave (Front)'),

View File

@@ -214,6 +214,9 @@ def generate_itempool(world, player):
world.push_item(world.get_location('Dark Blacksmith Ruins', player), ItemFactory('Pick Up Purple Chest', player), False)
world.get_location('Dark Blacksmith Ruins', player).event = True
world.get_location('Dark Blacksmith Ruins', player).locked = True
world.push_item(world.get_location('Middle Aged Man', player), ItemFactory('Deliver Purple Chest', player), False)
world.get_location('Middle Aged Man', player).event = True
world.get_location('Middle Aged Man', player).locked = True
world.push_item(world.get_location('Frog', player), ItemFactory('Get Frog', player), False)
world.get_location('Frog', player).event = True
world.get_location('Frog', player).locked = True
@@ -223,6 +226,12 @@ def generate_itempool(world, player):
world.push_item(world.get_location('Floodgate', player), ItemFactory('Open Floodgate', player), False)
world.get_location('Floodgate', player).event = True
world.get_location('Floodgate', player).locked = True
world.push_item(world.get_location('Big Bomb', player), ItemFactory('Pick Up Big Bomb', player), False)
world.get_location('Big Bomb', player).event = True
world.get_location('Big Bomb', player).locked = True
world.push_item(world.get_location('Pyramid Crack', player), ItemFactory('Detonate Big Bomb', player), False)
world.get_location('Pyramid Crack', player).event = True
world.get_location('Pyramid Crack', player).locked = True
world.push_item(world.get_location('Trench 1 Switch', player), ItemFactory('Trench 1 Filled', player), False)
world.get_location('Trench 1 Switch', player).event = True
world.get_location('Trench 1 Switch', player).locked = True

View File

@@ -176,7 +176,10 @@ item_table = {'Bow': (True, False, None, 0x0B, 200, 'You have\nchosen the\narche
'Get Frog': (True, False, 'Event', 999, None, None, None, None, None, None, None, None),
'Return Smith': (True, False, 'Event', 999, None, None, None, None, None, None, None, None),
'Pick Up Purple Chest': (True, False, 'Event', 999, None, None, None, None, None, None, None, None),
'Deliver Purple Chest': (True, False, 'Event', 999, None, None, None, None, None, None, None, None),
'Open Floodgate': (True, False, 'Event', 999, None, None, None, None, None, None, None, None),
'Pick Up Big Bomb': (True, False, 'Event', 999, None, None, None, None, None, None, None, None),
'Detonate Big Bomb': (True, False, 'Event', 999, None, None, None, None, None, None, None, None),
'Trench 1 Filled': (True, False, 'Event', 999, None, None, None, None, None, None, None, None),
'Trench 2 Filled': (True, False, 'Event', 999, None, None, None, None, None, None, None, None),
'Drained Swamp': (True, False, 'Event', 999, None, None, None, None, None, None, None, None),

View File

@@ -567,7 +567,7 @@ def create_playthrough(world):
# get locations containing progress items
prog_locations = [location for location in world.get_filled_locations() if location.item.advancement]
optional_locations = ['Trench 1 Switch', 'Trench 2 Switch', 'Ice Block Drop']
optional_locations = ['Trench 1 Switch', 'Trench 2 Switch', 'Ice Block Drop', 'Big Bomb']
state_cache = [None]
collection_spheres = []
state = CollectionState(world)

View File

@@ -820,6 +820,7 @@ OWTileRegions = bidict({
'Ice Cave Area': 0x37,
'Desert Pass Area': 0x3a,
'Middle Aged Man': 0x3a,
'Desert Pass Southeast': 0x3a,
'Desert Pass Ledge': 0x3a,
@@ -891,6 +892,7 @@ OWTileRegions = bidict({
'Shield Shop Fence': 0x5a,
'Pyramid Area': 0x5b,
'Pyramid Crack': 0x5b,
'Pyramid Exit Ledge': 0x5b,
'Pyramid Pass': 0x5b,
@@ -1403,8 +1405,6 @@ OWExitTypes = {
'Zora Waterfall Water Drop',
'Bonk Rock Ledge Drop',
'Graveyard Ledge Drop',
'River Bend Water Drop',
'River Bend East Water Drop',
'Potion Shop Water Drop',
'Potion Shop Northeast Water Drop',
'Zora Approach Bottom Ledge Drop',
@@ -1444,13 +1444,9 @@ OWExitTypes = {
'Dam Cliff Ledge Drop',
'Bombos Tablet Drop',
'Cave 45 Ledge Drop',
'Lake Hylia Water Drop',
'Lake Hylia South Water Drop',
'Lake Hylia Northeast Water Drop',
'Lake Hylia Central Water Drop',
'Lake Hylia Island Water Drop',
'Desert Pass Ledge Drop',
'Octoballoon Water Drop',
'Octoballoon Waterfall Water Drop',
'Dark Death Mountain Drop (West)',
'Dark Death Mountain Drop (East)',
@@ -1460,7 +1456,6 @@ OWExitTypes = {
'Bumper Cave Ledge Drop',
'Bumper Cave Entrance Drop',
'Qirn Jump Water Drop',
'Qirn Jump East Water Drop',
'Dark Witch Water Drop',
'Dark Witch Northeast Water Drop',
'Catfish Approach Bottom Ledge Drop',
@@ -1483,6 +1478,8 @@ OWExitTypes = {
'Dark Bonk Rocks Cliff Ledge Drop',
'Bomb Shop Cliff Ledge Drop',
'Hammer Bridge South Cliff Ledge Drop',
'Ice Lake Northeast Pier Hop',
'Ice Lake Moat Bomb Jump',
'Ice Lake Area Cliff Ledge Drop',
'Ice Palace Island FAWT Ledge Drop',
'Hammer Bridge EC Cliff Water Drop',
@@ -1499,10 +1496,8 @@ OWExitTypes = {
'Swamp Nook Cliff Ledge Drop',
'Swamp Cliff Ledge Drop',
'Ice Lake Water Drop',
'Ice Lake Northeast Water Drop',
'Ice Lake Southwest Water Drop',
'Ice Lake Southeast Water Drop',
'Bomber Corner Water Drop',
'Bomber Corner Waterfall Water Drop'
],
'OWTerrain': ['Lost Woods Bush (West)',
@@ -1528,7 +1523,9 @@ OWExitTypes = {
'Graveyard Ladder (Bottom)',
'Graveyard Ladder (Top)',
'Kings Grave Inner Rocks',
'River Bend Water Drop',
'River Bend West Pier',
'River Bend East Water Drop',
'River Bend East Pier',
'Potion Shop Rock (South)',
'Potion Shop Rock (North)',
@@ -1566,14 +1563,19 @@ OWExitTypes = {
'C Whirlpool Rock (Top)',
'Statues Water Entry',
'Statues Landing',
'Lake Hylia Central Water Drop',
'Lake Hylia Central Island Pier',
'Lake Hylia Island Pier',
'Lake Hylia Water Drop',
'Lake Hylia West Pier',
'Lake Hylia Northeast Water Drop',
'Lake Hylia East Pier',
'Desert Pass Ladder (South)',
'Desert Pass Rocks (North)',
'Desert Pass Rocks (South)',
'Desert Pass Ladder (North)',
'Middle Aged Man',
'Octoballoon Water Drop',
'Octoballoon Pier',
'Skull Woods Bush Rock (East)',
'Skull Woods Bush Rock (West)',
@@ -1590,6 +1592,7 @@ OWExitTypes = {
'Skull Woods Pass Rock (Bottom)',
'Dark Graveyard Bush (South)',
'Dark Graveyard Bush (North)',
'Qirn Jump East Water Drop',
'Qirn Jump Pier',
'Dark Witch Rock (South)',
'Dark Witch Rock (North)',
@@ -1597,6 +1600,7 @@ OWExitTypes = {
'Catfish Approach Rocks (East)',
'Village of Outcasts Pegs',
'Grassy Lawn Pegs',
'Pyramid Crack',
'Broken Bridge Hammer Rock (South)',
'Broken Bridge Hammer Rock (North)',
'Broken Bridge Hookshot Gap',
@@ -1617,11 +1621,12 @@ OWExitTypes = {
'Dark C Whirlpool Rock (Top)',
'Hype Cave Water Entry',
'Hype Cave Landing',
'Ice Lake Northeast Water Drop',
'Ice Lake Northeast Pier',
'Ice Lake Moat Water Entry',
'Ice Lake Northeast Pier Bomb Jump',
'Ice Palace Approach',
'Ice Palace Leave',
'Bomber Corner Water Drop',
'Bomber Corner Pier'
],
'Portal': ['West Death Mountain Teleporter',

View File

@@ -3,7 +3,7 @@ from BaseClasses import OWEdge, WorldType, RegionType, Direction, Terrain, PolSl
from Regions import mark_dark_world_regions, mark_light_world_regions
from OWEdges import OWTileRegions, OWTileGroups, OWEdgeGroups, OWExitTypes, OpenStd, parallel_links, IsParallel
__version__ = '0.2.1.3-u'
__version__ = '0.2.2.0-u'
def link_overworld(world, player):
# setup mandatory connections
@@ -902,6 +902,7 @@ mandatory_connections = [# Intra-tile OW Connections
('Desert Pass Ledge Drop', 'Desert Pass Area'),
('Desert Pass Rocks (North)', 'Desert Pass Southeast'), #glove
('Desert Pass Rocks (South)', 'Desert Pass Area'), #glove
('Middle Aged Man', 'Middle Aged Man'),
('Octoballoon Water Drop', 'Octoballoon Water'), #flippers
('Octoballoon Waterfall Water Drop', 'Octoballoon Water'), #flippers
('Octoballoon Pier', 'Octoballoon Area'),
@@ -942,6 +943,7 @@ mandatory_connections = [# Intra-tile OW Connections
('Shield Shop Fence (Outer) Ledge Drop', 'Shield Shop Fence'),
('Shield Shop Fence (Inner) Ledge Drop', 'Shield Shop Area'),
('Pyramid Exit Ledge Drop', 'Pyramid Area'),
('Pyramid Crack', 'Pyramid Crack'),
('Broken Bridge Hammer Rock (South)', 'Broken Bridge Northeast'), #hammer/glove
('Broken Bridge Hammer Rock (North)', 'Broken Bridge Area'), #hammer/glove
('Broken Bridge Hookshot Gap', 'Broken Bridge West'), #hookshot
@@ -1023,7 +1025,8 @@ mandatory_connections = [# Intra-tile OW Connections
('Dark Bonk Rocks Cliff Ledge Drop', 'Dark Bonk Rocks Area'),
('Hammer Bridge South Cliff Ledge Drop', 'Hammer Bridge South Area'),
('Ice Lake Area Cliff Ledge Drop', 'Ice Lake Area'),
('Ice Lake Northeast Pier Bomb Jump', 'Ice Lake Northeast Bank'),
('Ice Lake Northeast Pier Hop', 'Ice Lake Northeast Bank'),
('Ice Lake Moat Bomb Jump', 'Ice Lake Moat'),
('Dark C Whirlpool Cliff Ledge Drop', 'Dark C Whirlpool Area'),
('Dark C Whirlpool Outer Cliff Ledge Drop', 'Dark C Whirlpool Outer Area'),
('Hype Cliff Ledge Drop', 'Hype Cave Area'),

View File

@@ -111,7 +111,8 @@ def create_regions(world, player):
create_lw_region(player, 'Lake Hylia Island', ['Lake Hylia Island'], ['Lake Hylia Island Water Drop']),
create_lw_region(player, 'Lake Hylia Water', None, ['Lake Hylia Central Island Pier', 'Lake Hylia Island Pier', 'Lake Hylia West Pier', 'Lake Hylia East Pier', 'Lake Hylia NC', 'Lake Hylia EC', 'Lake Hylia Whirlpool'], Terrain.Water),
create_lw_region(player, 'Ice Cave Area', None, ['Ice Rod Cave', 'Good Bee Cave', '20 Rupee Cave', 'Shopping Mall Mirror Spot', 'Ice Cave SE', 'Ice Cave SW']),
create_lw_region(player, 'Desert Pass Area', ['Purple Chest'], ['Desert Pass Ladder (South)', 'Desert Fairy', '50 Rupee Cave', 'Swamp Nook Mirror Spot', 'Desert Pass WS', 'Desert Pass EC', 'Desert Pass Rocks (North)']),
create_lw_region(player, 'Desert Pass Area', ['Middle Aged Man'], ['Desert Pass Ladder (South)', 'Middle Aged Man', 'Desert Fairy', '50 Rupee Cave', 'Swamp Nook Mirror Spot', 'Desert Pass WS', 'Desert Pass EC', 'Desert Pass Rocks (North)']),
create_lw_region(player, 'Middle Aged Man', ['Purple Chest'], None),
create_lw_region(player, 'Desert Pass Southeast', None, ['Desert Pass Rocks (South)', 'Swamp Nook Southeast Mirror Spot', 'Desert Pass ES']),
create_lw_region(player, 'Desert Pass Ledge', None, ['Desert Pass Ladder (North)', 'Desert Pass Ledge Drop', 'Swamp Nook Pegs Mirror Spot', 'Desert Pass WC']),
create_lw_region(player, 'Dam Area', ['Sunken Treasure'], ['Dam', 'Swamp Mirror Spot', 'Dam WC', 'Dam WS', 'Dam NC', 'Dam EC']),
@@ -163,7 +164,8 @@ def create_regions(world, player):
create_dw_region(player, 'Dark Grassy Lawn', None, ['Grassy Lawn Pegs', 'Dark World Shop', 'Kakariko Grass Mirror Spot']),
create_dw_region(player, 'Shield Shop Area', None, ['Shield Shop Fence (Outer) Ledge Drop', 'Forgotton Forest Mirror Spot', 'Shield Shop NW', 'Shield Shop NE']),
create_dw_region(player, 'Shield Shop Fence', None, ['Shield Shop Fence (Inner) Ledge Drop', 'Red Shield Shop', 'Forgotton Forest Fence Mirror Spot']),
create_dw_region(player, 'Pyramid Area', ['Pyramid'], ['Pyramid Fairy', 'Pyramid Hole', 'HC Ledge Mirror Spot', 'HC Courtyard Mirror Spot', 'HC Area Mirror Spot', 'HC East Entry Mirror Spot', 'Pyramid ES']),
create_dw_region(player, 'Pyramid Area', ['Pyramid'], ['Pyramid Fairy', 'Pyramid Crack', 'Pyramid Hole', 'HC Ledge Mirror Spot', 'HC Courtyard Mirror Spot', 'HC Area Mirror Spot', 'HC East Entry Mirror Spot', 'Pyramid ES']),
create_dw_region(player, 'Pyramid Crack', ['Pyramid Crack'], None),
create_dw_region(player, 'Pyramid Exit Ledge', None, ['Pyramid Exit Ledge Drop', 'HC Courtyard Left Mirror Spot', 'Pyramid Entrance']),
create_dw_region(player, 'Pyramid Pass', None, ['Post Aga Inverted Teleporter', 'HC Area South Mirror Spot', 'Pyramid SW', 'Pyramid SE']),
create_dw_region(player, 'Broken Bridge Area', None, ['Broken Bridge Hammer Rock (South)', 'Broken Bridge Water Drop', 'Wooden Bridge Mirror Spot', 'Broken Bridge SW']),
@@ -206,8 +208,8 @@ def create_regions(world, player):
create_dw_region(player, 'Ice Lake Northeast Bank', None, ['Ice Lake Northeast Water Drop', 'Lake Hylia Northeast Mirror Spot', 'Ice Lake NE']),
create_dw_region(player, 'Ice Lake Ledge (West)', None, ['Ice Lake Southwest Water Drop', 'South Shore Mirror Spot', 'Ice Lake WS']),
create_dw_region(player, 'Ice Lake Ledge (East)', None, ['Ice Lake Southeast Water Drop', 'South Shore East Mirror Spot', 'Ice Lake ES']),
create_dw_region(player, 'Ice Lake Water', None, ['Ice Lake Northeast Pier', 'Lake Hylia Island Mirror Spot', 'Ice Lake NC', 'Ice Lake EC'], Terrain.Water),
create_dw_region(player, 'Ice Lake Moat', None, ['Ice Lake Moat Water Entry', 'Ice Lake Northeast Pier Bomb Jump', 'Ice Palace Approach', 'Lake Hylia Water Mirror Spot']),
create_dw_region(player, 'Ice Lake Water', None, ['Ice Lake Northeast Pier', 'Ice Lake Moat Bomb Jump', 'Lake Hylia Island Mirror Spot', 'Ice Lake NC', 'Ice Lake EC'], Terrain.Water),
create_dw_region(player, 'Ice Lake Moat', None, ['Ice Lake Moat Water Entry', 'Ice Lake Northeast Pier Hop', 'Ice Palace Approach', 'Lake Hylia Water Mirror Spot']),
create_dw_region(player, 'Ice Palace Area', None, ['Ice Palace Leave', 'Ice Palace', 'Ice Palace Teleporter', 'Lake Hylia Central Island Mirror Spot']),
create_dw_region(player, 'Shopping Mall Area', None, ['Dark Lake Hylia Ledge Fairy', 'Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Ledge Spike Cave', 'Ice Cave Mirror Spot', 'Shopping Mall SW', 'Shopping Mall SE']),
create_dw_region(player, 'Swamp Nook Area', None, ['Desert Pass Ledge Mirror Spot', 'Desert Pass Mirror Spot', 'Swamp Nook EC', 'Swamp Nook ES']),
@@ -268,7 +270,8 @@ def create_regions(world, player):
create_cave_region(player, 'Tavern (Front)', 'the tavern'),
create_cave_region(player, 'Hyrule Castle Secret Entrance', 'a drop\'s exit', ['Link\'s Uncle', 'Secret Passage'], ['Hyrule Castle Secret Entrance Exit']),
create_cave_region(player, 'Sahasrahlas Hut', 'Sahasrahla', ['Sahasrahla\'s Hut - Left', 'Sahasrahla\'s Hut - Middle', 'Sahasrahla\'s Hut - Right', 'Sahasrahla']),
create_cave_region(player, 'Blacksmiths Hut', 'the smith', ['Blacksmith', 'Missing Smith']),
create_cave_region(player, 'Blacksmiths Hut', 'the smith', ['Blacksmith'], ['Missing Smith']),
create_cave_region(player, 'Missing Smith', None, ['Missing Smith']),
create_cave_region(player, 'Bat Cave (right)', 'a drop\'s exit', ['Magic Bat'], ['Bat Cave Door']),
create_cave_region(player, 'Bat Cave (left)', 'a drop\'s exit', None, ['Bat Cave Exit']),
create_cave_region(player, 'Two Brothers House', 'a connector', None, ['Two Brothers House Exit (East)', 'Two Brothers House Exit (West)']),
@@ -321,7 +324,7 @@ def create_regions(world, player):
create_cave_region(player, 'Dark World Hammer Peg Cave', 'a cave with an item', ['Peg Cave']),
create_cave_region(player, 'Archery Game', 'a game of skill'),
create_cave_region(player, 'Bonk Fairy (Dark)', 'a fairy fountain'),
create_cave_region(player, 'Big Bomb Shop', 'the bomb shop'),
create_cave_region(player, 'Big Bomb Shop', 'the bomb shop', ['Big Bomb']),
create_cave_region(player, 'Dark Lake Hylia Healer Fairy', 'a fairy fountain'),
create_cave_region(player, 'East Dark World Hint', 'a storyteller'),
create_cave_region(player, 'Hype Cave', 'a bounty of five items', ['Hype Cave - Top', 'Hype Cave - Middle Right', 'Hype Cave - Middle Left',
@@ -1488,6 +1491,9 @@ location_table = {'Mushroom': (0x180013, 0x186338, False, 'in the woods'),
'Frog': (None, None, False, None),
'Missing Smith': (None, None, False, None),
'Dark Blacksmith Ruins': (None, None, False, None),
'Big Bomb': (None, None, False, None),
'Pyramid Crack': (None, None, False, None),
'Middle Aged Man': (None, None, False, None),
'Trench 1 Switch': (None, None, False, None),
'Trench 2 Switch': (None, None, False, None),
'Swamp Drain': (None, None, False, None),

472
Rules.py
View File

@@ -58,15 +58,6 @@ def set_rules(world, player):
elif world.goal[player] == 'triforcehunt':
add_rule(world.get_location('Murahdahla', player), lambda state: state.item_count('Triforce Piece', player) + state.item_count('Power Star', player) >= int(state.world.treasure_hunt_count[player]))
if world.mode[player] != 'inverted':
set_big_bomb_rules(world, player)
if world.logic[player] == 'owglitches' and world.shuffle[player] not in ('insanity', 'insanity_legacy'):
path_to_hc = mirrorless_path_to_location(world, 'West Death Mountain (Bottom)', 'Hyrule Castle Area', player)
path_to_courtyard = mirrorless_path_to_castle_courtyard(world, player)
add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.world.get_entrance('Dark Death Mountain Offset Mirror', player).can_reach(state) and all(rule(state) for rule in path_to_courtyard) and all(rule(state) for rule in path_to_hc), 'or')
else:
set_inverted_big_bomb_rules(world, player)
# if swamp and dam have not been moved we require mirror for swamp palace
if not world.swamp_patch_required[player]:
add_rule(world.get_entrance('Swamp Lobby Moat', player), lambda state: state.has_Mirror(player))
@@ -192,11 +183,14 @@ def global_rules(world, player):
set_rule(world.get_location('Sunken Treasure', player), lambda state: state.has('Open Floodgate', player))
set_rule(world.get_location('Dark Blacksmith Ruins', player), lambda state: state.has('Return Smith', player))
set_rule(world.get_location('Purple Chest', player), lambda state: state.has('Pick Up Purple Chest', player)) # Can S&Q with chest
set_rule(world.get_location('Ether Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player))
set_rule(world.get_location('Middle Aged Man', player), lambda state: state.has('Pick Up Purple Chest', player)) # Can S&Q with chest
set_rule(world.get_location('Purple Chest', player), lambda state: state.has('Deliver Purple Chest', player)) # Can S&Q with chest
set_rule(world.get_location('Big Bomb', player), lambda state: state.has('Crystal 5', player) and state.has('Crystal 6', player))
set_rule(world.get_location('Pyramid Crack', player), lambda state: state.has('Pick Up Big Bomb', player))
set_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.has('Detonate Big Bomb', player))
set_rule(world.get_location('Master Sword Pedestal', player), lambda state: state.has('Red Pendant', player) and state.has('Blue Pendant', player) and state.has('Green Pendant', player))
set_rule(world.get_location('Missing Smith', player), lambda state: state.has('Get Frog', player) and state.can_reach('Blacksmiths Hut', 'Region', player)) # Can't S&Q with smith
set_rule(world.get_location('Missing Smith', player), lambda state: state.has('Get Frog', player))
set_rule(world.get_location('Blacksmith', player), lambda state: state.has('Return Smith', player))
set_rule(world.get_location('Magic Bat', player), lambda state: state.has('Magic Powder', player))
set_rule(world.get_location('Sick Kid', player), lambda state: state.has_bottle(player))
@@ -605,9 +599,11 @@ def bomb_rules(world, player):
'Hookshot Cave Back to Middle', 'Hookshot Cave Front to Middle', 'Hookshot Cave Middle to Front','Hookshot Cave Middle to Back',
'Dark Lake Hylia Ledge Fairy', 'Hype Cave', 'Brewery']
for entrance in bonkable_doors:
add_rule(world.get_entrance(entrance, player), lambda state: state.can_use_bombs(player) or state.has_Boots(player))
add_rule(world.get_entrance(entrance, player), lambda state: state.can_use_bombs(player) or state.has_Boots(player))
add_bunny_rule(world.get_entrance(entrance, player), player)
for entrance in bombable_doors:
add_rule(world.get_entrance(entrance, player), lambda state: state.can_use_bombs(player))
add_rule(world.get_entrance(entrance, player), lambda state: state.can_use_bombs(player))
add_bunny_rule(world.get_entrance(entrance, player), player)
bonkable_items = ['Sahasrahla\'s Hut - Left', 'Sahasrahla\'s Hut - Middle', 'Sahasrahla\'s Hut - Right']
bombable_items = ['Blind\'s Hideout - Top', 'Kakariko Well - Top', 'Chicken House', 'Aginah\'s Cave', 'Graveyard Cave',
@@ -615,18 +611,23 @@ def bomb_rules(world, player):
'Hype Cave - Top', 'Hype Cave - Middle Right', 'Hype Cave - Middle Left', 'Hype Cave - Bottom']
for location in bonkable_items:
add_rule(world.get_location(location, player), lambda state: state.can_use_bombs(player) or state.has_Boots(player))
add_bunny_rule(world.get_location(location, player), player)
for location in bombable_items:
add_rule(world.get_location(location, player), lambda state: state.can_use_bombs(player))
add_bunny_rule(world.get_location(location, player), player)
cave_kill_locations = ['Mini Moldorm Cave - Far Left', 'Mini Moldorm Cave - Far Right', 'Mini Moldorm Cave - Left', 'Mini Moldorm Cave - Right', 'Mini Moldorm Cave - Generous Guy', 'Spiral Cave']
for location in cave_kill_locations:
add_rule(world.get_location(location, player), lambda state: state.can_kill_most_things(player) or state.can_use_bombs(player))
add_bunny_rule(world.get_location(location, player), player)
add_rule(world.get_entrance('Spiral Cave (top to bottom)', player), lambda state: state.can_kill_most_things(player) or state.can_use_bombs(player))
add_bunny_rule(world.get_entrance('Spiral Cave (top to bottom)', player), player)
paradox_switch_chests = ['Paradox Cave Lower - Far Left', 'Paradox Cave Lower - Left', 'Paradox Cave Lower - Right', 'Paradox Cave Lower - Far Right', 'Paradox Cave Lower - Middle']
for location in paradox_switch_chests:
add_rule(world.get_location(location, player), lambda state: state.can_hit_crystal_through_barrier(player))
add_bunny_rule(world.get_location(location, player), player)
# Dungeon bomb logic
easy_kill_rooms = [ # Door, bool-bombable
('Hyrule Dungeon Armory S', True), # One green guard
@@ -683,7 +684,7 @@ def bomb_rules(world, player):
if world.doorShuffle[player] == 'vanilla':
add_rule(world.get_entrance('TR Lazy Eyes SE', player), lambda state: state.can_use_bombs(player)) # ToDo: Add always true for inverted, cross-entrance, and door-variants and so on.
add_rule(world.get_entrance('Turtle Rock Ledge Exit (West)', player), lambda state: state.can_use_bombs(player)) # Is this the same as above?
dungeon_bonkable = ['Sewers Rat Path WS', 'Sewers Rat Path WN',
'PoD Warp Hint SE', 'PoD Jelly Hall NW', 'PoD Jelly Hall NE', 'PoD Mimics 1 SW',
'Thieves Ambush E', 'Thieves Rail Ledge W',
@@ -724,6 +725,7 @@ def default_rules(world, player):
set_rule(world.get_location('Zora\'s Ledge', player), lambda state: state.has('Flippers', player))
set_rule(world.get_location('Potion Shop', player), lambda state: state.has('Mushroom', player))
set_rule(world.get_location('Flute Spot', player), lambda state: state.has('Shovel', player))
set_rule(world.get_location('Ether Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player))
set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player))
# Entrance Access
@@ -1352,7 +1354,7 @@ def no_glitches_rules(world, player):
def fake_flipper_rules(world, player):
set_rule(world.get_entrance('Waterfall of Wishing Cave Entry', player), lambda state: state.has('Flippers', player) or (state.has_Pearl(player) and state.can_reach('Lake Hylia Water', player)))
set_rule(world.get_entrance('Waterfall of Wishing Cave Entry', player), lambda state: True) # warning, assumes FF possible on other end of whirlpool or local ancilla splash delete
set_rule(world.get_entrance('River Bend Water Drop', player), lambda state: True)
set_rule(world.get_entrance('River Bend East Water Drop', player), lambda state: True)
set_rule(world.get_entrance('Potion Shop Water Drop', player), lambda state: True)
@@ -1637,440 +1639,6 @@ def find_rules_for_zelda_delivery(world, player):
raise Exception('No path to Sanctuary found')
def set_big_bomb_rules(world, player):
# this is a mess
if len(world.get_region('Big Bomb Shop', player).entrances) > 0:
bombshop_entrance = world.get_region('Big Bomb Shop', player).entrances[0]
Normal_LW_entrances = ['Blinds Hideout',
'Bonk Fairy (Light)',
'Lake Hylia Fairy',
'Light Hype Fairy',
'Desert Fairy',
'Chicken House',
'Aginahs Cave',
'Sahasrahlas Hut',
'Cave Shop (Lake Hylia)',
'Blacksmiths Hut',
'Sick Kids House',
'Lost Woods Gamble',
'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',
'Good Bee Cave',
'20 Rupee Cave',
'50 Rupee Cave',
'Ice Rod Cave',
'Bonk Rock Cave',
'Library',
'Potion Shop',
'Dam',
'Lumberjack House',
'Lake Hylia Fortune Teller',
'Eastern Palace',
'Kakariko Gamble Game',
'Kakariko Well Cave',
'Bat Cave Cave',
'Elder House (East)',
'Elder House (West)',
'North Fairy Cave',
'Lost Woods Hideout Stump',
'Lumberjack Tree Cave',
'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']
Northern_DW_entrances = ['Brewery',
'C-Shaped House',
'Chest Game',
'Dark World Hammer Peg Cave',
'Red Shield Shop',
'Dark Sanctuary Hint',
'Fortune Teller (Dark)',
'Dark World Shop',
'Dark World Lumberjack Shop',
'Thieves Town',
'Skull Woods First Section Door',
'Skull Woods Second Section Door (East)']
Southern_DW_entrances = ['Hype Cave',
'Bonk Fairy (Dark)',
'Archery Game',
'Big Bomb Shop',
'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)',
'Bumper Cave (Top)',
'Superbunny Cave (Top)',
'Superbunny Cave (Bottom)',
'Hookshot Cave',
'Ganons Tower',
'Turtle Rock Isolated Ledge Entrance',
'Hookshot Cave Back Entrance']
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)',
'Agahnims Tower']
Desert_mirrorable_ledge_entrances = ['Desert Palace Entrance (West)',
'Desert Palace Entrance (North)',
'Desert Palace Entrance (South)',
'Checkerboard Cave']
set_rule(world.get_entrance('Pyramid Fairy', player), lambda state: (state.can_reach('Pyramid Area', 'Region', player) or state.can_reach('East Dark World', 'Region', player)) and state.can_reach('Big Bomb Shop', 'Region', player) and state.has('Crystal 5', player) and state.has('Crystal 6', player))
#crossing peg bridge starting from the southern dark world
def cross_peg_bridge(state):
return state.has('Hammer', player) and state.has_Pearl(player)
# returning via the eastern and southern teleporters needs the same items, so we use the southern teleporter for out routing.
# crossing preg bridge already requires hammer so we just add the gloves to the requirement
def southern_teleporter(state):
return state.can_lift_rocks(player) and cross_peg_bridge(state)
# the basic routes assume you can reach eastern light world with the bomb.
# you can then use the southern teleporter, or (if you have beaten Aga1) the hyrule castle gate warp
def basic_routes(state):
return southern_teleporter(state) or state.has('Beat Agahnim 1', player)
# Key for below abbreviations:
# P = pearl
# A = Aga1
# H = hammer
# M = Mirror
# G = Glove
if bombshop_entrance.name in Normal_LW_entrances:
#1. basic routes
#2. Can reach Eastern dark world some other way, mirror, get bomb, return to mirror spot, walk to pyramid: Needs mirror
# -> M or BR
add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: basic_routes(state) or state.has_Mirror(player))
elif bombshop_entrance.name in LW_walkable_entrances:
#1. Mirror then basic routes
# -> M and BR
add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.has_Mirror(player) and basic_routes(state))
elif bombshop_entrance.name in Northern_DW_entrances:
#1. Mirror and basic routes
#2. Go to south DW and then cross peg bridge: Need Mitts and hammer and moon pearl
# -> (Mitts and CPB) or (M and BR)
add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: (state.can_lift_heavy_rocks(player) and cross_peg_bridge(state)) or (state.has_Mirror(player) and basic_routes(state)))
elif bombshop_entrance.name == 'Bumper Cave (Bottom)':
#1. Mirror and Lift rock and basic_routes
#2. Mirror and Flute and basic routes (can make difference if accessed via insanity or w/ mirror from connector, and then via hyrule castle gate, because no gloves are needed in that case)
#3. Go to south DW and then cross peg bridge: Need Mitts and hammer and moon pearl
# -> (Mitts and CPB) or (((G or Flute) and M) and BR))
add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: (state.can_lift_heavy_rocks(player) and cross_peg_bridge(state)) or (((state.can_lift_rocks(player) or state.can_flute(player)) and state.has_Mirror(player)) and basic_routes(state)))
elif bombshop_entrance.name in Southern_DW_entrances:
#1. Mirror and enter via gate: Need mirror and Aga1
#2. cross peg bridge: Need hammer and moon pearl
# -> CPB or (M and A)
add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: cross_peg_bridge(state) or (state.has_Mirror(player) and state.has('Beat Agahnim 1', player)))
elif bombshop_entrance.name in Isolated_DW_entrances:
# 1. mirror then flute then basic routes
# -> M and Flute and BR
add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.has_Mirror(player) and state.can_flute(player) and basic_routes(state))
elif bombshop_entrance.name in Isolated_LW_entrances:
# 1. flute then basic routes
# Prexisting mirror spot is not permitted, because mirror might have been needed to reach these isolated locations.
# -> Flute and BR
add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.can_flute(player) and basic_routes(state))
elif bombshop_entrance.name in West_LW_DM_entrances:
# 1. flute then basic routes or mirror
# Prexisting mirror spot is permitted, because flute can be used to reach west DM directly.
# -> Flute and (M or BR)
add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.can_reach('West Death Mountain (Bottom)', 'Region', player))
elif bombshop_entrance.name in East_LW_DM_entrances:
# 1. flute then basic routes or mirror and hookshot
# Prexisting mirror spot is permitted, because flute can be used to reach west DM directly and then east DM via Hookshot
# -> Flute and ((M and Hookshot) or BR)
add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.can_reach('East Death Mountain (Bottom)', 'Region', player))
elif bombshop_entrance.name == 'Fairy Ascension Cave (Bottom)':
# Same as East_LW_DM_entrances except navigation without BR requires Mitts
# -> Flute and ((M and Hookshot and Mitts) or BR)
add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.can_reach('East Death Mountain (Bottom)', 'Region', player) and state.can_lift_heavy_rocks(player))
elif bombshop_entrance.name in Castle_ledge_entrances:
# 1. mirror on pyramid to castle ledge, grab bomb, return through mirror spot: Needs mirror
# 2. flute then basic routes
# -> M or (Flute and BR)
add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.can_reach('Hyrule Castle Ledge', 'Region', player))
elif bombshop_entrance.name in Desert_mirrorable_ledge_entrances:
# Cases when you have mire access: Mirror to reach locations, return via mirror spot, move to center of desert, mirror anagin and:
# 1. Have mire access, Mirror to reach locations, return via mirror spot, move to center of desert, mirror again and then basic routes
# 2. flute then basic routes
# -> (Mire access and M) or Flute) and BR
add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.can_reach('Desert Ledge', 'Region', player))
elif bombshop_entrance.name == 'Old Man Cave (West)':
# 1. Lift rock then basic_routes
# 2. flute then basic_routes
# -> (Flute or G) and BR
add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.can_reach('Death Mountain Entrance', 'Region', player))
elif bombshop_entrance.name == 'Graveyard Cave':
# 1. flute then basic routes
# 2. (has west dark world access) use existing mirror spot (required Pearl), mirror again off ledge
# -> (Flute or (M and P and West Dark World access) and BR
add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: (state.can_flute(player) or (state.can_reach('Dark Graveyard Area', 'Region', player) and state.has_Pearl(player) and state.has_Mirror(player))) and basic_routes(state))
elif bombshop_entrance.name in Mirror_from_SDW_entrances:
# 1. flute then basic routes
# 2. (has South dark world access) use existing mirror spot, mirror again off ledge
# -> (Flute or (M and South Dark World access) and BR
add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: (state.can_flute(player) or (state.can_reach('Pyramid Area', 'Region', player) and state.has_Mirror(player))) and basic_routes(state))
elif bombshop_entrance.name == 'Dark World Potion Shop':
# 1. walk down by lifting rock: needs gloves and pearl`
# 2. walk down by hammering peg: needs hammer and pearl
# 3. mirror and basic routes
# -> (P and (H or Gloves)) or (M and BR)
add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.can_reach('Dark Witch Area', 'Region', player))
elif bombshop_entrance.name == 'Kings Grave':
# same as the Normal_LW_entrances case except that the pre-existing mirror is only possible if you have mitts
# (because otherwise mirror was used to reach the grave, so would cancel a pre-existing mirror spot)
# to account for insanity, must consider a way to escape without a cave for basic_routes
# -> (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) or state.can_flute(player) or (state.can_reach('Dark Graveyard Area', 'Region', player) and state.has_Pearl(player) and state.has_Mirror(player))))
elif bombshop_entrance.name == 'Waterfall of Wishing':
# same as the Normal_LW_entrances case except in insanity it's possible you could be here without Flippers which
# means you need an escape route of either Flippers or Flute
add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: (state.has('Flippers', player) or state.can_flute(player)))
#TODO: Fix red bomb rules, artifically adding a bunch of rules to help reduce unbeatable seeds in OW shuffle
set_rule(world.get_entrance('Pyramid Fairy', player), lambda state: False)
#add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.can_reach('Pyramid Area', 'Region', player))
#add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: (state.can_lift_heavy_rocks(player) and state.has('Flippers', player) and state.can_flute(player) and state.has('Hammer', player) and state.has('Hookshot', player) and state.has_Pearl(player) and state.has_Mirror(player)))
def set_inverted_big_bomb_rules(world, player):
if len(world.get_region('Big Bomb Shop', player).entrances) > 0:
bombshop_entrance = world.get_region('Big Bomb Shop', player).entrances[0]
Normal_LW_entrances = ['Blinds Hideout',
'Bonk Fairy (Light)',
'Lake Hylia Fairy',
'Light Hype Fairy',
'Desert Fairy',
'Chicken House',
'Aginahs Cave',
'Sahasrahlas Hut',
'Cave Shop (Lake Hylia)',
'Blacksmiths Hut',
'Sick Kids House',
'Lost Woods Gamble',
'Fortune Teller (Light)',
'Snitch Lady (East)',
'Snitch Lady (West)',
'Tavern (Front)',
'Kakariko Shop',
'Mini Moldorm Cave',
'Long Fairy Cave',
'Good Bee Cave',
'20 Rupee Cave',
'50 Rupee Cave',
'Ice Rod Cave',
'Bonk Rock Cave',
'Library',
'Potion Shop',
'Dam',
'Lumberjack House',
'Lake Hylia Fortune Teller',
'Eastern Palace',
'Kakariko Gamble Game',
'Kakariko Well Cave',
'Bat Cave Cave',
'Elder House (East)',
'Elder House (West)',
'North Fairy Cave',
'Lost Woods Hideout Stump',
'Lumberjack Tree Cave',
'Two Brothers House (East)',
'Sanctuary',
'Hyrule Castle Entrance (South)',
'Hyrule Castle Secret Entrance Stairs',
'Hyrule Castle Entrance (West)',
'Hyrule Castle Entrance (East)',
'Ganons Tower',
'Cave 45',
'Checkerboard Cave',
'Links House']
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',
'Dark Sanctuary Hint',
'Fortune Teller (Dark)',
'Dark World Lumberjack Shop',
'Thieves Town',
'Skull Woods First Section Door',
'Skull Woods Second Section Door (East)']
Southern_DW_entrances = ['Hype Cave',
'Bonk Fairy (Dark)',
'Archery Game',
'Big Bomb Shop',
'Dark Lake Hylia Shop',
'Swamp Palace']
Isolated_DW_entrances = ['Spike Cave',
'Cave Shop (Dark Death Mountain)',
'Dark Death Mountain Fairy',
'Skull Woods Second Section Door (West)',
'Skull Woods Final Section',
'Turtle Rock',
'Dark Death Mountain Ledge (West)',
'Dark Death Mountain Ledge (East)',
'Bumper Cave (Top)',
'Superbunny Cave (Top)',
'Superbunny Cave (Bottom)',
'Hookshot Cave',
'Turtle Rock Isolated Ledge Entrance',
'Hookshot Cave Back Entrance',
'Agahnims Tower']
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)']
set_rule(world.get_entrance('Pyramid Fairy', player),
lambda state: state.can_reach('Pyramid Area', 'Region', player) and state.can_reach('Big Bomb Shop', 'Region', player) and state.has('Crystal 5', player) and state.has('Crystal 6', player))
# Key for below abbreviations:
# P = pearl
# A = Aga1
# H = hammer
# M = Mirror
# G = Glove
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 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 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('Hyrule Castle Area', '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('Hyrule Castle Area', '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('Hyrule Castle Area', '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('Hyrule Castle Area', '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('Hyrule Castle Area', 'Region', player)))
elif bombshop_entrance.name == 'Old Man Cave (West)':
# 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':
# 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 == '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 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)
if world.owShuffle[player] != 'vanilla' or world.owMixed[player] or world.owCrossed[player] not in ['none', 'polar']:
set_rule(world.get_entrance('Pyramid Fairy', player), lambda state: False) #temp disable progression until routing to Pyramid get be guaranteed
def set_bunny_rules(world, player, inverted):
# regions for the exits of multi-entrace caves/drops that bunny cannot pass
@@ -2081,7 +1649,7 @@ def set_bunny_rules(world, player, inverted):
'Checkerboard Cave', 'Potion Shop', 'Spectacle Rock Cave', 'Pyramid',
'Hype Cave - Generous Guy', 'Peg Cave', 'Bumper Cave Ledge', 'Dark Blacksmith Ruins',
'Spectacle Rock', 'Bombos Tablet', 'Ether Tablet', 'Purple Chest', 'Blacksmith',
'Missing Smith', 'Master Sword Pedestal', 'Bottle Merchant', 'Sunken Treasure', 'Desert Ledge',
'Missing Smith', 'Pyramid Crack', 'Big Bomb', 'Master Sword Pedestal', 'Bottle Merchant', 'Sunken Treasure', 'Desert Ledge',
'Kakariko Shop - Left', 'Kakariko Shop - Middle', 'Kakariko Shop - Right',
'Lake Hylia Shop - Left', 'Lake Hylia Shop - Middle', 'Lake Hylia Shop - Right',
'Potion Shop - Left', 'Potion Shop - Middle', 'Potion Shop - Right',