Merge branch 'OverworldShuffle' of github.com:codemann8/ALttPDoorRandomizer into OverworldShuffle

This commit is contained in:
2021-10-07 15:28:16 -07:00
6 changed files with 268 additions and 263 deletions

View File

@@ -1,5 +1,13 @@
# Changelog # Changelog
### 0.1.9.4
- Hotfix for bad 0.1.9.3 version
### 0.1.9.3
- Moved flute spot from Northwest Lake Hylia to Southeast Lake Hylia
- Fixed Links House start in Inverted ER
- Minor accuracy improvements to ER, mostly preparations for future work
### 0.1.9.2 ### 0.1.9.2
- Fixed spoiler log and mystery for new Crossed/Mixed structure - Fixed spoiler log and mystery for new Crossed/Mixed structure
- Minor preparations and tweaks to ER framework (added global Entrance/Exit pool) - Minor preparations and tweaks to ER framework (added global Entrance/Exit pool)

View File

@@ -18,6 +18,11 @@ def link_entrances(world, player):
isolated_entrances = Isolated_LH_Doors.copy() isolated_entrances = Isolated_LH_Doors.copy()
# modifications to lists # modifications to lists
Dungeon_Exits = Dungeon_Exits_Base.copy()
Cave_Exits = Cave_Exits_Base.copy()
Old_Man_House = Old_Man_House_Base.copy()
Cave_Three_Exits = Cave_Three_Exits_Base.copy()
if invFlag == (0x1b in world.owswaps[player][0] and world.owMixed[player]): if invFlag == (0x1b in world.owswaps[player][0] and world.owMixed[player]):
drop_connections.append(tuple(('Pyramid Hole', 'Pyramid'))) drop_connections.append(tuple(('Pyramid Hole', 'Pyramid')))
dropexit_connections.append(tuple(('Pyramid Entrance', 'Pyramid Exit'))) dropexit_connections.append(tuple(('Pyramid Entrance', 'Pyramid Exit')))
@@ -31,11 +36,11 @@ def link_entrances(world, player):
dropexit_connections.append(tuple(('Inverted Pyramid Entrance', 'Pyramid Exit'))) dropexit_connections.append(tuple(('Inverted Pyramid Entrance', 'Pyramid Exit')))
connect_simple(world, 'Other World S&Q', 'Hyrule Castle Ledge', player) connect_simple(world, 'Other World S&Q', 'Hyrule Castle Ledge', player)
Dungeon_Exits = Dungeon_Exits_Base.copy() if invFlag == (0x03 in world.owswaps[player][0] and world.owMixed[player]):
Cave_Exits = Cave_Exits_Base.copy() connect_simple(world, 'Old Man S&Q', 'Old Man House', player)
Old_Man_House = Old_Man_House_Base.copy() else:
Cave_Three_Exits = Cave_Three_Exits_Base.copy() connect_simple(world, 'Old Man S&Q', 'West Dark Death Mountain (Bottom)', player)
unbias_some_entrances(Dungeon_Exits, Cave_Exits, Old_Man_House, Cave_Three_Exits) unbias_some_entrances(Dungeon_Exits, Cave_Exits, Old_Man_House, Cave_Three_Exits)
# setup mandatory connections # setup mandatory connections
@@ -65,16 +70,13 @@ def link_entrances(world, player):
if not invFlag: if not invFlag:
for entrancename, exitname in open_default_connections: for entrancename, exitname in open_default_connections:
connect_logical(world, entrancename, exitname, player, True) connect_logical(world, entrancename, exitname, player, exitname.endswith(' Exit'))
ignore_pool = True
connect_exit(world, 'Chris Houlihan Room Exit', 'Links House', player)
else: else:
for entrancename, exitname in inverted_default_connections: for entrancename, exitname in inverted_default_connections:
connect_logical(world, entrancename, exitname, player, True) connect_logical(world, entrancename, exitname, player, exitname.endswith(' Exit'))
ignore_pool = True
connect_exit(world, 'Chris Houlihan Room Exit', 'Big Bomb Shop', player)
# inverted entrance mods # inverted entrance mods
ignore_pool = True
for owid in swapped_connections.keys(): for owid in swapped_connections.keys():
if invFlag != (owid in world.owswaps[player][0] and world.owMixed[player]): if invFlag != (owid in world.owswaps[player][0] and world.owMixed[player]):
for (entrancename, exitname) in swapped_connections[owid]: for (entrancename, exitname) in swapped_connections[owid]:
@@ -139,15 +141,14 @@ def link_entrances(world, player):
exit1, exit2 = caves.pop() exit1, exit2 = caves.pop()
connect_two_way(world, entrance1, exit1, player) connect_two_way(world, entrance1, exit1, player)
connect_two_way(world, entrance2, exit2, player) connect_two_way(world, entrance2, exit2, player)
# place links house # place links house
if world.mode[player] == 'standard' or not world.shufflelinks[player]: if world.mode[player] == 'standard' or not world.shufflelinks[player]:
links_house = 'Links House' links_house = 'Links House' if not invFlag else 'Big Bomb Shop'
else: else:
links_house_doors = [i for i in LW_Single_Cave_Doors if i not in isolated_entrances + ([] if not invFlag else Inverted_Dark_Sanctuary_Doors)] links_house_doors = [i for i in (LW_Single_Cave_Doors if not invFlag else DW_Single_Cave_Doors) if i not in isolated_entrances + ([] if not invFlag else Inverted_Dark_Sanctuary_Doors)]
links_house = random.choice(links_house_doors) links_house = random.choice(links_house_doors)
connect_two_way(world, links_house, 'Links House Exit', player) connect_two_way(world, links_house, 'Links House Exit', player)
connect_exit(world, 'Chris Houlihan Room Exit', links_house, player) # should always match link's house, except for plandos
if links_house in bomb_shop_doors: if links_house in bomb_shop_doors:
bomb_shop_doors.remove(links_house) bomb_shop_doors.remove(links_house)
@@ -161,7 +162,6 @@ def link_entrances(world, player):
sanc_doors = [door for door in Inverted_Dark_Sanctuary_Doors if door in bomb_shop_doors] sanc_doors = [door for door in Inverted_Dark_Sanctuary_Doors if door in bomb_shop_doors]
sanc_door = random.choice(sanc_doors) sanc_door = random.choice(sanc_doors)
bomb_shop_doors.remove(sanc_door) bomb_shop_doors.remove(sanc_door)
connect_entrance(world, sanc_door, 'Dark Sanctuary Hint', player) connect_entrance(world, sanc_door, 'Dark Sanctuary Hint', player)
world.get_entrance('Dark Sanctuary Hint Exit', player).connect(world.get_entrance(sanc_door, player).parent_region) world.get_entrance('Dark Sanctuary Hint Exit', player).connect(world.get_entrance(sanc_door, player).parent_region)
@@ -174,17 +174,16 @@ def link_entrances(world, player):
else: else:
# at this point only Light World death mountain entrances remain # at this point only Light World death mountain entrances remain
# place old man, has limited options # place old man, has limited options
remaining_entrances = ['Old Man Cave (West)', 'Old Man House (Bottom)', 'Death Mountain Return Cave (West)', 'Paradox Cave (Bottom)', 'Paradox Cave (Middle)', 'Paradox Cave (Top)', lw_dm_entrances = ['Old Man Cave (West)', 'Old Man House (Bottom)', 'Death Mountain Return Cave (West)', 'Paradox Cave (Bottom)', 'Paradox Cave (Middle)', 'Paradox Cave (Top)',
'Fairy Ascension Cave (Bottom)', 'Fairy Ascension Cave (Top)', 'Spiral Cave', 'Spiral Cave (Bottom)'] 'Fairy Ascension Cave (Bottom)', 'Fairy Ascension Cave (Top)', 'Spiral Cave', 'Spiral Cave (Bottom)']
random.shuffle(old_man_entrances) random.shuffle(old_man_entrances)
old_man_exit = old_man_entrances.pop() old_man_exit = old_man_entrances.pop()
if not invFlag: if not invFlag:
remaining_entrances.extend(old_man_entrances) lw_dm_entrances.extend(old_man_entrances)
random.shuffle(remaining_entrances) random.shuffle(lw_dm_entrances)
old_man_entrance = remaining_entrances.pop() old_man_entrance = lw_dm_entrances.pop()
connect_two_way(world, old_man_entrance if invFlag == (0x0a in world.owswaps[player][0] and world.owMixed[player]) else 'Bumper Cave (Bottom)', 'Old Man Cave Exit (West)', player)
connect_two_way(world, old_man_entrance if invFlag == (0x0a in world.owswaps[player][0] and world.owMixed[player]) else 'Bumper Cave (Bottom)', 'Old Man Cave Exit (West)', player)
connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player) connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player)
if invFlag and old_man_exit == 'Spike Cave': if invFlag and old_man_exit == 'Spike Cave':
@@ -196,7 +195,7 @@ def link_entrances(world, player):
caves.extend(list(three_exit_caves)) caves.extend(list(three_exit_caves))
# connect rest # connect rest
connect_caves(world, remaining_entrances if not invFlag else lw_dm_entrances, [], caves, player) connect_caves(world, lw_dm_entrances, [], caves, player)
# scramble holes # scramble holes
scramble_holes(world, player) scramble_holes(world, player)
@@ -245,18 +244,26 @@ def link_entrances(world, player):
# place links house # place links house
if world.mode[player] == 'standard' or not world.shufflelinks[player]: if world.mode[player] == 'standard' or not world.shufflelinks[player]:
links_house = 'Links House' links_house = 'Links House' if not invFlag else 'Big Bomb Shop'
else: else:
links_house_doors = [i for i in LW_Single_Cave_Doors if i not in isolated_entrances + ([] if not invFlag else Inverted_Dark_Sanctuary_Doors)] links_house_doors = [i for i in (lw_entrances if not invFlag else dw_entrances) if i not in isolated_entrances + ([] if not invFlag else Inverted_Dark_Sanctuary_Doors)]
links_house = random.choice(links_house_doors) links_house = random.choice(links_house_doors)
connect_two_way(world, links_house, 'Links House Exit', player) connect_two_way(world, links_house, 'Links House Exit', player)
connect_exit(world, 'Chris Houlihan Room Exit', links_house, player) # should always match link's house, except for plandos if not invFlag:
if links_house in lw_entrances: if links_house in lw_entrances:
if not invFlag:
lw_entrances.remove(links_house) lw_entrances.remove(links_house)
else: else:
if links_house in dw_entrances:
dw_entrances.remove(links_house) dw_entrances.remove(links_house)
# place dark sanc
if invFlag:
sanc_doors = [door for door in Inverted_Dark_Sanctuary_Doors if door in dw_entrances]
sanc_door = random.choice(sanc_doors)
dw_entrances.remove(sanc_door)
connect_entrance(world, sanc_door, 'Dark Sanctuary Hint', player)
world.get_entrance('Dark Sanctuary Hint Exit', player).connect(world.get_entrance(sanc_door, player).parent_region)
# in restricted, the only mandatory exits are in dark world (lw in inverted) # in restricted, the only mandatory exits are in dark world (lw in inverted)
if not invFlag: if not invFlag:
connect_mandatory_exits(world, dw_entrances, caves, dw_must_exits, player) connect_mandatory_exits(world, dw_entrances, caves, dw_must_exits, player)
@@ -265,10 +272,7 @@ def link_entrances(world, player):
# place old man, has limited options # place old man, has limited options
# exit has to come from specific set of doors, the entrance is free to move about # exit has to come from specific set of doors, the entrance is free to move about
if not invFlag: old_man_entrances = [door for door in old_man_entrances if door in (lw_entrances if not invFlag else dw_entrances)]
old_man_entrances = [door for door in old_man_entrances if door in lw_entrances]
else:
old_man_entrances = [door for door in old_man_entrances if door in dw_entrances]
random.shuffle(old_man_entrances) random.shuffle(old_man_entrances)
old_man_exit = old_man_entrances.pop() old_man_exit = old_man_entrances.pop()
connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player) connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player)
@@ -321,9 +325,8 @@ def link_entrances(world, player):
# scramble holes # scramble holes
scramble_holes(world, player) scramble_holes(world, player)
doors = lw_entrances + dw_entrances
# place remaining doors # place remaining doors
doors = lw_entrances + dw_entrances
connect_doors(world, doors, door_targets, player) connect_doors(world, doors, door_targets, player)
elif world.shuffle[player] == 'full': elif world.shuffle[player] == 'full':
skull_woods_shuffle(world, player) skull_woods_shuffle(world, player)
@@ -334,7 +337,6 @@ def link_entrances(world, player):
dw_must_exits = list(DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit) dw_must_exits = list(DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit)
lw_must_exits = list(LW_Dungeon_Entrances_Must_Exit) lw_must_exits = list(LW_Dungeon_Entrances_Must_Exit)
old_man_entrances = list(Old_Man_Entrances + ['Tower of Hera']) old_man_entrances = list(Old_Man_Entrances + ['Tower of Hera'])
caves = list(Cave_Exits + Dungeon_Exits + Cave_Three_Exits) # don't need to consider three exit caves, have one exit caves to avoid parity issues
bomb_shop_doors = list(Bomb_Shop_Single_Cave_Doors + Bomb_Shop_Multi_Cave_Doors) bomb_shop_doors = list(Bomb_Shop_Single_Cave_Doors + Bomb_Shop_Multi_Cave_Doors)
blacksmith_doors = list(Blacksmith_Single_Cave_Doors + Blacksmith_Multi_Cave_Doors) blacksmith_doors = list(Blacksmith_Single_Cave_Doors + Blacksmith_Multi_Cave_Doors)
door_targets = list(Single_Cave_Targets) door_targets = list(Single_Cave_Targets)
@@ -343,7 +345,6 @@ def link_entrances(world, player):
dw_entrances = list(Inverted_DW_Entrances + Inverted_DW_Dungeon_Entrances + Inverted_DW_Single_Cave_Doors + Inverted_Old_Man_Entrances) dw_entrances = list(Inverted_DW_Entrances + Inverted_DW_Dungeon_Entrances + Inverted_DW_Single_Cave_Doors + Inverted_Old_Man_Entrances)
lw_must_exits = list(Inverted_LW_Dungeon_Entrances_Must_Exit + Inverted_LW_Entrances_Must_Exit) lw_must_exits = list(Inverted_LW_Dungeon_Entrances_Must_Exit + Inverted_LW_Entrances_Must_Exit)
old_man_entrances = list(Inverted_Old_Man_Entrances + Old_Man_Entrances + ['Ganons Tower', 'Tower of Hera']) old_man_entrances = list(Inverted_Old_Man_Entrances + Old_Man_Entrances + ['Ganons Tower', 'Tower of Hera'])
caves = list(Cave_Exits + Dungeon_Exits + Cave_Three_Exits) # don't need to consider three exit caves, have one exit caves to avoid parity issues
bomb_shop_doors = list(Inverted_Bomb_Shop_Single_Cave_Doors + Inverted_Bomb_Shop_Multi_Cave_Doors) bomb_shop_doors = list(Inverted_Bomb_Shop_Single_Cave_Doors + Inverted_Bomb_Shop_Multi_Cave_Doors)
blacksmith_doors = list(Inverted_Blacksmith_Single_Cave_Doors + Blacksmith_Multi_Cave_Doors) blacksmith_doors = list(Inverted_Blacksmith_Single_Cave_Doors + Blacksmith_Multi_Cave_Doors)
door_targets = list(Inverted_Single_Cave_Targets) door_targets = list(Inverted_Single_Cave_Targets)
@@ -355,15 +356,17 @@ def link_entrances(world, player):
else: else:
lw_must_exits.append('Desert Palace Entrance (West)') lw_must_exits.append('Desert Palace Entrance (West)')
lw_entrances.append('Desert Palace Entrance (North)') lw_entrances.append('Desert Palace Entrance (North)')
caves = list(Cave_Exits + Dungeon_Exits + Cave_Three_Exits) # don't need to consider three exit caves, have one exit caves to avoid parity issues
old_man_house = list(Old_Man_House) old_man_house = list(Old_Man_House)
if world.mode[player] == 'standard': if world.mode[player] == 'standard':
# must connect front of hyrule castle to do escape # must connect front of hyrule castle to do escape
connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player) connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player)
elif invFlag or world.doorShuffle[player] == 'vanilla': else:
caves.append(tuple(random.sample(['Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)'],3))) lw_entrances.append('Hyrule Castle Entrance (South)')
lw_entrances.append('Hyrule Castle Entrance (South)') if invFlag or world.doorShuffle[player] == 'vanilla':
caves.append(tuple(random.sample(['Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)'],3)))
if not world.shuffle_ganon: if not world.shuffle_ganon:
connect_two_way(world, 'Ganons Tower' if not invFlag else 'Agahnims Tower', 'Ganons Tower Exit', player) connect_two_way(world, 'Ganons Tower' if not invFlag else 'Agahnims Tower', 'Ganons Tower Exit', player)
hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)'] hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)']
@@ -401,12 +404,11 @@ def link_entrances(world, player):
# place links house # place links house
if world.mode[player] == 'standard' or not world.shufflelinks[player]: if world.mode[player] == 'standard' or not world.shufflelinks[player]:
links_house = 'Links House' links_house = 'Links House' if not invFlag else 'Big Bomb Shop'
else: else:
links_house_doors = [i for i in LW_Single_Cave_Doors if i not in isolated_entrances + ([] if not invFlag else Inverted_Dark_Sanctuary_Doors)] links_house_doors = [i for i in (lw_entrances + lw_must_exits if not invFlag else dw_entrances) if i not in isolated_entrances + ([] if not invFlag else Inverted_Dark_Sanctuary_Doors)]
links_house = random.choice(links_house_doors) links_house = random.choice(links_house_doors)
connect_two_way(world, links_house, 'Links House Exit', player) connect_two_way(world, links_house, 'Links House Exit', player)
connect_exit(world, 'Chris Houlihan Room Exit', links_house, player) # should always match link's house, except for plandos
if not invFlag: if not invFlag:
if links_house in lw_entrances: if links_house in lw_entrances:
lw_entrances.remove(links_house) lw_entrances.remove(links_house)
@@ -509,16 +511,14 @@ def link_entrances(world, player):
old_man_entrance = dw_entrances.pop() old_man_entrance = dw_entrances.pop()
connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)', player) connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)', player)
# now scramble the rest # now scramble the rest
connect_caves(world, lw_entrances, dw_entrances, caves, player) connect_caves(world, lw_entrances, dw_entrances, caves, player)
# scramble holes # scramble holes
scramble_holes(world, player) scramble_holes(world, player)
doors = lw_entrances + dw_entrances
# place remaining doors # place remaining doors
doors = lw_entrances + dw_entrances
connect_doors(world, doors, door_targets, player) connect_doors(world, doors, door_targets, player)
elif world.shuffle[player] == 'crossed': elif world.shuffle[player] == 'crossed':
skull_woods_shuffle(world, player) skull_woods_shuffle(world, player)
@@ -527,7 +527,6 @@ def link_entrances(world, player):
entrances = list(LW_Entrances + LW_Dungeon_Entrances + LW_Single_Cave_Doors + Old_Man_Entrances + DW_Entrances + DW_Dungeon_Entrances + DW_Single_Cave_Doors) entrances = list(LW_Entrances + LW_Dungeon_Entrances + LW_Single_Cave_Doors + Old_Man_Entrances + DW_Entrances + DW_Dungeon_Entrances + DW_Single_Cave_Doors)
must_exits = list(DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit + LW_Dungeon_Entrances_Must_Exit) must_exits = list(DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit + LW_Dungeon_Entrances_Must_Exit)
old_man_entrances = list(Old_Man_Entrances + ['Tower of Hera']) old_man_entrances = list(Old_Man_Entrances + ['Tower of Hera'])
caves = list(Cave_Exits + Dungeon_Exits + Cave_Three_Exits + Old_Man_House) # don't need to consider three exit caves, have one exit caves to avoid parity issues
bomb_shop_doors = list(Bomb_Shop_Single_Cave_Doors + Bomb_Shop_Multi_Cave_Doors) bomb_shop_doors = list(Bomb_Shop_Single_Cave_Doors + Bomb_Shop_Multi_Cave_Doors)
blacksmith_doors = list(Blacksmith_Single_Cave_Doors + Blacksmith_Multi_Cave_Doors) blacksmith_doors = list(Blacksmith_Single_Cave_Doors + Blacksmith_Multi_Cave_Doors)
door_targets = list(Single_Cave_Targets) door_targets = list(Single_Cave_Targets)
@@ -535,10 +534,10 @@ def link_entrances(world, player):
entrances = list(Inverted_LW_Entrances + Inverted_LW_Dungeon_Entrances + LW_Single_Cave_Doors + Inverted_Old_Man_Entrances + Inverted_DW_Entrances + Inverted_DW_Dungeon_Entrances + Inverted_DW_Single_Cave_Doors) entrances = list(Inverted_LW_Entrances + Inverted_LW_Dungeon_Entrances + LW_Single_Cave_Doors + Inverted_Old_Man_Entrances + Inverted_DW_Entrances + Inverted_DW_Dungeon_Entrances + Inverted_DW_Single_Cave_Doors)
must_exits = list(Inverted_LW_Entrances_Must_Exit + Inverted_LW_Dungeon_Entrances_Must_Exit) must_exits = list(Inverted_LW_Entrances_Must_Exit + Inverted_LW_Dungeon_Entrances_Must_Exit)
old_man_entrances = list(Inverted_Old_Man_Entrances + Old_Man_Entrances + ['Ganons Tower', 'Tower of Hera']) old_man_entrances = list(Inverted_Old_Man_Entrances + Old_Man_Entrances + ['Ganons Tower', 'Tower of Hera'])
caves = list(Cave_Exits + Dungeon_Exits + Cave_Three_Exits + Old_Man_House) # don't need to consider three exit caves, have one exit caves to avoid parity issues
bomb_shop_doors = list(Inverted_Bomb_Shop_Single_Cave_Doors + Inverted_Bomb_Shop_Multi_Cave_Doors) bomb_shop_doors = list(Inverted_Bomb_Shop_Single_Cave_Doors + Inverted_Bomb_Shop_Multi_Cave_Doors)
blacksmith_doors = list(Inverted_Blacksmith_Single_Cave_Doors + Blacksmith_Multi_Cave_Doors) blacksmith_doors = list(Inverted_Blacksmith_Single_Cave_Doors + Blacksmith_Multi_Cave_Doors)
door_targets = list(Inverted_Single_Cave_Targets) door_targets = list(Inverted_Single_Cave_Targets)
caves = list(Cave_Exits + Dungeon_Exits + Cave_Three_Exits + Old_Man_House) # don't need to consider three exit caves, have one exit caves to avoid parity issues
if invFlag: if invFlag:
# randomize which desert ledge door is a must-exit # randomize which desert ledge door is a must-exit
@@ -583,16 +582,15 @@ def link_entrances(world, player):
# place links house # place links house
if world.mode[player] == 'standard' or not world.shufflelinks[player]: if world.mode[player] == 'standard' or not world.shufflelinks[player]:
links_house = 'Links House' links_house = 'Links House' if not invFlag else 'Big Bomb Shop'
else: else:
links_house_doors = [i for i in LW_Single_Cave_Doors if i not in isolated_entrances + ([] if not invFlag else Inverted_Dark_Sanctuary_Doors)] links_house_doors = [i for i in entrances + must_exits if i not in isolated_entrances + ([] if not invFlag else Inverted_Dark_Sanctuary_Doors)]
if not invFlag and world.doorShuffle[player] == 'crossed' and world.intensity[player] >= 3: if not invFlag and world.doorShuffle[player] == 'crossed' and world.intensity[player] >= 3:
exclusions = DW_Entrances + DW_Dungeon_Entrances + DW_Single_Cave_Doors\ exclusions = DW_Entrances + DW_Dungeon_Entrances + DW_Single_Cave_Doors\
+ DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit + ['Ganons Tower'] + DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit + ['Ganons Tower']
links_house_doors = [i for i in links_house_doors if i not in exclusions] links_house_doors = [i for i in links_house_doors if i not in exclusions]
links_house = random.choice(list(links_house_doors)) links_house = random.choice(list(links_house_doors))
connect_two_way(world, links_house, 'Links House Exit', player) connect_two_way(world, links_house, 'Links House Exit', player)
connect_exit(world, 'Chris Houlihan Room Exit', links_house, player) # should always match link's house, except for plandos
if links_house in entrances: if links_house in entrances:
entrances.remove(links_house) entrances.remove(links_house)
elif links_house in must_exits: elif links_house in must_exits:
@@ -632,7 +630,6 @@ def link_entrances(world, player):
bomb_shop_doors.extend(blacksmith_doors) bomb_shop_doors.extend(blacksmith_doors)
# place bomb shop, has limited options # place bomb shop, has limited options
# cannot place it anywhere already taken (or that are otherwise not eligible for placement) # cannot place it anywhere already taken (or that are otherwise not eligible for placement)
bomb_shop_doors = [door for door in bomb_shop_doors if door in entrances] bomb_shop_doors = [door for door in bomb_shop_doors if door in entrances]
random.shuffle(bomb_shop_doors) random.shuffle(bomb_shop_doors)
@@ -664,7 +661,6 @@ def link_entrances(world, player):
DW_Entrances + DW_Dungeon_Entrances + DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit + ['Skull Woods First Section Door', 'Skull Woods Second Section Door (East)', 'Skull Woods Second Section Door (West)'] +\ DW_Entrances + DW_Dungeon_Entrances + DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit + ['Skull Woods First Section Door', 'Skull Woods Second Section Door (East)', 'Skull Woods Second Section Door (West)'] +\
LW_Single_Cave_Doors + DW_Single_Cave_Doors LW_Single_Cave_Doors + DW_Single_Cave_Doors
else: else:
entrances = Inverted_LW_Entrances + Inverted_LW_Dungeon_Entrances + Inverted_DW_Entrances + Inverted_DW_Dungeon_Entrances + Inverted_Old_Man_Entrances + Old_Man_Entrances + ['Skull Woods Second Section Door (East)', 'Skull Woods Second Section Door (West)', 'Skull Woods First Section Door', 'Kakariko Well Cave', 'Bat Cave Cave', 'North Fairy Cave', 'Sanctuary', 'Lost Woods Hideout Stump', 'Lumberjack Tree Cave', 'Hyrule Castle Entrance (South)']
entrances_must_exits = Inverted_LW_Entrances_Must_Exit + Inverted_LW_Dungeon_Entrances_Must_Exit entrances_must_exits = Inverted_LW_Entrances_Must_Exit + Inverted_LW_Dungeon_Entrances_Must_Exit
doors = Inverted_LW_Entrances + Inverted_LW_Dungeon_Entrances + Inverted_LW_Entrances_Must_Exit + Inverted_LW_Dungeon_Entrances_Must_Exit + ['Kakariko Well Cave', 'Bat Cave Cave', 'North Fairy Cave', 'Sanctuary', 'Lost Woods Hideout Stump', 'Lumberjack Tree Cave', 'Hyrule Castle Secret Entrance Stairs'] + Inverted_Old_Man_Entrances +\ doors = Inverted_LW_Entrances + Inverted_LW_Dungeon_Entrances + Inverted_LW_Entrances_Must_Exit + Inverted_LW_Dungeon_Entrances_Must_Exit + ['Kakariko Well Cave', 'Bat Cave Cave', 'North Fairy Cave', 'Sanctuary', 'Lost Woods Hideout Stump', 'Lumberjack Tree Cave', 'Hyrule Castle Secret Entrance Stairs'] + Inverted_Old_Man_Entrances +\
@@ -721,10 +717,10 @@ def link_entrances(world, player):
else: else:
hole_entrances.append('Hyrule Castle Secret Entrance Drop') hole_entrances.append('Hyrule Castle Secret Entrance Drop')
hole_targets.append('Hyrule Castle Secret Entrance') hole_targets.append('Hyrule Castle Secret Entrance')
exit_pool.append('Hyrule Castle Secret Entrance Stairs')
caves.append('Hyrule Castle Secret Entrance Exit') caves.append('Hyrule Castle Secret Entrance Exit')
if not invFlag: if not invFlag:
doors.append('Hyrule Castle Secret Entrance Stairs') doors.append('Hyrule Castle Secret Entrance Stairs')
exit_pool.append('Hyrule Castle Secret Entrance Stairs')
if not world.shuffle_ganon: if not world.shuffle_ganon:
connect_two_way(world, 'Ganons Tower' if not invFlag else 'Agahnims Tower', 'Ganons Tower Exit', player) connect_two_way(world, 'Ganons Tower' if not invFlag else 'Agahnims Tower', 'Ganons Tower Exit', player)
@@ -733,13 +729,8 @@ def link_entrances(world, player):
else: else:
caves.extend(['Ganons Tower Exit', 'Pyramid Exit']) caves.extend(['Ganons Tower Exit', 'Pyramid Exit'])
hole_targets.append('Pyramid') hole_targets.append('Pyramid')
exit_pool.extend(['Ganons Tower' if not invFlag else 'Agahnims Tower'])
if not invFlag: doors.extend(['Ganons Tower' if not invFlag else 'Agahnims Tower'])
exit_pool.extend(['Ganons Tower'])
doors.extend(['Ganons Tower'])
else:
exit_pool.extend(['Agahnims Tower'])
doors.extend(['Agahnims Tower'])
if invFlag == (0x1b in world.owswaps[player][0] and world.owMixed[player]): if invFlag == (0x1b in world.owswaps[player][0] and world.owMixed[player]):
exit_pool.extend(['Pyramid Entrance']) exit_pool.extend(['Pyramid Entrance'])
@@ -773,16 +764,15 @@ def link_entrances(world, player):
# place links house # place links house
if world.mode[player] == 'standard' or not world.shufflelinks[player]: if world.mode[player] == 'standard' or not world.shufflelinks[player]:
links_house = 'Links House' links_house = 'Links House' if not invFlag else 'Big Bomb Shop'
else: else:
links_house_doors = [i for i in LW_Single_Cave_Doors if i not in isolated_entrances + ([] if not invFlag else Inverted_Dark_Sanctuary_Doors)] links_house_doors = [i for i in doors if i not in isolated_entrances + ([] if not invFlag else Inverted_Dark_Sanctuary_Doors)]
if not invFlag and world.doorShuffle[player] == 'crossed' and world.intensity[player] >= 3: if not invFlag and world.doorShuffle[player] == 'crossed' and world.intensity[player] >= 3:
exclusions = DW_Entrances + DW_Dungeon_Entrances + DW_Single_Cave_Doors \ exclusions = DW_Entrances + DW_Dungeon_Entrances + DW_Single_Cave_Doors \
+ DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit + ['Ganons Tower'] + DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit + ['Ganons Tower']
links_house_doors = [i for i in links_house_doors if i not in exclusions] links_house_doors = [i for i in links_house_doors if i not in exclusions]
links_house = random.choice(links_house_doors) links_house = random.choice(links_house_doors)
connect_two_way(world, links_house, 'Links House Exit', player) connect_two_way(world, links_house, 'Links House Exit', player)
connect_exit(world, 'Chris Houlihan Room Exit', links_house, player) # should always match link's house, except for plandos
exit_pool.remove(links_house) exit_pool.remove(links_house)
doors.remove(links_house) doors.remove(links_house)
@@ -867,6 +857,13 @@ def link_entrances(world, player):
connect_doors(world, doors, door_targets, player) connect_doors(world, doors, door_targets, player)
else: else:
raise NotImplementedError('Shuffling not supported yet') raise NotImplementedError('Shuffling not supported yet')
# ensure Houlihan exits where Links House does
# TODO: Plando should overrule this
for links_house in world.get_entrance('Links House Exit', player).connected_region.exits:
if links_house.connected_region and links_house.connected_region.name == 'Links House':
break
connect_exit(world, 'Chris Houlihan Room Exit', links_house.name, player)
# check for swamp palace fix # check for swamp palace fix
if world.get_entrance('Dam', player).connected_region.name != 'Dam' or world.get_entrance('Swamp Palace', player).connected_region.name != 'Swamp Portal': if world.get_entrance('Dam', player).connected_region.name != 'Dam' or world.get_entrance('Swamp Palace', player).connected_region.name != 'Swamp Portal':
@@ -2404,7 +2401,7 @@ Exit_Pool_Base = {'Links House Exit',
'Chest Game', 'Chest Game',
'Dark World Hammer Peg Cave', 'Dark World Hammer Peg Cave',
'Red Shield Shop', 'Red Shield Shop',
'Dark Sanctuary Hint', 'Dark Sanctuary Hint Exit',
'Fortune Teller (Dark)', 'Fortune Teller (Dark)',
'Archery Game', 'Archery Game',
'Mire Shed', 'Mire Shed',
@@ -2426,7 +2423,6 @@ Exit_Pool_Base = {'Links House Exit',
# these are connections that cannot be shuffled and always exist. They link together separate parts of the world we need to divide into regions # these are connections that cannot be shuffled and always exist. They link together separate parts of the world we need to divide into regions
mandatory_connections = [('Links House S&Q', 'Links House'), mandatory_connections = [('Links House S&Q', 'Links House'),
('Old Man S&Q', 'Old Man House'),
# UW Connections # UW Connections
('Lost Woods Hideout (top to bottom)', 'Lost Woods Hideout (bottom)'), ('Lost Woods Hideout (top to bottom)', 'Lost Woods Hideout (bottom)'),
@@ -2488,7 +2484,7 @@ default_connections = [('Lumberjack House', 'Lumberjack House'),
('Dark Lake Hylia Ledge Spike Cave', 'Dark Lake Hylia Ledge Spike Cave'), ('Dark Lake Hylia Ledge Spike Cave', 'Dark Lake Hylia Ledge Spike Cave'),
('Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Ledge Hint'), ('Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Ledge Hint'),
('Bonk Fairy (Dark)', 'Bonk Fairy (Dark)'), ('Bonk Fairy (Dark)', 'Bonk Fairy (Dark)'),
('Dark Sanctuary Hint', 'Dark Sanctuary Hint'), ('Dark Sanctuary Hint', 'Dark Sanctuary Hint Exit'),
('Fortune Teller (Dark)', 'Fortune Teller (Dark)'), ('Fortune Teller (Dark)', 'Fortune Teller (Dark)'),
('Archery Game', 'Archery Game'), ('Archery Game', 'Archery Game'),
('Dark Desert Hint', 'Dark Desert Hint'), ('Dark Desert Hint', 'Dark Desert Hint'),

View File

@@ -292,7 +292,7 @@ def main(args, seed=None, fish=None):
customize_shops(world, player) customize_shops(world, player)
balance_money_progression(world) balance_money_progression(world)
if world.owShuffle[1] != 'vanilla' or world.owCrossed[1] != 'none' or world.owMixed[1] or str(world.seed).startswith('M'): if world.owShuffle[1] != 'vanilla' or world.owCrossed[1] not in ['none', 'polar'] or world.owMixed[1] or str(world.seed).startswith('M'):
outfilebase = f'OR_{args.outputname if args.outputname else world.seed}' outfilebase = f'OR_{args.outputname if args.outputname else world.seed}'
else: else:
outfilebase = f'DR_{args.outputname if args.outputname else world.seed}' outfilebase = f'DR_{args.outputname if args.outputname else world.seed}'

View File

@@ -2,7 +2,7 @@ import RaceRandom as random, logging, copy
from BaseClasses import OWEdge, WorldType, RegionType, Direction, Terrain, PolSlot, Entrance from BaseClasses import OWEdge, WorldType, RegionType, Direction, Terrain, PolSlot, Entrance
from OWEdges import OWTileRegions, OWTileGroups, OWEdgeGroups, OpenStd, parallel_links, IsParallel from OWEdges import OWTileRegions, OWTileGroups, OWEdgeGroups, OpenStd, parallel_links, IsParallel
__version__ = '0.1.9.2-u' __version__ = '0.1.9.4-u'
def link_overworld(world, player): def link_overworld(world, player):
# setup mandatory connections # setup mandatory connections
@@ -1442,7 +1442,7 @@ flute_data = {
0x32: (['Flute Boy Approach Area', 'Stumpy Approach Area'], 0x32, 0x03a0, 0x0c6c, 0x0500, 0x0cd0, 0x05a8, 0x0cdb, 0x0585, 0x0002, 0x0000, 0x0cd6, 0x05a8), 0x32: (['Flute Boy Approach Area', 'Stumpy Approach Area'], 0x32, 0x03a0, 0x0c6c, 0x0500, 0x0cd0, 0x05a8, 0x0cdb, 0x0585, 0x0002, 0x0000, 0x0cd6, 0x05a8),
0x33: (['C Whirlpool Outer Area', 'Dark C Whirlpool Outer Area'], 0x33, 0x0180, 0x0c20, 0x0600, 0x0c80, 0x0628, 0x0c8f, 0x067d, 0x0000, 0x0000, 0x0c80, 0x0628), 0x33: (['C Whirlpool Outer Area', 'Dark C Whirlpool Outer Area'], 0x33, 0x0180, 0x0c20, 0x0600, 0x0c80, 0x0628, 0x0c8f, 0x067d, 0x0000, 0x0000, 0x0c80, 0x0628),
0x34: (['Statues Area', 'Hype Cave Area'], 0x34, 0x088e, 0x0d00, 0x0866, 0x0d60, 0x08d8, 0x0d6f, 0x08e3, 0x0000, 0x000a, 0x0d60, 0x08d8), 0x34: (['Statues Area', 'Hype Cave Area'], 0x34, 0x088e, 0x0d00, 0x0866, 0x0d60, 0x08d8, 0x0d6f, 0x08e3, 0x0000, 0x000a, 0x0d60, 0x08d8),
0x35: (['Lake Hylia Area', 'Ice Lake Area'], 0x35, 0x0d00, 0x0da6, 0x0a06, 0x0e08, 0x0a80, 0x0e13, 0x0a8b, 0xfffa, 0xfffa, 0x0d88, 0x0a88), 0x3e: (['Lake Hylia South Shore', 'Ice Lake Ledge (East)'], 0x35, 0x1860, 0x0f1e, 0x0d00, 0x0f98, 0x0da8, 0x0f8b, 0x0d85, 0x0000, 0x0000, 0x0f90, 0x0da4),
0x37: (['Ice Cave Area', 'Shopping Mall Area'], 0x37, 0x0786, 0x0cf6, 0x0e2e, 0x0d58, 0x0ea0, 0x0d63, 0x0eab, 0x000a, 0x0002, 0x0d48, 0x0ed0), 0x37: (['Ice Cave Area', 'Shopping Mall Area'], 0x37, 0x0786, 0x0cf6, 0x0e2e, 0x0d58, 0x0ea0, 0x0d63, 0x0eab, 0x000a, 0x0002, 0x0d48, 0x0ed0),
0x3a: (['Desert Pass Area', 'Swamp Nook Area'], 0x3a, 0x001a, 0x0e08, 0x04c6, 0x0e70, 0x0540, 0x0e7d, 0x054b, 0x0006, 0x000a, 0x0e70, 0x0540), 0x3a: (['Desert Pass Area', 'Swamp Nook Area'], 0x3a, 0x001a, 0x0e08, 0x04c6, 0x0e70, 0x0540, 0x0e7d, 0x054b, 0x0006, 0x000a, 0x0e70, 0x0540),
0x3b: (['Dam Area', 'Swamp Area'], 0x3b, 0x069e, 0x0edf, 0x06f2, 0x0f3d, 0x0778, 0x0f4c, 0x077f, 0xfff1, 0xfffe, 0x0f30, 0x0770), 0x3b: (['Dam Area', 'Swamp Area'], 0x3b, 0x069e, 0x0edf, 0x06f2, 0x0f3d, 0x0778, 0x0f4c, 0x077f, 0xfff1, 0xfffe, 0x0f30, 0x0770),

2
Rom.py
View File

@@ -661,7 +661,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
# patch overworld edges # patch overworld edges
inverted_buffer = [0] * 0x82 inverted_buffer = [0] * 0x82
if world.owShuffle[player] != 'vanilla' or world.owCrossed[player] != 'none' or world.owMixed[player]: if world.owShuffle[player] != 'vanilla' or world.owCrossed[player] not in ['none', 'polar'] or world.owMixed[player]:
owMode = 0 owMode = 0
if world.owShuffle[player] == 'parallel': if world.owShuffle[player] == 'parallel':
owMode = 1 owMode = 1

383
Rules.py
View File

@@ -1900,199 +1900,200 @@ def set_big_bomb_rules(world, 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))) #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): def set_inverted_big_bomb_rules(world, player):
bombshop_entrance = world.get_region('Big Bomb Shop', player).entrances[0] if len(world.get_region('Big Bomb Shop', player).entrances) > 0:
Normal_LW_entrances = ['Blinds Hideout', bombshop_entrance = world.get_region('Big Bomb Shop', player).entrances[0]
'Bonk Fairy (Light)', Normal_LW_entrances = ['Blinds Hideout',
'Lake Hylia Fairy', 'Bonk Fairy (Light)',
'Light Hype Fairy', 'Lake Hylia Fairy',
'Desert Fairy', 'Light Hype Fairy',
'Chicken House', 'Desert Fairy',
'Aginahs Cave', 'Chicken House',
'Sahasrahlas Hut', 'Aginahs Cave',
'Cave Shop (Lake Hylia)', 'Sahasrahlas Hut',
'Blacksmiths Hut', 'Cave Shop (Lake Hylia)',
'Sick Kids House', 'Blacksmiths Hut',
'Lost Woods Gamble', 'Sick Kids House',
'Fortune Teller (Light)', 'Lost Woods Gamble',
'Snitch Lady (East)', 'Fortune Teller (Light)',
'Snitch Lady (West)', 'Snitch Lady (East)',
'Tavern (Front)', 'Snitch Lady (West)',
'Kakariko Shop', 'Tavern (Front)',
'Mini Moldorm Cave', 'Kakariko Shop',
'Long Fairy Cave', 'Mini Moldorm Cave',
'Good Bee Cave', 'Long Fairy Cave',
'20 Rupee Cave', 'Good Bee Cave',
'50 Rupee Cave', '20 Rupee Cave',
'Ice Rod Cave', '50 Rupee Cave',
'Bonk Rock Cave', 'Ice Rod Cave',
'Library', 'Bonk Rock Cave',
'Potion Shop', 'Library',
'Dam', 'Potion Shop',
'Lumberjack House', 'Dam',
'Lake Hylia Fortune Teller', 'Lumberjack House',
'Eastern Palace', 'Lake Hylia Fortune Teller',
'Kakariko Gamble Game', 'Eastern Palace',
'Kakariko Well Cave', 'Kakariko Gamble Game',
'Bat Cave Cave', 'Kakariko Well Cave',
'Elder House (East)', 'Bat Cave Cave',
'Elder House (West)', 'Elder House (East)',
'North Fairy Cave', 'Elder House (West)',
'Lost Woods Hideout Stump', 'North Fairy Cave',
'Lumberjack Tree Cave', 'Lost Woods Hideout Stump',
'Two Brothers House (East)', 'Lumberjack Tree Cave',
'Sanctuary', 'Two Brothers House (East)',
'Hyrule Castle Entrance (South)', 'Sanctuary',
'Hyrule Castle Secret Entrance Stairs', 'Hyrule Castle Entrance (South)',
'Hyrule Castle Entrance (West)', 'Hyrule Castle Secret Entrance Stairs',
'Hyrule Castle Entrance (East)', 'Hyrule Castle Entrance (West)',
'Ganons Tower', 'Hyrule Castle Entrance (East)',
'Cave 45', 'Ganons Tower',
'Checkerboard Cave', 'Cave 45',
'Links House'] 'Checkerboard Cave',
Isolated_LW_entrances = ['Old Man Cave (East)', 'Links House']
'Old Man House (Bottom)', Isolated_LW_entrances = ['Old Man Cave (East)',
'Old Man House (Top)', 'Old Man House (Bottom)',
'Death Mountain Return Cave (East)', 'Old Man House (Top)',
'Spectacle Rock Cave Peak', 'Death Mountain Return Cave (East)',
'Tower of Hera', 'Spectacle Rock Cave Peak',
'Death Mountain Return Cave (West)', 'Tower of Hera',
'Paradox Cave (Top)', 'Death Mountain Return Cave (West)',
'Fairy Ascension Cave (Top)', 'Paradox Cave (Top)',
'Spiral Cave', 'Fairy Ascension Cave (Top)',
'Paradox Cave (Bottom)', 'Spiral Cave',
'Paradox Cave (Middle)', 'Paradox Cave (Bottom)',
'Hookshot Fairy', 'Paradox Cave (Middle)',
'Spiral Cave (Bottom)', 'Hookshot Fairy',
'Mimic Cave', 'Spiral Cave (Bottom)',
'Fairy Ascension Cave (Bottom)', 'Mimic Cave',
'Desert Palace Entrance (West)', 'Fairy Ascension Cave (Bottom)',
'Desert Palace Entrance (North)', 'Desert Palace Entrance (West)',
'Desert Palace Entrance (South)'] 'Desert Palace Entrance (North)',
Eastern_DW_entrances = ['Palace of Darkness', 'Desert Palace Entrance (South)']
'Palace of Darkness Hint', Eastern_DW_entrances = ['Palace of Darkness',
'Dark Lake Hylia Fairy', 'Palace of Darkness Hint',
'East Dark World Hint'] 'Dark Lake Hylia Fairy',
Northern_DW_entrances = ['Brewery', 'East Dark World Hint']
'C-Shaped House', Northern_DW_entrances = ['Brewery',
'Chest Game', 'C-Shaped House',
'Dark World Hammer Peg Cave', 'Chest Game',
'Dark Sanctuary Hint', 'Dark World Hammer Peg Cave',
'Fortune Teller (Dark)', 'Dark Sanctuary Hint',
'Dark World Lumberjack Shop', 'Fortune Teller (Dark)',
'Thieves Town', 'Dark World Lumberjack Shop',
'Skull Woods First Section Door', 'Thieves Town',
'Skull Woods Second Section Door (East)'] 'Skull Woods First Section Door',
Southern_DW_entrances = ['Hype Cave', 'Skull Woods Second Section Door (East)']
'Bonk Fairy (Dark)', Southern_DW_entrances = ['Hype Cave',
'Archery Game', 'Bonk Fairy (Dark)',
'Big Bomb Shop', 'Archery Game',
'Dark Lake Hylia Shop', 'Big Bomb Shop',
'Swamp Palace'] 'Dark Lake Hylia Shop',
Isolated_DW_entrances = ['Spike Cave', 'Swamp Palace']
'Cave Shop (Dark Death Mountain)', Isolated_DW_entrances = ['Spike Cave',
'Dark Death Mountain Fairy', 'Cave Shop (Dark Death Mountain)',
'Skull Woods Second Section Door (West)', 'Dark Death Mountain Fairy',
'Skull Woods Final Section', 'Skull Woods Second Section Door (West)',
'Turtle Rock', 'Skull Woods Final Section',
'Dark Death Mountain Ledge (West)', 'Turtle Rock',
'Dark Death Mountain Ledge (East)', 'Dark Death Mountain Ledge (West)',
'Bumper Cave (Top)', 'Dark Death Mountain Ledge (East)',
'Superbunny Cave (Top)', 'Bumper Cave (Top)',
'Superbunny Cave (Bottom)', 'Superbunny Cave (Top)',
'Hookshot Cave', 'Superbunny Cave (Bottom)',
'Turtle Rock Isolated Ledge Entrance', 'Hookshot Cave',
'Hookshot Cave Back Entrance', 'Turtle Rock Isolated Ledge Entrance',
'Agahnims Tower'] 'Hookshot Cave Back Entrance',
LW_walkable_entrances = ['Dark Lake Hylia Ledge Fairy', 'Agahnims Tower']
'Dark Lake Hylia Ledge Spike Cave', LW_walkable_entrances = ['Dark Lake Hylia Ledge Fairy',
'Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Ledge Spike Cave',
'Mire Shed', 'Dark Lake Hylia Ledge Hint',
'Dark Desert Hint', 'Mire Shed',
'Dark Desert Fairy', 'Dark Desert Hint',
'Misery Mire', 'Dark Desert Fairy',
'Red Shield Shop'] 'Misery Mire',
LW_bush_entrances = ['Bush Covered House', 'Red Shield Shop']
'Light World Bomb Hut', LW_bush_entrances = ['Bush Covered House',
'Graveyard Cave'] 'Light World Bomb Hut',
LW_inaccessible_entrances = ['Desert Palace Entrance (East)', 'Graveyard Cave']
'Spectacle Rock Cave', LW_inaccessible_entrances = ['Desert Palace Entrance (East)',
'Spectacle Rock Cave (Bottom)'] 'Spectacle Rock Cave',
'Spectacle Rock Cave (Bottom)']
set_rule(world.get_entrance('Pyramid Fairy', player), 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)) 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: # Key for below abbreviations:
# P = pearl # P = pearl
# A = Aga1 # A = Aga1
# H = hammer # H = hammer
# M = Mirror # M = Mirror
# G = Glove # G = Glove
if bombshop_entrance.name in Eastern_DW_entrances: if bombshop_entrance.name in Eastern_DW_entrances:
# Just walk to the pyramid # Just walk to the pyramid
pass pass
elif bombshop_entrance.name in Normal_LW_entrances: elif bombshop_entrance.name in Normal_LW_entrances:
# Just walk to the castle and mirror. # Just walk to the castle and mirror.
add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.has_Mirror(player)) add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.has_Mirror(player))
elif bombshop_entrance.name in Isolated_LW_entrances: 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. # 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)) 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: 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, # 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. # 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))) 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: elif bombshop_entrance.name in Southern_DW_entrances:
# This is the same as north DW without the Mitts rock present. # 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))) 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: elif bombshop_entrance.name in Isolated_DW_entrances:
# There's just no way to escape these places with the bomb and no Flute. # 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)) add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.can_flute(player))
elif bombshop_entrance.name in LW_walkable_entrances: 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 # 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))) 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: 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. # 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)))) 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': 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 # 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)))) 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)': 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. # 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))) 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)': 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. # 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))) 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': 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. # 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)) 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': elif bombshop_entrance.name == 'Kings Grave':
# Either lift the rock and walk to the castle to Mirror or Mirror immediately and Flute. # 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)) 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)': 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. # 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)) 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': elif bombshop_entrance.name == 'Waterfall of Wishing':
# You absolutely must be able to swim to return it from here. # 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)) 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': elif bombshop_entrance.name == 'Ice Palace':
# You can swim to the dock or use the Flute to get off the island. # 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)) 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': elif bombshop_entrance.name == 'Capacity Upgrade':
# You must Mirror but then can use either Ice Palace return path. # 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)) 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)': 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. # 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)) 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: elif bombshop_entrance.name in LW_inaccessible_entrances:
# You can't get to the pyramid from these entrances without bomb duping. # 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) raise Exception('No valid path to open Pyramid Fairy. (Could not route from %s)' % bombshop_entrance.name)
elif bombshop_entrance.name == 'Pyramid Fairy': elif bombshop_entrance.name == 'Pyramid Fairy':
# Self locking. The shuffles don't put the bomb shop here, but doesn't lock anything important. # 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) set_rule(world.get_entrance('Pyramid Fairy', player), lambda state: False)
else: else:
raise Exception('No logic found for routing from %s to the pyramid.' % bombshop_entrance.name) 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] != 'none': if world.owShuffle[player] != 'vanilla' or world.owMixed[player] or world.owCrossed[player] != 'none':
add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: False) #temp disable progression until routing to Pyramid get be guaranteed add_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): def set_bunny_rules(world, player, inverted):