From 2c21d95e57838610b19b4a1cceafef5fc1e97284 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sat, 2 Oct 2021 20:00:37 -0500 Subject: [PATCH 01/10] Minor filename output change --- Main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Main.py b/Main.py index 220ca123..056c010e 100644 --- a/Main.py +++ b/Main.py @@ -265,7 +265,7 @@ def main(args, seed=None, fish=None): customize_shops(world, player) 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}' else: outfilebase = f'DR_{args.outputname if args.outputname else world.seed}' From 83f21bab07f4f45352bd7c057bfa3b8f4f2964ae Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 3 Oct 2021 09:09:39 -0500 Subject: [PATCH 02/10] Prevent writes to ROM if invalid combinations of OW shuffle are used --- Rom.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rom.py b/Rom.py index d05e723e..ad27a3b5 100644 --- a/Rom.py +++ b/Rom.py @@ -646,7 +646,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): # patch overworld edges 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 if world.owShuffle[player] == 'parallel': owMode = 1 From 37dd6f874a7cdf231468b78762fc8d6c65cfdc67 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 4 Oct 2021 19:38:29 -0500 Subject: [PATCH 03/10] Moved Lake Hylia flute spot to east south shore --- OverworldShuffle.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 7b7ad24c..5a3f0718 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -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), 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), - 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), 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), From 354d4ab1fc5d6d56716a8f8a24dbfbea0fd74ed5 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 4 Oct 2021 21:56:53 -0500 Subject: [PATCH 04/10] Fix Links House default placement in Inverted ER --- EntranceShuffle.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/EntranceShuffle.py b/EntranceShuffle.py index c5398aa1..302f02ec 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -142,9 +142,9 @@ def link_entrances(world, player): # place links house 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: - 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) 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 @@ -245,9 +245,7 @@ def link_entrances(world, player): # place links house if world.mode[player] == 'standard' or not world.shufflelinks[player]: - links_house = 'Links House' 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 = random.choice(links_house_doors) 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 @@ -401,9 +399,9 @@ def link_entrances(world, player): # place links house 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: - 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) 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 @@ -583,9 +581,9 @@ def link_entrances(world, player): # place links house 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: - 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: exclusions = DW_Entrances + DW_Dungeon_Entrances + DW_Single_Cave_Doors\ + DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit + ['Ganons Tower'] @@ -773,9 +771,9 @@ def link_entrances(world, player): # place links house 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: - 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: exclusions = DW_Entrances + DW_Dungeon_Entrances + DW_Single_Cave_Doors \ + DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit + ['Ganons Tower'] From 116ffe6bd18c21721aad18e8e8877ea4f0a90659 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Tue, 5 Oct 2021 19:08:29 -0500 Subject: [PATCH 05/10] Fix Links House default placement in Inverted ER --- EntranceShuffle.py | 1 + 1 file changed, 1 insertion(+) diff --git a/EntranceShuffle.py b/EntranceShuffle.py index 302f02ec..8350b5bb 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -245,6 +245,7 @@ def link_entrances(world, player): # place links house if world.mode[player] == 'standard' or not world.shufflelinks[player]: + links_house = 'Links House' if not invFlag else 'Big Bomb Shop' else: links_house = random.choice(links_house_doors) connect_two_way(world, links_house, 'Links House Exit', player) From 457421f54a76853ff16331b31792e3e236430935 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Tue, 5 Oct 2021 19:30:38 -0500 Subject: [PATCH 06/10] Minor accuracy improvements to ER algorithm --- EntranceShuffle.py | 83 +++++----- Rules.py | 383 +++++++++++++++++++++++---------------------- 2 files changed, 234 insertions(+), 232 deletions(-) diff --git a/EntranceShuffle.py b/EntranceShuffle.py index 8350b5bb..8994b93c 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -18,6 +18,11 @@ def link_entrances(world, player): isolated_entrances = Isolated_LH_Doors.copy() # 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]): drop_connections.append(tuple(('Pyramid Hole', 'Pyramid'))) 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'))) connect_simple(world, 'Other World S&Q', 'Hyrule Castle Ledge', player) - 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 == (0x03 in world.owswaps[player][0] and world.owMixed[player]): + connect_simple(world, 'Old Man S&Q', 'Old Man House', player) + else: + 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) # setup mandatory connections @@ -139,7 +144,7 @@ def link_entrances(world, player): exit1, exit2 = caves.pop() connect_two_way(world, entrance1, exit1, player) connect_two_way(world, entrance2, exit2, player) - + # place links house if world.mode[player] == 'standard' or not world.shufflelinks[player]: links_house = 'Links House' if not invFlag else 'Big Bomb Shop' @@ -174,17 +179,18 @@ def link_entrances(world, player): else: # at this point only Light World death mountain entrances remain # 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)'] random.shuffle(old_man_entrances) old_man_exit = old_man_entrances.pop() if not invFlag: - remaining_entrances.extend(old_man_entrances) - random.shuffle(remaining_entrances) - old_man_entrance = remaining_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) + lw_dm_entrances.extend(old_man_entrances) + random.shuffle(lw_dm_entrances) + 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_exit, 'Old Man Cave Exit (East)', player) if invFlag and old_man_exit == 'Spike Cave': @@ -196,7 +202,7 @@ def link_entrances(world, player): caves.extend(list(three_exit_caves)) # 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(world, player) @@ -247,15 +253,24 @@ def link_entrances(world, player): if world.mode[player] == 'standard' or not world.shufflelinks[player]: links_house = 'Links House' if not invFlag else 'Big Bomb Shop' else: + 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) 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 lw_entrances: - if not invFlag: + if not invFlag: + if links_house in lw_entrances: lw_entrances.remove(links_house) - else: + else: + if links_house in dw_entrances: 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_two_way(world, sanc_door, 'Dark Sanctuary Hint', player) + # in restricted, the only mandatory exits are in dark world (lw in inverted) if not invFlag: connect_mandatory_exits(world, dw_entrances, caves, dw_must_exits, player) @@ -264,10 +279,7 @@ def link_entrances(world, player): # place old man, has limited options # 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] - else: - old_man_entrances = [door for door in old_man_entrances if door in dw_entrances] + old_man_entrances = [door for door in old_man_entrances if door in (lw_entrances if not invFlag else dw_entrances)] random.shuffle(old_man_entrances) old_man_exit = old_man_entrances.pop() connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player) @@ -320,9 +332,8 @@ def link_entrances(world, player): # scramble holes scramble_holes(world, player) - doors = lw_entrances + dw_entrances - # place remaining doors + doors = lw_entrances + dw_entrances connect_doors(world, doors, door_targets, player) elif world.shuffle[player] == 'full': skull_woods_shuffle(world, player) @@ -333,7 +344,6 @@ def link_entrances(world, player): dw_must_exits = list(DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit) lw_must_exits = list(LW_Dungeon_Entrances_Must_Exit) 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) blacksmith_doors = list(Blacksmith_Single_Cave_Doors + Blacksmith_Multi_Cave_Doors) door_targets = list(Single_Cave_Targets) @@ -342,7 +352,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) 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']) - 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) blacksmith_doors = list(Inverted_Blacksmith_Single_Cave_Doors + Blacksmith_Multi_Cave_Doors) door_targets = list(Inverted_Single_Cave_Targets) @@ -354,15 +363,17 @@ def link_entrances(world, player): else: lw_must_exits.append('Desert Palace Entrance (West)') 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) if world.mode[player] == 'standard': # must connect front of hyrule castle to do escape connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player) - elif invFlag or world.doorShuffle[player] == 'vanilla': - 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)') - + else: + 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: 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)'] @@ -508,16 +519,14 @@ def link_entrances(world, player): old_man_entrance = dw_entrances.pop() connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)', player) - # now scramble the rest connect_caves(world, lw_entrances, dw_entrances, caves, player) # scramble holes scramble_holes(world, player) - doors = lw_entrances + dw_entrances - # place remaining doors + doors = lw_entrances + dw_entrances connect_doors(world, doors, door_targets, player) elif world.shuffle[player] == 'crossed': skull_woods_shuffle(world, player) @@ -526,7 +535,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) 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']) - 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) blacksmith_doors = list(Blacksmith_Single_Cave_Doors + Blacksmith_Multi_Cave_Doors) door_targets = list(Single_Cave_Targets) @@ -534,10 +542,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) 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']) - 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) blacksmith_doors = list(Inverted_Blacksmith_Single_Cave_Doors + Blacksmith_Multi_Cave_Doors) 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: # randomize which desert ledge door is a must-exit @@ -631,7 +639,6 @@ def link_entrances(world, player): bomb_shop_doors.extend(blacksmith_doors) # place bomb shop, has limited options - # 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] random.shuffle(bomb_shop_doors) @@ -663,7 +670,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)'] +\ LW_Single_Cave_Doors + DW_Single_Cave_Doors 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 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 +\ @@ -720,10 +726,10 @@ def link_entrances(world, player): else: hole_entrances.append('Hyrule Castle Secret Entrance Drop') hole_targets.append('Hyrule Castle Secret Entrance') - exit_pool.append('Hyrule Castle Secret Entrance Stairs') caves.append('Hyrule Castle Secret Entrance Exit') if not invFlag: doors.append('Hyrule Castle Secret Entrance Stairs') + exit_pool.append('Hyrule Castle Secret Entrance Stairs') if not world.shuffle_ganon: connect_two_way(world, 'Ganons Tower' if not invFlag else 'Agahnims Tower', 'Ganons Tower Exit', player) @@ -732,13 +738,8 @@ def link_entrances(world, player): else: caves.extend(['Ganons Tower Exit', 'Pyramid Exit']) hole_targets.append('Pyramid') - - if not invFlag: - exit_pool.extend(['Ganons Tower']) - doors.extend(['Ganons Tower']) - else: - exit_pool.extend(['Agahnims Tower']) - doors.extend(['Agahnims Tower']) + exit_pool.extend(['Ganons Tower' if not invFlag else 'Agahnims Tower']) + doors.extend(['Ganons Tower' if not invFlag else 'Agahnims Tower']) if invFlag == (0x1b in world.owswaps[player][0] and world.owMixed[player]): exit_pool.extend(['Pyramid Entrance']) diff --git a/Rules.py b/Rules.py index 702f7d2b..9ceac0d7 100644 --- a/Rules.py +++ b/Rules.py @@ -1865,199 +1865,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))) def set_inverted_big_bomb_rules(world, player): - 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)'] + 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)) + 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] != 'none': - add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: False) #temp disable progression until routing to Pyramid get be guaranteed + # 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] != 'none': + 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): From 249591e1f6306d3038b364f1e1a3d3104aadea94 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Tue, 5 Oct 2021 19:32:53 -0500 Subject: [PATCH 07/10] Simplified Houlihan designation in ER --- EntranceShuffle.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/EntranceShuffle.py b/EntranceShuffle.py index 8994b93c..dd93d302 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -72,12 +72,10 @@ def link_entrances(world, player): for entrancename, exitname in open_default_connections: connect_logical(world, entrancename, exitname, player, True) ignore_pool = True - connect_exit(world, 'Chris Houlihan Room Exit', 'Links House', player) else: for entrancename, exitname in inverted_default_connections: connect_logical(world, entrancename, exitname, player, True) ignore_pool = True - connect_exit(world, 'Chris Houlihan Room Exit', 'Big Bomb Shop', player) # inverted entrance mods for owid in swapped_connections.keys(): @@ -152,7 +150,6 @@ def link_entrances(world, player): 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) 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: bomb_shop_doors.remove(links_house) @@ -256,7 +253,6 @@ def link_entrances(world, player): 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) 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: lw_entrances.remove(links_house) @@ -416,7 +412,6 @@ def link_entrances(world, player): 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) 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: lw_entrances.remove(links_house) @@ -599,7 +594,6 @@ def link_entrances(world, player): links_house_doors = [i for i in links_house_doors if i not in exclusions] links_house = random.choice(list(links_house_doors)) 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: entrances.remove(links_house) elif links_house in must_exits: @@ -782,7 +776,6 @@ def link_entrances(world, player): links_house_doors = [i for i in links_house_doors if i not in exclusions] links_house = random.choice(links_house_doors) 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) doors.remove(links_house) @@ -867,6 +860,13 @@ def link_entrances(world, player): connect_doors(world, doors, door_targets, player) else: 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.name == 'Links House': + break + connect_exit(world, 'Chris Houlihan Room Exit', links_house.name, player) # 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': From e94431a1b6374a148f770a11448870211abdea05 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Tue, 5 Oct 2021 19:34:11 -0500 Subject: [PATCH 08/10] Changed Dark Sanc to 2way connection in ER --- EntranceShuffle.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/EntranceShuffle.py b/EntranceShuffle.py index dd93d302..88fb6625 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -163,9 +163,7 @@ def link_entrances(world, player): sanc_doors = [door for door in Inverted_Dark_Sanctuary_Doors if door in bomb_shop_doors] sanc_door = random.choice(sanc_doors) bomb_shop_doors.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) + connect_two_way(world, sanc_door, 'Dark Sanctuary Hint', player) lw_dm_entrances = ['Paradox Cave (Bottom)', 'Paradox Cave (Middle)', 'Paradox Cave (Top)', 'Old Man House (Bottom)', 'Fairy Ascension Cave (Bottom)', 'Fairy Ascension Cave (Top)', 'Spiral Cave (Bottom)', 'Old Man Cave (East)', @@ -425,8 +423,7 @@ def link_entrances(world, player): 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) + connect_two_way(world, sanc_door, 'Dark Sanctuary Hint', player) # we randomize which world requirements we fulfill first so we get better dungeon distribution # we also places the Old Man House at this time to make sure he can be connected to the desert one way @@ -604,8 +601,7 @@ def link_entrances(world, player): sanc_doors = [door for door in Inverted_Dark_Sanctuary_Doors if door in entrances] sanc_door = random.choice(sanc_doors) 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) + connect_two_way(world, sanc_door, 'Dark Sanctuary Hint', player) #place must-exit caves connect_mandatory_exits(world, entrances, caves, must_exits, player) @@ -785,8 +781,7 @@ def link_entrances(world, player): sanc_door = random.choice(sanc_doors) exit_pool.remove(sanc_door) doors.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) + connect_two_way(world, sanc_door, 'Dark Sanctuary Hint', player) # now let's deal with mandatory reachable stuff def extract_reachable_exit(cavelist): From e9c4486e1ccc5b5392993d03b217429e0e37d39a Mon Sep 17 00:00:00 2001 From: codemann8 Date: Tue, 5 Oct 2021 19:35:18 -0500 Subject: [PATCH 09/10] Minor accuracy improvements to ER algorithm --- EntranceShuffle.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/EntranceShuffle.py b/EntranceShuffle.py index 88fb6625..b55a8673 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -180,8 +180,6 @@ def link_entrances(world, player): random.shuffle(old_man_entrances) old_man_exit = old_man_entrances.pop() if not invFlag: - - 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) lw_dm_entrances.extend(old_man_entrances) random.shuffle(lw_dm_entrances) old_man_entrance = lw_dm_entrances.pop() From 80ae3eecc22373f84fe92a0c544f94d07ad87baa Mon Sep 17 00:00:00 2001 From: codemann8 Date: Tue, 5 Oct 2021 19:47:05 -0500 Subject: [PATCH 10/10] Version bump 0.1.9.3 --- CHANGELOG.md | 5 +++++ OverworldShuffle.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 778324c1..1c6e10d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +### 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 - Fixed spoiler log and mystery for new Crossed/Mixed structure - Minor preparations and tweaks to ER framework (added global Entrance/Exit pool) diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 5a3f0718..810c4df0 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -2,7 +2,7 @@ import RaceRandom as random, logging, copy from BaseClasses import OWEdge, WorldType, RegionType, Direction, Terrain, PolSlot, Entrance from OWEdges import OWTileRegions, OWTileGroups, OWEdgeGroups, OpenStd, parallel_links, IsParallel -__version__ = '0.1.9.2-u' +__version__ = '0.1.9.3-u' def link_overworld(world, player): # setup mandatory connections