From bd53400fecf73f64d0e3b7fb85bb3943f55cf882 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Tue, 6 Dec 2022 22:21:35 -0600 Subject: [PATCH 001/196] Replaced all references of Inverted-variant regions/exits --- BaseClasses.py | 5 +- DoorShuffle.py | 10 +- EntranceShuffle.py | 338 ++++++++++--------------- InvertedRegions.py | 18 +- KeyDoorShuffle.py | 16 +- Main.py | 5 +- OverworldGlitchRules.py | 2 +- Regions.py | 9 +- Rom.py | 18 +- Rules.py | 20 +- source/item/District.py | 10 - source/item/FillUtil.py | 2 +- source/overworld/EntranceShuffle2.py | 171 ++++++------- test/inverted/TestInvertedBombRules.py | 8 +- test/inverted/TestInvertedEntrances.py | 40 +-- 15 files changed, 282 insertions(+), 390 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index d7724a98..0625a3cb 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -265,6 +265,9 @@ class World(object): return portal raise RuntimeError('No such portal %s for player %d' % (portal_name, player)) + def is_atgt_swapped(self, player): + return self.mode[player] == 'inverted' + def check_for_door(self, doorname, player): if isinstance(doorname, Door): return doorname @@ -2845,8 +2848,6 @@ class Pot(object): return [self.x, high_byte, item] def get_region(self, world, player): - if world.mode[player] == 'inverted' and self.room == 'Links House': - return world.get_region('Inverted Links House', 1) return world.get_region(self.room, 1) def __eq__(self, other): diff --git a/DoorShuffle.py b/DoorShuffle.py index bab0bf56..c212e990 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -610,8 +610,6 @@ def analyze_portals(world, player): def connect_portal(portal, world, player): ent, ext, entrance_name = portal_map[portal.name] - if world.mode[player] == 'inverted' and portal.name in ['Ganons Tower', 'Agahnims Tower']: - ext = 'Inverted ' + ext portal_entrance = world.get_entrance(portal.door.entrance.name, player) # ensures I get the right one for copying target_exit = world.get_entrance(ext, player) portal_entrance.connected_region = target_exit.parent_region @@ -3192,7 +3190,7 @@ def find_inaccessible_regions(world, player): if world.mode[player] != 'inverted': start_regions = ['Links House', 'Sanctuary'] else: - start_regions = ['Inverted Links House', 'Inverted Dark Sanctuary'] + start_regions = ['Links House', 'Dark Sanctuary Hint'] regs = convert_regions(start_regions, world, player) all_regions = set([r for r in world.regions if r.player == player and r.type is not RegionType.Dungeon]) visited_regions = set() @@ -3200,7 +3198,7 @@ def find_inaccessible_regions(world, player): while len(queue) > 0: next_region = queue.popleft() visited_regions.add(next_region) - if next_region.name == 'Inverted Dark Sanctuary': # special spawn point in cave + if next_region.name == 'Dark Sanctuary Hint': # special spawn point in cave for ent in next_region.entrances: parent = ent.parent_region if parent and parent.type is not RegionType.Dungeon and parent not in queue and parent not in visited_regions: @@ -3230,9 +3228,9 @@ def find_accessible_entrances(world, player, builder): hc_std = True start_regions = ['Hyrule Castle Courtyard'] elif world.mode[player] != 'inverted': - start_regions = ['Links House', 'Sanctuary'] + start_regions = ['Links House', 'Sanctuary', 'West Dark World'] else: - start_regions = ['Inverted Links House', 'Inverted Dark Sanctuary', 'Hyrule Castle Ledge'] + start_regions = ['Links House', 'Dark Sanctuary Hint', 'Hyrule Castle Ledge'] regs = convert_regions(start_regions, world, player) visited_regions = set() visited_entrances = [] diff --git a/EntranceShuffle.py b/EntranceShuffle.py index c2806835..c373ab78 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -718,12 +718,12 @@ def link_inverted_entrances(world, player): lw_entrances.append('Hyrule Castle Entrance (South)') if not world.shuffle_ganon: - connect_two_way(world, 'Inverted Ganons Tower', 'Inverted Ganons Tower Exit', player) + connect_two_way(world, 'Agahnims Tower', 'Ganons Tower Exit', player) hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)'] else: - lw_entrances.append('Inverted Ganons Tower') - dungeon_exits.append('Inverted Ganons Tower Exit') - hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)', 'Inverted Ganons Tower'] + lw_entrances.append('Agahnims Tower') + dungeon_exits.append('Ganons Tower Exit') + hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)', 'Agahnims Tower'] # shuffle aga door first. If it's on HC ledge, remaining HC ledge door must be must-exit all_entrances_aga = lw_entrances + dw_entrances @@ -745,8 +745,8 @@ def link_inverted_entrances(world, player): elif aga_door in dw_entrances: dw_entrances.remove(aga_door) - connect_two_way(world, aga_door, 'Inverted Agahnims Tower Exit', player) - dungeon_exits.remove('Inverted Agahnims Tower Exit') + connect_two_way(world, aga_door, 'Agahnims Tower Exit', player) + dungeon_exits.remove('Agahnims Tower Exit') connect_mandatory_exits(world, lw_entrances, dungeon_exits, lw_dungeon_entrances_must_exit, player) @@ -786,11 +786,11 @@ def link_inverted_entrances(world, player): # place links house if not world.shufflelinks[player]: - links_house = 'Inverted Links House' + links_house = 'Big Bomb Shop' else: links_house_doors = [i for i in DW_Single_Cave_Doors if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors] links_house = random.choice(links_house_doors) - connect_two_way(world, links_house, 'Inverted 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 match link's house if links_house in bomb_shop_doors: bomb_shop_doors.remove(links_house) @@ -804,8 +804,8 @@ def link_inverted_entrances(world, player): sanc_door = random.choice(sanc_doors) bomb_shop_doors.remove(sanc_door) - connect_entrance(world, sanc_door, 'Inverted Dark Sanctuary', player) - world.get_entrance('Inverted Dark Sanctuary Exit', player).connect(world.get_entrance(sanc_door, player).parent_region) + 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) 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)', @@ -843,7 +843,7 @@ def link_inverted_entrances(world, player): bomb_shop_doors = [door for door in bomb_shop_doors[:]] random.shuffle(bomb_shop_doors) bomb_shop = bomb_shop_doors.pop() - connect_entrance(world, bomb_shop, 'Inverted Big Bomb Shop', player) + connect_entrance(world, bomb_shop, 'Big Bomb Shop', player) single_doors.extend(bomb_shop_doors) # tavern back door cannot be shuffled yet @@ -867,11 +867,11 @@ def link_inverted_entrances(world, player): # place links house if not world.shufflelinks[player]: - links_house = 'Inverted Links House' + links_house = 'Big Bomb Shop' else: links_house_doors = [i for i in dw_entrances if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors] links_house = random.choice(links_house_doors) - connect_two_way(world, links_house, 'Inverted 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 match link's house if links_house in dw_entrances: dw_entrances.remove(links_house) @@ -880,8 +880,8 @@ def link_inverted_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, 'Inverted Dark Sanctuary', player) - world.get_entrance('Inverted Dark Sanctuary Exit', player).connect(world.get_entrance(sanc_door, player).parent_region) + 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) # tavern back door cannot be shuffled yet connect_doors(world, ['Tavern North'], ['Tavern'], player) @@ -916,7 +916,7 @@ def link_inverted_entrances(world, player): bomb_shop_doors = [door for door in bomb_shop_doors if door in all_entrances] random.shuffle(bomb_shop_doors) bomb_shop = bomb_shop_doors.pop() - connect_entrance(world, bomb_shop, 'Inverted Big Bomb Shop', player) + connect_entrance(world, bomb_shop, 'Big Bomb Shop', player) if bomb_shop in lw_entrances: lw_entrances.remove(bomb_shop) if bomb_shop in dw_entrances: @@ -942,7 +942,7 @@ def link_inverted_entrances(world, player): lw_entrances = list(Inverted_LW_Entrances + Inverted_LW_Dungeon_Entrances + Inverted_LW_Single_Cave_Doors) 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 + ['Inverted Agahnims 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) blacksmith_doors = list(Inverted_Blacksmith_Single_Cave_Doors + Inverted_Blacksmith_Multi_Cave_Doors) @@ -965,16 +965,16 @@ def link_inverted_entrances(world, player): if not world.shuffle_ganon: - connect_two_way(world, 'Inverted Ganons Tower', 'Inverted Ganons Tower Exit', player) + connect_two_way(world, 'Agahnims Tower', 'Ganons Tower Exit', player) hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)'] else: - lw_entrances.append('Inverted Ganons Tower') - caves.append('Inverted Ganons Tower Exit') - hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)', 'Inverted Ganons Tower'] + lw_entrances.append('Agahnims Tower') + caves.append('Ganons Tower Exit') + hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)', 'Agahnims Tower'] # shuffle aga door first. if it's on hc ledge, then one other hc ledge door has to be must_exit all_entrances_aga = lw_entrances + dw_entrances - aga_doors = [i for i in all_entrances_aga if world.shufflelinks[player] or i != 'Inverted Links House'] + aga_doors = [i for i in all_entrances_aga if world.shufflelinks[player] or i != 'Big Bomb Shop'] random.shuffle(aga_doors) aga_door = aga_doors.pop() @@ -992,16 +992,16 @@ def link_inverted_entrances(world, player): elif aga_door in dw_entrances: dw_entrances.remove(aga_door) - connect_two_way(world, aga_door, 'Inverted Agahnims Tower Exit', player) - caves.remove('Inverted Agahnims Tower Exit') + connect_two_way(world, aga_door, 'Agahnims Tower Exit', player) + caves.remove('Agahnims Tower Exit') # place links house if not world.shufflelinks[player]: - links_house = 'Inverted Links House' + links_house = 'Big Bomb Shop' else: links_house_doors = [i for i in dw_entrances if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors] links_house = random.choice(links_house_doors) - connect_two_way(world, links_house, 'Inverted 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 match link's house if links_house in dw_entrances: dw_entrances.remove(links_house) @@ -1010,8 +1010,8 @@ def link_inverted_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, 'Inverted Dark Sanctuary', player) - world.get_entrance('Inverted Dark Sanctuary Exit', player).connect(world.get_entrance(sanc_door, player).parent_region) + 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) # place old man house # no dw must exits in inverted, but we randomize whether cave is in light or dark world @@ -1060,7 +1060,7 @@ def link_inverted_entrances(world, player): bomb_shop_doors = [door for door in bomb_shop_doors if door in all_entrances] random.shuffle(bomb_shop_doors) bomb_shop = bomb_shop_doors.pop() - connect_entrance(world, bomb_shop, 'Inverted Big Bomb Shop', player) + connect_entrance(world, bomb_shop, 'Big Bomb Shop', player) if bomb_shop in lw_entrances: lw_entrances.remove(bomb_shop) if bomb_shop in dw_entrances: @@ -1092,7 +1092,7 @@ def link_inverted_entrances(world, player): entrances = list(Inverted_LW_Entrances + Inverted_LW_Dungeon_Entrances + Inverted_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 + ['Inverted Agahnims 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) blacksmith_doors = list(Inverted_Blacksmith_Single_Cave_Doors + Inverted_Blacksmith_Multi_Cave_Doors) @@ -1110,15 +1110,15 @@ def link_inverted_entrances(world, player): entrances.append('Hyrule Castle Entrance (South)') if not world.shuffle_ganon: - connect_two_way(world, 'Inverted Ganons Tower', 'Inverted Ganons Tower Exit', player) + connect_two_way(world, 'Agahnims Tower', 'Ganons Tower Exit', player) hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)'] else: - entrances.append('Inverted Ganons Tower') - caves.append('Inverted Ganons Tower Exit') - hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)', 'Inverted Ganons Tower'] + entrances.append('Agahnims Tower') + caves.append('Ganons Tower Exit') + hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)', 'Agahnims Tower'] # shuffle aga door. if it's on hc ledge, then one other hc ledge door has to be must_exit - aga_choices = [x for x in entrances if world.shufflelinks[player] or x != 'Inverted Links House'] + aga_choices = [x for x in entrances if world.shufflelinks[player] or x != 'Big Bomb Shop'] aga_door = random.choice(aga_choices) if aga_door in hc_ledge_entrances: @@ -1130,16 +1130,16 @@ def link_inverted_entrances(world, player): must_exits.append(hc_ledge_must_exit) entrances.remove(aga_door) - connect_two_way(world, aga_door, 'Inverted Agahnims Tower Exit', player) - caves.remove('Inverted Agahnims Tower Exit') + connect_two_way(world, aga_door, 'Agahnims Tower Exit', player) + caves.remove('Agahnims Tower Exit') # place links house if not world.shufflelinks[player]: - links_house = 'Inverted Links House' + links_house = 'Big Bomb Shop' else: links_house_doors = [i for i in entrances + must_exits if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors] links_house = random.choice(links_house_doors) - connect_two_way(world, links_house, 'Inverted 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 match link's house if links_house in entrances: entrances.remove(links_house) @@ -1150,8 +1150,8 @@ def link_inverted_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, 'Inverted Dark Sanctuary', player) - world.get_entrance('Inverted Dark Sanctuary Exit', player).connect(world.get_entrance(sanc_door, player).parent_region) + 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) # tavern back door cannot be shuffled yet connect_doors(world, ['Tavern North'], ['Tavern'], player) @@ -1183,7 +1183,7 @@ def link_inverted_entrances(world, player): bomb_shop_doors = [door for door in bomb_shop_doors if door in entrances] random.shuffle(bomb_shop_doors) bomb_shop = bomb_shop_doors.pop() - connect_entrance(world, bomb_shop, 'Inverted Big Bomb Shop', player) + connect_entrance(world, bomb_shop, 'Big Bomb Shop', player) entrances.remove(bomb_shop) # place the old man cave's entrance somewhere @@ -1225,7 +1225,7 @@ def link_inverted_entrances(world, player): random.shuffle(doors) - old_man_entrances = list(Inverted_Old_Man_Entrances + Old_Man_Entrances) + ['Tower of Hera', 'Inverted Agahnims Tower'] + old_man_entrances = list(Inverted_Old_Man_Entrances + Old_Man_Entrances) + ['Tower of Hera', 'Ganons Tower'] caves = Cave_Exits + Dungeon_Exits + Cave_Three_Exits + ['Old Man House Exit (Bottom)', 'Old Man House Exit (Top)', 'Skull Woods First Section Exit', 'Skull Woods Second Section Exit (East)', 'Skull Woods Second Section Exit (West)', 'Kakariko Well Exit', 'Bat Cave Exit', 'North Fairy Cave Exit', 'Lost Woods Hideout Exit', 'Lumberjack Tree Exit', 'Sanctuary Exit'] @@ -1246,15 +1246,15 @@ def link_inverted_entrances(world, player): caves.append('Hyrule Castle Secret Entrance Exit') if not world.shuffle_ganon: - connect_two_way(world, 'Inverted Ganons Tower', 'Inverted Ganons Tower Exit', player) + connect_two_way(world, 'Agahnims Tower', 'Ganons Tower Exit', player) connect_two_way(world, 'Inverted Pyramid Entrance', 'Pyramid Exit', player) connect_entrance(world, 'Inverted Pyramid Hole', 'Pyramid', player) else: - caves.extend(['Inverted Ganons Tower Exit', 'Pyramid Exit']) + caves.extend(['Ganons Tower Exit', 'Pyramid Exit']) hole_entrances.append('Inverted Pyramid Hole') hole_targets.append('Pyramid') - doors.extend(['Inverted Ganons Tower', 'Inverted Pyramid Entrance']) - exit_pool.extend(['Inverted Ganons Tower', 'Inverted Pyramid Entrance']) + doors.extend(['Agahnims Tower', 'Inverted Pyramid Entrance']) + exit_pool.extend(['Agahnims Tower', 'Inverted Pyramid Entrance']) random.shuffle(hole_entrances) random.shuffle(hole_targets) @@ -1269,11 +1269,11 @@ def link_inverted_entrances(world, player): # place links house and dark sanc if not world.shufflelinks[player]: - links_house = 'Inverted Links House' + links_house = 'Big Bomb Shop' else: links_house_doors = [i for i in doors if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors] links_house = random.choice(links_house_doors) - connect_two_way(world, links_house, 'Inverted 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 match link's house doors.remove(links_house) exit_pool.remove(links_house) @@ -1282,8 +1282,8 @@ def link_inverted_entrances(world, player): sanc_door = random.choice(sanc_doors) exit_pool.remove(sanc_door) doors.remove(sanc_door) - connect_entrance(world, sanc_door, 'Inverted Dark Sanctuary', player) - world.get_entrance('Inverted Dark Sanctuary Exit', player).connect(world.get_entrance(sanc_door, player).parent_region) + 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) # now let's deal with mandatory reachable stuff def extract_reachable_exit(cavelist): @@ -1339,7 +1339,7 @@ def link_inverted_entrances(world, player): bomb_shop_doors = [door for door in bomb_shop_doors if door in doors] random.shuffle(bomb_shop_doors) bomb_shop = bomb_shop_doors.pop() - connect_entrance(world, bomb_shop, 'Inverted Big Bomb Shop', player) + connect_entrance(world, bomb_shop, 'Big Bomb Shop', player) doors.remove(bomb_shop) # handle remaining caves @@ -1369,7 +1369,7 @@ def link_inverted_entrances(world, player): world.ganon_at_pyramid[player] = False # check for Ganon's Tower location - if world.get_entrance('Inverted Ganons Tower', player).connected_region.name != 'GT Lobby': + if world.get_entrance('Agahnims Tower', player).connected_region.name != 'GT Lobby': world.ganonstower_vanilla[player] = False @@ -1556,7 +1556,7 @@ def connect_mandatory_exits(world, entrances, caves, must_be_exits, player): for entrance in invalid_connections: if world.get_entrance(entrance, player).connected_region == world.get_region('Agahnims Tower Portal', player): for exit in invalid_connections[entrance]: - invalid_connections[exit] = invalid_connections[exit].union({'Inverted Ganons Tower', 'Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)'}) + invalid_connections[exit] = invalid_connections[exit].union({'Agahnims Tower', 'Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)'}) break used_caves = [] @@ -1671,28 +1671,25 @@ def simple_shuffle_dungeons(world, player): dungeon_entrances = ['Eastern Palace', 'Tower of Hera', 'Thieves Town', 'Skull Woods Final Section', 'Palace of Darkness', 'Ice Palace', 'Misery Mire', 'Swamp Palace'] dungeon_exits = ['Eastern Palace Exit', 'Tower of Hera Exit', 'Thieves Town Exit', 'Skull Woods Final Section Exit', 'Palace of Darkness Exit', 'Ice Palace Exit', 'Misery Mire Exit', 'Swamp Palace Exit'] - if world.mode[player] != 'inverted': - if not world.shuffle_ganon: - connect_two_way(world, 'Ganons Tower', 'Ganons Tower Exit', player) - else: - dungeon_entrances.append('Ganons Tower') - dungeon_exits.append('Ganons Tower Exit') + # TODO: Consider letting inverted shuffle GT + if not world.is_atgt_swapped(player) and not world.shuffle_ganon: + connect_two_way(world, 'Ganons Tower', 'Ganons Tower Exit', player) else: - dungeon_entrances.append('Inverted Agahnims Tower') - dungeon_exits.append('Inverted Agahnims Tower Exit') + dungeon_entrances.append('Ganons Tower') + dungeon_exits.append('Ganons Tower Exit') # shuffle up single entrance dungeons connect_random(world, dungeon_entrances, dungeon_exits, player, True) # mix up 4 door dungeons multi_dungeons = ['Desert', 'Turtle Rock'] - if world.mode[player] == 'open' or (world.mode[player] == 'inverted' and world.shuffle_ganon): + if world.mode[player] == 'open' or (world.is_atgt_swapped(player) and world.shuffle_ganon): multi_dungeons.append('Hyrule Castle') random.shuffle(multi_dungeons) dp_target = multi_dungeons[0] tr_target = multi_dungeons[1] - if world.mode[player] not in ['open', 'inverted'] or (world.mode[player] == 'inverted' and world.shuffle_ganon is False): + if world.mode[player] not in ['open', 'inverted'] or (world.is_atgt_swapped(player) and world.shuffle_ganon is False): # place hyrule castle as intended hc_target = 'Hyrule Castle' else: @@ -1707,103 +1704,53 @@ def simple_shuffle_dungeons(world, player): hc_target, tr_target = tr_target, hc_target # ToDo improve this? + if hc_target == 'Hyrule Castle': + connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player) + connect_two_way(world, 'Hyrule Castle Entrance (East)', 'Hyrule Castle Exit (East)', player) + connect_two_way(world, 'Hyrule Castle Entrance (West)', 'Hyrule Castle Exit (West)', player) + connect_two_way(world, 'Agahnims Tower', 'Agahnims Tower Exit', player) + elif hc_target == 'Desert': + connect_two_way(world, 'Desert Palace Entrance (South)', 'Hyrule Castle Exit (South)', player) + connect_two_way(world, 'Desert Palace Entrance (East)', 'Hyrule Castle Exit (East)', player) + connect_two_way(world, 'Desert Palace Entrance (West)', 'Hyrule Castle Exit (West)', player) + connect_two_way(world, 'Desert Palace Entrance (North)', 'Agahnims Tower Exit', player) + elif hc_target == 'Turtle Rock': + connect_two_way(world, 'Turtle Rock', 'Hyrule Castle Exit (South)', player) + connect_two_way(world, 'Turtle Rock Isolated Ledge Entrance', 'Hyrule Castle Exit (East)', player) + connect_two_way(world, 'Dark Death Mountain Ledge (West)', 'Hyrule Castle Exit (West)', player) + connect_two_way(world, 'Dark Death Mountain Ledge (East)', 'Agahnims Tower Exit', player) - if world.mode[player] != 'inverted': - if hc_target == 'Hyrule Castle': - connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player) - connect_two_way(world, 'Hyrule Castle Entrance (East)', 'Hyrule Castle Exit (East)', player) - connect_two_way(world, 'Hyrule Castle Entrance (West)', 'Hyrule Castle Exit (West)', player) - connect_two_way(world, 'Agahnims Tower', 'Agahnims Tower Exit', player) - elif hc_target == 'Desert': - connect_two_way(world, 'Desert Palace Entrance (South)', 'Hyrule Castle Exit (South)', player) - connect_two_way(world, 'Desert Palace Entrance (East)', 'Hyrule Castle Exit (East)', player) - connect_two_way(world, 'Desert Palace Entrance (West)', 'Hyrule Castle Exit (West)', player) - connect_two_way(world, 'Desert Palace Entrance (North)', 'Agahnims Tower Exit', player) - elif hc_target == 'Turtle Rock': - connect_two_way(world, 'Turtle Rock', 'Hyrule Castle Exit (South)', player) - connect_two_way(world, 'Turtle Rock Isolated Ledge Entrance', 'Hyrule Castle Exit (East)', player) - connect_two_way(world, 'Dark Death Mountain Ledge (West)', 'Hyrule Castle Exit (West)', player) - connect_two_way(world, 'Dark Death Mountain Ledge (East)', 'Agahnims Tower Exit', player) + if dp_target == 'Hyrule Castle': + connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Desert Palace Exit (South)', player) + connect_two_way(world, 'Hyrule Castle Entrance (East)', 'Desert Palace Exit (East)', player) + connect_two_way(world, 'Hyrule Castle Entrance (West)', 'Desert Palace Exit (West)', player) + connect_two_way(world, 'Agahnims Tower', 'Desert Palace Exit (North)', player) + elif dp_target == 'Desert': + connect_two_way(world, 'Desert Palace Entrance (South)', 'Desert Palace Exit (South)', player) + connect_two_way(world, 'Desert Palace Entrance (East)', 'Desert Palace Exit (East)', player) + connect_two_way(world, 'Desert Palace Entrance (West)', 'Desert Palace Exit (West)', player) + connect_two_way(world, 'Desert Palace Entrance (North)', 'Desert Palace Exit (North)', player) + elif dp_target == 'Turtle Rock': + connect_two_way(world, 'Turtle Rock', 'Desert Palace Exit (South)', player) + connect_two_way(world, 'Turtle Rock Isolated Ledge Entrance', 'Desert Palace Exit (East)', player) + connect_two_way(world, 'Dark Death Mountain Ledge (West)', 'Desert Palace Exit (West)', player) + connect_two_way(world, 'Dark Death Mountain Ledge (East)', 'Desert Palace Exit (North)', player) - if dp_target == 'Hyrule Castle': - connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Desert Palace Exit (South)', player) - connect_two_way(world, 'Hyrule Castle Entrance (East)', 'Desert Palace Exit (East)', player) - connect_two_way(world, 'Hyrule Castle Entrance (West)', 'Desert Palace Exit (West)', player) - connect_two_way(world, 'Agahnims Tower', 'Desert Palace Exit (North)', player) - elif dp_target == 'Desert': - connect_two_way(world, 'Desert Palace Entrance (South)', 'Desert Palace Exit (South)', player) - connect_two_way(world, 'Desert Palace Entrance (East)', 'Desert Palace Exit (East)', player) - connect_two_way(world, 'Desert Palace Entrance (West)', 'Desert Palace Exit (West)', player) - connect_two_way(world, 'Desert Palace Entrance (North)', 'Desert Palace Exit (North)', player) - elif dp_target == 'Turtle Rock': - connect_two_way(world, 'Turtle Rock', 'Desert Palace Exit (South)', player) - connect_two_way(world, 'Turtle Rock Isolated Ledge Entrance', 'Desert Palace Exit (East)', player) - connect_two_way(world, 'Dark Death Mountain Ledge (West)', 'Desert Palace Exit (West)', player) - connect_two_way(world, 'Dark Death Mountain Ledge (East)', 'Desert Palace Exit (North)', player) - - if tr_target == 'Hyrule Castle': - connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Turtle Rock Exit (Front)', player) - connect_two_way(world, 'Hyrule Castle Entrance (East)', 'Turtle Rock Ledge Exit (East)', player) - connect_two_way(world, 'Hyrule Castle Entrance (West)', 'Turtle Rock Ledge Exit (West)', player) - connect_two_way(world, 'Agahnims Tower', 'Turtle Rock Isolated Ledge Exit', player) - elif tr_target == 'Desert': - connect_two_way(world, 'Desert Palace Entrance (South)', 'Turtle Rock Exit (Front)', player) - connect_two_way(world, 'Desert Palace Entrance (North)', 'Turtle Rock Ledge Exit (East)', player) - connect_two_way(world, 'Desert Palace Entrance (West)', 'Turtle Rock Ledge Exit (West)', player) - connect_two_way(world, 'Desert Palace Entrance (East)', 'Turtle Rock Isolated Ledge Exit', player) - elif tr_target == 'Turtle Rock': - connect_two_way(world, 'Turtle Rock', 'Turtle Rock Exit (Front)', player) - connect_two_way(world, 'Turtle Rock Isolated Ledge Entrance', 'Turtle Rock Isolated Ledge Exit', player) - connect_two_way(world, 'Dark Death Mountain Ledge (West)', 'Turtle Rock Ledge Exit (West)', player) - connect_two_way(world, 'Dark Death Mountain Ledge (East)', 'Turtle Rock Ledge Exit (East)', player) - else: - if hc_target == 'Hyrule Castle': - connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Hyrule Castle Exit (South)', player) - connect_two_way(world, 'Hyrule Castle Entrance (East)', 'Hyrule Castle Exit (East)', player) - connect_two_way(world, 'Hyrule Castle Entrance (West)', 'Hyrule Castle Exit (West)', player) - connect_two_way(world, 'Inverted Ganons Tower', 'Inverted Ganons Tower Exit', player) - elif hc_target == 'Desert': - connect_two_way(world, 'Desert Palace Entrance (South)', 'Hyrule Castle Exit (South)', player) - connect_two_way(world, 'Desert Palace Entrance (East)', 'Hyrule Castle Exit (East)', player) - connect_two_way(world, 'Desert Palace Entrance (West)', 'Hyrule Castle Exit (West)', player) - connect_two_way(world, 'Desert Palace Entrance (North)', 'Inverted Ganons Tower Exit', player) - elif hc_target == 'Turtle Rock': - connect_two_way(world, 'Turtle Rock', 'Hyrule Castle Exit (South)', player) - connect_two_way(world, 'Turtle Rock Isolated Ledge Entrance', 'Inverted Ganons Tower Exit', player) - connect_two_way(world, 'Dark Death Mountain Ledge (West)', 'Hyrule Castle Exit (West)', player) - connect_two_way(world, 'Dark Death Mountain Ledge (East)', 'Hyrule Castle Exit (East)', player) - - if dp_target == 'Hyrule Castle': - connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Desert Palace Exit (South)', player) - connect_two_way(world, 'Hyrule Castle Entrance (East)', 'Desert Palace Exit (East)', player) - connect_two_way(world, 'Hyrule Castle Entrance (West)', 'Desert Palace Exit (West)', player) - connect_two_way(world, 'Inverted Ganons Tower', 'Desert Palace Exit (North)', player) - elif dp_target == 'Desert': - connect_two_way(world, 'Desert Palace Entrance (South)', 'Desert Palace Exit (South)', player) - connect_two_way(world, 'Desert Palace Entrance (East)', 'Desert Palace Exit (East)', player) - connect_two_way(world, 'Desert Palace Entrance (West)', 'Desert Palace Exit (West)', player) - connect_two_way(world, 'Desert Palace Entrance (North)', 'Desert Palace Exit (North)', player) - elif dp_target == 'Turtle Rock': - connect_two_way(world, 'Turtle Rock', 'Desert Palace Exit (South)', player) - connect_two_way(world, 'Turtle Rock Isolated Ledge Entrance', 'Desert Palace Exit (East)', player) - connect_two_way(world, 'Dark Death Mountain Ledge (West)', 'Desert Palace Exit (West)', player) - connect_two_way(world, 'Dark Death Mountain Ledge (East)', 'Desert Palace Exit (North)', player) - - if tr_target == 'Hyrule Castle': - connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Turtle Rock Exit (Front)', player) - connect_two_way(world, 'Hyrule Castle Entrance (East)', 'Turtle Rock Ledge Exit (East)', player) - connect_two_way(world, 'Hyrule Castle Entrance (West)', 'Turtle Rock Ledge Exit (West)', player) - connect_two_way(world, 'Inverted Ganons Tower', 'Turtle Rock Isolated Ledge Exit', player) - elif tr_target == 'Desert': - connect_two_way(world, 'Desert Palace Entrance (South)', 'Turtle Rock Exit (Front)', player) - connect_two_way(world, 'Desert Palace Entrance (North)', 'Turtle Rock Ledge Exit (East)', player) - connect_two_way(world, 'Desert Palace Entrance (West)', 'Turtle Rock Ledge Exit (West)', player) - connect_two_way(world, 'Desert Palace Entrance (East)', 'Turtle Rock Isolated Ledge Exit', player) - elif tr_target == 'Turtle Rock': - connect_two_way(world, 'Turtle Rock', 'Turtle Rock Exit (Front)', player) - connect_two_way(world, 'Turtle Rock Isolated Ledge Entrance', 'Turtle Rock Isolated Ledge Exit', player) - connect_two_way(world, 'Dark Death Mountain Ledge (West)', 'Turtle Rock Ledge Exit (West)', player) - connect_two_way(world, 'Dark Death Mountain Ledge (East)', 'Turtle Rock Ledge Exit (East)', player) + if tr_target == 'Hyrule Castle': + connect_two_way(world, 'Hyrule Castle Entrance (South)', 'Turtle Rock Exit (Front)', player) + connect_two_way(world, 'Hyrule Castle Entrance (East)', 'Turtle Rock Ledge Exit (East)', player) + connect_two_way(world, 'Hyrule Castle Entrance (West)', 'Turtle Rock Ledge Exit (West)', player) + connect_two_way(world, 'Agahnims Tower', 'Turtle Rock Isolated Ledge Exit', player) + elif tr_target == 'Desert': + connect_two_way(world, 'Desert Palace Entrance (South)', 'Turtle Rock Exit (Front)', player) + connect_two_way(world, 'Desert Palace Entrance (North)', 'Turtle Rock Ledge Exit (East)', player) + connect_two_way(world, 'Desert Palace Entrance (West)', 'Turtle Rock Ledge Exit (West)', player) + connect_two_way(world, 'Desert Palace Entrance (East)', 'Turtle Rock Isolated Ledge Exit', player) + elif tr_target == 'Turtle Rock': + connect_two_way(world, 'Turtle Rock', 'Turtle Rock Exit (Front)', player) + connect_two_way(world, 'Turtle Rock Isolated Ledge Entrance', 'Turtle Rock Isolated Ledge Exit', player) + connect_two_way(world, 'Dark Death Mountain Ledge (West)', 'Turtle Rock Ledge Exit (West)', player) + connect_two_way(world, 'Dark Death Mountain Ledge (East)', 'Turtle Rock Ledge Exit (East)', player) def unbias_some_entrances(Dungeon_Exits, Cave_Exits, Old_Man_House, Cave_Three_Exits): def shuffle_lists_in_list(ls): @@ -2230,7 +2177,7 @@ Inverted_DW_Dungeon_Entrances = ['Thieves Town', 'Dark Death Mountain Ledge (West)', 'Dark Death Mountain Ledge (East)', 'Turtle Rock Isolated Ledge Entrance', - 'Inverted Agahnims Tower'] + 'Ganons Tower'] Inverted_LW_Dungeon_Entrances_Must_Exit = ['Desert Palace Entrance (East)'] @@ -2244,7 +2191,7 @@ Inverted_Dungeon_Exits_Base = [['Desert Palace Exit (South)', 'Desert Palace Exi 'Misery Mire Exit', 'Palace of Darkness Exit', 'Swamp Palace Exit', - 'Inverted Agahnims Tower Exit', + 'Agahnims Tower Exit', ['Turtle Rock Ledge Exit (East)', 'Turtle Rock Exit (Front)', 'Turtle Rock Ledge Exit (West)', 'Turtle Rock Isolated Ledge Exit']] @@ -2307,7 +2254,7 @@ Inverted_Bomb_Shop_Multi_Cave_Doors = ['Hyrule Castle Entrance (South)', 'Superbunny Cave (Top)', 'Superbunny Cave (Bottom)', 'Hookshot Cave', - 'Inverted Agahnims Tower', + 'Ganons Tower', 'Desert Palace Entrance (South)', 'Tower of Hera', 'Two Brothers House (West)', @@ -2327,17 +2274,17 @@ Inverted_Bomb_Shop_Multi_Cave_Doors = ['Hyrule Castle Entrance (South)', 'Palace of Darkness', 'Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)', - 'Inverted Ganons Tower', + 'Agahnims Tower', 'Desert Palace Entrance (West)', 'Desert Palace Entrance (North)'] Inverted_Blacksmith_Multi_Cave_Doors = Blacksmith_Multi_Cave_Doors # same as non-inverted -Inverted_LW_Single_Cave_Doors = [x for x in LW_Single_Cave_Doors if x != 'Links House'] + ['Inverted Big Bomb Shop'] +Inverted_LW_Single_Cave_Doors = [x for x in LW_Single_Cave_Doors] Inverted_DW_Single_Cave_Doors = ['Bonk Fairy (Dark)', - 'Inverted Dark Sanctuary', - 'Inverted Links House', + 'Dark Sanctuary Hint', + 'Big Bomb Shop', 'Dark Lake Hylia Fairy', 'C-Shaped House', 'Bumper Cave (Top)', @@ -2386,7 +2333,7 @@ Inverted_Bomb_Shop_Single_Cave_Doors = ['Waterfall of Wishing', 'Chest Game', 'Dark World Hammer Peg Cave', 'Red Shield Shop', - 'Inverted Dark Sanctuary', + 'Dark Sanctuary Hint', 'Fortune Teller (Dark)', 'Dark World Shop', 'Dark World Lumberjack Shop', @@ -2400,8 +2347,8 @@ Inverted_Bomb_Shop_Single_Cave_Doors = ['Waterfall of Wishing', 'Bumper Cave (Top)', 'Mimic Cave', 'Dark Lake Hylia Shop', - 'Inverted Links House', - 'Inverted Big Bomb Shop'] + 'Big Bomb Shop', + 'Links House'] Inverted_Blacksmith_Single_Cave_Doors = ['Blinds Hideout', 'Lake Hylia Fairy', @@ -2433,7 +2380,7 @@ Inverted_Blacksmith_Single_Cave_Doors = ['Blinds Hideout', 'Lumberjack House', 'Lake Hylia Fortune Teller', 'Kakariko Gamble Game', - 'Inverted Big Bomb Shop'] + 'Links House'] Inverted_Single_Cave_Targets = ['Blinds Hideout', 'Bonk Fairy (Light)', @@ -2502,7 +2449,7 @@ Inverted_Single_Cave_Targets = ['Blinds Hideout', 'Dam'] # in inverted we put dark sanctuary in west dark world for now -Inverted_Dark_Sanctuary_Doors = ['Inverted Dark Sanctuary', +Inverted_Dark_Sanctuary_Doors = ['Dark Sanctuary Hint', 'Fortune Teller (Dark)', 'Brewery', 'C-Shaped House', @@ -2538,9 +2485,9 @@ Inverted_Must_Exit_Invalid_Connections = defaultdict(set, { 'Death Mountain Return Cave (West)': {'Bumper Cave (Top)'}, 'Desert Palace Entrance (North)': {'Desert Palace Entrance (West)'}, 'Desert Palace Entrance (West)': {'Desert Palace Entrance (North)'}, - 'Inverted Ganons Tower': {'Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)'}, - 'Hyrule Castle Entrance (West)': {'Hyrule Castle Entrance (East)', 'Inverted Ganons Tower'}, - 'Hyrule Castle Entrance (East)': {'Hyrule Castle Entrance (West)', 'Inverted Ganons Tower'}, + 'Agahnims Tower': {'Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)'}, + 'Hyrule Castle Entrance (West)': {'Hyrule Castle Entrance (East)', 'Agahnims Tower'}, + 'Hyrule Castle Entrance (East)': {'Hyrule Castle Entrance (West)', 'Agahnims Tower'}, }) @@ -2549,6 +2496,7 @@ Inverted_Must_Exit_Invalid_Connections = defaultdict(set, { mandatory_connections = [('Links House S&Q', 'Links House'), ('Sanctuary S&Q', 'Sanctuary'), ('Old Man S&Q', 'Old Man House'), + ('Other World S&Q', 'East Dark World'), ('Lake Hylia Central Island Pier', 'Lake Hylia Central Island'), ('Lake Hylia Central Island Teleporter', 'Dark Lake Hylia Central Island'), ('Zoras River', 'Zoras River'), @@ -2685,10 +2633,10 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Hyrule Castle Ledge Drop', 'Light World'), ] -inverted_mandatory_connections = [('Links House S&Q', 'Inverted Links House'), - ('Dark Sanctuary S&Q', 'Inverted Dark Sanctuary'), +inverted_mandatory_connections = [('Links House S&Q', 'Links House'), + ('Sanctuary S&Q', 'Dark Sanctuary Hint'), ('Old Man S&Q', 'Old Man House'), - ('Castle Ledge S&Q', 'Hyrule Castle Ledge'), + ('Other World S&Q', 'Hyrule Castle Ledge'), ('Lake Hylia Central Island Pier', 'Lake Hylia Central Island'), ('Lake Hylia Island Pier', 'Lake Hylia Island'), ('Lake Hylia Warp', 'Northeast Light World'), @@ -3139,11 +3087,11 @@ inverted_default_connections = [('Waterfall of Wishing', 'Waterfall of Wishing' ('Hookshot Cave Back Entrance', 'Hookshot Cave (Back)'), ('Mimic Cave', 'Mimic Cave'), ('Inverted Pyramid Hole', 'Pyramid'), - ('Inverted Links House', 'Inverted Links House'), - ('Inverted Links House Exit', 'South Dark World'), - ('Inverted Big Bomb Shop', 'Inverted Big Bomb Shop'), - ('Inverted Dark Sanctuary', 'Inverted Dark Sanctuary'), - ('Inverted Dark Sanctuary Exit', 'West Dark World'), + ('Links House', 'Big Bomb Shop'), + ('Links House Exit', 'South Dark World'), + ('Big Bomb Shop', 'Links House'), + ('Dark Sanctuary Hint', 'Dark Sanctuary Hint'), + ('Dark Sanctuary Hint Exit', 'West Dark World'), ('Old Man Cave (West)', 'Bumper Cave (bottom)'), ('Old Man Cave (East)', 'Death Mountain Return Cave (left)'), ('Old Man Cave Exit (West)', 'West Dark World'), @@ -3268,10 +3216,10 @@ inverted_default_dungeon_connections = [('Desert Palace Entrance (South)', 'Dese ('Dark Death Mountain Ledge (East)', 'Turtle Rock Chest Portal'), ('Turtle Rock Isolated Ledge Exit', 'Dark Death Mountain Isolated Ledge'), ('Turtle Rock Isolated Ledge Entrance', 'Turtle Rock Eye Bridge Portal'), - ('Inverted Ganons Tower', 'Ganons Tower Portal'), - ('Inverted Ganons Tower Exit', 'Hyrule Castle Ledge'), - ('Inverted Agahnims Tower', 'Agahnims Tower Portal'), - ('Inverted Agahnims Tower Exit', 'Dark Death Mountain'), + ('Agahnims Tower', 'Ganons Tower Portal'), + ('Ganons Tower Exit', 'Hyrule Castle Ledge'), + ('Ganons Tower', 'Agahnims Tower Portal'), + ('Agahnims Tower Exit', 'Dark Death Mountain'), ('Turtle Rock Exit (Front)', 'Dark Death Mountain'), ('Ice Palace Exit', 'Dark Lake Hylia') ] @@ -3294,7 +3242,6 @@ indirect_connections = { # ToDo somehow merge this with creation of the locations door_addresses = {'Links House': (0x00, (0x0104, 0x2c, 0x0506, 0x0a9a, 0x0832, 0x0ae8, 0x08b8, 0x0b07, 0x08bf, 0x06, 0xfe, 0x0816, 0x0000)), - 'Inverted Big Bomb Shop': (0x00, (0x0104, 0x2c, 0x0506, 0x0a9a, 0x0832, 0x0ae8, 0x08b8, 0x0b07, 0x08bf, 0x06, 0xfe, 0x0816, 0x0000)), 'Desert Palace Entrance (South)': (0x08, (0x0084, 0x30, 0x0314, 0x0c56, 0x00a6, 0x0ca8, 0x0128, 0x0cc3, 0x0133, 0x0a, 0xfa, 0x0000, 0x0000)), 'Desert Palace Entrance (West)': (0x0A, (0x0083, 0x30, 0x0280, 0x0c46, 0x0003, 0x0c98, 0x0088, 0x0cb3, 0x0090, 0x0a, 0xfd, 0x0000, 0x0000)), 'Desert Palace Entrance (North)': (0x0B, (0x0063, 0x30, 0x0016, 0x0c00, 0x00a2, 0x0c28, 0x0128, 0x0c6d, 0x012f, 0x00, 0x0e, 0x0000, 0x0000)), @@ -3306,7 +3253,6 @@ door_addresses = {'Links House': (0x00, (0x0104, 0x2c, 0x0506, 0x0a9a, 0x0832, 0 'Hyrule Castle Entrance (East)': (0x04, (0x0062, 0x1b, 0x004a, 0x0600, 0x0856, 0x0604, 0x08c8, 0x066d, 0x08d3, 0x00, 0xfa, 0x0000, 0x8158)), 'Inverted Pyramid Entrance': (0x35, (0x0010, 0x1b, 0x0418, 0x0679, 0x06b4, 0x06c6, 0x0728, 0x06e6, 0x0733, 0x07, 0xf9, 0x0000, 0x0000)), 'Agahnims Tower': (0x23, (0x00e0, 0x1b, 0x0032, 0x0600, 0x0784, 0x0634, 0x07f8, 0x066d, 0x0803, 0x00, 0x0a, 0x0000, 0x82be)), - 'Inverted Ganons Tower': (0x23, (0x00e0, 0x1b, 0x0032, 0x0600, 0x0784, 0x0634, 0x07f8, 0x066d, 0x0803, 0x00, 0x0a, 0x0000, 0x82be)), 'Thieves Town': (0x33, (0x00db, 0x58, 0x0b2e, 0x075a, 0x0176, 0x07a8, 0x01f8, 0x07c7, 0x0203, 0x06, 0xfa, 0x0000, 0x0000)), 'Skull Woods First Section Door': (0x29, (0x0058, 0x40, 0x0f4c, 0x01f6, 0x0262, 0x0248, 0x02e8, 0x0263, 0x02ef, 0x0a, 0xfe, 0x0000, 0x0000)), 'Skull Woods Second Section Door (East)': (0x28, (0x0057, 0x40, 0x0eb8, 0x01e6, 0x01c2, 0x0238, 0x0248, 0x0253, 0x024f, 0x0a, 0xfe, 0x0000, 0x0000)), @@ -3354,7 +3300,6 @@ door_addresses = {'Links House': (0x00, (0x0104, 0x2c, 0x0506, 0x0a9a, 0x0832, 0 'Hookshot Cave': (0x39, (0x003c, 0x45, 0x04da, 0x00a3, 0x0cd6, 0x0107, 0x0d48, 0x0112, 0x0d53, 0x0b, 0xfa, 0x0000, 0x0000)), 'Hookshot Cave Back Entrance': (0x3A, (0x002c, 0x45, 0x004c, 0x0000, 0x0c56, 0x0038, 0x0cc8, 0x006f, 0x0cd3, 0x00, 0x0a, 0x0000, 0x0000)), 'Ganons Tower': (0x36, (0x000c, 0x43, 0x0052, 0x0000, 0x0884, 0x0028, 0x08f8, 0x006f, 0x0903, 0x00, 0xfc, 0x0000, 0x0000)), - 'Inverted Agahnims Tower': (0x36, (0x000c, 0x43, 0x0052, 0x0000, 0x0884, 0x0028, 0x08f8, 0x006f, 0x0903, 0x00, 0xfc, 0x0000, 0x0000)), 'Pyramid Entrance': (0x35, (0x0010, 0x5b, 0x0b0e, 0x075a, 0x0674, 0x07a8, 0x06e8, 0x07c7, 0x06f3, 0x06, 0xfa, 0x0000, 0x0000)), 'Skull Woods First Section Hole (West)': ([0xDB84D, 0xDB84E], None), 'Skull Woods First Section Hole (East)': ([0xDB84F, 0xDB850], None), @@ -3421,7 +3366,6 @@ door_addresses = {'Links House': (0x00, (0x0104, 0x2c, 0x0506, 0x0a9a, 0x0832, 0 'Dark World Hammer Peg Cave': (0x7E, (0x0127, 0x62, 0x0894, 0x091e, 0x0492, 0x09a6, 0x0508, 0x098b, 0x050f, 0x00, 0x00, 0x0000, 0x0000)), 'Red Shield Shop': (0x74, (0x0110, 0x5a, 0x079a, 0x06e8, 0x04d6, 0x0738, 0x0548, 0x0755, 0x0553, 0x08, 0xf8, 0x0AA8, 0x0000)), 'Dark Sanctuary Hint': (0x59, (0x0112, 0x53, 0x001e, 0x0400, 0x06e2, 0x0446, 0x0758, 0x046d, 0x075f, 0x00, 0x00, 0x0000, 0x0000)), - 'Inverted Dark Sanctuary': (0x59, (0x0112, 0x53, 0x001e, 0x0400, 0x06e2, 0x0446, 0x0758, 0x046d, 0x075f, 0x00, 0x00, 0x0000, 0x0000)), 'Fortune Teller (Dark)': (0x65, (0x0122, 0x51, 0x0610, 0x04b4, 0x027e, 0x0507, 0x02f8, 0x0523, 0x0303, 0x0a, 0xf6, 0x091E, 0x0000)), 'Dark World Shop': (0x5F, (0x010f, 0x58, 0x1058, 0x0814, 0x02be, 0x0868, 0x0338, 0x0883, 0x0343, 0x0a, 0xf6, 0x0000, 0x0000)), 'Dark World Lumberjack Shop': (0x56, (0x010f, 0x42, 0x041c, 0x0074, 0x04e2, 0x00c7, 0x0558, 0x00e3, 0x055f, 0x0a, 0xf6, 0x0000, 0x0000)), @@ -3435,7 +3379,6 @@ door_addresses = {'Links House': (0x00, (0x0104, 0x2c, 0x0506, 0x0a9a, 0x0832, 0 'Dark Death Mountain Fairy': (0x6F, (0x0115, 0x43, 0x1400, 0x0294, 0x0600, 0x02e8, 0x0678, 0x0303, 0x0685, 0x0a, 0xf6, 0x0000, 0x0000)), 'Mimic Cave': (0x4E, (0x010c, 0x05, 0x07e0, 0x0103, 0x0d00, 0x0156, 0x0d78, 0x0172, 0x0d7d, 0x0b, 0xf5, 0x0000, 0x0000)), 'Big Bomb Shop': (0x52, (0x011c, 0x6c, 0x0506, 0x0a9a, 0x0832, 0x0ae7, 0x08b8, 0x0b07, 0x08bf, 0x06, 0xfa, 0x0816, 0x0000)), - 'Inverted Links House': (0x52, (0x011c, 0x6c, 0x0506, 0x0a9a, 0x0832, 0x0ae7, 0x08b8, 0x0b07, 0x08bf, 0x06, 0xfa, 0x0816, 0x0000)), 'Dark Lake Hylia Shop': (0x73, (0x010f, 0x75, 0x0380, 0x0c6a, 0x0a00, 0x0cb8, 0x0a58, 0x0cd7, 0x0a85, 0x06, 0xfa, 0x0000, 0x0000)), 'Lumberjack House': (0x75, (0x011f, 0x02, 0x049c, 0x0088, 0x04e6, 0x00d8, 0x0558, 0x00f7, 0x0563, 0x08, 0xf8, 0x07AA, 0x0000)), 'Lake Hylia Fortune Teller': (0x72, (0x0122, 0x35, 0x0380, 0x0c6a, 0x0a00, 0x0cb8, 0x0a58, 0x0cd7, 0x0a85, 0x06, 0xfa, 0x0000, 0x0000)), @@ -3446,7 +3389,6 @@ door_addresses = {'Links House': (0x00, (0x0104, 0x2c, 0x0506, 0x0a9a, 0x0832, 0 # value = entrance # # | (entrance #, exit #) exit_ids = {'Links House Exit': (0x01, 0x00), - 'Inverted Links House Exit': (0x01, 0x00), 'Chris Houlihan Room Exit': (None, 0x3D), 'Desert Palace Exit (South)': (0x09, 0x0A), 'Desert Palace Exit (West)': (0x0B, 0x0C), @@ -3458,7 +3400,6 @@ exit_ids = {'Links House Exit': (0x01, 0x00), 'Hyrule Castle Exit (West)': (0x03, 0x02), 'Hyrule Castle Exit (East)': (0x05, 0x04), 'Agahnims Tower Exit': (0x24, 0x25), - 'Inverted Agahnims Tower Exit': (0x24, 0x25), 'Thieves Town Exit': (0x34, 0x35), 'Skull Woods First Section Exit': (0x2A, 0x2B), 'Skull Woods Second Section Exit (East)': (0x29, 0x2A), @@ -3506,7 +3447,6 @@ exit_ids = {'Links House Exit': (0x01, 0x00), 'Hookshot Cave Front Exit': (0x3A, 0x3B), 'Hookshot Cave Back Exit': (0x3B, 0x3C), 'Ganons Tower Exit': (0x37, 0x38), - 'Inverted Ganons Tower Exit': (0x37, 0x38), 'Pyramid Exit': (0x36, 0x37), 'Waterfall of Wishing': 0x5C, 'Dam': 0x4E, @@ -3558,7 +3498,6 @@ exit_ids = {'Links House Exit': (0x01, 0x00), 'East Dark World Hint': 0x69, 'Palace of Darkness Hint': 0x68, 'Big Bomb Shop': 0x53, - 'Inverted Big Bomb Shop': 0x53, 'Village of Outcasts Shop': 0x60, 'Dark Lake Hylia Shop': 0x60, 'Dark World Lumberjack Shop': 0x60, @@ -3572,7 +3511,6 @@ exit_ids = {'Links House Exit': (0x01, 0x00), 'Dark World Hammer Peg Cave': 0x83, 'Red Shield Shop': 0x57, 'Dark Sanctuary Hint': 0x5A, - 'Inverted Dark Sanctuary': 0x5A, 'Fortune Teller (Dark)': 0x66, 'Archery Game': 0x59, 'Mire Shed': 0x5F, @@ -3592,13 +3530,13 @@ exit_ids = {'Links House Exit': (0x01, 0x00), 'Skull Pot Circle': 0x76, 'Pyramid': 0x7B} -ow_prize_table = {'Links House': (0x8b1, 0xb2d), 'Inverted Big Bomb Shop': (0x8b1, 0xb2d), +ow_prize_table = {'Links House': (0x8b1, 0xb2d), 'Desert Palace Entrance (South)': (0x108, 0xd70), 'Desert Palace Entrance (West)': (0x031, 0xca0), 'Desert Palace Entrance (North)': (0x0e1, 0xba0), 'Desert Palace Entrance (East)': (0x191, 0xca0), 'Eastern Palace': (0xf31, 0x620), 'Tower of Hera': (0x8D0, 0x080), 'Hyrule Castle Entrance (South)': (0x7b0, 0x730), 'Hyrule Castle Entrance (West)': (0x700, 0x640), 'Hyrule Castle Entrance (East)': (0x8a0, 0x640), 'Inverted Pyramid Entrance': (0x720, 0x700), - 'Agahnims Tower': (0x7e0, 0x640), 'Inverted Ganons Tower': (0x7e0, 0x640), + 'Agahnims Tower': (0x7e0, 0x640), 'Thieves Town': (0x1d0, 0x780), 'Skull Woods First Section Door': (0x240, 0x280), 'Skull Woods Second Section Door (East)': (0x1a0, 0x240), 'Skull Woods Second Section Door (West)': (0x0c0, 0x1c0), 'Skull Woods Final Section': (0x082, 0x0b0), @@ -3643,7 +3581,6 @@ ow_prize_table = {'Links House': (0x8b1, 0xb2d), 'Inverted Big Bomb Shop': (0x8b 'Hookshot Cave': (0xc80, 0x0c0), 'Hookshot Cave Back Entrance': (0xcf0, 0x004), 'Ganons Tower': (0x8D0, 0x080), - 'Inverted Agahnims Tower': (0x8D0, 0x080), 'Pyramid Entrance': (0x640, 0x7c0), 'Skull Woods First Section Hole (West)': None, 'Skull Woods First Section Hole (East)': None, @@ -3707,7 +3644,6 @@ ow_prize_table = {'Links House': (0x8b1, 0xb2d), 'Inverted Big Bomb Shop': (0x8b 'Dark World Hammer Peg Cave': (0x4c0, 0x940), 'Red Shield Shop': (0x500, 0x680), 'Dark Sanctuary Hint': (0x720, 0x4a0), - 'Inverted Dark Sanctuary': (0x720, 0x4a0), 'Fortune Teller (Dark)': (0x2c0, 0x4c0), 'Dark World Shop': (0x2e0, 0x880), 'Dark World Lumberjack Shop': (0x4e0, 0x0d0), @@ -3720,7 +3656,7 @@ ow_prize_table = {'Links House': (0x8b1, 0xb2d), 'Inverted Big Bomb Shop': (0x8b 'Cave Shop (Dark Death Mountain)': (0xd80, 0x180), 'Dark Death Mountain Fairy': (0x620, 0x2c0), 'Mimic Cave': (0xc80, 0x180), - 'Big Bomb Shop': (0x8b1, 0xb2d), 'Inverted Links House': (0x8b1, 0xb2d), + 'Big Bomb Shop': (0x8b1, 0xb2d), 'Dark Lake Hylia Shop': (0xa40, 0xc40), 'Lumberjack House': (0x4e0, 0x0d0), 'Lake Hylia Fortune Teller': (0xa40, 0xc40), diff --git a/InvertedRegions.py b/InvertedRegions.py index a02bfbea..fabc4a76 100644 --- a/InvertedRegions.py +++ b/InvertedRegions.py @@ -5,10 +5,10 @@ from Regions import create_lw_region, create_dw_region, create_cave_region, crea def create_inverted_regions(world, player): world.regions += [ - create_menu_region(player, 'Menu', None, ['Links House S&Q', 'Dark Sanctuary S&Q', 'Old Man S&Q', 'Castle Ledge S&Q']), + create_menu_region(player, 'Menu', None, ['Links House S&Q', 'Sanctuary S&Q', 'Old Man S&Q', 'Other World S&Q']), create_lw_region(player, 'Light World', ['Mushroom', 'Bottle Merchant', 'Flute Spot', 'Sunken Treasure', 'Purple Chest', 'Bombos Tablet'], ["Blinds Hideout", "Hyrule Castle Secret Entrance Drop", 'Kings Grave Outer Rocks', 'Dam', - 'Inverted Big Bomb Shop', 'Tavern North', 'Chicken House', 'Aginahs Cave', 'Sahasrahlas Hut', 'Kakariko Well Drop', 'Kakariko Well Cave', + 'Links House', 'Tavern North', 'Chicken House', 'Aginahs Cave', 'Sahasrahlas Hut', 'Kakariko Well Drop', 'Kakariko Well Cave', 'Blacksmiths Hut', 'Bat Cave Drop Ledge', 'Bat Cave Cave', 'Sick Kids House', 'Hobo Bridge', 'Lost Woods Hideout Drop', 'Lost Woods Hideout Stump', 'Lumberjack Tree Tree', 'Lumberjack Tree Cave', 'Mini Moldorm Cave', 'Ice Rod Cave', 'Lake Hylia Central Island Pier', 'Lake Hylia Island Pier', 'Lake Hylia Warp', 'Bonk Rock Cave', 'Library', 'Two Brothers House (East)', 'Desert Palace Stairs', 'Eastern Palace', 'Master Sword Meadow', @@ -41,7 +41,7 @@ def create_inverted_regions(world, player): create_cave_region(player, 'Kings Grave', 'a cave with a chest', ['King\'s Tomb']), create_cave_region(player, 'North Fairy Cave', 'a drop\'s exit', None, ['North Fairy Cave Exit']), create_cave_region(player, 'Dam', 'the dam', ['Floodgate', 'Floodgate Chest']), - create_cave_region(player, 'Inverted Links House', 'your house', ['Link\'s House'], ['Inverted Links House Exit']), + create_cave_region(player, 'Links House', 'your house', ['Link\'s House'], ['Links House Exit']), create_cave_region(player, 'Chris Houlihan Room', 'I AM ERROR', None, ['Chris Houlihan Room Exit']), create_cave_region(player, 'Tavern', 'the tavern', ['Kakariko Tavern']), create_cave_region(player, 'Elder House', 'a connector', None, ['Elder House Exit (East)', 'Elder House Exit (West)']), @@ -108,7 +108,7 @@ def create_inverted_regions(world, player): create_lw_region(player, 'Desert Palace Entrance (North) Spot', None, ['Desert Palace Entrance (North)', 'Desert Ledge Return Rocks', 'Desert Palace North Mirror Spot']), create_lw_region(player, 'Master Sword Meadow', ['Master Sword Pedestal']), create_cave_region(player, 'Lost Woods Gamble', 'a game of chance'), - create_lw_region(player, 'Hyrule Castle Ledge', None, ['Hyrule Castle Entrance (East)', 'Hyrule Castle Entrance (West)', 'Inverted Ganons Tower', 'Hyrule Castle Ledge Courtyard Drop', 'Inverted Pyramid Hole']), + create_lw_region(player, 'Hyrule Castle Ledge', None, ['Hyrule Castle Entrance (East)', 'Hyrule Castle Entrance (West)', 'Agahnims Tower', 'Hyrule Castle Ledge Courtyard Drop', 'Inverted Pyramid Hole']), create_cave_region(player, 'Old Man Cave', 'a connector', ['Old Man'], ['Old Man Cave Exit (East)']), create_cave_region(player, 'Old Man Cave Ledge', 'a connector', None, ['Old Man Cave Exit (West)', 'Old Man Cave Dropdown']), create_cave_region(player, 'Old Man House', 'a connector', None, ['Old Man House Exit (Bottom)', 'Old Man House Front to Back']), @@ -155,9 +155,9 @@ def create_inverted_regions(world, player): create_dw_region(player, 'Northeast Dark World', None, ['West Dark World Gap', 'Dark World Potion Shop', 'East Dark World Broken Bridge Pass', 'NEDW Flute', 'Dark Lake Hylia Teleporter', 'Catfish Entrance Rock']), create_cave_region(player, 'Palace of Darkness Hint', 'a storyteller'), create_cave_region(player, 'East Dark World Hint', 'a storyteller'), - create_dw_region(player, 'South Dark World', ['Stumpy', 'Digging Game'], ['Dark Lake Hylia Drop (South)', 'Hype Cave', 'Swamp Palace', 'Village of Outcasts Heavy Rock', 'East Dark World Bridge', 'Inverted Links House', 'Archery Game', 'Bonk Fairy (Dark)', + create_dw_region(player, 'South Dark World', ['Stumpy', 'Digging Game'], ['Dark Lake Hylia Drop (South)', 'Hype Cave', 'Swamp Palace', 'Village of Outcasts Heavy Rock', 'East Dark World Bridge', 'Big Bomb Shop', 'Archery Game', 'Bonk Fairy (Dark)', 'Dark Lake Hylia Shop', 'South Dark World Teleporter', 'Post Aga Teleporter', 'SDW Flute']), - create_cave_region(player, 'Inverted Big Bomb Shop', 'the bomb shop'), + create_cave_region(player, 'Big Bomb Shop', 'the bomb shop'), create_cave_region(player, 'Archery Game', 'a game of skill'), create_dw_region(player, 'Dark Lake Hylia', None, ['East Dark World Pier', 'Dark Lake Hylia Ledge Pier', 'Ice Palace Missing Wall']), create_dw_region(player, 'Dark Lake Hylia Central Island', None, ['Dark Lake Hylia Shallows', 'Ice Palace', 'Dark Lake Hylia Central Island Teleporter']), @@ -167,7 +167,7 @@ def create_inverted_regions(world, player): create_cave_region(player, 'Hype Cave', 'a bounty of five items', ['Hype Cave - Top', 'Hype Cave - Middle Right', 'Hype Cave - Middle Left', 'Hype Cave - Bottom', 'Hype Cave - Generous Guy']), create_dw_region(player, 'West Dark World', ['Frog'], ['Village of Outcasts Drop', 'East Dark World River Pier', 'Brewery', 'C-Shaped House', 'Chest Game', 'Thieves Town', 'Bumper Cave Entrance Rock', - 'Skull Woods Forest', 'Village of Outcasts Pegs', 'Village of Outcasts Eastern Rocks', 'Red Shield Shop', 'Inverted Dark Sanctuary', 'Fortune Teller (Dark)', 'Dark World Lumberjack Shop', + 'Skull Woods Forest', 'Village of Outcasts Pegs', 'Village of Outcasts Eastern Rocks', 'Red Shield Shop', 'Dark Sanctuary Hint', 'Fortune Teller (Dark)', 'Dark World Lumberjack Shop', 'West Dark World Teleporter', 'WDW Flute']), create_dw_region(player, 'Dark Grassy Lawn', None, ['Grassy Lawn Pegs', 'Dark World Shop', 'Dark Grassy Lawn Flute']), create_dw_region(player, 'Hammer Peg Area', ['Dark Blacksmith Ruins'], ['Dark World Hammer Peg Cave', 'Peg Area Rocks', 'Hammer Peg Area Flute']), @@ -183,7 +183,7 @@ def create_inverted_regions(world, player): create_cave_region(player, 'C-Shaped House', 'a house with a chest', ['C-Shaped House']), create_cave_region(player, 'Chest Game', 'a game of 16 chests', ['Chest Game']), create_cave_region(player, 'Red Shield Shop', 'the rare shop', ['Red Shield Shop - Left', 'Red Shield Shop - Middle', 'Red Shield Shop - Right']), - create_cave_region(player, 'Inverted Dark Sanctuary', 'a storyteller', None, ['Inverted Dark Sanctuary Exit']), + create_cave_region(player, 'Dark Sanctuary Hint', 'a storyteller', None, ['Dark Sanctuary Hint Exit']), create_cave_region(player, 'Bumper Cave (bottom)', 'a connector', None, ['Bumper Cave Exit (Bottom)', 'Bumper Cave Bottom to Top']), create_cave_region(player, 'Bumper Cave (top)', 'a connector', None, ['Bumper Cave Exit (Top)', 'Bumper Cave Top To Bottom']), create_dw_region(player, 'Skull Woods Forest', None, ['Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', @@ -193,7 +193,7 @@ def create_inverted_regions(world, player): create_dw_region(player, 'Dark Desert Ledge', None, ['Dark Desert Drop', 'Dark Desert Teleporter']), create_cave_region(player, 'Mire Shed', 'a cave with two chests', ['Mire Shed - Left', 'Mire Shed - Right']), create_cave_region(player, 'Dark Desert Hint', 'a storyteller'), - create_dw_region(player, 'Dark Death Mountain', None, ['Dark Death Mountain Drop (East)', 'Inverted Agahnims Tower', 'Superbunny Cave (Top)', 'Hookshot Cave', 'Turtle Rock', + create_dw_region(player, 'Dark Death Mountain', None, ['Dark Death Mountain Drop (East)', 'Ganons Tower', 'Superbunny Cave (Top)', 'Hookshot Cave', 'Turtle Rock', 'Spike Cave', 'Dark Death Mountain Fairy', 'Dark Death Mountain Teleporter (West)', 'Turtle Rock Tail Drop', 'DDM Flute']), create_dw_region(player, 'Dark Death Mountain Ledge', None, ['Dark Death Mountain Ledge (East)', 'Dark Death Mountain Ledge (West)']), create_dw_region(player, 'Turtle Rock (Top)', None, ['Dark Death Mountain Teleporter (East)', 'Turtle Rock Drop']), diff --git a/KeyDoorShuffle.py b/KeyDoorShuffle.py index 17859357..d82adbf1 100644 --- a/KeyDoorShuffle.py +++ b/KeyDoorShuffle.py @@ -1404,18 +1404,18 @@ def forced_big_key_avail(locations): return None -def prize_relevance(key_layout, dungeon_entrance): +def prize_relevance(key_layout, dungeon_entrance, is_atgt_swapped): if len(key_layout.start_regions) > 1 and dungeon_entrance and dungeon_table[key_layout.key_logic.dungeon].prize: - if dungeon_entrance.name in ['Ganons Tower', 'Inverted Ganons Tower']: + if dungeon_entrance.name == 'Agahnims Tower' if is_atgt_swapped else 'Ganons Tower': return 'GT' elif dungeon_entrance.name == 'Pyramid Fairy': return 'BigBomb' return None -def prize_relevance_sig2(start_regions, d_name, dungeon_entrance): +def prize_relevance_sig2(start_regions, d_name, dungeon_entrance, is_atgt_swapped): if len(start_regions) > 1 and dungeon_entrance and dungeon_table[d_name].prize: - if dungeon_entrance.name in ['Ganons Tower', 'Inverted Ganons Tower']: + if dungeon_entrance.name == 'Agahnims Tower' if is_atgt_swapped else 'Ganons Tower': return 'GT' elif dungeon_entrance.name == 'Pyramid Fairy': return 'BigBomb' @@ -1431,7 +1431,7 @@ def validate_bk_layout(proposal, builder, start_regions, world, player): state.big_key_special = bk_special for region in start_regions: dungeon_entrance, portal_door = find_outside_connection(region) - prize_relevant_flag = prize_relevance_sig2(start_regions, builder.name, dungeon_entrance) + prize_relevant_flag = prize_relevance_sig2(start_regions, builder.name, dungeon_entrance, world.is_atgt_swapped(player)) if prize_relevant_flag: state.append_door_to_list(portal_door, state.prize_doors) state.prize_door_set[portal_door] = dungeon_entrance @@ -1462,7 +1462,7 @@ def validate_key_layout(key_layout, world, player): state.big_key_special = check_bk_special(key_layout.sector.regions, world, player) for region in key_layout.start_regions: dungeon_entrance, portal_door = find_outside_connection(region) - prize_relevant_flag = prize_relevance(key_layout, dungeon_entrance) + prize_relevant_flag = prize_relevance(key_layout, dungeon_entrance, world.is_atgt_swapped(player)) if prize_relevant_flag: state.append_door_to_list(portal_door, state.prize_doors) state.prize_door_set[portal_door] = dungeon_entrance @@ -1593,7 +1593,7 @@ def determine_prize_lock(key_layout, world, player): prize_lock_possible = False for region in key_layout.start_regions: dungeon_entrance, portal_door = find_outside_connection(region) - prize_relevant_flag = prize_relevance(key_layout, dungeon_entrance) + prize_relevant_flag = prize_relevance(key_layout, dungeon_entrance, world.is_atgt_swapped(player)) if prize_relevant_flag: state.append_door_to_list(portal_door, state.prize_doors) state.prize_door_set[portal_door] = dungeon_entrance @@ -1664,7 +1664,7 @@ def create_key_counters(key_layout, world, player): state.big_key_special = True for region in key_layout.start_regions: dungeon_entrance, portal_door = find_outside_connection(region) - prize_relevant_flag = prize_relevance(key_layout, dungeon_entrance) + prize_relevant_flag = prize_relevance(key_layout, dungeon_entrance, world.is_atgt_swapped(player)) if prize_relevant_flag: state.append_door_to_list(portal_door, state.prize_doors) state.prize_door_set[portal_door] = dungeon_entrance diff --git a/Main.py b/Main.py index 08e29254..9c2f1441 100644 --- a/Main.py +++ b/Main.py @@ -727,10 +727,7 @@ def create_playthrough(world): old_world.spoiler.paths.update({location.gen_name(): get_path(state, location.parent_region) for sphere in collection_spheres for location in sphere if location.player == player}) for path in dict(old_world.spoiler.paths).values(): if any(exit == 'Pyramid Fairy' for (_, exit) in path): - if world.mode[player] != 'inverted': - old_world.spoiler.paths[str(world.get_region('Big Bomb Shop', player))] = get_path(state, world.get_region('Big Bomb Shop', player)) - else: - old_world.spoiler.paths[str(world.get_region('Inverted Big Bomb Shop', player))] = get_path(state, world.get_region('Inverted Big Bomb Shop', player)) + old_world.spoiler.paths[str(world.get_region('Big Bomb Shop', player))] = get_path(state, world.get_region('Big Bomb Shop', player)) # we can finally output our playthrough old_world.spoiler.playthrough = {"0": [str(item) for item in world.precollected_items if item.advancement]} diff --git a/OverworldGlitchRules.py b/OverworldGlitchRules.py index 3ec0807b..27ce257e 100644 --- a/OverworldGlitchRules.py +++ b/OverworldGlitchRules.py @@ -119,7 +119,7 @@ def get_non_mandatory_exits(inverted): if inverted: yield 'Desert Palace Entrance (North)' yield 'Desert Palace Entrance (West)' - yield 'Inverted Ganons Tower' + yield 'Agahnims Tower' yield 'Hyrule Castle Entrance (West)' yield 'Hyrule Castle Entrance (East)' else: diff --git a/Regions.py b/Regions.py index 3c307e40..f293e220 100644 --- a/Regions.py +++ b/Regions.py @@ -6,7 +6,7 @@ from PotShuffle import key_drop_data, vanilla_pots, choose_pots, PotSecretTable def create_regions(world, player): world.regions += [ - create_menu_region(player, 'Menu', None, ['Links House S&Q', 'Sanctuary S&Q', 'Old Man S&Q']), + create_menu_region(player, 'Menu', None, ['Links House S&Q', 'Sanctuary S&Q', 'Old Man S&Q', 'Other World S&Q']), create_lw_region(player, 'Light World', ['Mushroom', 'Bottle Merchant', 'Flute Spot', 'Sunken Treasure', 'Purple Chest'], ["Blinds Hideout", "Hyrule Castle Secret Entrance Drop", 'Zoras River', 'Kings Grave Outer Rocks', 'Dam', 'Links House', 'Tavern North', 'Chicken House', 'Aginahs Cave', 'Sahasrahlas Hut', 'Kakariko Well Drop', 'Kakariko Well Cave', @@ -235,7 +235,7 @@ def create_dungeon_regions(world, player): create_dungeon_region(player, 'Desert East Portal', 'Desert Palace', None, ['Desert Palace Exit (East)', 'Enter Desert (East)']), create_dungeon_region(player, 'Desert Back Portal', 'Desert Palace', None, ['Desert Palace Exit (North)', 'Enter Desert (North)']), create_dungeon_region(player, 'Hera Portal', 'Tower of Hera', None, ['Tower of Hera Exit', 'Enter Hera']), - create_dungeon_region(player, 'Agahnims Tower Portal', 'Castle Tower', None, [inv_flag and 'Inverted Agahnims Tower Exit' or 'Agahnims Tower Exit', 'Enter Agahnims Tower']), + create_dungeon_region(player, 'Agahnims Tower Portal', 'Castle Tower', None, ['Agahnims Tower Exit', 'Enter Agahnims Tower']), create_dungeon_region(player, 'Palace of Darkness Portal', 'Palace of Darkness', None, ['Palace of Darkness Exit', 'Enter Palace of Darkness']), create_dungeon_region(player, 'Swamp Portal', 'Swamp Palace', None, ['Swamp Palace Exit', 'Enter Swamp']), create_dungeon_region(player, 'Skull 1 Portal', 'Skull Woods', None, ['Skull Woods First Section Exit', 'Enter Skull Woods 1']), @@ -249,7 +249,7 @@ def create_dungeon_regions(world, player): create_dungeon_region(player, 'Turtle Rock Lazy Eyes Portal', 'Turtle Rock', None, ['Turtle Rock Ledge Exit (West)', 'Enter Turtle Rock (Lazy Eyes)']), create_dungeon_region(player, 'Turtle Rock Chest Portal', 'Turtle Rock', None, ['Turtle Rock Ledge Exit (East)', 'Enter Turtle Rock (Chest)']), create_dungeon_region(player, 'Turtle Rock Eye Bridge Portal', 'Turtle Rock', None, ['Turtle Rock Isolated Ledge Exit', 'Enter Turtle Rock (Laser Bridge)']), - create_dungeon_region(player, 'Ganons Tower Portal', "Ganon's Tower", None, [inv_flag and 'Inverted Ganons Tower Exit' or 'Ganons Tower Exit', 'Enter Ganons Tower']), + create_dungeon_region(player, 'Ganons Tower Portal', "Ganon's Tower", None, ['Ganons Tower Exit', 'Enter Ganons Tower']), create_dungeon_region(player, 'Hyrule Castle Lobby', 'Hyrule Castle', None, ['Hyrule Castle Lobby W', 'Hyrule Castle Lobby E', 'Hyrule Castle Lobby WN', 'Hyrule Castle Lobby North Stairs', 'Hyrule Castle Lobby S']), @@ -1087,9 +1087,6 @@ def create_pot_location(pot, pot_index, super_tile, world, player): and world.pottery[player] not in ['none', 'cave', 'keys', 'cavekeys']))): address = pot_address(pot_index, super_tile) region = pot.room - if world.mode[player] == 'inverted': - if region == 'Links House': - region = 'Inverted Links House' parent = world.get_region(region, player) descriptor = 'Large Block' if pot.flags & PotFlags.Block else f'Pot #{pot_index+1}' hint_text = ('under a block' if pot.flags & PotFlags.Block else 'in a pot') diff --git a/Rom.py b/Rom.py index f8b5b107..10125e66 100644 --- a/Rom.py +++ b/Rom.py @@ -783,7 +783,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): if should_be_bunny(sanc_region, world.mode[player]): rom.write_bytes(0x13fff2, [0x12, 0x00]) - lh_name = 'Links House' if world.mode[player] != 'inverted' else 'Inverted Links House' + lh_name = 'Links House' links_house = world.get_region(lh_name, player) if should_be_bunny(links_house, world.mode[player]): rom.write_bytes(0x13fff0, [0x04, 0x01]) @@ -2044,7 +2044,7 @@ def write_strings(rom, world, player, team): entrances_to_hint.update(InconvenientDungeonEntrances) if world.shuffle_ganon: if world.mode[player] == 'inverted': - entrances_to_hint.update({'Inverted Ganons Tower': 'The sealed castle door'}) + entrances_to_hint.update({'Agahnims Tower': 'The sealed castle door'}) else: entrances_to_hint.update({'Ganons Tower': 'Ganon\'s Tower'}) if world.shuffle[player] in ['simple', 'restricted']: @@ -2077,7 +2077,7 @@ def write_strings(rom, world, player, team): entrances_to_hint.update(ConnectorEntrances) entrances_to_hint.update(DungeonEntrances) if world.mode[player] == 'inverted': - entrances_to_hint.update({'Inverted Agahnims Tower': 'The dark mountain tower'}) + entrances_to_hint.update({'Ganons Tower': 'The dark mountain tower'}) else: entrances_to_hint.update({'Agahnims Tower': 'The sealed castle door'}) elif world.shuffle[player] == 'restricted': @@ -2090,17 +2090,14 @@ def write_strings(rom, world, player, team): entrances_to_hint.update(ShopEntrances) if world.shufflelinks[player] and world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull']: if world.mode[player] == 'inverted': - entrances_to_hint.update({'Inverted Links House': 'The hero\'s old residence'}) + entrances_to_hint.update({'Big Bomb Shop': 'The old hero\'s dark home'}) else: entrances_to_hint.update({'Links House': 'The hero\'s old residence'}) if world.shuffletavern[player] and world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull']: entrances_to_hint.update({'Tavern North': 'A backdoor'}) if world.mode[player] == 'inverted': - entrances_to_hint.update({'Inverted Dark Sanctuary': 'The dark sanctuary cave'}) - entrances_to_hint.update({'Inverted Big Bomb Shop': 'The old hero\'s dark home'}) - entrances_to_hint.update({'Inverted Links House': 'The old hero\'s light home'}) + entrances_to_hint.update({'Links House': 'The old hero\'s light home'}) else: - entrances_to_hint.update({'Dark Sanctuary Hint': 'The dark sanctuary cave'}) entrances_to_hint.update({'Big Bomb Shop': 'The old bomb shop'}) if world.shuffle[player] in ['insanity']: entrances_to_hint.update(InsanityEntrances) @@ -2678,7 +2675,7 @@ def set_inverted_mode(world, player, rom): rom.write_bytes(snes_to_pc(0x06B2AB), [0xF0, 0xE1, 0x05]) def patch_shuffled_dark_sanc(world, rom, player): - dark_sanc = world.get_region('Inverted Dark Sanctuary', player) + dark_sanc = world.get_region('Dark Sanctuary Hint', player) dark_sanc_entrance = str([i for i in dark_sanc.entrances if i.parent_region.name != 'Menu'][0].name) room_id, ow_area, vram_loc, scroll_y, scroll_x, link_y, link_x, camera_y, camera_x, unknown_1, unknown_2, door_1, door_2 = door_addresses[dark_sanc_entrance][1] door_index = door_addresses[str(dark_sanc_entrance)][0] @@ -2836,7 +2833,8 @@ OtherEntrances = {'Lake Hylia Fairy': 'A cave NE of Lake Hylia', 'Dark Lake Hylia Ledge Hint': 'The open cave SE dark Lake Hylia', 'Dark Desert Fairy': 'The eastern hut in the mire', 'Dark Lake Hylia Ledge Fairy': 'The sealed cave SE dark Lake Hylia', - 'Fortune Teller (Dark)': 'The building NE the Village of Outcasts' + 'Fortune Teller (Dark)': 'The building NE the Village of Outcasts', + 'Dark Sanctuary Hint': 'The dark sanctuary cave' } InsanityEntrances = {'Sanctuary': 'Sanctuary', diff --git a/Rules.py b/Rules.py index 67417aac..7c2435fe 100644 --- a/Rules.py +++ b/Rules.py @@ -771,6 +771,8 @@ def pot_rules(world, player): def default_rules(world, player): + set_rule(world.get_entrance('Other World S&Q', player), lambda state: state.has_Mirror(player) and state.has('Beat Agahnim 1', player)) + # overworld requirements set_rule(world.get_entrance('Kings Grave', player), lambda state: state.has_Boots(player)) set_rule(world.get_entrance('Kings Grave Outer Rocks', player), lambda state: state.can_lift_heavy_rocks(player)) @@ -887,7 +889,7 @@ def default_rules(world, player): def inverted_rules(world, player): # s&q regions. link's house entrance is set to true so the filler knows the chest inside can always be reached - set_rule(world.get_entrance('Castle Ledge S&Q', player), lambda state: state.has_Mirror(player) and state.has('Beat Agahnim 1', player)) + set_rule(world.get_entrance('Other World S&Q', player), lambda state: state.has_Mirror(player) and state.has('Beat Agahnim 1', player)) # overworld requirements set_rule(world.get_location('Ice Rod Cave', player), lambda state: state.has_Pearl(player)) @@ -1034,7 +1036,7 @@ def inverted_rules(world, player): if world.swords[player] == 'swordless': swordless_rules(world, player) - set_rule(world.get_entrance('Inverted Ganons Tower', player), lambda state: state.has_crystals(world.crystals_needed_for_gt[player], player)) + set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has_crystals(world.crystals_needed_for_gt[player], player)) def no_glitches_rules(world, player): @@ -1589,7 +1591,7 @@ def set_big_bomb_rules(world, player): def set_inverted_big_bomb_rules(world, player): - bombshop_entrance = world.get_region('Inverted 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', @@ -1634,10 +1636,10 @@ def set_inverted_big_bomb_rules(world, player): 'Hyrule Castle Secret Entrance Stairs', 'Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)', - 'Inverted Ganons Tower', + 'Agahnims Tower', 'Cave 45', 'Checkerboard Cave', - 'Inverted Big Bomb Shop'] + 'Links House'] Isolated_LW_entrances = ['Old Man Cave (East)', 'Old Man House (Bottom)', 'Old Man House (Top)', @@ -1665,7 +1667,7 @@ def set_inverted_big_bomb_rules(world, player): 'C-Shaped House', 'Chest Game', 'Dark World Hammer Peg Cave', - 'Inverted Dark Sanctuary', + 'Dark Sanctuary Hint', 'Fortune Teller (Dark)', 'Dark World Lumberjack Shop', 'Thieves Town', @@ -1674,7 +1676,7 @@ def set_inverted_big_bomb_rules(world, player): Southern_DW_entrances = ['Hype Cave', 'Bonk Fairy (Dark)', 'Archery Game', - 'Inverted Links House', + 'Big Bomb Shop', 'Dark Lake Hylia Shop', 'Swamp Palace'] Isolated_DW_entrances = ['Spike Cave', @@ -1691,7 +1693,7 @@ def set_inverted_big_bomb_rules(world, player): 'Hookshot Cave', 'Turtle Rock Isolated Ledge Entrance', 'Hookshot Cave Back Entrance', - 'Inverted Agahnims Tower'] + 'Ganons Tower'] LW_walkable_entrances = ['Dark Lake Hylia Ledge Fairy', 'Dark Lake Hylia Ledge Spike Cave', 'Dark Lake Hylia Ledge Hint', @@ -1708,7 +1710,7 @@ def set_inverted_big_bomb_rules(world, player): 'Spectacle Rock Cave (Bottom)'] set_rule(world.get_entrance('Pyramid Fairy', player), - lambda state: state.can_reach('East Dark World', 'Region', player) and state.can_reach('Inverted Big Bomb Shop', 'Region', player) and state.has('Crystal 5', player) and state.has('Crystal 6', player)) + lambda state: state.can_reach('East Dark World', 'Region', player) and state.can_reach('Big Bomb Shop', 'Region', player) and state.has('Crystal 5', player) and state.has('Crystal 6', player)) # Key for below abbreviations: # P = pearl diff --git a/source/item/District.py b/source/item/District.py index b4e2aec0..9d858ac2 100644 --- a/source/item/District.py +++ b/source/item/District.py @@ -82,16 +82,6 @@ def create_district_helper(world, player): 'Cave Shop (Dark Death Mountain)', 'Dark Death Mountain Fairy'] if inverted: - south_dw_entrances.remove('Big Bomb Shop') - central_lw_entrances.append('Inverted Big Bomb Shop') - central_lw_entrances.remove('Links House') - south_dw_entrances.append('Inverted Links House') - voo_north_entrances.remove('Dark Sanctuary Hint') - voo_north_entrances.append('Inverted Dark Sanctuary') - ddm_entrances.remove('Ganons Tower') - central_lw_entrances.append('Inverted Ganons Tower') - central_lw_entrances.remove('Agahnims Tower') - ddm_entrances.append('Inverted Agahnims Tower') east_dw_entrances.remove('Pyramid Entrance') central_lw_entrances.append('Inverted Pyramid Entrance') east_dw_entrances.remove('Pyramid Hole') diff --git a/source/item/FillUtil.py b/source/item/FillUtil.py index 6b242589..bbde4feb 100644 --- a/source/item/FillUtil.py +++ b/source/item/FillUtil.py @@ -213,7 +213,7 @@ def district_item_pool_config(world): scale_factors = defaultdict(int) scale_total = 0 for p in range(1, world.players + 1): - ent = 'Inverted Ganons Tower' if world.mode[p] == 'inverted' else 'Ganons Tower' + ent = 'Agahnims Tower' if world.is_atgt_swapped(p) else 'Ganons Tower' dungeon = world.get_entrance(ent, p).connected_region.dungeon if dungeon: scale = world.crystals_needed_for_gt[p] diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index 6760b480..a5a66c54 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -40,14 +40,12 @@ def link_entrances_new(world, player): avail_pool = EntrancePool(world, player) i_drop_map = {x: y for x, y in drop_map.items() if not x.startswith('Inverted')} i_entrance_map = {x: y for x, y in entrance_map.items() if not x.startswith('Inverted')} - i_single_ent_map = {x: y for x, y in single_entrance_map.items() if not x.startswith('Inverted')} + i_single_ent_map = {x: y for x, y in single_entrance_map.items()} avail_pool.entrances = set(i_drop_map.keys()).union(i_entrance_map.keys()).union(i_single_ent_map.keys()) avail_pool.exits = set(i_entrance_map.values()).union(i_drop_map.values()).union(i_single_ent_map.values()) avail_pool.exits.add('Chris Houlihan Room Exit') avail_pool.inverted = world.mode[player] == 'inverted' - if avail_pool.inverted: - avail_pool.exits.add('Inverted Dark Sanctuary Exit') inverted_substitution(avail_pool, avail_pool.entrances, True, True) inverted_substitution(avail_pool, avail_pool.exits, False, True) avail_pool.original_entrances.update(avail_pool.entrances) @@ -145,14 +143,14 @@ def link_entrances_new(world, player): world.ganon_at_pyramid[player] = False # check for Ganon's Tower location - gt = 'Inverted Ganons Tower' if avail_pool.inverted else 'Ganons Tower' + gt = 'Agahnims Tower' if avail_pool.world.is_atgt_swapped(avail_pool.player) else 'Ganons Tower' if world.get_entrance(gt, player).connected_region.name != 'Ganons Tower Portal': world.ganonstower_vanilla[player] = False def do_vanilla_connections(avail_pool): if 'Chris Houlihan Room Exit' in avail_pool.exits: - lh = 'Inverted Links House' if avail_pool.inverted else 'Links House' + lh = 'Big Bomb Shop' if avail_pool.inverted else 'Links House' connect_exit('Chris Houlihan Room Exit', lh, avail_pool) for ent in list(avail_pool.entrances): if ent in avail_pool.default_map and avail_pool.default_map[ent] in avail_pool.exits: @@ -173,13 +171,13 @@ def do_main_shuffle(entrances, exits, avail, mode_def): avail.decoupled_exits.extend(exits) if not avail.world.shuffle_ganon: - if avail.inverted and 'Inverted Ganons Tower' in entrances: - connect_two_way('Inverted Ganons Tower', 'Inverted Ganons Tower Exit', avail) - entrances.remove('Inverted Ganons Tower') - exits.remove('Inverted Ganons Tower Exit') + if avail.world.is_atgt_swapped(avail.player) and 'Agahnims Tower' in entrances: + connect_two_way('Agahnims Tower', 'Ganons Tower Exit', avail) + entrances.remove('Agahnims Tower') + exits.remove('Ganons Tower Exit') if not avail.coupled: - avail.decoupled_entrances.remove('Inverted Ganons Tower') - avail.decoupled_exits.remove('Inverted Ganons Tower Exit') + avail.decoupled_entrances.remove('Agahnims Tower') + avail.decoupled_exits.remove('Ganons Tower Exit') elif 'Ganons Tower' in entrances: connect_two_way('Ganons Tower', 'Ganons Tower Exit', avail) entrances.remove('Ganons Tower') @@ -200,13 +198,13 @@ def do_main_shuffle(entrances, exits, avail, mode_def): do_links_house(entrances, exits, avail, cross_world) # inverted sanc - if avail.inverted and 'Inverted Dark Sanctuary Exit' in exits: + if avail.inverted and 'Dark Sanctuary Hint' in exits: choices = [e for e in Inverted_Dark_Sanctuary_Doors if e in entrances] choice = random.choice(choices) entrances.remove(choice) - exits.remove('Inverted Dark Sanctuary Exit') - connect_entrance(choice, 'Inverted Dark Sanctuary', avail) - ext = avail.world.get_entrance('Inverted Dark Sanctuary Exit', avail.player) + exits.remove('Dark Sanctuary Hint') + connect_entrance(choice, 'Dark Sanctuary Hint', avail) + ext = avail.world.get_entrance('Dark Sanctuary Hint Exit', avail.player) ext.connect(avail.world.get_entrance(choice, avail.player).parent_region) if not avail.coupled: avail.decoupled_entrances.remove(choice) @@ -256,7 +254,7 @@ def do_main_shuffle(entrances, exits, avail, mode_def): rem_exits.remove('Blacksmiths Hut') # bomb shop - bomb_shop = 'Inverted Big Bomb Shop' if avail.inverted else 'Big Bomb Shop' + bomb_shop = 'Links House' if avail.inverted else 'Big Bomb Shop' if bomb_shop in rem_exits: bomb_shop_options = Inverted_Bomb_Shop_Options if avail.inverted else Bomb_Shop_Options bomb_shop_options = [x for x in bomb_shop_options if x in rem_entrances] @@ -417,10 +415,10 @@ def do_holes_and_linked_drops(entrances, exits, avail, cross_world, keep_togethe def do_links_house(entrances, exits, avail, cross_world): - lh_exit = 'Inverted Links House Exit' if avail.inverted else 'Links House Exit' + lh_exit = 'Links House Exit' if lh_exit in exits: if not avail.world.shufflelinks[avail.player]: - links_house = 'Inverted Links House' if avail.inverted else 'Links House' + links_house = 'Big Bomb Shop' if avail.inverted else 'Links House' else: forbidden = list(Isolated_LH_Doors_Inv + Inverted_Dark_Sanctuary_Doors if avail.inverted else Isolated_LH_Doors_Open) @@ -632,7 +630,7 @@ def do_fixed_shuffle(avail, entrance_list): if ('Hyrule Castle Entrance (South)' in entrances and avail.world.doorShuffle[avail.player] in ['basic', 'crossed']): rules.must_exit_to_lw = True - if 'Inverted Ganons Tower' in entrances and not avail.world.shuffle_ganon: + if avail.world.is_atgt_swapped(avail.player) and 'Agahnims Tower' in entrances and not avail.world.shuffle_ganon: rules.fixed = True option = (i, entrances, targets, rules) options[i] = option @@ -644,7 +642,8 @@ def do_fixed_shuffle(avail, entrance_list): elif rules.fixed: choice = choices[i] elif rules.must_exit_to_lw: - filtered_choices = {i: opt for i, opt in choices.items() if all(t in default_lw for t in opt[2])} + lw_exits = default_lw + ['Big Bomb Shop', 'Ganons Tower Exit'] if avail.inverted else ['Links House Exit', 'Agahnims Tower Exit'] + filtered_choices = {i: opt for i, opt in choices.items() if all(t in lw_exits for t in opt[2])} index, choice = random.choice(list(filtered_choices.items())) else: index, choice = random.choice(list(choices.items())) @@ -812,7 +811,7 @@ def do_mandatory_connections(avail, entrances, cave_options, must_exit): for entrance in invalid_connections: if avail.world.get_entrance(entrance, avail.player).connected_region == at: for ext in invalid_connections[entrance]: - invalid_connections[ext] = invalid_connections[ext].union({'Inverted Ganons Tower', 'Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)'}) + invalid_connections[ext] = invalid_connections[ext].union({'Agahnims Tower', 'Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)'}) break used_caves = [] @@ -955,7 +954,7 @@ def find_entrances_and_exits(avail_pool, entrance_pool): if item in avail_pool.entrances: entrances.append(item) if item in entrance_map and entrance_map[item] in avail_pool.exits: - if entrance_map[item] in ['Links House Exit', 'Inverted Links House Exit']: + if entrance_map[item] == 'Links House Exit': targets.append('Chris Houlihan Room Exit') targets.append(entrance_map[item]) elif item in single_entrance_map and single_entrance_map[item] in avail_pool.exits: @@ -964,21 +963,18 @@ def find_entrances_and_exits(avail_pool, entrance_pool): inverted_sub_table = { - 'Ganons Tower': 'Inverted Agahnims Tower', - 'Agahnims Tower': 'Inverted Ganons Tower', - 'Dark Sanctuary Hint': 'Inverted Dark Sanctuary', - 'Big Bomb Shop': 'Inverted Links House', - 'Links House': 'Inverted Big Bomb Shop', + #TODO: Confirm this is correct + #'Ganons Tower': 'Agahnims Tower', + #'Agahnims Tower': 'Ganons Tower', + #'Links House': 'Big Bomb Shop', + #'Big Bomb Shop': 'Links House', 'Pyramid Hole': 'Inverted Pyramid Hole', 'Pyramid Entrance': 'Inverted Pyramid Entrance' } inverted_exit_sub_table = { - 'Ganons Tower Exit': 'Inverted Agahnims Tower Exit', - 'Agahnims Tower Exit': 'Inverted Ganons Tower Exit', - 'Dark Sanctuary Hint': 'Inverted Dark Sanctuary Exit', - 'Big Bomb Shop': 'Inverted Links House Exit', - 'Links House Exit': 'Inverted Big Bomb Shop', + #'Ganons Tower Exit': 'Ganons Tower Exit', + #'Agahnims Tower Exit': 'Agahnims Tower Exit' } @@ -1071,10 +1067,7 @@ def connect_entrance(entrancename, exit_name, avail): entrance.connect(region, addresses, target) avail.entrances.remove(entrancename) if avail.coupled: - if exit_name == 'Inverted Dark Sanctuary': - avail.exits.remove('Inverted Dark Sanctuary Exit') - else: - avail.exits.remove(exit_name) + avail.exits.remove(exit_name) world.spoiler.set_entrance(entrance.name, exit.name if exit is not None else region.name, 'entrance', player) logging.getLogger('').debug(f'Connected (entr) {entrance.name} to {exit.name if exit is not None else region.name}') @@ -1197,7 +1190,7 @@ modes = { 'Dark Lake Hylia Shop', 'East Dark World Hint', 'Kakariko Gamble Game', 'Good Bee Cave', 'Long Fairy Cave', 'Bush Covered House', 'Fortune Teller (Light)', 'Lost Woods Gamble', 'Desert Fairy', 'Light Hype Fairy', 'Lake Hylia Fortune Teller', 'Lake Hylia Fairy', - 'Bonk Fairy (Light)', 'Inverted Dark Sanctuary'], + 'Bonk Fairy (Light)'], }, 'fixed_shops': { 'special': 'vanilla', @@ -1221,14 +1214,13 @@ modes = { 'Ice Rod Cave', 'Dam', 'Bonk Rock Cave', 'Library', 'Potion Shop', 'Mini Moldorm Cave', 'Checkerboard Cave', 'Graveyard Cave', 'Cave 45', 'Sick Kids House', 'Blacksmiths Hut', 'Sahasrahlas Hut', 'Aginahs Cave', 'Chicken House', 'Kings Grave', 'Blinds Hideout', - 'Waterfall of Wishing', 'Inverted Bomb Shop', 'Cave Shop (Dark Death Mountain)', + 'Waterfall of Wishing', 'Cave Shop (Dark Death Mountain)', 'Dark World Potion Shop', 'Dark World Lumberjack Shop', 'Dark World Shop', 'Red Shield Shop', 'Kakariko Shop', 'Capacity Upgrade', 'Cave Shop (Lake Hylia)', 'Lumberjack House', 'Snitch Lady (West)', 'Snitch Lady (East)', 'Tavern (Front)', 'Light World Bomb Hut', '20 Rupee Cave', '50 Rupee Cave', 'Hookshot Fairy', 'Palace of Darkness Hint', 'Dark Lake Hylia Ledge Spike Cave', - 'Dark Desert Hint', - 'Links House', 'Inverted Links House', 'Tavern North'] + 'Dark Desert Hint', 'Links House', 'Tavern North'] }, 'old_man_cave': { # have to do old man cave first so lw dungeon don't use up everything 'special': 'old_man_cave_east', @@ -1273,7 +1265,7 @@ modes = { 'Dark Lake Hylia Shop', 'East Dark World Hint', 'Kakariko Gamble Game', 'Good Bee Cave', 'Long Fairy Cave', 'Bush Covered House', 'Fortune Teller (Light)', 'Lost Woods Gamble', 'Desert Fairy', 'Light Hype Fairy', 'Lake Hylia Fortune Teller', 'Lake Hylia Fairy', - 'Bonk Fairy (Light)', 'Inverted Dark Sanctuary'], + 'Bonk Fairy (Light)'], }, 'fixed_shops': { 'special': 'vanilla', @@ -1297,14 +1289,13 @@ modes = { 'Ice Rod Cave', 'Dam', 'Bonk Rock Cave', 'Library', 'Potion Shop', 'Mini Moldorm Cave', 'Checkerboard Cave', 'Graveyard Cave', 'Cave 45', 'Sick Kids House', 'Blacksmiths Hut', 'Sahasrahlas Hut', 'Aginahs Cave', 'Chicken House', 'Kings Grave', 'Blinds Hideout', - 'Waterfall of Wishing', 'Inverted Bomb Shop', 'Cave Shop (Dark Death Mountain)', + 'Waterfall of Wishing', 'Cave Shop (Dark Death Mountain)', 'Dark World Potion Shop', 'Dark World Lumberjack Shop', 'Dark World Shop', 'Red Shield Shop', 'Kakariko Shop', 'Capacity Upgrade', 'Cave Shop (Lake Hylia)', 'Lumberjack House', 'Snitch Lady (West)', 'Snitch Lady (East)', 'Tavern (Front)', 'Light World Bomb Hut', '20 Rupee Cave', '50 Rupee Cave', 'Hookshot Fairy', 'Palace of Darkness Hint', 'Dark Lake Hylia Ledge Spike Cave', - 'Dark Desert Hint', - 'Links House', 'Inverted Links House', 'Tavern North'] + 'Dark Desert Hint', 'Links House', 'Tavern North'] } } }, @@ -1512,7 +1503,6 @@ entrance_map = { 'Hyrule Castle Entrance (West)': 'Hyrule Castle Exit (West)', 'Hyrule Castle Entrance (East)': 'Hyrule Castle Exit (East)', 'Agahnims Tower': 'Agahnims Tower Exit', - 'Inverted Agahnims Tower': 'Inverted Agahnims Tower Exit', 'Thieves Town': 'Thieves Town Exit', 'Skull Woods First Section Door': 'Skull Woods First Section Exit', @@ -1529,10 +1519,8 @@ entrance_map = { 'Dark Death Mountain Ledge (East)': 'Turtle Rock Ledge Exit (East)', 'Turtle Rock Isolated Ledge Entrance': 'Turtle Rock Isolated Ledge Exit', 'Ganons Tower': 'Ganons Tower Exit', - 'Inverted Ganons Tower': 'Inverted Ganons Tower Exit', 'Links House': 'Links House Exit', - 'Inverted Links House': 'Inverted Links House Exit', 'Hyrule Castle Secret Entrance Stairs': 'Hyrule Castle Secret Entrance Exit', @@ -1571,7 +1559,7 @@ entrance_map = { 'Spectacle Rock Cave': 'Spectacle Rock Cave Exit (Top)', 'Paradox Cave (Bottom)': 'Paradox Cave Exit (Bottom)', 'Paradox Cave (Middle)': 'Paradox Cave Exit (Middle)', - 'Paradox Cave (Top)': 'Paradox Cave Exit (Top)', + 'Paradox Cave (Top)': 'Paradox Cave Exit (Top)' } @@ -1606,8 +1594,7 @@ single_entrance_map = { 'Kings Grave': 'Kings Grave', 'Desert Fairy': 'Desert Healer Fairy', 'Light Hype Fairy': 'Swamp Healer Fairy', 'Lake Hylia Fortune Teller': 'Lake Hylia Fortune Teller', 'Lake Hylia Fairy': 'Lake Hylia Healer Fairy', 'Bonk Fairy (Light)': 'Bonk Fairy (Light)', 'Lumberjack House': 'Lumberjack House', 'Dam': 'Dam', - 'Blinds Hideout': 'Blinds Hideout', 'Waterfall of Wishing': 'Waterfall of Wishing', - 'Inverted Bomb Shop': 'Inverted Bomb Shop', 'Inverted Dark Sanctuary': 'Inverted Dark Sanctuary', + 'Blinds Hideout': 'Blinds Hideout', 'Waterfall of Wishing': 'Waterfall of Wishing' } default_dw = { @@ -1616,21 +1603,21 @@ default_dw = { 'Palace of Darkness Exit', 'Swamp Palace Exit', 'Turtle Rock Exit (Front)', 'Turtle Rock Ledge Exit (West)', 'Turtle Rock Ledge Exit (East)', 'Turtle Rock Isolated Ledge Exit', 'Bumper Cave Exit (Top)', 'Bumper Cave Exit (Bottom)', 'Superbunny Cave Exit (Top)', 'Superbunny Cave Exit (Bottom)', - 'Hookshot Cave Front Exit', 'Hookshot Cave Back Exit', 'Ganons Tower Exit', 'Pyramid Exit', + 'Hookshot Cave Front Exit', 'Hookshot Cave Back Exit', 'Pyramid Exit', 'Dark Lake Hylia Healer Fairy', 'Dark Lake Hylia Ledge Healer Fairy', 'Dark Desert Healer Fairy', 'Dark Death Mountain Healer Fairy', 'Cave Shop (Dark Death Mountain)', 'Pyramid Fairy', 'East Dark World Hint', - 'Palace of Darkness Hint', 'Big Bomb Shop', 'Village of Outcasts Shop', 'Dark Lake Hylia Shop', + 'Palace of Darkness Hint', 'Village of Outcasts Shop', 'Dark Lake Hylia Shop', 'Dark World Lumberjack Shop', 'Dark World Potion Shop', 'Dark Lake Hylia Ledge Spike Cave', 'Dark Lake Hylia Ledge Hint', 'Hype Cave', 'Brewery', 'C-Shaped House', 'Chest Game', 'Dark World Hammer Peg Cave', 'Red Shield Shop', 'Dark Sanctuary Hint', 'Fortune Teller (Dark)', 'Archery Game', 'Mire Shed', 'Dark Desert Hint', - 'Spike Cave', 'Skull Back Drop', 'Skull Left Drop', 'Skull Pinball', 'Skull Pot Circle', 'Pyramid', - 'Inverted Agahnims Tower Exit', 'Inverted Dark Sanctuary Exit', 'Inverted Links House Exit' + 'Spike Cave', 'Skull Back Drop', 'Skull Left Drop', 'Skull Pinball', 'Skull Pot Circle', 'Pyramid' + #'Big Bomb Shop', 'Ganons Tower Exit', } default_lw = { - 'Links House Exit', 'Desert Palace Exit (South)', 'Desert Palace Exit (West)', 'Desert Palace Exit (East)', + 'Desert Palace Exit (South)', 'Desert Palace Exit (West)', 'Desert Palace Exit (East)', 'Desert Palace Exit (North)', 'Eastern Palace Exit', 'Tower of Hera Exit', 'Hyrule Castle Exit (South)', - 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)', 'Agahnims Tower Exit', + 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)', 'Hyrule Castle Secret Entrance Exit', 'Kakariko Well Exit', 'Bat Cave Exit', 'Elder House Exit (East)', 'Elder House Exit (West)', 'North Fairy Cave Exit', 'Lost Woods Hideout Exit', 'Lumberjack Tree Exit', 'Two Brothers House Exit (East)', 'Two Brothers House Exit (West)', 'Sanctuary Exit', 'Old Man Cave Exit (East)', @@ -1647,8 +1634,7 @@ default_lw = { 'Mini Moldorm Cave', 'Long Fairy Cave', 'Good Bee Cave', '20 Rupee Cave', '50 Rupee Cave', 'Ice Rod Cave', 'Bonk Rock Cave', 'Library', 'Kakariko Gamble Game', 'Potion Shop', 'Hookshot Fairy', 'Mimic Cave', 'Kakariko Well (top)', 'Hyrule Castle Secret Entrance', 'Bat Cave (right)', 'North Fairy Cave', - 'Lost Woods Hideout (top)', 'Lumberjack Tree (top)', 'Sewer Drop', 'Inverted Ganons Tower Exit', - 'Inverted Big Bomb Shop' + 'Lost Woods Hideout (top)', 'Lumberjack Tree (top)', 'Sewer Drop' } LW_Entrances = ['Elder House (East)', 'Elder House (West)', 'Two Brothers House (East)', 'Two Brothers House (West)', @@ -1669,8 +1655,7 @@ LW_Entrances = ['Elder House (East)', 'Elder House (West)', 'Two Brothers House 'Old Man House (Top)', 'Death Mountain Return Cave (East)', 'Spectacle Rock Cave', 'Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Bottom)', 'Hyrule Castle Secret Entrance Stairs', 'Kakariko Well Cave', 'Bat Cave Cave', 'North Fairy Cave', 'Lost Woods Hideout Stump', - 'Lumberjack Tree Cave', 'Sanctuary', - 'Inverted Ganons Tower', 'Inverted Big Bomb Shop', 'Inverted Pyramid Entrance'] + 'Lumberjack Tree Cave', 'Sanctuary', 'Inverted Pyramid Entrance'] DW_Entrances = ['Bumper Cave (Bottom)', 'Superbunny Cave (Top)', 'Superbunny Cave (Bottom)', 'Hookshot Cave', 'Thieves Town', 'Skull Woods Final Section', 'Ice Palace', 'Misery Mire', 'Palace of Darkness', @@ -1684,8 +1669,7 @@ DW_Entrances = ['Bumper Cave (Bottom)', 'Superbunny Cave (Top)', 'Superbunny Ca 'Dark Lake Hylia Ledge Hint', 'Chest Game', 'Dark Desert Fairy', 'Dark Lake Hylia Ledge Fairy', 'Fortune Teller (Dark)', 'Dark World Hammer Peg Cave', 'Pyramid Entrance', 'Skull Woods First Section Door', 'Skull Woods Second Section Door (East)', - 'Skull Woods Second Section Door (West)', - 'Inverted Dark Sanctuary', 'Inverted Links House', 'Inverted Agahnims Tower'] + 'Skull Woods Second Section Door (West)'] LW_Must_Exit = ['Desert Palace Entrance (East)'] @@ -1696,7 +1680,7 @@ DW_Must_Exit = [('Dark Death Mountain Ledge (East)', 'Dark Death Mountain Ledge Inverted_LW_Must_Exit = [('Desert Palace Entrance (North)', 'Desert Palace Entrance (West)'), 'Desert Palace Entrance (East)', 'Death Mountain Return Cave (West)', 'Two Brothers House (West)', - ('Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)', 'Inverted Ganons Tower')] + ('Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)', 'Agahnims Tower')] Inverted_DW_Must_Exit = [] @@ -1720,7 +1704,7 @@ LH_DM_Connector_List = { 'Fairy Ascension Cave (Bottom)', 'Fairy Ascension Cave (Top)', 'Spiral Cave', 'Spiral Cave (Bottom)', 'Tower of Hera', 'Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Bottom)', 'Spectacle Rock Cave', 'Paradox Cave (Bottom)', 'Paradox Cave (Middle)', 'Paradox Cave (Top)', 'Hookshot Fairy', 'Spike Cave', - 'Dark Death Mountain Fairy', 'Inverted Agahnims Tower', 'Superbunny Cave (Top)', 'Superbunny Cave (Bottom)', + 'Dark Death Mountain Fairy', 'Ganons Tower', 'Superbunny Cave (Top)', 'Superbunny Cave (Bottom)', 'Hookshot Cave', 'Cave Shop (Dark Death Mountain)', 'Turtle Rock'} LH_DM_Exit_Forbidden = { @@ -1732,7 +1716,7 @@ LH_DM_Exit_Forbidden = { # in inverted we put dark sanctuary in west dark world for now Inverted_Dark_Sanctuary_Doors = [ - 'Inverted Dark Sanctuary', 'Fortune Teller (Dark)', 'Brewery', 'C-Shaped House', 'Chest Game', + 'Dark Sanctuary Hint', 'Fortune Teller (Dark)', 'Brewery', 'C-Shaped House', 'Chest Game', 'Dark World Lumberjack Shop', 'Red Shield Shop', 'Bumper Cave (Bottom)', 'Bumper Cave (Top)', 'Thieves Town' ] @@ -1782,9 +1766,9 @@ Inverted_Must_Exit_Invalid_Connections = defaultdict(set, { 'Death Mountain Return Cave (West)': {'Bumper Cave (Top)'}, 'Desert Palace Entrance (North)': {'Desert Palace Entrance (West)'}, 'Desert Palace Entrance (West)': {'Desert Palace Entrance (North)'}, - 'Inverted Ganons Tower': {'Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)'}, - 'Hyrule Castle Entrance (West)': {'Hyrule Castle Entrance (East)', 'Inverted Ganons Tower'}, - 'Hyrule Castle Entrance (East)': {'Hyrule Castle Entrance (West)', 'Inverted Ganons Tower'}, + 'Agahnims Tower': {'Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)'}, + 'Hyrule Castle Entrance (West)': {'Hyrule Castle Entrance (East)', 'Agahnims Tower'}, + 'Hyrule Castle Entrance (East)': {'Hyrule Castle Entrance (West)', 'Agahnims Tower'}, }) Old_Man_Entrances = ['Old Man Cave (East)', @@ -1795,7 +1779,7 @@ Old_Man_Entrances = ['Old Man Cave (East)', 'Spectacle Rock Cave (Bottom)', 'Tower of Hera'] -Inverted_Old_Man_Entrances = ['Dark Death Mountain Fairy', 'Spike Cave', 'Inverted Agahnims Tower'] +Inverted_Old_Man_Entrances = ['Dark Death Mountain Fairy', 'Spike Cave', 'Ganons Tower'] Simple_DM_Non_Connectors = {'Old Man Cave Ledge', 'Spiral Cave (Top)', 'Superbunny Cave (Bottom)', 'Spectacle Rock Cave (Peak)', 'Spectacle Rock Cave (Top)'} @@ -1808,7 +1792,7 @@ Blacksmith_Options = [ '50 Rupee Cave', 'Ice Rod Cave', 'Library', 'Potion Shop', 'Dam', 'Lumberjack House', 'Lake Hylia Fortune Teller', 'Kakariko Gamble Game', 'Eastern Palace', 'Elder House (East)', 'Elder House (West)', 'Two Brothers House (East)', 'Old Man Cave (West)', 'Sanctuary', 'Lumberjack Tree Cave', 'Lost Woods Hideout Stump', 'North Fairy Cave', - 'Bat Cave Cave', 'Kakariko Well Cave', 'Inverted Big Bomb Shop', 'Links House'] + 'Bat Cave Cave', 'Kakariko Well Cave', 'Links House'] Bomb_Shop_Options = [ 'Waterfall of Wishing', 'Capacity Upgrade', 'Bonk Rock Cave', 'Graveyard Cave', 'Checkerboard Cave', 'Cave 45', @@ -1852,8 +1836,7 @@ Inverted_Bomb_Shop_Options = [ 'Fairy Ascension Cave (Top)', 'Spiral Cave', 'Spiral Cave (Bottom)', 'Palace of Darkness', 'Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)', 'Desert Palace Entrance (West)', 'Desert Palace Entrance (North)', - 'Inverted Ganons Tower', 'Inverted Agahnims Tower', 'Inverted Dark Sanctuary', 'Inverted Links House', - 'Inverted Big Bomb Shop'] + Blacksmith_Options + 'Agahnims Tower', 'Ganons Tower', 'Dark Sanctuary Hint', 'Big Bomb Shop', 'Links House'] + Blacksmith_Options # these are connections that cannot be shuffled and always exist. @@ -1861,6 +1844,7 @@ Inverted_Bomb_Shop_Options = [ mandatory_connections = [('Links House S&Q', 'Links House'), ('Sanctuary S&Q', 'Sanctuary'), ('Old Man S&Q', 'Old Man House'), + ('Other World S&Q', 'East Dark World'), ('Lake Hylia Central Island Pier', 'Lake Hylia Central Island'), ('Lake Hylia Central Island Teleporter', 'Dark Lake Hylia Central Island'), ('Zoras River', 'Zoras River'), @@ -1997,10 +1981,10 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Hyrule Castle Ledge Drop', 'Light World'), ] -inverted_mandatory_connections = [('Links House S&Q', 'Inverted Links House'), - ('Dark Sanctuary S&Q', 'Inverted Dark Sanctuary'), +inverted_mandatory_connections = [('Links House S&Q', 'Links House'), + ('Sanctuary S&Q', 'Dark Sanctuary Hint'), ('Old Man S&Q', 'Old Man House'), - ('Castle Ledge S&Q', 'Hyrule Castle Ledge'), + ('Other World S&Q', 'Hyrule Castle Ledge'), ('Lake Hylia Central Island Pier', 'Lake Hylia Central Island'), ('Lake Hylia Island Pier', 'Lake Hylia Island'), ('Lake Hylia Warp', 'Northeast Light World'), @@ -2298,6 +2282,7 @@ default_connections = {'Links House': 'Links House', 'Bumper Cave (Top)': 'Bumper Cave (top)', 'Red Shield Shop': 'Red Shield Shop', 'Dark Sanctuary Hint': 'Dark Sanctuary Hint', + 'Dark Sanctuary Hint Exit': 'West Dark World', 'Fortune Teller (Dark)': 'Fortune Teller (Dark)', 'Dark World Shop': 'Village of Outcasts Shop', 'Dark World Lumberjack Shop': 'Dark World Lumberjack Shop', @@ -2451,11 +2436,11 @@ inverted_default_connections = {'Waterfall of Wishing': 'Waterfall of Wishing', 'Hookshot Cave Back Entrance': 'Hookshot Cave (Back)', 'Mimic Cave': 'Mimic Cave', 'Inverted Pyramid Hole': 'Pyramid', - 'Inverted Links House': 'Inverted Links House', - 'Inverted Links House Exit': 'South Dark World', - 'Inverted Big Bomb Shop': 'Inverted Big Bomb Shop', - 'Inverted Dark Sanctuary': 'Inverted Dark Sanctuary', - 'Inverted Dark Sanctuary Exit': 'West Dark World', + 'Links House': 'Links House', + 'Links House Exit': 'South Dark World', + 'Big Bomb Shop': 'Big Bomb Shop', + 'Dark Sanctuary Hint': 'Dark Sanctuary Hint', + 'Dark Sanctuary Hint Exit': 'West Dark World', 'Old Man Cave (West)': 'Bumper Cave (bottom)', 'Old Man Cave (East)': 'Death Mountain Return Cave (left)', 'Old Man Cave Exit (West)': 'West Dark World', @@ -2581,10 +2566,10 @@ inverted_default_dungeon_connections = [('Desert Palace Entrance (South)', 'Dese ('Dark Death Mountain Ledge (East)', 'Turtle Rock Chest Portal'), ('Turtle Rock Isolated Ledge Exit', 'Dark Death Mountain Isolated Ledge'), ('Turtle Rock Isolated Ledge Entrance', 'Turtle Rock Eye Bridge Portal'), - ('Inverted Ganons Tower', 'Ganons Tower Portal'), - ('Inverted Ganons Tower Exit', 'Hyrule Castle Ledge'), - ('Inverted Agahnims Tower', 'Agahnims Tower Portal'), - ('Inverted Agahnims Tower Exit', 'Dark Death Mountain'), + ('Agahnims Tower', 'Ganons Tower Portal'), + ('Ganons Tower Exit', 'Hyrule Castle Ledge'), + ('Ganons Tower', 'Agahnims Tower Portal'), + ('Agahnims Tower Exit', 'Dark Death Mountain'), ('Turtle Rock Exit (Front)', 'Dark Death Mountain'), ('Ice Palace Exit', 'Dark Lake Hylia') ] @@ -2607,7 +2592,6 @@ indirect_connections = { # ToDo somehow merge this with creation of the locations door_addresses = {'Links House': (0x00, (0x0104, 0x2c, 0x0506, 0x0a9a, 0x0832, 0x0ae8, 0x08b8, 0x0b07, 0x08bf, 0x06, 0xfe, 0x0816, 0x0000)), - 'Inverted Big Bomb Shop': (0x00, (0x0104, 0x2c, 0x0506, 0x0a9a, 0x0832, 0x0ae8, 0x08b8, 0x0b07, 0x08bf, 0x06, 0xfe, 0x0816, 0x0000)), 'Desert Palace Entrance (South)': (0x08, (0x0084, 0x30, 0x0314, 0x0c56, 0x00a6, 0x0ca8, 0x0128, 0x0cc3, 0x0133, 0x0a, 0xfa, 0x0000, 0x0000)), 'Desert Palace Entrance (West)': (0x0A, (0x0083, 0x30, 0x0280, 0x0c46, 0x0003, 0x0c98, 0x0088, 0x0cb3, 0x0090, 0x0a, 0xfd, 0x0000, 0x0000)), 'Desert Palace Entrance (North)': (0x0B, (0x0063, 0x30, 0x0016, 0x0c00, 0x00a2, 0x0c28, 0x0128, 0x0c6d, 0x012f, 0x00, 0x0e, 0x0000, 0x0000)), @@ -2619,7 +2603,6 @@ door_addresses = {'Links House': (0x00, (0x0104, 0x2c, 0x0506, 0x0a9a, 0x0832, 0 'Hyrule Castle Entrance (East)': (0x04, (0x0062, 0x1b, 0x004a, 0x0600, 0x0856, 0x0604, 0x08c8, 0x066d, 0x08d3, 0x00, 0xfa, 0x0000, 0x8158)), 'Inverted Pyramid Entrance': (0x35, (0x0010, 0x1b, 0x0418, 0x0679, 0x06b4, 0x06c6, 0x0728, 0x06e6, 0x0733, 0x07, 0xf9, 0x0000, 0x0000)), 'Agahnims Tower': (0x23, (0x00e0, 0x1b, 0x0032, 0x0600, 0x0784, 0x0634, 0x07f8, 0x066d, 0x0803, 0x00, 0x0a, 0x0000, 0x82be)), - 'Inverted Ganons Tower': (0x23, (0x00e0, 0x1b, 0x0032, 0x0600, 0x0784, 0x0634, 0x07f8, 0x066d, 0x0803, 0x00, 0x0a, 0x0000, 0x82be)), 'Thieves Town': (0x33, (0x00db, 0x58, 0x0b2e, 0x075a, 0x0176, 0x07a8, 0x01f8, 0x07c7, 0x0203, 0x06, 0xfa, 0x0000, 0x0000)), 'Skull Woods First Section Door': (0x29, (0x0058, 0x40, 0x0f4c, 0x01f6, 0x0262, 0x0248, 0x02e8, 0x0263, 0x02ef, 0x0a, 0xfe, 0x0000, 0x0000)), 'Skull Woods Second Section Door (East)': (0x28, (0x0057, 0x40, 0x0eb8, 0x01e6, 0x01c2, 0x0238, 0x0248, 0x0253, 0x024f, 0x0a, 0xfe, 0x0000, 0x0000)), @@ -2667,7 +2650,6 @@ door_addresses = {'Links House': (0x00, (0x0104, 0x2c, 0x0506, 0x0a9a, 0x0832, 0 'Hookshot Cave': (0x39, (0x003c, 0x45, 0x04da, 0x00a3, 0x0cd6, 0x0107, 0x0d48, 0x0112, 0x0d53, 0x0b, 0xfa, 0x0000, 0x0000)), 'Hookshot Cave Back Entrance': (0x3A, (0x002c, 0x45, 0x004c, 0x0000, 0x0c56, 0x0038, 0x0cc8, 0x006f, 0x0cd3, 0x00, 0x0a, 0x0000, 0x0000)), 'Ganons Tower': (0x36, (0x000c, 0x43, 0x0052, 0x0000, 0x0884, 0x0028, 0x08f8, 0x006f, 0x0903, 0x00, 0xfc, 0x0000, 0x0000)), - 'Inverted Agahnims Tower': (0x36, (0x000c, 0x43, 0x0052, 0x0000, 0x0884, 0x0028, 0x08f8, 0x006f, 0x0903, 0x00, 0xfc, 0x0000, 0x0000)), 'Pyramid Entrance': (0x35, (0x0010, 0x5b, 0x0b0e, 0x075a, 0x0674, 0x07a8, 0x06e8, 0x07c7, 0x06f3, 0x06, 0xfa, 0x0000, 0x0000)), 'Skull Woods First Section Hole (West)': ([0xDB84D, 0xDB84E], None), 'Skull Woods First Section Hole (East)': ([0xDB84F, 0xDB850], None), @@ -2734,7 +2716,6 @@ door_addresses = {'Links House': (0x00, (0x0104, 0x2c, 0x0506, 0x0a9a, 0x0832, 0 'Dark World Hammer Peg Cave': (0x7E, (0x0127, 0x62, 0x0894, 0x091e, 0x0492, 0x09a6, 0x0508, 0x098b, 0x050f, 0x00, 0x00, 0x0000, 0x0000)), 'Red Shield Shop': (0x74, (0x0110, 0x5a, 0x079a, 0x06e8, 0x04d6, 0x0738, 0x0548, 0x0755, 0x0553, 0x08, 0xf8, 0x0AA8, 0x0000)), 'Dark Sanctuary Hint': (0x59, (0x0112, 0x53, 0x001e, 0x0400, 0x06e2, 0x0446, 0x0758, 0x046d, 0x075f, 0x00, 0x00, 0x0000, 0x0000)), - 'Inverted Dark Sanctuary': (0x59, (0x0112, 0x53, 0x001e, 0x0400, 0x06e2, 0x0446, 0x0758, 0x046d, 0x075f, 0x00, 0x00, 0x0000, 0x0000)), 'Fortune Teller (Dark)': (0x65, (0x0122, 0x51, 0x0610, 0x04b4, 0x027e, 0x0507, 0x02f8, 0x0523, 0x0303, 0x0a, 0xf6, 0x091E, 0x0000)), 'Dark World Shop': (0x5F, (0x010f, 0x58, 0x1058, 0x0814, 0x02be, 0x0868, 0x0338, 0x0883, 0x0343, 0x0a, 0xf6, 0x0000, 0x0000)), 'Dark World Lumberjack Shop': (0x56, (0x010f, 0x42, 0x041c, 0x0074, 0x04e2, 0x00c7, 0x0558, 0x00e3, 0x055f, 0x0a, 0xf6, 0x0000, 0x0000)), @@ -2748,7 +2729,6 @@ door_addresses = {'Links House': (0x00, (0x0104, 0x2c, 0x0506, 0x0a9a, 0x0832, 0 'Dark Death Mountain Fairy': (0x6F, (0x0115, 0x43, 0x1400, 0x0294, 0x0600, 0x02e8, 0x0678, 0x0303, 0x0685, 0x0a, 0xf6, 0x0000, 0x0000)), 'Mimic Cave': (0x4E, (0x010c, 0x05, 0x07e0, 0x0103, 0x0d00, 0x0156, 0x0d78, 0x0172, 0x0d7d, 0x0b, 0xf5, 0x0000, 0x0000)), 'Big Bomb Shop': (0x52, (0x011c, 0x6c, 0x0506, 0x0a9a, 0x0832, 0x0ae7, 0x08b8, 0x0b07, 0x08bf, 0x06, 0xfa, 0x0816, 0x0000)), - 'Inverted Links House': (0x52, (0x011c, 0x6c, 0x0506, 0x0a9a, 0x0832, 0x0ae7, 0x08b8, 0x0b07, 0x08bf, 0x06, 0xfa, 0x0816, 0x0000)), 'Dark Lake Hylia Shop': (0x73, (0x010f, 0x75, 0x0380, 0x0c6a, 0x0a00, 0x0cb8, 0x0a58, 0x0cd7, 0x0a85, 0x06, 0xfa, 0x0000, 0x0000)), 'Lumberjack House': (0x75, (0x011f, 0x02, 0x049c, 0x0088, 0x04e6, 0x00d8, 0x0558, 0x00f7, 0x0563, 0x08, 0xf8, 0x07AA, 0x0000)), 'Lake Hylia Fortune Teller': (0x72, (0x0122, 0x35, 0x0380, 0x0c6a, 0x0a00, 0x0cb8, 0x0a58, 0x0cd7, 0x0a85, 0x06, 0xfa, 0x0000, 0x0000)), @@ -2759,7 +2739,6 @@ door_addresses = {'Links House': (0x00, (0x0104, 0x2c, 0x0506, 0x0a9a, 0x0832, 0 # value = entrance # # | (entrance #, exit #) exit_ids = {'Links House Exit': (0x01, 0x00), - 'Inverted Links House Exit': (0x01, 0x00), 'Chris Houlihan Room Exit': (None, 0x3D), 'Desert Palace Exit (South)': (0x09, 0x0A), 'Desert Palace Exit (West)': (0x0B, 0x0C), @@ -2771,7 +2750,6 @@ exit_ids = {'Links House Exit': (0x01, 0x00), 'Hyrule Castle Exit (West)': (0x03, 0x02), 'Hyrule Castle Exit (East)': (0x05, 0x04), 'Agahnims Tower Exit': (0x24, 0x25), - 'Inverted Agahnims Tower Exit': (0x24, 0x25), 'Thieves Town Exit': (0x34, 0x35), 'Skull Woods First Section Exit': (0x2A, 0x2B), 'Skull Woods Second Section Exit (East)': (0x29, 0x2A), @@ -2819,7 +2797,6 @@ exit_ids = {'Links House Exit': (0x01, 0x00), 'Hookshot Cave Front Exit': (0x3A, 0x3B), 'Hookshot Cave Back Exit': (0x3B, 0x3C), 'Ganons Tower Exit': (0x37, 0x38), - 'Inverted Ganons Tower Exit': (0x37, 0x38), 'Pyramid Exit': (0x36, 0x37), 'Waterfall of Wishing': 0x5C, 'Dam': 0x4E, @@ -2871,7 +2848,6 @@ exit_ids = {'Links House Exit': (0x01, 0x00), 'East Dark World Hint': 0x69, 'Palace of Darkness Hint': 0x68, 'Big Bomb Shop': 0x53, - 'Inverted Big Bomb Shop': 0x53, 'Village of Outcasts Shop': 0x60, 'Dark Lake Hylia Shop': 0x60, 'Dark World Lumberjack Shop': 0x60, @@ -2885,7 +2861,6 @@ exit_ids = {'Links House Exit': (0x01, 0x00), 'Dark World Hammer Peg Cave': 0x83, 'Red Shield Shop': 0x57, 'Dark Sanctuary Hint': 0x5A, - 'Inverted Dark Sanctuary': 0x5A, 'Fortune Teller (Dark)': 0x66, 'Archery Game': 0x59, 'Mire Shed': 0x5F, @@ -2905,13 +2880,13 @@ exit_ids = {'Links House Exit': (0x01, 0x00), 'Skull Pot Circle': 0x76, 'Pyramid': 0x7B} -ow_prize_table = {'Links House': (0x8b1, 0xb2d), 'Inverted Big Bomb Shop': (0x8b1, 0xb2d), +ow_prize_table = {'Links House': (0x8b1, 0xb2d), 'Desert Palace Entrance (South)': (0x108, 0xd70), 'Desert Palace Entrance (West)': (0x031, 0xca0), 'Desert Palace Entrance (North)': (0x0e1, 0xba0), 'Desert Palace Entrance (East)': (0x191, 0xca0), 'Eastern Palace': (0xf31, 0x620), 'Tower of Hera': (0x8D0, 0x080), 'Hyrule Castle Entrance (South)': (0x7b0, 0x730), 'Hyrule Castle Entrance (West)': (0x700, 0x640), 'Hyrule Castle Entrance (East)': (0x8a0, 0x640), 'Inverted Pyramid Entrance': (0x720, 0x700), - 'Agahnims Tower': (0x7e0, 0x640), 'Inverted Ganons Tower': (0x7e0, 0x640), + 'Agahnims Tower': (0x7e0, 0x640), 'Thieves Town': (0x1d0, 0x780), 'Skull Woods First Section Door': (0x240, 0x280), 'Skull Woods Second Section Door (East)': (0x1a0, 0x240), 'Skull Woods Second Section Door (West)': (0x0c0, 0x1c0), 'Skull Woods Final Section': (0x082, 0x0b0), @@ -2956,7 +2931,6 @@ ow_prize_table = {'Links House': (0x8b1, 0xb2d), 'Inverted Big Bomb Shop': (0x8b 'Hookshot Cave': (0xc80, 0x0c0), 'Hookshot Cave Back Entrance': (0xcf0, 0x004), 'Ganons Tower': (0x8D0, 0x080), - 'Inverted Agahnims Tower': (0x8D0, 0x080), 'Pyramid Entrance': (0x640, 0x7c0), 'Skull Woods First Section Hole (West)': None, 'Skull Woods First Section Hole (East)': None, @@ -3020,7 +2994,6 @@ ow_prize_table = {'Links House': (0x8b1, 0xb2d), 'Inverted Big Bomb Shop': (0x8b 'Dark World Hammer Peg Cave': (0x4c0, 0x940), 'Red Shield Shop': (0x500, 0x680), 'Dark Sanctuary Hint': (0x720, 0x4a0), - 'Inverted Dark Sanctuary': (0x720, 0x4a0), 'Fortune Teller (Dark)': (0x2c0, 0x4c0), 'Dark World Shop': (0x2e0, 0x880), 'Dark World Lumberjack Shop': (0x4e0, 0x0d0), @@ -3033,7 +3006,7 @@ ow_prize_table = {'Links House': (0x8b1, 0xb2d), 'Inverted Big Bomb Shop': (0x8b 'Cave Shop (Dark Death Mountain)': (0xd80, 0x180), 'Dark Death Mountain Fairy': (0x620, 0x2c0), 'Mimic Cave': (0xc80, 0x180), - 'Big Bomb Shop': (0x8b1, 0xb2d), 'Inverted Links House': (0x8b1, 0xb2d), + 'Big Bomb Shop': (0x8b1, 0xb2d), 'Dark Lake Hylia Shop': (0xa40, 0xc40), 'Lumberjack House': (0x4e0, 0x0d0), 'Lake Hylia Fortune Teller': (0xa40, 0xc40), diff --git a/test/inverted/TestInvertedBombRules.py b/test/inverted/TestInvertedBombRules.py index bbcf43dd..72039712 100644 --- a/test/inverted/TestInvertedBombRules.py +++ b/test/inverted/TestInvertedBombRules.py @@ -20,8 +20,8 @@ class TestInvertedBombRules(TestInverted): if entrance_name not in ['Desert Palace Entrance (East)', 'Spectacle Rock Cave', 'Spectacle Rock Cave (Bottom)']: entrance = self.world.get_entrance(entrance_name, 1) entrance.connected_region = None - self.world.get_region('Inverted Big Bomb Shop', 1).entrances = [] - connect_entrance(self.world, entrance, 'Inverted Big Bomb Shop', 1) + self.world.get_region('Big Bomb Shop', 1).entrances = [] + connect_entrance(self.world, entrance, 'Big Bomb Shop', 1) set_inverted_big_bomb_rules(self.world, 1) entrance.connected_region.entrances.remove(entrance) entrance.connected_region = None @@ -35,8 +35,8 @@ class TestInvertedBombRules(TestInverted): def testInvalidEntrances(self): for entrance_name in ['Desert Palace Entrance (East)', 'Spectacle Rock Cave', 'Spectacle Rock Cave (Bottom)']: entrance = self.world.get_entrance(entrance_name, 1) - self.world.get_region('Inverted Big Bomb Shop', 1).entrances = [] - connect_entrance(self.world, entrance, 'Inverted Big Bomb Shop', 1) + self.world.get_region('Big Bomb Shop', 1).entrances = [] + connect_entrance(self.world, entrance, 'Big Bomb Shop', 1) with self.assertRaises(Exception): set_inverted_big_bomb_rules(self.world, 1) entrance.connected_region.entrances.remove(entrance) diff --git a/test/inverted/TestInvertedEntrances.py b/test/inverted/TestInvertedEntrances.py index 89b3e000..a4c2b1d7 100644 --- a/test/inverted/TestInvertedEntrances.py +++ b/test/inverted/TestInvertedEntrances.py @@ -49,15 +49,15 @@ class TestEntrances(TestInverted): ["Tower of Hera", True, ["Moon Pearl", "Hammer", "Hookshot", "Progressive Glove", "Ocarina"]], ["Tower of Hera", True, ["Moon Pearl", "Hammer", "Beat Agahnim 1", "Ocarina", "Hookshot"]], - ["Inverted Agahnims Tower", False, []], - ["Inverted Agahnims Tower", False, [], ["Ocarina", "Lamp"]], - ["Inverted Agahnims Tower", False, [], ["Ocarina", "Progressive Glove"]], - ["Inverted Agahnims Tower", False, [], ["Moon Pearl", "Lamp"]], - ["Inverted Agahnims Tower", False, [], ["Moon Pearl", "Progressive Glove"]], - ["Inverted Agahnims Tower", True, ["Lamp", "Progressive Glove"]], - ["Inverted Agahnims Tower", True, ["Ocarina", "Beat Agahnim 1", "Moon Pearl"]], - ["Inverted Agahnims Tower", True, ["Ocarina", "Progressive Glove", "Progressive Glove", "Moon Pearl"]], - ["Inverted Agahnims Tower", True, ["Ocarina", "Progressive Glove", "Hammer", "Moon Pearl"]], + ["Agahnims Tower", False, []], + ["Agahnims Tower", False, [], ["Ocarina", "Lamp"]], + ["Agahnims Tower", False, [], ["Ocarina", "Progressive Glove"]], + ["Agahnims Tower", False, [], ["Moon Pearl", "Lamp"]], + ["Agahnims Tower", False, [], ["Moon Pearl", "Progressive Glove"]], + ["Agahnims Tower", True, ["Lamp", "Progressive Glove"]], + ["Agahnims Tower", True, ["Ocarina", "Beat Agahnim 1", "Moon Pearl"]], + ["Agahnims Tower", True, ["Ocarina", "Progressive Glove", "Progressive Glove", "Moon Pearl"]], + ["Agahnims Tower", True, ["Ocarina", "Progressive Glove", "Hammer", "Moon Pearl"]], ["Palace of Darkness", False, []], ["Palace of Darkness", False, [], ["Hammer", "Flippers", "Magic Mirror", "Ocarina"]], @@ -104,15 +104,15 @@ class TestEntrances(TestInverted): ["Turtle Rock", True, ["Quake", "Progressive Sword", "Progressive Glove", "Hammer", "Moon Pearl", "Ocarina"]], ["Turtle Rock", True, ["Quake", "Progressive Sword", "Beat Agahnim 1", "Moon Pearl", "Ocarina"]], - ["Inverted Ganons Tower", False, []], - ["Inverted Ganons Tower", False, [], ["Crystal 1"]], - ["Inverted Ganons Tower", False, [], ["Crystal 2"]], - ["Inverted Ganons Tower", False, [], ["Crystal 3"]], - ["Inverted Ganons Tower", False, [], ["Crystal 4"]], - ["Inverted Ganons Tower", False, [], ["Crystal 5"]], - ["Inverted Ganons Tower", False, [], ["Crystal 6"]], - ["Inverted Ganons Tower", False, [], ["Crystal 7"]], - ["Inverted Ganons Tower", True, ["Beat Agahnim 1", "Crystal 1", "Crystal 2", "Crystal 3", "Crystal 4", "Crystal 5", "Crystal 6", "Crystal 7"]], - ["Inverted Ganons Tower", True, ["Moon Pearl", "Progressive Glove", "Progressive Glove", "Crystal 1", "Crystal 2", "Crystal 3", "Crystal 4", "Crystal 5", "Crystal 6", "Crystal 7"]], - ["Inverted Ganons Tower", True, ["Moon Pearl", "Hammer", "Progressive Glove", "Progressive Glove", "Crystal 1", "Crystal 2", "Crystal 3", "Crystal 4", "Crystal 5", "Crystal 6", "Crystal 7"]], + ["Ganons Tower", False, []], + ["Ganons Tower", False, [], ["Crystal 1"]], + ["Ganons Tower", False, [], ["Crystal 2"]], + ["Ganons Tower", False, [], ["Crystal 3"]], + ["Ganons Tower", False, [], ["Crystal 4"]], + ["Ganons Tower", False, [], ["Crystal 5"]], + ["Ganons Tower", False, [], ["Crystal 6"]], + ["Ganons Tower", False, [], ["Crystal 7"]], + ["Ganons Tower", True, ["Beat Agahnim 1", "Crystal 1", "Crystal 2", "Crystal 3", "Crystal 4", "Crystal 5", "Crystal 6", "Crystal 7"]], + ["Ganons Tower", True, ["Moon Pearl", "Progressive Glove", "Progressive Glove", "Crystal 1", "Crystal 2", "Crystal 3", "Crystal 4", "Crystal 5", "Crystal 6", "Crystal 7"]], + ["Ganons Tower", True, ["Moon Pearl", "Hammer", "Progressive Glove", "Progressive Glove", "Crystal 1", "Crystal 2", "Crystal 3", "Crystal 4", "Crystal 5", "Crystal 6", "Crystal 7"]], ]) \ No newline at end of file From 52edfcdddb67133235dfff7ef29c5b7f76cc9d0f Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 7 Dec 2022 22:05:48 -0600 Subject: [PATCH 002/196] Merged Inverted/Open ER code and data --- EntranceShuffle.py | 1868 ++++++++------------------ Main.py | 7 +- source/overworld/EntranceShuffle2.py | 521 ++----- test/inverted/TestInverted.py | 4 +- test/inverted_owg/TestInvertedOWG.py | 4 +- test/stats/EntranceShuffleStats.py | 12 +- 6 files changed, 732 insertions(+), 1684 deletions(-) diff --git a/EntranceShuffle.py b/EntranceShuffle.py index c373ab78..553eac31 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -5,6 +5,8 @@ from collections import defaultdict def link_entrances(world, player): + invFlag = world.mode[player] == 'inverted' + connect_exit(world, 'Chris Houlihan Room Exit', 'Links House', player) # should always match link's house, except for plandos Dungeon_Exits = Dungeon_Exits_Base.copy() @@ -18,6 +20,13 @@ def link_entrances(world, player): for exitname, regionname in mandatory_connections: connect_simple(world, exitname, regionname, player) + if not invFlag: + for exitname, regionname in open_mandatory_connections: + connect_simple(world, exitname, regionname, player) + else: + for exitname, regionname in inverted_mandatory_connections: + connect_simple(world, exitname, regionname, player) + connect_custom(world, player) # if we do not shuffle, set default connections @@ -26,22 +35,56 @@ def link_entrances(world, player): connect_simple(world, exitname, regionname, player) for exitname, regionname in default_dungeon_connections: connect_simple(world, exitname, regionname, player) + if not invFlag: + for exitname, regionname in open_default_connections: + connect_simple(world, exitname, regionname, player) + for exitname, regionname in open_default_dungeon_connections: + connect_simple(world, exitname, regionname, player) + else: + for exitname, regionname in inverted_default_connections: + connect_simple(world, exitname, regionname, player) + for exitname, regionname in inverted_default_dungeon_connections: + connect_simple(world, exitname, regionname, player) elif world.shuffle[player] == 'dungeonssimple': for exitname, regionname in default_connections: connect_simple(world, exitname, regionname, player) + if not invFlag: + for exitname, regionname in open_default_connections: + connect_simple(world, exitname, regionname, player) + else: + for exitname, regionname in inverted_default_connections: + connect_simple(world, exitname, regionname, player) simple_shuffle_dungeons(world, player) elif world.shuffle[player] == 'dungeonsfull': for exitname, regionname in default_connections: connect_simple(world, exitname, regionname, player) + if not invFlag: + for exitname, regionname in open_default_connections: + connect_simple(world, exitname, regionname, player) + else: + for exitname, regionname in inverted_default_connections: + connect_simple(world, exitname, regionname, player) skull_woods_shuffle(world, player) dungeon_exits = list(Dungeon_Exits) - lw_entrances = list(LW_Dungeon_Entrances) - dw_entrances = list(DW_Dungeon_Entrances) + lw_entrances = list(LW_Dungeon_Entrances) if not invFlag else list(Inverted_LW_Dungeon_Entrances) + dw_entrances = list(DW_Dungeon_Entrances) if not invFlag else list(Inverted_DW_Dungeon_Entrances) - if world.mode[player] == 'standard': + if invFlag: + lw_dungeon_entrances_must_exit = list(Inverted_LW_Dungeon_Entrances_Must_Exit) + + # randomize which desert ledge door is a must-exit + if random.randint(0, 1) == 0: + lw_dungeon_entrances_must_exit.append('Desert Palace Entrance (North)') + lw_entrances.append('Desert Palace Entrance (West)') + else: + lw_dungeon_entrances_must_exit.append('Desert Palace Entrance (West)') + lw_entrances.append('Desert Palace Entrance (North)') + dungeon_exits.append(('Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)')) + lw_entrances.append('Hyrule Castle Entrance (South)') + elif 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 world.doorShuffle[player] != 'vanilla': @@ -51,12 +94,42 @@ def link_entrances(world, player): lw_entrances.append('Hyrule Castle Entrance (South)') if not world.shuffle_ganon: - connect_two_way(world, 'Ganons Tower', 'Ganons Tower Exit', player) + connect_two_way(world, 'Agahnims Tower' if world.is_atgt_swapped(player) else 'Ganons Tower', 'Ganons Tower Exit', player) + hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)'] else: - dw_entrances.append('Ganons Tower') + if not invFlag: + dw_entrances.append('Ganons Tower') + else: + lw_entrances.append('Agahnims Tower') dungeon_exits.append('Ganons Tower Exit') + hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)', 'Agahnims Tower'] - if world.mode[player] == 'standard': + if invFlag: + # shuffle aga door first. If it's on HC ledge, remaining HC ledge door must be must-exit + all_entrances_aga = lw_entrances + dw_entrances + aga_doors = [i for i in all_entrances_aga] + random.shuffle(aga_doors) + aga_door = aga_doors.pop() + + if aga_door in hc_ledge_entrances: + lw_entrances.remove(aga_door) + hc_ledge_entrances.remove(aga_door) + + random.shuffle(hc_ledge_entrances) + hc_ledge_must_exit = hc_ledge_entrances.pop() + lw_entrances.remove(hc_ledge_must_exit) + lw_dungeon_entrances_must_exit.append(hc_ledge_must_exit) + + if aga_door in lw_entrances: + lw_entrances.remove(aga_door) + elif aga_door in dw_entrances: + dw_entrances.remove(aga_door) + + connect_two_way(world, aga_door, 'Agahnims Tower Exit', player) + dungeon_exits.remove('Agahnims Tower Exit') + + connect_mandatory_exits(world, lw_entrances, dungeon_exits, lw_dungeon_entrances_must_exit, player) + elif world.mode[player] == 'standard': # rest of hyrule castle must be in light world, so it has to be the one connected to east exit of desert hyrule_castle_exits = [('Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)')] connect_mandatory_exits(world, lw_entrances, hyrule_castle_exits, list(LW_Dungeon_Entrances_Must_Exit), player) @@ -69,23 +142,25 @@ def link_entrances(world, player): connect_caves(world, lw_entrances, [], hyrule_castle_exits, player) else: connect_mandatory_exits(world, lw_entrances, dungeon_exits, list(LW_Dungeon_Entrances_Must_Exit), player) - connect_mandatory_exits(world, dw_entrances, dungeon_exits, list(DW_Dungeon_Entrances_Must_Exit), player) + + if not invFlag: + connect_mandatory_exits(world, dw_entrances, dungeon_exits, list(DW_Dungeon_Entrances_Must_Exit), player) connect_caves(world, lw_entrances, dw_entrances, dungeon_exits, player) elif world.shuffle[player] == 'simple': simple_shuffle_dungeons(world, player) - old_man_entrances = list(Old_Man_Entrances) + old_man_entrances = list(Old_Man_Entrances) if not invFlag else list(Inverted_Old_Man_Entrances) caves = list(Cave_Exits) three_exit_caves = list(Cave_Three_Exits) single_doors = list(Single_Cave_Doors) - bomb_shop_doors = list(Bomb_Shop_Single_Cave_Doors) - blacksmith_doors = list(Blacksmith_Single_Cave_Doors) + ['Links House'] - door_targets = list(Single_Cave_Targets) + bomb_shop_doors = list(Bomb_Shop_Single_Cave_Doors) if not invFlag else list(Inverted_Bomb_Shop_Single_Cave_Doors) + blacksmith_doors = list(Blacksmith_Single_Cave_Doors) + (['Links House'] if not invFlag else []) + door_targets = list(Single_Cave_Targets) if not invFlag else list(Inverted_Single_Cave_Targets) # we shuffle all 2 entrance caves as pairs as a start # start with the ones that need to be directed - two_door_caves = list(Two_Door_Caves_Directional) + two_door_caves = list(Two_Door_Caves_Directional) if not invFlag else list(Inverted_Two_Door_Caves_Directional) random.shuffle(two_door_caves) random.shuffle(caves) while two_door_caves: @@ -95,7 +170,7 @@ def link_entrances(world, player): connect_two_way(world, entrance2, exit2, player) # now the remaining pairs - two_door_caves = list(Two_Door_Caves) + two_door_caves = list(Two_Door_Caves) if not invFlag else list(Inverted_Two_Door_Caves) random.shuffle(two_door_caves) while two_door_caves: entrance1, entrance2 = two_door_caves.pop() @@ -105,9 +180,12 @@ 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_LH_Doors_Open] + if not invFlag: + links_house_doors = [i for i in LW_Single_Cave_Doors if i not in Isolated_LH_Doors_Open] + else: + links_house_doors = [i for i in DW_Single_Cave_Doors if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_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 match link's house @@ -115,19 +193,46 @@ def link_entrances(world, player): bomb_shop_doors.remove(links_house) if links_house in blacksmith_doors: blacksmith_doors.remove(links_house) + if links_house in old_man_entrances: + old_man_entrances.remove(links_house) + if links_house in single_doors: + single_doors.remove(links_house) + + if invFlag: + # place dark sanc + 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) # 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)', - '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() - remaining_entrances.extend(old_man_entrances) - random.shuffle(remaining_entrances) - old_man_entrance = remaining_entrances.pop() - connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)', player) + if not invFlag: + remaining_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)'] + + remaining_entrances.extend(old_man_entrances) + random.shuffle(remaining_entrances) + old_man_entrance = remaining_entrances.pop() + connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)', player) + else: + remaining_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)', + 'Death Mountain Return Cave (East)', 'Spiral Cave', 'Old Man House (Top)', 'Spectacle Rock Cave', + 'Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Bottom)'] + + # place old man, bumper cave bottom to DDM entrances not in east bottom + connect_two_way(world, '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': + bomb_shop_doors.remove('Spike Cave') + bomb_shop_doors.extend(old_man_entrances) + # add old man house to ensure it is always somewhere on light death mountain caves.extend(list(Old_Man_House)) caves.extend(list(three_exit_caves)) @@ -153,49 +258,83 @@ def link_entrances(world, player): # tavern back door cannot be shuffled yet connect_doors(world, ['Tavern North'], ['Tavern'], player) + assert(len(single_doors) == len(door_targets)) + # place remaining doors connect_doors(world, single_doors, door_targets, player) elif world.shuffle[player] == 'restricted': simple_shuffle_dungeons(world, player) - lw_entrances = list(LW_Entrances + LW_Single_Cave_Doors + Old_Man_Entrances) - dw_entrances = list(DW_Entrances + DW_Single_Cave_Doors) - dw_must_exits = list(DW_Entrances_Must_Exit) - old_man_entrances = list(Old_Man_Entrances) - caves = list(Cave_Exits + Cave_Three_Exits) - single_doors = list(Single_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) - door_targets = list(Single_Cave_Targets) + if not invFlag: + lw_entrances = list(LW_Entrances + LW_Single_Cave_Doors + Old_Man_Entrances) + dw_entrances = list(DW_Entrances + DW_Single_Cave_Doors) + dw_must_exits = list(DW_Entrances_Must_Exit) + old_man_entrances = list(Old_Man_Entrances) + caves = list(Cave_Exits + Cave_Three_Exits) + single_doors = list(Single_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) + door_targets = list(Single_Cave_Targets) + else: + lw_entrances = list(Inverted_LW_Entrances + Inverted_LW_Single_Cave_Doors) + dw_entrances = list(Inverted_DW_Entrances + Inverted_DW_Single_Cave_Doors + Inverted_Old_Man_Entrances) + lw_must_exits = list(Inverted_LW_Entrances_Must_Exit) + old_man_entrances = list(Inverted_Old_Man_Entrances) + caves = list(Cave_Exits + Cave_Three_Exits + Old_Man_House) + single_doors = list(Single_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 + Inverted_Blacksmith_Multi_Cave_Doors) + door_targets = list(Inverted_Single_Cave_Targets) # 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_entrances if i not in Isolated_LH_Doors_Open] + if not invFlag: + links_house_doors = [i for i in lw_entrances if i not in Isolated_LH_Doors_Open] + else: + links_house_doors = [i for i in dw_entrances if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_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 match link's house - if links_house in lw_entrances: - lw_entrances.remove(links_house) + if not invFlag: + if links_house in lw_entrances: + lw_entrances.remove(links_house) + else: + if links_house in dw_entrances: + dw_entrances.remove(links_house) + + if invFlag: + # place dark sanc + 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) # tavern back door cannot be shuffled yet connect_doors(world, ['Tavern North'], ['Tavern'], player) - # in restricted, the only mandatory exits are in dark world - connect_mandatory_exits(world, dw_entrances, caves, dw_must_exits, 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) + else: + connect_mandatory_exits(world, lw_entrances, caves, lw_must_exits, player) # place old man, has limited options # exit has to come from specific set of doors, the entrance is free to move about - old_man_entrances = [door for door in old_man_entrances if door in lw_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) - lw_entrances.remove(old_man_exit) + if not invFlag: + lw_entrances.remove(old_man_exit) + else: + dw_entrances.remove(old_man_exit) # place blacksmith, has limited options all_entrances = lw_entrances + dw_entrances - # cannot place it anywhere already taken (or that are otherwise not eligable for placement) + # cannot place it anywhere already taken (or that are otherwise not eligible for placement) blacksmith_doors = [door for door in blacksmith_doors if door in all_entrances] random.shuffle(blacksmith_doors) blacksmith_hut = blacksmith_doors.pop() @@ -208,7 +347,7 @@ def link_entrances(world, player): # place bomb shop, has limited options all_entrances = lw_entrances + dw_entrances - # cannot place it anywhere already taken (or that are otherwise not eligable 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 all_entrances] random.shuffle(bomb_shop_doors) bomb_shop = bomb_shop_doors.pop() @@ -226,13 +365,17 @@ def link_entrances(world, player): removed = True # place the old man cave's entrance somewhere in the light world - random.shuffle(lw_entrances) - old_man_entrance = lw_entrances.pop() + if not invFlag: + random.shuffle(lw_entrances) + old_man_entrance = lw_entrances.pop() + else: + random.shuffle(dw_entrances) + old_man_entrance = dw_entrances.pop() connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)', player) - # place Old Man House in Light World - connect_caves(world, lw_entrances, [], list(Old_Man_House), player) #for multiple seeds - + if not invFlag: + # place Old Man House in Light World + connect_caves(world, lw_entrances, [], list(Old_Man_House), player) #for multiple seeds # now scramble the rest connect_caves(world, lw_entrances, dw_entrances, caves, player) @@ -249,16 +392,35 @@ def link_entrances(world, player): elif world.shuffle[player] == 'full': skull_woods_shuffle(world, player) - lw_entrances = list(LW_Entrances + LW_Dungeon_Entrances + LW_Single_Cave_Doors + Old_Man_Entrances) - dw_entrances = list(DW_Entrances + DW_Dungeon_Entrances + DW_Single_Cave_Doors) - 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) - old_man_house = list(Old_Man_House) + if not invFlag: + lw_entrances = list(LW_Entrances + LW_Dungeon_Entrances + LW_Single_Cave_Doors + Old_Man_Entrances) + dw_entrances = list(DW_Entrances + DW_Dungeon_Entrances + DW_Single_Cave_Doors) + 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) + old_man_house = list(Old_Man_House) + else: + lw_entrances = list(Inverted_LW_Entrances + Inverted_LW_Dungeon_Entrances + Inverted_LW_Single_Cave_Doors) + 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 + Inverted_Blacksmith_Multi_Cave_Doors) + door_targets = list(Inverted_Single_Cave_Targets) + old_man_house = list(Old_Man_House) + + # randomize which desert ledge door is a must-exit + if random.randint(0, 1) == 0: + lw_must_exits.append('Desert Palace Entrance (North)') + lw_entrances.append('Desert Palace Entrance (West)') + else: + lw_must_exits.append('Desert Palace Entrance (West)') + lw_entrances.append('Desert Palace Entrance (North)') # tavern back door cannot be shuffled yet connect_doors(world, ['Tavern North'], ['Tavern'], player) @@ -266,33 +428,75 @@ def link_entrances(world, player): 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 world.doorShuffle[player] != 'vanilla': + elif not invFlag and world.doorShuffle[player] != 'vanilla': lw_entrances.append('Hyrule Castle Entrance (South)') 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)') if not world.shuffle_ganon: - connect_two_way(world, 'Ganons Tower', 'Ganons Tower Exit', player) + connect_two_way(world, 'Ganons Tower' if not world.is_atgt_swapped(player) else 'Agahnims Tower', 'Ganons Tower Exit', player) + hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)'] else: - dw_entrances.append('Ganons Tower') + if not invFlag: + dw_entrances.append('Ganons Tower') + else: + lw_entrances.append('Agahnims Tower') caves.append('Ganons Tower Exit') + hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)', 'Agahnims Tower'] + + if invFlag: + # shuffle aga door first. if it's on hc ledge, then one other hc ledge door has to be must_exit + all_entrances_aga = lw_entrances + dw_entrances + aga_doors = [i for i in all_entrances_aga if world.shufflelinks[player] or i != 'Big Bomb Shop'] + random.shuffle(aga_doors) + aga_door = aga_doors.pop() + + if aga_door in hc_ledge_entrances: + lw_entrances.remove(aga_door) + hc_ledge_entrances.remove(aga_door) + + random.shuffle(hc_ledge_entrances) + hc_ledge_must_exit = hc_ledge_entrances.pop() + lw_entrances.remove(hc_ledge_must_exit) + lw_must_exits.append(hc_ledge_must_exit) + if aga_door in lw_entrances: + lw_entrances.remove(aga_door) + elif aga_door in dw_entrances: + dw_entrances.remove(aga_door) + connect_two_way(world, aga_door, 'Agahnims Tower Exit', player) + caves.remove('Agahnims Tower Exit') # 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_entrances + lw_must_exits if i not in Isolated_LH_Doors_Open] + if not invFlag: + links_house_doors = [i for i in lw_entrances + lw_must_exits if i not in Isolated_LH_Doors_Open] + else: + links_house_doors = [i for i in dw_entrances if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_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 match link's house - if links_house in lw_entrances: - lw_entrances.remove(links_house) - if links_house in lw_must_exits: - lw_must_exits.remove(links_house) + if not invFlag: + if links_house in lw_entrances: + lw_entrances.remove(links_house) + if links_house in lw_must_exits: + lw_must_exits.remove(links_house) + else: + if links_house in dw_entrances: + dw_entrances.remove(links_house) + + # place dark sanc + 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) # 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 + # we also places the Old Man House at this time to make sure he can be connected to the desert one way + # no dw must exits in inverted, but we randomize whether cave is in light or dark world if random.randint(0, 1) == 0: caves += old_man_house connect_mandatory_exits(world, lw_entrances, caves, lw_must_exits, player) @@ -302,35 +506,46 @@ def link_entrances(world, player): pass else: #if the cave wasn't placed we get here connect_caves(world, lw_entrances, [], old_man_house, player) - connect_mandatory_exits(world, dw_entrances, caves, dw_must_exits, player) + if not invFlag: + connect_mandatory_exits(world, dw_entrances, caves, dw_must_exits, player) else: - connect_mandatory_exits(world, dw_entrances, caves, dw_must_exits, player) - caves += old_man_house - connect_mandatory_exits(world, lw_entrances, caves, lw_must_exits, player) - try: - caves.remove(old_man_house[0]) - except ValueError: - pass - else: # if the cave wasn't placed we get here - connect_caves(world, lw_entrances, [], old_man_house, player) + if not invFlag: + connect_mandatory_exits(world, dw_entrances, caves, dw_must_exits, player) + caves += old_man_house + connect_mandatory_exits(world, lw_entrances, caves, lw_must_exits, player) + try: + caves.remove(old_man_house[0]) + except ValueError: + pass + else: # if the cave wasn't placed we get here + connect_caves(world, lw_entrances, [], old_man_house, player) + else: + connect_caves(world, dw_entrances, [], old_man_house, player) + connect_mandatory_exits(world, lw_entrances, caves, lw_must_exits, player) + if world.mode[player] == 'standard': # rest of hyrule castle must be in light world connect_caves(world, lw_entrances, [], [('Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)')], player) # in full, Sanc must be in light world, so must all of HC if door shuffle is on - elif world.doorShuffle[player] != 'vanilla': + elif not invFlag and world.doorShuffle[player] != 'vanilla': connect_caves(world, lw_entrances, [], [('Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)', 'Hyrule Castle Exit (South)')], player) # place old man, has limited options # exit has to come from specific set of doors, the entrance is free to move about - old_man_entrances = [door for door in old_man_entrances if door in lw_entrances] + old_man_entrances = [door for door in old_man_entrances if door in lw_entrances + (dw_entrances if invFlag else [])] 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) - lw_entrances.remove(old_man_exit) + if old_man_exit in dw_entrances: + dw_entrances.remove(old_man_exit) + old_man_world = 'dark' + elif old_man_exit in lw_entrances: + lw_entrances.remove(old_man_exit) + old_man_world = 'light' # place blacksmith, has limited options all_entrances = lw_entrances + dw_entrances - # cannot place it anywhere already taken (or that are otherwise not eligable for placement) + # cannot place it anywhere already taken (or that are otherwise not eligible for placement) blacksmith_doors = [door for door in blacksmith_doors if door in all_entrances] random.shuffle(blacksmith_doors) blacksmith_hut = blacksmith_doors.pop() @@ -343,7 +558,7 @@ def link_entrances(world, player): # place bomb shop, has limited options all_entrances = lw_entrances + dw_entrances - # cannot place it anywhere already taken (or that are otherwise not eligable 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 all_entrances] random.shuffle(bomb_shop_doors) bomb_shop = bomb_shop_doors.pop() @@ -360,8 +575,13 @@ def link_entrances(world, player): lw_entrances.remove('Bonk Fairy (Light)') removed = True - # place the old man cave's entrance somewhere in the light world - old_man_entrance = lw_entrances.pop() + # place the old man cave's entrance somewhere in the same world he'll exit from + if old_man_world == 'light': + random.shuffle(lw_entrances) + old_man_entrance = lw_entrances.pop() + elif old_man_world == 'dark': + random.shuffle(dw_entrances) + old_man_entrance = dw_entrances.pop() connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)', player) # now scramble the rest @@ -380,14 +600,32 @@ def link_entrances(world, player): elif world.shuffle[player] == 'crossed': skull_woods_shuffle(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) + if not invFlag: + 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) + 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) + else: + entrances = list(Inverted_LW_Entrances + Inverted_LW_Dungeon_Entrances + Inverted_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 + Inverted_Blacksmith_Multi_Cave_Doors) + door_targets = list(Inverted_Single_Cave_Targets) + + # randomize which desert ledge door is a must-exit + if random.randint(0, 1) == 0: + must_exits.append('Desert Palace Entrance (North)') + entrances.append('Desert Palace Entrance (West)') + else: + must_exits.append('Desert Palace Entrance (West)') + entrances.append('Desert Palace Entrance (North)') # tavern back door cannot be shuffled yet connect_doors(world, ['Tavern North'], ['Tavern'], player) @@ -400,17 +638,39 @@ def link_entrances(world, player): entrances.append('Hyrule Castle Entrance (South)') if not world.shuffle_ganon: - connect_two_way(world, 'Ganons Tower', 'Ganons Tower Exit', player) + connect_two_way(world, 'Ganons Tower' if not world.is_atgt_swapped(player) else 'Agahnims Tower', 'Ganons Tower Exit', player) + hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)'] else: - entrances.append('Ganons Tower') + entrances.append('Ganons Tower' if not world.is_atgt_swapped(player) else 'Agahnims Tower') caves.append('Ganons Tower Exit') + hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)', 'Agahnims Tower'] + if invFlag: + # shuffle aga door. if it's on hc ledge, then one other hc ledge door has to be must_exit + aga_choices = [x for x in entrances if world.shufflelinks[player] or x != 'Big Bomb Shop'] + aga_door = random.choice(aga_choices) + + if aga_door in hc_ledge_entrances: + hc_ledge_entrances.remove(aga_door) + + random.shuffle(hc_ledge_entrances) + hc_ledge_must_exit = hc_ledge_entrances.pop() + entrances.remove(hc_ledge_must_exit) + must_exits.append(hc_ledge_must_exit) + + entrances.remove(aga_door) + connect_two_way(world, aga_door, 'Agahnims Tower Exit', player) + caves.remove('Agahnims Tower Exit') + # 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 entrances + must_exits if i not in Isolated_LH_Doors_Open] - if world.doorShuffle[player] == 'crossed' and world.intensity[player] >= 3: + if not invFlag: + links_house_doors = [i for i in entrances + must_exits if i not in Isolated_LH_Doors_Open] + else: + links_house_doors = [i for i in entrances + must_exits if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_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'] links_house_doors = [i for i in links_house_doors if i not in exclusions] @@ -422,6 +682,14 @@ def link_entrances(world, player): elif links_house in must_exits: must_exits.remove(links_house) + if invFlag: + # place dark sanc + 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) + #place must-exit caves connect_mandatory_exits(world, entrances, caves, must_exits, player) @@ -438,17 +706,17 @@ def link_entrances(world, player): entrances.remove(old_man_exit) # place blacksmith, has limited options - # cannot place it anywhere already taken (or that are otherwise not eligable for placement) + # cannot place it anywhere already taken (or that are otherwise not eligible for placement) blacksmith_doors = [door for door in blacksmith_doors if door in entrances] random.shuffle(blacksmith_doors) blacksmith_hut = blacksmith_doors.pop() connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player) entrances.remove(blacksmith_hut) - bomb_shop_doors.extend(blacksmith_doors) + if not invFlag: + bomb_shop_doors.extend(blacksmith_doors) # place bomb shop, has limited options - - # cannot place it anywhere already taken (or that are otherwise not eligable 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] random.shuffle(bomb_shop_doors) bomb_shop = bomb_shop_doors.pop() @@ -481,31 +749,54 @@ def link_entrances(world, player): elif world.shuffle[player] == 'insanity': # beware ye who enter here - entrances_must_exits = DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit + LW_Dungeon_Entrances_Must_Exit + ['Skull Woods Second Section Door (West)'] + if not invFlag: + entrances_must_exits = DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit + LW_Dungeon_Entrances_Must_Exit + ['Skull Woods Second Section Door (West)'] - doors = LW_Entrances + LW_Dungeon_Entrances + LW_Dungeon_Entrances_Must_Exit + ['Kakariko Well Cave', 'Bat Cave Cave', 'North Fairy Cave', 'Sanctuary', 'Lost Woods Hideout Stump', 'Lumberjack Tree Cave'] + Old_Man_Entrances +\ - 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 - exit_pool = list(doors) + doors = LW_Entrances + LW_Dungeon_Entrances + LW_Dungeon_Entrances_Must_Exit + ['Kakariko Well Cave', 'Bat Cave Cave', 'North Fairy Cave', 'Sanctuary', 'Lost Woods Hideout Stump', 'Lumberjack Tree Cave'] + Old_Man_Entrances +\ + 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 + exit_pool = list(doors) - # TODO: there are other possible entrances we could support here by way of exiting from a connector, - # and rentering to find bomb shop. However appended list here is all those that we currently have - # bomb shop logic for. - # Specifically we could potentially add: 'Dark Death Mountain Ledge (East)' and doors associated with pits - bomb_shop_doors = list(Bomb_Shop_Single_Cave_Doors + Bomb_Shop_Multi_Cave_Doors+['Desert Palace Entrance (East)', 'Turtle Rock Isolated Ledge Entrance', 'Bumper Cave (Top)', 'Hookshot Cave Back Entrance']) - blacksmith_doors = list(Blacksmith_Single_Cave_Doors + Blacksmith_Multi_Cave_Doors) - door_targets = list(Single_Cave_Targets) + # TODO: there are other possible entrances we could support here by way of exiting from a connector, + # and rentering to find bomb shop. However appended list here is all those that we currently have + # bomb shop logic for. + # Specifically we could potentially add: 'Dark Death Mountain Ledge (East)' and doors associated with pits + bomb_shop_doors = list(Bomb_Shop_Single_Cave_Doors + Bomb_Shop_Multi_Cave_Doors+['Desert Palace Entrance (East)', 'Turtle Rock Isolated Ledge Entrance', 'Bumper Cave (Top)', 'Hookshot Cave Back Entrance']) + blacksmith_doors = list(Blacksmith_Single_Cave_Doors + Blacksmith_Multi_Cave_Doors) + door_targets = list(Single_Cave_Targets) + else: + 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 +\ + Inverted_DW_Entrances + Inverted_DW_Dungeon_Entrances + ['Skull Woods First Section Door', 'Skull Woods Second Section Door (East)', 'Skull Woods Second Section Door (West)'] +\ + Inverted_LW_Single_Cave_Doors + Inverted_DW_Single_Cave_Doors + ['Desert Palace Entrance (West)', 'Desert Palace Entrance (North)'] + exit_pool = list(doors) + + # TODO: there are other possible entrances we could support here by way of exiting from a connector, + # and rentering to find bomb shop. However appended list here is all those that we currently have + # bomb shop logic for. + # Specifically we could potentially add: 'Dark Death Mountain Ledge (East)' and doors associated with pits + bomb_shop_doors = list(Inverted_Bomb_Shop_Single_Cave_Doors + Inverted_Bomb_Shop_Multi_Cave_Doors + ['Turtle Rock Isolated Ledge Entrance', 'Hookshot Cave Back Entrance']) + blacksmith_doors = list(Inverted_Blacksmith_Single_Cave_Doors + Inverted_Blacksmith_Multi_Cave_Doors) + door_targets = list(Inverted_Single_Cave_Targets) + + # randomize which desert ledge door is a must-exit + if random.randint(0, 1) == 0: + entrances_must_exits.append('Desert Palace Entrance (North)') + else: + entrances_must_exits.append('Desert Palace Entrance (West)') random.shuffle(doors) old_man_entrances = list(Old_Man_Entrances) + ['Tower of Hera'] + if invFlag: + old_man_entrances += list(Inverted_Old_Man_Entrances) + ['Ganons Tower'] caves = Cave_Exits + Dungeon_Exits + Cave_Three_Exits + ['Old Man House Exit (Bottom)', 'Old Man House Exit (Top)', 'Skull Woods First Section Exit', 'Skull Woods Second Section Exit (East)', 'Skull Woods Second Section Exit (West)', 'Kakariko Well Exit', 'Bat Cave Exit', 'North Fairy Cave Exit', 'Lost Woods Hideout Exit', 'Lumberjack Tree Exit', 'Sanctuary Exit'] # shuffle up holes - hole_entrances = ['Kakariko Well Drop', 'Bat Cave Drop', 'North Fairy Cave Drop', 'Lost Woods Hideout Drop', 'Lumberjack Tree Tree', 'Sanctuary Grave', 'Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', 'Skull Woods Second Section Hole'] @@ -523,21 +814,23 @@ def link_entrances(world, player): else: hole_entrances.append('Hyrule Castle Secret Entrance Drop') hole_targets.append('Hyrule Castle Secret Entrance') - doors.append('Hyrule Castle Secret Entrance Stairs') - 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', 'Ganons Tower Exit', player) - connect_two_way(world, 'Pyramid Entrance', 'Pyramid Exit', player) - connect_entrance(world, 'Pyramid Hole', 'Pyramid', player) + connect_two_way(world, 'Ganons Tower' if not world.is_atgt_swapped(player) else 'Agahnims Tower', 'Ganons Tower Exit', player) + connect_two_way(world, 'Pyramid Entrance' if not invFlag else 'Inverted Pyramid Entrance', 'Pyramid Exit', player) + connect_entrance(world, 'Pyramid Hole' if not invFlag else 'Inverted Pyramid Hole', 'Pyramid', player) else: caves.extend(['Ganons Tower Exit', 'Pyramid Exit']) - hole_entrances.append('Pyramid Hole') + hole_entrances.append('Pyramid Hole' if not invFlag else 'Inverted Pyramid Hole') hole_targets.append('Pyramid') - entrances_must_exits.append('Pyramid Entrance') - exit_pool.extend(['Ganons Tower', 'Pyramid Entrance']) - doors.extend(['Ganons Tower', 'Pyramid Entrance']) + if not invFlag: + entrances_must_exits.append('Pyramid Entrance') + exit_pool.extend(['Ganons Tower', 'Pyramid Entrance'] if not invFlag else ['Agahnims Tower', 'Inverted Pyramid Entrance']) + doors.extend(['Ganons Tower', 'Pyramid Entrance'] if not invFlag else ['Agahnims Tower', 'Inverted Pyramid Entrance']) random.shuffle(hole_entrances) random.shuffle(hole_targets) @@ -555,15 +848,19 @@ def link_entrances(world, player): caves.append(('Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)')) else: doors.append('Hyrule Castle Entrance (South)') - exit_pool.append('Hyrule Castle Entrance (South)') caves.append(('Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)')) + if not invFlag: + exit_pool.append('Hyrule Castle Entrance (South)') # 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 doors if i not in Isolated_LH_Doors_Open] - if world.doorShuffle[player] == 'crossed' and world.intensity[player] >= 3: + if not invFlag: + links_house_doors = [i for i in doors if i not in Isolated_LH_Doors_Open] + else: + links_house_doors = [i for i in doors if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_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'] links_house_doors = [i for i in links_house_doors if i not in exclusions] @@ -573,6 +870,15 @@ def link_entrances(world, player): exit_pool.remove(links_house) doors.remove(links_house) + if invFlag: + # place dark sanc + sanc_doors = [door for door in Inverted_Dark_Sanctuary_Doors if door in exit_pool] + 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) + # now let's deal with mandatory reachable stuff def extract_reachable_exit(cavelist): random.shuffle(cavelist) @@ -663,713 +969,11 @@ def link_entrances(world, player): world.powder_patch_required[player] = True # check for ganon location - if world.get_entrance('Pyramid Hole', player).connected_region.name != 'Pyramid': + if world.get_entrance('Pyramid Hole' if not invFlag else 'Inverted Pyramid Hole', player).connected_region.name != 'Pyramid': world.ganon_at_pyramid[player] = False # check for Ganon's Tower location - if world.get_entrance('Ganons Tower', player).connected_region.name != 'Ganons Tower Portal': - world.ganonstower_vanilla[player] = False - -def link_inverted_entrances(world, player): - # Link's house shuffled freely, Houlihan set in mandatory_connections - - Dungeon_Exits = Inverted_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() - - unbias_some_entrances(Dungeon_Exits, Cave_Exits, Old_Man_House, Cave_Three_Exits) - - # setup mandatory connections - for exitname, regionname in inverted_mandatory_connections: - connect_simple(world, exitname, regionname, player) - - # if we do not shuffle, set default connections - if world.shuffle[player] == 'vanilla': - for exitname, regionname in inverted_default_connections: - connect_simple(world, exitname, regionname, player) - for exitname, regionname in inverted_default_dungeon_connections: - connect_simple(world, exitname, regionname, player) - elif world.shuffle[player] == 'dungeonssimple': - for exitname, regionname in inverted_default_connections: - connect_simple(world, exitname, regionname, player) - - simple_shuffle_dungeons(world, player) - elif world.shuffle[player] == 'dungeonsfull': - for exitname, regionname in inverted_default_connections: - connect_simple(world, exitname, regionname, player) - - skull_woods_shuffle(world, player) - - dungeon_exits = list(Dungeon_Exits) - lw_entrances = list(Inverted_LW_Dungeon_Entrances) - lw_dungeon_entrances_must_exit = list(Inverted_LW_Dungeon_Entrances_Must_Exit) - dw_entrances = list(Inverted_DW_Dungeon_Entrances) - - # randomize which desert ledge door is a must-exit - if random.randint(0, 1) == 0: - lw_dungeon_entrances_must_exit.append('Desert Palace Entrance (North)') - lw_entrances.append('Desert Palace Entrance (West)') - else: - lw_dungeon_entrances_must_exit.append('Desert Palace Entrance (West)') - lw_entrances.append('Desert Palace Entrance (North)') - - dungeon_exits.append(('Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)')) - lw_entrances.append('Hyrule Castle Entrance (South)') - - if not world.shuffle_ganon: - connect_two_way(world, 'Agahnims Tower', 'Ganons Tower Exit', player) - hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)'] - else: - lw_entrances.append('Agahnims Tower') - dungeon_exits.append('Ganons Tower Exit') - hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)', 'Agahnims Tower'] - - # shuffle aga door first. If it's on HC ledge, remaining HC ledge door must be must-exit - all_entrances_aga = lw_entrances + dw_entrances - aga_doors = [i for i in all_entrances_aga] - random.shuffle(aga_doors) - aga_door = aga_doors.pop() - - if aga_door in hc_ledge_entrances: - lw_entrances.remove(aga_door) - hc_ledge_entrances.remove(aga_door) - - random.shuffle(hc_ledge_entrances) - hc_ledge_must_exit = hc_ledge_entrances.pop() - lw_entrances.remove(hc_ledge_must_exit) - lw_dungeon_entrances_must_exit.append(hc_ledge_must_exit) - - if aga_door in lw_entrances: - lw_entrances.remove(aga_door) - elif aga_door in dw_entrances: - dw_entrances.remove(aga_door) - - connect_two_way(world, aga_door, 'Agahnims Tower Exit', player) - dungeon_exits.remove('Agahnims Tower Exit') - - connect_mandatory_exits(world, lw_entrances, dungeon_exits, lw_dungeon_entrances_must_exit, player) - - connect_caves(world, lw_entrances, dw_entrances, dungeon_exits, player) - - elif world.shuffle[player] == 'simple': - simple_shuffle_dungeons(world, player) - - old_man_entrances = list(Inverted_Old_Man_Entrances) - caves = list(Cave_Exits) - three_exit_caves = list(Cave_Three_Exits) - - single_doors = list(Single_Cave_Doors) - bomb_shop_doors = list(Inverted_Bomb_Shop_Single_Cave_Doors) - blacksmith_doors = list(Blacksmith_Single_Cave_Doors) - door_targets = list(Inverted_Single_Cave_Targets) - - # we shuffle all 2 entrance caves as pairs as a start - # start with the ones that need to be directed - two_door_caves = list(Inverted_Two_Door_Caves_Directional) - random.shuffle(two_door_caves) - random.shuffle(caves) - while two_door_caves: - entrance1, entrance2 = two_door_caves.pop() - exit1, exit2 = caves.pop() - connect_two_way(world, entrance1, exit1, player) - connect_two_way(world, entrance2, exit2, player) - - # now the remaining pairs - two_door_caves = list(Inverted_Two_Door_Caves) - random.shuffle(two_door_caves) - while two_door_caves: - entrance1, entrance2 = two_door_caves.pop() - exit1, exit2 = caves.pop() - connect_two_way(world, entrance1, exit1, player) - connect_two_way(world, entrance2, exit2, player) - - # place links house - if not world.shufflelinks[player]: - links_house = 'Big Bomb Shop' - else: - links_house_doors = [i for i in DW_Single_Cave_Doors if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_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 match link's house - if links_house in bomb_shop_doors: - bomb_shop_doors.remove(links_house) - if links_house in blacksmith_doors: - blacksmith_doors.remove(links_house) - if links_house in old_man_entrances: - old_man_entrances.remove(links_house) - - # place dark sanc - 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) - - 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)', - 'Death Mountain Return Cave (East)', 'Spiral Cave', 'Old Man House (Top)', 'Spectacle Rock Cave', - 'Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Bottom)'] - - # place old man, bumper cave bottom to DDM entrances not in east bottom - - random.shuffle(old_man_entrances) - old_man_exit = old_man_entrances.pop() - connect_two_way(world, 'Bumper Cave (Bottom)', 'Old Man Cave Exit (West)', player) - connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player) - if old_man_exit == 'Spike Cave': - bomb_shop_doors.remove('Spike Cave') - bomb_shop_doors.extend(old_man_entrances) - - # add old man house to ensure it is always somewhere on light death mountain - caves.extend(list(Old_Man_House)) - caves.extend(list(three_exit_caves)) - - # connect rest - connect_caves(world, lw_dm_entrances, [], caves, player) - - # scramble holes - scramble_inverted_holes(world, player) - - # place blacksmith, has limited options - blacksmith_doors = [door for door in blacksmith_doors[:]] - random.shuffle(blacksmith_doors) - blacksmith_hut = blacksmith_doors.pop() - connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player) - bomb_shop_doors.extend(blacksmith_doors) - - # place bomb shop, has limited options - bomb_shop_doors = [door for door in bomb_shop_doors[:]] - random.shuffle(bomb_shop_doors) - bomb_shop = bomb_shop_doors.pop() - connect_entrance(world, bomb_shop, 'Big Bomb Shop', player) - single_doors.extend(bomb_shop_doors) - - # tavern back door cannot be shuffled yet - connect_doors(world, ['Tavern North'], ['Tavern'], player) - - # place remaining doors - connect_doors(world, single_doors, door_targets, player) - - elif world.shuffle[player] == 'restricted': - simple_shuffle_dungeons(world, player) - - lw_entrances = list(Inverted_LW_Entrances + Inverted_LW_Single_Cave_Doors) - dw_entrances = list(Inverted_DW_Entrances + Inverted_DW_Single_Cave_Doors + Inverted_Old_Man_Entrances) - lw_must_exits = list(Inverted_LW_Entrances_Must_Exit) - old_man_entrances = list(Inverted_Old_Man_Entrances) - caves = list(Cave_Exits + Cave_Three_Exits + Old_Man_House) - single_doors = list(Single_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 + Inverted_Blacksmith_Multi_Cave_Doors) - door_targets = list(Inverted_Single_Cave_Targets) - - # place links house - if not world.shufflelinks[player]: - links_house = 'Big Bomb Shop' - else: - links_house_doors = [i for i in dw_entrances if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_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 match link's house - if links_house in dw_entrances: - dw_entrances.remove(links_house) - - # place dark sanc - 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) - - # tavern back door cannot be shuffled yet - connect_doors(world, ['Tavern North'], ['Tavern'], player) - - # place must exits - connect_mandatory_exits(world, lw_entrances, caves, lw_must_exits, player) - - # place old man, has limited options - # exit has to come from specific set of doors, the entrance is free to move about - old_man_entrances = [door for door in old_man_entrances if door in 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) - dw_entrances.remove(old_man_exit) - - # place blacksmith, has limited options - all_entrances = lw_entrances + dw_entrances - # cannot place it anywhere already taken (or that are otherwise not eligible for placement) - blacksmith_doors = [door for door in blacksmith_doors if door in all_entrances] - random.shuffle(blacksmith_doors) - blacksmith_hut = blacksmith_doors.pop() - connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player) - if blacksmith_hut in lw_entrances: - lw_entrances.remove(blacksmith_hut) - if blacksmith_hut in dw_entrances: - dw_entrances.remove(blacksmith_hut) - bomb_shop_doors.extend(blacksmith_doors) - - # place bomb shop, has limited options - all_entrances = lw_entrances + dw_entrances - # 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 all_entrances] - random.shuffle(bomb_shop_doors) - bomb_shop = bomb_shop_doors.pop() - connect_entrance(world, bomb_shop, 'Big Bomb Shop', player) - if bomb_shop in lw_entrances: - lw_entrances.remove(bomb_shop) - if bomb_shop in dw_entrances: - dw_entrances.remove(bomb_shop) - - # place the old man cave's entrance somewhere in the dark world - random.shuffle(dw_entrances) - 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_inverted_holes(world, player) - - doors = lw_entrances + dw_entrances - # place remaining doors - connect_doors(world, doors, door_targets, player) - elif world.shuffle[player] == 'full': - skull_woods_shuffle(world, player) - - lw_entrances = list(Inverted_LW_Entrances + Inverted_LW_Dungeon_Entrances + Inverted_LW_Single_Cave_Doors) - 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 + Inverted_Blacksmith_Multi_Cave_Doors) - door_targets = list(Inverted_Single_Cave_Targets) - old_man_house = list(Old_Man_House) - - # randomize which desert ledge door is a must-exit - if random.randint(0, 1) == 0: - lw_must_exits.append('Desert Palace Entrance (North)') - lw_entrances.append('Desert Palace Entrance (West)') - else: - lw_must_exits.append('Desert Palace Entrance (West)') - lw_entrances.append('Desert Palace Entrance (North)') - - # tavern back door cannot be shuffled yet - connect_doors(world, ['Tavern North'], ['Tavern'], player) - - 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)') - - - if not world.shuffle_ganon: - connect_two_way(world, 'Agahnims Tower', 'Ganons Tower Exit', player) - hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)'] - else: - lw_entrances.append('Agahnims Tower') - caves.append('Ganons Tower Exit') - hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)', 'Agahnims Tower'] - - # shuffle aga door first. if it's on hc ledge, then one other hc ledge door has to be must_exit - all_entrances_aga = lw_entrances + dw_entrances - aga_doors = [i for i in all_entrances_aga if world.shufflelinks[player] or i != 'Big Bomb Shop'] - random.shuffle(aga_doors) - aga_door = aga_doors.pop() - - if aga_door in hc_ledge_entrances: - lw_entrances.remove(aga_door) - hc_ledge_entrances.remove(aga_door) - - random.shuffle(hc_ledge_entrances) - hc_ledge_must_exit = hc_ledge_entrances.pop() - lw_entrances.remove(hc_ledge_must_exit) - lw_must_exits.append(hc_ledge_must_exit) - - if aga_door in lw_entrances: - lw_entrances.remove(aga_door) - elif aga_door in dw_entrances: - dw_entrances.remove(aga_door) - - connect_two_way(world, aga_door, 'Agahnims Tower Exit', player) - caves.remove('Agahnims Tower Exit') - - # place links house - if not world.shufflelinks[player]: - links_house = 'Big Bomb Shop' - else: - links_house_doors = [i for i in dw_entrances if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_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 match link's house - if links_house in dw_entrances: - dw_entrances.remove(links_house) - - # place dark sanc - 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) - - # place old man house - # no dw must exits in inverted, but we randomize whether cave is in light or dark world - if random.randint(0, 1) == 0: - caves += old_man_house - connect_mandatory_exits(world, lw_entrances, caves, lw_must_exits, player) - try: - caves.remove(old_man_house[0]) - except ValueError: - pass - else: #if the cave wasn't placed we get here - connect_caves(world, lw_entrances, [], old_man_house, player) - else: - connect_caves(world, dw_entrances, [], old_man_house, player) - connect_mandatory_exits(world, lw_entrances, caves, lw_must_exits, player) - - # place old man, has limited options - # exit has to come from specific set of doors, the entrance is free to move about - old_man_entrances = [door for door in old_man_entrances if door in dw_entrances + lw_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) - if old_man_exit in dw_entrances: - dw_entrances.remove(old_man_exit) - old_man_world = 'dark' - elif old_man_exit in lw_entrances: - lw_entrances.remove(old_man_exit) - old_man_world = 'light' - - # place blacksmith, has limited options - all_entrances = lw_entrances + dw_entrances - # cannot place it anywhere already taken (or that are otherwise not eligible for placement) - blacksmith_doors = [door for door in blacksmith_doors if door in all_entrances] - random.shuffle(blacksmith_doors) - blacksmith_hut = blacksmith_doors.pop() - connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player) - if blacksmith_hut in lw_entrances: - lw_entrances.remove(blacksmith_hut) - if blacksmith_hut in dw_entrances: - dw_entrances.remove(blacksmith_hut) - bomb_shop_doors.extend(blacksmith_doors) - - # place bomb shop, has limited options - all_entrances = lw_entrances + dw_entrances - # 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 all_entrances] - random.shuffle(bomb_shop_doors) - bomb_shop = bomb_shop_doors.pop() - connect_entrance(world, bomb_shop, 'Big Bomb Shop', player) - if bomb_shop in lw_entrances: - lw_entrances.remove(bomb_shop) - if bomb_shop in dw_entrances: - dw_entrances.remove(bomb_shop) - - # place the old man cave's entrance somewhere in the same world he'll exit from - if old_man_world == 'light': - random.shuffle(lw_entrances) - old_man_entrance = lw_entrances.pop() - connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)', player) - elif old_man_world == 'dark': - random.shuffle(dw_entrances) - 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_inverted_holes(world, player) - - doors = lw_entrances + dw_entrances - - # place remaining doors - connect_doors(world, doors, door_targets, player) - elif world.shuffle[player] == 'crossed': - skull_woods_shuffle(world, player) - - entrances = list(Inverted_LW_Entrances + Inverted_LW_Dungeon_Entrances + Inverted_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 + Inverted_Blacksmith_Multi_Cave_Doors) - door_targets = list(Inverted_Single_Cave_Targets) - - # randomize which desert ledge door is a must-exit - if random.randint(0, 1) == 0: - must_exits.append('Desert Palace Entrance (North)') - entrances.append('Desert Palace Entrance (West)') - else: - must_exits.append('Desert Palace Entrance (West)') - entrances.append('Desert Palace Entrance (North)') - - caves.append(tuple(random.sample(['Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)'],3))) - entrances.append('Hyrule Castle Entrance (South)') - - if not world.shuffle_ganon: - connect_two_way(world, 'Agahnims Tower', 'Ganons Tower Exit', player) - hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)'] - else: - entrances.append('Agahnims Tower') - caves.append('Ganons Tower Exit') - hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)', 'Agahnims Tower'] - - # shuffle aga door. if it's on hc ledge, then one other hc ledge door has to be must_exit - aga_choices = [x for x in entrances if world.shufflelinks[player] or x != 'Big Bomb Shop'] - aga_door = random.choice(aga_choices) - - if aga_door in hc_ledge_entrances: - hc_ledge_entrances.remove(aga_door) - - random.shuffle(hc_ledge_entrances) - hc_ledge_must_exit = hc_ledge_entrances.pop() - entrances.remove(hc_ledge_must_exit) - must_exits.append(hc_ledge_must_exit) - - entrances.remove(aga_door) - connect_two_way(world, aga_door, 'Agahnims Tower Exit', player) - caves.remove('Agahnims Tower Exit') - - # place links house - if not world.shufflelinks[player]: - links_house = 'Big Bomb Shop' - else: - links_house_doors = [i for i in entrances + must_exits if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_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 match link's house - if links_house in entrances: - entrances.remove(links_house) - elif links_house in must_exits: - must_exits.remove(links_house) - - # place dark sanc - 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) - - # tavern back door cannot be shuffled yet - connect_doors(world, ['Tavern North'], ['Tavern'], player) - - - #place must-exit caves - connect_mandatory_exits(world, entrances, caves, must_exits, player) - - - # place old man, has limited options - # exit has to come from specific set of doors, the entrance is free to move about - old_man_entrances = [door for door in old_man_entrances if door in 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) - entrances.remove(old_man_exit) - - # place blacksmith, has limited options - # cannot place it anywhere already taken (or that are otherwise not eligible for placement) - blacksmith_doors = [door for door in blacksmith_doors if door in entrances] - random.shuffle(blacksmith_doors) - blacksmith_hut = blacksmith_doors.pop() - connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player) - entrances.remove(blacksmith_hut) - - # 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) - bomb_shop = bomb_shop_doors.pop() - connect_entrance(world, bomb_shop, 'Big Bomb Shop', player) - entrances.remove(bomb_shop) - - # place the old man cave's entrance somewhere - random.shuffle(entrances) - old_man_entrance = entrances.pop() - connect_two_way(world, old_man_entrance, 'Old Man Cave Exit (West)', player) - - # now scramble the rest - connect_caves(world, entrances, [], caves, player) - - # scramble holes - scramble_inverted_holes(world, player) - - # place remaining doors - connect_doors(world, entrances, door_targets, player) - elif world.shuffle[player] == 'insanity': - # beware ye who enter here - - 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 +\ - Inverted_DW_Entrances + Inverted_DW_Dungeon_Entrances + ['Skull Woods First Section Door', 'Skull Woods Second Section Door (East)', 'Skull Woods Second Section Door (West)'] +\ - Inverted_LW_Single_Cave_Doors + Inverted_DW_Single_Cave_Doors + ['Desert Palace Entrance (West)', 'Desert Palace Entrance (North)'] - exit_pool = list(doors) - - # randomize which desert ledge door is a must-exit - if random.randint(0, 1) == 0: - entrances_must_exits.append('Desert Palace Entrance (North)') - else: - entrances_must_exits.append('Desert Palace Entrance (West)') - - # TODO: there are other possible entrances we could support here by way of exiting from a connector, - # and rentering to find bomb shop. However appended list here is all those that we currently have - # bomb shop logic for. - # Specifically we could potentially add: 'Dark Death Mountain Ledge (East)' and doors associated with pits - bomb_shop_doors = list(Inverted_Bomb_Shop_Single_Cave_Doors + Inverted_Bomb_Shop_Multi_Cave_Doors + ['Turtle Rock Isolated Ledge Entrance', 'Hookshot Cave Back Entrance']) - blacksmith_doors = list(Inverted_Blacksmith_Single_Cave_Doors + Inverted_Blacksmith_Multi_Cave_Doors) - door_targets = list(Inverted_Single_Cave_Targets) - - random.shuffle(doors) - - old_man_entrances = list(Inverted_Old_Man_Entrances + Old_Man_Entrances) + ['Tower of Hera', 'Ganons Tower'] - - caves = Cave_Exits + Dungeon_Exits + Cave_Three_Exits + ['Old Man House Exit (Bottom)', 'Old Man House Exit (Top)', 'Skull Woods First Section Exit', 'Skull Woods Second Section Exit (East)', 'Skull Woods Second Section Exit (West)', - 'Kakariko Well Exit', 'Bat Cave Exit', 'North Fairy Cave Exit', 'Lost Woods Hideout Exit', 'Lumberjack Tree Exit', 'Sanctuary Exit'] - - - # shuffle up holes - hole_entrances = ['Kakariko Well Drop', 'Bat Cave Drop', 'North Fairy Cave Drop', 'Lost Woods Hideout Drop', 'Lumberjack Tree Tree', 'Sanctuary Grave', - 'Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', 'Skull Woods Second Section Hole'] - - hole_targets = ['Kakariko Well (top)', 'Bat Cave (right)', 'North Fairy Cave', 'Lost Woods Hideout (top)', 'Lumberjack Tree (top)', 'Sewer Drop', 'Skull Back Drop', - 'Skull Left Drop', 'Skull Pinball', 'Skull Pot Circle'] - - # tavern back door cannot be shuffled yet - connect_doors(world, ['Tavern North'], ['Tavern'], player) - - hole_entrances.append('Hyrule Castle Secret Entrance Drop') - hole_targets.append('Hyrule Castle Secret Entrance') - caves.append('Hyrule Castle Secret Entrance Exit') - - if not world.shuffle_ganon: - connect_two_way(world, 'Agahnims Tower', 'Ganons Tower Exit', player) - connect_two_way(world, 'Inverted Pyramid Entrance', 'Pyramid Exit', player) - connect_entrance(world, 'Inverted Pyramid Hole', 'Pyramid', player) - else: - caves.extend(['Ganons Tower Exit', 'Pyramid Exit']) - hole_entrances.append('Inverted Pyramid Hole') - hole_targets.append('Pyramid') - doors.extend(['Agahnims Tower', 'Inverted Pyramid Entrance']) - exit_pool.extend(['Agahnims Tower', 'Inverted Pyramid Entrance']) - - random.shuffle(hole_entrances) - random.shuffle(hole_targets) - random.shuffle(exit_pool) - - # fill up holes - for hole in hole_entrances: - connect_entrance(world, hole, hole_targets.pop(), player) - - doors.append('Hyrule Castle Entrance (South)') - caves.append(('Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)')) - - # place links house and dark sanc - if not world.shufflelinks[player]: - links_house = 'Big Bomb Shop' - else: - links_house_doors = [i for i in doors if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_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 match link's house - doors.remove(links_house) - exit_pool.remove(links_house) - - sanc_doors = [door for door in Inverted_Dark_Sanctuary_Doors if door in exit_pool] - 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) - - # now let's deal with mandatory reachable stuff - def extract_reachable_exit(cavelist): - random.shuffle(cavelist) - candidate = None - for cave in cavelist: - if isinstance(cave, tuple) and len(cave) > 1: - # special handling: TRock has two entries that we should consider entrance only - # ToDo this should be handled in a more sensible manner - if cave[0] in ['Turtle Rock Exit (Front)', 'Spectacle Rock Cave Exit (Peak)'] and len(cave) == 2: - continue - candidate = cave - break - if candidate is None: - raise RuntimeError('No suitable cave.') - cavelist.remove(candidate) - return candidate - - def connect_reachable_exit(entrance, caves, doors, exit_pool): - cave = extract_reachable_exit(caves) - - exit = cave[-1] - cave = cave[:-1] - connect_exit(world, exit, entrance, player) - connect_entrance(world, doors.pop(), exit, player) - # rest of cave now is forced to be in this world - exit_pool.remove(entrance) - caves.append(cave) - - # connect mandatory exits - for entrance in entrances_must_exits: - connect_reachable_exit(entrance, caves, doors, exit_pool) - - # place old man, has limited options - # exit has to come from specific set of doors, the entrance is free to move about - old_man_entrances = [entrance for entrance in old_man_entrances if entrance in exit_pool] - random.shuffle(old_man_entrances) - old_man_exit = old_man_entrances.pop() - exit_pool.remove(old_man_exit) - - connect_exit(world, 'Old Man Cave Exit (East)', old_man_exit, player) - connect_entrance(world, doors.pop(), 'Old Man Cave Exit (East)', player) - caves.append('Old Man Cave Exit (West)') - - # place blacksmith, has limited options - blacksmith_doors = [door for door in blacksmith_doors if door in doors] - random.shuffle(blacksmith_doors) - blacksmith_hut = blacksmith_doors.pop() - connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player) - doors.remove(blacksmith_hut) - - # place dam and pyramid fairy, have limited options - bomb_shop_doors = [door for door in bomb_shop_doors if door in doors] - random.shuffle(bomb_shop_doors) - bomb_shop = bomb_shop_doors.pop() - connect_entrance(world, bomb_shop, 'Big Bomb Shop', player) - doors.remove(bomb_shop) - - # handle remaining caves - for cave in caves: - if isinstance(cave, str): - cave = (cave,) - - for exit in cave: - connect_exit(world, exit, exit_pool.pop(), player) - connect_entrance(world, doors.pop(), exit, player) - - # place remaining doors - connect_doors(world, doors, door_targets, player) - else: - raise NotImplementedError('Shuffling not supported yet') - - # 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': - world.swamp_patch_required[player] = True - - # check for potion shop location - if world.get_entrance('Potion Shop', player).connected_region.name != 'Potion Shop': - world.powder_patch_required[player] = True - - # check for ganon location - if world.get_entrance('Inverted Pyramid Hole', player).connected_region.name != 'Pyramid': - world.ganon_at_pyramid[player] = False - - # check for Ganon's Tower location - if world.get_entrance('Agahnims Tower', player).connected_region.name != 'GT Lobby': + if world.get_entrance('Ganons Tower' if not world.is_atgt_swapped(player) else 'Agahnims Tower', player).connected_region.name != 'Ganons Tower Portal': world.ganonstower_vanilla[player] = False @@ -1447,8 +1051,12 @@ def scramble_holes(world, player): ('Lumberjack Tree Exit', 'Lumberjack Tree (top)')] if not world.shuffle_ganon: - connect_two_way(world, 'Pyramid Entrance', 'Pyramid Exit', player) - connect_entrance(world, 'Pyramid Hole', 'Pyramid', player) + if world.mode[player] == 'inverted': + connect_two_way(world, 'Inverted Pyramid Entrance', 'Pyramid Exit', player) + connect_entrance(world, 'Inverted Pyramid Hole', 'Pyramid', player) + else: + connect_two_way(world, 'Pyramid Entrance', 'Pyramid Exit', player) + connect_entrance(world, 'Pyramid Hole', 'Pyramid', player) else: hole_targets.append(('Pyramid Exit', 'Pyramid')) @@ -1466,8 +1074,12 @@ def scramble_holes(world, player): if world.shuffle_ganon: random.shuffle(hole_targets) exit, target = hole_targets.pop() - connect_two_way(world, 'Pyramid Entrance', exit, player) - connect_entrance(world, 'Pyramid Hole', target, player) + if world.mode[player] == 'inverted': + connect_two_way(world, 'Inverted Pyramid Entrance', exit, player) + connect_entrance(world, 'Inverted Pyramid Hole', target, player) + else: + connect_two_way(world, 'Pyramid Entrance', exit, player) + connect_entrance(world, 'Pyramid Hole', target, player) if world.shuffle[player] != 'crossed': hole_targets.append(('Sanctuary Exit', 'Sewer Drop')) @@ -1478,47 +1090,6 @@ def scramble_holes(world, player): connect_entrance(world, drop, target, player) -def scramble_inverted_holes(world, player): - hole_entrances = [('Kakariko Well Cave', 'Kakariko Well Drop'), - ('Bat Cave Cave', 'Bat Cave Drop'), - ('North Fairy Cave', 'North Fairy Cave Drop'), - ('Lost Woods Hideout Stump', 'Lost Woods Hideout Drop'), - ('Lumberjack Tree Cave', 'Lumberjack Tree Tree'), - ('Sanctuary', 'Sanctuary Grave')] - - hole_targets = [('Kakariko Well Exit', 'Kakariko Well (top)'), - ('Bat Cave Exit', 'Bat Cave (right)'), - ('North Fairy Cave Exit', 'North Fairy Cave'), - ('Lost Woods Hideout Exit', 'Lost Woods Hideout (top)'), - ('Lumberjack Tree Exit', 'Lumberjack Tree (top)')] - - if not world.shuffle_ganon: - connect_two_way(world, 'Inverted Pyramid Entrance', 'Pyramid Exit', player) - connect_entrance(world, 'Inverted Pyramid Hole', 'Pyramid', player) - else: - hole_targets.append(('Pyramid Exit', 'Pyramid')) - - - hole_entrances.append(('Hyrule Castle Secret Entrance Stairs', 'Hyrule Castle Secret Entrance Drop')) - hole_targets.append(('Hyrule Castle Secret Entrance Exit', 'Hyrule Castle Secret Entrance')) - - # do not shuffle sanctuary into pyramid hole unless shuffle is crossed - if world.shuffle[player] == 'crossed': - hole_targets.append(('Sanctuary Exit', 'Sewer Drop')) - if world.shuffle_ganon: - random.shuffle(hole_targets) - exit, target = hole_targets.pop() - connect_two_way(world, 'Inverted Pyramid Entrance', exit, player) - connect_entrance(world, 'Inverted Pyramid Hole', target, player) - if world.shuffle[player] != 'crossed': - hole_targets.append(('Sanctuary Exit', 'Sewer Drop')) - - random.shuffle(hole_targets) - for entrance, drop in hole_entrances: - exit, target = hole_targets.pop() - connect_two_way(world, entrance, exit, player) - connect_entrance(world, drop, target, player) - def connect_random(world, exitlist, targetlist, player, two_way=False): targetlist = list(targetlist) random.shuffle(targetlist) @@ -2494,17 +2065,10 @@ Inverted_Must_Exit_Invalid_Connections = defaultdict(set, { # 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'), - ('Sanctuary S&Q', 'Sanctuary'), - ('Old Man S&Q', 'Old Man House'), - ('Other World S&Q', 'East Dark World'), ('Lake Hylia Central Island Pier', 'Lake Hylia Central Island'), - ('Lake Hylia Central Island Teleporter', 'Dark Lake Hylia Central Island'), ('Zoras River', 'Zoras River'), - ('Zora Waterfall Entryway', 'Zora Waterfall Entryway'), - ('Zora Waterfall Water Drop', 'Light World'), ('Kings Grave Outer Rocks', 'Kings Grave Area'), ('Kings Grave Inner Rocks', 'Light World'), - ('Kings Grave Mirror Spot', 'Kings Grave Area'), ('Kakariko Well (top to bottom)', 'Kakariko Well (bottom)'), ('Kakariko Well (top to back)', 'Kakariko Well (back)'), ('Master Sword Meadow', 'Master Sword Meadow'), @@ -2518,10 +2082,7 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Desert Palace Stairs Drop', 'Light World'), ('Desert Palace Entrance (North) Rocks', 'Desert Palace Entrance (North) Spot'), ('Desert Ledge Return Rocks', 'Desert Ledge'), - ('Hyrule Castle Ledge Courtyard Drop', 'Hyrule Castle Courtyard'), - ('Hyrule Castle Main Gate', 'Hyrule Castle Courtyard'), ('Sewer Drop', 'Sewers Rat Path'), - ('Flute Spot 1', 'Death Mountain'), ('Death Mountain Entrance Rock', 'Death Mountain Entrance'), ('Death Mountain Entrance Drop', 'Light World'), ('Spectacle Rock Cave Drop', 'Spectacle Rock Cave (Bottom)'), @@ -2541,29 +2102,19 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('East Death Mountain (Top)', 'East Death Mountain (Top)'), ('Death Mountain (Top)', 'Death Mountain (Top)'), ('Death Mountain Drop', 'Death Mountain'), - ('Spectacle Rock Drop', 'Death Mountain (Top)'), - - ('Top of Pyramid', 'East Dark World'), ('Dark Lake Hylia Drop (East)', 'Dark Lake Hylia'), ('Dark Lake Hylia Drop (South)', 'Dark Lake Hylia'), ('Dark Lake Hylia Teleporter', 'Dark Lake Hylia'), - ('Dark Lake Hylia Ledge', 'Dark Lake Hylia Ledge'), ('Dark Lake Hylia Ledge Drop', 'Dark Lake Hylia'), ('East Dark World Pier', 'East Dark World'), - ('Lake Hylia Island Mirror Spot', 'Lake Hylia Island'), - ('Lake Hylia Central Island Mirror Spot', 'Lake Hylia Central Island'), - ('Hyrule Castle Ledge Mirror Spot', 'Hyrule Castle Ledge'), ('South Dark World Bridge', 'South Dark World'), ('East Dark World Bridge', 'East Dark World'), - ('Maze Race Mirror Spot', 'Maze Race Ledge'), ('Village of Outcasts Heavy Rock', 'West Dark World'), ('Village of Outcasts Drop', 'South Dark World'), ('Village of Outcasts Eastern Rocks', 'Hammer Peg Area'), ('Village of Outcasts Pegs', 'Dark Grassy Lawn'), ('Peg Area Rocks', 'West Dark World'), ('Grassy Lawn Pegs', 'West Dark World'), - ('Bat Cave Drop Ledge Mirror Spot', 'Bat Cave Drop Ledge'), - ('East Dark World River Pier', 'East Dark World'), ('West Dark World Gap', 'West Dark World'), ('East Dark World Broken Bridge Pass', 'East Dark World'), ('Catfish Exit Rock', 'Northeast Dark World'), @@ -2571,21 +2122,10 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Northeast Dark World Broken Bridge Pass', 'Northeast Dark World'), ('Bumper Cave Entrance Rock', 'Bumper Cave Entrance'), ('Bumper Cave Entrance Drop', 'West Dark World'), - ('Bumper Cave Entrance Mirror Spot', 'Death Mountain Entrance'), ('Bumper Cave Ledge Drop', 'West Dark World'), - ('Bumper Cave Ledge Mirror Spot', 'Death Mountain Return Ledge'), ('Bumper Cave Bottom to Top', 'Bumper Cave (top)'), ('Bumper Cave Top To Bottom', 'Bumper Cave (bottom)'), ('Skull Woods Forest', 'Skull Woods Forest'), - ('Desert Ledge Mirror Spot', 'Desert Ledge'), - ('Desert Ledge (Northeast) Mirror Spot', 'Desert Ledge (Northeast)'), - ('Desert Palace Entrance (North) Mirror Spot', 'Desert Palace Entrance (North) Spot'), - ('Dark Desert Teleporter', 'Dark Desert'), - ('Desert Palace Stairs Mirror Spot', 'Desert Palace Stairs'), - ('East Hyrule Teleporter', 'East Dark World'), - ('South Hyrule Teleporter', 'South Dark World'), - ('Kakariko Teleporter', 'West Dark World'), - ('Death Mountain Teleporter', 'Dark Death Mountain (West Bottom)'), ('Paradox Cave Push Block Reverse', 'Paradox Cave Chest Area'), ('Paradox Cave Push Block', 'Paradox Cave Front'), ('Paradox Cave Chest Area NE', 'Paradox Cave Bomb Area'), @@ -2593,17 +2133,12 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Paradox Cave Drop', 'Paradox Cave Chest Area'), ('Light World Death Mountain Shop', 'Light World Death Mountain Shop'), ('Fairy Ascension Rocks', 'Fairy Ascension Plateau'), - ('Fairy Ascension Mirror Spot', 'Fairy Ascension Plateau'), ('Fairy Ascension Drop', 'East Death Mountain (Bottom)'), ('Fairy Ascension Ledge Drop', 'Fairy Ascension Plateau'), - ('Fairy Ascension Ledge', 'Fairy Ascension Ledge'), ('Fairy Ascension Cave Climb', 'Fairy Ascension Cave (Top)'), ('Fairy Ascension Cave Pots', 'Fairy Ascension Cave (Bottom)'), ('Fairy Ascension Cave Drop', 'Fairy Ascension Cave (Drop)'), - ('Spectacle Rock Mirror Spot', 'Spectacle Rock'), ('Dark Death Mountain Drop (East)', 'Dark Death Mountain (East Bottom)'), - ('Dark Death Mountain Drop (West)', 'Dark Death Mountain (West Bottom)'), - ('East Death Mountain (Top) Mirror Spot', 'East Death Mountain (Top)'), ('Superbunny Cave Climb', 'Superbunny Cave (Top)'), ('Hookshot Cave Front to Middle', 'Hookshot Cave (Middle)'), ('Hookshot Cave Middle to Front', 'Hookshot Cave (Front)'), @@ -2611,118 +2146,95 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Hookshot Cave Back to Middle', 'Hookshot Cave (Middle)'), ('Hookshot Cave Bonk Path', 'Hookshot Cave (Bonk Islands)'), ('Hookshot Cave Hook Path', 'Hookshot Cave (Hook Islands)'), - ('Turtle Rock Teleporter', 'Turtle Rock (Top)'), - ('Turtle Rock Drop', 'Dark Death Mountain (Top)'), - ('Floating Island Drop', 'Dark Death Mountain (Top)'), - ('Floating Island Mirror Spot', 'Death Mountain Floating Island (Light World)'), - ('East Death Mountain Teleporter', 'Dark Death Mountain (East Bottom)'), - ('Isolated Ledge Mirror Spot', 'Fairy Ascension Ledge'), - ('Spiral Cave Mirror Spot', 'Spiral Cave Ledge'), - ('Mimic Cave Mirror Spot', 'Mimic Cave Ledge'), - ('Cave 45 Mirror Spot', 'Cave 45 Ledge'), - ('Bombos Tablet Mirror Spot', 'Bombos Tablet Ledge'), - ('Graveyard Ledge Mirror Spot', 'Graveyard Ledge'), ('Ganon Drop', 'Bottom of Pyramid'), ('Pyramid Drop', 'East Dark World'), ('Maze Race Ledge Drop', 'Light World'), - ('Graveyard Ledge Drop', 'Light World'), - ('Cave 45 Ledge Drop', 'Light World'), - ('Checkerboard Ledge Drop', 'Light World'), - ('Desert Ledge Drop', 'Light World'), - ('Hyrule Castle Main Gate (North)', 'Light World'), - ('Hyrule Castle Ledge Drop', 'Light World'), - ] + ('Desert Ledge Drop', 'Light World') + ] -inverted_mandatory_connections = [('Links House S&Q', 'Links House'), - ('Sanctuary S&Q', 'Dark Sanctuary Hint'), +open_mandatory_connections = [('Sanctuary S&Q', 'Sanctuary'), + ('Old Man S&Q', 'Old Man House'), + ('Other World S&Q', 'East Dark World'), + ('Lake Hylia Central Island Teleporter', 'Dark Lake Hylia Central Island'), + ('Zora Waterfall Entryway', 'Zora Waterfall Entryway'), + ('Zora Waterfall Water Drop', 'Light World'), + ('Kings Grave Mirror Spot', 'Kings Grave Area'), + ('Hyrule Castle Ledge Courtyard Drop', 'Hyrule Castle Courtyard'), + ('Hyrule Castle Main Gate', 'Hyrule Castle Courtyard'), + ('Flute Spot 1', 'Death Mountain'), + ('Spectacle Rock Drop', 'Death Mountain (Top)'), + ('Top of Pyramid', 'East Dark World'), + ('Lake Hylia Island Mirror Spot', 'Lake Hylia Island'), + ('Lake Hylia Central Island Mirror Spot', 'Lake Hylia Central Island'), + ('Hyrule Castle Ledge Mirror Spot', 'Hyrule Castle Ledge'), + ('Maze Race Mirror Spot', 'Maze Race Ledge'), + ('Bat Cave Drop Ledge Mirror Spot', 'Bat Cave Drop Ledge'), + ('East Dark World River Pier', 'East Dark World'), + ('Bumper Cave Entrance Mirror Spot', 'Death Mountain Entrance'), + ('Bumper Cave Ledge Mirror Spot', 'Death Mountain Return Ledge'), + ('Desert Ledge Mirror Spot', 'Desert Ledge'), + ('Desert Ledge (Northeast) Mirror Spot', 'Desert Ledge (Northeast)'), + ('Desert Palace Entrance (North) Mirror Spot', 'Desert Palace Entrance (North) Spot'), + ('Dark Desert Teleporter', 'Dark Desert'), + ('Desert Palace Stairs Mirror Spot', 'Desert Palace Stairs'), + ('East Hyrule Teleporter', 'East Dark World'), + ('South Hyrule Teleporter', 'South Dark World'), + ('Kakariko Teleporter', 'West Dark World'), + ('Death Mountain Teleporter', 'Dark Death Mountain (West Bottom)'), + ('Fairy Ascension Mirror Spot', 'Fairy Ascension Plateau'), + ('Fairy Ascension Ledge', 'Fairy Ascension Ledge'), + ('Spectacle Rock Mirror Spot', 'Spectacle Rock'), + ('Dark Death Mountain Drop (West)', 'Dark Death Mountain (West Bottom)'), + ('East Death Mountain (Top) Mirror Spot', 'East Death Mountain (Top)'), + ('Turtle Rock Teleporter', 'Turtle Rock (Top)'), + ('Turtle Rock Drop', 'Dark Death Mountain (Top)'), + ('Floating Island Drop', 'Dark Death Mountain (Top)'), + ('Floating Island Mirror Spot', 'Death Mountain Floating Island (Light World)'), + ('East Death Mountain Teleporter', 'Dark Death Mountain (East Bottom)'), + ('Isolated Ledge Mirror Spot', 'Fairy Ascension Ledge'), + ('Spiral Cave Mirror Spot', 'Spiral Cave Ledge'), + ('Mimic Cave Mirror Spot', 'Mimic Cave Ledge'), + ('Cave 45 Mirror Spot', 'Cave 45 Ledge'), + ('Bombos Tablet Mirror Spot', 'Bombos Tablet Ledge'), + ('Graveyard Ledge Mirror Spot', 'Graveyard Ledge'), + ('Graveyard Ledge Drop', 'Light World'), + ('Cave 45 Ledge Drop', 'Light World'), + ('Checkerboard Ledge Drop', 'Light World'), + ('Hyrule Castle Main Gate (North)', 'Light World'), + ('Hyrule Castle Ledge Drop', 'Light World'), + ] + +inverted_mandatory_connections = [('Sanctuary S&Q', 'Dark Sanctuary Hint'), ('Old Man S&Q', 'Old Man House'), ('Other World S&Q', 'Hyrule Castle Ledge'), - ('Lake Hylia Central Island Pier', 'Lake Hylia Central Island'), ('Lake Hylia Island Pier', 'Lake Hylia Island'), ('Lake Hylia Warp', 'Northeast Light World'), ('Northeast Light World Warp', 'Light World'), - ('Zoras River', 'Zoras River'), ('Waterfall of Wishing Cave', 'Waterfall of Wishing Cave'), ('Northeast Light World Return', 'Northeast Light World'), - ('Kings Grave Outer Rocks', 'Kings Grave Area'), - ('Kings Grave Inner Rocks', 'Light World'), - ('Kakariko Well (top to bottom)', 'Kakariko Well (bottom)'), - ('Kakariko Well (top to back)', 'Kakariko Well (back)'), - ('Master Sword Meadow', 'Master Sword Meadow'), - ('Hobo Bridge', 'Hobo Bridge'), - ('Bat Cave Drop Ledge', 'Bat Cave Drop Ledge'), - ('Bat Cave Door', 'Bat Cave (left)'), - ('Lost Woods Hideout (top to bottom)', 'Lost Woods Hideout (bottom)'), - ('Lumberjack Tree (top to bottom)', 'Lumberjack Tree (bottom)'), - ('Blinds Hideout N', 'Blinds Hideout (Top)'), - ('Desert Palace Stairs', 'Desert Palace Stairs'), - ('Desert Palace Stairs Drop', 'Light World'), - ('Desert Palace Entrance (North) Rocks', 'Desert Palace Entrance (North) Spot'), - ('Desert Ledge Return Rocks', 'Desert Ledge'), - ('Sewer Drop', 'Sewers Rat Path'), - ('Death Mountain Entrance Rock', 'Death Mountain Entrance'), - ('Death Mountain Entrance Drop', 'Light World'), - ('Death Mountain Return Cave E', 'Death Mountain Return Cave (right)'), - ('Death Mountain Return Cave W', 'Death Mountain Return Cave (left)'), - ('Spectacle Rock Cave Drop', 'Spectacle Rock Cave (Bottom)'), - ('Spectacle Rock Cave Peak Drop', 'Spectacle Rock Cave (Bottom)'), - ('Death Mountain Return Ledge Drop', 'Light World'), - ('Old Man Cave Dropdown', 'Old Man Cave'), - ('Old Man House Front to Back', 'Old Man House Back'), - ('Old Man House Back to Front', 'Old Man House'), - ('Broken Bridge (West)', 'East Death Mountain (Bottom)'), - ('Broken Bridge (East)', 'Death Mountain'), - ('East Death Mountain Drop', 'East Death Mountain (Bottom)'), - ('Spiral Cave Ledge Access', 'Spiral Cave Ledge'), - ('Spiral Cave Ledge Drop', 'East Death Mountain (Bottom)'), - ('Spiral Cave (top to bottom)', 'Spiral Cave (Bottom)'), - ('East Death Mountain (Top)', 'East Death Mountain (Top)'), - ('Death Mountain (Top)', 'Death Mountain (Top)'), - ('Death Mountain Drop', 'Death Mountain'), - ('Dark Lake Hylia Drop (East)', 'Dark Lake Hylia'), - ('Dark Lake Hylia Drop (South)', 'Dark Lake Hylia'), - ('Dark Lake Hylia Teleporter', 'Dark Lake Hylia'), + ('Hyrule Castle Ledge Courtyard Drop', 'Light World'), + ('DDM Flute', 'The Sky'), + ('DDM Landing', 'Dark Death Mountain'), + ('NEDW Flute', 'The Sky'), + ('NEDW Landing', 'Northeast Dark World'), + ('WDW Flute', 'The Sky'), + ('WDW Landing', 'West Dark World'), + ('SDW Flute', 'The Sky'), + ('SDW Landing', 'South Dark World'), + ('EDW Flute', 'The Sky'), + ('EDW Landing', 'East Dark World'), + ('DLHL Flute', 'The Sky'), + ('DLHL Landing', 'Dark Lake Hylia Ledge'), + ('DD Flute', 'The Sky'), + ('DD Landing', 'Dark Desert Ledge'), + ('EDDM Flute', 'The Sky'), + ('Dark Grassy Lawn Flute', 'The Sky'), + ('Hammer Peg Area Flute', 'The Sky'), ('Dark Lake Hylia Ledge Pier', 'Dark Lake Hylia Ledge'), - ('Dark Lake Hylia Ledge Drop', 'Dark Lake Hylia'), ('Ice Palace Missing Wall', 'Dark Lake Hylia Central Island'), ('Dark Lake Hylia Shallows', 'Dark Lake Hylia'), - ('East Dark World Pier', 'East Dark World'), - ('South Dark World Bridge', 'South Dark World'), - ('East Dark World Bridge', 'East Dark World'), - ('Village of Outcasts Heavy Rock', 'West Dark World'), - ('Village of Outcasts Drop', 'South Dark World'), - ('Village of Outcasts Eastern Rocks', 'Hammer Peg Area'), - ('Village of Outcasts Pegs', 'Dark Grassy Lawn'), - ('Peg Area Rocks', 'West Dark World'), - ('Grassy Lawn Pegs', 'West Dark World'), ('East Dark World River Pier', 'Northeast Dark World'), - ('West Dark World Gap', 'West Dark World'), - ('East Dark World Broken Bridge Pass', 'East Dark World'), - ('Northeast Dark World Broken Bridge Pass', 'Northeast Dark World'), - ('Catfish Exit Rock', 'Northeast Dark World'), - ('Catfish Entrance Rock', 'Catfish'), - ('Bumper Cave Entrance Rock', 'Bumper Cave Entrance'), - ('Bumper Cave Entrance Drop', 'West Dark World'), - ('Bumper Cave Ledge Drop', 'West Dark World'), - ('Bumper Cave Bottom to Top', 'Bumper Cave (top)'), - ('Bumper Cave Top To Bottom', 'Bumper Cave (bottom)'), - ('Skull Woods Forest', 'Skull Woods Forest'), - ('Paradox Cave Push Block Reverse', 'Paradox Cave Chest Area'), - ('Paradox Cave Push Block', 'Paradox Cave Front'), - ('Paradox Cave Chest Area NE', 'Paradox Cave Bomb Area'), - ('Paradox Cave Bomb Jump', 'Paradox Cave'), - ('Paradox Cave Drop', 'Paradox Cave Chest Area'), - ('Light World Death Mountain Shop', 'Light World Death Mountain Shop'), - ('Fairy Ascension Rocks', 'Fairy Ascension Plateau'), - ('Fairy Ascension Drop', 'East Death Mountain (Bottom)'), - ('Fairy Ascension Ledge Drop', 'Fairy Ascension Plateau'), ('Fairy Ascension Ledge Access', 'Fairy Ascension Ledge'), - ('Fairy Ascension Cave Climb', 'Fairy Ascension Cave (Top)'), - ('Fairy Ascension Cave Pots', 'Fairy Ascension Cave (Bottom)'), - ('Fairy Ascension Cave Drop', 'Fairy Ascension Cave (Drop)'), - ('Dark Death Mountain Drop (East)', 'Dark Death Mountain (East Bottom)'), - ('Ganon Drop', 'Bottom of Pyramid'), - ('Pyramid Drop', 'East Dark World'), ('Post Aga Teleporter', 'Light World'), ('Secret Passage Inner Bushes', 'Light World'), ('Secret Passage Outer Bushes', 'Hyrule Castle Secret Entrance Area'), @@ -2737,19 +2249,10 @@ inverted_mandatory_connections = [('Links House S&Q', 'Links House'), ('Light World River Drop', 'River'), ('Light World Pier', 'Light World'), ('Potion Shop Pier', 'Potion Shop Area'), - ('Hyrule Castle Ledge Courtyard Drop', 'Light World'), ('Mimic Cave Ledge Access', 'Mimic Cave Ledge'), ('Mimic Cave Ledge Drop', 'East Death Mountain (Bottom)'), ('Turtle Rock Tail Drop', 'Turtle Rock (Top)'), ('Turtle Rock Drop', 'Dark Death Mountain'), - ('Superbunny Cave Climb', 'Superbunny Cave (Top)'), - ('Hookshot Cave Front to Middle', 'Hookshot Cave (Middle)'), - ('Hookshot Cave Middle to Front', 'Hookshot Cave (Front)'), - ('Hookshot Cave Middle to Back', 'Hookshot Cave (Back)'), - ('Hookshot Cave Back to Middle', 'Hookshot Cave (Middle)'), - ('Hookshot Cave Bonk Path', 'Hookshot Cave (Bonk Islands)'), - ('Hookshot Cave Hook Path', 'Hookshot Cave (Hook Islands)'), - ('Desert Ledge Drop', 'Light World'), ('Floating Island Drop', 'Dark Death Mountain'), ('Dark Lake Hylia Central Island Teleporter', 'Lake Hylia Central Island'), ('Dark Desert Teleporter', 'Light World'), @@ -2783,40 +2286,21 @@ inverted_mandatory_connections = [('Links House S&Q', 'Links House'), ('Catfish Mirror Spot', 'Catfish'), ('Shopping Mall Mirror Spot', 'Dark Lake Hylia Ledge'), ('Skull Woods Mirror Spot', 'Skull Woods Forest (West)'), - ('DDM Flute', 'The Sky'), - ('DDM Landing', 'Dark Death Mountain'), - ('NEDW Flute', 'The Sky'), - ('NEDW Landing', 'Northeast Dark World'), - ('WDW Flute', 'The Sky'), - ('WDW Landing', 'West Dark World'), - ('SDW Flute', 'The Sky'), - ('SDW Landing', 'South Dark World'), - ('EDW Flute', 'The Sky'), - ('EDW Landing', 'East Dark World'), - ('DLHL Flute', 'The Sky'), - ('DLHL Landing', 'Dark Lake Hylia Ledge'), - ('DD Flute', 'The Sky'), - ('DD Landing', 'Dark Desert Ledge'), - ('EDDM Flute', 'The Sky'), - ('Dark Grassy Lawn Flute', 'The Sky'), - ('Hammer Peg Area Flute', 'The Sky'), ('Bush Covered Lawn Inner Bushes', 'Light World'), ('Bush Covered Lawn Outer Bushes', 'Bush Covered Lawn'), ('Bush Covered Lawn Mirror Spot', 'Dark Grassy Lawn'), ('Bomb Hut Inner Bushes', 'Light World'), ('Bomb Hut Outer Bushes', 'Bomb Hut Area'), - ('Bomb Hut Mirror Spot', 'West Dark World'), - ('Maze Race Ledge Drop', 'Light World')] + ('Bomb Hut Mirror Spot', 'West Dark World') + ] + # non-shuffled entrance links -default_connections = [('Links House', 'Links House'), - ('Links House Exit', 'Light World'), - ('Waterfall of Wishing', 'Waterfall of Wishing'), - ("Blinds Hideout", "Blinds Hideout"), +default_connections = [('Waterfall of Wishing', 'Waterfall of Wishing'), + ('Blinds Hideout', 'Blinds Hideout'), ('Dam', 'Dam'), ('Lumberjack House', 'Lumberjack House'), - ("Hyrule Castle Secret Entrance Drop", "Hyrule Castle Secret Entrance"), - ("Hyrule Castle Secret Entrance Stairs", "Hyrule Castle Secret Entrance"), - ("Hyrule Castle Secret Entrance Exit", "Hyrule Castle Courtyard"), + ('Hyrule Castle Secret Entrance Drop', 'Hyrule Castle Secret Entrance'), + ('Hyrule Castle Secret Entrance Stairs', 'Hyrule Castle Secret Entrance'), ('Bonk Fairy (Light)', 'Bonk Fairy (Light)'), ('Lake Hylia Fairy', 'Lake Hylia Healer Fairy'), ('Lake Hylia Fortune Teller', 'Lake Hylia Fortune Teller'), @@ -2862,7 +2346,7 @@ default_connections = [('Links House', 'Links House'), ('Graveyard Cave', 'Graveyard Cave'), ('Checkerboard Cave', 'Checkerboard Cave'), ('Mini Moldorm Cave', 'Mini Moldorm Cave'), - ('Long Fairy Cave', 'Long Fairy Cave'), # near East Light World Teleporter + ('Long Fairy Cave', 'Long Fairy Cave'), ('Good Bee Cave', 'Good Bee Cave'), ('20 Rupee Cave', '20 Rupee Cave'), ('50 Rupee Cave', '50 Rupee Cave'), @@ -2875,22 +2359,14 @@ default_connections = [('Links House', 'Links House'), ('Two Brothers House (West)', 'Two Brothers House'), ('Two Brothers House Exit (East)', 'Light World'), ('Two Brothers House Exit (West)', 'Maze Race Ledge'), - ('Sanctuary', 'Sanctuary Portal'), ('Sanctuary Grave', 'Sewer Drop'), ('Sanctuary Exit', 'Light World'), - - ('Old Man Cave (West)', 'Old Man Cave Ledge'), - ('Old Man Cave (East)', 'Old Man Cave'), - ('Old Man Cave Exit (West)', 'Light World'), - ('Old Man Cave Exit (East)', 'Death Mountain'), ('Old Man House (Bottom)', 'Old Man House'), ('Old Man House Exit (Bottom)', 'Death Mountain'), ('Old Man House (Top)', 'Old Man House Back'), ('Old Man House Exit (Top)', 'Death Mountain'), ('Death Mountain Return Cave (East)', 'Death Mountain Return Cave (right)'), - ('Death Mountain Return Cave (West)', 'Death Mountain Return Cave (left)'), - ('Death Mountain Return Cave Exit (West)', 'Death Mountain Return Ledge'), ('Death Mountain Return Cave Exit (East)', 'Death Mountain'), ('Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Peak)'), ('Spectacle Rock Cave (Bottom)', 'Spectacle Rock Cave (Bottom)'), @@ -2913,11 +2389,9 @@ default_connections = [('Links House', 'Links House'), ('Spiral Cave (Bottom)', 'Spiral Cave (Bottom)'), ('Spiral Cave Exit', 'East Death Mountain (Bottom)'), ('Spiral Cave Exit (Top)', 'Spiral Cave Ledge'), - ('Pyramid Fairy', 'Pyramid Fairy'), ('East Dark World Hint', 'East Dark World Hint'), ('Palace of Darkness Hint', 'Palace of Darkness Hint'), - ('Big Bomb Shop', 'Big Bomb Shop'), ('Dark Lake Hylia Shop', 'Dark Lake Hylia Shop'), ('Dark Lake Hylia Fairy', 'Dark Lake Hylia Healer Fairy'), ('Dark Lake Hylia Ledge Fairy', 'Dark Lake Hylia Ledge Healer Fairy'), @@ -2929,8 +2403,6 @@ default_connections = [('Links House', 'Links House'), ('C-Shaped House', 'C-Shaped House'), ('Chest Game', 'Chest Game'), ('Dark World Hammer Peg Cave', 'Dark World Hammer Peg Cave'), - ('Bumper Cave (Bottom)', 'Bumper Cave (bottom)'), - ('Bumper Cave (Top)', 'Bumper Cave (top)'), ('Red Shield Shop', 'Red Shield Shop'), ('Dark Sanctuary Hint', 'Dark Sanctuary Hint'), ('Fortune Teller (Dark)', 'Fortune Teller (Dark)'), @@ -2938,8 +2410,6 @@ default_connections = [('Links House', 'Links House'), ('Dark World Lumberjack Shop', 'Dark World Lumberjack Shop'), ('Dark World Potion Shop', 'Dark World Potion Shop'), ('Archery Game', 'Archery Game'), - ('Bumper Cave Exit (Top)', 'Bumper Cave Ledge'), - ('Bumper Cave Exit (Bottom)', 'West Dark World'), ('Mire Shed', 'Mire Shed'), ('Dark Desert Hint', 'Dark Desert Hint'), ('Dark Desert Fairy', 'Dark Desert Healer Fairy'), @@ -2947,168 +2417,57 @@ default_connections = [('Links House', 'Links House'), ('Hookshot Cave', 'Hookshot Cave (Front)'), ('Superbunny Cave (Top)', 'Superbunny Cave (Top)'), ('Cave Shop (Dark Death Mountain)', 'Cave Shop (Dark Death Mountain)'), - ('Dark Death Mountain Fairy', 'Dark Death Mountain Healer Fairy'), ('Superbunny Cave (Bottom)', 'Superbunny Cave (Bottom)'), - ('Superbunny Cave Exit (Top)', 'Dark Death Mountain (Top)'), ('Superbunny Cave Exit (Bottom)', 'Dark Death Mountain (East Bottom)'), - ('Hookshot Cave Front Exit', 'Dark Death Mountain (Top)'), ('Hookshot Cave Back Exit', 'Death Mountain Floating Island (Dark World)'), ('Hookshot Cave Back Entrance', 'Hookshot Cave (Back)'), - ('Mimic Cave', 'Mimic Cave'), - - ('Pyramid Hole', 'Pyramid'), - ('Pyramid Exit', 'Pyramid Ledge'), - ('Pyramid Entrance', 'Bottom of Pyramid') + ('Mimic Cave', 'Mimic Cave') ] -inverted_default_connections = [('Waterfall of Wishing', 'Waterfall of Wishing'), - ('Blinds Hideout', 'Blinds Hideout'), - ('Dam', 'Dam'), - ('Lumberjack House', 'Lumberjack House'), - ('Hyrule Castle Secret Entrance Drop', 'Hyrule Castle Secret Entrance'), - ('Hyrule Castle Secret Entrance Stairs', 'Hyrule Castle Secret Entrance'), - ('Hyrule Castle Secret Entrance Exit', 'Light World'), - ('Bonk Fairy (Light)', 'Bonk Fairy (Light)'), - ('Lake Hylia Fairy', 'Lake Hylia Healer Fairy'), - ('Lake Hylia Fortune Teller', 'Lake Hylia Fortune Teller'), - ('Light Hype Fairy', 'Swamp Healer Fairy'), - ('Desert Fairy', 'Desert Healer Fairy'), - ('Kings Grave', 'Kings Grave'), - ('Tavern North', 'Tavern'), - ('Chicken House', 'Chicken House'), - ('Aginahs Cave', 'Aginahs Cave'), - ('Sahasrahlas Hut', 'Sahasrahlas Hut'), - ('Cave Shop (Lake Hylia)', 'Cave Shop (Lake Hylia)'), - ('Capacity Upgrade', 'Capacity Upgrade'), - ('Kakariko Well Drop', 'Kakariko Well (top)'), - ('Kakariko Well Cave', 'Kakariko Well (bottom)'), - ('Kakariko Well Exit', 'Light World'), - ('Blacksmiths Hut', 'Blacksmiths Hut'), - ('Bat Cave Drop', 'Bat Cave (right)'), - ('Bat Cave Cave', 'Bat Cave (left)'), - ('Bat Cave Exit', 'Light World'), - ('Sick Kids House', 'Sick Kids House'), - ('Elder House (East)', 'Elder House'), - ('Elder House (West)', 'Elder House'), - ('Elder House Exit (East)', 'Light World'), - ('Elder House Exit (West)', 'Light World'), - ('North Fairy Cave Drop', 'North Fairy Cave'), - ('North Fairy Cave', 'North Fairy Cave'), - ('North Fairy Cave Exit', 'Light World'), - ('Lost Woods Gamble', 'Lost Woods Gamble'), - ('Fortune Teller (Light)', 'Fortune Teller (Light)'), - ('Snitch Lady (East)', 'Snitch Lady (East)'), - ('Snitch Lady (West)', 'Snitch Lady (West)'), - ('Bush Covered House', 'Bush Covered House'), - ('Tavern (Front)', 'Tavern (Front)'), - ('Light World Bomb Hut', 'Light World Bomb Hut'), - ('Kakariko Shop', 'Kakariko Shop'), - ('Lost Woods Hideout Drop', 'Lost Woods Hideout (top)'), - ('Lost Woods Hideout Stump', 'Lost Woods Hideout (bottom)'), - ('Lost Woods Hideout Exit', 'Light World'), - ('Lumberjack Tree Tree', 'Lumberjack Tree (top)'), - ('Lumberjack Tree Cave', 'Lumberjack Tree (bottom)'), - ('Lumberjack Tree Exit', 'Light World'), - ('Cave 45', 'Cave 45'), - ('Graveyard Cave', 'Graveyard Cave'), - ('Checkerboard Cave', 'Checkerboard Cave'), - ('Mini Moldorm Cave', 'Mini Moldorm Cave'), - ('Long Fairy Cave', 'Long Fairy Cave'), - ('Good Bee Cave', 'Good Bee Cave'), - ('20 Rupee Cave', '20 Rupee Cave'), - ('50 Rupee Cave', '50 Rupee Cave'), - ('Ice Rod Cave', 'Ice Rod Cave'), - ('Bonk Rock Cave', 'Bonk Rock Cave'), - ('Library', 'Library'), - ('Kakariko Gamble Game', 'Kakariko Gamble Game'), - ('Potion Shop', 'Potion Shop'), - ('Two Brothers House (East)', 'Two Brothers House'), - ('Two Brothers House (West)', 'Two Brothers House'), - ('Two Brothers House Exit (East)', 'Light World'), - ('Two Brothers House Exit (West)', 'Maze Race Ledge'), - ('Sanctuary', 'Sanctuary Portal'), - ('Sanctuary Grave', 'Sewer Drop'), - ('Sanctuary Exit', 'Light World'), - ('Old Man House (Bottom)', 'Old Man House'), - ('Old Man House Exit (Bottom)', 'Death Mountain'), - ('Old Man House (Top)', 'Old Man House Back'), - ('Old Man House Exit (Top)', 'Death Mountain'), - ('Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Peak)'), - ('Spectacle Rock Cave (Bottom)', 'Spectacle Rock Cave (Bottom)'), - ('Spectacle Rock Cave', 'Spectacle Rock Cave (Top)'), - ('Spectacle Rock Cave Exit', 'Death Mountain'), - ('Spectacle Rock Cave Exit (Top)', 'Death Mountain'), - ('Spectacle Rock Cave Exit (Peak)', 'Death Mountain'), - ('Paradox Cave (Bottom)', 'Paradox Cave Front'), - ('Paradox Cave (Middle)', 'Paradox Cave'), - ('Paradox Cave (Top)', 'Paradox Cave'), - ('Paradox Cave Exit (Bottom)', 'East Death Mountain (Bottom)'), - ('Paradox Cave Exit (Middle)', 'East Death Mountain (Bottom)'), - ('Paradox Cave Exit (Top)', 'East Death Mountain (Top)'), - ('Hookshot Fairy', 'Hookshot Fairy'), - ('Fairy Ascension Cave (Bottom)', 'Fairy Ascension Cave (Bottom)'), - ('Fairy Ascension Cave (Top)', 'Fairy Ascension Cave (Top)'), - ('Fairy Ascension Cave Exit (Bottom)', 'Fairy Ascension Plateau'), - ('Fairy Ascension Cave Exit (Top)', 'Fairy Ascension Ledge'), - ('Spiral Cave', 'Spiral Cave (Top)'), - ('Spiral Cave (Bottom)', 'Spiral Cave (Bottom)'), - ('Spiral Cave Exit', 'East Death Mountain (Bottom)'), - ('Spiral Cave Exit (Top)', 'Spiral Cave Ledge'), - ('Pyramid Fairy', 'Pyramid Fairy'), - ('East Dark World Hint', 'East Dark World Hint'), - ('Palace of Darkness Hint', 'Palace of Darkness Hint'), - ('Dark Lake Hylia Shop', 'Dark Lake Hylia Shop'), - ('Dark Lake Hylia Fairy', 'Dark Lake Hylia Healer Fairy'), - ('Dark Lake Hylia Ledge Fairy', 'Dark Lake Hylia Ledge Healer Fairy'), - ('Dark Lake Hylia Ledge Spike Cave', 'Dark Lake Hylia Ledge Spike Cave'), - ('Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Ledge Hint'), - ('Hype Cave', 'Hype Cave'), - ('Bonk Fairy (Dark)', 'Bonk Fairy (Dark)'), - ('Brewery', 'Brewery'), - ('C-Shaped House', 'C-Shaped House'), - ('Chest Game', 'Chest Game'), - ('Dark World Hammer Peg Cave', 'Dark World Hammer Peg Cave'), - ('Red Shield Shop', 'Red Shield Shop'), - ('Fortune Teller (Dark)', 'Fortune Teller (Dark)'), - ('Dark World Shop', 'Village of Outcasts Shop'), - ('Dark World Lumberjack Shop', 'Dark World Lumberjack Shop'), - ('Dark World Potion Shop', 'Dark World Potion Shop'), - ('Archery Game', 'Archery Game'), - ('Mire Shed', 'Mire Shed'), - ('Dark Desert Hint', 'Dark Desert Hint'), - ('Dark Desert Fairy', 'Dark Desert Healer Fairy'), - ('Spike Cave', 'Spike Cave'), - ('Hookshot Cave', 'Hookshot Cave (Front)'), - ('Superbunny Cave (Top)', 'Superbunny Cave (Top)'), - ('Cave Shop (Dark Death Mountain)', 'Cave Shop (Dark Death Mountain)'), - ('Superbunny Cave (Bottom)', 'Superbunny Cave (Bottom)'), - ('Superbunny Cave Exit (Bottom)', 'Dark Death Mountain (East Bottom)'), - ('Hookshot Cave Back Exit', 'Death Mountain Floating Island (Dark World)'), - ('Hookshot Cave Back Entrance', 'Hookshot Cave (Back)'), - ('Mimic Cave', 'Mimic Cave'), - ('Inverted Pyramid Hole', 'Pyramid'), - ('Links House', 'Big Bomb Shop'), - ('Links House Exit', 'South Dark World'), - ('Big Bomb Shop', 'Links House'), - ('Dark Sanctuary Hint', 'Dark Sanctuary Hint'), - ('Dark Sanctuary Hint Exit', 'West Dark World'), - ('Old Man Cave (West)', 'Bumper Cave (bottom)'), - ('Old Man Cave (East)', 'Death Mountain Return Cave (left)'), - ('Old Man Cave Exit (West)', 'West Dark World'), - ('Old Man Cave Exit (East)', 'Dark Death Mountain'), - ('Dark Death Mountain Fairy', 'Old Man Cave'), - ('Bumper Cave (Bottom)', 'Old Man Cave Ledge'), - ('Bumper Cave (Top)', 'Dark Death Mountain Healer Fairy'), - ('Bumper Cave Exit (Top)', 'Death Mountain Return Ledge'), - ('Bumper Cave Exit (Bottom)', 'Light World'), - ('Death Mountain Return Cave (West)', 'Bumper Cave (top)'), - ('Death Mountain Return Cave (East)', 'Death Mountain Return Cave (right)'), - ('Death Mountain Return Cave Exit (West)', 'Death Mountain'), - ('Death Mountain Return Cave Exit (East)', 'Death Mountain'), - ('Hookshot Cave Front Exit', 'Dark Death Mountain'), - ('Superbunny Cave Exit (Top)', 'Dark Death Mountain'), - ('Pyramid Exit', 'Light World'), - ('Inverted Pyramid Entrance', 'Bottom of Pyramid')] +open_default_connections = [('Links House', 'Links House'), + ('Links House Exit', 'Light World'), + ('Hyrule Castle Secret Entrance Exit', 'Hyrule Castle Courtyard'), + ('Old Man Cave (West)', 'Old Man Cave Ledge'), + ('Old Man Cave (East)', 'Old Man Cave'), + ('Old Man Cave Exit (West)', 'Light World'), + ('Old Man Cave Exit (East)', 'Death Mountain'), + ('Death Mountain Return Cave (West)', 'Death Mountain Return Cave (left)'), + ('Death Mountain Return Cave Exit (West)', 'Death Mountain Return Ledge'), + ('Big Bomb Shop', 'Big Bomb Shop'), + ('Bumper Cave (Bottom)', 'Bumper Cave (bottom)'), + ('Bumper Cave (Top)', 'Bumper Cave (top)'), + ('Bumper Cave Exit (Top)', 'Bumper Cave Ledge'), + ('Bumper Cave Exit (Bottom)', 'West Dark World'), + ('Dark Death Mountain Fairy', 'Dark Death Mountain Healer Fairy'), + ('Superbunny Cave Exit (Top)', 'Dark Death Mountain (Top)'), + ('Hookshot Cave Front Exit', 'Dark Death Mountain (Top)'), + ('Pyramid Hole', 'Pyramid'), + ('Pyramid Exit', 'Pyramid Ledge'), + ('Pyramid Entrance', 'Bottom of Pyramid') + ] + +inverted_default_connections = [('Links House', 'Big Bomb Shop'), + ('Links House Exit', 'South Dark World'), + ('Hyrule Castle Secret Entrance Exit', 'Light World'), + ('Old Man Cave (West)', 'Bumper Cave (bottom)'), + ('Old Man Cave (East)', 'Death Mountain Return Cave (left)'), + ('Old Man Cave Exit (West)', 'West Dark World'), + ('Old Man Cave Exit (East)', 'Dark Death Mountain'), + ('Death Mountain Return Cave (West)', 'Bumper Cave (top)'), + ('Death Mountain Return Cave Exit (West)', 'Death Mountain'), + ('Big Bomb Shop', 'Links House'), + ('Bumper Cave (Bottom)', 'Old Man Cave Ledge'), + ('Bumper Cave (Top)', 'Dark Death Mountain Healer Fairy'), + ('Dark Sanctuary Hint Exit', 'West Dark World'), + ('Bumper Cave Exit (Top)', 'Death Mountain Return Ledge'), + ('Bumper Cave Exit (Bottom)', 'Light World'), + ('Dark Death Mountain Fairy', 'Old Man Cave'), + ('Superbunny Cave Exit (Top)', 'Dark Death Mountain'), + ('Hookshot Cave Front Exit', 'Dark Death Mountain'), + ('Inverted Pyramid Hole', 'Pyramid'), + ('Pyramid Exit', 'Light World'), + ('Inverted Pyramid Entrance', 'Bottom of Pyramid') + ] # non shuffled dungeons default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert South Portal'), @@ -3119,7 +2478,6 @@ default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert South ('Desert Palace Exit (West)', 'Desert Ledge'), ('Desert Palace Exit (East)', 'Desert Palace Lone Stairs'), ('Desert Palace Exit (North)', 'Desert Palace Entrance (North) Spot'), - ('Eastern Palace', 'Eastern Portal'), ('Eastern Palace Exit', 'Light World'), ('Tower of Hera', 'Hera Portal'), @@ -3128,66 +2486,9 @@ default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert South ('Hyrule Castle Entrance (South)', 'Hyrule Castle South Portal'), ('Hyrule Castle Entrance (West)', 'Hyrule Castle West Portal'), ('Hyrule Castle Entrance (East)', 'Hyrule Castle East Portal'), - ('Hyrule Castle Exit (South)', 'Hyrule Castle Courtyard'), - ('Hyrule Castle Exit (West)', 'Hyrule Castle Ledge'), - ('Hyrule Castle Exit (East)', 'Hyrule Castle Ledge'), - ('Agahnims Tower', 'Agahnims Tower Portal'), - ('Agahnims Tower Exit', 'Hyrule Castle Ledge'), - - ('Thieves Town', 'Thieves Town Portal'), - ('Thieves Town Exit', 'West Dark World'), - ('Skull Woods First Section Hole (East)', 'Skull Pinball'), - ('Skull Woods First Section Hole (West)', 'Skull Left Drop'), - ('Skull Woods First Section Hole (North)', 'Skull Pot Circle'), - ('Skull Woods First Section Door', 'Skull 1 Portal'), - ('Skull Woods First Section Exit', 'Skull Woods Forest'), - ('Skull Woods Second Section Hole', 'Skull Back Drop'), - ('Skull Woods Second Section Door (East)', 'Skull 2 East Portal'), - ('Skull Woods Second Section Door (West)', 'Skull 2 West Portal'), - ('Skull Woods Second Section Exit (East)', 'Skull Woods Forest'), - ('Skull Woods Second Section Exit (West)', 'Skull Woods Forest (West)'), - ('Skull Woods Final Section', 'Skull 3 Portal'), - ('Skull Woods Final Section Exit', 'Skull Woods Forest (West)'), - ('Ice Palace', 'Ice Portal'), - ('Ice Palace Exit', 'Dark Lake Hylia Central Island'), - ('Misery Mire', 'Mire Portal'), - ('Misery Mire Exit', 'Dark Desert'), - ('Palace of Darkness', 'Palace of Darkness Portal'), - ('Palace of Darkness Exit', 'East Dark World'), - ('Swamp Palace', 'Swamp Portal'), # requires additional patch for flooding moat if moved - ('Swamp Palace Exit', 'South Dark World'), - - ('Turtle Rock', 'Turtle Rock Main Portal'), - ('Turtle Rock Exit (Front)', 'Dark Death Mountain (Top)'), - ('Turtle Rock Ledge Exit (West)', 'Dark Death Mountain Ledge'), - ('Turtle Rock Ledge Exit (East)', 'Dark Death Mountain Ledge'), - ('Dark Death Mountain Ledge (West)', 'Turtle Rock Lazy Eyes Portal'), - ('Dark Death Mountain Ledge (East)', 'Turtle Rock Chest Portal'), - ('Turtle Rock Isolated Ledge Exit', 'Dark Death Mountain Isolated Ledge'), - ('Turtle Rock Isolated Ledge Entrance', 'Turtle Rock Eye Bridge Portal'), - - ('Ganons Tower', 'Ganons Tower Portal'), - ('Ganons Tower Exit', 'Dark Death Mountain (Top)') - ] - -inverted_default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert South Portal'), - ('Desert Palace Entrance (West)', 'Desert West Portal'), - ('Desert Palace Entrance (North)', 'Desert Back Portal'), - ('Desert Palace Entrance (East)', 'Desert East Portal'), - ('Desert Palace Exit (South)', 'Desert Palace Stairs'), - ('Desert Palace Exit (West)', 'Desert Ledge'), - ('Desert Palace Exit (East)', 'Desert Palace Lone Stairs'), - ('Desert Palace Exit (North)', 'Desert Palace Entrance (North) Spot'), - ('Eastern Palace', 'Eastern Portal'), - ('Eastern Palace Exit', 'Light World'), - ('Tower of Hera', 'Hera Portal'), - ('Tower of Hera Exit', 'Death Mountain (Top)'), - ('Hyrule Castle Entrance (South)', 'Hyrule Castle South Portal'), - ('Hyrule Castle Entrance (West)', 'Hyrule Castle West Portal'), - ('Hyrule Castle Entrance (East)', 'Hyrule Castle East Portal'), - ('Hyrule Castle Exit (South)', 'Light World'), ('Hyrule Castle Exit (West)', 'Hyrule Castle Ledge'), ('Hyrule Castle Exit (East)', 'Hyrule Castle Ledge'), + ('Thieves Town', 'Thieves Town Portal'), ('Thieves Town Exit', 'West Dark World'), ('Skull Woods First Section Hole (East)', 'Skull Pinball'), @@ -3209,21 +2510,34 @@ inverted_default_dungeon_connections = [('Desert Palace Entrance (South)', 'Dese ('Palace of Darkness Exit', 'East Dark World'), ('Swamp Palace', 'Swamp Portal'), # requires additional patch for flooding moat if moved ('Swamp Palace Exit', 'South Dark World'), + ('Turtle Rock', 'Turtle Rock Main Portal'), ('Turtle Rock Ledge Exit (West)', 'Dark Death Mountain Ledge'), ('Turtle Rock Ledge Exit (East)', 'Dark Death Mountain Ledge'), ('Dark Death Mountain Ledge (West)', 'Turtle Rock Lazy Eyes Portal'), ('Dark Death Mountain Ledge (East)', 'Turtle Rock Chest Portal'), ('Turtle Rock Isolated Ledge Exit', 'Dark Death Mountain Isolated Ledge'), - ('Turtle Rock Isolated Ledge Entrance', 'Turtle Rock Eye Bridge Portal'), - ('Agahnims Tower', 'Ganons Tower Portal'), - ('Ganons Tower Exit', 'Hyrule Castle Ledge'), - ('Ganons Tower', 'Agahnims Tower Portal'), - ('Agahnims Tower Exit', 'Dark Death Mountain'), - ('Turtle Rock Exit (Front)', 'Dark Death Mountain'), - ('Ice Palace Exit', 'Dark Lake Hylia') + ('Turtle Rock Isolated Ledge Entrance', 'Turtle Rock Eye Bridge Portal') ] +open_default_dungeon_connections = [('Hyrule Castle Entrance (South)', 'Hyrule Castle South Portal'), + ('Agahnims Tower', 'Agahnims Tower Portal'), + ('Agahnims Tower Exit', 'Hyrule Castle Ledge'), + ('Ice Palace Exit', 'Dark Lake Hylia Central Island'), + ('Turtle Rock Exit (Front)', 'Dark Death Mountain (Top)'), + ('Ganons Tower', 'Ganons Tower Portal'), + ('Ganons Tower Exit', 'Dark Death Mountain (Top)') + ] + +inverted_default_dungeon_connections = [('Hyrule Castle Entrance (South)', 'Hyrule Castle South Portal'), + ('Agahnims Tower', 'Ganons Tower Portal'), + ('Agahnims Tower Exit', 'Dark Death Mountain'), + ('Ice Palace Exit', 'Dark Lake Hylia'), + ('Turtle Rock Exit (Front)', 'Dark Death Mountain'), + ('Ganons Tower', 'Agahnims Tower Portal'), + ('Ganons Tower Exit', 'Hyrule Castle Ledge') + ] + indirect_connections = { 'Turtle Rock (Top)': 'Turtle Rock', 'East Dark World': 'Pyramid Fairy', diff --git a/Main.py b/Main.py index 9c2f1441..da28d6b3 100644 --- a/Main.py +++ b/Main.py @@ -16,7 +16,7 @@ from OverworldGlitchRules import create_owg_connections from PotShuffle import shuffle_pots, shuffle_pot_switches from Regions import create_regions, create_shops, mark_light_world_regions, create_dungeon_regions, adjust_locations from InvertedRegions import create_inverted_regions, mark_dark_world_regions -from EntranceShuffle import link_entrances, link_inverted_entrances +from EntranceShuffle import link_entrances from Rom import patch_rom, patch_race_rom, patch_enemizer, apply_rom_settings, LocalRom, JsonRom, get_hash_string from Doors import create_doors from DoorShuffle import link_doors, connect_portal, link_doors_prep @@ -224,10 +224,7 @@ def main(args, seed=None, fish=None): if world.experimental[player] or world.shuffle[player] in ['lite', 'lean'] or world.shuffletavern[player] or (world.customizer and world.customizer.get_entrances()): link_entrances_new(world, player) else: - if world.mode[player] != 'inverted': - link_entrances(world, player) - else: - link_inverted_entrances(world, player) + link_entrances(world, player) logger.info(world.fish.translate("cli", "cli", "shuffling.prep")) for player in range(1, world.players + 1): diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index a5a66c54..403b5488 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -68,8 +68,10 @@ def link_entrances_new(world, player): avail_pool.one_way_map = one_way_map # setup mandatory connections + for exit_name, region_name in mandatory_connections: + connect_simple(world, exit_name, region_name, player) if not avail_pool.inverted: - for exit_name, region_name in mandatory_connections: + for exit_name, region_name in open_mandatory_connections: connect_simple(world, exit_name, region_name, player) else: for exit_name, region_name in inverted_mandatory_connections: @@ -772,7 +774,7 @@ def do_vanilla_connect(pool_def, avail): elif pool_def['condition'] == 'pottery': # this condition involves whether caves with pots are shuffled or not if avail.world.pottery[avail.player] not in ['none', 'keys', 'dungeon']: return - defaults = inverted_default_connections if avail.inverted else default_connections + defaults = default_connections + (inverted_default_connections if avail.inverted else open_default_connections) for entrance in pool_def['entrances']: if entrance in avail.entrances: target = defaults[entrance] @@ -1842,17 +1844,10 @@ Inverted_Bomb_Shop_Options = [ # 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'), - ('Sanctuary S&Q', 'Sanctuary'), - ('Old Man S&Q', 'Old Man House'), - ('Other World S&Q', 'East Dark World'), ('Lake Hylia Central Island Pier', 'Lake Hylia Central Island'), - ('Lake Hylia Central Island Teleporter', 'Dark Lake Hylia Central Island'), ('Zoras River', 'Zoras River'), - ('Zora Waterfall Entryway', 'Zora Waterfall Entryway'), - ('Zora Waterfall Water Drop', 'Light World'), ('Kings Grave Outer Rocks', 'Kings Grave Area'), ('Kings Grave Inner Rocks', 'Light World'), - ('Kings Grave Mirror Spot', 'Kings Grave Area'), ('Kakariko Well (top to bottom)', 'Kakariko Well (bottom)'), ('Kakariko Well (top to back)', 'Kakariko Well (back)'), ('Master Sword Meadow', 'Master Sword Meadow'), @@ -1866,10 +1861,7 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Desert Palace Stairs Drop', 'Light World'), ('Desert Palace Entrance (North) Rocks', 'Desert Palace Entrance (North) Spot'), ('Desert Ledge Return Rocks', 'Desert Ledge'), - ('Hyrule Castle Ledge Courtyard Drop', 'Hyrule Castle Courtyard'), - ('Hyrule Castle Main Gate', 'Hyrule Castle Courtyard'), ('Sewer Drop', 'Sewers Rat Path'), - ('Flute Spot 1', 'Death Mountain'), ('Death Mountain Entrance Rock', 'Death Mountain Entrance'), ('Death Mountain Entrance Drop', 'Light World'), ('Spectacle Rock Cave Drop', 'Spectacle Rock Cave (Bottom)'), @@ -1889,29 +1881,19 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('East Death Mountain (Top)', 'East Death Mountain (Top)'), ('Death Mountain (Top)', 'Death Mountain (Top)'), ('Death Mountain Drop', 'Death Mountain'), - ('Spectacle Rock Drop', 'Death Mountain (Top)'), - - ('Top of Pyramid', 'East Dark World'), ('Dark Lake Hylia Drop (East)', 'Dark Lake Hylia'), ('Dark Lake Hylia Drop (South)', 'Dark Lake Hylia'), ('Dark Lake Hylia Teleporter', 'Dark Lake Hylia'), - ('Dark Lake Hylia Ledge', 'Dark Lake Hylia Ledge'), ('Dark Lake Hylia Ledge Drop', 'Dark Lake Hylia'), ('East Dark World Pier', 'East Dark World'), - ('Lake Hylia Island Mirror Spot', 'Lake Hylia Island'), - ('Lake Hylia Central Island Mirror Spot', 'Lake Hylia Central Island'), - ('Hyrule Castle Ledge Mirror Spot', 'Hyrule Castle Ledge'), ('South Dark World Bridge', 'South Dark World'), ('East Dark World Bridge', 'East Dark World'), - ('Maze Race Mirror Spot', 'Maze Race Ledge'), ('Village of Outcasts Heavy Rock', 'West Dark World'), ('Village of Outcasts Drop', 'South Dark World'), ('Village of Outcasts Eastern Rocks', 'Hammer Peg Area'), ('Village of Outcasts Pegs', 'Dark Grassy Lawn'), ('Peg Area Rocks', 'West Dark World'), ('Grassy Lawn Pegs', 'West Dark World'), - ('Bat Cave Drop Ledge Mirror Spot', 'Bat Cave Drop Ledge'), - ('East Dark World River Pier', 'East Dark World'), ('West Dark World Gap', 'West Dark World'), ('East Dark World Broken Bridge Pass', 'East Dark World'), ('Catfish Exit Rock', 'Northeast Dark World'), @@ -1919,21 +1901,10 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Northeast Dark World Broken Bridge Pass', 'Northeast Dark World'), ('Bumper Cave Entrance Rock', 'Bumper Cave Entrance'), ('Bumper Cave Entrance Drop', 'West Dark World'), - ('Bumper Cave Entrance Mirror Spot', 'Death Mountain Entrance'), ('Bumper Cave Ledge Drop', 'West Dark World'), - ('Bumper Cave Ledge Mirror Spot', 'Death Mountain Return Ledge'), - ('Bumper Cave Top To Bottom', 'Bumper Cave (bottom)'), ('Bumper Cave Bottom to Top', 'Bumper Cave (top)'), + ('Bumper Cave Top To Bottom', 'Bumper Cave (bottom)'), ('Skull Woods Forest', 'Skull Woods Forest'), - ('Desert Ledge Mirror Spot', 'Desert Ledge'), - ('Desert Ledge (Northeast) Mirror Spot', 'Desert Ledge (Northeast)'), - ('Desert Palace Entrance (North) Mirror Spot', 'Desert Palace Entrance (North) Spot'), - ('Dark Desert Teleporter', 'Dark Desert'), - ('Desert Palace Stairs Mirror Spot', 'Desert Palace Stairs'), - ('East Hyrule Teleporter', 'East Dark World'), - ('South Hyrule Teleporter', 'South Dark World'), - ('Kakariko Teleporter', 'West Dark World'), - ('Death Mountain Teleporter', 'Dark Death Mountain (West Bottom)'), ('Paradox Cave Push Block Reverse', 'Paradox Cave Chest Area'), ('Paradox Cave Push Block', 'Paradox Cave Front'), ('Paradox Cave Chest Area NE', 'Paradox Cave Bomb Area'), @@ -1941,17 +1912,12 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Paradox Cave Drop', 'Paradox Cave Chest Area'), ('Light World Death Mountain Shop', 'Light World Death Mountain Shop'), ('Fairy Ascension Rocks', 'Fairy Ascension Plateau'), - ('Fairy Ascension Mirror Spot', 'Fairy Ascension Plateau'), ('Fairy Ascension Drop', 'East Death Mountain (Bottom)'), ('Fairy Ascension Ledge Drop', 'Fairy Ascension Plateau'), - ('Fairy Ascension Ledge', 'Fairy Ascension Ledge'), ('Fairy Ascension Cave Climb', 'Fairy Ascension Cave (Top)'), ('Fairy Ascension Cave Pots', 'Fairy Ascension Cave (Bottom)'), ('Fairy Ascension Cave Drop', 'Fairy Ascension Cave (Drop)'), - ('Spectacle Rock Mirror Spot', 'Spectacle Rock'), ('Dark Death Mountain Drop (East)', 'Dark Death Mountain (East Bottom)'), - ('Dark Death Mountain Drop (West)', 'Dark Death Mountain (West Bottom)'), - ('East Death Mountain (Top) Mirror Spot', 'East Death Mountain (Top)'), ('Superbunny Cave Climb', 'Superbunny Cave (Top)'), ('Hookshot Cave Front to Middle', 'Hookshot Cave (Middle)'), ('Hookshot Cave Middle to Front', 'Hookshot Cave (Front)'), @@ -1959,118 +1925,95 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Hookshot Cave Back to Middle', 'Hookshot Cave (Middle)'), ('Hookshot Cave Bonk Path', 'Hookshot Cave (Bonk Islands)'), ('Hookshot Cave Hook Path', 'Hookshot Cave (Hook Islands)'), - ('Turtle Rock Teleporter', 'Turtle Rock (Top)'), - ('Turtle Rock Drop', 'Dark Death Mountain (Top)'), - ('Floating Island Drop', 'Dark Death Mountain (Top)'), - ('Floating Island Mirror Spot', 'Death Mountain Floating Island (Light World)'), - ('East Death Mountain Teleporter', 'Dark Death Mountain (East Bottom)'), - ('Isolated Ledge Mirror Spot', 'Fairy Ascension Ledge'), - ('Spiral Cave Mirror Spot', 'Spiral Cave Ledge'), - ('Mimic Cave Mirror Spot', 'Mimic Cave Ledge'), - ('Cave 45 Mirror Spot', 'Cave 45 Ledge'), - ('Bombos Tablet Mirror Spot', 'Bombos Tablet Ledge'), - ('Graveyard Ledge Mirror Spot', 'Graveyard Ledge'), ('Ganon Drop', 'Bottom of Pyramid'), ('Pyramid Drop', 'East Dark World'), ('Maze Race Ledge Drop', 'Light World'), - ('Graveyard Ledge Drop', 'Light World'), - ('Cave 45 Ledge Drop', 'Light World'), - ('Checkerboard Ledge Drop', 'Light World'), - ('Desert Ledge Drop', 'Light World'), - ('Hyrule Castle Main Gate (North)', 'Light World'), - ('Hyrule Castle Ledge Drop', 'Light World'), - ] + ('Desert Ledge Drop', 'Light World') + ] -inverted_mandatory_connections = [('Links House S&Q', 'Links House'), - ('Sanctuary S&Q', 'Dark Sanctuary Hint'), +open_mandatory_connections = [('Sanctuary S&Q', 'Sanctuary'), + ('Old Man S&Q', 'Old Man House'), + ('Other World S&Q', 'East Dark World'), + ('Lake Hylia Central Island Teleporter', 'Dark Lake Hylia Central Island'), + ('Zora Waterfall Entryway', 'Zora Waterfall Entryway'), + ('Zora Waterfall Water Drop', 'Light World'), + ('Kings Grave Mirror Spot', 'Kings Grave Area'), + ('Hyrule Castle Ledge Courtyard Drop', 'Hyrule Castle Courtyard'), + ('Hyrule Castle Main Gate', 'Hyrule Castle Courtyard'), + ('Flute Spot 1', 'Death Mountain'), + ('Spectacle Rock Drop', 'Death Mountain (Top)'), + ('Top of Pyramid', 'East Dark World'), + ('Lake Hylia Island Mirror Spot', 'Lake Hylia Island'), + ('Lake Hylia Central Island Mirror Spot', 'Lake Hylia Central Island'), + ('Hyrule Castle Ledge Mirror Spot', 'Hyrule Castle Ledge'), + ('Maze Race Mirror Spot', 'Maze Race Ledge'), + ('Bat Cave Drop Ledge Mirror Spot', 'Bat Cave Drop Ledge'), + ('East Dark World River Pier', 'East Dark World'), + ('Bumper Cave Entrance Mirror Spot', 'Death Mountain Entrance'), + ('Bumper Cave Ledge Mirror Spot', 'Death Mountain Return Ledge'), + ('Desert Ledge Mirror Spot', 'Desert Ledge'), + ('Desert Ledge (Northeast) Mirror Spot', 'Desert Ledge (Northeast)'), + ('Desert Palace Entrance (North) Mirror Spot', 'Desert Palace Entrance (North) Spot'), + ('Dark Desert Teleporter', 'Dark Desert'), + ('Desert Palace Stairs Mirror Spot', 'Desert Palace Stairs'), + ('East Hyrule Teleporter', 'East Dark World'), + ('South Hyrule Teleporter', 'South Dark World'), + ('Kakariko Teleporter', 'West Dark World'), + ('Death Mountain Teleporter', 'Dark Death Mountain (West Bottom)'), + ('Fairy Ascension Mirror Spot', 'Fairy Ascension Plateau'), + ('Fairy Ascension Ledge', 'Fairy Ascension Ledge'), + ('Spectacle Rock Mirror Spot', 'Spectacle Rock'), + ('Dark Death Mountain Drop (West)', 'Dark Death Mountain (West Bottom)'), + ('East Death Mountain (Top) Mirror Spot', 'East Death Mountain (Top)'), + ('Turtle Rock Teleporter', 'Turtle Rock (Top)'), + ('Turtle Rock Drop', 'Dark Death Mountain (Top)'), + ('Floating Island Drop', 'Dark Death Mountain (Top)'), + ('Floating Island Mirror Spot', 'Death Mountain Floating Island (Light World)'), + ('East Death Mountain Teleporter', 'Dark Death Mountain (East Bottom)'), + ('Isolated Ledge Mirror Spot', 'Fairy Ascension Ledge'), + ('Spiral Cave Mirror Spot', 'Spiral Cave Ledge'), + ('Mimic Cave Mirror Spot', 'Mimic Cave Ledge'), + ('Cave 45 Mirror Spot', 'Cave 45 Ledge'), + ('Bombos Tablet Mirror Spot', 'Bombos Tablet Ledge'), + ('Graveyard Ledge Mirror Spot', 'Graveyard Ledge'), + ('Graveyard Ledge Drop', 'Light World'), + ('Cave 45 Ledge Drop', 'Light World'), + ('Checkerboard Ledge Drop', 'Light World'), + ('Hyrule Castle Main Gate (North)', 'Light World'), + ('Hyrule Castle Ledge Drop', 'Light World'), + ] + +inverted_mandatory_connections = [('Sanctuary S&Q', 'Dark Sanctuary Hint'), ('Old Man S&Q', 'Old Man House'), ('Other World S&Q', 'Hyrule Castle Ledge'), - ('Lake Hylia Central Island Pier', 'Lake Hylia Central Island'), ('Lake Hylia Island Pier', 'Lake Hylia Island'), ('Lake Hylia Warp', 'Northeast Light World'), ('Northeast Light World Warp', 'Light World'), - ('Zoras River', 'Zoras River'), ('Waterfall of Wishing Cave', 'Waterfall of Wishing Cave'), ('Northeast Light World Return', 'Northeast Light World'), - ('Kings Grave Outer Rocks', 'Kings Grave Area'), - ('Kings Grave Inner Rocks', 'Light World'), - ('Kakariko Well (top to bottom)', 'Kakariko Well (bottom)'), - ('Kakariko Well (top to back)', 'Kakariko Well (back)'), - ('Master Sword Meadow', 'Master Sword Meadow'), - ('Hobo Bridge', 'Hobo Bridge'), - ('Bat Cave Drop Ledge', 'Bat Cave Drop Ledge'), - ('Bat Cave Door', 'Bat Cave (left)'), - ('Lost Woods Hideout (top to bottom)', 'Lost Woods Hideout (bottom)'), - ('Lumberjack Tree (top to bottom)', 'Lumberjack Tree (bottom)'), - ('Blinds Hideout N', 'Blinds Hideout (Top)'), - ('Desert Palace Stairs', 'Desert Palace Stairs'), - ('Desert Palace Stairs Drop', 'Light World'), - ('Desert Palace Entrance (North) Rocks', 'Desert Palace Entrance (North) Spot'), - ('Desert Ledge Return Rocks', 'Desert Ledge'), - ('Sewer Drop', 'Sewers Rat Path'), - ('Death Mountain Entrance Rock', 'Death Mountain Entrance'), - ('Death Mountain Entrance Drop', 'Light World'), - ('Death Mountain Return Cave E', 'Death Mountain Return Cave (right)'), - ('Death Mountain Return Cave W', 'Death Mountain Return Cave (left)'), - ('Spectacle Rock Cave Drop', 'Spectacle Rock Cave (Bottom)'), - ('Spectacle Rock Cave Peak Drop', 'Spectacle Rock Cave (Bottom)'), - ('Death Mountain Return Ledge Drop', 'Light World'), - ('Old Man Cave Dropdown', 'Old Man Cave'), - ('Old Man House Front to Back', 'Old Man House Back'), - ('Old Man House Back to Front', 'Old Man House'), - ('Broken Bridge (West)', 'East Death Mountain (Bottom)'), - ('Broken Bridge (East)', 'Death Mountain'), - ('East Death Mountain Drop', 'East Death Mountain (Bottom)'), - ('Spiral Cave Ledge Access', 'Spiral Cave Ledge'), - ('Spiral Cave Ledge Drop', 'East Death Mountain (Bottom)'), - ('Spiral Cave (top to bottom)', 'Spiral Cave (Bottom)'), - ('East Death Mountain (Top)', 'East Death Mountain (Top)'), - ('Death Mountain (Top)', 'Death Mountain (Top)'), - ('Death Mountain Drop', 'Death Mountain'), - ('Dark Lake Hylia Drop (East)', 'Dark Lake Hylia'), - ('Dark Lake Hylia Drop (South)', 'Dark Lake Hylia'), - ('Dark Lake Hylia Teleporter', 'Dark Lake Hylia'), + ('Hyrule Castle Ledge Courtyard Drop', 'Light World'), + ('DDM Flute', 'The Sky'), + ('DDM Landing', 'Dark Death Mountain'), + ('NEDW Flute', 'The Sky'), + ('NEDW Landing', 'Northeast Dark World'), + ('WDW Flute', 'The Sky'), + ('WDW Landing', 'West Dark World'), + ('SDW Flute', 'The Sky'), + ('SDW Landing', 'South Dark World'), + ('EDW Flute', 'The Sky'), + ('EDW Landing', 'East Dark World'), + ('DLHL Flute', 'The Sky'), + ('DLHL Landing', 'Dark Lake Hylia Ledge'), + ('DD Flute', 'The Sky'), + ('DD Landing', 'Dark Desert Ledge'), + ('EDDM Flute', 'The Sky'), + ('Dark Grassy Lawn Flute', 'The Sky'), + ('Hammer Peg Area Flute', 'The Sky'), ('Dark Lake Hylia Ledge Pier', 'Dark Lake Hylia Ledge'), - ('Dark Lake Hylia Ledge Drop', 'Dark Lake Hylia'), ('Ice Palace Missing Wall', 'Dark Lake Hylia Central Island'), ('Dark Lake Hylia Shallows', 'Dark Lake Hylia'), - ('East Dark World Pier', 'East Dark World'), - ('South Dark World Bridge', 'South Dark World'), - ('East Dark World Bridge', 'East Dark World'), - ('Village of Outcasts Heavy Rock', 'West Dark World'), - ('Village of Outcasts Drop', 'South Dark World'), - ('Village of Outcasts Eastern Rocks', 'Hammer Peg Area'), - ('Village of Outcasts Pegs', 'Dark Grassy Lawn'), - ('Peg Area Rocks', 'West Dark World'), - ('Grassy Lawn Pegs', 'West Dark World'), ('East Dark World River Pier', 'Northeast Dark World'), - ('West Dark World Gap', 'West Dark World'), - ('East Dark World Broken Bridge Pass', 'East Dark World'), - ('Northeast Dark World Broken Bridge Pass', 'Northeast Dark World'), - ('Catfish Exit Rock', 'Northeast Dark World'), - ('Catfish Entrance Rock', 'Catfish'), - ('Bumper Cave Entrance Rock', 'Bumper Cave Entrance'), - ('Bumper Cave Entrance Drop', 'West Dark World'), - ('Bumper Cave Ledge Drop', 'West Dark World'), - ('Bumper Cave Top To Bottom', 'Bumper Cave (bottom)'), - ('Bumper Cave Bottom to Top', 'Bumper Cave (top)'), - ('Skull Woods Forest', 'Skull Woods Forest'), - ('Paradox Cave Push Block Reverse', 'Paradox Cave Chest Area'), - ('Paradox Cave Push Block', 'Paradox Cave Front'), - ('Paradox Cave Chest Area NE', 'Paradox Cave Bomb Area'), - ('Paradox Cave Bomb Jump', 'Paradox Cave'), - ('Paradox Cave Drop', 'Paradox Cave Chest Area'), - ('Light World Death Mountain Shop', 'Light World Death Mountain Shop'), - ('Fairy Ascension Rocks', 'Fairy Ascension Plateau'), - ('Fairy Ascension Drop', 'East Death Mountain (Bottom)'), - ('Fairy Ascension Ledge Drop', 'Fairy Ascension Plateau'), ('Fairy Ascension Ledge Access', 'Fairy Ascension Ledge'), - ('Fairy Ascension Cave Climb', 'Fairy Ascension Cave (Top)'), - ('Fairy Ascension Cave Pots', 'Fairy Ascension Cave (Bottom)'), - ('Fairy Ascension Cave Drop', 'Fairy Ascension Cave (Drop)'), - ('Dark Death Mountain Drop (East)', 'Dark Death Mountain (East Bottom)'), - ('Ganon Drop', 'Bottom of Pyramid'), - ('Pyramid Drop', 'East Dark World'), ('Post Aga Teleporter', 'Light World'), ('Secret Passage Inner Bushes', 'Light World'), ('Secret Passage Outer Bushes', 'Hyrule Castle Secret Entrance Area'), @@ -2085,19 +2028,10 @@ inverted_mandatory_connections = [('Links House S&Q', 'Links House'), ('Light World River Drop', 'River'), ('Light World Pier', 'Light World'), ('Potion Shop Pier', 'Potion Shop Area'), - ('Hyrule Castle Ledge Courtyard Drop', 'Light World'), ('Mimic Cave Ledge Access', 'Mimic Cave Ledge'), ('Mimic Cave Ledge Drop', 'East Death Mountain (Bottom)'), ('Turtle Rock Tail Drop', 'Turtle Rock (Top)'), ('Turtle Rock Drop', 'Dark Death Mountain'), - ('Superbunny Cave Climb', 'Superbunny Cave (Top)'), - ('Hookshot Cave Front to Middle', 'Hookshot Cave (Middle)'), - ('Hookshot Cave Middle to Front', 'Hookshot Cave (Front)'), - ('Hookshot Cave Middle to Back', 'Hookshot Cave (Back)'), - ('Hookshot Cave Back to Middle', 'Hookshot Cave (Middle)'), - ('Hookshot Cave Bonk Path', 'Hookshot Cave (Bonk Islands)'), - ('Hookshot Cave Hook Path', 'Hookshot Cave (Hook Islands)'), - ('Desert Ledge Drop', 'Light World'), ('Floating Island Drop', 'Dark Death Mountain'), ('Dark Lake Hylia Central Island Teleporter', 'Lake Hylia Central Island'), ('Dark Desert Teleporter', 'Light World'), @@ -2131,41 +2065,21 @@ inverted_mandatory_connections = [('Links House S&Q', 'Links House'), ('Catfish Mirror Spot', 'Catfish'), ('Shopping Mall Mirror Spot', 'Dark Lake Hylia Ledge'), ('Skull Woods Mirror Spot', 'Skull Woods Forest (West)'), - ('DDM Flute', 'The Sky'), - ('DDM Landing', 'Dark Death Mountain'), - ('NEDW Flute', 'The Sky'), - ('NEDW Landing', 'Northeast Dark World'), - ('WDW Flute', 'The Sky'), - ('WDW Landing', 'West Dark World'), - ('SDW Flute', 'The Sky'), - ('SDW Landing', 'South Dark World'), - ('EDW Flute', 'The Sky'), - ('EDW Landing', 'East Dark World'), - ('DLHL Flute', 'The Sky'), - ('DLHL Landing', 'Dark Lake Hylia Ledge'), - ('DD Flute', 'The Sky'), - ('DD Landing', 'Dark Desert Ledge'), - ('EDDM Flute', 'The Sky'), - ('Dark Grassy Lawn Flute', 'The Sky'), - ('Hammer Peg Area Flute', 'The Sky'), ('Bush Covered Lawn Inner Bushes', 'Light World'), ('Bush Covered Lawn Outer Bushes', 'Bush Covered Lawn'), ('Bush Covered Lawn Mirror Spot', 'Dark Grassy Lawn'), ('Bomb Hut Inner Bushes', 'Light World'), ('Bomb Hut Outer Bushes', 'Bomb Hut Area'), - ('Bomb Hut Mirror Spot', 'West Dark World'), - ('Maze Race Ledge Drop', 'Light World')] + ('Bomb Hut Mirror Spot', 'West Dark World') + ] # non-shuffled entrance links -default_connections = {'Links House': 'Links House', - 'Links House Exit': 'Light World', - 'Waterfall of Wishing': 'Waterfall of Wishing', +default_connections = {'Waterfall of Wishing': 'Waterfall of Wishing', 'Blinds Hideout': 'Blinds Hideout', 'Dam': 'Dam', 'Lumberjack House': 'Lumberjack House', 'Hyrule Castle Secret Entrance Drop': 'Hyrule Castle Secret Entrance', 'Hyrule Castle Secret Entrance Stairs': 'Hyrule Castle Secret Entrance', - 'Hyrule Castle Secret Entrance Exit': 'Hyrule Castle Courtyard', 'Bonk Fairy (Light)': 'Bonk Fairy (Light)', 'Lake Hylia Fairy': 'Lake Hylia Healer Fairy', 'Lake Hylia Fortune Teller': 'Lake Hylia Fortune Teller', @@ -2211,7 +2125,7 @@ default_connections = {'Links House': 'Links House', 'Graveyard Cave': 'Graveyard Cave', 'Checkerboard Cave': 'Checkerboard Cave', 'Mini Moldorm Cave': 'Mini Moldorm Cave', - 'Long Fairy Cave': 'Long Fairy Cave', # near East Light World Teleporter + 'Long Fairy Cave': 'Long Fairy Cave', 'Good Bee Cave': 'Good Bee Cave', '20 Rupee Cave': '20 Rupee Cave', '50 Rupee Cave': '50 Rupee Cave', @@ -2224,22 +2138,14 @@ default_connections = {'Links House': 'Links House', 'Two Brothers House (West)': 'Two Brothers House', 'Two Brothers House Exit (East)': 'Light World', 'Two Brothers House Exit (West)': 'Maze Race Ledge', - 'Sanctuary': 'Sanctuary Portal', 'Sanctuary Grave': 'Sewer Drop', 'Sanctuary Exit': 'Light World', - - 'Old Man Cave (West)': 'Old Man Cave Ledge', - 'Old Man Cave (East)': 'Old Man Cave', - 'Old Man Cave Exit (West)': 'Light World', - 'Old Man Cave Exit (East)': 'Death Mountain', 'Old Man House (Bottom)': 'Old Man House', 'Old Man House Exit (Bottom)': 'Death Mountain', 'Old Man House (Top)': 'Old Man House Back', 'Old Man House Exit (Top)': 'Death Mountain', 'Death Mountain Return Cave (East)': 'Death Mountain Return Cave (right)', - 'Death Mountain Return Cave (West)': 'Death Mountain Return Cave (left)', - 'Death Mountain Return Cave Exit (West)': 'Death Mountain Return Ledge', 'Death Mountain Return Cave Exit (East)': 'Death Mountain', 'Spectacle Rock Cave Peak': 'Spectacle Rock Cave (Peak)', 'Spectacle Rock Cave (Bottom)': 'Spectacle Rock Cave (Bottom)', @@ -2262,11 +2168,9 @@ default_connections = {'Links House': 'Links House', 'Spiral Cave (Bottom)': 'Spiral Cave (Bottom)', 'Spiral Cave Exit': 'East Death Mountain (Bottom)', 'Spiral Cave Exit (Top)': 'Spiral Cave Ledge', - 'Pyramid Fairy': 'Pyramid Fairy', 'East Dark World Hint': 'East Dark World Hint', 'Palace of Darkness Hint': 'Palace of Darkness Hint', - 'Big Bomb Shop': 'Big Bomb Shop', 'Dark Lake Hylia Shop': 'Dark Lake Hylia Shop', 'Dark Lake Hylia Fairy': 'Dark Lake Hylia Healer Fairy', 'Dark Lake Hylia Ledge Fairy': 'Dark Lake Hylia Ledge Healer Fairy', @@ -2278,18 +2182,13 @@ default_connections = {'Links House': 'Links House', 'C-Shaped House': 'C-Shaped House', 'Chest Game': 'Chest Game', 'Dark World Hammer Peg Cave': 'Dark World Hammer Peg Cave', - 'Bumper Cave (Bottom)': 'Bumper Cave (bottom)', - 'Bumper Cave (Top)': 'Bumper Cave (top)', 'Red Shield Shop': 'Red Shield Shop', 'Dark Sanctuary Hint': 'Dark Sanctuary Hint', - 'Dark Sanctuary Hint Exit': 'West Dark World', 'Fortune Teller (Dark)': 'Fortune Teller (Dark)', 'Dark World Shop': 'Village of Outcasts Shop', 'Dark World Lumberjack Shop': 'Dark World Lumberjack Shop', 'Dark World Potion Shop': 'Dark World Potion Shop', 'Archery Game': 'Archery Game', - 'Bumper Cave Exit (Top)': 'Bumper Cave Ledge', - 'Bumper Cave Exit (Bottom)': 'West Dark World', 'Mire Shed': 'Mire Shed', 'Dark Desert Hint': 'Dark Desert Hint', 'Dark Desert Fairy': 'Dark Desert Healer Fairy', @@ -2297,167 +2196,57 @@ default_connections = {'Links House': 'Links House', 'Hookshot Cave': 'Hookshot Cave (Front)', 'Superbunny Cave (Top)': 'Superbunny Cave (Top)', 'Cave Shop (Dark Death Mountain)': 'Cave Shop (Dark Death Mountain)', - 'Dark Death Mountain Fairy': 'Dark Death Mountain Healer Fairy', 'Superbunny Cave (Bottom)': 'Superbunny Cave (Bottom)', - 'Superbunny Cave Exit (Top)': 'Dark Death Mountain (Top)', 'Superbunny Cave Exit (Bottom)': 'Dark Death Mountain (East Bottom)', - 'Hookshot Cave Front Exit': 'Dark Death Mountain (Top)', 'Hookshot Cave Back Exit': 'Death Mountain Floating Island (Dark World)', 'Hookshot Cave Back Entrance': 'Hookshot Cave (Back)', - 'Mimic Cave': 'Mimic Cave', + 'Mimic Cave': 'Mimic Cave' + } - 'Pyramid Hole': 'Pyramid', - 'Pyramid Exit': 'Pyramid Ledge', - 'Pyramid Entrance': 'Bottom of Pyramid'} +open_default_connections = {'Links House': 'Links House', + 'Links House Exit': 'Light World', + 'Hyrule Castle Secret Entrance Exit': 'Hyrule Castle Courtyard', + 'Old Man Cave (West)': 'Old Man Cave Ledge', + 'Old Man Cave (East)': 'Old Man Cave', + 'Old Man Cave Exit (West)': 'Light World', + 'Old Man Cave Exit (East)': 'Death Mountain', + 'Death Mountain Return Cave (West)': 'Death Mountain Return Cave (left)', + 'Death Mountain Return Cave Exit (West)': 'Death Mountain Return Ledge', + 'Big Bomb Shop': 'Big Bomb Shop', + 'Bumper Cave (Bottom)': 'Bumper Cave (bottom)', + 'Bumper Cave (Top)': 'Bumper Cave (top)', + 'Bumper Cave Exit (Top)': 'Bumper Cave Ledge', + 'Bumper Cave Exit (Bottom)': 'West Dark World', + 'Dark Death Mountain Fairy': 'Dark Death Mountain Healer Fairy', + 'Superbunny Cave Exit (Top)': 'Dark Death Mountain (Top)', + 'Hookshot Cave Front Exit': 'Dark Death Mountain (Top)', + 'Pyramid Hole': 'Pyramid', + 'Pyramid Exit': 'Pyramid Ledge', + 'Pyramid Entrance': 'Bottom of Pyramid' + } -inverted_default_connections = {'Waterfall of Wishing': 'Waterfall of Wishing', - 'Blinds Hideout': 'Blinds Hideout', - 'Dam': 'Dam', - 'Lumberjack House': 'Lumberjack House', - 'Hyrule Castle Secret Entrance Drop': 'Hyrule Castle Secret Entrance', - 'Hyrule Castle Secret Entrance Stairs': 'Hyrule Castle Secret Entrance', - 'Hyrule Castle Secret Entrance Exit': 'Light World', - 'Bonk Fairy (Light)': 'Bonk Fairy (Light)', - 'Lake Hylia Fairy': 'Lake Hylia Healer Fairy', - 'Lake Hylia Fortune Teller': 'Lake Hylia Fortune Teller', - 'Light Hype Fairy': 'Swamp Healer Fairy', - 'Desert Fairy': 'Desert Healer Fairy', - 'Kings Grave': 'Kings Grave', - 'Tavern North': 'Tavern', - 'Chicken House': 'Chicken House', - 'Aginahs Cave': 'Aginahs Cave', - 'Sahasrahlas Hut': 'Sahasrahlas Hut', - 'Cave Shop (Lake Hylia)': 'Cave Shop (Lake Hylia)', - 'Capacity Upgrade': 'Capacity Upgrade', - 'Kakariko Well Drop': 'Kakariko Well (top)', - 'Kakariko Well Cave': 'Kakariko Well (bottom)', - 'Kakariko Well Exit': 'Light World', - 'Blacksmiths Hut': 'Blacksmiths Hut', - 'Bat Cave Drop': 'Bat Cave (right)', - 'Bat Cave Cave': 'Bat Cave (left)', - 'Bat Cave Exit': 'Light World', - 'Sick Kids House': 'Sick Kids House', - 'Elder House (East)': 'Elder House', - 'Elder House (West)': 'Elder House', - 'Elder House Exit (East)': 'Light World', - 'Elder House Exit (West)': 'Light World', - 'North Fairy Cave Drop': 'North Fairy Cave', - 'North Fairy Cave': 'North Fairy Cave', - 'North Fairy Cave Exit': 'Light World', - 'Lost Woods Gamble': 'Lost Woods Gamble', - 'Fortune Teller (Light)': 'Fortune Teller (Light)', - 'Snitch Lady (East)': 'Snitch Lady (East)', - 'Snitch Lady (West)': 'Snitch Lady (West)', - 'Bush Covered House': 'Bush Covered House', - 'Tavern (Front)': 'Tavern (Front)', - 'Light World Bomb Hut': 'Light World Bomb Hut', - 'Kakariko Shop': 'Kakariko Shop', - 'Lost Woods Hideout Drop': 'Lost Woods Hideout (top)', - 'Lost Woods Hideout Stump': 'Lost Woods Hideout (bottom)', - 'Lost Woods Hideout Exit': 'Light World', - 'Lumberjack Tree Tree': 'Lumberjack Tree (top)', - 'Lumberjack Tree Cave': 'Lumberjack Tree (bottom)', - 'Lumberjack Tree Exit': 'Light World', - 'Cave 45': 'Cave 45', - 'Graveyard Cave': 'Graveyard Cave', - 'Checkerboard Cave': 'Checkerboard Cave', - 'Mini Moldorm Cave': 'Mini Moldorm Cave', - 'Long Fairy Cave': 'Long Fairy Cave', - 'Good Bee Cave': 'Good Bee Cave', - '20 Rupee Cave': '20 Rupee Cave', - '50 Rupee Cave': '50 Rupee Cave', - 'Ice Rod Cave': 'Ice Rod Cave', - 'Bonk Rock Cave': 'Bonk Rock Cave', - 'Library': 'Library', - 'Kakariko Gamble Game': 'Kakariko Gamble Game', - 'Potion Shop': 'Potion Shop', - 'Two Brothers House (East)': 'Two Brothers House', - 'Two Brothers House (West)': 'Two Brothers House', - 'Two Brothers House Exit (East)': 'Light World', - 'Two Brothers House Exit (West)': 'Maze Race Ledge', - 'Sanctuary': 'Sanctuary Portal', - 'Sanctuary Grave': 'Sewer Drop', - 'Sanctuary Exit': 'Light World', - 'Old Man House (Bottom)': 'Old Man House', - 'Old Man House Exit (Bottom)': 'Death Mountain', - 'Old Man House (Top)': 'Old Man House Back', - 'Old Man House Exit (Top)': 'Death Mountain', - 'Spectacle Rock Cave Peak': 'Spectacle Rock Cave (Peak)', - 'Spectacle Rock Cave (Bottom)': 'Spectacle Rock Cave (Bottom)', - 'Spectacle Rock Cave': 'Spectacle Rock Cave (Top)', - 'Spectacle Rock Cave Exit': 'Death Mountain', - 'Spectacle Rock Cave Exit (Top)': 'Death Mountain', - 'Spectacle Rock Cave Exit (Peak)': 'Death Mountain', - 'Paradox Cave (Bottom)': 'Paradox Cave Front', - 'Paradox Cave (Middle)': 'Paradox Cave', - 'Paradox Cave (Top)': 'Paradox Cave', - 'Paradox Cave Exit (Bottom)': 'East Death Mountain (Bottom)', - 'Paradox Cave Exit (Middle)': 'East Death Mountain (Bottom)', - 'Paradox Cave Exit (Top)': 'East Death Mountain (Top)', - 'Hookshot Fairy': 'Hookshot Fairy', - 'Fairy Ascension Cave (Bottom)': 'Fairy Ascension Cave (Bottom)', - 'Fairy Ascension Cave (Top)': 'Fairy Ascension Cave (Top)', - 'Fairy Ascension Cave Exit (Bottom)': 'Fairy Ascension Plateau', - 'Fairy Ascension Cave Exit (Top)': 'Fairy Ascension Ledge', - 'Spiral Cave': 'Spiral Cave (Top)', - 'Spiral Cave (Bottom)': 'Spiral Cave (Bottom)', - 'Spiral Cave Exit': 'East Death Mountain (Bottom)', - 'Spiral Cave Exit (Top)': 'Spiral Cave Ledge', - 'Pyramid Fairy': 'Pyramid Fairy', - 'East Dark World Hint': 'East Dark World Hint', - 'Palace of Darkness Hint': 'Palace of Darkness Hint', - 'Dark Lake Hylia Shop': 'Dark Lake Hylia Shop', - 'Dark Lake Hylia Fairy': 'Dark Lake Hylia Healer Fairy', - 'Dark Lake Hylia Ledge Fairy': 'Dark Lake Hylia Ledge Healer Fairy', - 'Dark Lake Hylia Ledge Spike Cave': 'Dark Lake Hylia Ledge Spike Cave', - 'Dark Lake Hylia Ledge Hint': 'Dark Lake Hylia Ledge Hint', - 'Hype Cave': 'Hype Cave', - 'Bonk Fairy (Dark)': 'Bonk Fairy (Dark)', - 'Brewery': 'Brewery', - 'C-Shaped House': 'C-Shaped House', - 'Chest Game': 'Chest Game', - 'Dark World Hammer Peg Cave': 'Dark World Hammer Peg Cave', - 'Red Shield Shop': 'Red Shield Shop', - 'Fortune Teller (Dark)': 'Fortune Teller (Dark)', - 'Dark World Shop': 'Village of Outcasts Shop', - 'Dark World Lumberjack Shop': 'Dark World Lumberjack Shop', - 'Dark World Potion Shop': 'Dark World Potion Shop', - 'Archery Game': 'Archery Game', - 'Mire Shed': 'Mire Shed', - 'Dark Desert Hint': 'Dark Desert Hint', - 'Dark Desert Fairy': 'Dark Desert Healer Fairy', - 'Spike Cave': 'Spike Cave', - 'Hookshot Cave': 'Hookshot Cave (Front)', - 'Superbunny Cave (Top)': 'Superbunny Cave (Top)', - 'Cave Shop (Dark Death Mountain)': 'Cave Shop (Dark Death Mountain)', - 'Superbunny Cave (Bottom)': 'Superbunny Cave (Bottom)', - 'Superbunny Cave Exit (Bottom)': 'Dark Death Mountain (East Bottom)', - 'Hookshot Cave Back Exit': 'Death Mountain Floating Island (Dark World)', - 'Hookshot Cave Back Entrance': 'Hookshot Cave (Back)', - 'Mimic Cave': 'Mimic Cave', - 'Inverted Pyramid Hole': 'Pyramid', - 'Links House': 'Links House', +inverted_default_connections = {'Links House': 'Big Bomb Shop', 'Links House Exit': 'South Dark World', - 'Big Bomb Shop': 'Big Bomb Shop', - 'Dark Sanctuary Hint': 'Dark Sanctuary Hint', - 'Dark Sanctuary Hint Exit': 'West Dark World', + 'Hyrule Castle Secret Entrance Exit': 'Light World', 'Old Man Cave (West)': 'Bumper Cave (bottom)', 'Old Man Cave (East)': 'Death Mountain Return Cave (left)', 'Old Man Cave Exit (West)': 'West Dark World', 'Old Man Cave Exit (East)': 'Dark Death Mountain', - 'Dark Death Mountain Fairy': 'Old Man Cave', + 'Death Mountain Return Cave (West)': 'Bumper Cave (top)', + 'Death Mountain Return Cave Exit (West)': 'Death Mountain', + 'Big Bomb Shop': 'Links House', 'Bumper Cave (Bottom)': 'Old Man Cave Ledge', 'Bumper Cave (Top)': 'Dark Death Mountain Healer Fairy', + 'Dark Sanctuary Hint Exit': 'West Dark World', 'Bumper Cave Exit (Top)': 'Death Mountain Return Ledge', 'Bumper Cave Exit (Bottom)': 'Light World', - 'Death Mountain Return Cave (West)': 'Bumper Cave (top)', - 'Death Mountain Return Cave (East)': 'Death Mountain Return Cave (right)', - 'Death Mountain Return Cave Exit (West)': 'Death Mountain', - 'Death Mountain Return Cave Exit (East)': 'Death Mountain', - 'Hookshot Cave Front Exit': 'Dark Death Mountain', + 'Dark Death Mountain Fairy': 'Old Man Cave', 'Superbunny Cave Exit (Top)': 'Dark Death Mountain', + 'Hookshot Cave Front Exit': 'Dark Death Mountain', + 'Inverted Pyramid Hole': 'Pyramid', 'Pyramid Exit': 'Light World', - 'Inverted Pyramid Entrance': 'Bottom of Pyramid'} + 'Inverted Pyramid Entrance': 'Bottom of Pyramid' + } # non shuffled dungeons default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert South Portal'), @@ -2468,7 +2257,6 @@ default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert South ('Desert Palace Exit (West)', 'Desert Ledge'), ('Desert Palace Exit (East)', 'Desert Palace Lone Stairs'), ('Desert Palace Exit (North)', 'Desert Palace Entrance (North) Spot'), - ('Eastern Palace', 'Eastern Portal'), ('Eastern Palace Exit', 'Light World'), ('Tower of Hera', 'Hera Portal'), @@ -2477,12 +2265,9 @@ default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert South ('Hyrule Castle Entrance (South)', 'Hyrule Castle South Portal'), ('Hyrule Castle Entrance (West)', 'Hyrule Castle West Portal'), ('Hyrule Castle Entrance (East)', 'Hyrule Castle East Portal'), - ('Hyrule Castle Exit (South)', 'Hyrule Castle Courtyard'), ('Hyrule Castle Exit (West)', 'Hyrule Castle Ledge'), ('Hyrule Castle Exit (East)', 'Hyrule Castle Ledge'), - ('Agahnims Tower', 'Agahnims Tower Portal'), - ('Agahnims Tower Exit', 'Hyrule Castle Ledge'), - + ('Thieves Town', 'Thieves Town Portal'), ('Thieves Town Exit', 'West Dark World'), ('Skull Woods First Section Hole (East)', 'Skull Pinball'), @@ -2498,7 +2283,6 @@ default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert South ('Skull Woods Final Section', 'Skull 3 Portal'), ('Skull Woods Final Section Exit', 'Skull Woods Forest (West)'), ('Ice Palace', 'Ice Portal'), - ('Ice Palace Exit', 'Dark Lake Hylia Central Island'), ('Misery Mire', 'Mire Portal'), ('Misery Mire Exit', 'Dark Desert'), ('Palace of Darkness', 'Palace of Darkness Portal'), @@ -2507,72 +2291,31 @@ default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert South ('Swamp Palace Exit', 'South Dark World'), ('Turtle Rock', 'Turtle Rock Main Portal'), - ('Turtle Rock Exit (Front)', 'Dark Death Mountain (Top)'), ('Turtle Rock Ledge Exit (West)', 'Dark Death Mountain Ledge'), ('Turtle Rock Ledge Exit (East)', 'Dark Death Mountain Ledge'), ('Dark Death Mountain Ledge (West)', 'Turtle Rock Lazy Eyes Portal'), ('Dark Death Mountain Ledge (East)', 'Turtle Rock Chest Portal'), ('Turtle Rock Isolated Ledge Exit', 'Dark Death Mountain Isolated Ledge'), - ('Turtle Rock Isolated Ledge Entrance', 'Turtle Rock Eye Bridge Portal'), + ('Turtle Rock Isolated Ledge Entrance', 'Turtle Rock Eye Bridge Portal') + ] - ('Ganons Tower', 'Ganons Tower Portal'), - ('Ganons Tower Exit', 'Dark Death Mountain (Top)') - ] +open_default_dungeon_connections = [('Hyrule Castle Entrance (South)', 'Hyrule Castle South Portal'), + ('Agahnims Tower', 'Agahnims Tower Portal'), + ('Agahnims Tower Exit', 'Hyrule Castle Ledge'), + ('Ice Palace Exit', 'Dark Lake Hylia Central Island'), + ('Turtle Rock Exit (Front)', 'Dark Death Mountain (Top)'), + ('Ganons Tower', 'Ganons Tower Portal'), + ('Ganons Tower Exit', 'Dark Death Mountain (Top)') + ] -inverted_default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert South Portal'), - ('Desert Palace Entrance (West)', 'Desert West Portal'), - ('Desert Palace Entrance (North)', 'Desert Back Portal'), - ('Desert Palace Entrance (East)', 'Desert East Portal'), - ('Desert Palace Exit (South)', 'Desert Palace Stairs'), - ('Desert Palace Exit (West)', 'Desert Ledge'), - ('Desert Palace Exit (East)', 'Desert Palace Lone Stairs'), - ('Desert Palace Exit (North)', 'Desert Palace Entrance (North) Spot'), - ('Eastern Palace', 'Eastern Portal'), - ('Eastern Palace Exit', 'Light World'), - ('Tower of Hera', 'Hera Portal'), - ('Tower of Hera Exit', 'Death Mountain (Top)'), - ('Hyrule Castle Entrance (South)', 'Hyrule Castle South Portal'), - ('Hyrule Castle Entrance (West)', 'Hyrule Castle West Portal'), - ('Hyrule Castle Entrance (East)', 'Hyrule Castle East Portal'), - ('Hyrule Castle Exit (South)', 'Light World'), - ('Hyrule Castle Exit (West)', 'Hyrule Castle Ledge'), - ('Hyrule Castle Exit (East)', 'Hyrule Castle Ledge'), - ('Thieves Town', 'Thieves Town Portal'), - ('Thieves Town Exit', 'West Dark World'), - ('Skull Woods First Section Hole (East)', 'Skull Pinball'), - ('Skull Woods First Section Hole (West)', 'Skull Left Drop'), - ('Skull Woods First Section Hole (North)', 'Skull Pot Circle'), - ('Skull Woods First Section Door', 'Skull 1 Portal'), - ('Skull Woods First Section Exit', 'Skull Woods Forest'), - ('Skull Woods Second Section Hole', 'Skull Back Drop'), - ('Skull Woods Second Section Door (East)', 'Skull 2 East Portal'), - ('Skull Woods Second Section Door (West)', 'Skull 2 West Portal'), - ('Skull Woods Second Section Exit (East)', 'Skull Woods Forest'), - ('Skull Woods Second Section Exit (West)', 'Skull Woods Forest (West)'), - ('Skull Woods Final Section', 'Skull 3 Portal'), - ('Skull Woods Final Section Exit', 'Skull Woods Forest (West)'), - ('Ice Palace', 'Ice Portal'), - ('Misery Mire', 'Mire Portal'), - ('Misery Mire Exit', 'Dark Desert'), - ('Palace of Darkness', 'Palace of Darkness Portal'), - ('Palace of Darkness Exit', 'East Dark World'), - # requires additional patch for flooding moat if moved - ('Swamp Palace', 'Swamp Portal'), - ('Swamp Palace Exit', 'South Dark World'), - ('Turtle Rock', 'Turtle Rock Main Portal'), - ('Turtle Rock Ledge Exit (West)', 'Dark Death Mountain Ledge'), - ('Turtle Rock Ledge Exit (East)', 'Dark Death Mountain Ledge'), - ('Dark Death Mountain Ledge (West)', 'Turtle Rock Lazy Eyes Portal'), - ('Dark Death Mountain Ledge (East)', 'Turtle Rock Chest Portal'), - ('Turtle Rock Isolated Ledge Exit', 'Dark Death Mountain Isolated Ledge'), - ('Turtle Rock Isolated Ledge Entrance', 'Turtle Rock Eye Bridge Portal'), +inverted_default_dungeon_connections = [('Hyrule Castle Entrance (South)', 'Hyrule Castle South Portal'), ('Agahnims Tower', 'Ganons Tower Portal'), - ('Ganons Tower Exit', 'Hyrule Castle Ledge'), - ('Ganons Tower', 'Agahnims Tower Portal'), ('Agahnims Tower Exit', 'Dark Death Mountain'), + ('Ice Palace Exit', 'Dark Lake Hylia'), ('Turtle Rock Exit (Front)', 'Dark Death Mountain'), - ('Ice Palace Exit', 'Dark Lake Hylia') - ] + ('Ganons Tower', 'Agahnims Tower Portal'), + ('Ganons Tower Exit', 'Hyrule Castle Ledge') + ] indirect_connections = { 'Turtle Rock (Top)': 'Turtle Rock', diff --git a/test/inverted/TestInverted.py b/test/inverted/TestInverted.py index 06d7a655..6861329d 100644 --- a/test/inverted/TestInverted.py +++ b/test/inverted/TestInverted.py @@ -2,7 +2,7 @@ from BaseClasses import World from DoorShuffle import link_doors from Doors import create_doors from Dungeons import create_dungeons, get_dungeon_item_pool -from EntranceShuffle import link_inverted_entrances +from EntranceShuffle import link_entrances from InvertedRegions import create_inverted_regions from ItemList import generate_itempool, difficulties from Items import ItemFactory @@ -24,7 +24,7 @@ class TestInverted(TestBase): create_doors(self.world, 1) create_rooms(self.world, 1) create_dungeons(self.world, 1) - link_inverted_entrances(self.world, 1) + link_entrances(self.world, 1) link_doors(self.world, 1) generate_itempool(self.world, 1) self.world.required_medallions[1] = ['Ether', 'Quake'] diff --git a/test/inverted_owg/TestInvertedOWG.py b/test/inverted_owg/TestInvertedOWG.py index b772468f..d0d938f6 100644 --- a/test/inverted_owg/TestInvertedOWG.py +++ b/test/inverted_owg/TestInvertedOWG.py @@ -2,7 +2,7 @@ from BaseClasses import World from DoorShuffle import link_doors from Doors import create_doors from Dungeons import create_dungeons, get_dungeon_item_pool -from EntranceShuffle import link_inverted_entrances +from EntranceShuffle import link_entrances from InvertedRegions import create_inverted_regions from ItemList import generate_itempool, difficulties from Items import ItemFactory @@ -26,7 +26,7 @@ class TestInvertedOWG(TestBase): create_rooms(self.world, 1) create_dungeons(self.world, 1) create_owg_connections(self.world, 1) - link_inverted_entrances(self.world, 1) + link_entrances(self.world, 1) link_doors(self.world, 1) generate_itempool(self.world, 1) self.world.required_medallions[1] = ['Ether', 'Quake'] diff --git a/test/stats/EntranceShuffleStats.py b/test/stats/EntranceShuffleStats.py index 2be02071..16ab90e5 100644 --- a/test/stats/EntranceShuffleStats.py +++ b/test/stats/EntranceShuffleStats.py @@ -5,7 +5,7 @@ import time from collections import Counter, defaultdict from source.overworld.EntranceShuffle2 import link_entrances_new -from EntranceShuffle import link_entrances, link_inverted_entrances +from EntranceShuffle import link_entrances from BaseClasses import World from Regions import create_regions, create_dungeon_regions from InvertedRegions import create_inverted_regions @@ -30,10 +30,7 @@ def run_stats(): link_entrances_new(world, 1) def runner_old(world): - if main_mode == 'inverted': - link_inverted_entrances(world, 1) - else: - link_entrances(world, 1) + link_entrances(world, 1) compare_tests(tests, shuffle_mode, main_mode, ls, runner_old, runner_new) @@ -68,10 +65,7 @@ def run_old_stats(): continue def runner(world): - if main_mode == 'inverted': - link_inverted_entrances(world, 1) - else: - link_entrances(world, 1) + link_entrances(world, 1) run_tests(tests, shuffle_mode, main_mode, ls, runner) From 5ac01f4f35ee46466701612371f11d1a792a4571 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 7 Dec 2022 22:16:55 -0600 Subject: [PATCH 003/196] Merged Inverted/Open ER code and data --- EntranceShuffle.py | 6 ++---- source/overworld/EntranceShuffle2.py | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/EntranceShuffle.py b/EntranceShuffle.py index 553eac31..039b2b43 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -2520,8 +2520,7 @@ default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert South ('Turtle Rock Isolated Ledge Entrance', 'Turtle Rock Eye Bridge Portal') ] -open_default_dungeon_connections = [('Hyrule Castle Entrance (South)', 'Hyrule Castle South Portal'), - ('Agahnims Tower', 'Agahnims Tower Portal'), +open_default_dungeon_connections = [('Agahnims Tower', 'Agahnims Tower Portal'), ('Agahnims Tower Exit', 'Hyrule Castle Ledge'), ('Ice Palace Exit', 'Dark Lake Hylia Central Island'), ('Turtle Rock Exit (Front)', 'Dark Death Mountain (Top)'), @@ -2529,8 +2528,7 @@ open_default_dungeon_connections = [('Hyrule Castle Entrance (South)', 'Hyrule C ('Ganons Tower Exit', 'Dark Death Mountain (Top)') ] -inverted_default_dungeon_connections = [('Hyrule Castle Entrance (South)', 'Hyrule Castle South Portal'), - ('Agahnims Tower', 'Ganons Tower Portal'), +inverted_default_dungeon_connections = [('Agahnims Tower', 'Ganons Tower Portal'), ('Agahnims Tower Exit', 'Dark Death Mountain'), ('Ice Palace Exit', 'Dark Lake Hylia'), ('Turtle Rock Exit (Front)', 'Dark Death Mountain'), diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index 403b5488..8ac2ee24 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -2299,8 +2299,7 @@ default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert South ('Turtle Rock Isolated Ledge Entrance', 'Turtle Rock Eye Bridge Portal') ] -open_default_dungeon_connections = [('Hyrule Castle Entrance (South)', 'Hyrule Castle South Portal'), - ('Agahnims Tower', 'Agahnims Tower Portal'), +open_default_dungeon_connections = [('Agahnims Tower', 'Agahnims Tower Portal'), ('Agahnims Tower Exit', 'Hyrule Castle Ledge'), ('Ice Palace Exit', 'Dark Lake Hylia Central Island'), ('Turtle Rock Exit (Front)', 'Dark Death Mountain (Top)'), @@ -2308,8 +2307,7 @@ open_default_dungeon_connections = [('Hyrule Castle Entrance (South)', 'Hyrule C ('Ganons Tower Exit', 'Dark Death Mountain (Top)') ] -inverted_default_dungeon_connections = [('Hyrule Castle Entrance (South)', 'Hyrule Castle South Portal'), - ('Agahnims Tower', 'Ganons Tower Portal'), +inverted_default_dungeon_connections = [('Agahnims Tower', 'Ganons Tower Portal'), ('Agahnims Tower Exit', 'Dark Death Mountain'), ('Ice Palace Exit', 'Dark Lake Hylia'), ('Turtle Rock Exit (Front)', 'Dark Death Mountain'), From 8e08f336d007399edec565108ed6a871ba67a877 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Tue, 13 Dec 2022 01:40:44 -0600 Subject: [PATCH 004/196] Merging Regions and Rulesets --- DoorShuffle.py | 24 +- EntranceShuffle.py | 258 +++++----- InvertedRegions.py | 523 -------------------- Main.py | 19 +- OverworldGlitchRules.py | 51 +- Regions.py | 144 +++--- Rules.py | 632 ++++++++++++------------- source/item/District.py | 6 +- source/overworld/EntranceShuffle2.py | 252 +++++----- test/inverted/TestInverted.py | 7 +- test/inverted/TestInvertedBombRules.py | 2 +- test/inverted_owg/TestInvertedOWG.py | 7 +- test/owg/TestVanillaOWG.py | 5 +- test/stats/EntranceShuffleStats.py | 7 +- test/vanilla/TestVanilla.py | 5 +- 15 files changed, 720 insertions(+), 1222 deletions(-) delete mode 100644 InvertedRegions.py diff --git a/DoorShuffle.py b/DoorShuffle.py index c212e990..1124760a 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -401,7 +401,6 @@ def pair_existing_key_doors(world, player, door_a, door_b): def choose_portals(world, player): - if world.doorShuffle[player] != ['vanilla']: shuffle_flag = world.doorShuffle[player] != 'basic' allowed = {} @@ -1144,6 +1143,8 @@ def enable_new_entrances(region, connections, potentials, enabled, world, player while len(queue) > 0: ext = queue.popleft() visited.add(ext) + if ext.connected_region is None: + continue region_name = ext.connected_region.name if region_name in connections.keys() and connections[region_name] in potentials.keys(): for potential in potentials.pop(connections[region_name]): @@ -3250,7 +3251,7 @@ def find_accessible_entrances(world, player, builder): if connect not in queue and connect not in visited_regions: queue.append(connect) for ext in next_region.exits: - if hc_std and ext.name == 'Hyrule Castle Main Gate (North)': # just skip it + if hc_std and ext.name in ['Hyrule Castle Main Gate (North)', 'Top of Pyramid', 'Hyrule Castle Ledge Drop']: # just skip it continue connect = ext.connected_region if connect is None or ext.door and ext.door.blocked: @@ -3286,7 +3287,7 @@ def create_doors_for_inaccessible_region(inaccessible_region, world, player): region = world.get_region(inaccessible_region, player) for ext in region.exits: create_door(world, player, ext.name, region.name) - if ext.connected_region.name.endswith(' Portal'): + if ext.connected_region and ext.connected_region.name.endswith(' Portal'): for more_exts in ext.connected_region.exits: create_door(world, player, more_exts.name, ext.connected_region.name) @@ -3294,14 +3295,15 @@ def create_doors_for_inaccessible_region(inaccessible_region, world, player): def create_door(world, player, entName, region_name): entrance = world.get_entrance(entName, player) connect = entrance.connected_region - for ext in connect.exits: - if ext.connected_region is not None and ext.connected_region.name == region_name: - d = Door(player, ext.name, DoorType.Logical, ext), - world.doors += d - connect_door_only(world, ext.name, ext.connected_region, player) - d = Door(player, entName, DoorType.Logical, entrance), - world.doors += d - connect_door_only(world, entName, connect, player) + if connect is not None: + for ext in connect.exits: + if ext.connected_region and ext.connected_region.name == region_name: + d = Door(player, ext.name, DoorType.Logical, ext), + world.doors += d + connect_door_only(world, ext.name, ext.connected_region, player) + d = Door(player, entName, DoorType.Logical, entrance), + world.doors += d + connect_door_only(world, entName, connect, player) def check_required_paths(paths, world, player): diff --git a/EntranceShuffle.py b/EntranceShuffle.py index 039b2b43..4c5b57a7 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -2066,19 +2066,38 @@ Inverted_Must_Exit_Invalid_Connections = defaultdict(set, { # They link together separate parts of the world we need to divide into regions mandatory_connections = [('Links House S&Q', 'Links House'), ('Lake Hylia Central Island Pier', 'Lake Hylia Central Island'), - ('Zoras River', 'Zoras River'), + ('Lake Hylia Central Island Water Drop', 'Lake Hylia Water'), + ('Potion Shop Water Drop', 'Lake Hylia Water'), + ('Northeast Light World Water Drop', 'Lake Hylia Water'), + ('Zora Waterfall Water Drop', 'Lake Hylia Water'), + ('Light World Water Drop', 'Lake Hylia Water'), + ('East Dark World Water Drop', 'Dark Lake Hylia Water'), + ('South Dark World Water Drop', 'Dark Lake Hylia Water'), + ('Southeast Dark World Water Drop', 'Dark Lake Hylia Water'), + ('Northeast Dark World Water Drop', 'Dark Lake Hylia Water'), + ('Catfish Water Drop', 'Dark Lake Hylia Water'), + ('Ice Palace Leave Water Drop', 'Dark Lake Hylia Water'), + ('West Dark World Water Drop', 'Dark Lake Hylia Water'), + ('Zoras Domain', 'Zoras Domain'), ('Kings Grave Outer Rocks', 'Kings Grave Area'), ('Kings Grave Inner Rocks', 'Light World'), ('Kakariko Well (top to bottom)', 'Kakariko Well (bottom)'), ('Kakariko Well (top to back)', 'Kakariko Well (back)'), ('Master Sword Meadow', 'Master Sword Meadow'), - ('Hobo Bridge', 'Hobo Bridge'), - ('Bat Cave Drop Ledge', 'Bat Cave Drop Ledge'), + ('Hobo Pier', 'Hobo Bridge'), + ('Bat Cave Ledge Peg', 'Bat Cave Ledge'), + ('Bat Cave Ledge Peg (East)', 'Light World'), ('Bat Cave Door', 'Bat Cave (left)'), ('Lost Woods Hideout (top to bottom)', 'Lost Woods Hideout (bottom)'), ('Lumberjack Tree (top to bottom)', 'Lumberjack Tree (bottom)'), ('Blinds Hideout N', 'Blinds Hideout (Top)'), - ('Desert Palace Stairs', 'Desert Palace Stairs'), + ('Light World Pier', 'Light World'), + ('Potion Shop Pier', 'Potion Shop Area'), + ('Wooden Bridge Bush (North)', 'Light World'), + ('Wooden Bridge Bush (South)', 'Potion Shop Area'), + ('Potion Shop Rock (South)', 'Northeast Light World'), + ('Potion Shop Rock (North)', 'Potion Shop Area'), + ('Desert Statue Move', 'Desert Palace Stairs'), ('Desert Palace Stairs Drop', 'Light World'), ('Desert Palace Entrance (North) Rocks', 'Desert Palace Entrance (North) Spot'), ('Desert Ledge Return Rocks', 'Desert Ledge'), @@ -2093,22 +2112,18 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Old Man Cave Dropdown', 'Old Man Cave'), ('Old Man House Front to Back', 'Old Man House Back'), ('Old Man House Back to Front', 'Old Man House'), - ('Broken Bridge (West)', 'East Death Mountain (Bottom)'), - ('Broken Bridge (East)', 'Death Mountain'), + ('DM Broken Bridge (West)', 'East Death Mountain (Bottom)'), + ('DM Broken Bridge (East)', 'Death Mountain (West Bottom)'), ('East Death Mountain Drop', 'East Death Mountain (Bottom)'), ('Spiral Cave Ledge Access', 'Spiral Cave Ledge'), ('Spiral Cave Ledge Drop', 'East Death Mountain (Bottom)'), ('Spiral Cave (top to bottom)', 'Spiral Cave (Bottom)'), - ('East Death Mountain (Top)', 'East Death Mountain (Top)'), - ('Death Mountain (Top)', 'Death Mountain (Top)'), - ('Death Mountain Drop', 'Death Mountain'), - ('Dark Lake Hylia Drop (East)', 'Dark Lake Hylia'), - ('Dark Lake Hylia Drop (South)', 'Dark Lake Hylia'), - ('Dark Lake Hylia Teleporter', 'Dark Lake Hylia'), - ('Dark Lake Hylia Ledge Drop', 'Dark Lake Hylia'), + ('DM Hammer Bridge (West)', 'East Death Mountain (Top)'), + ('DM Hammer Bridge (East)', 'Death Mountain (Top)'), + ('Death Mountain Drop', 'Death Mountain (West Bottom)'), ('East Dark World Pier', 'East Dark World'), - ('South Dark World Bridge', 'South Dark World'), - ('East Dark World Bridge', 'East Dark World'), + ('Hammer Bridge Pegs (North)', 'South Dark World'), + ('Hammer Bridge Pegs (South)', 'East Dark World'), ('Village of Outcasts Heavy Rock', 'West Dark World'), ('Village of Outcasts Drop', 'South Dark World'), ('Village of Outcasts Eastern Rocks', 'Hammer Peg Area'), @@ -2117,8 +2132,8 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Grassy Lawn Pegs', 'West Dark World'), ('West Dark World Gap', 'West Dark World'), ('East Dark World Broken Bridge Pass', 'East Dark World'), - ('Catfish Exit Rock', 'Northeast Dark World'), - ('Catfish Entrance Rock', 'Catfish'), + ('Dark Witch Rock (North)', 'Northeast Dark World'), + ('Dark Witch Rock (South)', 'Catfish Area'), ('Northeast Dark World Broken Bridge Pass', 'Northeast Dark World'), ('Bumper Cave Entrance Rock', 'Bumper Cave Entrance'), ('Bumper Cave Entrance Drop', 'West Dark World'), @@ -2149,132 +2164,146 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Ganon Drop', 'Bottom of Pyramid'), ('Pyramid Drop', 'East Dark World'), ('Maze Race Ledge Drop', 'Light World'), - ('Desert Ledge Drop', 'Light World') + ('Hyrule Castle Ledge Drop', 'Light World'), + ('Desert Ledge Drop', 'Light World'), + ('Lake Hylia Whirlpool', 'Northeast Light World'), + ('Hyrule Castle Ledge Courtyard Drop', 'Hyrule Castle Courtyard'), + ('Southeast Dark World Pier', 'Southeast Dark World'), + ('Northeast Dark World River Pier', 'Northeast Dark World'), + ('Fairy Ascension Ledge Access', 'Fairy Ascension Ledge'), + ('Hyrule Castle Courtyard Bush (North)', 'Hyrule Castle Courtyard'), + ('Hyrule Castle Courtyard Bush (South)', 'Hyrule Castle Secret Entrance Area'), + ('Turtle Rock Drop', 'Dark Death Mountain (Top)'), + ('Floating Island Drop', 'Dark Death Mountain (Top)'), + ('Dark Desert Drop', 'Dark Desert'), + ('Kakariko Yard Bush (North)', 'Light World'), + ('Kakariko Yard Bush (South)', 'Bush Covered Lawn'), + ('Bush Covered Lawn Mirror Spot', 'Dark Grassy Lawn'), + ('Kakariko Southwest Bush (South)', 'Light World'), + ('Kakariko Southwest Bush (North)', 'Bomb Hut Area'), + ('Hyrule Castle Main Gate', 'Hyrule Castle Courtyard'), + ('Spectacle Rock Drop', 'Death Mountain (Top)'), + ('Desert Teleporter Drop', 'Light World'), + ('Dark Death Mountain Drop (West)', 'Dark Death Mountain (West Bottom)'), + ('Graveyard Ledge Drop', 'Light World'), + ('Cave 45 Ledge Drop', 'Light World'), + ('Checkerboard Ledge Drop', 'Light World'), + ('Hyrule Castle Main Gate (North)', 'Light World') ] open_mandatory_connections = [('Sanctuary S&Q', 'Sanctuary'), ('Old Man S&Q', 'Old Man House'), ('Other World S&Q', 'East Dark World'), + ('Flute Spot 1', 'Death Mountain (West Bottom)'), + ('Flute Spot 2', 'Potion Shop Area'), + ('Flute Spot 3', 'Light World'), + ('Flute Spot 4', 'Light World'), + ('Flute Spot 5', 'Light World'), + ('Flute Spot 6', 'Desert Teleporter Ledge'), + ('Flute Spot 7', 'Light World'), + ('Flute Spot 8', 'Light World'), + ('LW Flute', 'Flute Sky'), + ('NWLW Flute', 'Flute Sky'), + ('ZLW Flute', 'Flute Sky'), + ('DM Flute', 'Flute Sky'), + ('EDM Flute', 'Flute Sky'), ('Lake Hylia Central Island Teleporter', 'Dark Lake Hylia Central Island'), - ('Zora Waterfall Entryway', 'Zora Waterfall Entryway'), - ('Zora Waterfall Water Drop', 'Light World'), ('Kings Grave Mirror Spot', 'Kings Grave Area'), - ('Hyrule Castle Ledge Courtyard Drop', 'Hyrule Castle Courtyard'), - ('Hyrule Castle Main Gate', 'Hyrule Castle Courtyard'), - ('Flute Spot 1', 'Death Mountain'), - ('Spectacle Rock Drop', 'Death Mountain (Top)'), ('Top of Pyramid', 'East Dark World'), ('Lake Hylia Island Mirror Spot', 'Lake Hylia Island'), ('Lake Hylia Central Island Mirror Spot', 'Lake Hylia Central Island'), ('Hyrule Castle Ledge Mirror Spot', 'Hyrule Castle Ledge'), - ('Maze Race Mirror Spot', 'Maze Race Ledge'), - ('Bat Cave Drop Ledge Mirror Spot', 'Bat Cave Drop Ledge'), - ('East Dark World River Pier', 'East Dark World'), + ('Dig Game Mirror Spot', 'Maze Race Ledge'), + ('Bat Cave Drop Ledge Mirror Spot', 'Bat Cave Ledge'), ('Bumper Cave Entrance Mirror Spot', 'Death Mountain Entrance'), ('Bumper Cave Ledge Mirror Spot', 'Death Mountain Return Ledge'), ('Desert Ledge Mirror Spot', 'Desert Ledge'), - ('Desert Ledge (Northeast) Mirror Spot', 'Desert Ledge (Northeast)'), + ('Desert Ledge (Northeast) Mirror Spot', 'Desert Checkerboard Ledge'), ('Desert Palace Entrance (North) Mirror Spot', 'Desert Palace Entrance (North) Spot'), - ('Dark Desert Teleporter', 'Dark Desert'), - ('Desert Palace Stairs Mirror Spot', 'Desert Palace Stairs'), + ('Desert Teleporter', 'Dark Desert'), + ('Mire To Desert Palace Stairs Mirror Spot', 'Desert Palace Stairs'), ('East Hyrule Teleporter', 'East Dark World'), ('South Hyrule Teleporter', 'South Dark World'), ('Kakariko Teleporter', 'West Dark World'), ('Death Mountain Teleporter', 'Dark Death Mountain (West Bottom)'), ('Fairy Ascension Mirror Spot', 'Fairy Ascension Plateau'), - ('Fairy Ascension Ledge', 'Fairy Ascension Ledge'), ('Spectacle Rock Mirror Spot', 'Spectacle Rock'), - ('Dark Death Mountain Drop (West)', 'Dark Death Mountain (West Bottom)'), ('East Death Mountain (Top) Mirror Spot', 'East Death Mountain (Top)'), ('Turtle Rock Teleporter', 'Turtle Rock (Top)'), - ('Turtle Rock Drop', 'Dark Death Mountain (Top)'), - ('Floating Island Drop', 'Dark Death Mountain (Top)'), - ('Floating Island Mirror Spot', 'Death Mountain Floating Island (Light World)'), + ('Dark Grassy Lawn Mirror Spot', 'Bush Covered Lawn'), + ('Dark Floating Island Mirror Spot', 'Death Mountain Floating Island'), ('East Death Mountain Teleporter', 'Dark Death Mountain (East Bottom)'), ('Isolated Ledge Mirror Spot', 'Fairy Ascension Ledge'), ('Spiral Cave Mirror Spot', 'Spiral Cave Ledge'), ('Mimic Cave Mirror Spot', 'Mimic Cave Ledge'), ('Cave 45 Mirror Spot', 'Cave 45 Ledge'), ('Bombos Tablet Mirror Spot', 'Bombos Tablet Ledge'), - ('Graveyard Ledge Mirror Spot', 'Graveyard Ledge'), - ('Graveyard Ledge Drop', 'Light World'), - ('Cave 45 Ledge Drop', 'Light World'), - ('Checkerboard Ledge Drop', 'Light World'), - ('Hyrule Castle Main Gate (North)', 'Light World'), - ('Hyrule Castle Ledge Drop', 'Light World'), + ('Graveyard Ledge Mirror Spot', 'Graveyard Ledge') ] inverted_mandatory_connections = [('Sanctuary S&Q', 'Dark Sanctuary Hint'), - ('Old Man S&Q', 'Old Man House'), + ('Old Man S&Q', 'Dark Death Mountain (West Bottom)'), ('Other World S&Q', 'Hyrule Castle Ledge'), ('Lake Hylia Island Pier', 'Lake Hylia Island'), - ('Lake Hylia Warp', 'Northeast Light World'), - ('Northeast Light World Warp', 'Light World'), - ('Waterfall of Wishing Cave', 'Waterfall of Wishing Cave'), - ('Northeast Light World Return', 'Northeast Light World'), - ('Hyrule Castle Ledge Courtyard Drop', 'Light World'), - ('DDM Flute', 'The Sky'), - ('DDM Landing', 'Dark Death Mountain'), - ('NEDW Flute', 'The Sky'), - ('NEDW Landing', 'Northeast Dark World'), - ('WDW Flute', 'The Sky'), - ('WDW Landing', 'West Dark World'), - ('SDW Flute', 'The Sky'), - ('SDW Landing', 'South Dark World'), - ('EDW Flute', 'The Sky'), - ('EDW Landing', 'East Dark World'), - ('DLHL Flute', 'The Sky'), - ('DLHL Landing', 'Dark Lake Hylia Ledge'), - ('DD Flute', 'The Sky'), - ('DD Landing', 'Dark Desert Ledge'), - ('EDDM Flute', 'The Sky'), - ('Dark Grassy Lawn Flute', 'The Sky'), - ('Hammer Peg Area Flute', 'The Sky'), - ('Dark Lake Hylia Ledge Pier', 'Dark Lake Hylia Ledge'), - ('Ice Palace Missing Wall', 'Dark Lake Hylia Central Island'), - ('Dark Lake Hylia Shallows', 'Dark Lake Hylia'), - ('East Dark World River Pier', 'Northeast Dark World'), - ('Fairy Ascension Ledge Access', 'Fairy Ascension Ledge'), + ('Spectacle Rock Leave', 'Death Mountain (Top)'), + ('Spectacle Rock Approach', 'Spectacle Rock'), + ('Checkerboard Ledge Approach', 'Desert Checkerboard Ledge'), + ('Checkerboard Ledge Leave', 'Light World'), + ('Cave 45 Approach', 'Cave 45 Ledge'), + ('Cave 45 Leave', 'Light World'), + ('Flute Spot 1', 'Dark Death Mountain (West Bottom)'), + ('Flute Spot 2', 'Northeast Dark World'), + ('Flute Spot 3', 'West Dark World'), + ('Flute Spot 4', 'South Dark World'), + ('Flute Spot 5', 'East Dark World'), + ('Flute Spot 6', 'Dark Desert Ledge'), + ('Flute Spot 7', 'South Dark World'), + ('Flute Spot 8', 'Southeast Dark World'), + ('DDM Flute', 'Flute Sky'), + ('NEDW Flute', 'Flute Sky'), + ('WDW Flute', 'Flute Sky'), + ('SDW Flute', 'Flute Sky'), + ('EDW Flute', 'Flute Sky'), + ('DD Flute', 'Flute Sky'), + ('DLHL Flute', 'Flute Sky'), + ('EDDM Flute', 'Flute Sky'), + ('Dark Grassy Lawn Flute', 'Flute Sky'), + ('Hammer Peg Area Flute', 'Flute Sky'), + ('Dark Death Mountain Ladder (Bottom)', 'Dark Death Mountain (Top)'), + ('Dark Death Mountain Ladder (Top)', 'Dark Death Mountain (West Bottom)'), + ('Ice Palace Approach', 'Dark Lake Hylia Central Island'), + ('Floating Island Bridge (East)', 'Death Mountain Floating Island'), + ('Floating Island Bridge (West)', 'East Death Mountain (Top)'), ('Post Aga Teleporter', 'Light World'), - ('Secret Passage Inner Bushes', 'Light World'), - ('Secret Passage Outer Bushes', 'Hyrule Castle Secret Entrance Area'), - ('Potion Shop Inner Bushes', 'Light World'), - ('Potion Shop Outer Bushes', 'Potion Shop Area'), - ('Potion Shop Inner Rock', 'Northeast Light World'), - ('Potion Shop Outer Rock', 'Potion Shop Area'), - ('Potion Shop River Drop', 'River'), - ('Graveyard Cave Inner Bushes', 'Light World'), - ('Graveyard Cave Outer Bushes', 'Graveyard Cave Area'), + ('Graveyard Ladder (Top)', 'Light World'), + ('Graveyard Ladder (Bottom)', 'Graveyard Ledge'), ('Graveyard Cave Mirror Spot', 'West Dark World'), - ('Light World River Drop', 'River'), - ('Light World Pier', 'Light World'), - ('Potion Shop Pier', 'Potion Shop Area'), + ('Pyramid Uncle Mirror Spot', 'East Dark World'), ('Mimic Cave Ledge Access', 'Mimic Cave Ledge'), ('Mimic Cave Ledge Drop', 'East Death Mountain (Bottom)'), ('Turtle Rock Tail Drop', 'Turtle Rock (Top)'), - ('Turtle Rock Drop', 'Dark Death Mountain'), - ('Floating Island Drop', 'Dark Death Mountain'), ('Dark Lake Hylia Central Island Teleporter', 'Lake Hylia Central Island'), ('Dark Desert Teleporter', 'Light World'), ('East Dark World Teleporter', 'Light World'), ('South Dark World Teleporter', 'Light World'), ('West Dark World Teleporter', 'Light World'), - ('Dark Death Mountain Teleporter (West)', 'Death Mountain'), + ('Dark Death Mountain Teleporter (West)', 'Death Mountain (West Bottom)'), ('Dark Death Mountain Teleporter (East)', 'East Death Mountain (Top)'), ('Dark Death Mountain Teleporter (East Bottom)', 'East Death Mountain (Bottom)'), ('Mire Mirror Spot', 'Dark Desert'), - ('Dark Desert Drop', 'Dark Desert'), + ('Bombos Tablet Ladder (Top)', 'Light World'), + ('Bombos Tablet Ladder (Bottom)', 'Bombos Tablet Ledge'), ('Desert Palace Stairs Mirror Spot', 'Dark Desert'), ('Desert Palace North Mirror Spot', 'Dark Desert'), - ('Maze Race Mirror Spot', 'West Dark World'), + ('Maze Race Mirror Spot', 'South Dark World'), ('Lake Hylia Central Island Mirror Spot', 'Dark Lake Hylia Central Island'), ('Hammer Peg Area Mirror Spot', 'Hammer Peg Area'), - ('Bumper Cave Ledge Mirror Spot', 'Bumper Cave Ledge'), + ('Mountain Exit Ledge Mirror Spot', 'Bumper Cave Ledge'), ('Bumper Cave Entrance Mirror Spot', 'Bumper Cave Entrance'), - ('Death Mountain Mirror Spot', 'Dark Death Mountain'), - ('East Death Mountain Mirror Spot (Top)', 'Dark Death Mountain'), + ('Death Mountain Mirror Spot', 'Dark Death Mountain (West Bottom)'), + ('East Death Mountain Mirror Spot (Top)', 'Dark Death Mountain (Top)'), ('East Death Mountain Mirror Spot (Bottom)', 'Dark Death Mountain (East Bottom)'), - ('Death Mountain (Top) Mirror Spot', 'Dark Death Mountain'), + ('Death Mountain (Top) Mirror Spot', 'Dark Death Mountain (Top)'), ('Dark Death Mountain Ledge Mirror Spot (East)', 'Dark Death Mountain Ledge'), ('Dark Death Mountain Ledge Mirror Spot (West)', 'Dark Death Mountain Ledge'), ('Floating Island Mirror Spot', 'Death Mountain Floating Island (Dark World)'), @@ -2283,14 +2312,9 @@ inverted_mandatory_connections = [('Sanctuary S&Q', 'Dark Sanctuary Hint'), ('West Dark World Mirror Spot', 'West Dark World'), ('South Dark World Mirror Spot', 'South Dark World'), ('Potion Shop Mirror Spot', 'Northeast Dark World'), - ('Catfish Mirror Spot', 'Catfish'), - ('Shopping Mall Mirror Spot', 'Dark Lake Hylia Ledge'), + ('Catfish Mirror Spot', 'Catfish Area'), + ('Shopping Mall Mirror Spot', 'Southeast Dark World'), ('Skull Woods Mirror Spot', 'Skull Woods Forest (West)'), - ('Bush Covered Lawn Inner Bushes', 'Light World'), - ('Bush Covered Lawn Outer Bushes', 'Bush Covered Lawn'), - ('Bush Covered Lawn Mirror Spot', 'Dark Grassy Lawn'), - ('Bomb Hut Inner Bushes', 'Light World'), - ('Bomb Hut Outer Bushes', 'Bomb Hut Area'), ('Bomb Hut Mirror Spot', 'West Dark World') ] @@ -2301,6 +2325,7 @@ default_connections = [('Waterfall of Wishing', 'Waterfall of Wishing'), ('Lumberjack House', 'Lumberjack House'), ('Hyrule Castle Secret Entrance Drop', 'Hyrule Castle Secret Entrance'), ('Hyrule Castle Secret Entrance Stairs', 'Hyrule Castle Secret Entrance'), + ('Hyrule Castle Secret Entrance Exit', 'Hyrule Castle Secret Entrance Area'), ('Bonk Fairy (Light)', 'Bonk Fairy (Light)'), ('Lake Hylia Fairy', 'Lake Hylia Healer Fairy'), ('Lake Hylia Fortune Teller', 'Lake Hylia Fortune Teller'), @@ -2363,17 +2388,17 @@ default_connections = [('Waterfall of Wishing', 'Waterfall of Wishing'), ('Sanctuary Grave', 'Sewer Drop'), ('Sanctuary Exit', 'Light World'), ('Old Man House (Bottom)', 'Old Man House'), - ('Old Man House Exit (Bottom)', 'Death Mountain'), + ('Old Man House Exit (Bottom)', 'Death Mountain (West Bottom)'), ('Old Man House (Top)', 'Old Man House Back'), - ('Old Man House Exit (Top)', 'Death Mountain'), + ('Old Man House Exit (Top)', 'Death Mountain (West Bottom)'), ('Death Mountain Return Cave (East)', 'Death Mountain Return Cave (right)'), - ('Death Mountain Return Cave Exit (East)', 'Death Mountain'), + ('Death Mountain Return Cave Exit (East)', 'Death Mountain (West Bottom)'), ('Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Peak)'), ('Spectacle Rock Cave (Bottom)', 'Spectacle Rock Cave (Bottom)'), ('Spectacle Rock Cave', 'Spectacle Rock Cave (Top)'), - ('Spectacle Rock Cave Exit', 'Death Mountain'), - ('Spectacle Rock Cave Exit (Top)', 'Death Mountain'), - ('Spectacle Rock Cave Exit (Peak)', 'Death Mountain'), + ('Spectacle Rock Cave Exit', 'Death Mountain (West Bottom)'), + ('Spectacle Rock Cave Exit (Top)', 'Death Mountain (West Bottom)'), + ('Spectacle Rock Cave Exit (Peak)', 'Death Mountain (West Bottom)'), ('Paradox Cave (Bottom)', 'Paradox Cave Front'), ('Paradox Cave (Middle)', 'Paradox Cave'), ('Paradox Cave (Top)', 'Paradox Cave'), @@ -2415,7 +2440,9 @@ default_connections = [('Waterfall of Wishing', 'Waterfall of Wishing'), ('Dark Desert Fairy', 'Dark Desert Healer Fairy'), ('Spike Cave', 'Spike Cave'), ('Hookshot Cave', 'Hookshot Cave (Front)'), + ('Hookshot Cave Front Exit', 'Dark Death Mountain (Top)'), ('Superbunny Cave (Top)', 'Superbunny Cave (Top)'), + ('Superbunny Cave Exit (Top)', 'Dark Death Mountain (Top)'), ('Cave Shop (Dark Death Mountain)', 'Cave Shop (Dark Death Mountain)'), ('Superbunny Cave (Bottom)', 'Superbunny Cave (Bottom)'), ('Superbunny Cave Exit (Bottom)', 'Dark Death Mountain (East Bottom)'), @@ -2426,11 +2453,10 @@ default_connections = [('Waterfall of Wishing', 'Waterfall of Wishing'), open_default_connections = [('Links House', 'Links House'), ('Links House Exit', 'Light World'), - ('Hyrule Castle Secret Entrance Exit', 'Hyrule Castle Courtyard'), ('Old Man Cave (West)', 'Old Man Cave Ledge'), ('Old Man Cave (East)', 'Old Man Cave'), ('Old Man Cave Exit (West)', 'Light World'), - ('Old Man Cave Exit (East)', 'Death Mountain'), + ('Old Man Cave Exit (East)', 'Death Mountain (West Bottom)'), ('Death Mountain Return Cave (West)', 'Death Mountain Return Cave (left)'), ('Death Mountain Return Cave Exit (West)', 'Death Mountain Return Ledge'), ('Big Bomb Shop', 'Big Bomb Shop'), @@ -2439,8 +2465,6 @@ open_default_connections = [('Links House', 'Links House'), ('Bumper Cave Exit (Top)', 'Bumper Cave Ledge'), ('Bumper Cave Exit (Bottom)', 'West Dark World'), ('Dark Death Mountain Fairy', 'Dark Death Mountain Healer Fairy'), - ('Superbunny Cave Exit (Top)', 'Dark Death Mountain (Top)'), - ('Hookshot Cave Front Exit', 'Dark Death Mountain (Top)'), ('Pyramid Hole', 'Pyramid'), ('Pyramid Exit', 'Pyramid Ledge'), ('Pyramid Entrance', 'Bottom of Pyramid') @@ -2448,24 +2472,21 @@ open_default_connections = [('Links House', 'Links House'), inverted_default_connections = [('Links House', 'Big Bomb Shop'), ('Links House Exit', 'South Dark World'), - ('Hyrule Castle Secret Entrance Exit', 'Light World'), ('Old Man Cave (West)', 'Bumper Cave (bottom)'), ('Old Man Cave (East)', 'Death Mountain Return Cave (left)'), ('Old Man Cave Exit (West)', 'West Dark World'), - ('Old Man Cave Exit (East)', 'Dark Death Mountain'), + ('Old Man Cave Exit (East)', 'Dark Death Mountain (West Bottom)'), ('Death Mountain Return Cave (West)', 'Bumper Cave (top)'), - ('Death Mountain Return Cave Exit (West)', 'Death Mountain'), + ('Death Mountain Return Cave Exit (West)', 'Death Mountain (West Bottom)'), ('Big Bomb Shop', 'Links House'), ('Bumper Cave (Bottom)', 'Old Man Cave Ledge'), ('Bumper Cave (Top)', 'Dark Death Mountain Healer Fairy'), - ('Dark Sanctuary Hint Exit', 'West Dark World'), ('Bumper Cave Exit (Top)', 'Death Mountain Return Ledge'), ('Bumper Cave Exit (Bottom)', 'Light World'), ('Dark Death Mountain Fairy', 'Old Man Cave'), - ('Superbunny Cave Exit (Top)', 'Dark Death Mountain'), - ('Hookshot Cave Front Exit', 'Dark Death Mountain'), + ('Dark Sanctuary Hint Exit', 'West Dark World'), ('Inverted Pyramid Hole', 'Pyramid'), - ('Pyramid Exit', 'Light World'), + ('Pyramid Exit', 'Hyrule Castle Courtyard'), ('Inverted Pyramid Entrance', 'Bottom of Pyramid') ] @@ -2476,7 +2497,7 @@ default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert South ('Desert Palace Entrance (East)', 'Desert East Portal'), ('Desert Palace Exit (South)', 'Desert Palace Stairs'), ('Desert Palace Exit (West)', 'Desert Ledge'), - ('Desert Palace Exit (East)', 'Desert Palace Lone Stairs'), + ('Desert Palace Exit (East)', 'Desert Palace Mouth'), ('Desert Palace Exit (North)', 'Desert Palace Entrance (North) Spot'), ('Eastern Palace', 'Eastern Portal'), ('Eastern Palace Exit', 'Light World'), @@ -2486,6 +2507,7 @@ default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert South ('Hyrule Castle Entrance (South)', 'Hyrule Castle South Portal'), ('Hyrule Castle Entrance (West)', 'Hyrule Castle West Portal'), ('Hyrule Castle Entrance (East)', 'Hyrule Castle East Portal'), + ('Hyrule Castle Exit (South)', 'Hyrule Castle Courtyard'), ('Hyrule Castle Exit (West)', 'Hyrule Castle Ledge'), ('Hyrule Castle Exit (East)', 'Hyrule Castle Ledge'), @@ -2529,9 +2551,9 @@ open_default_dungeon_connections = [('Agahnims Tower', 'Agahnims Tower Portal'), ] inverted_default_dungeon_connections = [('Agahnims Tower', 'Ganons Tower Portal'), - ('Agahnims Tower Exit', 'Dark Death Mountain'), - ('Ice Palace Exit', 'Dark Lake Hylia'), - ('Turtle Rock Exit (Front)', 'Dark Death Mountain'), + ('Agahnims Tower Exit', 'Dark Death Mountain (Top)'), + ('Ice Palace Exit', 'Dark Lake Hylia Central Island'), + ('Turtle Rock Exit (Front)', 'Dark Death Mountain (Top)'), ('Ganons Tower', 'Agahnims Tower Portal'), ('Ganons Tower Exit', 'Hyrule Castle Ledge') ] diff --git a/InvertedRegions.py b/InvertedRegions.py deleted file mode 100644 index fabc4a76..00000000 --- a/InvertedRegions.py +++ /dev/null @@ -1,523 +0,0 @@ -import collections -from BaseClasses import RegionType -from Regions import create_lw_region, create_dw_region, create_cave_region, create_dungeon_region, create_menu_region - -def create_inverted_regions(world, player): - - world.regions += [ - create_menu_region(player, 'Menu', None, ['Links House S&Q', 'Sanctuary S&Q', 'Old Man S&Q', 'Other World S&Q']), - create_lw_region(player, 'Light World', ['Mushroom', 'Bottle Merchant', 'Flute Spot', 'Sunken Treasure', 'Purple Chest', 'Bombos Tablet'], - ["Blinds Hideout", "Hyrule Castle Secret Entrance Drop", 'Kings Grave Outer Rocks', 'Dam', - 'Links House', 'Tavern North', 'Chicken House', 'Aginahs Cave', 'Sahasrahlas Hut', 'Kakariko Well Drop', 'Kakariko Well Cave', - 'Blacksmiths Hut', 'Bat Cave Drop Ledge', 'Bat Cave Cave', 'Sick Kids House', 'Hobo Bridge', 'Lost Woods Hideout Drop', 'Lost Woods Hideout Stump', - 'Lumberjack Tree Tree', 'Lumberjack Tree Cave', 'Mini Moldorm Cave', 'Ice Rod Cave', 'Lake Hylia Central Island Pier', 'Lake Hylia Island Pier', 'Lake Hylia Warp', - 'Bonk Rock Cave', 'Library', 'Two Brothers House (East)', 'Desert Palace Stairs', 'Eastern Palace', 'Master Sword Meadow', - 'Sanctuary', 'Sanctuary Grave', 'Death Mountain Entrance Rock', 'Light World River Drop', - 'Elder House (East)', 'Elder House (West)', 'North Fairy Cave', 'North Fairy Cave Drop', 'Lost Woods Gamble', 'Snitch Lady (East)', 'Snitch Lady (West)', 'Tavern (Front)', - 'Kakariko Shop', 'Long Fairy Cave', 'Good Bee Cave', '20 Rupee Cave', 'Cave Shop (Lake Hylia)', - 'Bonk Fairy (Light)', '50 Rupee Cave', 'Fortune Teller (Light)', 'Lake Hylia Fairy', 'Light Hype Fairy', 'Desert Fairy', 'Lumberjack House', 'Lake Hylia Fortune Teller', 'Kakariko Gamble Game', - 'East Dark World Mirror Spot', 'West Dark World Mirror Spot', 'South Dark World Mirror Spot', 'Cave 45', 'Checkerboard Cave', 'Mire Mirror Spot', 'Hammer Peg Area Mirror Spot', - 'Shopping Mall Mirror Spot', 'Skull Woods Mirror Spot', 'Inverted Pyramid Entrance','Hyrule Castle Entrance (South)', 'Secret Passage Outer Bushes', 'Bush Covered Lawn Outer Bushes', - 'Potion Shop Outer Bushes', 'Graveyard Cave Outer Bushes', 'Bomb Hut Outer Bushes']), - create_lw_region(player, 'Bush Covered Lawn', None, ['Bush Covered House', 'Bush Covered Lawn Inner Bushes', 'Bush Covered Lawn Mirror Spot']), - create_lw_region(player, 'Bomb Hut Area', None, ['Light World Bomb Hut', 'Bomb Hut Inner Bushes', 'Bomb Hut Mirror Spot']), - create_lw_region(player, 'Hyrule Castle Secret Entrance Area', None, ['Hyrule Castle Secret Entrance Stairs', 'Secret Passage Inner Bushes']), - create_lw_region(player, 'Death Mountain Entrance', None, ['Old Man Cave (West)', 'Death Mountain Entrance Drop', 'Bumper Cave Entrance Mirror Spot']), - create_lw_region(player, 'Lake Hylia Central Island', None, ['Capacity Upgrade', 'Lake Hylia Central Island Mirror Spot']), - create_cave_region(player, 'Blinds Hideout', 'a bounty of five items', - ["Blind's Hideout - Left", "Blind's Hideout - Right", "Blind's Hideout - Far Left", - "Blind's Hideout - Far Right"], ['Blinds Hideout N']), - create_cave_region(player, 'Blinds Hideout (Top)', 'a bounty of five items', ["Blind's Hideout - Top"]), - create_lw_region(player, 'Northeast Light World', None, ['Zoras River', 'Waterfall of Wishing Cave', 'Potion Shop Outer Rock', 'Catfish Mirror Spot', 'Northeast Light World Warp']), - create_lw_region(player, 'Waterfall of Wishing Cave', None, ['Waterfall of Wishing', 'Northeast Light World Return']), - create_lw_region(player, 'Potion Shop Area', None, ['Potion Shop', 'Potion Shop Inner Bushes', 'Potion Shop Inner Rock', 'Potion Shop Mirror Spot', 'Potion Shop River Drop']), - create_lw_region(player, 'Graveyard Cave Area', None, ['Graveyard Cave', 'Graveyard Cave Inner Bushes', 'Graveyard Cave Mirror Spot']), - create_lw_region(player, 'River', None, ['Light World Pier', 'Potion Shop Pier']), - create_cave_region(player, 'Hyrule Castle Secret Entrance', 'a drop\'s exit', ['Link\'s Uncle', 'Secret Passage'], ['Hyrule Castle Secret Entrance Exit']), - create_dungeon_region(player, 'Sewer Drop', 'a drop\'s exit', None, ['Sewer Drop']), # This exists only to be referenced for access checks - create_lw_region(player, 'Zoras River', ['King Zora', 'Zora\'s Ledge']), - create_cave_region(player, 'Waterfall of Wishing', 'a cave with two chests', ['Waterfall Fairy - Left', 'Waterfall Fairy - Right']), - create_lw_region(player, 'Kings Grave Area', None, ['Kings Grave', 'Kings Grave Inner Rocks']), - create_cave_region(player, 'Kings Grave', 'a cave with a chest', ['King\'s Tomb']), - create_cave_region(player, 'North Fairy Cave', 'a drop\'s exit', None, ['North Fairy Cave Exit']), - create_cave_region(player, 'Dam', 'the dam', ['Floodgate', 'Floodgate Chest']), - create_cave_region(player, 'Links House', 'your house', ['Link\'s House'], ['Links House Exit']), - create_cave_region(player, 'Chris Houlihan Room', 'I AM ERROR', None, ['Chris Houlihan Room Exit']), - create_cave_region(player, 'Tavern', 'the tavern', ['Kakariko Tavern']), - create_cave_region(player, 'Elder House', 'a connector', None, ['Elder House Exit (East)', 'Elder House Exit (West)']), - create_cave_region(player, 'Snitch Lady (East)', 'a boring house'), - create_cave_region(player, 'Snitch Lady (West)', 'a boring house'), - create_cave_region(player, 'Bush Covered House', 'the grass man'), - create_cave_region(player, 'Tavern (Front)', 'the tavern'), - create_cave_region(player, 'Light World Bomb Hut', 'a restock room'), - create_cave_region(player, 'Kakariko Shop', 'a common shop', ['Kakariko Shop - Left', 'Kakariko Shop - Middle', 'Kakariko Shop - Right']), - create_cave_region(player, 'Fortune Teller (Light)', 'a fortune teller'), - create_cave_region(player, 'Lake Hylia Fortune Teller', 'a fortune teller'), - create_cave_region(player, 'Lumberjack House', 'a boring house'), - create_cave_region(player, 'Bonk Fairy (Light)', 'a fairy fountain'), - create_cave_region(player, 'Bonk Fairy (Dark)', 'a fairy fountain'), - create_cave_region(player, 'Lake Hylia Healer Fairy', 'a fairy fountain'), - create_cave_region(player, 'Swamp Healer Fairy', 'a fairy fountain'), - create_cave_region(player, 'Desert Healer Fairy', 'a fairy fountain'), - create_cave_region(player, 'Dark Lake Hylia Healer Fairy', 'a fairy fountain'), - create_cave_region(player, 'Dark Lake Hylia Ledge Healer Fairy', 'a fairy fountain'), - create_cave_region(player, 'Dark Desert Healer Fairy', 'a fairy fountain'), - create_cave_region(player, 'Dark Death Mountain Healer Fairy', 'a fairy fountain'), - create_cave_region(player, 'Chicken House', 'a house with a chest', ['Chicken House']), - create_cave_region(player, 'Aginahs Cave', 'a cave with a chest', ['Aginah\'s Cave']), - create_cave_region(player, 'Sahasrahlas Hut', 'Sahasrahla', ['Sahasrahla\'s Hut - Left', 'Sahasrahla\'s Hut - Middle', 'Sahasrahla\'s Hut - Right', 'Sahasrahla']), - create_cave_region(player, 'Kakariko Well (top)', 'a drop', - ['Kakariko Well - Left', 'Kakariko Well - Middle', 'Kakariko Well - Right', - 'Kakariko Well - Bottom'], - ['Kakariko Well (top to bottom)', 'Kakariko Well (top to back)']), - create_cave_region(player, 'Kakariko Well (back)', 'a drop', ['Kakariko Well - Top']), - create_cave_region(player, 'Kakariko Well (bottom)', 'a drop\'s exit', None, ['Kakariko Well Exit']), - create_cave_region(player, 'Blacksmiths Hut', 'the smith', ['Blacksmith', 'Missing Smith']), - create_lw_region(player, 'Bat Cave Drop Ledge', None, ['Bat Cave Drop']), - create_cave_region(player, 'Bat Cave (right)', 'a drop', ['Magic Bat'], ['Bat Cave Door']), - create_cave_region(player, 'Bat Cave (left)', 'a drop\'s exit', None, ['Bat Cave Exit']), - create_cave_region(player, 'Sick Kids House', 'the sick kid', ['Sick Kid']), - create_lw_region(player, 'Hobo Bridge', ['Hobo']), - create_cave_region(player, 'Lost Woods Hideout (top)', 'a drop\'s exit', ['Lost Woods Hideout'], ['Lost Woods Hideout (top to bottom)']), - create_cave_region(player, 'Lost Woods Hideout (bottom)', 'a drop\'s exit', None, ['Lost Woods Hideout Exit']), - create_cave_region(player, 'Lumberjack Tree (top)', 'a drop\'s exit', ['Lumberjack Tree'], ['Lumberjack Tree (top to bottom)']), - create_cave_region(player, 'Lumberjack Tree (bottom)', 'a drop\'s exit', None, ['Lumberjack Tree Exit']), - create_cave_region(player, 'Cave 45', 'a cave with an item', ['Cave 45']), - create_cave_region(player, 'Graveyard Cave', 'a cave with an item', ['Graveyard Cave']), - create_cave_region(player, 'Checkerboard Cave', 'a cave with an item', ['Checkerboard Cave']), - create_cave_region(player, 'Long Fairy Cave', 'a fairy fountain'), - create_cave_region(player, 'Mini Moldorm Cave', 'a bounty of five items', ['Mini Moldorm Cave - Far Left', 'Mini Moldorm Cave - Left', 'Mini Moldorm Cave - Right', - 'Mini Moldorm Cave - Far Right', 'Mini Moldorm Cave - Generous Guy']), - create_cave_region(player, 'Ice Rod Cave', 'a cave with a chest', ['Ice Rod Cave']), - create_cave_region(player, 'Good Bee Cave', 'a cold bee'), - create_cave_region(player, '20 Rupee Cave', 'a cave with some cash'), - create_cave_region(player, 'Cave Shop (Lake Hylia)', 'a common shop', ['Lake Hylia Shop - Left', 'Lake Hylia Shop - Middle', 'Lake Hylia Shop - Right']), - create_cave_region(player, 'Cave Shop (Dark Death Mountain)', 'a common shop', ['Dark Death Mountain Shop - Left', 'Dark Death Mountain Shop - Middle', 'Dark Death Mountain Shop - Right']), - create_cave_region(player, 'Bonk Rock Cave', 'a cave with a chest', ['Bonk Rock Cave']), - create_cave_region(player, 'Library', 'the library', ['Library']), - create_cave_region(player, 'Kakariko Gamble Game', 'a game of chance'), - create_cave_region(player, 'Potion Shop', 'the potion shop', ['Potion Shop', 'Potion Shop - Left', 'Potion Shop - Middle', 'Potion Shop - Right']), - create_lw_region(player, 'Lake Hylia Island', ['Lake Hylia Island']), - create_cave_region(player, 'Capacity Upgrade', 'the queen of fairies', ['Capacity Upgrade - Left', 'Capacity Upgrade - Right']), - create_cave_region(player, 'Two Brothers House', 'a connector', None, ['Two Brothers House Exit (East)', 'Two Brothers House Exit (West)']), - create_lw_region(player, 'Maze Race Ledge', ['Maze Race'], ['Two Brothers House (West)', 'Maze Race Mirror Spot', 'Maze Race Ledge Drop']), - create_cave_region(player, '50 Rupee Cave', 'a cave with some cash'), - create_lw_region(player, 'Desert Ledge', ['Desert Ledge'], ['Desert Palace Entrance (North) Rocks', 'Desert Palace Entrance (West)', 'Desert Ledge Drop']), - create_lw_region(player, 'Desert Palace Stairs', None, ['Desert Palace Entrance (South)', 'Desert Palace Stairs Mirror Spot']), - create_lw_region(player, 'Desert Palace Lone Stairs', None, ['Desert Palace Stairs Drop', 'Desert Palace Entrance (East)']), - create_lw_region(player, 'Desert Palace Entrance (North) Spot', None, ['Desert Palace Entrance (North)', 'Desert Ledge Return Rocks', 'Desert Palace North Mirror Spot']), - create_lw_region(player, 'Master Sword Meadow', ['Master Sword Pedestal']), - create_cave_region(player, 'Lost Woods Gamble', 'a game of chance'), - create_lw_region(player, 'Hyrule Castle Ledge', None, ['Hyrule Castle Entrance (East)', 'Hyrule Castle Entrance (West)', 'Agahnims Tower', 'Hyrule Castle Ledge Courtyard Drop', 'Inverted Pyramid Hole']), - create_cave_region(player, 'Old Man Cave', 'a connector', ['Old Man'], ['Old Man Cave Exit (East)']), - create_cave_region(player, 'Old Man Cave Ledge', 'a connector', None, ['Old Man Cave Exit (West)', 'Old Man Cave Dropdown']), - create_cave_region(player, 'Old Man House', 'a connector', None, ['Old Man House Exit (Bottom)', 'Old Man House Front to Back']), - create_cave_region(player, 'Old Man House Back', 'a connector', None, ['Old Man House Exit (Top)', 'Old Man House Back to Front']), - create_lw_region(player, 'Death Mountain', None, ['Old Man Cave (East)', 'Old Man House (Bottom)', 'Old Man House (Top)', 'Death Mountain Return Cave (East)', 'Spectacle Rock Cave', - 'Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Bottom)', 'Broken Bridge (West)', 'Death Mountain Mirror Spot']), - create_cave_region(player, 'Death Mountain Return Cave (left)', 'a connector', None, ['Death Mountain Return Cave Exit (West)', 'Death Mountain Return Cave E']), - create_cave_region(player, 'Death Mountain Return Cave (right)', 'a connector', None, ['Death Mountain Return Cave Exit (East)', 'Death Mountain Return Cave W']), - create_lw_region(player, 'Death Mountain Return Ledge', None, ['Death Mountain Return Ledge Drop', 'Death Mountain Return Cave (West)', 'Bumper Cave Ledge Mirror Spot']), - create_cave_region(player, 'Spectacle Rock Cave (Top)', 'a connector', ['Spectacle Rock Cave'], ['Spectacle Rock Cave Drop', 'Spectacle Rock Cave Exit (Top)']), - create_cave_region(player, 'Spectacle Rock Cave (Bottom)', 'a connector', None, ['Spectacle Rock Cave Exit']), - create_cave_region(player, 'Spectacle Rock Cave (Peak)', 'a connector', None, ['Spectacle Rock Cave Peak Drop', 'Spectacle Rock Cave Exit (Peak)']), - create_lw_region(player, 'East Death Mountain (Bottom)', None, ['Broken Bridge (East)', 'Paradox Cave (Bottom)', 'Paradox Cave (Middle)', 'East Death Mountain Mirror Spot (Bottom)', 'Hookshot Fairy', - 'Fairy Ascension Rocks', 'Spiral Cave (Bottom)']), - create_cave_region(player, 'Hookshot Fairy', 'fairies deep in a cave'), - create_cave_region(player, 'Paradox Cave Front', 'a connector', None, ['Paradox Cave Push Block Reverse', 'Paradox Cave Exit (Bottom)', 'Light World Death Mountain Shop']), - create_cave_region(player, 'Paradox Cave Chest Area', 'a connector', ['Paradox Cave Lower - Far Left', - 'Paradox Cave Lower - Left', - 'Paradox Cave Lower - Right', - 'Paradox Cave Lower - Far Right', - 'Paradox Cave Lower - Middle'], - ['Paradox Cave Push Block', 'Paradox Cave Bomb Jump', 'Paradox Cave Chest Area NE']), - create_cave_region(player, 'Paradox Cave Bomb Area', 'a connector', ['Paradox Cave Upper - Left', - 'Paradox Cave Upper - Right']), - create_cave_region(player, 'Paradox Cave', 'a connector', None, ['Paradox Cave Exit (Middle)', 'Paradox Cave Exit (Top)', 'Paradox Cave Drop']), - create_cave_region(player, 'Light World Death Mountain Shop', 'a common shop', ['Paradox Shop - Left', 'Paradox Shop - Middle', 'Paradox Shop - Right']), - create_lw_region(player, 'East Death Mountain (Top)', ['Floating Island'], ['Paradox Cave (Top)', 'Death Mountain (Top)', 'Spiral Cave Ledge Access', 'East Death Mountain Drop', 'East Death Mountain Mirror Spot (Top)', 'Fairy Ascension Ledge Access', 'Mimic Cave Ledge Access', - 'Floating Island Mirror Spot']), - create_lw_region(player, 'Spiral Cave Ledge', None, ['Spiral Cave', 'Spiral Cave Ledge Drop', 'Dark Death Mountain Ledge Mirror Spot (West)']), - create_lw_region(player, 'Mimic Cave Ledge', None, ['Mimic Cave', 'Mimic Cave Ledge Drop', 'Dark Death Mountain Ledge Mirror Spot (East)']), - create_cave_region(player, 'Spiral Cave (Top)', 'a connector', ['Spiral Cave'], ['Spiral Cave (top to bottom)', 'Spiral Cave Exit (Top)']), - create_cave_region(player, 'Spiral Cave (Bottom)', 'a connector', None, ['Spiral Cave Exit']), - create_lw_region(player, 'Fairy Ascension Plateau', None, ['Fairy Ascension Drop', 'Fairy Ascension Cave (Bottom)']), - create_cave_region(player, 'Fairy Ascension Cave (Bottom)', 'a connector', None, ['Fairy Ascension Cave Climb', 'Fairy Ascension Cave Exit (Bottom)']), - create_cave_region(player, 'Fairy Ascension Cave (Drop)', 'a connector', None, ['Fairy Ascension Cave Pots']), - create_cave_region(player, 'Fairy Ascension Cave (Top)', 'a connector', None, ['Fairy Ascension Cave Exit (Top)', 'Fairy Ascension Cave Drop']), - create_lw_region(player, 'Fairy Ascension Ledge', None, ['Fairy Ascension Ledge Drop', 'Fairy Ascension Cave (Top)', 'Laser Bridge Mirror Spot']), - create_lw_region(player, 'Death Mountain (Top)', ['Ether Tablet', 'Spectacle Rock'], ['East Death Mountain (Top)', 'Tower of Hera', 'Death Mountain Drop', 'Death Mountain (Top) Mirror Spot']), - create_dw_region(player, 'Bumper Cave Ledge', ['Bumper Cave Ledge'], ['Bumper Cave Ledge Drop', 'Bumper Cave (Top)']), - - create_dw_region(player, 'East Dark World', ['Pyramid'], ['Pyramid Fairy', 'South Dark World Bridge', 'Palace of Darkness', 'Dark Lake Hylia Drop (East)', - 'Dark Lake Hylia Fairy', 'Palace of Darkness Hint', 'East Dark World Hint', 'Northeast Dark World Broken Bridge Pass', 'East Dark World Teleporter', 'EDW Flute']), - create_dw_region(player, 'Catfish', ['Catfish'], ['Catfish Exit Rock']), - create_dw_region(player, 'Northeast Dark World', None, ['West Dark World Gap', 'Dark World Potion Shop', 'East Dark World Broken Bridge Pass', 'NEDW Flute', 'Dark Lake Hylia Teleporter', 'Catfish Entrance Rock']), - create_cave_region(player, 'Palace of Darkness Hint', 'a storyteller'), - create_cave_region(player, 'East Dark World Hint', 'a storyteller'), - create_dw_region(player, 'South Dark World', ['Stumpy', 'Digging Game'], ['Dark Lake Hylia Drop (South)', 'Hype Cave', 'Swamp Palace', 'Village of Outcasts Heavy Rock', 'East Dark World Bridge', 'Big Bomb Shop', 'Archery Game', 'Bonk Fairy (Dark)', - 'Dark Lake Hylia Shop', 'South Dark World Teleporter', 'Post Aga Teleporter', 'SDW Flute']), - create_cave_region(player, 'Big Bomb Shop', 'the bomb shop'), - create_cave_region(player, 'Archery Game', 'a game of skill'), - create_dw_region(player, 'Dark Lake Hylia', None, ['East Dark World Pier', 'Dark Lake Hylia Ledge Pier', 'Ice Palace Missing Wall']), - create_dw_region(player, 'Dark Lake Hylia Central Island', None, ['Dark Lake Hylia Shallows', 'Ice Palace', 'Dark Lake Hylia Central Island Teleporter']), - create_dw_region(player, 'Dark Lake Hylia Ledge', None, ['Dark Lake Hylia Ledge Drop', 'Dark Lake Hylia Ledge Fairy', 'Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Ledge Spike Cave', 'DLHL Flute']), - create_cave_region(player, 'Dark Lake Hylia Ledge Hint', 'a storyteller'), - create_cave_region(player, 'Dark Lake Hylia Ledge Spike Cave', 'a spiky hint'), - create_cave_region(player, 'Hype Cave', 'a bounty of five items', ['Hype Cave - Top', 'Hype Cave - Middle Right', 'Hype Cave - Middle Left', - 'Hype Cave - Bottom', 'Hype Cave - Generous Guy']), - create_dw_region(player, 'West Dark World', ['Frog'], ['Village of Outcasts Drop', 'East Dark World River Pier', 'Brewery', 'C-Shaped House', 'Chest Game', 'Thieves Town', 'Bumper Cave Entrance Rock', - 'Skull Woods Forest', 'Village of Outcasts Pegs', 'Village of Outcasts Eastern Rocks', 'Red Shield Shop', 'Dark Sanctuary Hint', 'Fortune Teller (Dark)', 'Dark World Lumberjack Shop', - 'West Dark World Teleporter', 'WDW Flute']), - create_dw_region(player, 'Dark Grassy Lawn', None, ['Grassy Lawn Pegs', 'Dark World Shop', 'Dark Grassy Lawn Flute']), - create_dw_region(player, 'Hammer Peg Area', ['Dark Blacksmith Ruins'], ['Dark World Hammer Peg Cave', 'Peg Area Rocks', 'Hammer Peg Area Flute']), - create_dw_region(player, 'Bumper Cave Entrance', None, ['Bumper Cave (Bottom)', 'Bumper Cave Entrance Drop']), - create_cave_region(player, 'Fortune Teller (Dark)', 'a fortune teller'), - create_cave_region(player, 'Village of Outcasts Shop', 'a common shop', ['Village of Outcasts Shop - Left', 'Village of Outcasts Shop - Middle', 'Village of Outcasts Shop - Right']), - create_cave_region(player, 'Dark Lake Hylia Shop', 'a common shop', ['Dark Lake Hylia Shop - Left', 'Dark Lake Hylia Shop - Middle', 'Dark Lake Hylia Shop - Right']), - create_cave_region(player, 'Dark World Lumberjack Shop', 'a common shop', ['Dark Lumberjack Shop - Left', 'Dark Lumberjack Shop - Middle', 'Dark Lumberjack Shop - Right']), - create_cave_region(player, 'Dark World Potion Shop', 'a common shop', ['Dark Potion Shop - Left', 'Dark Potion Shop - Middle', 'Dark Potion Shop - Right']), - create_cave_region(player, 'Dark World Hammer Peg Cave', 'a cave with an item', ['Peg Cave']), - create_cave_region(player, 'Pyramid Fairy', 'a cave with two chests', ['Pyramid Fairy - Left', 'Pyramid Fairy - Right']), - create_cave_region(player, 'Brewery', 'a house with a chest', ['Brewery']), - create_cave_region(player, 'C-Shaped House', 'a house with a chest', ['C-Shaped House']), - create_cave_region(player, 'Chest Game', 'a game of 16 chests', ['Chest Game']), - create_cave_region(player, 'Red Shield Shop', 'the rare shop', ['Red Shield Shop - Left', 'Red Shield Shop - Middle', 'Red Shield Shop - Right']), - create_cave_region(player, 'Dark Sanctuary Hint', 'a storyteller', None, ['Dark Sanctuary Hint Exit']), - create_cave_region(player, 'Bumper Cave (bottom)', 'a connector', None, ['Bumper Cave Exit (Bottom)', 'Bumper Cave Bottom to Top']), - create_cave_region(player, 'Bumper Cave (top)', 'a connector', None, ['Bumper Cave Exit (Top)', 'Bumper Cave Top To Bottom']), - create_dw_region(player, 'Skull Woods Forest', None, ['Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', - 'Skull Woods First Section Door', 'Skull Woods Second Section Door (East)']), - create_dw_region(player, 'Skull Woods Forest (West)', None, ['Skull Woods Second Section Hole', 'Skull Woods Second Section Door (West)', 'Skull Woods Final Section']), - create_dw_region(player, 'Dark Desert', None, ['Misery Mire', 'Mire Shed', 'Dark Desert Hint', 'Dark Desert Fairy', 'DD Flute']), - create_dw_region(player, 'Dark Desert Ledge', None, ['Dark Desert Drop', 'Dark Desert Teleporter']), - create_cave_region(player, 'Mire Shed', 'a cave with two chests', ['Mire Shed - Left', 'Mire Shed - Right']), - create_cave_region(player, 'Dark Desert Hint', 'a storyteller'), - create_dw_region(player, 'Dark Death Mountain', None, ['Dark Death Mountain Drop (East)', 'Ganons Tower', 'Superbunny Cave (Top)', 'Hookshot Cave', 'Turtle Rock', - 'Spike Cave', 'Dark Death Mountain Fairy', 'Dark Death Mountain Teleporter (West)', 'Turtle Rock Tail Drop', 'DDM Flute']), - create_dw_region(player, 'Dark Death Mountain Ledge', None, ['Dark Death Mountain Ledge (East)', 'Dark Death Mountain Ledge (West)']), - create_dw_region(player, 'Turtle Rock (Top)', None, ['Dark Death Mountain Teleporter (East)', 'Turtle Rock Drop']), - create_dw_region(player, 'Dark Death Mountain Isolated Ledge', None, ['Turtle Rock Isolated Ledge Entrance']), - create_dw_region(player, 'Dark Death Mountain (East Bottom)', None, ['Superbunny Cave (Bottom)', 'Cave Shop (Dark Death Mountain)', 'Dark Death Mountain Teleporter (East Bottom)', 'EDDM Flute']), - create_cave_region(player, 'Superbunny Cave (Top)', 'a connector', ['Superbunny Cave - Top', 'Superbunny Cave - Bottom'], ['Superbunny Cave Exit (Top)']), - create_cave_region(player, 'Superbunny Cave (Bottom)', 'a connector', None, ['Superbunny Cave Climb', 'Superbunny Cave Exit (Bottom)']), - create_cave_region(player, 'Spike Cave', 'Spike Cave', ['Spike Cave']), - create_cave_region(player, 'Hookshot Cave (Front)', 'a connector', None, - ['Hookshot Cave Front to Middle', 'Hookshot Cave Front Exit', 'Hookshot Cave Bonk Path', 'Hookshot Cave Hook Path']), - create_cave_region(player, 'Hookshot Cave (Bonk Islands)', 'a connector', ['Hookshot Cave - Bottom Right']), - create_cave_region(player, 'Hookshot Cave (Hook Islands)', 'a connector', ['Hookshot Cave - Top Right', 'Hookshot Cave - Top Left', 'Hookshot Cave - Bottom Left']), - create_cave_region(player, 'Hookshot Cave (Back)', 'a connector', None, ['Hookshot Cave Back to Middle', 'Hookshot Cave Back Exit']), - create_cave_region(player, 'Hookshot Cave (Middle)', 'a connector', None, ['Hookshot Cave Middle to Back', 'Hookshot Cave Middle to Front']), - - create_dw_region(player, 'Death Mountain Floating Island (Dark World)', None, ['Floating Island Drop', 'Hookshot Cave Back Entrance']), - create_cave_region(player, 'Mimic Cave', 'Mimic Cave', ['Mimic Cave']), - - create_cave_region(player, 'Pyramid', 'a drop\'s exit', ['Ganon'], ['Ganon Drop']), - create_cave_region(player, 'Bottom of Pyramid', 'a drop\'s exit', None, ['Pyramid Exit']), - create_dw_region(player, 'Pyramid Ledge', None, ['Pyramid Drop']), # houlihan room exits here in inverted - - # to simplify flute connections - create_cave_region(player, 'The Sky', 'A Dark Sky', None, ['DDM Landing','NEDW Landing', 'WDW Landing', 'SDW Landing', 'EDW Landing', 'DD Landing', 'DLHL Landing']), - - create_lw_region(player, 'Desert Northern Cliffs'), - create_lw_region(player, 'Death Mountain Bunny Descent Area') - ] - - -def mark_dark_world_regions(world, player): - # cross world caves may have some sections marked as both in_light_world, and in_dark_work. - # That is ok. the bunny logic will check for this case and incorporate special rules. - queue = collections.deque(region for region in world.get_regions(player) if region.type == RegionType.DarkWorld) - seen = set(queue) - while queue: - current = queue.popleft() - current.is_dark_world = True - for exit in current.exits: - if exit.connected_region is None or exit.connected_region.type == RegionType.LightWorld: # todo: remove none check - # Don't venture into the light world - continue - if exit.connected_region not in seen: - seen.add(exit.connected_region) - queue.append(exit.connected_region) - - queue = collections.deque(region for region in world.get_regions(player) if region.type == RegionType.LightWorld) - seen = set(queue) - while queue: - current = queue.popleft() - current.is_light_world = True - for exit in current.exits: - if exit.connected_region is not None: - if exit.connected_region.type == RegionType.DarkWorld: - # Don't venture into the dark world - continue - if exit.connected_region not in seen: - seen.add(exit.connected_region) - queue.append(exit.connected_region) - - -location_table = {'Mushroom': (0x180013, 0x186338, False, 'in the woods'), - 'Bottle Merchant': (0x2eb18, 0x186339, False, 'with a merchant'), - 'Flute Spot': (0x18014a, 0x18633d, False, 'underground'), - 'Sunken Treasure': (0x180145, 0x186354, False, 'underwater'), - 'Purple Chest': (0x33d68, 0x186359, False, 'from a box'), - "Blind's Hideout - Top": (0xeb0f, 0x1862e3, False, 'in a basement'), - "Blind's Hideout - Left": (0xeb12, 0x1862e6, False, 'in a basement'), - "Blind's Hideout - Right": (0xeb15, 0x1862e9, False, 'in a basement'), - "Blind's Hideout - Far Left": (0xeb18, 0x1862ec, False, 'in a basement'), - "Blind's Hideout - Far Right": (0xeb1b, 0x1862ef, False, 'in a basement'), - "Link's Uncle": (0x2df45, 0x18635f, False, 'with your uncle'), - 'Secret Passage': (0xe971, 0x186145, False, 'near your uncle'), - 'King Zora': (0xee1c3, 0x186360, False, 'at a high price'), - "Zora's Ledge": (0x180149, 0x186358, False, 'near Zora'), - 'Waterfall Fairy - Left': (0xe9b0, 0x186184, False, 'near a fairy'), - 'Waterfall Fairy - Right': (0xe9d1, 0x1861a5, False, 'near a fairy'), - "King's Tomb": (0xe97a, 0x18614e, False, 'alone in a cave'), - 'Floodgate Chest': (0xe98c, 0x186160, False, 'in the dam'), - "Link's House": (0xe9bc, 0x186190, False, 'in your home'), - 'Kakariko Tavern': (0xe9ce, 0x1861a2, False, 'in the bar'), - 'Chicken House': (0xe9e9, 0x1861bd, False, 'near poultry'), - "Aginah's Cave": (0xe9f2, 0x1861c6, False, 'with Aginah'), - "Sahasrahla's Hut - Left": (0xea82, 0x186256, False, 'near the elder'), - "Sahasrahla's Hut - Middle": (0xea85, 0x186259, False, 'near the elder'), - "Sahasrahla's Hut - Right": (0xea88, 0x18625c, False, 'near the elder'), - 'Sahasrahla': (0x2f1fc, 0x186365, False, 'with the elder'), - 'Kakariko Well - Top': (0xea8e, 0x186262, False, 'in a well'), - 'Kakariko Well - Left': (0xea91, 0x186265, False, 'in a well'), - 'Kakariko Well - Middle': (0xea94, 0x186268, False, 'in a well'), - 'Kakariko Well - Right': (0xea97, 0x18626b, False, 'in a well'), - 'Kakariko Well - Bottom': (0xea9a, 0x18626e, False, 'in a well'), - 'Blacksmith': (0x18002a, 0x186366, False, 'with the smith'), - 'Magic Bat': (0x180015, 0x18635e, False, 'with the bat'), - 'Sick Kid': (0x339cf, 0x186367, False, 'with the sick'), - 'Hobo': (0x33e7d, 0x186368, False, 'with the hobo'), - 'Lost Woods Hideout': (0x180000, 0x186348, False, 'near a thief'), - 'Lumberjack Tree': (0x180001, 0x186349, False, 'in a hole'), - 'Cave 45': (0x180003, 0x18634b, False, 'alone in a cave'), - 'Graveyard Cave': (0x180004, 0x18634c, False, 'alone in a cave'), - 'Checkerboard Cave': (0x180005, 0x18634d, False, 'alone in a cave'), - 'Mini Moldorm Cave - Far Left': (0xeb42, 0x186316, False, 'near Moldorms'), - 'Mini Moldorm Cave - Left': (0xeb45, 0x186319, False, 'near Moldorms'), - 'Mini Moldorm Cave - Right': (0xeb48, 0x18631c, False, 'near Moldorms'), - 'Mini Moldorm Cave - Far Right': (0xeb4b, 0x18631f, False, 'near Moldorms'), - 'Mini Moldorm Cave - Generous Guy': (0x180010, 0x18635a, False, 'near Moldorms'), - 'Ice Rod Cave': (0xeb4e, 0x186322, False, 'in a frozen cave'), - 'Bonk Rock Cave': (0xeb3f, 0x186313, False, 'alone in a cave'), - 'Library': (0x180012, 0x18635c, False, 'near books'), - 'Potion Shop': (0x180014, 0x18635d, False, 'near potions'), - 'Lake Hylia Island': (0x180144, 0x186353, False, 'on an island'), - 'Maze Race': (0x180142, 0x186351, False, 'at the race'), - 'Desert Ledge': (0x180143, 0x186352, False, 'in the desert'), - 'Desert Palace - Big Chest': (0xe98f, 0x186163, False, 'in Desert Palace'), - 'Desert Palace - Torch': (0x180160, 0x186362, False, 'in Desert Palace'), - 'Desert Palace - Map Chest': (0xe9b6, 0x18618a, False, 'in Desert Palace'), - 'Desert Palace - Compass Chest': (0xe9cb, 0x18619f, False, 'in Desert Palace'), - 'Desert Palace - Big Key Chest': (0xe9c2, 0x186196, False, 'in Desert Palace'), - 'Desert Palace - Boss': (0x180151, 0x18633f, False, 'with Lanmolas'), - 'Eastern Palace - Compass Chest': (0xe977, 0x18614b, False, 'in Eastern Palace'), - 'Eastern Palace - Big Chest': (0xe97d, 0x186151, False, 'in Eastern Palace'), - 'Eastern Palace - Cannonball Chest': (0xe9b3, 0x186187, False, 'in Eastern Palace'), - 'Eastern Palace - Big Key Chest': (0xe9b9, 0x18618d, False, 'in Eastern Palace'), - 'Eastern Palace - Map Chest': (0xe9f5, 0x1861c9, False, 'in Eastern Palace'), - 'Eastern Palace - Boss': (0x180150, 0x18633e, False, 'with the Armos'), - 'Master Sword Pedestal': (0x289b0, 0x186369, False, 'at the pedestal'), - 'Hyrule Castle - Boomerang Chest': (0xe974, 0x186148, False, 'in Hyrule Castle'), - 'Hyrule Castle - Map Chest': (0xeb0c, 0x1862e0, False, 'in Hyrule Castle'), - "Hyrule Castle - Zelda's Chest": (0xeb09, 0x1862dd, False, 'in Hyrule Castle'), - 'Sewers - Dark Cross': (0xe96e, 0x186142, False, 'in the sewers'), - 'Sewers - Secret Room - Left': (0xeb5d, 0x186331, False, 'in the sewers'), - 'Sewers - Secret Room - Middle': (0xeb60, 0x186334, False, 'in the sewers'), - 'Sewers - Secret Room - Right': (0xeb63, 0x186337, False, 'in the sewers'), - 'Sanctuary': (0xea79, 0x18624d, False, 'in Sanctuary'), - 'Castle Tower - Room 03': (0xeab5, 0x186289, False, 'in Castle Tower'), - 'Castle Tower - Dark Maze': (0xeab2, 0x186286, False, 'in Castle Tower'), - 'Old Man': (0xf69fa, 0x186364, False, 'with the old man'), - 'Spectacle Rock Cave': (0x180002, 0x18634a, False, 'alone in a cave'), - 'Paradox Cave Lower - Far Left': (0xeb2a, 0x1862fe, False, 'in a cave with seven chests'), - 'Paradox Cave Lower - Left': (0xeb2d, 0x186301, False, 'in a cave with seven chests'), - 'Paradox Cave Lower - Right': (0xeb30, 0x186304, False, 'in a cave with seven chests'), - 'Paradox Cave Lower - Far Right': (0xeb33, 0x186307, False, 'in a cave with seven chests'), - 'Paradox Cave Lower - Middle': (0xeb36, 0x18630a, False, 'in a cave with seven chests'), - 'Paradox Cave Upper - Left': (0xeb39, 0x18630d, False, 'in a cave with seven chests'), - 'Paradox Cave Upper - Right': (0xeb3c, 0x186310, False, 'in a cave with seven chests'), - 'Spiral Cave': (0xe9bf, 0x186193, False, 'in spiral cave'), - 'Ether Tablet': (0x180016, 0x18633b, False, 'at a monolith'), - 'Spectacle Rock': (0x180140, 0x18634f, False, 'atop a rock'), - 'Tower of Hera - Basement Cage': (0x180162, 0x18633a, False, 'in Tower of Hera'), - 'Tower of Hera - Map Chest': (0xe9ad, 0x186181, False, 'in Tower of Hera'), - 'Tower of Hera - Big Key Chest': (0xe9e6, 0x1861ba, False, 'in Tower of Hera'), - 'Tower of Hera - Compass Chest': (0xe9fb, 0x1861cf, False, 'in Tower of Hera'), - 'Tower of Hera - Big Chest': (0xe9f8, 0x1861cc, False, 'in Tower of Hera'), - 'Tower of Hera - Boss': (0x180152, 0x186340, False, 'with Moldorm'), - 'Pyramid': (0x180147, 0x186356, False, 'on the pyramid'), - 'Catfish': (0xee185, 0x186361, False, 'with a catfish'), - 'Stumpy': (0x330c7, 0x18636a, False, 'with tree boy'), - 'Digging Game': (0x180148, 0x186357, False, 'underground'), - 'Bombos Tablet': (0x180017, 0x18633c, False, 'at a monolith'), - 'Hype Cave - Top': (0xeb1e, 0x1862f2, False, 'near a bat-like man'), - 'Hype Cave - Middle Right': (0xeb21, 0x1862f5, False, 'near a bat-like man'), - 'Hype Cave - Middle Left': (0xeb24, 0x1862f8, False, 'near a bat-like man'), - 'Hype Cave - Bottom': (0xeb27, 0x1862fb, False, 'near a bat-like man'), - 'Hype Cave - Generous Guy': (0x180011, 0x18635b, False, 'with a bat-like man'), - 'Peg Cave': (0x180006, 0x18634e, False, 'alone in a cave'), - 'Pyramid Fairy - Left': (0xe980, 0x186154, False, 'near a fairy'), - 'Pyramid Fairy - Right': (0xe983, 0x186157, False, 'near a fairy'), - 'Brewery': (0xe9ec, 0x1861c0, False, 'alone in a home'), - 'C-Shaped House': (0xe9ef, 0x1861c3, False, 'alone in a home'), - 'Chest Game': (0xeda8, 0x18636b, False, 'as a prize'), - 'Bumper Cave Ledge': (0x180146, 0x186355, False, 'on a ledge'), - 'Mire Shed - Left': (0xea73, 0x186247, False, 'near sparks'), - 'Mire Shed - Right': (0xea76, 0x18624a, False, 'near sparks'), - 'Superbunny Cave - Top': (0xea7c, 0x186250, False, 'in a connection'), - 'Superbunny Cave - Bottom': (0xea7f, 0x186253, False, 'in a connection'), - 'Spike Cave': (0xea8b, 0x18625f, False, 'beyond spikes'), - 'Hookshot Cave - Top Right': (0xeb51, 0x186325, False, 'across pits'), - 'Hookshot Cave - Top Left': (0xeb54, 0x186328, False, 'across pits'), - 'Hookshot Cave - Bottom Right': (0xeb5a, 0x18632e, False, 'across pits'), - 'Hookshot Cave - Bottom Left': (0xeb57, 0x18632b, False, 'across pits'), - 'Floating Island': (0x180141, 0x186350, False, 'on an island'), - 'Mimic Cave': (0xe9c5, 0x186199, False, 'in a cave of mimicry'), - 'Swamp Palace - Entrance': (0xea9d, 0x186271, False, 'in Swamp Palace'), - 'Swamp Palace - Map Chest': (0xe986, 0x18615a, False, 'in Swamp Palace'), - 'Swamp Palace - Big Chest': (0xe989, 0x18615d, False, 'in Swamp Palace'), - 'Swamp Palace - Compass Chest': (0xeaa0, 0x186274, False, 'in Swamp Palace'), - 'Swamp Palace - Big Key Chest': (0xeaa6, 0x18627a, False, 'in Swamp Palace'), - 'Swamp Palace - West Chest': (0xeaa3, 0x186277, False, 'in Swamp Palace'), - 'Swamp Palace - Flooded Room - Left': (0xeaa9, 0x18627d, False, 'in Swamp Palace'), - 'Swamp Palace - Flooded Room - Right': (0xeaac, 0x186280, False, 'in Swamp Palace'), - 'Swamp Palace - Waterfall Room': (0xeaaf, 0x186283, False, 'in Swamp Palace'), - 'Swamp Palace - Boss': (0x180154, 0x186342, False, 'with Arrghus'), - "Thieves' Town - Big Key Chest": (0xea04, 0x1861d8, False, "in Thieves' Town"), - "Thieves' Town - Map Chest": (0xea01, 0x1861d5, False, "in Thieves' Town"), - "Thieves' Town - Compass Chest": (0xea07, 0x1861db, False, "in Thieves' Town"), - "Thieves' Town - Ambush Chest": (0xea0a, 0x1861de, False, "in Thieves' Town"), - "Thieves' Town - Attic": (0xea0d, 0x1861e1, False, "in Thieves' Town"), - "Thieves' Town - Big Chest": (0xea10, 0x1861e4, False, "in Thieves' Town"), - "Thieves' Town - Blind's Cell": (0xea13, 0x1861e7, False, "in Thieves' Town"), - "Thieves' Town - Boss": (0x180156, 0x186344, False, 'with Blind'), - 'Skull Woods - Compass Chest': (0xe992, 0x186166, False, 'in Skull Woods'), - 'Skull Woods - Map Chest': (0xe99b, 0x18616f, False, 'in Skull Woods'), - 'Skull Woods - Big Chest': (0xe998, 0x18616c, False, 'in Skull Woods'), - 'Skull Woods - Pot Prison': (0xe9a1, 0x186175, False, 'in Skull Woods'), - 'Skull Woods - Pinball Room': (0xe9c8, 0x18619c, False, 'in Skull Woods'), - 'Skull Woods - Big Key Chest': (0xe99e, 0x186172, False, 'in Skull Woods'), - 'Skull Woods - Bridge Room': (0xe9fe, 0x1861d2, False, 'near Mothula'), - 'Skull Woods - Boss': (0x180155, 0x186343, False, 'with Mothula'), - 'Ice Palace - Compass Chest': (0xe9d4, 0x1861a8, False, 'in Ice Palace'), - 'Ice Palace - Freezor Chest': (0xe995, 0x186169, False, 'in Ice Palace'), - 'Ice Palace - Big Chest': (0xe9aa, 0x18617e, False, 'in Ice Palace'), - 'Ice Palace - Iced T Room': (0xe9e3, 0x1861b7, False, 'in Ice Palace'), - 'Ice Palace - Spike Room': (0xe9e0, 0x1861b4, False, 'in Ice Palace'), - 'Ice Palace - Big Key Chest': (0xe9a4, 0x186178, False, 'in Ice Palace'), - 'Ice Palace - Map Chest': (0xe9dd, 0x1861b1, False, 'in Ice Palace'), - 'Ice Palace - Boss': (0x180157, 0x186345, False, 'with Kholdstare'), - 'Misery Mire - Big Chest': (0xea67, 0x18623b, False, 'in Misery Mire'), - 'Misery Mire - Map Chest': (0xea6a, 0x18623e, False, 'in Misery Mire'), - 'Misery Mire - Main Lobby': (0xea5e, 0x186232, False, 'in Misery Mire'), - 'Misery Mire - Bridge Chest': (0xea61, 0x186235, False, 'in Misery Mire'), - 'Misery Mire - Spike Chest': (0xe9da, 0x1861ae, False, 'in Misery Mire'), - 'Misery Mire - Compass Chest': (0xea64, 0x186238, False, 'in Misery Mire'), - 'Misery Mire - Big Key Chest': (0xea6d, 0x186241, False, 'in Misery Mire'), - 'Misery Mire - Boss': (0x180158, 0x186346, False, 'with Vitreous'), - 'Turtle Rock - Compass Chest': (0xea22, 0x1861f6, False, 'in Turtle Rock'), - 'Turtle Rock - Roller Room - Left': (0xea1c, 0x1861f0, False, 'in Turtle Rock'), - 'Turtle Rock - Roller Room - Right': (0xea1f, 0x1861f3, False, 'in Turtle Rock'), - 'Turtle Rock - Chain Chomps': (0xea16, 0x1861ea, False, 'in Turtle Rock'), - 'Turtle Rock - Big Key Chest': (0xea25, 0x1861f9, False, 'in Turtle Rock'), - 'Turtle Rock - Big Chest': (0xea19, 0x1861ed, False, 'in Turtle Rock'), - 'Turtle Rock - Crystaroller Room': (0xea34, 0x186208, False, 'in Turtle Rock'), - 'Turtle Rock - Eye Bridge - Bottom Left': (0xea31, 0x186205, False, 'in Turtle Rock'), - 'Turtle Rock - Eye Bridge - Bottom Right': (0xea2e, 0x186202, False, 'in Turtle Rock'), - 'Turtle Rock - Eye Bridge - Top Left': (0xea2b, 0x1861ff, False, 'in Turtle Rock'), - 'Turtle Rock - Eye Bridge - Top Right': (0xea28, 0x1861fc, False, 'in Turtle Rock'), - 'Turtle Rock - Boss': (0x180159, 0x186347, False, 'with Trinexx'), - 'Palace of Darkness - Shooter Room': (0xea5b, 0x18622f, False, 'in Palace of Darkness'), - 'Palace of Darkness - The Arena - Bridge': (0xea3d, 0x186211, False, 'in Palace of Darkness'), - 'Palace of Darkness - Stalfos Basement': (0xea49, 0x18621d, False, 'in Palace of Darkness'), - 'Palace of Darkness - Big Key Chest': (0xea37, 0x18620b, False, 'in Palace of Darkness'), - 'Palace of Darkness - The Arena - Ledge': (0xea3a, 0x18620e, False, 'in Palace of Darkness'), - 'Palace of Darkness - Map Chest': (0xea52, 0x186226, False, 'in Palace of Darkness'), - 'Palace of Darkness - Compass Chest': (0xea43, 0x186217, False, 'in Palace of Darkness'), - 'Palace of Darkness - Dark Basement - Left': (0xea4c, 0x186220, False, 'in Palace of Darkness'), - 'Palace of Darkness - Dark Basement - Right': (0xea4f, 0x186223, False, 'in Palace of Darkness'), - 'Palace of Darkness - Dark Maze - Top': (0xea55, 0x186229, False, 'in Palace of Darkness'), - 'Palace of Darkness - Dark Maze - Bottom': (0xea58, 0x18622c, False, 'in Palace of Darkness'), - 'Palace of Darkness - Big Chest': (0xea40, 0x186214, False, 'in Palace of Darkness'), - 'Palace of Darkness - Harmless Hellway': (0xea46, 0x18621a, False, 'in Palace of Darkness'), - 'Palace of Darkness - Boss': (0x180153, 0x186341, False, 'with Helmasaur King'), - "Ganons Tower - Bob's Torch": (0x180161, 0x186363, False, "in Ganon's Tower"), - 'Ganons Tower - Hope Room - Left': (0xead9, 0x1862ad, False, "in Ganon's Tower"), - 'Ganons Tower - Hope Room - Right': (0xeadc, 0x1862b0, False, "in Ganon's Tower"), - 'Ganons Tower - Tile Room': (0xeae2, 0x1862b6, False, "in Ganon's Tower"), - 'Ganons Tower - Compass Room - Top Left': (0xeae5, 0x1862b9, False, "in Ganon's Tower"), - 'Ganons Tower - Compass Room - Top Right': (0xeae8, 0x1862bc, False, "in Ganon's Tower"), - 'Ganons Tower - Compass Room - Bottom Left': (0xeaeb, 0x1862bf, False, "in Ganon's Tower"), - 'Ganons Tower - Compass Room - Bottom Right': (0xeaee, 0x1862c2, False, "in Ganon's Tower"), - 'Ganons Tower - DMs Room - Top Left': (0xeab8, 0x18628c, False, "in Ganon's Tower"), - 'Ganons Tower - DMs Room - Top Right': (0xeabb, 0x18628f, False, "in Ganon's Tower"), - 'Ganons Tower - DMs Room - Bottom Left': (0xeabe, 0x186292, False, "in Ganon's Tower"), - 'Ganons Tower - DMs Room - Bottom Right': (0xeac1, 0x186295, False, "in Ganon's Tower"), - 'Ganons Tower - Map Chest': (0xead3, 0x1862a7, False, "in Ganon's Tower"), - 'Ganons Tower - Firesnake Room': (0xead0, 0x1862a4, False, "in Ganon's Tower"), - 'Ganons Tower - Randomizer Room - Top Left': (0xeac4, 0x186298, False, "in Ganon's Tower"), - 'Ganons Tower - Randomizer Room - Top Right': (0xeac7, 0x18629b, False, "in Ganon's Tower"), - 'Ganons Tower - Randomizer Room - Bottom Left': (0xeaca, 0x18629e, False, "in Ganon's Tower"), - 'Ganons Tower - Randomizer Room - Bottom Right': (0xeacd, 0x1862a1, False, "in Ganon's Tower"), - "Ganons Tower - Bob's Chest": (0xeadf, 0x1862b3, False, "in Ganon's Tower"), - 'Ganons Tower - Big Chest': (0xead6, 0x1862aa, False, "in Ganon's Tower"), - 'Ganons Tower - Big Key Room - Left': (0xeaf4, 0x1862c8, False, "in Ganon's Tower"), - 'Ganons Tower - Big Key Room - Right': (0xeaf7, 0x1862cb, False, "in Ganon's Tower"), - 'Ganons Tower - Big Key Chest': (0xeaf1, 0x1862c5, False, "in Ganon's Tower"), - 'Ganons Tower - Mini Helmasaur Room - Left': (0xeafd, 0x1862d1, False, "atop Ganon's Tower"), - 'Ganons Tower - Mini Helmasaur Room - Right': (0xeb00, 0x1862d4, False, "atop Ganon's Tower"), - 'Ganons Tower - Pre-Moldorm Chest': (0xeb03, 0x1862d7, False, "atop Ganon's Tower"), - 'Ganons Tower - Validation Chest': (0xeb06, 0x1862da, False, "atop Ganon's Tower"), - 'Ganon': (None, None, False, 'from me'), - 'Agahnim 1': (None, None, False, 'from Ganon\'s wizardry form'), - 'Agahnim 2': (None, None, False, 'from Ganon\'s wizardry form'), - 'Floodgate': (None, None, False, None), - 'Frog': (None, None, False, None), - 'Missing Smith': (None, None, False, None), - 'Dark Blacksmith Ruins': (None, None, False, None), - 'Eastern Palace - Prize': ([0x1209D, 0x53EF8, 0x53EF9, 0x180052, 0x18007C, 0xC6FE], None, True, 'Eastern Palace'), - 'Desert Palace - Prize': ([0x1209E, 0x53F1C, 0x53F1D, 0x180053, 0x180078, 0xC6FF], None, True, 'Desert Palace'), - 'Tower of Hera - Prize': ([0x120A5, 0x53F0A, 0x53F0B, 0x18005A, 0x18007A, 0xC706], None, True, 'Tower of Hera'), - 'Palace of Darkness - Prize': ([0x120A1, 0x53F00, 0x53F01, 0x180056, 0x18007D, 0xC702], None, True, 'Palace of Darkness'), - 'Swamp Palace - Prize': ([0x120A0, 0x53F6C, 0x53F6D, 0x180055, 0x180071, 0xC701], None, True, 'Swamp Palace'), - 'Thieves\' Town - Prize': ([0x120A6, 0x53F36, 0x53F37, 0x18005B, 0x180077, 0xC707], None, True, 'Thieves\' Town'), - 'Skull Woods - Prize': ([0x120A3, 0x53F12, 0x53F13, 0x180058, 0x18007B, 0xC704], None, True, 'Skull Woods'), - 'Ice Palace - Prize': ([0x120A4, 0x53F5A, 0x53F5B, 0x180059, 0x180073, 0xC705], None, True, 'Ice Palace'), - 'Misery Mire - Prize': ([0x120A2, 0x53F48, 0x53F49, 0x180057, 0x180075, 0xC703], None, True, 'Misery Mire'), - 'Turtle Rock - Prize': ([0x120A7, 0x53F24, 0x53F25, 0x18005C, 0x180079, 0xC708], None, True, 'Turtle Rock'), - 'Kakariko Shop - Left': (None, None, False, 'for sale in Kakariko'), - 'Kakariko Shop - Middle': (None, None, False, 'for sale in Kakariko'), - 'Kakariko Shop - Right': (None, None, False, 'for sale in Kakariko'), - 'Lake Hylia Shop - Left': (None, None, False, 'for sale near the lake'), - 'Lake Hylia Shop - Middle': (None, None, False, 'for sale near the lake'), - 'Lake Hylia Shop - Right': (None, None, False, 'for sale near the lake'), - 'Paradox Shop - Left': (None, None, False, 'for sale near seven chests'), - 'Paradox Shop - Middle': (None, None, False, 'for sale near seven chests'), - 'Paradox Shop - Right': (None, None, False, 'for sale near seven chests'), - 'Capacity Upgrade - Left': (None, None, False, 'for sale near the queen'), - 'Capacity Upgrade - Right': (None, None, False, 'for sale near the queen'), - 'Village of Outcasts Shop - Left': (None, None, False, 'for sale near outcasts'), - 'Village of Outcasts Shop - Middle': (None, None, False, 'for sale near outcasts'), - 'Village of Outcasts Shop - Right': (None, None, False, 'for sale near outcasts'), - 'Dark Lumberjack Shop - Left': (None, None, False, 'for sale in the far north'), - 'Dark Lumberjack Shop - Middle': (None, None, False, 'for sale in the far north'), - 'Dark Lumberjack Shop - Right': (None, None, False, 'for sale in the far north'), - 'Dark Lake Hylia Shop - Left': (None, None, False, 'for sale near the dark lake'), - 'Dark Lake Hylia Shop - Middle': (None, None, False, 'for sale near the dark lake'), - 'Dark Lake Hylia Shop - Right': (None, None, False, 'for sale near the dark lake'), - 'Dark Potion Shop - Left': (None, None, False, 'for sale near a catfish'), - 'Dark Potion Shop - Middle': (None, None, False, 'for sale near a catfish'), - 'Dark Potion Shop - Right': (None, None, False, 'for sale near a catfish'), - 'Dark Death Mountain Shop - Left': (None, None, False, 'for sale on the dark mountain'), - 'Dark Death Mountain Shop - Middle': (None, None, False, 'for sale on the dark mountain'), - 'Dark Death Mountain Shop - Right': (None, None, False, 'for sale on the dark mountain'), - 'Red Shield Shop - Left': (None, None, False, 'for sale as a curiosity'), - 'Red Shield Shop - Middle': (None, None, False, 'for sale as a curiosity'), - 'Red Shield Shop - Right': (None, None, False, 'for sale as a curiosity'), - 'Potion Shop - Left': (None, None, False, 'for sale near the witch'), - 'Potion Shop - Middle': (None, None, False, 'for sale near the witch'), - 'Potion Shop - Right': (None, None, False, 'for sale near the witch'), - } diff --git a/Main.py b/Main.py index da28d6b3..63c24cae 100644 --- a/Main.py +++ b/Main.py @@ -14,8 +14,7 @@ from Items import ItemFactory from KeyDoorShuffle import validate_key_placement from OverworldGlitchRules import create_owg_connections from PotShuffle import shuffle_pots, shuffle_pot_switches -from Regions import create_regions, create_shops, mark_light_world_regions, create_dungeon_regions, adjust_locations -from InvertedRegions import create_inverted_regions, mark_dark_world_regions +from Regions import create_regions, create_shops, mark_light_dark_world_regions, create_dungeon_regions, adjust_locations from EntranceShuffle import link_entrances from Rom import patch_rom, patch_race_rom, patch_enemizer, apply_rom_settings, LocalRom, JsonRom, get_hash_string from Doors import create_doors @@ -176,10 +175,7 @@ def main(args, seed=None, fish=None): world.spoiler.mystery_meta_to_file(output_path(f'{outfilebase}_meta.txt')) for player in range(1, world.players + 1): - if world.mode[player] != 'inverted': - create_regions(world, player) - else: - create_inverted_regions(world, player) + create_regions(world, player) if world.logic[player] in ('owglitches', 'nologic'): create_owg_connections(world, player) create_dungeon_regions(world, player) @@ -238,10 +234,7 @@ def main(args, seed=None, fish=None): for player in range(1, world.players + 1): link_doors(world, player) - if world.mode[player] != 'inverted': - mark_light_world_regions(world, player) - else: - mark_dark_world_regions(world, player) + mark_light_dark_world_regions(world, player) if args.print_custom_yaml: world.settings.record_doors(world) logger.info(world.fish.translate("cli", "cli", "generating.itempool")) @@ -254,6 +247,7 @@ def main(args, seed=None, fish=None): for player in range(1, world.players + 1): set_rules(world, player) + reg = world.get_region('Dark Desert', 1) district_item_pool_config(world) for player in range(1, world.players + 1): if world.shopsanity[player]: @@ -490,10 +484,7 @@ def copy_world(world): ret.restrict_boss_items = world.restrict_boss_items.copy() for player in range(1, world.players + 1): - if world.mode[player] != 'inverted': - create_regions(ret, player) - else: - create_inverted_regions(ret, player) + create_regions(ret, player) create_dungeon_regions(ret, player) create_shops(ret, player) create_rooms(ret, player) diff --git a/OverworldGlitchRules.py b/OverworldGlitchRules.py index 27ce257e..2268246e 100644 --- a/OverworldGlitchRules.py +++ b/OverworldGlitchRules.py @@ -134,26 +134,26 @@ def get_boots_clip_exits_lw(inverted = False): Special Light World region exits that require boots clips. """ - yield ('Bat Cave River Clip Spot', 'Light World', 'Bat Cave Drop Ledge') - yield ('Light World DMA Clip Spot', 'Light World', 'Death Mountain') - yield ('Hera Ascent', 'Death Mountain', 'Death Mountain (Top)') + yield ('Bat Cave River Clip Spot', 'Light World', 'Bat Cave Ledge') + yield ('Light World DMA Clip Spot', 'Light World', 'Death Mountain (West Bottom)') + yield ('Hera Ascent', 'Death Mountain (West Bottom)', 'Death Mountain (Top)') yield ('Death Mountain Return Ledge Clip Spot', 'Light World', 'Death Mountain Return Ledge') yield ('Death Mountain Entrance Clip Spot', 'Light World', 'Death Mountain Entrance') - yield ('Death Mountain Glitched Bridge', 'Death Mountain', 'East Death Mountain (Top)') - yield ('Zora Descent Clip Spot', 'East Death Mountain (Top)', 'Zoras River') + yield ('Death Mountain Glitched Bridge', 'Death Mountain (West Bottom)', 'East Death Mountain (Top)') + yield ('Zora Descent Clip Spot', 'East Death Mountain (Top)', 'Zoras Domain') yield ('Desert Northern Cliffs', 'Light World', 'Desert Northern Cliffs') yield ('Desert Ledge Dropdown', 'Desert Northern Cliffs', 'Desert Ledge') yield ('Desert Palace Entrance Dropdown', 'Desert Northern Cliffs', 'Desert Palace Entrance (North) Spot') yield ('Lake Hylia Island Clip Spot', 'Light World', 'Lake Hylia Island') - yield ('Death Mountain Descent', 'Death Mountain', 'Light World') - yield ('Kings Grave Clip Spot', 'Death Mountain', 'Kings Grave Area') + yield ('Death Mountain Descent', 'Death Mountain (West Bottom)', 'Light World') + yield ('Kings Grave Clip Spot', 'Death Mountain (West Bottom)', 'Kings Grave Area') if not inverted: - yield ('Graveyard Ledge Clip Spot', 'Death Mountain', 'Graveyard Ledge') - yield ('Desert Ledge (Northeast) Dropdown', 'Desert Northern Cliffs', 'Desert Ledge (Northeast)') + yield ('Graveyard Ledge Clip Spot', 'Death Mountain (West Bottom)', 'Graveyard Ledge') + yield ('Desert Ledge (Northeast) Dropdown', 'Desert Northern Cliffs', 'Desert Checkerboard Ledge') yield ('Spectacle Rock Clip Spot', 'Death Mountain (Top)', 'Spectacle Rock') yield ('Bombos Tablet Clip Spot', 'Light World', 'Bombos Tablet Ledge') - yield ('Floating Island Clip Spot', 'East Death Mountain (Top)', 'Death Mountain Floating Island (Light World)') + yield ('Floating Island Clip Spot', 'East Death Mountain (Top)', 'Death Mountain Floating Island') yield ('Cave 45 Clip Spot', 'Light World', 'Cave 45 Ledge') @@ -162,12 +162,12 @@ def get_boots_clip_exits_dw(inverted): Special Dark World region exits that require boots clips. """ - yield ('Dark World DMA Clip Spot', 'West Dark World', inverted and 'Dark Death Mountain' or 'Dark Death Mountain (West Bottom)') + yield ('Dark World DMA Clip Spot', 'West Dark World', 'Dark Death Mountain (West Bottom)') yield ('Bumper Cave Ledge Clip Spot', 'West Dark World', 'Bumper Cave Ledge') yield ('Bumper Cave Entrance Clip Spot', 'West Dark World', 'Bumper Cave Entrance') - yield ('Catfish Descent', inverted and 'Dark Death Mountain' or 'Dark Death Mountain (Top)', 'Catfish') + yield ('Catfish Descent', 'Dark Death Mountain (Top)', 'Catfish Area') yield ('Hammer Pegs River Clip Spot', 'East Dark World', 'Hammer Peg Area') - yield ('Dark Lake Hylia Ledge Clip Spot', 'East Dark World', 'Dark Lake Hylia Ledge') + yield ('Dark Lake Hylia Ledge Clip Spot', 'East Dark World', 'Southeast Dark World') yield ('Dark Desert Cliffs Clip Spot', 'South Dark World', 'Dark Desert') yield ('DW Floating Island Clip Spot', 'Dark Death Mountain (East Bottom)', 'Death Mountain Floating Island (Dark World)') @@ -184,17 +184,16 @@ def get_glitched_speed_drops_dw(inverted = False): """ Dark World drop-down ledges that require glitched speed. """ - yield ('Dark Death Mountain Ledge Clip Spot', inverted and 'Dark Death Mountain' or 'Dark Death Mountain (Top)', 'Dark Death Mountain Ledge') + yield ('Dark Death Mountain Ledge Clip Spot', 'Dark Death Mountain (Top)', 'Dark Death Mountain Ledge') def get_mirror_clip_spots_dw(): """ Out of bounds transitions using the mirror """ - yield ('Dark Death Mountain Bunny Descent Mirror Spot', 'Dark Death Mountain (West Bottom)', 'Dark Death Mountain Bunny Descent Area') - yield ('West Dark World Bunny Descent', 'Dark Death Mountain Bunny Descent Area', 'West Dark World') - yield ('Dark Death Mountain (East Bottom) Jump', 'Dark Death Mountain Bunny Descent Area', 'Dark Death Mountain (East Bottom)') - yield ('Desert East Mirror Clip', 'Dark Desert', 'Desert Palace Lone Stairs') + yield ('Dark Death Mountain Bunny Descent Mirror Spot', 'Dark Death Mountain (West Bottom)', 'West Dark World') + yield ('Dark Death Mountain Bunny Mirror To East Jump', 'Dark Death Mountain (West Bottom)', 'Dark Death Mountain (East Bottom)') + yield ('Desert East Mirror Clip', 'Dark Desert', 'Desert Palace Mouth') def get_mirror_offset_spots_dw(): @@ -208,8 +207,8 @@ def get_mirror_offset_spots_lw(player): """ Mirror shenanigans placing a mirror portal with a broken camera """ - yield ('Death Mountain Offset Mirror', 'Death Mountain', 'Light World') - yield ('Death Mountain Offset Mirror (Houlihan Exit)', 'Death Mountain', 'Hyrule Castle Ledge', lambda state: state.has_Mirror(player) and state.can_boots_clip_dw(player) and state.has_Pearl(player)) + yield ('Death Mountain Offset Mirror', 'Death Mountain (West Bottom)', 'Light World') + yield ('Death Mountain Offset Mirror (Houlihan Exit)', 'Death Mountain (West Bottom)', 'Hyrule Castle Ledge', lambda state: state.has_Mirror(player) and state.can_boots_clip_dw(player) and state.has_Pearl(player)) def create_owg_connections(world, player): @@ -251,16 +250,14 @@ def overworld_glitches_rules(world, player): # Regions that require the boots and some other stuff. if world.mode[player] != 'inverted': world.get_entrance('Turtle Rock Teleporter', player).access_rule = lambda state: (state.can_boots_clip_lw(player) or state.can_lift_heavy_rocks(player)) and state.has('Hammer', player) - add_alternate_rule(world.get_entrance('Waterfall of Wishing', player), lambda state: state.has('Moon Pearl', player) or state.has_Boots(player)) + add_alternate_rule(world.get_entrance('Waterfall Fairy Access', player), lambda state: state.has_Pearl(player) or state.has_Boots(player)) # assumes access to Waterwalk ability (boots case) else: - add_alternate_rule(world.get_entrance('Waterfall of Wishing Cave', player), lambda state: state.has('Moon Pearl', player)) + add_alternate_rule(world.get_entrance('Waterfall Fairy Access', player), lambda state: state.has_Pearl(player)) - world.get_entrance('Dark Desert Teleporter', player).access_rule = lambda state: (state.can_flute(player) or state.has_Boots(player)) and state.can_lift_heavy_rocks(player) - add_alternate_rule(world.get_entrance('Catfish Exit Rock', player), lambda state: state.can_boots_clip_dw(player)) + world.get_entrance('Dark Desert Teleporter', player).access_rule = lambda state: (state.can_flute(player) or state.can_boots_clip_dw(player)) and state.can_lift_heavy_rocks(player) + add_alternate_rule(world.get_entrance('Dark Witch Rock (North)', player), lambda state: state.can_boots_clip_dw(player)) add_alternate_rule(world.get_entrance('East Dark World Broken Bridge Pass', player), lambda state: state.can_boots_clip_dw(player)) - - # Zora's Ledge via waterwalk setup. - add_alternate_rule(world.get_location('Zora\'s Ledge', player), lambda state: state.has_Boots(player)) + add_alternate_rule(world.get_location('Zora\'s Ledge', player), lambda state: state.can_boots_clip_lw(player)) # assumes access to Waterwalk ability def add_alternate_rule(entrance, rule): diff --git a/Regions.py b/Regions.py index f293e220..b98465ca 100644 --- a/Regions.py +++ b/Regions.py @@ -7,18 +7,24 @@ from PotShuffle import key_drop_data, vanilla_pots, choose_pots, PotSecretTable def create_regions(world, player): world.regions += [ create_menu_region(player, 'Menu', None, ['Links House S&Q', 'Sanctuary S&Q', 'Old Man S&Q', 'Other World S&Q']), + create_menu_region(player, 'Flute Sky', None, ['Flute Spot 1', 'Flute Spot 2', 'Flute Spot 3', 'Flute Spot 4', 'Flute Spot 5', 'Flute Spot 6', 'Flute Spot 7', 'Flute Spot 8']), create_lw_region(player, 'Light World', ['Mushroom', 'Bottle Merchant', 'Flute Spot', 'Sunken Treasure', 'Purple Chest'], - ["Blinds Hideout", "Hyrule Castle Secret Entrance Drop", 'Zoras River', 'Kings Grave Outer Rocks', 'Dam', + ['Blinds Hideout', 'Hyrule Castle Secret Entrance Drop', 'Kings Grave Outer Rocks', 'Dam', 'Links House', 'Tavern North', 'Chicken House', 'Aginahs Cave', 'Sahasrahlas Hut', 'Kakariko Well Drop', 'Kakariko Well Cave', - 'Blacksmiths Hut', 'Bat Cave Drop Ledge', 'Bat Cave Cave', 'Sick Kids House', 'Hobo Bridge', 'Lost Woods Hideout Drop', 'Lost Woods Hideout Stump', - 'Lumberjack Tree Tree', 'Lumberjack Tree Cave', 'Mini Moldorm Cave', 'Ice Rod Cave', 'Lake Hylia Central Island Pier', - 'Bonk Rock Cave', 'Library', 'Potion Shop', 'Two Brothers House (East)', 'Desert Palace Stairs', 'Eastern Palace', 'Master Sword Meadow', - 'Sanctuary', 'Sanctuary Grave', 'Death Mountain Entrance Rock', 'Flute Spot 1', 'Dark Desert Teleporter', 'East Hyrule Teleporter', 'South Hyrule Teleporter', 'Kakariko Teleporter', + 'Blacksmiths Hut', 'Bat Cave Ledge Peg', 'Bat Cave Cave', 'Sick Kids House', 'Lost Woods Hideout Drop', 'Lost Woods Hideout Stump', + 'Lumberjack Tree Tree', 'Lumberjack Tree Cave', 'Mini Moldorm Cave', 'Ice Rod Cave', + 'Bonk Rock Cave', 'Library', 'Two Brothers House (East)', 'Desert Statue Move', 'Eastern Palace', 'Master Sword Meadow', + 'Sanctuary', 'Sanctuary Grave', 'Death Mountain Entrance Rock', 'Light World Water Drop', 'LW Flute', 'East Hyrule Teleporter', 'South Hyrule Teleporter', 'Kakariko Teleporter', 'Elder House (East)', 'Elder House (West)', 'North Fairy Cave', 'North Fairy Cave Drop', 'Lost Woods Gamble', 'Snitch Lady (East)', 'Snitch Lady (West)', 'Tavern (Front)', - 'Bush Covered House', 'Light World Bomb Hut', 'Kakariko Shop', 'Long Fairy Cave', 'Good Bee Cave', '20 Rupee Cave', 'Cave Shop (Lake Hylia)', 'Zora Waterfall Entryway', 'Hyrule Castle Main Gate', - 'Bonk Fairy (Light)', '50 Rupee Cave', 'Fortune Teller (Light)', 'Lake Hylia Fairy', 'Light Hype Fairy', 'Desert Fairy', 'Lumberjack House', 'Lake Hylia Fortune Teller', 'Kakariko Gamble Game', 'Top of Pyramid']), + 'Kakariko Shop', 'Long Fairy Cave', 'Good Bee Cave', '20 Rupee Cave', 'Cave Shop (Lake Hylia)', 'Hyrule Castle Main Gate', + 'Bonk Fairy (Light)', '50 Rupee Cave', 'Fortune Teller (Light)', 'Lake Hylia Fairy', 'Light Hype Fairy', 'Desert Fairy', 'Lumberjack House', 'Lake Hylia Fortune Teller', 'Kakariko Gamble Game', 'Top of Pyramid', + 'East Dark World Mirror Spot', 'West Dark World Mirror Spot', 'South Dark World Mirror Spot', 'Cave 45 Approach', 'Checkerboard Ledge Approach', 'Mire Mirror Spot', 'Hammer Peg Area Mirror Spot', + 'Shopping Mall Mirror Spot', 'Skull Woods Mirror Spot', 'Kakariko Yard Bush (South)', 'Bombos Tablet Ladder (Bottom)', + 'Wooden Bridge Bush (South)', 'Graveyard Ladder (Bottom)', 'Kakariko Southwest Bush (North)']), + create_lw_region(player, 'Bush Covered Lawn', None, ['Bush Covered House', 'Kakariko Yard Bush (North)', 'Bush Covered Lawn Mirror Spot']), + create_lw_region(player, 'Bomb Hut Area', None, ['Light World Bomb Hut', 'Kakariko Southwest Bush (South)', 'Bomb Hut Mirror Spot']), create_lw_region(player, 'Death Mountain Entrance', None, ['Old Man Cave (West)', 'Death Mountain Entrance Drop']), - create_lw_region(player, 'Lake Hylia Central Island', None, ['Capacity Upgrade', 'Lake Hylia Central Island Teleporter']), + create_lw_region(player, 'Lake Hylia Central Island', None, ['Capacity Upgrade', 'Lake Hylia Central Island Water Drop', 'Lake Hylia Central Island Teleporter']), create_cave_region(player, 'Blinds Hideout', 'a bounty of five items', [ "Blind's Hideout - Left", "Blind's Hideout - Right", @@ -26,9 +32,12 @@ def create_regions(world, player): "Blind's Hideout - Far Right"], ['Blinds Hideout N']), create_cave_region(player, 'Blinds Hideout (Top)', 'a bounty of five items', ["Blind's Hideout - Top"]), + create_lw_region(player, 'Northeast Light World', None, ['Zoras Domain', 'Potion Shop Rock (North)', 'Catfish Mirror Spot', 'Northeast Light World Water Drop']), + create_lw_region(player, 'Potion Shop Area', None, ['Potion Shop', 'Wooden Bridge Bush (North)', 'Potion Shop Rock (South)', 'NWLW Flute', 'Potion Shop Mirror Spot', 'Potion Shop Water Drop']), + create_lw_region(player, 'Lake Hylia Water', None, ['Hobo Pier', 'Light World Pier', 'Potion Shop Pier', 'Lake Hylia Central Island Pier', 'Lake Hylia Island Pier', 'Lake Hylia Whirlpool', 'Waterfall Fairy Access']), create_cave_region(player, 'Hyrule Castle Secret Entrance', 'a drop\'s exit', ['Link\'s Uncle', 'Secret Passage'], ['Hyrule Castle Secret Entrance Exit']), - create_lw_region(player, 'Zoras River', ['King Zora', 'Zora\'s Ledge']), - create_lw_region(player, 'Zora Waterfall Entryway', None, ['Waterfall of Wishing', 'Zora Waterfall Water Drop']), + create_lw_region(player, 'Zoras Domain', ['King Zora', 'Zora\'s Ledge']), + create_lw_region(player, 'Zora Waterfall Entryway', None, ['Waterfall of Wishing', 'ZLW Flute', 'Zora Waterfall Water Drop']), create_cave_region(player, 'Waterfall of Wishing', 'a cave with two chests', ['Waterfall Fairy - Left', 'Waterfall Fairy - Right']), create_lw_region(player, 'Kings Grave Area', None, ['Kings Grave', 'Kings Grave Inner Rocks']), create_cave_region(player, 'Kings Grave', 'a cave with a chest', ['King\'s Tomb']), @@ -66,7 +75,7 @@ def create_regions(world, player): create_cave_region(player, 'Kakariko Well (back)', 'a drop', ['Kakariko Well - Top']), create_cave_region(player, 'Kakariko Well (bottom)', 'a drop\'s exit', None, ['Kakariko Well Exit']), create_cave_region(player, 'Blacksmiths Hut', 'the smith', ['Blacksmith', 'Missing Smith']), - create_lw_region(player, 'Bat Cave Drop Ledge', None, ['Bat Cave Drop']), + create_lw_region(player, 'Bat Cave Ledge', None, ['Bat Cave Drop', 'Bat Cave Ledge Peg (East)']), create_cave_region(player, 'Bat Cave (right)', 'a drop', ['Magic Bat'], ['Bat Cave Door']), create_cave_region(player, 'Bat Cave (left)', 'a drop\'s exit', None, ['Bat Cave Exit']), create_cave_region(player, 'Sick Kids House', 'the sick kid', ['Sick Kid']), @@ -75,9 +84,9 @@ def create_regions(world, player): create_cave_region(player, 'Lost Woods Hideout (bottom)', 'a drop\'s exit', None, ['Lost Woods Hideout Exit']), create_cave_region(player, 'Lumberjack Tree (top)', 'a drop\'s exit', ['Lumberjack Tree'], ['Lumberjack Tree (top to bottom)']), create_cave_region(player, 'Lumberjack Tree (bottom)', 'a drop\'s exit', None, ['Lumberjack Tree Exit']), - create_lw_region(player, 'Cave 45 Ledge', None, ['Cave 45', 'Cave 45 Ledge Drop']), + create_lw_region(player, 'Cave 45 Ledge', None, ['Cave 45', 'Cave 45 Ledge Drop', 'Cave 45 Leave']), create_cave_region(player, 'Cave 45', 'a cave with an item', ['Cave 45']), - create_lw_region(player, 'Graveyard Ledge', None, ['Graveyard Cave', 'Graveyard Ledge Drop']), + create_lw_region(player, 'Graveyard Ledge', None, ['Graveyard Cave', 'Graveyard Ledge Drop', 'Graveyard Ladder (Top)', 'Graveyard Cave Mirror Spot']), create_cave_region(player, 'Graveyard Cave', 'a cave with an item', ['Graveyard Cave']), create_cave_region(player, 'Checkerboard Cave', 'a cave with an item', ['Checkerboard Cave']), create_cave_region(player, 'Long Fairy Cave', 'a fairy fountain'), @@ -95,79 +104,83 @@ def create_regions(world, player): create_lw_region(player, 'Lake Hylia Island', ['Lake Hylia Island']), create_cave_region(player, 'Capacity Upgrade', 'the queen of fairies', ['Capacity Upgrade - Left', 'Capacity Upgrade - Right']), create_cave_region(player, 'Two Brothers House', 'a connector', None, ['Two Brothers House Exit (East)', 'Two Brothers House Exit (West)']), - create_lw_region(player, 'Maze Race Ledge', ['Maze Race'], ['Two Brothers House (West)', 'Maze Race Ledge Drop'], 'a race against time'), + create_lw_region(player, 'Maze Race Ledge', ['Maze Race'], ['Two Brothers House (West)', 'Maze Race Mirror Spot', 'Maze Race Ledge Drop'], 'a race against time'), create_cave_region(player, '50 Rupee Cave', 'a cave with some cash'), create_lw_region(player, 'Desert Ledge', ['Desert Ledge'], ['Desert Palace Entrance (North) Rocks', 'Desert Palace Entrance (West)', 'Desert Ledge Drop'], 'the desert ledge'), - create_lw_region(player, 'Desert Ledge (Northeast)', None, ['Checkerboard Cave', 'Checkerboard Ledge Drop']), - create_lw_region(player, 'Desert Palace Stairs', None, ['Desert Palace Entrance (South)']), - create_lw_region(player, 'Desert Palace Lone Stairs', None, ['Desert Palace Stairs Drop', 'Desert Palace Entrance (East)'], 'a sandy vista'), - create_lw_region(player, 'Desert Palace Entrance (North) Spot', None, ['Desert Palace Entrance (North)', 'Desert Ledge Return Rocks'], 'the desert ledge'), + create_lw_region(player, 'Desert Checkerboard Ledge', None, ['Checkerboard Cave', 'Checkerboard Ledge Drop', 'Checkerboard Ledge Leave']), + create_lw_region(player, 'Desert Palace Stairs', None, ['Desert Palace Entrance (South)', 'Desert Palace Stairs Mirror Spot']), + create_lw_region(player, 'Desert Palace Mouth', None, ['Desert Palace Stairs Drop', 'Desert Palace Entrance (East)'], 'a sandy vista'), + create_lw_region(player, 'Desert Palace Entrance (North) Spot', None, ['Desert Palace Entrance (North)', 'Desert Ledge Return Rocks', 'Desert Palace North Mirror Spot'], 'the desert ledge'), + create_lw_region(player, 'Desert Teleporter Ledge', None, ['Desert Teleporter Drop', 'Desert Teleporter']), create_lw_region(player, 'Master Sword Meadow', ['Master Sword Pedestal']), create_cave_region(player, 'Lost Woods Gamble', 'a game of chance'), - create_lw_region(player, 'Hyrule Castle Courtyard', None, ['Hyrule Castle Secret Entrance Stairs', 'Hyrule Castle Entrance (South)', 'Hyrule Castle Main Gate (North)']), - create_lw_region(player, 'Hyrule Castle Ledge', None, ['Hyrule Castle Entrance (East)', 'Hyrule Castle Entrance (West)', 'Agahnims Tower', 'Hyrule Castle Ledge Courtyard Drop', 'Hyrule Castle Ledge Drop'], 'the castle rampart'), - create_dungeon_region(player, 'Sewer Drop', 'a drop\'s exit', None, ['Sewer Drop']), # This exists only to be referenced for access checks + create_lw_region(player, 'Hyrule Castle Courtyard', None, ['Hyrule Castle Entrance (South)', 'Inverted Pyramid Entrance', 'Hyrule Castle Courtyard Bush (South)', 'Hyrule Castle Main Gate (North)']), + create_lw_region(player, 'Hyrule Castle Ledge', None, ['Hyrule Castle Entrance (East)', 'Hyrule Castle Entrance (West)', 'Agahnims Tower', 'Hyrule Castle Ledge Courtyard Drop', 'Hyrule Castle Ledge Drop', 'Inverted Pyramid Hole'], 'the castle rampart'), + create_lw_region(player, 'Hyrule Castle Secret Entrance Area', None, ['Hyrule Castle Secret Entrance Stairs', 'Hyrule Castle Courtyard Bush (North)', 'Pyramid Uncle Mirror Spot']), + create_dungeon_region(player, 'Sewer Drop', 'a drop\'s exit', None, ['Sewer Drop']), # This exists only to be referenced for access checks create_cave_region(player, 'Old Man Cave', 'a connector', ['Old Man'], ['Old Man Cave Exit (East)']), create_cave_region(player, 'Old Man Cave Ledge', 'a connector', None, ['Old Man Cave Exit (West)', 'Old Man Cave Dropdown']), create_cave_region(player, 'Old Man House', 'a connector', None, ['Old Man House Exit (Bottom)', 'Old Man House Front to Back']), create_cave_region(player, 'Old Man House Back', 'a connector', None, ['Old Man House Exit (Top)', 'Old Man House Back to Front']), - create_lw_region(player, 'Death Mountain', None, ['Old Man Cave (East)', 'Old Man House (Bottom)', 'Old Man House (Top)', 'Death Mountain Return Cave (East)', 'Spectacle Rock Cave', 'Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Bottom)', 'Broken Bridge (West)', 'Death Mountain Teleporter']), + create_lw_region(player, 'Death Mountain (West Bottom)', None, ['Old Man Cave (East)', 'Old Man House (Bottom)', 'Old Man House (Top)', 'Death Mountain Return Cave (East)', 'Spectacle Rock Cave', + 'Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Bottom)', 'DM Broken Bridge (West)', 'Death Mountain Mirror Spot', 'DM Flute', 'Death Mountain Teleporter']), create_cave_region(player, 'Death Mountain Return Cave (left)', 'a connector', None, ['Death Mountain Return Cave Exit (West)', 'Death Mountain Return Cave E']), create_cave_region(player, 'Death Mountain Return Cave (right)', 'a connector', None, ['Death Mountain Return Cave Exit (East)', 'Death Mountain Return Cave W']), - create_lw_region(player, 'Death Mountain Return Ledge', None, ['Death Mountain Return Ledge Drop', 'Death Mountain Return Cave (West)'], 'a ledge in the foothills'), + create_lw_region(player, 'Death Mountain Return Ledge', None, ['Death Mountain Return Ledge Drop', 'Death Mountain Return Cave (West)', 'Mountain Exit Ledge Mirror Spot'], 'a ledge in the foothills'), create_cave_region(player, 'Spectacle Rock Cave (Top)', 'a connector', ['Spectacle Rock Cave'], ['Spectacle Rock Cave Drop', 'Spectacle Rock Cave Exit (Top)']), create_cave_region(player, 'Spectacle Rock Cave (Bottom)', 'a connector', None, ['Spectacle Rock Cave Exit']), create_cave_region(player, 'Spectacle Rock Cave (Peak)', 'a connector', None, ['Spectacle Rock Cave Peak Drop', 'Spectacle Rock Cave Exit (Peak)']), - create_lw_region(player, 'East Death Mountain (Bottom)', None, ['Broken Bridge (East)', 'Paradox Cave (Bottom)', 'Paradox Cave (Middle)', 'East Death Mountain Teleporter', 'Hookshot Fairy', 'Fairy Ascension Rocks', 'Spiral Cave (Bottom)']), + create_lw_region(player, 'East Death Mountain (Bottom)', None, ['DM Broken Bridge (East)', 'Paradox Cave (Bottom)', 'Paradox Cave (Middle)', 'East Death Mountain Mirror Spot (Bottom)', 'East Death Mountain Teleporter', 'Hookshot Fairy', + 'Fairy Ascension Rocks', 'Spiral Cave (Bottom)', 'EDM Flute']), create_cave_region(player, 'Hookshot Fairy', 'fairies deep in a cave'), create_cave_region(player, 'Paradox Cave Front', 'a connector', None, ['Paradox Cave Push Block Reverse', 'Paradox Cave Exit (Bottom)', 'Light World Death Mountain Shop']), create_cave_region(player, 'Paradox Cave Chest Area', 'a connector', ['Paradox Cave Lower - Far Left', 'Paradox Cave Lower - Left', 'Paradox Cave Lower - Right', 'Paradox Cave Lower - Far Right', - 'Paradox Cave Lower - Middle', - ], + 'Paradox Cave Lower - Middle'], ['Paradox Cave Push Block', 'Paradox Cave Bomb Jump', 'Paradox Cave Chest Area NE']), create_cave_region(player, 'Paradox Cave Bomb Area', 'a connector', ['Paradox Cave Upper - Left', 'Paradox Cave Upper - Right']), create_cave_region(player, 'Paradox Cave', 'a connector', None, ['Paradox Cave Exit (Middle)', 'Paradox Cave Exit (Top)', 'Paradox Cave Drop']), create_cave_region(player, 'Light World Death Mountain Shop', 'a common shop', ['Paradox Shop - Left', 'Paradox Shop - Middle', 'Paradox Shop - Right']), - create_lw_region(player, 'East Death Mountain (Top)', None, ['Paradox Cave (Top)', 'Death Mountain (Top)', 'Spiral Cave Ledge Access', 'East Death Mountain Drop', 'Turtle Rock Teleporter', 'Fairy Ascension Ledge']), - create_lw_region(player, 'Spiral Cave Ledge', None, ['Spiral Cave', 'Spiral Cave Ledge Drop']), + create_lw_region(player, 'East Death Mountain (Top)', None, ['Paradox Cave (Top)', 'DM Hammer Bridge (East)', 'Floating Island Bridge (East)', 'Spiral Cave Ledge Access', 'East Death Mountain Drop', 'Turtle Rock Teleporter', 'East Death Mountain Mirror Spot (Top)', 'Fairy Ascension Ledge Access', 'Mimic Cave Ledge Access']), + create_lw_region(player, 'Spiral Cave Ledge', None, ['Spiral Cave', 'Spiral Cave Ledge Drop', 'Dark Death Mountain Ledge Mirror Spot (West)']), create_cave_region(player, 'Spiral Cave (Top)', 'a connector', ['Spiral Cave'], ['Spiral Cave (top to bottom)', 'Spiral Cave Exit (Top)']), create_cave_region(player, 'Spiral Cave (Bottom)', 'a connector', None, ['Spiral Cave Exit']), create_lw_region(player, 'Fairy Ascension Plateau', None, ['Fairy Ascension Drop', 'Fairy Ascension Cave (Bottom)']), create_cave_region(player, 'Fairy Ascension Cave (Bottom)', 'a connector', None, ['Fairy Ascension Cave Climb', 'Fairy Ascension Cave Exit (Bottom)']), create_cave_region(player, 'Fairy Ascension Cave (Drop)', 'a connector', None, ['Fairy Ascension Cave Pots']), create_cave_region(player, 'Fairy Ascension Cave (Top)', 'a connector', None, ['Fairy Ascension Cave Exit (Top)', 'Fairy Ascension Cave Drop']), - create_lw_region(player, 'Fairy Ascension Ledge', None, ['Fairy Ascension Ledge Drop', 'Fairy Ascension Cave (Top)']), - create_lw_region(player, 'Death Mountain (Top)', ['Ether Tablet'], ['East Death Mountain (Top)', 'Tower of Hera', 'Death Mountain Drop']), - create_lw_region(player, 'Spectacle Rock', ['Spectacle Rock'], ['Spectacle Rock Drop']), + create_lw_region(player, 'Fairy Ascension Ledge', None, ['Fairy Ascension Ledge Drop', 'Fairy Ascension Cave (Top)', 'Laser Bridge Mirror Spot']), + create_lw_region(player, 'Death Mountain (Top)', ['Ether Tablet'], ['DM Hammer Bridge (West)', 'Tower of Hera', 'Death Mountain Drop', 'Spectacle Rock Approach', 'Death Mountain (Top) Mirror Spot']), + create_lw_region(player, 'Spectacle Rock', ['Spectacle Rock'], ['Spectacle Rock Drop', 'Spectacle Rock Leave']), - create_dw_region(player, 'East Dark World', ['Pyramid'], ['Pyramid Fairy', 'South Dark World Bridge', 'Palace of Darkness', 'Dark Lake Hylia Drop (East)', - 'Hyrule Castle Ledge Mirror Spot', 'Dark Lake Hylia Fairy', 'Palace of Darkness Hint', 'East Dark World Hint', 'Pyramid Hole', 'Northeast Dark World Broken Bridge Pass',]), - create_dw_region(player, 'Catfish', ['Catfish'], ['Catfish Exit Rock']), - create_dw_region(player, 'Northeast Dark World', None, ['West Dark World Gap', 'Dark World Potion Shop', 'East Dark World Broken Bridge Pass', 'Catfish Entrance Rock', 'Dark Lake Hylia Teleporter']), + create_dw_region(player, 'East Dark World', ['Pyramid'], ['Pyramid Fairy', 'Hammer Bridge Pegs (North)', 'Palace of Darkness', 'East Dark World Water Drop', + 'Hyrule Castle Ledge Mirror Spot', 'Dark Lake Hylia Fairy', 'Palace of Darkness Hint', 'East Dark World Hint', 'Pyramid Hole', 'Northeast Dark World Broken Bridge Pass', 'East Dark World Teleporter', 'EDW Flute']), + create_dw_region(player, 'Catfish Area', ['Catfish'], ['Dark Witch Rock (North)', 'Catfish Water Drop']), + create_dw_region(player, 'Northeast Dark World', None, ['West Dark World Gap', 'Dark World Potion Shop', 'East Dark World Broken Bridge Pass', 'Northeast Dark World Water Drop', 'Dark Witch Rock (South)', 'NEDW Flute']), create_cave_region(player, 'Palace of Darkness Hint', 'a storyteller'), create_cave_region(player, 'East Dark World Hint', 'a storyteller'), - create_dw_region(player, 'South Dark World', ['Stumpy', 'Digging Game'], ['Dark Lake Hylia Drop (South)', 'Hype Cave', 'Swamp Palace', 'Village of Outcasts Heavy Rock', 'Maze Race Mirror Spot', - 'Cave 45 Mirror Spot', 'East Dark World Bridge', 'Big Bomb Shop', 'Archery Game', 'Bonk Fairy (Dark)', 'Dark Lake Hylia Shop', - 'Bombos Tablet Mirror Spot']), - create_lw_region(player, 'Bombos Tablet Ledge', ['Bombos Tablet']), + create_dw_region(player, 'South Dark World', ['Stumpy', 'Digging Game'], ['Hype Cave', 'Swamp Palace', 'Village of Outcasts Heavy Rock', 'Dig Game Mirror Spot', + 'Cave 45 Mirror Spot', 'Hammer Bridge Pegs (South)', 'Big Bomb Shop', 'Archery Game', 'Bonk Fairy (Dark)', 'Dark Lake Hylia Shop', + 'Bombos Tablet Mirror Spot', 'South Dark World Water Drop', 'South Dark World Teleporter', 'Post Aga Teleporter', 'SDW Flute']), + create_lw_region(player, 'Bombos Tablet Ledge', ['Bombos Tablet'], ['Bombos Tablet Ladder (Top)']), create_cave_region(player, 'Big Bomb Shop', 'the bomb shop'), create_cave_region(player, 'Archery Game', 'a game of skill'), - create_dw_region(player, 'Dark Lake Hylia', None, ['Lake Hylia Island Mirror Spot', 'East Dark World Pier', 'Dark Lake Hylia Ledge']), - create_dw_region(player, 'Dark Lake Hylia Central Island', None, ['Ice Palace', 'Lake Hylia Central Island Mirror Spot']), - create_dw_region(player, 'Dark Lake Hylia Ledge', None, ['Dark Lake Hylia Ledge Drop', 'Dark Lake Hylia Ledge Fairy', 'Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Ledge Spike Cave']), + create_dw_region(player, 'Dark Lake Hylia Water', None, ['Lake Hylia Island Mirror Spot', 'Northeast Dark World River Pier', 'East Dark World Pier', 'Southeast Dark World Pier', 'Ice Palace Approach']), + create_dw_region(player, 'Dark Lake Hylia Central Island', None, ['Ice Palace Leave Water Drop', 'Ice Island To East Pier', 'Ice Palace', 'Lake Hylia Central Island Mirror Spot', 'Dark Lake Hylia Central Island Teleporter']), + create_dw_region(player, 'Southeast Dark World', None, ['Southeast Dark World Water Drop', 'Dark Lake Hylia Ledge Fairy', 'Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Ledge Spike Cave', 'DLHL Flute']), create_cave_region(player, 'Dark Lake Hylia Ledge Hint', 'a storyteller'), create_cave_region(player, 'Dark Lake Hylia Ledge Spike Cave', 'a spiky hint'), create_cave_region(player, 'Hype Cave', 'a bounty of five items', ['Hype Cave - Top', 'Hype Cave - Middle Right', 'Hype Cave - Middle Left', 'Hype Cave - Bottom', 'Hype Cave - Generous Guy']), - create_dw_region(player, 'West Dark World', ['Frog'], ['Village of Outcasts Drop', 'East Dark World River Pier', 'Brewery', 'C-Shaped House', 'Chest Game', 'Thieves Town', 'Graveyard Ledge Mirror Spot', 'Kings Grave Mirror Spot', 'Bumper Cave Entrance Rock', - 'Skull Woods Forest', 'Village of Outcasts Pegs', 'Village of Outcasts Eastern Rocks', 'Red Shield Shop', 'Dark Sanctuary Hint', 'Fortune Teller (Dark)', 'Dark World Lumberjack Shop']), - create_dw_region(player, 'Dark Grassy Lawn', None, ['Grassy Lawn Pegs', 'Dark World Shop']), - create_dw_region(player, 'Hammer Peg Area', ['Dark Blacksmith Ruins'], ['Bat Cave Drop Ledge Mirror Spot', 'Dark World Hammer Peg Cave', 'Peg Area Rocks']), + create_dw_region(player, 'West Dark World', ['Frog'], ['Village of Outcasts Drop', 'West Dark World Water Drop', 'Brewery', 'C-Shaped House', 'Chest Game', 'Thieves Town', 'Graveyard Ledge Mirror Spot', 'Kings Grave Mirror Spot', 'Bumper Cave Entrance Rock', + 'Skull Woods Forest', 'Village of Outcasts Pegs', 'Village of Outcasts Eastern Rocks', 'Red Shield Shop', 'Dark Sanctuary Hint', 'Fortune Teller (Dark)', 'Dark World Lumberjack Shop', + 'West Dark World Teleporter', 'WDW Flute']), + create_dw_region(player, 'Dark Grassy Lawn', None, ['Grassy Lawn Pegs', 'Dark World Shop', 'Dark Grassy Lawn Mirror Spot', 'Dark Grassy Lawn Flute']), + create_dw_region(player, 'Hammer Peg Area', ['Dark Blacksmith Ruins'], ['Bat Cave Drop Ledge Mirror Spot', 'Dark World Hammer Peg Cave', 'Peg Area Rocks', 'Hammer Peg Area Flute']), create_dw_region(player, 'Bumper Cave Entrance', None, ['Bumper Cave (Bottom)', 'Bumper Cave Entrance Mirror Spot', 'Bumper Cave Entrance Drop']), create_cave_region(player, 'Fortune Teller (Dark)', 'a fortune teller'), create_cave_region(player, 'Village of Outcasts Shop', 'a common shop', ['Village of Outcasts Shop - Left', 'Village of Outcasts Shop - Middle', 'Village of Outcasts Shop - Right']), @@ -180,23 +193,24 @@ def create_regions(world, player): create_cave_region(player, 'C-Shaped House', 'a house with a chest', ['C-Shaped House']), create_cave_region(player, 'Chest Game', 'a game of 16 chests', ['Chest Game']), create_cave_region(player, 'Red Shield Shop', 'the rare shop', ['Red Shield Shop - Left', 'Red Shield Shop - Middle', 'Red Shield Shop - Right']), - create_cave_region(player, 'Dark Sanctuary Hint', 'a storyteller'), + create_cave_region(player, 'Dark Sanctuary Hint', 'a storyteller', None, ['Dark Sanctuary Hint Exit']), create_cave_region(player, 'Bumper Cave (bottom)', 'a connector', None, ['Bumper Cave Exit (Bottom)', 'Bumper Cave Bottom to Top']), create_cave_region(player, 'Bumper Cave (top)', 'a connector', None, ['Bumper Cave Exit (Top)', 'Bumper Cave Top To Bottom']), create_dw_region(player, 'Bumper Cave Ledge', ['Bumper Cave Ledge'], ['Bumper Cave Ledge Drop', 'Bumper Cave (Top)', 'Bumper Cave Ledge Mirror Spot'], 'a ledge with an item'), create_dw_region(player, 'Skull Woods Forest', None, ['Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', 'Skull Woods First Section Door', 'Skull Woods Second Section Door (East)']), create_dw_region(player, 'Skull Woods Forest (West)', None, ['Skull Woods Second Section Hole', 'Skull Woods Second Section Door (West)', 'Skull Woods Final Section'], 'a deep, dark forest'), - create_dw_region(player, 'Dark Desert', None, ['Misery Mire', 'Mire Shed', 'Desert Ledge (Northeast) Mirror Spot', 'Desert Ledge Mirror Spot', 'Desert Palace Stairs Mirror Spot', - 'Desert Palace Entrance (North) Mirror Spot', 'Dark Desert Hint', 'Dark Desert Fairy']), + create_dw_region(player, 'Dark Desert', None, ['Misery Mire', 'Mire Shed', 'Dark Desert Hint', 'Dark Desert Fairy', 'Desert Ledge (Northeast) Mirror Spot', 'Desert Ledge Mirror Spot', 'Mire To Desert Palace Stairs Mirror Spot', + 'Desert Palace Entrance (North) Mirror Spot', 'DD Flute']), + create_dw_region(player, 'Dark Desert Ledge', None, ['Dark Desert Drop', 'Dark Desert Teleporter']), create_cave_region(player, 'Mire Shed', 'a cave with two chests', ['Mire Shed - Left', 'Mire Shed - Right']), create_cave_region(player, 'Dark Desert Hint', 'a storyteller'), - create_dw_region(player, 'Dark Death Mountain (West Bottom)', None, ['Spike Cave', 'Spectacle Rock Mirror Spot', 'Dark Death Mountain Fairy']), + create_dw_region(player, 'Dark Death Mountain (West Bottom)', None, ['Spike Cave', 'Spectacle Rock Mirror Spot', 'Dark Death Mountain Fairy', 'Dark Death Mountain Ladder (Bottom)', 'Dark Death Mountain Teleporter (West)', 'DDM Flute']), create_dw_region(player, 'Dark Death Mountain (Top)', None, ['Dark Death Mountain Drop (East)', 'Dark Death Mountain Drop (West)', 'Ganons Tower', 'Superbunny Cave (Top)', - 'Hookshot Cave', 'East Death Mountain (Top) Mirror Spot', 'Turtle Rock']), + 'Hookshot Cave', 'East Death Mountain (Top) Mirror Spot', 'Dark Death Mountain Ladder (Top)', 'Turtle Rock Tail Drop', 'Turtle Rock']), create_dw_region(player, 'Dark Death Mountain Ledge', None, ['Dark Death Mountain Ledge (East)', 'Dark Death Mountain Ledge (West)', 'Mimic Cave Mirror Spot', 'Spiral Cave Mirror Spot'], 'a dark ledge'), create_dw_region(player, 'Dark Death Mountain Isolated Ledge', None, ['Isolated Ledge Mirror Spot', 'Turtle Rock Isolated Ledge Entrance'], 'a dark vista'), - create_dw_region(player, 'Dark Death Mountain (East Bottom)', None, ['Superbunny Cave (Bottom)', 'Cave Shop (Dark Death Mountain)', 'Fairy Ascension Mirror Spot']), + create_dw_region(player, 'Dark Death Mountain (East Bottom)', None, ['Superbunny Cave (Bottom)', 'Cave Shop (Dark Death Mountain)', 'Fairy Ascension Mirror Spot', 'Dark Death Mountain Teleporter (East Bottom)', 'EDDM Flute']), create_cave_region(player, 'Superbunny Cave (Top)', 'a connector', ['Superbunny Cave - Top', 'Superbunny Cave - Bottom'], ['Superbunny Cave Exit (Top)']), create_cave_region(player, 'Superbunny Cave (Bottom)', 'a connector', None, ['Superbunny Cave Climb', 'Superbunny Cave Exit (Bottom)']), create_cave_region(player, 'Spike Cave', 'Spike Cave', ['Spike Cave']), @@ -207,17 +221,16 @@ def create_regions(world, player): create_cave_region(player, 'Hookshot Cave (Back)', 'a connector', None, ['Hookshot Cave Back to Middle', 'Hookshot Cave Back Exit']), create_cave_region(player, 'Hookshot Cave (Middle)', 'a connector', None, ['Hookshot Cave Middle to Back', 'Hookshot Cave Middle to Front']), - create_dw_region(player, 'Death Mountain Floating Island (Dark World)', None, ['Floating Island Drop', 'Hookshot Cave Back Entrance', 'Floating Island Mirror Spot'], 'a dark island'), - create_lw_region(player, 'Death Mountain Floating Island (Light World)', ['Floating Island']), - create_dw_region(player, 'Turtle Rock (Top)', None, ['Turtle Rock Drop']), - create_lw_region(player, 'Mimic Cave Ledge', None, ['Mimic Cave']), + create_dw_region(player, 'Death Mountain Floating Island (Dark World)', None, ['Floating Island Drop', 'Hookshot Cave Back Entrance', 'Dark Floating Island Mirror Spot'], 'a dark island'), + create_lw_region(player, 'Death Mountain Floating Island', ['Floating Island'], ['Floating Island Bridge (West)', 'Floating Island Mirror Spot']), + create_dw_region(player, 'Turtle Rock (Top)', None, ['Dark Death Mountain Teleporter (East)', 'Turtle Rock Drop']), + create_lw_region(player, 'Mimic Cave Ledge', None, ['Mimic Cave', 'Mimic Cave Ledge Drop', 'Dark Death Mountain Ledge Mirror Spot (East)']), create_cave_region(player, 'Mimic Cave', 'Mimic Cave', ['Mimic Cave']), create_cave_region(player, 'Pyramid', 'a drop\'s exit', ['Ganon'], ['Ganon Drop']), create_cave_region(player, 'Bottom of Pyramid', 'a drop\'s exit', None, ['Pyramid Exit']), create_dw_region(player, 'Pyramid Ledge', None, ['Pyramid Entrance', 'Pyramid Drop']), - create_lw_region(player, 'Desert Northern Cliffs'), - create_dw_region(player, 'Dark Death Mountain Bunny Descent Area') + create_lw_region(player, 'Desert Northern Cliffs') ] @@ -948,7 +961,7 @@ def _create_region(player, name, type, hint='Hyrule', locations=None, exits=None ret.locations.append(Location(player, location, address, crystal, hint_text, ret, None, player_address)) return ret -def mark_light_world_regions(world, player): +def mark_light_dark_world_regions(world, player): # cross world caves may have some sections marked as both in_light_world, and in_dark_work. # That is ok. the bunny logic will check for this case and incorporate special rules. queue = collections.deque(region for region in world.get_regions(player) if region.type == RegionType.LightWorld) @@ -970,13 +983,12 @@ def mark_light_world_regions(world, player): current = queue.popleft() current.is_dark_world = True for exit in current.exits: - if exit.connected_region is not None: - if exit.connected_region.type == RegionType.LightWorld: - # Don't venture into the light world - continue - if exit.connected_region not in seen: - seen.add(exit.connected_region) - queue.append(exit.connected_region) + if exit.connected_region is None or exit.connected_region.type == RegionType.LightWorld: + # Don't venture into the light world + continue + if exit.connected_region not in seen: + seen.add(exit.connected_region) + queue.append(exit.connected_region) def create_shops(world, player): diff --git a/Rules.py b/Rules.py index 7c2435fe..a8bc939b 100644 --- a/Rules.py +++ b/Rules.py @@ -20,18 +20,17 @@ def set_rules(world, player): return global_rules(world, player) - if world.mode[player] != 'inverted': - default_rules(world, player) + ow_inverted_rules(world, player) - if world.mode[player] == 'open': - open_rules(world, player) - elif world.mode[player] == 'standard': + if world.swords[player] == 'swordless': + swordless_rules(world, player) + + ow_bunny_rules(world, player) + + if world.mode[player] == 'standard': standard_rules(world, player) - elif world.mode[player] == 'inverted': - open_rules(world, player) - inverted_rules(world, player) else: - raise NotImplementedError('Not implemented yet') + misc_key_rules(world, player) bomb_rules(world, player) pot_rules(world, player) @@ -115,6 +114,11 @@ def add_rule(spot, rule, combine='and'): else: spot.access_rule = lambda state: rule(state) and old_rule(state) +def add_bunny_rule(spot, player): + region = spot.parent_region + if not (region.is_light_world if region.world.mode[player] != 'inverted' else region.is_dark_world): + add_rule(spot, lambda state: state.has_Pearl(player)) + def or_rule(rule1, rule2): return lambda state: rule1(state) or rule2(state) @@ -185,6 +189,86 @@ def global_rules(world, player): set_rule(world.get_entrance('Hookshot Cave Bonk Path', player), lambda state: state.has('Hookshot', player) or state.has('Pegasus Boots', player)) set_rule(world.get_entrance('Hookshot Cave Hook Path', player), lambda state: state.has('Hookshot', player)) + set_rule(world.get_entrance('Old Man Cave Exit (West)', player), lambda state: False) # drop cannot be climbed up + + # s&q regions. link's house entrance is set to true so the filler knows the chest inside can always be reached + set_rule(world.get_entrance('Other World S&Q', player), lambda state: state.has_Mirror(player) and state.has('Beat Agahnim 1', player)) + + # overworld requirements + set_rule(world.get_entrance('Kings Grave', player), lambda state: state.has_Boots(player)) + set_rule(world.get_entrance('Kings Grave Outer Rocks', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Kings Grave Inner Rocks', player), lambda state: state.can_lift_heavy_rocks(player)) + # Caution: If king's grave is relaxed at all to account for reaching it via a two way cave's exit in insanity mode, then the bomb shop logic will need to be updated (that would involve create a small ledge-like Region for it) + set_rule(world.get_entrance('Potion Shop Rock (North)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Potion Shop Rock (South)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Bonk Fairy (Light)', player), lambda state: state.has_Boots(player)) + set_rule(world.get_entrance('Bat Cave Ledge Peg', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Bat Cave Ledge Peg (East)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Lumberjack Tree Tree', player), lambda state: state.has_Boots(player) and state.has('Beat Agahnim 1', player)) + set_rule(world.get_entrance('Bonk Rock Cave', player), lambda state: state.has_Boots(player)) + set_rule(world.get_entrance('Desert Statue Move', player), lambda state: state.has('Book of Mudora', player)) + set_rule(world.get_entrance('Sanctuary Grave', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('20 Rupee Cave', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('50 Rupee Cave', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Death Mountain Entrance Rock', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_location('Flute Spot', player), lambda state: state.has('Shovel', player)) + + set_rule(world.get_location('Zora\'s Ledge', player), lambda state: state.has('Flippers', player)) + # can be fake flippered into, but is in weird state inside that might prevent you from doing things. + set_rule(world.get_entrance('Waterfall Fairy Access', player), lambda state: state.has('Flippers', player)) + + set_rule(world.get_location('Potion Shop', player), lambda state: state.has('Mushroom', player) and state.can_reach('Potion Shop Area', 'Region', player)) + set_rule(world.get_entrance('Desert Palace Entrance (North) Rocks', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Desert Ledge Return Rocks', player), lambda state: state.can_lift_rocks(player)) # should we decide to place something that is not a dungeon end up there at some point + set_rule(world.get_entrance('Checkerboard Cave', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has('Cape', player) or state.has_beam_sword(player)) + set_rule(world.get_entrance('DM Broken Bridge (West)', player), lambda state: state.has('Hookshot', player)) + set_rule(world.get_entrance('DM Broken Bridge (East)', player), lambda state: state.has('Hookshot', player)) + set_rule(world.get_entrance('East Death Mountain Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Fairy Ascension Rocks', player), lambda state: state.can_lift_heavy_rocks(player)) + # can erase block - overridden in noglitches + set_rule(world.get_entrance('Paradox Cave Push Block Reverse', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('DM Hammer Bridge (East)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Turtle Rock Teleporter', player), lambda state: state.can_lift_heavy_rocks(player) and state.has('Hammer', player)) + set_rule(world.get_entrance('DM Hammer Bridge (West)', player), lambda state: state.has('Hammer', player)) + + set_rule(world.get_entrance('Dark Witch Rock (North)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Dark Witch Rock (South)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Northeast Dark World Broken Bridge Pass', player), lambda state: state.can_lift_rocks(player) or state.has('Hammer', player) or state.has('Flippers', player)) + set_rule(world.get_entrance('East Dark World Broken Bridge Pass', player), lambda state: state.can_lift_rocks(player) or state.has('Hammer', player)) + set_rule(world.get_entrance('Hammer Bridge Pegs (North)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Bonk Fairy (Dark)', player), lambda state: state.has_Boots(player)) + set_rule(world.get_entrance('West Dark World Gap', player), lambda state: state.has('Hookshot', player)) + set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player)) + set_rule(world.get_entrance('Dark Lake Hylia Ledge Spike Cave', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Village of Outcasts Heavy Rock', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Hammer Bridge Pegs (South)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Bumper Cave Entrance Rock', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Dark World Hammer Peg Cave', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Village of Outcasts Eastern Rocks', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Peg Area Rocks', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Village of Outcasts Pegs', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Grassy Lawn Pegs', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Bumper Cave Bottom to Top', player), lambda state: state.has('Cape', player)) + set_rule(world.get_entrance('Bumper Cave Top To Bottom', player), lambda state: state.has('Cape', player) or state.has('Hookshot', player)) + + set_rule(world.get_entrance('Skull Woods Final Section', player), lambda state: state.has('Fire Rod', player)) + set_rule(world.get_entrance('Hookshot Cave', player), lambda state: state.can_lift_rocks(player)) + + set_rule(world.get_entrance('Misery Mire', player), lambda state: state.has_sword(player) and state.has_misery_mire_medallion(player)) # sword required to cast magic (!) + set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has_sword(player) and state.has_turtle_rock_medallion(player) and state.can_reach('Turtle Rock (Top)', 'Region', player)) # sword required to cast magic (!) + + set_rule(world.get_entrance('Flute Spot 1', player), lambda state: state.can_flute(player)) + set_rule(world.get_entrance('Flute Spot 2', player), lambda state: state.can_flute(player)) + set_rule(world.get_entrance('Flute Spot 3', player), lambda state: state.can_flute(player)) + set_rule(world.get_entrance('Flute Spot 4', player), lambda state: state.can_flute(player)) + set_rule(world.get_entrance('Flute Spot 5', player), lambda state: state.can_flute(player)) + set_rule(world.get_entrance('Flute Spot 6', player), lambda state: state.can_flute(player)) + set_rule(world.get_entrance('Flute Spot 7', player), lambda state: state.can_flute(player)) + set_rule(world.get_entrance('Flute Spot 8', player), lambda state: state.can_flute(player)) + + set_rule(world.get_entrance('Ganons Tower' if not world.is_atgt_swapped(player) else 'Agahnims Tower', player), lambda state: state.has_crystals(world.crystals_needed_for_gt[player], player)) + # Start of door rando rules # TODO: Do these need to flag off when door rando is off? - some of them, yes @@ -619,9 +703,11 @@ def bomb_rules(world, player): 'Paradox Cave Chest Area NE', 'Blinds Hideout N', 'Kakariko Well (top to back)', 'Light Hype Fairy'] for entrance in bonkable_doors: - add_rule(world.get_entrance(entrance, player), lambda state: state.can_use_bombs(player) or state.has_Boots(player)) + add_rule(world.get_entrance(entrance, player), lambda state: state.can_use_bombs(player) or state.has_Boots(player)) + add_bunny_rule(world.get_entrance(entrance, player), player) for entrance in bombable_doors: - add_rule(world.get_entrance(entrance, player), lambda state: state.can_use_bombs(player)) + add_rule(world.get_entrance(entrance, player), lambda state: state.can_use_bombs(player)) + add_bunny_rule(world.get_entrance(entrance, player), player) bonkable_items = ['Sahasrahla\'s Hut - Left', 'Sahasrahla\'s Hut - Middle', 'Sahasrahla\'s Hut - Right'] bombable_items = ['Chicken House', 'Aginah\'s Cave', 'Graveyard Cave', @@ -769,301 +855,205 @@ def pot_rules(world, player): add_rule(l, lambda state: state.can_hit_crystal(player)) +def ow_inverted_rules(world, player): + if world.mode[player] != 'inverted': + set_rule(world.get_entrance('Kings Grave Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Bumper Cave Entrance Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Lake Hylia Central Island Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Desert Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('East Hyrule Teleporter', player), lambda state: state.has('Hammer', player) and state.can_lift_rocks(player) and state.has_Pearl(player)) # bunny cannot use hammer + set_rule(world.get_entrance('South Hyrule Teleporter', player), lambda state: state.has('Hammer', player) and state.can_lift_rocks(player) and state.has_Pearl(player)) # bunny cannot use hammer + set_rule(world.get_entrance('Kakariko Teleporter', player), lambda state: ((state.has('Hammer', player) and state.can_lift_rocks(player)) or state.can_lift_heavy_rocks(player)) and state.has_Pearl(player)) # bunny cannot lift bushes + set_rule(world.get_entrance('Top of Pyramid', player), lambda state: state.has('Beat Agahnim 1', player)) + set_rule(world.get_entrance('Hyrule Castle Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Hyrule Castle Main Gate', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Hyrule Castle Main Gate (North)', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Dig Game Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Cave 45 Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Bombos Tablet Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Lake Hylia Island Mirror Spot', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player) and state.has_Mirror(player)) # force flipper rule since fake flipper cannot mirror + set_rule(world.get_entrance('Lake Hylia Central Island Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Graveyard Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Bumper Cave Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Bat Cave Drop Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Dark Grassy Lawn Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Desert Ledge (Northeast) Mirror Spot', player), lambda state: state.has_Mirror(player)) -def default_rules(world, player): - set_rule(world.get_entrance('Other World S&Q', player), lambda state: state.has_Mirror(player) and state.has('Beat Agahnim 1', player)) + set_rule(world.get_entrance('Desert Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Mire To Desert Palace Stairs Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Desert Palace Entrance (North) Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Spectacle Rock Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('East Death Mountain (Top) Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Mimic Cave Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Spiral Cave Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Fairy Ascension Mirror Spot', player), lambda state: state.has_Mirror(player) and state.has_Pearl(player)) # need to lift flowers + set_rule(world.get_entrance('Isolated Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Dark Floating Island Mirror Spot', player), lambda state: state.has_Mirror(player)) - # overworld requirements - set_rule(world.get_entrance('Kings Grave', player), lambda state: state.has_Boots(player)) - set_rule(world.get_entrance('Kings Grave Outer Rocks', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Kings Grave Inner Rocks', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Kings Grave Mirror Spot', player), lambda state: state.has_Pearl(player) and state.has_Mirror(player)) - # Caution: If king's grave is releaxed at all to account for reaching it via a two way cave's exit in insanity mode, then the bomb shop logic will need to be updated (that would involve create a small ledge-like Region for it) - set_rule(world.get_entrance('Bonk Fairy (Light)', player), lambda state: state.has_Boots(player)) - set_rule(world.get_entrance('Bat Cave Drop Ledge', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Lumberjack Tree Tree', player), lambda state: state.has_Boots(player) and state.has('Beat Agahnim 1', player)) - set_rule(world.get_entrance('Bonk Rock Cave', player), lambda state: state.has_Boots(player)) - set_rule(world.get_entrance('Desert Palace Stairs', player), lambda state: state.has('Book of Mudora', player)) - set_rule(world.get_entrance('Sanctuary Grave', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('20 Rupee Cave', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('50 Rupee Cave', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Death Mountain Entrance Rock', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Bumper Cave Entrance Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Flute Spot 1', player), lambda state: state.can_flute(player)) - set_rule(world.get_entrance('Lake Hylia Central Island Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Dark Desert Teleporter', player), lambda state: state.can_flute(player) and state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('East Hyrule Teleporter', player), lambda state: state.has('Hammer', player) and state.can_lift_rocks(player) and state.has_Pearl(player)) # bunny cannot use hammer - set_rule(world.get_entrance('South Hyrule Teleporter', player), lambda state: state.has('Hammer', player) and state.can_lift_rocks(player) and state.has_Pearl(player)) # bunny cannot use hammer - set_rule(world.get_entrance('Kakariko Teleporter', player), lambda state: ((state.has('Hammer', player) and state.can_lift_rocks(player)) or state.can_lift_heavy_rocks(player)) and state.has_Pearl(player)) # bunny cannot lift bushes - set_rule(world.get_location('Flute Spot', player), lambda state: state.has('Shovel', player)) + set_rule(world.get_location('Frog', player), lambda state: state.can_lift_heavy_rocks(player) and state.has_Pearl(player)) - set_rule(world.get_location('Zora\'s Ledge', player), lambda state: state.has('Flippers', player)) - # can be fake flippered into, but is in weird state inside that might prevent you from doing things. - set_rule(world.get_entrance('Waterfall of Wishing', player), lambda state: state.has('Flippers', player)) - # to leave via fake flippers, you'd need pearl and have waterwalk or swimming state, so just require flippers - set_rule(world.get_entrance('Zora Waterfall Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_location('Frog', player), lambda state: state.can_lift_heavy_rocks(player)) # will get automatic moon pearl requirement - set_rule(world.get_location('Potion Shop', player), lambda state: state.has('Mushroom', player)) - set_rule(world.get_entrance('Desert Palace Entrance (North) Rocks', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Desert Ledge Return Rocks', player), lambda state: state.can_lift_rocks(player)) # should we decide to place something that is not a dungeon end up there at some point - set_rule(world.get_entrance('Checkerboard Cave', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has('Cape', player) or state.has_beam_sword(player) or state.has('Beat Agahnim 1', player)) # barrier gets removed after killing agahnim, relevant for entrance shuffle - set_rule(world.get_entrance('Top of Pyramid', player), lambda state: state.has('Beat Agahnim 1', player)) - set_rule(world.get_entrance('Old Man Cave Exit (West)', player), lambda state: False) # drop cannot be climbed up - set_rule(world.get_entrance('Broken Bridge (West)', player), lambda state: state.has('Hookshot', player)) - set_rule(world.get_entrance('Broken Bridge (East)', player), lambda state: state.has('Hookshot', player)) - set_rule(world.get_entrance('East Death Mountain Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Fairy Ascension Rocks', player), lambda state: state.can_lift_heavy_rocks(player)) - # can erase block - overridden in noglitches - set_rule(world.get_entrance('Paradox Cave Push Block Reverse', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Death Mountain (Top)', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Turtle Rock Teleporter', player), lambda state: state.can_lift_heavy_rocks(player) and state.has('Hammer', player)) - set_rule(world.get_entrance('East Death Mountain (Top)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Pyramid Hole', player), lambda state: world.open_pyramid[player] or world.goal[player] == 'trinity' or state.has('Beat Agahnim 2', player)) + else: + set_rule(world.get_entrance('Bumper Cave Entrance Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Lake Hylia Central Island Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Dark Lake Hylia Central Island Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Dark Desert Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('East Dark World Teleporter', player), lambda state: state.has('Hammer', player) and state.can_lift_rocks(player) and state.has_Pearl(player)) # bunny cannot use hammer + set_rule(world.get_entrance('South Dark World Teleporter', player), lambda state: state.has('Hammer', player) and state.can_lift_rocks(player) and state.has_Pearl(player)) # bunny cannot use hammer + set_rule(world.get_entrance('West Dark World Teleporter', player), lambda state: ((state.has('Hammer', player) and state.can_lift_rocks(player)) or state.can_lift_heavy_rocks(player)) and state.has_Pearl(player)) + set_rule(world.get_entrance('Bush Covered Lawn Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Dark Death Mountain Teleporter (East Bottom)', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Dark Death Mountain Teleporter (East)', player), lambda state: state.can_lift_heavy_rocks(player) and state.has('Hammer', player) and state.has_Pearl(player)) # bunny cannot use hammer + set_rule(world.get_entrance('Lake Hylia Central Island Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Mountain Exit Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Hammer Peg Area Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Pyramid Uncle Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('East Death Mountain Mirror Spot (Top)', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Death Mountain (Top) Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Catfish Exit Rock', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Catfish Entrance Rock', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Northeast Dark World Broken Bridge Pass', player), lambda state: state.has_Pearl(player) and (state.can_lift_rocks(player) or state.has('Hammer', player) or state.has('Flippers', player))) - set_rule(world.get_entrance('East Dark World Broken Bridge Pass', player), lambda state: state.has_Pearl(player) and (state.can_lift_rocks(player) or state.has('Hammer', player))) - set_rule(world.get_entrance('South Dark World Bridge', player), lambda state: state.has('Hammer', player) and state.has_Pearl(player)) - set_rule(world.get_entrance('Bonk Fairy (Dark)', player), lambda state: state.has_Pearl(player) and state.has_Boots(player)) - set_rule(world.get_entrance('West Dark World Gap', player), lambda state: state.has_Pearl(player) and state.has('Hookshot', player)) - set_rule(world.get_entrance('Palace of Darkness', player), lambda state: state.has_Pearl(player)) # kiki needs pearl - set_rule(world.get_entrance('Hyrule Castle Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Hyrule Castle Main Gate', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Hyrule Castle Main Gate (North)', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Dark Lake Hylia Drop (East)', player), lambda state: (state.has_Pearl(player) and state.has('Flippers', player) or state.has_Mirror(player))) # Overworld Bunny Revival - set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player)) - set_rule(world.get_entrance('Dark Lake Hylia Drop (South)', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player)) # ToDo any fake flipper set up? - set_rule(world.get_entrance('Dark Lake Hylia Ledge Fairy', player), lambda state: state.has_Pearl(player)) # bomb required - set_rule(world.get_entrance('Dark Lake Hylia Ledge Spike Cave', player), lambda state: state.can_lift_rocks(player) and state.has_Pearl(player)) - set_rule(world.get_entrance('Dark Lake Hylia Teleporter', player), lambda state: state.has_Pearl(player) and (state.has('Hammer', player) or state.can_lift_rocks(player))) # Fake Flippers - set_rule(world.get_entrance('Village of Outcasts Heavy Rock', player), lambda state: state.has_Pearl(player) and state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Hype Cave', player), lambda state: state.has_Pearl(player)) # bomb required - set_rule(world.get_entrance('Brewery', player), lambda state: state.has_Pearl(player)) # bomb required - set_rule(world.get_entrance('Thieves Town', player), lambda state: state.has_Pearl(player)) # bunny cannot pull - set_rule(world.get_entrance('Skull Woods First Section Hole (North)', player), lambda state: state.has_Pearl(player)) # bunny cannot lift bush - set_rule(world.get_entrance('Skull Woods Second Section Hole', player), lambda state: state.has_Pearl(player)) # bunny cannot lift bush - set_rule(world.get_entrance('Maze Race Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Cave 45 Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Bombos Tablet Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('East Dark World Bridge', player), lambda state: state.has_Pearl(player) and state.has('Hammer', player)) - set_rule(world.get_entrance('Lake Hylia Island Mirror Spot', player), lambda state: state.has_Pearl(player) and state.has_Mirror(player) and state.has('Flippers', player)) - set_rule(world.get_entrance('Lake Hylia Central Island Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('East Dark World River Pier', player), lambda state: state.has_Pearl(player)) - set_rule(world.get_entrance('Graveyard Ledge Mirror Spot', player), lambda state: state.has_Pearl(player) and state.has_Mirror(player)) - set_rule(world.get_entrance('Bumper Cave Entrance Rock', player), lambda state: state.has_Pearl(player) and state.can_lift_rocks(player)) - set_rule(world.get_entrance('Bumper Cave Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Bat Cave Drop Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Dark World Hammer Peg Cave', player), lambda state: state.has_Pearl(player) and state.has('Hammer', player)) - set_rule(world.get_entrance('Village of Outcasts Eastern Rocks', player), lambda state: state.has_Pearl(player) and state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Peg Area Rocks', player), lambda state: state.has_Pearl(player) and state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Village of Outcasts Pegs', player), lambda state: state.has_Pearl(player) and state.has('Hammer', player)) - set_rule(world.get_entrance('Grassy Lawn Pegs', player), lambda state: state.has_Pearl(player) and state.has('Hammer', player)) - set_rule(world.get_entrance('Bumper Cave Bottom to Top', player), lambda state: state.has('Cape', player)) - set_rule(world.get_entrance('Bumper Cave Top To Bottom', player), lambda state: state.has('Cape', player) or state.has('Hookshot', player)) + set_rule(world.get_entrance('East Death Mountain Mirror Spot (Bottom)', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Dark Death Mountain Ledge Mirror Spot (East)', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Dark Death Mountain Ledge Mirror Spot (West)', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Laser Bridge Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Floating Island Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Post Aga Teleporter', player), lambda state: state.has('Beat Agahnim 1', player)) + set_rule(world.get_entrance('Mire Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Desert Palace Stairs Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Death Mountain Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('East Dark World Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('West Dark World Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('South Dark World Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Catfish Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Potion Shop Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Shopping Mall Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Maze Race Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Desert Palace North Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Death Mountain (Top) Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Graveyard Cave Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Bomb Hut Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Skull Woods Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Skull Woods Final Section', player), lambda state: state.has('Fire Rod', player) and state.has_Pearl(player)) # bunny cannot use fire rod - set_rule(world.get_entrance('Misery Mire', player), lambda state: state.has_Pearl(player) and state.has_sword(player) and state.has_misery_mire_medallion(player)) # sword required to cast magic (!) - set_rule(world.get_entrance('Desert Ledge (Northeast) Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_location('Frog', player), lambda state: state.can_lift_heavy_rocks(player) and + (state.has_Pearl(player) or state.has('Beat Agahnim 1', player)) + or (state.can_reach('Light World', 'Region', player) and state.has_Mirror(player))) # Need LW access using Mirror or Portal - set_rule(world.get_entrance('Desert Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Desert Palace Stairs Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Desert Palace Entrance (North) Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Spectacle Rock Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Hookshot Cave', player), lambda state: state.can_lift_rocks(player) and state.has_Pearl(player)) - - set_rule(world.get_entrance('East Death Mountain (Top) Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Mimic Cave Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Spiral Cave Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Fairy Ascension Mirror Spot', player), lambda state: state.has_Mirror(player) and state.has_Pearl(player)) # need to lift flowers - set_rule(world.get_entrance('Isolated Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Floating Island Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has_Pearl(player) and state.has_sword(player) and state.has_turtle_rock_medallion(player) and state.can_reach('Turtle Rock (Top)', 'Region', player)) # sword required to cast magic (!) - - set_rule(world.get_entrance('Pyramid Hole', player), lambda state: world.open_pyramid[player] or world.goal[player] == 'trinity' or state.has('Beat Agahnim 2', player)) - if world.swords[player] == 'swordless': - swordless_rules(world, player) - - set_rule(world.get_entrance('Ganons Tower', player), lambda state: state.has_crystals(world.crystals_needed_for_gt[player], player)) + set_rule(world.get_entrance('Inverted Pyramid Hole', player), lambda state: world.open_pyramid[player] or world.goal[player] == 'trinity' or state.has('Beat Agahnim 2', player)) -def inverted_rules(world, player): - # s&q regions. link's house entrance is set to true so the filler knows the chest inside can always be reached - set_rule(world.get_entrance('Other World S&Q', player), lambda state: state.has_Mirror(player) and state.has('Beat Agahnim 1', player)) +def ow_bunny_rules(world, player): + add_bunny_rule(world.get_entrance('Kings Grave', player), player) + add_bunny_rule(world.get_entrance('Kings Grave Outer Rocks', player), player) + add_bunny_rule(world.get_entrance('Kings Grave Inner Rocks', player), player) + add_bunny_rule(world.get_entrance('Bonk Fairy (Light)', player), player) + add_bunny_rule(world.get_entrance('Bat Cave Ledge Peg', player), player) + add_bunny_rule(world.get_entrance('Bat Cave Ledge Peg (East)', player), player) + add_bunny_rule(world.get_entrance('Lumberjack Tree Tree', player), player) + add_bunny_rule(world.get_entrance('Bonk Rock Cave', player), player) + add_bunny_rule(world.get_entrance('Sanctuary Grave', player), player) + add_bunny_rule(world.get_entrance('20 Rupee Cave', player), player) + add_bunny_rule(world.get_entrance('50 Rupee Cave', player), player) + add_bunny_rule(world.get_entrance('Death Mountain Entrance Rock', player), player) + add_bunny_rule(world.get_location('Flute Spot', player), player) - # overworld requirements - set_rule(world.get_location('Ice Rod Cave', player), lambda state: state.has_Pearl(player)) - set_rule(world.get_location('Maze Race', player), lambda state: state.has_Pearl(player)) - set_rule(world.get_entrance('Mini Moldorm Cave', player), lambda state: state.has_Pearl(player)) - set_rule(world.get_entrance('Ice Rod Cave', player), lambda state: state.has_Pearl(player)) - set_rule(world.get_entrance('Light Hype Fairy', player), lambda state: state.has_Pearl(player)) - set_rule(world.get_entrance('Potion Shop Pier', player), lambda state: state.has('Flippers', player) and state.has_Pearl(player)) - set_rule(world.get_entrance('Light World Pier', player), lambda state: state.has('Flippers', player) and state.has_Pearl(player)) - set_rule(world.get_entrance('Kings Grave', player), lambda state: state.has_Boots(player) and state.has_Pearl(player)) - set_rule(world.get_entrance('Kings Grave Outer Rocks', player), lambda state: state.can_lift_heavy_rocks(player) and state.has_Pearl(player)) - set_rule(world.get_entrance('Kings Grave Inner Rocks', player), lambda state: state.can_lift_heavy_rocks(player) and state.has_Pearl(player)) - set_rule(world.get_entrance('Potion Shop Inner Bushes', player), lambda state: state.has_Pearl(player)) - set_rule(world.get_entrance('Potion Shop Outer Bushes', player), lambda state: state.has_Pearl(player)) - set_rule(world.get_entrance('Potion Shop Outer Rock', player), lambda state: state.can_lift_rocks(player) and state.has_Pearl(player)) - set_rule(world.get_entrance('Potion Shop Inner Rock', player), lambda state: state.can_lift_rocks(player) and state.has_Pearl(player)) - set_rule(world.get_entrance('Graveyard Cave Inner Bushes', player), lambda state: state.has_Pearl(player)) - set_rule(world.get_entrance('Graveyard Cave Outer Bushes', player), lambda state: state.has_Pearl(player)) - set_rule(world.get_entrance('Secret Passage Inner Bushes', player), lambda state: state.has_Pearl(player)) - set_rule(world.get_entrance('Secret Passage Outer Bushes', player), lambda state: state.has_Pearl(player)) - set_rule(world.get_entrance('Bonk Fairy (Light)', player), lambda state: state.has_Boots(player) and state.has_Pearl(player)) - set_rule(world.get_entrance('Bat Cave Drop Ledge', player), lambda state: state.has('Hammer', player) and state.has_Pearl(player)) - set_rule(world.get_entrance('Lumberjack Tree Tree', player), lambda state: state.has_Boots(player) and state.has_Pearl(player) and state.has('Beat Agahnim 1', player)) - set_rule(world.get_entrance('Bonk Rock Cave', player), lambda state: state.has_Boots(player) and state.has_Pearl(player)) - set_rule(world.get_entrance('Desert Palace Stairs', player), lambda state: state.has('Book of Mudora', player)) # bunny can use book - set_rule(world.get_entrance('Sanctuary Grave', player), lambda state: state.can_lift_rocks(player) and state.has_Pearl(player)) - set_rule(world.get_entrance('20 Rupee Cave', player), lambda state: state.can_lift_rocks(player) and state.has_Pearl(player)) - set_rule(world.get_entrance('50 Rupee Cave', player), lambda state: state.can_lift_rocks(player) and state.has_Pearl(player)) - set_rule(world.get_entrance('Death Mountain Entrance Rock', player), lambda state: state.can_lift_rocks(player) and state.has_Pearl(player)) - set_rule(world.get_entrance('Bumper Cave Entrance Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Lake Hylia Central Island Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Dark Lake Hylia Central Island Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Dark Desert Teleporter', player), lambda state: state.can_flute(player) and state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('East Dark World Teleporter', player), lambda state: state.has('Hammer', player) and state.can_lift_rocks(player) and state.has_Pearl(player)) # bunny cannot use hammer - set_rule(world.get_entrance('South Dark World Teleporter', player), lambda state: state.has('Hammer', player) and state.can_lift_rocks(player) and state.has_Pearl(player)) # bunny cannot use hammer - set_rule(world.get_entrance('West Dark World Teleporter', player), lambda state: ((state.has('Hammer', player) and state.can_lift_rocks(player)) or state.can_lift_heavy_rocks(player)) and state.has_Pearl(player)) - set_rule(world.get_location('Flute Spot', player), lambda state: state.has('Shovel', player) and state.has_Pearl(player)) + add_bunny_rule(world.get_location('Zora\'s Ledge', player), player) + add_bunny_rule(world.get_entrance('Waterfall Fairy Access', player), player) - set_rule(world.get_location('Zora\'s Ledge', player), lambda state: state.has('Flippers', player) and state.has_Pearl(player)) - set_rule(world.get_entrance('Waterfall of Wishing Cave', player), lambda state: state.has('Flippers', player) and state.has_Pearl(player)) - set_rule(world.get_entrance('Northeast Light World Return', player), lambda state: state.has('Flippers', player) and state.has_Pearl(player)) - set_rule(world.get_location('Frog', player), lambda state: state.can_lift_heavy_rocks(player) and - (state.has_Pearl(player) or state.has('Beat Agahnim 1', player)) or (state.can_reach('Light World', 'Region', player) - and state.has_Mirror(player))) # Need LW access using Mirror or Portal - set_rule(world.get_location('Mushroom', player), lambda state: state.has_Pearl(player)) # need pearl to pick up bushes - set_rule(world.get_entrance('Bush Covered Lawn Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Bush Covered Lawn Inner Bushes', player), lambda state: state.has_Pearl(player)) - set_rule(world.get_entrance('Bush Covered Lawn Outer Bushes', player), lambda state: state.has_Pearl(player)) - set_rule(world.get_entrance('Bomb Hut Inner Bushes', player), lambda state: state.has_Pearl(player)) - set_rule(world.get_entrance('Bomb Hut Outer Bushes', player), lambda state: state.has_Pearl(player)) - set_rule(world.get_entrance('Light World Bomb Hut', player), lambda state: state.has_Pearl(player)) # need bomb - set_rule(world.get_entrance('North Fairy Cave Drop', player), lambda state: state.has_Pearl(player)) - set_rule(world.get_entrance('Lost Woods Hideout Drop', player), lambda state: state.has_Pearl(player)) - set_rule(world.get_location('Potion Shop', player), lambda state: state.has('Mushroom', player) and (state.can_reach('Potion Shop Area', 'Region', player))) # new inverted region, need pearl for bushes or access to potion shop door/waterfall fairy - set_rule(world.get_entrance('Desert Palace Entrance (North) Rocks', player), lambda state: state.can_lift_rocks(player) and state.has_Pearl(player)) - set_rule(world.get_entrance('Desert Ledge Return Rocks', player), lambda state: state.can_lift_rocks(player) and state.has_Pearl(player)) # should we decide to place something that is not a dungeon end up there at some point - set_rule(world.get_entrance('Checkerboard Cave', player), lambda state: state.can_lift_rocks(player) and state.has_Pearl(player)) - set_rule(world.get_entrance('Hyrule Castle Secret Entrance Drop', player), lambda state: state.has_Pearl(player)) - set_rule(world.get_entrance('Old Man Cave Exit (West)', player), lambda state: False) # drop cannot be climbed up - set_rule(world.get_entrance('Broken Bridge (West)', player), lambda state: state.has('Hookshot', player) and state.has_Pearl(player)) - set_rule(world.get_entrance('Broken Bridge (East)', player), lambda state: state.has('Hookshot', player) and state.has_Pearl(player)) - set_rule(world.get_entrance('Dark Death Mountain Teleporter (East Bottom)', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Fairy Ascension Rocks', player), lambda state: state.can_lift_heavy_rocks(player) and state.has_Pearl(player)) - # can erase block - overridden in noglitches - set_rule(world.get_entrance('Paradox Cave Push Block Reverse', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Death Mountain (Top)', player), lambda state: state.has('Hammer', player) and state.has_Pearl(player)) - set_rule(world.get_entrance('Dark Death Mountain Teleporter (East)', player), lambda state: state.can_lift_heavy_rocks(player) and state.has('Hammer', player) and state.has_Pearl(player)) # bunny cannot use hammer - set_rule(world.get_entrance('East Death Mountain (Top)', player), lambda state: state.has('Hammer', player) and state.has_Pearl(player)) # bunny can not use hammer + add_bunny_rule(world.get_entrance('Desert Palace Entrance (North) Rocks', player), player) + add_bunny_rule(world.get_entrance('Desert Ledge Return Rocks', player), player) + add_bunny_rule(world.get_entrance('Checkerboard Cave', player), player) + add_bunny_rule(world.get_entrance('DM Broken Bridge (West)', player), player) + add_bunny_rule(world.get_entrance('DM Broken Bridge (East)', player), player) + add_bunny_rule(world.get_entrance('East Death Mountain Teleporter', player), player) + add_bunny_rule(world.get_entrance('Fairy Ascension Rocks', player), player) + add_bunny_rule(world.get_entrance('DM Hammer Bridge (East)', player), player) + add_bunny_rule(world.get_entrance('Turtle Rock Teleporter', player), player) + add_bunny_rule(world.get_entrance('DM Hammer Bridge (West)', player), player) - set_rule(world.get_entrance('Catfish Entrance Rock', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Northeast Dark World Broken Bridge Pass', player), lambda state: ((state.can_lift_rocks(player) or state.has('Hammer', player)) or state.has('Flippers', player))) - set_rule(world.get_entrance('East Dark World Broken Bridge Pass', player), lambda state: (state.can_lift_rocks(player) or state.has('Hammer', player))) - set_rule(world.get_entrance('South Dark World Bridge', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Bonk Fairy (Dark)', player), lambda state: state.has_Boots(player)) - set_rule(world.get_entrance('West Dark World Gap', player), lambda state: state.has('Hookshot', player)) - set_rule(world.get_entrance('Dark Lake Hylia Drop (East)', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player)) - set_rule(world.get_entrance('Dark Lake Hylia Drop (South)', player), lambda state: state.has('Flippers', player)) # ToDo any fake flipper set up? - set_rule(world.get_entrance('Dark Lake Hylia Ledge Pier', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Dark Lake Hylia Ledge Spike Cave', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Dark Lake Hylia Teleporter', player), lambda state: state.has('Flippers', player)) # Fake Flippers - set_rule(world.get_entrance('Dark Lake Hylia Shallows', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Village of Outcasts Heavy Rock', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('East Dark World Bridge', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Lake Hylia Central Island Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Bumper Cave Entrance Rock', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Bumper Cave Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Hammer Peg Area Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Dark World Hammer Peg Cave', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Village of Outcasts Eastern Rocks', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Peg Area Rocks', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Village of Outcasts Pegs', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Grassy Lawn Pegs', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Bumper Cave Exit (Top)', player), lambda state: state.has('Cape', player)) - set_rule(world.get_entrance('Bumper Cave Exit (Bottom)', player), lambda state: state.has('Cape', player) or state.has('Hookshot', player)) + add_bunny_rule(world.get_entrance('Dark Witch Rock (North)', player), player) + add_bunny_rule(world.get_entrance('Dark Witch Rock (South)', player), player) + add_bunny_rule(world.get_entrance('Northeast Dark World Broken Bridge Pass', player), player) + add_bunny_rule(world.get_entrance('East Dark World Broken Bridge Pass', player), player) + add_bunny_rule(world.get_entrance('Hammer Bridge Pegs (North)', player), player) + add_bunny_rule(world.get_entrance('Bonk Fairy (Dark)', player), player) + add_bunny_rule(world.get_entrance('West Dark World Gap', player), player) + add_bunny_rule(world.get_entrance('Palace of Darkness', player), player) # kiki needs pearl + add_bunny_rule(world.get_entrance('Dark Lake Hylia Ledge Spike Cave', player), player) + add_bunny_rule(world.get_entrance('Village of Outcasts Heavy Rock', player), player) + add_bunny_rule(world.get_entrance('Thieves Town', player), player) # bunny cannot pull + add_bunny_rule(world.get_entrance('Skull Woods First Section Hole (North)', player), player) # bunny cannot lift bush + add_bunny_rule(world.get_entrance('Skull Woods Second Section Hole', player), player) # bunny cannot lift bush + add_bunny_rule(world.get_entrance('Hammer Bridge Pegs (South)', player), player) + add_bunny_rule(world.get_entrance('Bumper Cave Entrance Rock', player), player) + add_bunny_rule(world.get_entrance('Dark World Hammer Peg Cave', player), player) + add_bunny_rule(world.get_entrance('Village of Outcasts Eastern Rocks', player), player) + add_bunny_rule(world.get_entrance('Peg Area Rocks', player), player) + add_bunny_rule(world.get_entrance('Village of Outcasts Pegs', player), player) + add_bunny_rule(world.get_entrance('Grassy Lawn Pegs', player), player) + add_bunny_rule(world.get_entrance('Bumper Cave Bottom to Top', player), player) + add_bunny_rule(world.get_entrance('Bumper Cave Top To Bottom', player), player) - set_rule(world.get_entrance('Skull Woods Final Section', player), lambda state: state.has('Fire Rod', player)) - set_rule(world.get_entrance('Misery Mire', player), lambda state: state.has_sword(player) and state.has_misery_mire_medallion(player)) # sword required to cast magic (!) + add_bunny_rule(world.get_entrance('Skull Woods Final Section', player), player) # bunny cannot use fire rod + add_bunny_rule(world.get_entrance('Hookshot Cave', player), player) + add_bunny_rule(world.get_entrance('Misery Mire', player), player) + add_bunny_rule(world.get_entrance('Turtle Rock', player), player) - set_rule(world.get_entrance('Hookshot Cave', player), lambda state: state.can_lift_rocks(player)) + #add_bunny_rule(world.get_location('Ice Rod Cave', player), player) + add_bunny_rule(world.get_location('Maze Race', player), player) + + add_bunny_rule(world.get_entrance('Wooden Bridge Bush (North)', player), player) + add_bunny_rule(world.get_entrance('Wooden Bridge Bush (South)', player), player) + add_bunny_rule(world.get_entrance('Potion Shop Rock (North)', player), player) + add_bunny_rule(world.get_entrance('Potion Shop Rock (South)', player), player) + add_bunny_rule(world.get_entrance('Graveyard Ladder (Top)', player), player) + add_bunny_rule(world.get_entrance('Graveyard Ladder (Bottom)', player), player) + add_bunny_rule(world.get_entrance('Hyrule Castle Courtyard Bush (North)', player), player) + add_bunny_rule(world.get_entrance('Hyrule Castle Courtyard Bush (South)', player), player) + + add_bunny_rule(world.get_location('Mushroom', player), player) # need pearl to pick up bushes + add_bunny_rule(world.get_entrance('Kakariko Yard Bush (North)', player), player) + add_bunny_rule(world.get_entrance('Kakariko Yard Bush (South)', player), player) + add_bunny_rule(world.get_entrance('Kakariko Southwest Bush (South)', player), player) + add_bunny_rule(world.get_entrance('Kakariko Southwest Bush (North)', player), player) + add_bunny_rule(world.get_entrance('North Fairy Cave Drop', player), player) + add_bunny_rule(world.get_entrance('Lost Woods Hideout Drop', player), player) + add_bunny_rule(world.get_entrance('Hyrule Castle Secret Entrance Drop', player), player) - set_rule(world.get_entrance('East Death Mountain Mirror Spot (Top)', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Death Mountain (Top) Mirror Spot', player), lambda state: state.has_Mirror(player)) - - set_rule(world.get_entrance('East Death Mountain Mirror Spot (Bottom)', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Dark Death Mountain Ledge Mirror Spot (East)', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Dark Death Mountain Ledge Mirror Spot (West)', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Laser Bridge Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Floating Island Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has_sword(player) and state.has_turtle_rock_medallion(player) and state.can_reach('Turtle Rock (Top)', 'Region', player)) # sword required to cast magic (!) - - # new inverted spots - set_rule(world.get_entrance('Post Aga Teleporter', player), lambda state: state.has('Beat Agahnim 1', player)) - set_rule(world.get_entrance('Mire Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Desert Palace Stairs Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Death Mountain Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('East Dark World Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('West Dark World Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('South Dark World Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Catfish Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Potion Shop Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Shopping Mall Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Maze Race Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Desert Palace North Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Death Mountain (Top) Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Graveyard Cave Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Bomb Hut Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Skull Woods Mirror Spot', player), lambda state: state.has_Mirror(player)) - - # inverted flute spots - - set_rule(world.get_entrance('DDM Flute', player), lambda state: state.can_flute(player)) - set_rule(world.get_entrance('NEDW Flute', player), lambda state: state.can_flute(player)) - set_rule(world.get_entrance('WDW Flute', player), lambda state: state.can_flute(player)) - set_rule(world.get_entrance('SDW Flute', player), lambda state: state.can_flute(player)) - set_rule(world.get_entrance('EDW Flute', player), lambda state: state.can_flute(player)) - set_rule(world.get_entrance('DLHL Flute', player), lambda state: state.can_flute(player)) - set_rule(world.get_entrance('DD Flute', player), lambda state: state.can_flute(player)) - set_rule(world.get_entrance('EDDM Flute', player), lambda state: state.can_flute(player)) - set_rule(world.get_entrance('Dark Grassy Lawn Flute', player), lambda state: state.can_flute(player)) - set_rule(world.get_entrance('Hammer Peg Area Flute', player), lambda state: state.can_flute(player)) - - set_rule(world.get_entrance('Inverted Pyramid Hole', player), lambda state: world.open_pyramid[player] or world.goal[player] == 'trinity' or state.has('Beat Agahnim 2', player)) - if world.swords[player] == 'swordless': - swordless_rules(world, player) - - set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has_crystals(world.crystals_needed_for_gt[player], player)) + if not world.is_atgt_swapped(player): + add_bunny_rule(world.get_entrance('Agahnims Tower', player), player) + + #TODO: This needs to get applied after bunny rules, move somewhere else tho + if not world.is_atgt_swapped(player): + add_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has('Beat Agahnim 1', player), 'or') # barrier gets removed after killing agahnim, relevant for entrance shuffle def no_glitches_rules(world, player): - if world.mode[player] != 'inverted': - add_rule(world.get_entrance('Zoras River', player), lambda state: state.has('Flippers', player) or state.can_lift_rocks(player)) - set_rule(world.get_entrance('Zora Waterfall Entryway', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Zora Waterfall Water Drop', player), lambda state: state.has('Flippers', player)) - add_rule(world.get_entrance('Lake Hylia Central Island Pier', player), lambda state: state.has('Flippers', player)) # can be fake flippered to - add_rule(world.get_entrance('Hobo Bridge', player), lambda state: state.has('Flippers', player)) - add_rule(world.get_entrance('Dark Lake Hylia Drop (East)', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player)) - add_rule(world.get_entrance('Dark Lake Hylia Teleporter', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player) and (state.has('Hammer', player) or state.can_lift_rocks(player))) - add_rule(world.get_entrance('Dark Lake Hylia Ledge Drop', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player)) - add_rule(world.get_entrance('East Dark World River Pier', player), lambda state: state.has('Flippers', player)) - else: - add_rule(world.get_entrance('Zoras River', player), lambda state: state.has_Pearl(player) and (state.has('Flippers', player) or state.can_lift_rocks(player))) - add_rule(world.get_entrance('Lake Hylia Central Island Pier', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player)) # can be fake flippered to - add_rule(world.get_entrance('Lake Hylia Island Pier', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player)) # can be fake flippered to - set_rule(world.get_entrance('Lake Hylia Warp', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player)) # can be fake flippered to - set_rule(world.get_entrance('Northeast Light World Warp', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player)) # can be fake flippered to - add_rule(world.get_entrance('Hobo Bridge', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player)) - add_rule(world.get_entrance('Dark Lake Hylia Drop (East)', player), lambda state: state.has('Flippers', player)) - add_rule(world.get_entrance('Dark Lake Hylia Teleporter', player), lambda state: state.has('Flippers', player) and (state.has('Hammer', player) or state.can_lift_rocks(player))) - add_rule(world.get_entrance('Dark Lake Hylia Ledge Drop', player), lambda state: state.has('Flippers', player)) - add_rule(world.get_entrance('East Dark World Pier', player), lambda state: state.has('Flippers', player)) - add_rule(world.get_entrance('East Dark World River Pier', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Zora Waterfall Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Lake Hylia Central Island Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Light World Water Drop', player), lambda state: state.has('Flippers', player)) # can be fake flippered to + set_rule(world.get_entrance('Potion Shop Water Drop', player), lambda state: state.has('Flippers', player)) # can be fake flippered to + set_rule(world.get_entrance('Northeast Light World Water Drop', player), lambda state: state.has('Flippers', player)) # can be fake flippered to + set_rule(world.get_entrance('West Dark World Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('South Dark World Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('East Dark World Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Northeast Dark World Water Drop', player), lambda state: state.has('Flippers', player)) # can be fake flippered to + set_rule(world.get_entrance('Southeast Dark World Water Drop', player), lambda state: state.has('Flippers', player)) # can be fake flippered to + set_rule(world.get_entrance('Catfish Water Drop', player), lambda state: state.has('Flippers', player)) # can be fake flippered to + set_rule(world.get_entrance('Ice Palace Leave Water Drop', player), lambda state: state.has('Flippers', player)) + + add_bunny_rule(world.get_entrance('Zora Waterfall Water Drop', player), player) + add_bunny_rule(world.get_entrance('Lake Hylia Central Island Water Drop', player), player) + add_bunny_rule(world.get_entrance('Light World Water Drop', player), player) + add_bunny_rule(world.get_entrance('Potion Shop Water Drop', player), player) + add_bunny_rule(world.get_entrance('Northeast Light World Water Drop', player), player) + add_bunny_rule(world.get_entrance('West Dark World Water Drop', player), player) + add_bunny_rule(world.get_entrance('South Dark World Water Drop', player), player) + add_bunny_rule(world.get_entrance('East Dark World Water Drop', player), player) + add_bunny_rule(world.get_entrance('Northeast Dark World Water Drop', player), player) + add_bunny_rule(world.get_entrance('Southeast Dark World Water Drop', player), player) + add_bunny_rule(world.get_entrance('Catfish Water Drop', player), player) + add_bunny_rule(world.get_entrance('Ice Palace Leave Water Drop', player), player) - # todo: move some dungeon rules to no glictes logic - see these for examples + # todo: move some dungeon rules to no glicthes logic - see these for examples # add_rule(world.get_entrance('Ganons Tower (Hookshot Room)', player), lambda state: state.has('Hookshot', player) or state.has_Boots(player)) # add_rule(world.get_entrance('Ganons Tower (Double Switch Room)', player), lambda state: state.has('Hookshot', player)) # DMs_room_chests = ['Ganons Tower - DMs Room - Top Left', 'Ganons Tower - DMs Room - Top Right', 'Ganons Tower - DMs Room - Bottom Left', 'Ganons Tower - DMs Room - Bottom Right'] @@ -1075,24 +1065,19 @@ def no_glitches_rules(world, player): def fake_flipper_rules(world, player): - if world.mode[player] != 'inverted': - set_rule(world.get_entrance('Zoras River', player), lambda state: True) - set_rule(world.get_entrance('Lake Hylia Central Island Pier', player), lambda state: True) - set_rule(world.get_entrance('Hobo Bridge', player), lambda state: True) - set_rule(world.get_entrance('Dark Lake Hylia Drop (East)', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player)) - set_rule(world.get_entrance('Dark Lake Hylia Teleporter', player), lambda state: state.has_Pearl(player)) - set_rule(world.get_entrance('Dark Lake Hylia Ledge Drop', player), lambda state: state.has_Pearl(player)) - else: - set_rule(world.get_entrance('Zoras River', player), lambda state: state.has_Pearl(player)) - set_rule(world.get_entrance('Lake Hylia Central Island Pier', player), lambda state: state.has_Pearl(player)) - set_rule(world.get_entrance('Lake Hylia Island Pier', player), lambda state: state.has_Pearl(player)) - set_rule(world.get_entrance('Lake Hylia Warp', player), lambda state: state.has_Pearl(player)) - set_rule(world.get_entrance('Northeast Light World Warp', player), lambda state: state.has_Pearl(player)) - set_rule(world.get_entrance('Hobo Bridge', player), lambda state: state.has_Pearl(player)) - set_rule(world.get_entrance('Dark Lake Hylia Drop (East)', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Dark Lake Hylia Teleporter', player), lambda state: True) - set_rule(world.get_entrance('Dark Lake Hylia Ledge Drop', player), lambda state: True) - set_rule(world.get_entrance('East Dark World Pier', player), lambda state: True) + set_rule(world.get_entrance('Light World Water Drop', player), lambda state: True) + set_rule(world.get_entrance('Potion Shop Water Drop', player), lambda state: True) + set_rule(world.get_entrance('Northeast Light World Water Drop', player), lambda state: True) + set_rule(world.get_entrance('Northeast Dark World Water Drop', player), lambda state: True) + set_rule(world.get_entrance('Southeast Dark World Water Drop', player), lambda state: True) + set_rule(world.get_entrance('Catfish Water Drop', player), lambda state: True) + + add_bunny_rule(world.get_entrance('Light World Water Drop', player), player) + add_bunny_rule(world.get_entrance('Potion Shop Water Drop', player), player) + add_bunny_rule(world.get_entrance('Northeast Light World Water Drop', player), player) + add_bunny_rule(world.get_entrance('Northeast Dark World Water Drop', player), player) + add_bunny_rule(world.get_entrance('Southeast Dark World Water Drop', player), player) + add_bunny_rule(world.get_entrance('Catfish Water Drop', player), player) def forbid_bomb_jump_requirements(world, player): @@ -1100,6 +1085,7 @@ def forbid_bomb_jump_requirements(world, player): for location in DMs_room_chests: add_rule(world.get_location(location, player), lambda state: state.has('Hookshot', player)) set_rule(world.get_entrance('Paradox Cave Bomb Jump', player), lambda state: False) + set_rule(world.get_entrance('Ice Island To East Pier', player), lambda state: False) # Light cones in standard depend on which world we actually are in, not which one the location would normally be # We add Lamp requirements only to those locations which lie in the dark world (or everything if open @@ -1184,33 +1170,29 @@ def add_conditional_lamps(world, player): add_conditional_lamp('Old Man House Front to Back', 'Old Man House', 'Entrance') -def open_rules(world, player): + +def misc_key_rules(world, player): # softlock protection as you can reach the sewers small key door with a guard drop key set_rule(world.get_location('Hyrule Castle - Boomerang Chest', player), lambda state: state.has_sm_key('Small Key (Escape)', player)) set_rule(world.get_location('Hyrule Castle - Zelda\'s Chest', player), lambda state: state.has_sm_key('Small Key (Escape)', player)) def swordless_rules(world, player): - set_rule(world.get_entrance('Tower Altar NW', player), lambda state: True) set_rule(world.get_entrance('Skull Vines NW', player), lambda state: True) set_rule(world.get_entrance('Ice Lobby WS', player), lambda state: state.has('Fire Rod', player) or state.has('Bombos', player)) set_rule(world.get_location('Ice Palace - Freezor Chest', player), lambda state: state.has('Fire Rod', player) or state.has('Bombos', player)) set_rule(world.get_location('Ether Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has('Hammer', player)) + set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has('Hammer', player)) set_rule(world.get_location('Ganon', player), lambda state: state.has('Hammer', player) and state.has_fire_source(player) and state.has('Silver Arrows', player) and state.can_shoot_arrows(player) and state.has_crystals(world.crystals_needed_for_ganon[player], player)) set_rule(world.get_entrance('Ganon Drop', player), lambda state: state.has('Hammer', player)) # need to damage ganon to get tiles to drop + set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has_turtle_rock_medallion(player) and state.can_reach('Turtle Rock (Top)', 'Region', player)) # sword not required to use medallion for opening in swordless (!) + set_rule(world.get_entrance('Misery Mire', player), lambda state: state.has_misery_mire_medallion(player)) # sword not required to use medallion for opening in swordless (!) + if world.mode[player] != 'inverted': - set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has('Cape', player) or state.has('Hammer', player) or state.has('Beat Agahnim 1', player)) # barrier gets removed after killing agahnim, relevant for entrance shuffle - set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has_Pearl(player) and state.has_turtle_rock_medallion(player) and state.can_reach('Turtle Rock (Top)', 'Region', player)) # sword not required to use medallion for opening in swordless (!) - set_rule(world.get_entrance('Misery Mire', player), lambda state: state.has_Pearl(player) and state.has_misery_mire_medallion(player)) # sword not required to use medallion for opening in swordless (!) - set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has('Hammer', player) and state.has_Mirror(player)) - else: - # only need ddm access for aga tower in inverted - set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has_turtle_rock_medallion(player) and state.can_reach('Turtle Rock (Top)', 'Region', player)) # sword not required to use medallion for opening in swordless (!) - set_rule(world.get_entrance('Misery Mire', player), lambda state: state.has_misery_mire_medallion(player)) # sword not required to use medallion for opening in swordless (!) - set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has('Hammer', player)) + set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has('Cape', player) or state.has('Hammer', player)) std_kill_rooms = { @@ -1307,20 +1289,20 @@ def standard_rules(world, player): rule_list, debug_path = find_rules_for_zelda_delivery(world, player) set_rule(world.get_location('Zelda Drop Off', player), lambda state: state.has('Zelda Herself', player) and check_rule_list(state, rule_list)) - for location in ['Mushroom', 'Bottle Merchant', 'Flute Spot', 'Sunken Treasure', 'Purple Chest', 'Maze Race']: + for location in ['Mushroom', 'Bottle Merchant', 'Flute Spot', 'Sunken Treasure', 'Purple Chest']: add_rule(world.get_location(location, player), lambda state: state.has('Zelda Delivered', player)) - for entrance in ['Blinds Hideout', 'Zoras River', 'Kings Grave Outer Rocks', 'Dam', 'Tavern North', 'Chicken House', + for entrance in ['Blinds Hideout', 'Kings Grave Outer Rocks', 'Dam', 'Tavern North', 'Chicken House', 'Aginahs Cave', 'Sahasrahlas Hut', 'Kakariko Well Drop', 'Kakariko Well Cave', 'Blacksmiths Hut', - 'Bat Cave Drop Ledge', 'Bat Cave Cave', 'Sick Kids House', 'Hobo Bridge', + 'Bat Cave Ledge Peg', 'Bat Cave Cave', 'Sick Kids House', 'Wooden Bridge Bush (South)', 'Lost Woods Hideout Drop', 'Lost Woods Hideout Stump', 'Lumberjack Tree Tree', - 'Lumberjack Tree Cave', 'Mini Moldorm Cave', 'Ice Rod Cave', 'Lake Hylia Central Island Pier', - 'Bonk Rock Cave', 'Library', 'Potion Shop', 'Two Brothers House (East)', 'Desert Palace Stairs', + 'Lumberjack Tree Cave', 'Mini Moldorm Cave', 'Ice Rod Cave', 'Light World Water Drop', + 'Bonk Rock Cave', 'Library', 'Potion Shop', 'Two Brothers House (East)', 'Desert Statue Move', 'Eastern Palace', 'Master Sword Meadow', 'Sanctuary', 'Sanctuary Grave', - 'Death Mountain Entrance Rock', 'Flute Spot 1', 'Dark Desert Teleporter', 'East Hyrule Teleporter', + 'Death Mountain Entrance Rock', 'Light World Water Drop', 'East Hyrule Teleporter', 'South Hyrule Teleporter', 'Kakariko Teleporter', 'Elder House (East)', 'Elder House (West)', 'North Fairy Cave', 'North Fairy Cave Drop', 'Lost Woods Gamble', 'Snitch Lady (East)', - 'Snitch Lady (West)', 'Tavern (Front)', 'Bush Covered House', 'Light World Bomb Hut', + 'Snitch Lady (West)', 'Tavern (Front)', 'Kakariko Yard Bush (South)', 'Kakariko Southwest Bush (North)', 'Kakariko Shop', 'Long Fairy Cave', 'Good Bee Cave', '20 Rupee Cave', 'Cave Shop (Lake Hylia)', 'Waterfall of Wishing', 'Hyrule Castle Main Gate', '50 Rupee Cave', 'Bonk Fairy (Light)', 'Fortune Teller (Light)', 'Lake Hylia Fairy', 'Light Hype Fairy', 'Desert Fairy', @@ -1790,7 +1772,7 @@ def set_bunny_rules(world, player, inverted): bunny_impassable_caves = ['Bumper Cave (top)', 'Bumper Cave (bottom)', 'Two Brothers House', 'Hookshot Cave (Middle)', 'Pyramid', 'Spiral Cave (Top)', 'Fairy Ascension Cave (Drop)'] bunny_accessible_locations = ['Link\'s Uncle', 'Sahasrahla', 'Sick Kid', 'Lost Woods Hideout', 'Lumberjack Tree', - 'Checkerboard Cave', 'Potion Shop', 'Spectacle Rock Cave', 'Pyramid', + 'Checkerboard Cave', 'Potion Shop', 'Spectacle Rock Cave', 'Pyramid', 'Old Man', 'Hype Cave - Generous Guy', 'Peg Cave', 'Bumper Cave Ledge', 'Dark Blacksmith Ruins', 'Spectacle Rock', 'Bombos Tablet', 'Ether Tablet', 'Purple Chest', 'Blacksmith', 'Missing Smith', 'Master Sword Pedestal', 'Bottle Merchant', 'Sunken Treasure', 'Desert Ledge', diff --git a/source/item/District.py b/source/item/District.py index 9d858ac2..96599cc6 100644 --- a/source/item/District.py +++ b/source/item/District.py @@ -131,7 +131,7 @@ def resolve_districts(world): if not location.item and location.real: district.locations.add(location.name) for ext in region.exits: - if ext.connected_region not in visited: + if ext.connected_region and ext.connected_region not in visited: queue.appendleft(ext.connected_region) elif region.type == RegionType.Dungeon and region.dungeon: district.dungeons.add(region.dungeon.name) @@ -150,10 +150,10 @@ def find_reachable_locations(state, player): return check_set -inaccessible_regions_std = {'Desert Palace Lone Stairs', 'Bumper Cave Ledge', 'Skull Woods Forest (West)', +inaccessible_regions_std = {'Desert Palace Mouth', 'Bumper Cave Ledge', 'Skull Woods Forest (West)', 'Dark Death Mountain Ledge', 'Dark Death Mountain Isolated Ledge', 'Death Mountain Floating Island (Dark World)'} -inaccessible_regions_inv = {'Desert Palace Lone Stairs', 'Maze Race Ledge', 'Desert Ledge', +inaccessible_regions_inv = {'Desert Palace Mouth', 'Maze Race Ledge', 'Desert Ledge', 'Desert Palace Entrance (North) Spot', 'Hyrule Castle Ledge', 'Death Mountain Return Ledge'} diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index 8ac2ee24..3f198733 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -1845,19 +1845,38 @@ Inverted_Bomb_Shop_Options = [ # They link together separate parts of the world we need to divide into regions mandatory_connections = [('Links House S&Q', 'Links House'), ('Lake Hylia Central Island Pier', 'Lake Hylia Central Island'), - ('Zoras River', 'Zoras River'), + ('Lake Hylia Central Island Water Drop', 'Lake Hylia Water'), + ('Potion Shop Water Drop', 'Lake Hylia Water'), + ('Northeast Light World Water Drop', 'Lake Hylia Water'), + ('Zora Waterfall Water Drop', 'Lake Hylia Water'), + ('Light World Water Drop', 'Lake Hylia Water'), + ('East Dark World Water Drop', 'Dark Lake Hylia Water'), + ('South Dark World Water Drop', 'Dark Lake Hylia Water'), + ('Southeast Dark World Water Drop', 'Dark Lake Hylia Water'), + ('Northeast Dark World Water Drop', 'Dark Lake Hylia Water'), + ('Catfish Water Drop', 'Dark Lake Hylia Water'), + ('Ice Palace Leave Water Drop', 'Dark Lake Hylia Water'), + ('West Dark World Water Drop', 'Dark Lake Hylia Water'), + ('Zoras Domain', 'Zoras Domain'), ('Kings Grave Outer Rocks', 'Kings Grave Area'), ('Kings Grave Inner Rocks', 'Light World'), ('Kakariko Well (top to bottom)', 'Kakariko Well (bottom)'), ('Kakariko Well (top to back)', 'Kakariko Well (back)'), ('Master Sword Meadow', 'Master Sword Meadow'), - ('Hobo Bridge', 'Hobo Bridge'), - ('Bat Cave Drop Ledge', 'Bat Cave Drop Ledge'), + ('Hobo Pier', 'Hobo Bridge'), + ('Bat Cave Ledge Peg', 'Bat Cave Ledge'), + ('Bat Cave Ledge Peg (East)', 'Light World'), ('Bat Cave Door', 'Bat Cave (left)'), ('Lost Woods Hideout (top to bottom)', 'Lost Woods Hideout (bottom)'), ('Lumberjack Tree (top to bottom)', 'Lumberjack Tree (bottom)'), ('Blinds Hideout N', 'Blinds Hideout (Top)'), - ('Desert Palace Stairs', 'Desert Palace Stairs'), + ('Light World Pier', 'Light World'), + ('Potion Shop Pier', 'Potion Shop Area'), + ('Wooden Bridge Bush (North)', 'Light World'), + ('Wooden Bridge Bush (South)', 'Potion Shop Area'), + ('Potion Shop Rock (South)', 'Northeast Light World'), + ('Potion Shop Rock (North)', 'Potion Shop Area'), + ('Desert Statue Move', 'Desert Palace Stairs'), ('Desert Palace Stairs Drop', 'Light World'), ('Desert Palace Entrance (North) Rocks', 'Desert Palace Entrance (North) Spot'), ('Desert Ledge Return Rocks', 'Desert Ledge'), @@ -1872,22 +1891,18 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Old Man Cave Dropdown', 'Old Man Cave'), ('Old Man House Front to Back', 'Old Man House Back'), ('Old Man House Back to Front', 'Old Man House'), - ('Broken Bridge (West)', 'East Death Mountain (Bottom)'), - ('Broken Bridge (East)', 'Death Mountain'), + ('DM Broken Bridge (West)', 'East Death Mountain (Bottom)'), + ('DM Broken Bridge (East)', 'Death Mountain (West Bottom)'), ('East Death Mountain Drop', 'East Death Mountain (Bottom)'), ('Spiral Cave Ledge Access', 'Spiral Cave Ledge'), ('Spiral Cave Ledge Drop', 'East Death Mountain (Bottom)'), ('Spiral Cave (top to bottom)', 'Spiral Cave (Bottom)'), - ('East Death Mountain (Top)', 'East Death Mountain (Top)'), - ('Death Mountain (Top)', 'Death Mountain (Top)'), - ('Death Mountain Drop', 'Death Mountain'), - ('Dark Lake Hylia Drop (East)', 'Dark Lake Hylia'), - ('Dark Lake Hylia Drop (South)', 'Dark Lake Hylia'), - ('Dark Lake Hylia Teleporter', 'Dark Lake Hylia'), - ('Dark Lake Hylia Ledge Drop', 'Dark Lake Hylia'), + ('DM Hammer Bridge (West)', 'East Death Mountain (Top)'), + ('DM Hammer Bridge (East)', 'Death Mountain (Top)'), + ('Death Mountain Drop', 'Death Mountain (West Bottom)'), ('East Dark World Pier', 'East Dark World'), - ('South Dark World Bridge', 'South Dark World'), - ('East Dark World Bridge', 'East Dark World'), + ('Hammer Bridge Pegs (North)', 'South Dark World'), + ('Hammer Bridge Pegs (South)', 'East Dark World'), ('Village of Outcasts Heavy Rock', 'West Dark World'), ('Village of Outcasts Drop', 'South Dark World'), ('Village of Outcasts Eastern Rocks', 'Hammer Peg Area'), @@ -1896,8 +1911,8 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Grassy Lawn Pegs', 'West Dark World'), ('West Dark World Gap', 'West Dark World'), ('East Dark World Broken Bridge Pass', 'East Dark World'), - ('Catfish Exit Rock', 'Northeast Dark World'), - ('Catfish Entrance Rock', 'Catfish'), + ('Dark Witch Rock (North)', 'Northeast Dark World'), + ('Dark Witch Rock (South)', 'Catfish Area'), ('Northeast Dark World Broken Bridge Pass', 'Northeast Dark World'), ('Bumper Cave Entrance Rock', 'Bumper Cave Entrance'), ('Bumper Cave Entrance Drop', 'West Dark World'), @@ -1928,132 +1943,146 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Ganon Drop', 'Bottom of Pyramid'), ('Pyramid Drop', 'East Dark World'), ('Maze Race Ledge Drop', 'Light World'), - ('Desert Ledge Drop', 'Light World') + ('Hyrule Castle Ledge Drop', 'Light World'), + ('Desert Ledge Drop', 'Light World'), + ('Lake Hylia Whirlpool', 'Northeast Light World'), + ('Hyrule Castle Ledge Courtyard Drop', 'Hyrule Castle Courtyard'), + ('Southeast Dark World Pier', 'Southeast Dark World'), + ('Northeast Dark World River Pier', 'Northeast Dark World'), + ('Fairy Ascension Ledge Access', 'Fairy Ascension Ledge'), + ('Hyrule Castle Courtyard Bush (North)', 'Hyrule Castle Courtyard'), + ('Hyrule Castle Courtyard Bush (South)', 'Hyrule Castle Secret Entrance Area'), + ('Turtle Rock Drop', 'Dark Death Mountain (Top)'), + ('Floating Island Drop', 'Dark Death Mountain (Top)'), + ('Dark Desert Drop', 'Dark Desert'), + ('Kakariko Yard Bush (North)', 'Light World'), + ('Kakariko Yard Bush (South)', 'Bush Covered Lawn'), + ('Bush Covered Lawn Mirror Spot', 'Dark Grassy Lawn'), + ('Kakariko Southwest Bush (South)', 'Light World'), + ('Kakariko Southwest Bush (North)', 'Bomb Hut Area'), + ('Hyrule Castle Main Gate', 'Hyrule Castle Courtyard'), + ('Spectacle Rock Drop', 'Death Mountain (Top)'), + ('Desert Teleporter Drop', 'Light World'), + ('Dark Death Mountain Drop (West)', 'Dark Death Mountain (West Bottom)'), + ('Graveyard Ledge Drop', 'Light World'), + ('Cave 45 Ledge Drop', 'Light World'), + ('Checkerboard Ledge Drop', 'Light World'), + ('Hyrule Castle Main Gate (North)', 'Light World') ] open_mandatory_connections = [('Sanctuary S&Q', 'Sanctuary'), ('Old Man S&Q', 'Old Man House'), ('Other World S&Q', 'East Dark World'), + ('Flute Spot 1', 'Death Mountain (West Bottom)'), + ('Flute Spot 2', 'Potion Shop Area'), + ('Flute Spot 3', 'Light World'), + ('Flute Spot 4', 'Light World'), + ('Flute Spot 5', 'Light World'), + ('Flute Spot 6', 'Desert Teleporter Ledge'), + ('Flute Spot 7', 'Light World'), + ('Flute Spot 8', 'Light World'), + ('LW Flute', 'Flute Sky'), + ('NWLW Flute', 'Flute Sky'), + ('ZLW Flute', 'Flute Sky'), + ('DM Flute', 'Flute Sky'), + ('EDM Flute', 'Flute Sky'), ('Lake Hylia Central Island Teleporter', 'Dark Lake Hylia Central Island'), - ('Zora Waterfall Entryway', 'Zora Waterfall Entryway'), - ('Zora Waterfall Water Drop', 'Light World'), ('Kings Grave Mirror Spot', 'Kings Grave Area'), - ('Hyrule Castle Ledge Courtyard Drop', 'Hyrule Castle Courtyard'), - ('Hyrule Castle Main Gate', 'Hyrule Castle Courtyard'), - ('Flute Spot 1', 'Death Mountain'), - ('Spectacle Rock Drop', 'Death Mountain (Top)'), ('Top of Pyramid', 'East Dark World'), ('Lake Hylia Island Mirror Spot', 'Lake Hylia Island'), ('Lake Hylia Central Island Mirror Spot', 'Lake Hylia Central Island'), ('Hyrule Castle Ledge Mirror Spot', 'Hyrule Castle Ledge'), - ('Maze Race Mirror Spot', 'Maze Race Ledge'), - ('Bat Cave Drop Ledge Mirror Spot', 'Bat Cave Drop Ledge'), - ('East Dark World River Pier', 'East Dark World'), + ('Dig Game Mirror Spot', 'Maze Race Ledge'), + ('Bat Cave Drop Ledge Mirror Spot', 'Bat Cave Ledge'), ('Bumper Cave Entrance Mirror Spot', 'Death Mountain Entrance'), ('Bumper Cave Ledge Mirror Spot', 'Death Mountain Return Ledge'), ('Desert Ledge Mirror Spot', 'Desert Ledge'), - ('Desert Ledge (Northeast) Mirror Spot', 'Desert Ledge (Northeast)'), + ('Desert Ledge (Northeast) Mirror Spot', 'Desert Checkerboard Ledge'), ('Desert Palace Entrance (North) Mirror Spot', 'Desert Palace Entrance (North) Spot'), - ('Dark Desert Teleporter', 'Dark Desert'), - ('Desert Palace Stairs Mirror Spot', 'Desert Palace Stairs'), + ('Desert Teleporter', 'Dark Desert'), + ('Mire To Desert Palace Stairs Mirror Spot', 'Desert Palace Stairs'), ('East Hyrule Teleporter', 'East Dark World'), ('South Hyrule Teleporter', 'South Dark World'), ('Kakariko Teleporter', 'West Dark World'), ('Death Mountain Teleporter', 'Dark Death Mountain (West Bottom)'), ('Fairy Ascension Mirror Spot', 'Fairy Ascension Plateau'), - ('Fairy Ascension Ledge', 'Fairy Ascension Ledge'), ('Spectacle Rock Mirror Spot', 'Spectacle Rock'), - ('Dark Death Mountain Drop (West)', 'Dark Death Mountain (West Bottom)'), ('East Death Mountain (Top) Mirror Spot', 'East Death Mountain (Top)'), ('Turtle Rock Teleporter', 'Turtle Rock (Top)'), - ('Turtle Rock Drop', 'Dark Death Mountain (Top)'), - ('Floating Island Drop', 'Dark Death Mountain (Top)'), - ('Floating Island Mirror Spot', 'Death Mountain Floating Island (Light World)'), + ('Dark Grassy Lawn Mirror Spot', 'Bush Covered Lawn'), + ('Dark Floating Island Mirror Spot', 'Death Mountain Floating Island'), ('East Death Mountain Teleporter', 'Dark Death Mountain (East Bottom)'), ('Isolated Ledge Mirror Spot', 'Fairy Ascension Ledge'), ('Spiral Cave Mirror Spot', 'Spiral Cave Ledge'), ('Mimic Cave Mirror Spot', 'Mimic Cave Ledge'), ('Cave 45 Mirror Spot', 'Cave 45 Ledge'), ('Bombos Tablet Mirror Spot', 'Bombos Tablet Ledge'), - ('Graveyard Ledge Mirror Spot', 'Graveyard Ledge'), - ('Graveyard Ledge Drop', 'Light World'), - ('Cave 45 Ledge Drop', 'Light World'), - ('Checkerboard Ledge Drop', 'Light World'), - ('Hyrule Castle Main Gate (North)', 'Light World'), - ('Hyrule Castle Ledge Drop', 'Light World'), + ('Graveyard Ledge Mirror Spot', 'Graveyard Ledge') ] inverted_mandatory_connections = [('Sanctuary S&Q', 'Dark Sanctuary Hint'), - ('Old Man S&Q', 'Old Man House'), + ('Old Man S&Q', 'Dark Death Mountain (West Bottom)'), ('Other World S&Q', 'Hyrule Castle Ledge'), ('Lake Hylia Island Pier', 'Lake Hylia Island'), - ('Lake Hylia Warp', 'Northeast Light World'), - ('Northeast Light World Warp', 'Light World'), - ('Waterfall of Wishing Cave', 'Waterfall of Wishing Cave'), - ('Northeast Light World Return', 'Northeast Light World'), - ('Hyrule Castle Ledge Courtyard Drop', 'Light World'), - ('DDM Flute', 'The Sky'), - ('DDM Landing', 'Dark Death Mountain'), - ('NEDW Flute', 'The Sky'), - ('NEDW Landing', 'Northeast Dark World'), - ('WDW Flute', 'The Sky'), - ('WDW Landing', 'West Dark World'), - ('SDW Flute', 'The Sky'), - ('SDW Landing', 'South Dark World'), - ('EDW Flute', 'The Sky'), - ('EDW Landing', 'East Dark World'), - ('DLHL Flute', 'The Sky'), - ('DLHL Landing', 'Dark Lake Hylia Ledge'), - ('DD Flute', 'The Sky'), - ('DD Landing', 'Dark Desert Ledge'), - ('EDDM Flute', 'The Sky'), - ('Dark Grassy Lawn Flute', 'The Sky'), - ('Hammer Peg Area Flute', 'The Sky'), - ('Dark Lake Hylia Ledge Pier', 'Dark Lake Hylia Ledge'), - ('Ice Palace Missing Wall', 'Dark Lake Hylia Central Island'), - ('Dark Lake Hylia Shallows', 'Dark Lake Hylia'), - ('East Dark World River Pier', 'Northeast Dark World'), - ('Fairy Ascension Ledge Access', 'Fairy Ascension Ledge'), + ('Spectacle Rock Leave', 'Death Mountain (Top)'), + ('Spectacle Rock Approach', 'Spectacle Rock'), + ('Checkerboard Ledge Approach', 'Desert Checkerboard Ledge'), + ('Checkerboard Ledge Leave', 'Light World'), + ('Cave 45 Approach', 'Cave 45 Ledge'), + ('Cave 45 Leave', 'Light World'), + ('Flute Spot 1', 'Dark Death Mountain (West Bottom)'), + ('Flute Spot 2', 'Northeast Dark World'), + ('Flute Spot 3', 'West Dark World'), + ('Flute Spot 4', 'South Dark World'), + ('Flute Spot 5', 'East Dark World'), + ('Flute Spot 6', 'Dark Desert Ledge'), + ('Flute Spot 7', 'South Dark World'), + ('Flute Spot 8', 'Southeast Dark World'), + ('DDM Flute', 'Flute Sky'), + ('NEDW Flute', 'Flute Sky'), + ('WDW Flute', 'Flute Sky'), + ('SDW Flute', 'Flute Sky'), + ('EDW Flute', 'Flute Sky'), + ('DD Flute', 'Flute Sky'), + ('DLHL Flute', 'Flute Sky'), + ('EDDM Flute', 'Flute Sky'), + ('Dark Grassy Lawn Flute', 'Flute Sky'), + ('Hammer Peg Area Flute', 'Flute Sky'), + ('Dark Death Mountain Ladder (Bottom)', 'Dark Death Mountain (Top)'), + ('Dark Death Mountain Ladder (Top)', 'Dark Death Mountain (West Bottom)'), + ('Ice Palace Approach', 'Dark Lake Hylia Central Island'), + ('Floating Island Bridge (East)', 'Death Mountain Floating Island'), + ('Floating Island Bridge (West)', 'East Death Mountain (Top)'), ('Post Aga Teleporter', 'Light World'), - ('Secret Passage Inner Bushes', 'Light World'), - ('Secret Passage Outer Bushes', 'Hyrule Castle Secret Entrance Area'), - ('Potion Shop Inner Bushes', 'Light World'), - ('Potion Shop Outer Bushes', 'Potion Shop Area'), - ('Potion Shop Inner Rock', 'Northeast Light World'), - ('Potion Shop Outer Rock', 'Potion Shop Area'), - ('Potion Shop River Drop', 'River'), - ('Graveyard Cave Inner Bushes', 'Light World'), - ('Graveyard Cave Outer Bushes', 'Graveyard Cave Area'), + ('Graveyard Ladder (Top)', 'Light World'), + ('Graveyard Ladder (Bottom)', 'Graveyard Ledge'), ('Graveyard Cave Mirror Spot', 'West Dark World'), - ('Light World River Drop', 'River'), - ('Light World Pier', 'Light World'), - ('Potion Shop Pier', 'Potion Shop Area'), + ('Pyramid Uncle Mirror Spot', 'East Dark World'), ('Mimic Cave Ledge Access', 'Mimic Cave Ledge'), ('Mimic Cave Ledge Drop', 'East Death Mountain (Bottom)'), ('Turtle Rock Tail Drop', 'Turtle Rock (Top)'), - ('Turtle Rock Drop', 'Dark Death Mountain'), - ('Floating Island Drop', 'Dark Death Mountain'), ('Dark Lake Hylia Central Island Teleporter', 'Lake Hylia Central Island'), ('Dark Desert Teleporter', 'Light World'), ('East Dark World Teleporter', 'Light World'), ('South Dark World Teleporter', 'Light World'), ('West Dark World Teleporter', 'Light World'), - ('Dark Death Mountain Teleporter (West)', 'Death Mountain'), + ('Dark Death Mountain Teleporter (West)', 'Death Mountain (West Bottom)'), ('Dark Death Mountain Teleporter (East)', 'East Death Mountain (Top)'), ('Dark Death Mountain Teleporter (East Bottom)', 'East Death Mountain (Bottom)'), ('Mire Mirror Spot', 'Dark Desert'), - ('Dark Desert Drop', 'Dark Desert'), + ('Bombos Tablet Ladder (Top)', 'Light World'), + ('Bombos Tablet Ladder (Bottom)', 'Bombos Tablet Ledge'), ('Desert Palace Stairs Mirror Spot', 'Dark Desert'), ('Desert Palace North Mirror Spot', 'Dark Desert'), - ('Maze Race Mirror Spot', 'West Dark World'), + ('Maze Race Mirror Spot', 'South Dark World'), ('Lake Hylia Central Island Mirror Spot', 'Dark Lake Hylia Central Island'), ('Hammer Peg Area Mirror Spot', 'Hammer Peg Area'), - ('Bumper Cave Ledge Mirror Spot', 'Bumper Cave Ledge'), + ('Mountain Exit Ledge Mirror Spot', 'Bumper Cave Ledge'), ('Bumper Cave Entrance Mirror Spot', 'Bumper Cave Entrance'), - ('Death Mountain Mirror Spot', 'Dark Death Mountain'), - ('East Death Mountain Mirror Spot (Top)', 'Dark Death Mountain'), + ('Death Mountain Mirror Spot', 'Dark Death Mountain (West Bottom)'), + ('East Death Mountain Mirror Spot (Top)', 'Dark Death Mountain (Top)'), ('East Death Mountain Mirror Spot (Bottom)', 'Dark Death Mountain (East Bottom)'), - ('Death Mountain (Top) Mirror Spot', 'Dark Death Mountain'), + ('Death Mountain (Top) Mirror Spot', 'Dark Death Mountain (Top)'), ('Dark Death Mountain Ledge Mirror Spot (East)', 'Dark Death Mountain Ledge'), ('Dark Death Mountain Ledge Mirror Spot (West)', 'Dark Death Mountain Ledge'), ('Floating Island Mirror Spot', 'Death Mountain Floating Island (Dark World)'), @@ -2062,14 +2091,9 @@ inverted_mandatory_connections = [('Sanctuary S&Q', 'Dark Sanctuary Hint'), ('West Dark World Mirror Spot', 'West Dark World'), ('South Dark World Mirror Spot', 'South Dark World'), ('Potion Shop Mirror Spot', 'Northeast Dark World'), - ('Catfish Mirror Spot', 'Catfish'), - ('Shopping Mall Mirror Spot', 'Dark Lake Hylia Ledge'), + ('Catfish Mirror Spot', 'Catfish Area'), + ('Shopping Mall Mirror Spot', 'Southeast Dark World'), ('Skull Woods Mirror Spot', 'Skull Woods Forest (West)'), - ('Bush Covered Lawn Inner Bushes', 'Light World'), - ('Bush Covered Lawn Outer Bushes', 'Bush Covered Lawn'), - ('Bush Covered Lawn Mirror Spot', 'Dark Grassy Lawn'), - ('Bomb Hut Inner Bushes', 'Light World'), - ('Bomb Hut Outer Bushes', 'Bomb Hut Area'), ('Bomb Hut Mirror Spot', 'West Dark World') ] @@ -2080,6 +2104,7 @@ default_connections = {'Waterfall of Wishing': 'Waterfall of Wishing', 'Lumberjack House': 'Lumberjack House', 'Hyrule Castle Secret Entrance Drop': 'Hyrule Castle Secret Entrance', 'Hyrule Castle Secret Entrance Stairs': 'Hyrule Castle Secret Entrance', + 'Hyrule Castle Secret Entrance Exit': 'Hyrule Castle Secret Entrance Area', 'Bonk Fairy (Light)': 'Bonk Fairy (Light)', 'Lake Hylia Fairy': 'Lake Hylia Healer Fairy', 'Lake Hylia Fortune Teller': 'Lake Hylia Fortune Teller', @@ -2142,17 +2167,17 @@ default_connections = {'Waterfall of Wishing': 'Waterfall of Wishing', 'Sanctuary Grave': 'Sewer Drop', 'Sanctuary Exit': 'Light World', 'Old Man House (Bottom)': 'Old Man House', - 'Old Man House Exit (Bottom)': 'Death Mountain', + 'Old Man House Exit (Bottom)': 'Death Mountain (West Bottom)', 'Old Man House (Top)': 'Old Man House Back', - 'Old Man House Exit (Top)': 'Death Mountain', + 'Old Man House Exit (Top)': 'Death Mountain (West Bottom)', 'Death Mountain Return Cave (East)': 'Death Mountain Return Cave (right)', - 'Death Mountain Return Cave Exit (East)': 'Death Mountain', + 'Death Mountain Return Cave Exit (East)': 'Death Mountain (West Bottom)', 'Spectacle Rock Cave Peak': 'Spectacle Rock Cave (Peak)', 'Spectacle Rock Cave (Bottom)': 'Spectacle Rock Cave (Bottom)', 'Spectacle Rock Cave': 'Spectacle Rock Cave (Top)', - 'Spectacle Rock Cave Exit': 'Death Mountain', - 'Spectacle Rock Cave Exit (Top)': 'Death Mountain', - 'Spectacle Rock Cave Exit (Peak)': 'Death Mountain', + 'Spectacle Rock Cave Exit': 'Death Mountain (West Bottom)', + 'Spectacle Rock Cave Exit (Top)': 'Death Mountain (West Bottom)', + 'Spectacle Rock Cave Exit (Peak)': 'Death Mountain (West Bottom)', 'Paradox Cave (Bottom)': 'Paradox Cave Front', 'Paradox Cave (Middle)': 'Paradox Cave', 'Paradox Cave (Top)': 'Paradox Cave', @@ -2194,7 +2219,9 @@ default_connections = {'Waterfall of Wishing': 'Waterfall of Wishing', 'Dark Desert Fairy': 'Dark Desert Healer Fairy', 'Spike Cave': 'Spike Cave', 'Hookshot Cave': 'Hookshot Cave (Front)', + 'Hookshot Cave Front Exit': 'Dark Death Mountain (Top)', 'Superbunny Cave (Top)': 'Superbunny Cave (Top)', + 'Superbunny Cave Exit (Top)': 'Dark Death Mountain (Top)', 'Cave Shop (Dark Death Mountain)': 'Cave Shop (Dark Death Mountain)', 'Superbunny Cave (Bottom)': 'Superbunny Cave (Bottom)', 'Superbunny Cave Exit (Bottom)': 'Dark Death Mountain (East Bottom)', @@ -2205,11 +2232,10 @@ default_connections = {'Waterfall of Wishing': 'Waterfall of Wishing', open_default_connections = {'Links House': 'Links House', 'Links House Exit': 'Light World', - 'Hyrule Castle Secret Entrance Exit': 'Hyrule Castle Courtyard', 'Old Man Cave (West)': 'Old Man Cave Ledge', 'Old Man Cave (East)': 'Old Man Cave', 'Old Man Cave Exit (West)': 'Light World', - 'Old Man Cave Exit (East)': 'Death Mountain', + 'Old Man Cave Exit (East)': 'Death Mountain (West Bottom)', 'Death Mountain Return Cave (West)': 'Death Mountain Return Cave (left)', 'Death Mountain Return Cave Exit (West)': 'Death Mountain Return Ledge', 'Big Bomb Shop': 'Big Bomb Shop', @@ -2218,8 +2244,6 @@ open_default_connections = {'Links House': 'Links House', 'Bumper Cave Exit (Top)': 'Bumper Cave Ledge', 'Bumper Cave Exit (Bottom)': 'West Dark World', 'Dark Death Mountain Fairy': 'Dark Death Mountain Healer Fairy', - 'Superbunny Cave Exit (Top)': 'Dark Death Mountain (Top)', - 'Hookshot Cave Front Exit': 'Dark Death Mountain (Top)', 'Pyramid Hole': 'Pyramid', 'Pyramid Exit': 'Pyramid Ledge', 'Pyramid Entrance': 'Bottom of Pyramid' @@ -2227,24 +2251,21 @@ open_default_connections = {'Links House': 'Links House', inverted_default_connections = {'Links House': 'Big Bomb Shop', 'Links House Exit': 'South Dark World', - 'Hyrule Castle Secret Entrance Exit': 'Light World', 'Old Man Cave (West)': 'Bumper Cave (bottom)', 'Old Man Cave (East)': 'Death Mountain Return Cave (left)', 'Old Man Cave Exit (West)': 'West Dark World', - 'Old Man Cave Exit (East)': 'Dark Death Mountain', + 'Old Man Cave Exit (East)': 'Dark Death Mountain (West Bottom)', 'Death Mountain Return Cave (West)': 'Bumper Cave (top)', - 'Death Mountain Return Cave Exit (West)': 'Death Mountain', + 'Death Mountain Return Cave Exit (West)': 'Death Mountain (West Bottom)', 'Big Bomb Shop': 'Links House', 'Bumper Cave (Bottom)': 'Old Man Cave Ledge', 'Bumper Cave (Top)': 'Dark Death Mountain Healer Fairy', - 'Dark Sanctuary Hint Exit': 'West Dark World', 'Bumper Cave Exit (Top)': 'Death Mountain Return Ledge', 'Bumper Cave Exit (Bottom)': 'Light World', 'Dark Death Mountain Fairy': 'Old Man Cave', - 'Superbunny Cave Exit (Top)': 'Dark Death Mountain', - 'Hookshot Cave Front Exit': 'Dark Death Mountain', + 'Dark Sanctuary Hint Exit': 'West Dark World', 'Inverted Pyramid Hole': 'Pyramid', - 'Pyramid Exit': 'Light World', + 'Pyramid Exit': 'Hyrule Castle Courtyard', 'Inverted Pyramid Entrance': 'Bottom of Pyramid' } @@ -2265,6 +2286,7 @@ default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert South ('Hyrule Castle Entrance (South)', 'Hyrule Castle South Portal'), ('Hyrule Castle Entrance (West)', 'Hyrule Castle West Portal'), ('Hyrule Castle Entrance (East)', 'Hyrule Castle East Portal'), + ('Hyrule Castle Exit (South)', 'Hyrule Castle Courtyard'), ('Hyrule Castle Exit (West)', 'Hyrule Castle Ledge'), ('Hyrule Castle Exit (East)', 'Hyrule Castle Ledge'), @@ -2309,7 +2331,7 @@ open_default_dungeon_connections = [('Agahnims Tower', 'Agahnims Tower Portal'), inverted_default_dungeon_connections = [('Agahnims Tower', 'Ganons Tower Portal'), ('Agahnims Tower Exit', 'Dark Death Mountain'), - ('Ice Palace Exit', 'Dark Lake Hylia'), + ('Ice Palace Exit', 'Dark Lake Hylia Water'), ('Turtle Rock Exit (Front)', 'Dark Death Mountain'), ('Ganons Tower', 'Agahnims Tower Portal'), ('Ganons Tower Exit', 'Hyrule Castle Ledge') diff --git a/test/inverted/TestInverted.py b/test/inverted/TestInverted.py index 6861329d..75c945e6 100644 --- a/test/inverted/TestInverted.py +++ b/test/inverted/TestInverted.py @@ -3,10 +3,9 @@ from DoorShuffle import link_doors from Doors import create_doors from Dungeons import create_dungeons, get_dungeon_item_pool from EntranceShuffle import link_entrances -from InvertedRegions import create_inverted_regions from ItemList import generate_itempool, difficulties from Items import ItemFactory -from Regions import mark_light_world_regions, create_dungeon_regions, create_shops +from Regions import create_regions, mark_light_dark_world_regions, create_dungeon_regions, create_shops from RoomData import create_rooms from Rules import set_rules from test.TestBase import TestBase @@ -18,7 +17,7 @@ class TestInverted(TestBase): {1: True}, {1: False}, False, None, {1: False}) self.world.difficulty_requirements[1] = difficulties['normal'] self.world.intensity = {1: 1} - create_inverted_regions(self.world, 1) + create_regions(self.world, 1) create_dungeon_regions(self.world, 1) create_shops(self.world, 1) create_doors(self.world, 1) @@ -32,5 +31,5 @@ class TestInverted(TestBase): self.world.itempool.extend(ItemFactory(['Green Pendant', 'Red Pendant', 'Blue Pendant', 'Beat Agahnim 1', 'Beat Agahnim 2', 'Crystal 1', 'Crystal 2', 'Crystal 3', 'Crystal 4', 'Crystal 5', 'Crystal 6', 'Crystal 7'], 1)) self.world.get_location('Agahnim 1', 1).item = None self.world.get_location('Agahnim 2', 1).item = None - mark_light_world_regions(self.world, 1) + mark_light_dark_world_regions(self.world, 1) set_rules(self.world, 1) diff --git a/test/inverted/TestInvertedBombRules.py b/test/inverted/TestInvertedBombRules.py index 72039712..974ae797 100644 --- a/test/inverted/TestInvertedBombRules.py +++ b/test/inverted/TestInvertedBombRules.py @@ -4,7 +4,7 @@ from BaseClasses import World from Dungeons import create_dungeons from EntranceShuffle import connect_entrance, Inverted_LW_Entrances, Inverted_LW_Dungeon_Entrances, Inverted_LW_Single_Cave_Doors, Inverted_Old_Man_Entrances, Inverted_DW_Entrances, Inverted_DW_Dungeon_Entrances, Inverted_DW_Single_Cave_Doors, \ Inverted_LW_Entrances_Must_Exit, Inverted_LW_Dungeon_Entrances_Must_Exit, Inverted_Bomb_Shop_Multi_Cave_Doors, Inverted_Bomb_Shop_Single_Cave_Doors, Inverted_Blacksmith_Single_Cave_Doors, Inverted_Blacksmith_Multi_Cave_Doors -from InvertedRegions import create_inverted_regions +from Regions import create_regions from ItemList import difficulties from Rules import set_inverted_big_bomb_rules from test.inverted.TestInverted import TestInverted diff --git a/test/inverted_owg/TestInvertedOWG.py b/test/inverted_owg/TestInvertedOWG.py index d0d938f6..2453d7ab 100644 --- a/test/inverted_owg/TestInvertedOWG.py +++ b/test/inverted_owg/TestInvertedOWG.py @@ -3,11 +3,10 @@ from DoorShuffle import link_doors from Doors import create_doors from Dungeons import create_dungeons, get_dungeon_item_pool from EntranceShuffle import link_entrances -from InvertedRegions import create_inverted_regions from ItemList import generate_itempool, difficulties from Items import ItemFactory from OverworldGlitchRules import create_owg_connections -from Regions import mark_light_world_regions, create_dungeon_regions, create_shops +from Regions import create_regions, mark_light_dark_world_regions, create_dungeon_regions, create_shops from RoomData import create_rooms from Rules import set_rules from test.TestBase import TestBase @@ -19,7 +18,7 @@ class TestInvertedOWG(TestBase): {1: True}, {1: False}, False, None, {1: False}) self.world.difficulty_requirements[1] = difficulties['normal'] self.world.intensity = {1: 1} - create_inverted_regions(self.world, 1) + create_regions(self.world, 1) create_dungeon_regions(self.world, 1) create_shops(self.world, 1) create_doors(self.world, 1) @@ -36,5 +35,5 @@ class TestInvertedOWG(TestBase): self.world.get_location('Agahnim 2', 1).item = None self.world.precollected_items.clear() self.world.itempool.append(ItemFactory('Pegasus Boots', 1)) - mark_light_world_regions(self.world, 1) + mark_light_dark_world_regions(self.world, 1) set_rules(self.world, 1) diff --git a/test/owg/TestVanillaOWG.py b/test/owg/TestVanillaOWG.py index 0eb4271f..c5bd18d0 100644 --- a/test/owg/TestVanillaOWG.py +++ b/test/owg/TestVanillaOWG.py @@ -3,11 +3,10 @@ from DoorShuffle import link_doors from Doors import create_doors from Dungeons import create_dungeons, get_dungeon_item_pool from EntranceShuffle import link_entrances -from InvertedRegions import mark_dark_world_regions from ItemList import difficulties, generate_itempool from Items import ItemFactory from OverworldGlitchRules import create_owg_connections -from Regions import create_regions, create_dungeon_regions, create_shops +from Regions import create_regions, create_dungeon_regions, create_shops, mark_light_dark_world_regions from RoomData import create_rooms from Rules import set_rules from test.TestBase import TestBase @@ -36,5 +35,5 @@ class TestVanillaOWG(TestBase): self.world.get_location('Agahnim 2', 1).item = None self.world.precollected_items.clear() self.world.itempool.append(ItemFactory('Pegasus Boots', 1)) - mark_dark_world_regions(self.world, 1) + mark_light_dark_world_regions(self.world, 1) set_rules(self.world, 1) \ No newline at end of file diff --git a/test/stats/EntranceShuffleStats.py b/test/stats/EntranceShuffleStats.py index 16ab90e5..313b060d 100644 --- a/test/stats/EntranceShuffleStats.py +++ b/test/stats/EntranceShuffleStats.py @@ -8,7 +8,6 @@ from source.overworld.EntranceShuffle2 import link_entrances_new from EntranceShuffle import link_entrances from BaseClasses import World from Regions import create_regions, create_dungeon_regions -from InvertedRegions import create_inverted_regions # tested: open + crossed (lh) Mar. 17 (made changes) @@ -103,10 +102,8 @@ def test_loop(tests, entrance_set, exit_set, ctr, shuffle_mode, main_mode, links {}, {}, {}, {}, {}, True, {}, {}, [], {}) world.customizer = False world.shufflelinks = {1: links} - if world.mode[1] != 'inverted': - create_regions(world, 1) - else: - create_inverted_regions(world, 1) + world.shuffletavern = {1: False} + create_regions(world, 1) create_dungeon_regions(world, 1) # print(f'Linking seed {seed}') # try: diff --git a/test/vanilla/TestVanilla.py b/test/vanilla/TestVanilla.py index 1fc316e9..80bbc7b9 100644 --- a/test/vanilla/TestVanilla.py +++ b/test/vanilla/TestVanilla.py @@ -3,10 +3,9 @@ from DoorShuffle import link_doors from Doors import create_doors from Dungeons import create_dungeons, get_dungeon_item_pool from EntranceShuffle import link_entrances -from InvertedRegions import mark_dark_world_regions from ItemList import difficulties, generate_itempool from Items import ItemFactory -from Regions import create_regions, create_dungeon_regions, create_shops +from Regions import create_regions, create_dungeon_regions, create_shops, mark_light_dark_world_regions from RoomData import create_rooms from Rules import set_rules from test.TestBase import TestBase @@ -32,5 +31,5 @@ class TestVanilla(TestBase): self.world.itempool.extend(ItemFactory(['Green Pendant', 'Red Pendant', 'Blue Pendant', 'Beat Agahnim 1', 'Beat Agahnim 2', 'Crystal 1', 'Crystal 2', 'Crystal 3', 'Crystal 4', 'Crystal 5', 'Crystal 6', 'Crystal 7'], 1)) self.world.get_location('Agahnim 1', 1).item = None self.world.get_location('Agahnim 2', 1).item = None - mark_dark_world_regions(self.world, 1) + mark_light_dark_world_regions(self.world, 1) set_rules(self.world, 1) From f8bba4176b38c0e4f4638dab597ffca1b3121427 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 14 Dec 2022 04:12:17 -0600 Subject: [PATCH 005/196] Reorganized and renamed regions, rules, and lists --- DoorShuffle.py | 2 +- EntranceShuffle.py | 723 +++++++++++++------------- ItemList.py | 6 +- OverworldGlitchRules.py | 38 +- PotShuffle.py | 8 +- Regions.py | 361 +++++++------ Rom.py | 12 +- Rules.py | 482 +++++++++-------- source/item/District.py | 12 +- source/overworld/EntranceShuffle2.py | 747 ++++++++++++++------------- 10 files changed, 1217 insertions(+), 1174 deletions(-) diff --git a/DoorShuffle.py b/DoorShuffle.py index 1124760a..4bbd53da 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -3251,7 +3251,7 @@ def find_accessible_entrances(world, player, builder): if connect not in queue and connect not in visited_regions: queue.append(connect) for ext in next_region.exits: - if hc_std and ext.name in ['Hyrule Castle Main Gate (North)', 'Top of Pyramid', 'Hyrule Castle Ledge Drop']: # just skip it + if hc_std and ext.name in ['Hyrule Castle Main Gate (North)', 'Castle Gate Teleporter', 'Hyrule Castle Ledge Drop']: # just skip it continue connect = ext.connected_region if connect is None or ext.door and ext.door.blocked: diff --git a/EntranceShuffle.py b/EntranceShuffle.py index 4c5b57a7..a5dda17a 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -1519,7 +1519,7 @@ LW_Single_Cave_Doors = ['Blinds Hideout', 'Chicken House', 'Aginahs Cave', 'Sahasrahlas Hut', - 'Cave Shop (Lake Hylia)', + 'Lake Hylia Shop', 'Blacksmiths Hut', 'Sick Kids House', 'Lost Woods Gamble', @@ -1560,9 +1560,9 @@ Isolated_LH_Doors_Open = ['Mimic Cave', 'Desert Palace Entrance (South)', 'Desert Palace Entrance (North)', 'Capacity Upgrade', - 'Ice Palace', 'Dark World Shop', 'Dark World Potion Shop', + 'Ice Palace', 'Dark World Shop', 'Dark Potion Shop', 'Skull Woods Final Section', 'Skull Woods Second Section Door (West)', - 'Dark World Hammer Peg Cave', 'Dark Death Mountain Ledge (West)', + 'Hammer Peg Cave', 'Dark Death Mountain Ledge (West)', 'Turtle Rock Isolated Ledge Entrance', 'Dark Death Mountain Ledge (East)'] DW_Single_Cave_Doors = ['Bonk Fairy (Dark)', @@ -1580,11 +1580,11 @@ DW_Single_Cave_Doors = ['Bonk Fairy (Dark)', 'Spike Cave', 'Palace of Darkness Hint', 'Dark Lake Hylia Ledge Spike Cave', - 'Cave Shop (Dark Death Mountain)', - 'Dark World Potion Shop', + 'Dark Death Mountain Shop', + 'Dark Potion Shop', 'Pyramid Fairy', 'Archery Game', - 'Dark World Lumberjack Shop', + 'Dark Lumberjack Shop', 'Hype Cave', 'Brewery', 'Dark Lake Hylia Ledge Hint', @@ -1592,7 +1592,7 @@ DW_Single_Cave_Doors = ['Bonk Fairy (Dark)', 'Dark Desert Fairy', 'Dark Lake Hylia Ledge Fairy', 'Fortune Teller (Dark)', - 'Dark World Hammer Peg Cave'] + 'Hammer Peg Cave'] Blacksmith_Single_Cave_Doors = ['Blinds Hideout', 'Lake Hylia Fairy', @@ -1601,7 +1601,7 @@ Blacksmith_Single_Cave_Doors = ['Blinds Hideout', 'Chicken House', 'Aginahs Cave', 'Sahasrahlas Hut', - 'Cave Shop (Lake Hylia)', + 'Lake Hylia Shop', 'Blacksmiths Hut', 'Sick Kids House', 'Lost Woods Gamble', @@ -1645,19 +1645,19 @@ Bomb_Shop_Single_Cave_Doors = ['Waterfall of Wishing', 'Brewery', 'C-Shaped House', 'Chest Game', - 'Dark World Hammer Peg Cave', + 'Hammer Peg Cave', 'Red Shield Shop', 'Dark Sanctuary Hint', 'Fortune Teller (Dark)', 'Dark World Shop', - 'Dark World Lumberjack Shop', - 'Dark World Potion Shop', + 'Dark Lumberjack Shop', + 'Dark Potion Shop', 'Archery Game', 'Mire Shed', 'Dark Desert Hint', 'Dark Desert Fairy', 'Spike Cave', - 'Cave Shop (Dark Death Mountain)', + 'Dark Death Mountain Shop', 'Dark Death Mountain Fairy', 'Mimic Cave', 'Big Bomb Shop', @@ -1668,13 +1668,13 @@ Single_Cave_Doors = ['Pyramid Fairy'] Single_Cave_Targets = ['Blinds Hideout', 'Bonk Fairy (Light)', 'Lake Hylia Healer Fairy', - 'Swamp Healer Fairy', + 'Light Hype Fairy', 'Desert Healer Fairy', 'Kings Grave', 'Chicken House', 'Aginahs Cave', 'Sahasrahlas Hut', - 'Cave Shop (Lake Hylia)', + 'Lake Hylia Shop', 'Sick Kids House', 'Lost Woods Gamble', 'Fortune Teller (Light)', @@ -1711,22 +1711,22 @@ Single_Cave_Targets = ['Blinds Hideout', 'Brewery', 'C-Shaped House', 'Chest Game', - 'Dark World Hammer Peg Cave', + 'Hammer Peg Cave', 'Red Shield Shop', 'Dark Sanctuary Hint', 'Fortune Teller (Dark)', 'Village of Outcasts Shop', 'Dark Lake Hylia Shop', - 'Dark World Lumberjack Shop', + 'Dark Lumberjack Shop', 'Archery Game', 'Mire Shed', 'Dark Desert Hint', 'Dark Desert Healer Fairy', 'Spike Cave', - 'Cave Shop (Dark Death Mountain)', + 'Dark Death Mountain Shop', 'Dark Death Mountain Healer Fairy', 'Mimic Cave', - 'Dark World Potion Shop', + 'Dark Potion Shop', 'Lumberjack House', 'Lake Hylia Fortune Teller', 'Kakariko Gamble Game', @@ -1867,11 +1867,11 @@ Inverted_DW_Single_Cave_Doors = ['Bonk Fairy (Dark)', 'Dark Desert Hint', 'Palace of Darkness Hint', 'Dark Lake Hylia Ledge Spike Cave', - 'Cave Shop (Dark Death Mountain)', - 'Dark World Potion Shop', + 'Dark Death Mountain Shop', + 'Dark Potion Shop', 'Pyramid Fairy', 'Archery Game', - 'Dark World Lumberjack Shop', + 'Dark Lumberjack Shop', 'Hype Cave', 'Brewery', 'Dark Lake Hylia Ledge Hint', @@ -1879,7 +1879,7 @@ Inverted_DW_Single_Cave_Doors = ['Bonk Fairy (Dark)', 'Dark Desert Fairy', 'Dark Lake Hylia Ledge Fairy', 'Fortune Teller (Dark)', - 'Dark World Hammer Peg Cave'] + 'Hammer Peg Cave'] Inverted_Bomb_Shop_Single_Cave_Doors = ['Waterfall of Wishing', @@ -1902,19 +1902,19 @@ Inverted_Bomb_Shop_Single_Cave_Doors = ['Waterfall of Wishing', 'Brewery', 'C-Shaped House', 'Chest Game', - 'Dark World Hammer Peg Cave', + 'Hammer Peg Cave', 'Red Shield Shop', 'Dark Sanctuary Hint', 'Fortune Teller (Dark)', 'Dark World Shop', - 'Dark World Lumberjack Shop', - 'Dark World Potion Shop', + 'Dark Lumberjack Shop', + 'Dark Potion Shop', 'Archery Game', 'Mire Shed', 'Dark Desert Hint', 'Dark Desert Fairy', 'Spike Cave', - 'Cave Shop (Dark Death Mountain)', + 'Dark Death Mountain Shop', 'Bumper Cave (Top)', 'Mimic Cave', 'Dark Lake Hylia Shop', @@ -1928,7 +1928,7 @@ Inverted_Blacksmith_Single_Cave_Doors = ['Blinds Hideout', 'Chicken House', 'Aginahs Cave', 'Sahasrahlas Hut', - 'Cave Shop (Lake Hylia)', + 'Lake Hylia Shop', 'Blacksmiths Hut', 'Sick Kids House', 'Lost Woods Gamble', @@ -1956,13 +1956,13 @@ Inverted_Blacksmith_Single_Cave_Doors = ['Blinds Hideout', Inverted_Single_Cave_Targets = ['Blinds Hideout', 'Bonk Fairy (Light)', 'Lake Hylia Healer Fairy', - 'Swamp Healer Fairy', + 'Light Hype Fairy', 'Desert Healer Fairy', 'Kings Grave', 'Chicken House', 'Aginahs Cave', 'Sahasrahlas Hut', - 'Cave Shop (Lake Hylia)', + 'Lake Hylia Shop', 'Sick Kids House', 'Lost Woods Gamble', 'Fortune Teller (Light)', @@ -1999,21 +1999,21 @@ Inverted_Single_Cave_Targets = ['Blinds Hideout', 'Brewery', 'C-Shaped House', 'Chest Game', - 'Dark World Hammer Peg Cave', + 'Hammer Peg Cave', 'Red Shield Shop', 'Fortune Teller (Dark)', 'Village of Outcasts Shop', 'Dark Lake Hylia Shop', - 'Dark World Lumberjack Shop', + 'Dark Lumberjack Shop', 'Archery Game', 'Mire Shed', 'Dark Desert Hint', 'Dark Desert Healer Fairy', 'Spike Cave', - 'Cave Shop (Dark Death Mountain)', + 'Dark Death Mountain Shop', 'Dark Death Mountain Healer Fairy', 'Mimic Cave', - 'Dark World Potion Shop', + 'Dark Potion Shop', 'Lumberjack House', 'Lake Hylia Fortune Teller', 'Kakariko Gamble Game', @@ -2025,7 +2025,7 @@ Inverted_Dark_Sanctuary_Doors = ['Dark Sanctuary Hint', 'Brewery', 'C-Shaped House', 'Chest Game', - 'Dark World Lumberjack Shop', + 'Dark Lumberjack Shop', 'Red Shield Shop', 'Bumper Cave (Bottom)', 'Bumper Cave (Top)', @@ -2036,9 +2036,9 @@ Isolated_LH_Doors = ['Kings Grave', 'Desert Palace Entrance (South)', 'Desert Palace Entrance (North)', 'Capacity Upgrade', - 'Ice Palace', 'Dark World Shop', 'Dark World Potion Shop', + 'Ice Palace', 'Dark World Shop', 'Dark Potion Shop', 'Skull Woods Final Section', 'Skull Woods Second Section Door (West)', - 'Dark World Hammer Peg Cave', 'Dark Death Mountain Ledge (West)', + 'Hammer Peg Cave', 'Dark Death Mountain Ledge (West)', 'Turtle Rock Isolated Ledge Entrance', 'Dark Death Mountain Ledge (East)'] # Entrances that cannot be used to access a must_exit entrance - symmetrical to allow reverse lookups @@ -2065,136 +2065,153 @@ Inverted_Must_Exit_Invalid_Connections = defaultdict(set, { # 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'), - ('Lake Hylia Central Island Pier', 'Lake Hylia Central Island'), - ('Lake Hylia Central Island Water Drop', 'Lake Hylia Water'), - ('Potion Shop Water Drop', 'Lake Hylia Water'), - ('Northeast Light World Water Drop', 'Lake Hylia Water'), - ('Zora Waterfall Water Drop', 'Lake Hylia Water'), - ('Light World Water Drop', 'Lake Hylia Water'), - ('East Dark World Water Drop', 'Dark Lake Hylia Water'), - ('South Dark World Water Drop', 'Dark Lake Hylia Water'), - ('Southeast Dark World Water Drop', 'Dark Lake Hylia Water'), - ('Northeast Dark World Water Drop', 'Dark Lake Hylia Water'), - ('Catfish Water Drop', 'Dark Lake Hylia Water'), - ('Ice Palace Leave Water Drop', 'Dark Lake Hylia Water'), - ('West Dark World Water Drop', 'Dark Lake Hylia Water'), - ('Zoras Domain', 'Zoras Domain'), - ('Kings Grave Outer Rocks', 'Kings Grave Area'), - ('Kings Grave Inner Rocks', 'Light World'), - ('Kakariko Well (top to bottom)', 'Kakariko Well (bottom)'), - ('Kakariko Well (top to back)', 'Kakariko Well (back)'), - ('Master Sword Meadow', 'Master Sword Meadow'), - ('Hobo Pier', 'Hobo Bridge'), - ('Bat Cave Ledge Peg', 'Bat Cave Ledge'), - ('Bat Cave Ledge Peg (East)', 'Light World'), - ('Bat Cave Door', 'Bat Cave (left)'), + + # underworld ('Lost Woods Hideout (top to bottom)', 'Lost Woods Hideout (bottom)'), ('Lumberjack Tree (top to bottom)', 'Lumberjack Tree (bottom)'), - ('Blinds Hideout N', 'Blinds Hideout (Top)'), - ('Light World Pier', 'Light World'), - ('Potion Shop Pier', 'Potion Shop Area'), - ('Wooden Bridge Bush (North)', 'Light World'), - ('Wooden Bridge Bush (South)', 'Potion Shop Area'), - ('Potion Shop Rock (South)', 'Northeast Light World'), - ('Potion Shop Rock (North)', 'Potion Shop Area'), - ('Desert Statue Move', 'Desert Palace Stairs'), - ('Desert Palace Stairs Drop', 'Light World'), - ('Desert Palace Entrance (North) Rocks', 'Desert Palace Entrance (North) Spot'), - ('Desert Ledge Return Rocks', 'Desert Ledge'), - ('Sewer Drop', 'Sewers Rat Path'), - ('Death Mountain Entrance Rock', 'Death Mountain Entrance'), - ('Death Mountain Entrance Drop', 'Light World'), - ('Spectacle Rock Cave Drop', 'Spectacle Rock Cave (Bottom)'), - ('Spectacle Rock Cave Peak Drop', 'Spectacle Rock Cave (Bottom)'), ('Death Mountain Return Cave E', 'Death Mountain Return Cave (right)'), ('Death Mountain Return Cave W', 'Death Mountain Return Cave (left)'), - ('Death Mountain Return Ledge Drop', 'Light World'), ('Old Man Cave Dropdown', 'Old Man Cave'), + ('Spectacle Rock Cave Drop', 'Spectacle Rock Cave (Bottom)'), + ('Spectacle Rock Cave Peak Drop', 'Spectacle Rock Cave (Bottom)'), ('Old Man House Front to Back', 'Old Man House Back'), ('Old Man House Back to Front', 'Old Man House'), - ('DM Broken Bridge (West)', 'East Death Mountain (Bottom)'), - ('DM Broken Bridge (East)', 'Death Mountain (West Bottom)'), - ('East Death Mountain Drop', 'East Death Mountain (Bottom)'), - ('Spiral Cave Ledge Access', 'Spiral Cave Ledge'), - ('Spiral Cave Ledge Drop', 'East Death Mountain (Bottom)'), ('Spiral Cave (top to bottom)', 'Spiral Cave (Bottom)'), - ('DM Hammer Bridge (West)', 'East Death Mountain (Top)'), - ('DM Hammer Bridge (East)', 'Death Mountain (Top)'), - ('Death Mountain Drop', 'Death Mountain (West Bottom)'), - ('East Dark World Pier', 'East Dark World'), - ('Hammer Bridge Pegs (North)', 'South Dark World'), - ('Hammer Bridge Pegs (South)', 'East Dark World'), - ('Village of Outcasts Heavy Rock', 'West Dark World'), - ('Village of Outcasts Drop', 'South Dark World'), - ('Village of Outcasts Eastern Rocks', 'Hammer Peg Area'), - ('Village of Outcasts Pegs', 'Dark Grassy Lawn'), - ('Peg Area Rocks', 'West Dark World'), - ('Grassy Lawn Pegs', 'West Dark World'), - ('West Dark World Gap', 'West Dark World'), - ('East Dark World Broken Bridge Pass', 'East Dark World'), - ('Dark Witch Rock (North)', 'Northeast Dark World'), - ('Dark Witch Rock (South)', 'Catfish Area'), - ('Northeast Dark World Broken Bridge Pass', 'Northeast Dark World'), - ('Bumper Cave Entrance Rock', 'Bumper Cave Entrance'), - ('Bumper Cave Entrance Drop', 'West Dark World'), - ('Bumper Cave Ledge Drop', 'West Dark World'), - ('Bumper Cave Bottom to Top', 'Bumper Cave (top)'), - ('Bumper Cave Top To Bottom', 'Bumper Cave (bottom)'), - ('Skull Woods Forest', 'Skull Woods Forest'), ('Paradox Cave Push Block Reverse', 'Paradox Cave Chest Area'), ('Paradox Cave Push Block', 'Paradox Cave Front'), ('Paradox Cave Chest Area NE', 'Paradox Cave Bomb Area'), ('Paradox Cave Bomb Jump', 'Paradox Cave'), ('Paradox Cave Drop', 'Paradox Cave Chest Area'), - ('Light World Death Mountain Shop', 'Light World Death Mountain Shop'), - ('Fairy Ascension Rocks', 'Fairy Ascension Plateau'), - ('Fairy Ascension Drop', 'East Death Mountain (Bottom)'), - ('Fairy Ascension Ledge Drop', 'Fairy Ascension Plateau'), + ('Paradox Shop', 'Paradox Shop'), ('Fairy Ascension Cave Climb', 'Fairy Ascension Cave (Top)'), ('Fairy Ascension Cave Pots', 'Fairy Ascension Cave (Bottom)'), ('Fairy Ascension Cave Drop', 'Fairy Ascension Cave (Drop)'), - ('Dark Death Mountain Drop (East)', 'Dark Death Mountain (East Bottom)'), - ('Superbunny Cave Climb', 'Superbunny Cave (Top)'), + ('Sewer Drop', 'Sewers Rat Path'), + ('Kakariko Well (top to bottom)', 'Kakariko Well (bottom)'), + ('Kakariko Well (top to back)', 'Kakariko Well (back)'), + ('Blinds Hideout N', 'Blinds Hideout (Top)'), + ('Bat Cave Door', 'Bat Cave (left)'), + ('Hookshot Cave Front to Middle', 'Hookshot Cave (Middle)'), ('Hookshot Cave Middle to Front', 'Hookshot Cave (Front)'), ('Hookshot Cave Middle to Back', 'Hookshot Cave (Back)'), ('Hookshot Cave Back to Middle', 'Hookshot Cave (Middle)'), ('Hookshot Cave Bonk Path', 'Hookshot Cave (Bonk Islands)'), ('Hookshot Cave Hook Path', 'Hookshot Cave (Hook Islands)'), + ('Superbunny Cave Climb', 'Superbunny Cave (Top)'), + ('Bumper Cave Bottom to Top', 'Bumper Cave (top)'), + ('Bumper Cave Top To Bottom', 'Bumper Cave (bottom)'), ('Ganon Drop', 'Bottom of Pyramid'), - ('Pyramid Drop', 'East Dark World'), - ('Maze Race Ledge Drop', 'Light World'), - ('Hyrule Castle Ledge Drop', 'Light World'), - ('Desert Ledge Drop', 'Light World'), + + # water entry + ('Light World Water Drop', 'Lake Hylia Water'), + ('Potion Shop Water Drop', 'Lake Hylia Water'), + ('Northeast Light World Water Drop', 'Lake Hylia Water'), + ('Lake Hylia Central Island Water Drop', 'Lake Hylia Water'), + ('Zora Waterfall Water Drop', 'Lake Hylia Water'), + + ('West Dark World Water Drop', 'Dark Lake Hylia Water'), + ('South Dark World Water Drop', 'Dark Lake Hylia Water'), + ('East Dark World Water Drop', 'Dark Lake Hylia Water'), + ('Northeast Dark World Water Drop', 'Dark Lake Hylia Water'), + ('Southeast Dark World Water Drop', 'Dark Lake Hylia Water'), + ('Catfish Water Drop', 'Dark Lake Hylia Water'), + ('Ice Palace Leave Water Drop', 'Dark Lake Hylia Water'), + + # water exit + ('Lake Hylia Central Island Pier', 'Lake Hylia Central Island'), + ('Hobo Pier', 'Hobo Bridge'), + ('Light World Pier', 'Light World'), # there are several piers in-game, only one needs to be modeled + ('Potion Shop Pier', 'Potion Shop Area'), ('Lake Hylia Whirlpool', 'Northeast Light World'), - ('Hyrule Castle Ledge Courtyard Drop', 'Hyrule Castle Courtyard'), + ('Waterfall Fairy Access', 'Zora Waterfall Entryway'), + + ('East Dark World Pier', 'East Dark World'), ('Southeast Dark World Pier', 'Southeast Dark World'), ('Northeast Dark World River Pier', 'Northeast Dark World'), - ('Fairy Ascension Ledge Access', 'Fairy Ascension Ledge'), - ('Hyrule Castle Courtyard Bush (North)', 'Hyrule Castle Courtyard'), - ('Hyrule Castle Courtyard Bush (South)', 'Hyrule Castle Secret Entrance Area'), - ('Turtle Rock Drop', 'Dark Death Mountain (Top)'), - ('Floating Island Drop', 'Dark Death Mountain (Top)'), - ('Dark Desert Drop', 'Dark Desert'), + + # terrain + ('Master Sword Meadow', 'Master Sword Meadow'), + ('DM Hammer Bridge (West)', 'East Death Mountain (Top)'), + ('DM Hammer Bridge (East)', 'West Death Mountain (Top)'), + ('DM Broken Bridge (West)', 'East Death Mountain (Bottom)'), + ('DM Broken Bridge (East)', 'West Death Mountain (Bottom)'), + ('Fairy Ascension Rocks', 'Fairy Ascension Plateau'), + ('Death Mountain Entrance Rock', 'Death Mountain Entrance'), + ('Zoras Domain', 'Zoras Domain'), + ('Kings Grave Rocks (Outer)', 'Kings Grave Area'), + ('Kings Grave Rocks (Inner)', 'Light World'), + ('Potion Shop Rock (South)', 'Northeast Light World'), + ('Potion Shop Rock (North)', 'Potion Shop Area'), ('Kakariko Yard Bush (North)', 'Light World'), ('Kakariko Yard Bush (South)', 'Bush Covered Lawn'), - ('Bush Covered Lawn Mirror Spot', 'Dark Grassy Lawn'), ('Kakariko Southwest Bush (South)', 'Light World'), ('Kakariko Southwest Bush (North)', 'Bomb Hut Area'), ('Hyrule Castle Main Gate', 'Hyrule Castle Courtyard'), - ('Spectacle Rock Drop', 'Death Mountain (Top)'), - ('Desert Teleporter Drop', 'Light World'), - ('Dark Death Mountain Drop (West)', 'Dark Death Mountain (West Bottom)'), + ('Hyrule Castle Main Gate (North)', 'Light World'), + ('Hyrule Castle Courtyard Bush (North)', 'Hyrule Castle Courtyard'), + ('Hyrule Castle Courtyard Bush (South)', 'Hyrule Castle Secret Entrance Area'), + ('Wooden Bridge Bush (North)', 'Light World'), + ('Wooden Bridge Bush (South)', 'Potion Shop Area'), + ('Bat Cave Ledge Peg', 'Bat Cave Ledge'), + ('Bat Cave Ledge Peg (East)', 'Light World'), + ('Desert Statue Move', 'Desert Palace Stairs'), + ('Desert Ledge Rocks (Outer)', 'Desert Palace Entrance (North) Spot'), + ('Desert Ledge Rocks (Inner)', 'Desert Ledge'), + + ('Skull Woods Forest', 'Skull Woods Forest'), + ('Bumper Cave Entrance Rock', 'Bumper Cave Entrance'), + ('Dark Witch Rock (North)', 'Northeast Dark World'), + ('Dark Witch Rock (South)', 'Catfish Area'), + ('Grassy Lawn Pegs (Bottom)', 'Dark Grassy Lawn'), + ('Grassy Lawn Pegs (Top)', 'West Dark World'), + ('West Dark World Gap', 'West Dark World'), + ('Broken Bridge Pass (Top)', 'East Dark World'), + ('Broken Bridge Pass (Bottom)', 'Northeast Dark World'), + ('Peg Area Rocks (Left)', 'Hammer Peg Area'), + ('Peg Area Rocks (Right)', 'West Dark World'), + ('Village of Outcasts Heavy Rock', 'West Dark World'), + ('Hammer Bridge Pegs (North)', 'South Dark World'), + ('Hammer Bridge Pegs (South)', 'East Dark World'), + + # ledge drops + ('Spectacle Rock Drop', 'West Death Mountain (Top)'), + ('Death Mountain Drop', 'West Death Mountain (Bottom)'), + ('Spiral Cave Ledge Access', 'Spiral Cave Ledge'), + ('Fairy Ascension Ledge Access', 'Fairy Ascension Ledge'), + ('East Death Mountain Drop', 'East Death Mountain (Bottom)'), + ('Spiral Cave Ledge Drop', 'East Death Mountain (Bottom)'), + ('Fairy Ascension Ledge Drop', 'Fairy Ascension Plateau'), + ('Fairy Ascension Drop', 'East Death Mountain (Bottom)'), + ('Death Mountain Entrance Drop', 'Light World'), + ('Death Mountain Return Ledge Drop', 'Light World'), ('Graveyard Ledge Drop', 'Light World'), - ('Cave 45 Ledge Drop', 'Light World'), + ('Hyrule Castle Ledge Courtyard Drop', 'Hyrule Castle Courtyard'), + ('Hyrule Castle Ledge Drop', 'Light World'), + ('Maze Race Ledge Drop', 'Light World'), + ('Desert Ledge Drop', 'Light World'), + ('Desert Palace Mouth Drop', 'Light World'), ('Checkerboard Ledge Drop', 'Light World'), - ('Hyrule Castle Main Gate (North)', 'Light World') + ('Desert Teleporter Drop', 'Light World'), + ('Cave 45 Ledge Drop', 'Light World'), + + ('Dark Death Mountain Drop (West)', 'West Dark Death Mountain (Bottom)'), + ('Dark Death Mountain Drop (East)', 'East Dark Death Mountain (Bottom)'), + ('Floating Island Drop', 'Dark Death Mountain (Top)'), + ('Turtle Rock Drop', 'Dark Death Mountain (Top)'), + ('Bumper Cave Entrance Drop', 'West Dark World'), + ('Bumper Cave Ledge Drop', 'West Dark World'), + ('Pyramid Drop', 'East Dark World'), + ('Village of Outcasts Drop', 'South Dark World'), + ('Dark Desert Drop', 'Dark Desert') ] open_mandatory_connections = [('Sanctuary S&Q', 'Sanctuary'), ('Old Man S&Q', 'Old Man House'), ('Other World S&Q', 'East Dark World'), - ('Flute Spot 1', 'Death Mountain (West Bottom)'), + + # flute + ('Flute Spot 1', 'West Death Mountain (Bottom)'), ('Flute Spot 2', 'Potion Shop Area'), ('Flute Spot 3', 'Light World'), ('Flute Spot 4', 'Light World'), @@ -2207,51 +2224,50 @@ open_mandatory_connections = [('Sanctuary S&Q', 'Sanctuary'), ('ZLW Flute', 'Flute Sky'), ('DM Flute', 'Flute Sky'), ('EDM Flute', 'Flute Sky'), - ('Lake Hylia Central Island Teleporter', 'Dark Lake Hylia Central Island'), - ('Kings Grave Mirror Spot', 'Kings Grave Area'), - ('Top of Pyramid', 'East Dark World'), - ('Lake Hylia Island Mirror Spot', 'Lake Hylia Island'), - ('Lake Hylia Central Island Mirror Spot', 'Lake Hylia Central Island'), - ('Hyrule Castle Ledge Mirror Spot', 'Hyrule Castle Ledge'), - ('Dig Game Mirror Spot', 'Maze Race Ledge'), - ('Bat Cave Drop Ledge Mirror Spot', 'Bat Cave Ledge'), - ('Bumper Cave Entrance Mirror Spot', 'Death Mountain Entrance'), - ('Bumper Cave Ledge Mirror Spot', 'Death Mountain Return Ledge'), - ('Desert Ledge Mirror Spot', 'Desert Ledge'), - ('Desert Ledge (Northeast) Mirror Spot', 'Desert Checkerboard Ledge'), - ('Desert Palace Entrance (North) Mirror Spot', 'Desert Palace Entrance (North) Spot'), - ('Desert Teleporter', 'Dark Desert'), - ('Mire To Desert Palace Stairs Mirror Spot', 'Desert Palace Stairs'), + + # portals + ('Death Mountain Teleporter', 'West Dark Death Mountain (Bottom)'), + ('East Death Mountain Teleporter', 'East Dark Death Mountain (Bottom)'), + ('Turtle Rock Teleporter', 'Turtle Rock (Top)'), + ('Kakariko Teleporter', 'West Dark World'), + ('Castle Gate Teleporter', 'East Dark World'), ('East Hyrule Teleporter', 'East Dark World'), ('South Hyrule Teleporter', 'South Dark World'), - ('Kakariko Teleporter', 'West Dark World'), - ('Death Mountain Teleporter', 'Dark Death Mountain (West Bottom)'), - ('Fairy Ascension Mirror Spot', 'Fairy Ascension Plateau'), + ('Desert Teleporter', 'Dark Desert'), + ('Lake Hylia Teleporter', 'Dark Lake Hylia Central Island'), + + # mirror ('Spectacle Rock Mirror Spot', 'Spectacle Rock'), + ('Fairy Ascension Mirror Spot', 'Fairy Ascension Plateau'), ('East Death Mountain (Top) Mirror Spot', 'East Death Mountain (Top)'), - ('Turtle Rock Teleporter', 'Turtle Rock (Top)'), - ('Dark Grassy Lawn Mirror Spot', 'Bush Covered Lawn'), ('Dark Floating Island Mirror Spot', 'Death Mountain Floating Island'), - ('East Death Mountain Teleporter', 'Dark Death Mountain (East Bottom)'), - ('Isolated Ledge Mirror Spot', 'Fairy Ascension Ledge'), ('Spiral Cave Mirror Spot', 'Spiral Cave Ledge'), ('Mimic Cave Mirror Spot', 'Mimic Cave Ledge'), - ('Cave 45 Mirror Spot', 'Cave 45 Ledge'), + ('Isolated Ledge Mirror Spot', 'Fairy Ascension Ledge'), + ('Bumper Cave Ledge Mirror Spot', 'Death Mountain Return Ledge'), + ('Bumper Cave Entrance Mirror Spot', 'Death Mountain Entrance'), + ('Kings Grave Mirror Spot', 'Kings Grave Area'), + ('Dark Grassy Lawn Mirror Spot', 'Bush Covered Lawn'), + ('Hyrule Castle Ledge Mirror Spot', 'Hyrule Castle Ledge'), + ('Bat Cave Drop Ledge Mirror Spot', 'Bat Cave Ledge'), + ('Dig Game Mirror Spot', 'Maze Race Ledge'), + ('Desert Ledge Rocks Mirror Spot', 'Desert Palace Entrance (North) Spot'), + ('Desert Ledge Mirror Spot', 'Desert Ledge'), + ('Mire To Desert Stairs Mirror Spot', 'Desert Palace Stairs'), + ('Checkerboard Ledge Mirror Spot', 'Desert Checkerboard Ledge'), ('Bombos Tablet Mirror Spot', 'Bombos Tablet Ledge'), + ('Cave 45 Mirror Spot', 'Cave 45 Ledge'), + ('Lake Hylia Island Mirror Spot', 'Lake Hylia Island'), + ('Lake Hylia Central Island Mirror Spot', 'Lake Hylia Central Island'), ('Graveyard Ledge Mirror Spot', 'Graveyard Ledge') ] inverted_mandatory_connections = [('Sanctuary S&Q', 'Dark Sanctuary Hint'), - ('Old Man S&Q', 'Dark Death Mountain (West Bottom)'), + ('Old Man S&Q', 'West Dark Death Mountain (Bottom)'), ('Other World S&Q', 'Hyrule Castle Ledge'), - ('Lake Hylia Island Pier', 'Lake Hylia Island'), - ('Spectacle Rock Leave', 'Death Mountain (Top)'), - ('Spectacle Rock Approach', 'Spectacle Rock'), - ('Checkerboard Ledge Approach', 'Desert Checkerboard Ledge'), - ('Checkerboard Ledge Leave', 'Light World'), - ('Cave 45 Approach', 'Cave 45 Ledge'), - ('Cave 45 Leave', 'Light World'), - ('Flute Spot 1', 'Dark Death Mountain (West Bottom)'), + + # flute + ('Flute Spot 1', 'West Dark Death Mountain (Bottom)'), ('Flute Spot 2', 'Northeast Dark World'), ('Flute Spot 3', 'West Dark World'), ('Flute Spot 4', 'South Dark World'), @@ -2269,229 +2285,250 @@ inverted_mandatory_connections = [('Sanctuary S&Q', 'Dark Sanctuary Hint'), ('EDDM Flute', 'Flute Sky'), ('Dark Grassy Lawn Flute', 'Flute Sky'), ('Hammer Peg Area Flute', 'Flute Sky'), + + # modified terrain + ('Lake Hylia Island Pier', 'Lake Hylia Island'), + ('Spectacle Rock Leave', 'West Death Mountain (Top)'), + ('Spectacle Rock Approach', 'Spectacle Rock'), + ('Checkerboard Ledge Approach', 'Desert Checkerboard Ledge'), + ('Checkerboard Ledge Leave', 'Light World'), + ('Cave 45 Approach', 'Cave 45 Ledge'), + ('Cave 45 Leave', 'Light World'), ('Dark Death Mountain Ladder (Bottom)', 'Dark Death Mountain (Top)'), - ('Dark Death Mountain Ladder (Top)', 'Dark Death Mountain (West Bottom)'), + ('Dark Death Mountain Ladder (Top)', 'West Dark Death Mountain (Bottom)'), ('Ice Palace Approach', 'Dark Lake Hylia Central Island'), ('Floating Island Bridge (East)', 'Death Mountain Floating Island'), ('Floating Island Bridge (West)', 'East Death Mountain (Top)'), - ('Post Aga Teleporter', 'Light World'), ('Graveyard Ladder (Top)', 'Light World'), ('Graveyard Ladder (Bottom)', 'Graveyard Ledge'), - ('Graveyard Cave Mirror Spot', 'West Dark World'), - ('Pyramid Uncle Mirror Spot', 'East Dark World'), ('Mimic Cave Ledge Access', 'Mimic Cave Ledge'), ('Mimic Cave Ledge Drop', 'East Death Mountain (Bottom)'), ('Turtle Rock Tail Drop', 'Turtle Rock (Top)'), - ('Dark Lake Hylia Central Island Teleporter', 'Lake Hylia Central Island'), - ('Dark Desert Teleporter', 'Light World'), - ('East Dark World Teleporter', 'Light World'), - ('South Dark World Teleporter', 'Light World'), - ('West Dark World Teleporter', 'Light World'), - ('Dark Death Mountain Teleporter (West)', 'Death Mountain (West Bottom)'), - ('Dark Death Mountain Teleporter (East)', 'East Death Mountain (Top)'), - ('Dark Death Mountain Teleporter (East Bottom)', 'East Death Mountain (Bottom)'), - ('Mire Mirror Spot', 'Dark Desert'), ('Bombos Tablet Ladder (Top)', 'Light World'), ('Bombos Tablet Ladder (Bottom)', 'Bombos Tablet Ledge'), - ('Desert Palace Stairs Mirror Spot', 'Dark Desert'), - ('Desert Palace North Mirror Spot', 'Dark Desert'), - ('Maze Race Mirror Spot', 'South Dark World'), - ('Lake Hylia Central Island Mirror Spot', 'Dark Lake Hylia Central Island'), - ('Hammer Peg Area Mirror Spot', 'Hammer Peg Area'), - ('Mountain Exit Ledge Mirror Spot', 'Bumper Cave Ledge'), - ('Bumper Cave Entrance Mirror Spot', 'Bumper Cave Entrance'), - ('Death Mountain Mirror Spot', 'Dark Death Mountain (West Bottom)'), - ('East Death Mountain Mirror Spot (Top)', 'Dark Death Mountain (Top)'), - ('East Death Mountain Mirror Spot (Bottom)', 'Dark Death Mountain (East Bottom)'), + + # portals + ('Dark Death Mountain Teleporter (West)', 'West Death Mountain (Bottom)'), + ('East Dark Death Mountain Teleporter (Bottom)', 'East Death Mountain (Bottom)'), + ('East Dark Death Mountain Teleporter (Top)', 'East Death Mountain (Top)'), + ('West Dark World Teleporter', 'Light World'), + ('Post Aga Teleporter', 'Light World'), + ('East Dark World Teleporter', 'Light World'), + ('South Dark World Teleporter', 'Light World'), + ('Dark Desert Teleporter', 'Light World'), + ('Dark Lake Hylia Teleporter', 'Lake Hylia Central Island'), + + # mirror + ('Skull Woods Mirror Spot', 'Skull Woods Forest (West)'), + ('Death Mountain Mirror Spot', 'West Dark Death Mountain (Bottom)'), ('Death Mountain (Top) Mirror Spot', 'Dark Death Mountain (Top)'), + ('East Death Mountain Mirror Spot (Top)', 'Dark Death Mountain (Top)'), + ('Floating Island Mirror Spot', 'Dark Death Mountain Floating Island'), ('Dark Death Mountain Ledge Mirror Spot (East)', 'Dark Death Mountain Ledge'), ('Dark Death Mountain Ledge Mirror Spot (West)', 'Dark Death Mountain Ledge'), - ('Floating Island Mirror Spot', 'Death Mountain Floating Island (Dark World)'), ('Laser Bridge Mirror Spot', 'Dark Death Mountain Isolated Ledge'), + ('East Death Mountain Mirror Spot (Bottom)', 'East Dark Death Mountain (Bottom)'), + ('Mountain Exit Ledge Mirror Spot', 'Bumper Cave Ledge'), + ('Mountain Entrance Mirror Spot', 'Bumper Cave Entrance'), + ('Catfish Mirror Spot', 'Catfish Area'), + ('Graveyard Cave Mirror Spot', 'West Dark World'), + ('Potion Shop Mirror Spot', 'Northeast Dark World'), + ('Bush Covered Lawn Mirror Spot', 'Dark Grassy Lawn'), + ('Bomb Hut Mirror Spot', 'West Dark World'), + ('Pyramid Uncle Mirror Spot', 'East Dark World'), + ('Hammer Peg Area Mirror Spot', 'Hammer Peg Area'), + ('Maze Race Mirror Spot', 'South Dark World'), + ('South Dark World Mirror Spot', 'South Dark World'), + ('Mire Mirror Spot', 'Dark Desert'), + ('Desert Palace Stairs Mirror Spot', 'Dark Desert'), + ('Desert Palace North Mirror Spot', 'Dark Desert'), + ('Lake Hylia Central Island Mirror Spot', 'Dark Lake Hylia Central Island'), ('East Dark World Mirror Spot', 'East Dark World'), ('West Dark World Mirror Spot', 'West Dark World'), - ('South Dark World Mirror Spot', 'South Dark World'), - ('Potion Shop Mirror Spot', 'Northeast Dark World'), - ('Catfish Mirror Spot', 'Catfish Area'), - ('Shopping Mall Mirror Spot', 'Southeast Dark World'), - ('Skull Woods Mirror Spot', 'Skull Woods Forest (West)'), - ('Bomb Hut Mirror Spot', 'West Dark World') + ('Shopping Mall Mirror Spot', 'Southeast Dark World') ] # non-shuffled entrance links -default_connections = [('Waterfall of Wishing', 'Waterfall of Wishing'), - ('Blinds Hideout', 'Blinds Hideout'), - ('Dam', 'Dam'), - ('Lumberjack House', 'Lumberjack House'), - ('Hyrule Castle Secret Entrance Drop', 'Hyrule Castle Secret Entrance'), - ('Hyrule Castle Secret Entrance Stairs', 'Hyrule Castle Secret Entrance'), - ('Hyrule Castle Secret Entrance Exit', 'Hyrule Castle Secret Entrance Area'), - ('Bonk Fairy (Light)', 'Bonk Fairy (Light)'), - ('Lake Hylia Fairy', 'Lake Hylia Healer Fairy'), - ('Lake Hylia Fortune Teller', 'Lake Hylia Fortune Teller'), - ('Light Hype Fairy', 'Swamp Healer Fairy'), - ('Desert Fairy', 'Desert Healer Fairy'), - ('Kings Grave', 'Kings Grave'), - ('Tavern North', 'Tavern'), - ('Chicken House', 'Chicken House'), - ('Aginahs Cave', 'Aginahs Cave'), - ('Sahasrahlas Hut', 'Sahasrahlas Hut'), - ('Cave Shop (Lake Hylia)', 'Cave Shop (Lake Hylia)'), - ('Capacity Upgrade', 'Capacity Upgrade'), - ('Kakariko Well Drop', 'Kakariko Well (top)'), - ('Kakariko Well Cave', 'Kakariko Well (bottom)'), - ('Kakariko Well Exit', 'Light World'), - ('Blacksmiths Hut', 'Blacksmiths Hut'), - ('Bat Cave Drop', 'Bat Cave (right)'), - ('Bat Cave Cave', 'Bat Cave (left)'), - ('Bat Cave Exit', 'Light World'), - ('Sick Kids House', 'Sick Kids House'), - ('Elder House (East)', 'Elder House'), - ('Elder House (West)', 'Elder House'), - ('Elder House Exit (East)', 'Light World'), - ('Elder House Exit (West)', 'Light World'), - ('North Fairy Cave Drop', 'North Fairy Cave'), - ('North Fairy Cave', 'North Fairy Cave'), - ('North Fairy Cave Exit', 'Light World'), - ('Lost Woods Gamble', 'Lost Woods Gamble'), - ('Fortune Teller (Light)', 'Fortune Teller (Light)'), - ('Snitch Lady (East)', 'Snitch Lady (East)'), - ('Snitch Lady (West)', 'Snitch Lady (West)'), - ('Bush Covered House', 'Bush Covered House'), - ('Tavern (Front)', 'Tavern (Front)'), - ('Light World Bomb Hut', 'Light World Bomb Hut'), - ('Kakariko Shop', 'Kakariko Shop'), +default_connections = [('Lost Woods Gamble', 'Lost Woods Gamble'), ('Lost Woods Hideout Drop', 'Lost Woods Hideout (top)'), ('Lost Woods Hideout Stump', 'Lost Woods Hideout (bottom)'), ('Lost Woods Hideout Exit', 'Light World'), + ('Lumberjack House', 'Lumberjack House'), ('Lumberjack Tree Tree', 'Lumberjack Tree (top)'), ('Lumberjack Tree Cave', 'Lumberjack Tree (bottom)'), ('Lumberjack Tree Exit', 'Light World'), - ('Cave 45', 'Cave 45'), - ('Graveyard Cave', 'Graveyard Cave'), - ('Checkerboard Cave', 'Checkerboard Cave'), - ('Mini Moldorm Cave', 'Mini Moldorm Cave'), - ('Long Fairy Cave', 'Long Fairy Cave'), - ('Good Bee Cave', 'Good Bee Cave'), - ('20 Rupee Cave', '20 Rupee Cave'), - ('50 Rupee Cave', '50 Rupee Cave'), - ('Ice Rod Cave', 'Ice Rod Cave'), - ('Bonk Rock Cave', 'Bonk Rock Cave'), - ('Library', 'Library'), - ('Kakariko Gamble Game', 'Kakariko Gamble Game'), - ('Potion Shop', 'Potion Shop'), - ('Two Brothers House (East)', 'Two Brothers House'), - ('Two Brothers House (West)', 'Two Brothers House'), - ('Two Brothers House Exit (East)', 'Light World'), - ('Two Brothers House Exit (West)', 'Maze Race Ledge'), - ('Sanctuary', 'Sanctuary Portal'), - ('Sanctuary Grave', 'Sewer Drop'), - ('Sanctuary Exit', 'Light World'), - ('Old Man House (Bottom)', 'Old Man House'), - ('Old Man House Exit (Bottom)', 'Death Mountain (West Bottom)'), - ('Old Man House (Top)', 'Old Man House Back'), - ('Old Man House Exit (Top)', 'Death Mountain (West Bottom)'), ('Death Mountain Return Cave (East)', 'Death Mountain Return Cave (right)'), - ('Death Mountain Return Cave Exit (East)', 'Death Mountain (West Bottom)'), + ('Death Mountain Return Cave Exit (East)', 'West Death Mountain (Bottom)'), ('Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Peak)'), ('Spectacle Rock Cave (Bottom)', 'Spectacle Rock Cave (Bottom)'), ('Spectacle Rock Cave', 'Spectacle Rock Cave (Top)'), - ('Spectacle Rock Cave Exit', 'Death Mountain (West Bottom)'), - ('Spectacle Rock Cave Exit (Top)', 'Death Mountain (West Bottom)'), - ('Spectacle Rock Cave Exit (Peak)', 'Death Mountain (West Bottom)'), + ('Spectacle Rock Cave Exit', 'West Death Mountain (Bottom)'), + ('Spectacle Rock Cave Exit (Top)', 'West Death Mountain (Bottom)'), + ('Spectacle Rock Cave Exit (Peak)', 'West Death Mountain (Bottom)'), + ('Old Man House (Bottom)', 'Old Man House'), + ('Old Man House Exit (Bottom)', 'West Death Mountain (Bottom)'), + ('Old Man House (Top)', 'Old Man House Back'), + ('Old Man House Exit (Top)', 'West Death Mountain (Bottom)'), + ('Spiral Cave', 'Spiral Cave (Top)'), + ('Spiral Cave (Bottom)', 'Spiral Cave (Bottom)'), + ('Spiral Cave Exit', 'East Death Mountain (Bottom)'), + ('Spiral Cave Exit (Top)', 'Spiral Cave Ledge'), + ('Mimic Cave', 'Mimic Cave'), + ('Fairy Ascension Cave (Bottom)', 'Fairy Ascension Cave (Bottom)'), + ('Fairy Ascension Cave (Top)', 'Fairy Ascension Cave (Top)'), + ('Fairy Ascension Cave Exit (Bottom)', 'Fairy Ascension Plateau'), + ('Fairy Ascension Cave Exit (Top)', 'Fairy Ascension Ledge'), + ('Hookshot Fairy', 'Hookshot Fairy'), ('Paradox Cave (Bottom)', 'Paradox Cave Front'), ('Paradox Cave (Middle)', 'Paradox Cave'), ('Paradox Cave (Top)', 'Paradox Cave'), ('Paradox Cave Exit (Bottom)', 'East Death Mountain (Bottom)'), ('Paradox Cave Exit (Middle)', 'East Death Mountain (Bottom)'), ('Paradox Cave Exit (Top)', 'East Death Mountain (Top)'), - ('Hookshot Fairy', 'Hookshot Fairy'), - ('Fairy Ascension Cave (Bottom)', 'Fairy Ascension Cave (Bottom)'), - ('Fairy Ascension Cave (Top)', 'Fairy Ascension Cave (Top)'), - ('Fairy Ascension Cave Exit (Bottom)', 'Fairy Ascension Plateau'), - ('Fairy Ascension Cave Exit (Top)', 'Fairy Ascension Ledge'), - ('Spiral Cave', 'Spiral Cave (Top)'), - ('Spiral Cave (Bottom)', 'Spiral Cave (Bottom)'), - ('Spiral Cave Exit', 'East Death Mountain (Bottom)'), - ('Spiral Cave Exit (Top)', 'Spiral Cave Ledge'), - ('Pyramid Fairy', 'Pyramid Fairy'), - ('East Dark World Hint', 'East Dark World Hint'), - ('Palace of Darkness Hint', 'Palace of Darkness Hint'), - ('Dark Lake Hylia Shop', 'Dark Lake Hylia Shop'), - ('Dark Lake Hylia Fairy', 'Dark Lake Hylia Healer Fairy'), - ('Dark Lake Hylia Ledge Fairy', 'Dark Lake Hylia Ledge Healer Fairy'), - ('Dark Lake Hylia Ledge Spike Cave', 'Dark Lake Hylia Ledge Spike Cave'), - ('Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Ledge Hint'), - ('Hype Cave', 'Hype Cave'), - ('Bonk Fairy (Dark)', 'Bonk Fairy (Dark)'), - ('Brewery', 'Brewery'), - ('C-Shaped House', 'C-Shaped House'), - ('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'), - ('Fortune Teller (Dark)', 'Fortune Teller (Dark)'), - ('Dark World Shop', 'Village of Outcasts Shop'), - ('Dark World Lumberjack Shop', 'Dark World Lumberjack Shop'), - ('Dark World Potion Shop', 'Dark World Potion Shop'), - ('Archery Game', 'Archery Game'), - ('Mire Shed', 'Mire Shed'), - ('Dark Desert Hint', 'Dark Desert Hint'), - ('Dark Desert Fairy', 'Dark Desert Healer Fairy'), + ('Waterfall of Wishing', 'Waterfall of Wishing'), + ('Fortune Teller (Light)', 'Fortune Teller (Light)'), + ('Bonk Rock Cave', 'Bonk Rock Cave'), + ('Sanctuary', 'Sanctuary Portal'), + ('Sanctuary Exit', 'Light World'), + ('Sanctuary Grave', 'Sewer Drop'), + ('Graveyard Cave', 'Graveyard Cave'), + ('Kings Grave', 'Kings Grave'), + ('North Fairy Cave Drop', 'North Fairy Cave'), + ('North Fairy Cave', 'North Fairy Cave'), + ('North Fairy Cave Exit', 'Light World'), + ('Potion Shop', 'Potion Shop'), + ('Kakariko Well Drop', 'Kakariko Well (top)'), + ('Kakariko Well Cave', 'Kakariko Well (bottom)'), + ('Kakariko Well Exit', 'Light World'), + ('Blinds Hideout', 'Blinds Hideout'), + ('Elder House (East)', 'Elder House'), + ('Elder House (West)', 'Elder House'), + ('Elder House Exit (East)', 'Light World'), + ('Elder House Exit (West)', 'Light World'), + ('Snitch Lady (West)', 'Snitch Lady (West)'), + ('Snitch Lady (East)', 'Snitch Lady (East)'), + ('Bush Covered House', 'Bush Covered House'), + ('Chicken House', 'Chicken House'), + ('Sick Kids House', 'Sick Kids House'), + ('Light World Bomb Hut', 'Light World Bomb Hut'), + ('Kakariko Shop', 'Kakariko Shop'), + ('Tavern North', 'Tavern'), + ('Tavern (Front)', 'Tavern (Front)'), + ('Hyrule Castle Secret Entrance Drop', 'Hyrule Castle Secret Entrance'), + ('Hyrule Castle Secret Entrance Stairs', 'Hyrule Castle Secret Entrance'), + ('Hyrule Castle Secret Entrance Exit', 'Hyrule Castle Secret Entrance Area'), + ('Sahasrahlas Hut', 'Sahasrahlas Hut'), + ('Blacksmiths Hut', 'Blacksmiths Hut'), + ('Bat Cave Drop', 'Bat Cave (right)'), + ('Bat Cave Cave', 'Bat Cave (left)'), + ('Bat Cave Exit', 'Light World'), + ('Two Brothers House (West)', 'Two Brothers House'), + ('Two Brothers House Exit (West)', 'Maze Race Ledge'), + ('Two Brothers House (East)', 'Two Brothers House'), + ('Two Brothers House Exit (East)', 'Light World'), + ('Library', 'Library'), + ('Kakariko Gamble Game', 'Kakariko Gamble Game'), + ('Bonk Fairy (Light)', 'Bonk Fairy (Light)'), + ('Lake Hylia Fairy', 'Lake Hylia Healer Fairy'), + ('Long Fairy Cave', 'Long Fairy Cave'), + ('Checkerboard Cave', 'Checkerboard Cave'), + ('Aginahs Cave', 'Aginahs Cave'), + ('Cave 45', 'Cave 45'), + ('Light Hype Fairy', 'Light Hype Fairy'), + ('Lake Hylia Fortune Teller', 'Lake Hylia Fortune Teller'), + ('Lake Hylia Shop', 'Lake Hylia Shop'), + ('Capacity Upgrade', 'Capacity Upgrade'), + ('Mini Moldorm Cave', 'Mini Moldorm Cave'), + ('Ice Rod Cave', 'Ice Rod Cave'), + ('Good Bee Cave', 'Good Bee Cave'), + ('20 Rupee Cave', '20 Rupee Cave'), + ('Desert Fairy', 'Desert Healer Fairy'), + ('50 Rupee Cave', '50 Rupee Cave'), + ('Dam', 'Dam'), + + ('Dark Lumberjack Shop', 'Dark Lumberjack Shop'), ('Spike Cave', 'Spike Cave'), + ('Hookshot Cave Back Exit', 'Dark Death Mountain Floating Island'), + ('Hookshot Cave Back Entrance', 'Hookshot Cave (Back)'), ('Hookshot Cave', 'Hookshot Cave (Front)'), ('Hookshot Cave Front Exit', 'Dark Death Mountain (Top)'), ('Superbunny Cave (Top)', 'Superbunny Cave (Top)'), ('Superbunny Cave Exit (Top)', 'Dark Death Mountain (Top)'), - ('Cave Shop (Dark Death Mountain)', 'Cave Shop (Dark Death Mountain)'), ('Superbunny Cave (Bottom)', 'Superbunny Cave (Bottom)'), - ('Superbunny Cave Exit (Bottom)', 'Dark Death Mountain (East Bottom)'), - ('Hookshot Cave Back Exit', 'Death Mountain Floating Island (Dark World)'), - ('Hookshot Cave Back Entrance', 'Hookshot Cave (Back)'), - ('Mimic Cave', 'Mimic Cave') + ('Superbunny Cave Exit (Bottom)', 'East Dark Death Mountain (Bottom)'), + ('Dark Death Mountain Shop', 'Dark Death Mountain Shop'), + ('Fortune Teller (Dark)', 'Fortune Teller (Dark)'), + ('Dark Sanctuary Hint', 'Dark Sanctuary Hint'), + ('Dark Potion Shop', 'Dark Potion Shop'), + ('Chest Game', 'Chest Game'), + ('C-Shaped House', 'C-Shaped House'), + ('Brewery', 'Brewery'), + ('Dark World Shop', 'Village of Outcasts Shop'), + ('Hammer Peg Cave', 'Hammer Peg Cave'), + ('Red Shield Shop', 'Red Shield Shop'), + ('Pyramid Fairy', 'Pyramid Fairy'), + ('Palace of Darkness Hint', 'Palace of Darkness Hint'), + ('Archery Game', 'Archery Game'), + ('Bonk Fairy (Dark)', 'Bonk Fairy (Dark)'), + ('Dark Lake Hylia Fairy', 'Dark Lake Hylia Healer Fairy'), + ('East Dark World Hint', 'East Dark World Hint'), + ('Mire Shed', 'Mire Shed'), + ('Dark Desert Fairy', 'Dark Desert Healer Fairy'), + ('Dark Desert Hint', 'Dark Desert Hint'), + ('Hype Cave', 'Hype Cave'), + ('Dark Lake Hylia Shop', 'Dark Lake Hylia Shop'), + ('Dark Lake Hylia Ledge Fairy', 'Dark Lake Hylia Ledge Healer Fairy'), + ('Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Ledge Hint'), + ('Dark Lake Hylia Ledge Spike Cave', 'Dark Lake Hylia Ledge Spike Cave') ] open_default_connections = [('Links House', 'Links House'), ('Links House Exit', 'Light World'), + ('Big Bomb Shop', 'Big Bomb Shop'), ('Old Man Cave (West)', 'Old Man Cave Ledge'), ('Old Man Cave (East)', 'Old Man Cave'), ('Old Man Cave Exit (West)', 'Light World'), - ('Old Man Cave Exit (East)', 'Death Mountain (West Bottom)'), + ('Old Man Cave Exit (East)', 'West Death Mountain (Bottom)'), ('Death Mountain Return Cave (West)', 'Death Mountain Return Cave (left)'), ('Death Mountain Return Cave Exit (West)', 'Death Mountain Return Ledge'), - ('Big Bomb Shop', 'Big Bomb Shop'), ('Bumper Cave (Bottom)', 'Bumper Cave (bottom)'), ('Bumper Cave (Top)', 'Bumper Cave (top)'), ('Bumper Cave Exit (Top)', 'Bumper Cave Ledge'), ('Bumper Cave Exit (Bottom)', 'West Dark World'), ('Dark Death Mountain Fairy', 'Dark Death Mountain Healer Fairy'), ('Pyramid Hole', 'Pyramid'), - ('Pyramid Exit', 'Pyramid Ledge'), - ('Pyramid Entrance', 'Bottom of Pyramid') + ('Pyramid Entrance', 'Bottom of Pyramid'), + ('Pyramid Exit', 'Pyramid Exit Ledge') ] inverted_default_connections = [('Links House', 'Big Bomb Shop'), ('Links House Exit', 'South Dark World'), + ('Big Bomb Shop', 'Links House'), + ('Dark Sanctuary Hint Exit', 'West Dark World'), ('Old Man Cave (West)', 'Bumper Cave (bottom)'), ('Old Man Cave (East)', 'Death Mountain Return Cave (left)'), ('Old Man Cave Exit (West)', 'West Dark World'), - ('Old Man Cave Exit (East)', 'Dark Death Mountain (West Bottom)'), + ('Old Man Cave Exit (East)', 'West Dark Death Mountain (Bottom)'), ('Death Mountain Return Cave (West)', 'Bumper Cave (top)'), - ('Death Mountain Return Cave Exit (West)', 'Death Mountain (West Bottom)'), - ('Big Bomb Shop', 'Links House'), + ('Death Mountain Return Cave Exit (West)', 'West Death Mountain (Bottom)'), ('Bumper Cave (Bottom)', 'Old Man Cave Ledge'), ('Bumper Cave (Top)', 'Dark Death Mountain Healer Fairy'), ('Bumper Cave Exit (Top)', 'Death Mountain Return Ledge'), ('Bumper Cave Exit (Bottom)', 'Light World'), ('Dark Death Mountain Fairy', 'Old Man Cave'), - ('Dark Sanctuary Hint Exit', 'West Dark World'), ('Inverted Pyramid Hole', 'Pyramid'), - ('Pyramid Exit', 'Hyrule Castle Courtyard'), - ('Inverted Pyramid Entrance', 'Bottom of Pyramid') + ('Inverted Pyramid Entrance', 'Bottom of Pyramid'), + ('Pyramid Exit', 'Hyrule Castle Courtyard') ] # non shuffled dungeons -default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert South Portal'), +default_dungeon_connections = [('Hyrule Castle Entrance (South)', 'Hyrule Castle South Portal'), + ('Hyrule Castle Entrance (West)', 'Hyrule Castle West Portal'), + ('Hyrule Castle Entrance (East)', 'Hyrule Castle East Portal'), + ('Hyrule Castle Exit (South)', 'Hyrule Castle Courtyard'), + ('Hyrule Castle Exit (West)', 'Hyrule Castle Ledge'), + ('Hyrule Castle Exit (East)', 'Hyrule Castle Ledge'), + ('Desert Palace Entrance (South)', 'Desert South Portal'), ('Desert Palace Entrance (West)', 'Desert West Portal'), ('Desert Palace Entrance (North)', 'Desert Back Portal'), ('Desert Palace Entrance (East)', 'Desert East Portal'), @@ -2502,17 +2539,12 @@ default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert South ('Eastern Palace', 'Eastern Portal'), ('Eastern Palace Exit', 'Light World'), ('Tower of Hera', 'Hera Portal'), - ('Tower of Hera Exit', 'Death Mountain (Top)'), + ('Tower of Hera Exit', 'West Death Mountain (Top)'), - ('Hyrule Castle Entrance (South)', 'Hyrule Castle South Portal'), - ('Hyrule Castle Entrance (West)', 'Hyrule Castle West Portal'), - ('Hyrule Castle Entrance (East)', 'Hyrule Castle East Portal'), - ('Hyrule Castle Exit (South)', 'Hyrule Castle Courtyard'), - ('Hyrule Castle Exit (West)', 'Hyrule Castle Ledge'), - ('Hyrule Castle Exit (East)', 'Hyrule Castle Ledge'), - - ('Thieves Town', 'Thieves Town Portal'), - ('Thieves Town Exit', 'West Dark World'), + ('Palace of Darkness', 'Palace of Darkness Portal'), + ('Palace of Darkness Exit', 'East Dark World'), + ('Swamp Palace', 'Swamp Portal'), # requires additional patch for flooding moat if moved + ('Swamp Palace Exit', 'South Dark World'), ('Skull Woods First Section Hole (East)', 'Skull Pinball'), ('Skull Woods First Section Hole (West)', 'Skull Left Drop'), ('Skull Woods First Section Hole (North)', 'Skull Pot Circle'), @@ -2525,35 +2557,30 @@ default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert South ('Skull Woods Second Section Exit (West)', 'Skull Woods Forest (West)'), ('Skull Woods Final Section', 'Skull 3 Portal'), ('Skull Woods Final Section Exit', 'Skull Woods Forest (West)'), + ('Thieves Town', 'Thieves Town Portal'), + ('Thieves Town Exit', 'West Dark World'), ('Ice Palace', 'Ice Portal'), + ('Ice Palace Exit', 'Dark Lake Hylia Central Island'), ('Misery Mire', 'Mire Portal'), ('Misery Mire Exit', 'Dark Desert'), - ('Palace of Darkness', 'Palace of Darkness Portal'), - ('Palace of Darkness Exit', 'East Dark World'), - ('Swamp Palace', 'Swamp Portal'), # requires additional patch for flooding moat if moved - ('Swamp Palace Exit', 'South Dark World'), - ('Turtle Rock', 'Turtle Rock Main Portal'), - ('Turtle Rock Ledge Exit (West)', 'Dark Death Mountain Ledge'), - ('Turtle Rock Ledge Exit (East)', 'Dark Death Mountain Ledge'), + ('Turtle Rock Exit (Front)', 'Dark Death Mountain (Top)'), ('Dark Death Mountain Ledge (West)', 'Turtle Rock Lazy Eyes Portal'), ('Dark Death Mountain Ledge (East)', 'Turtle Rock Chest Portal'), - ('Turtle Rock Isolated Ledge Exit', 'Dark Death Mountain Isolated Ledge'), - ('Turtle Rock Isolated Ledge Entrance', 'Turtle Rock Eye Bridge Portal') + ('Turtle Rock Ledge Exit (West)', 'Dark Death Mountain Ledge'), + ('Turtle Rock Ledge Exit (East)', 'Dark Death Mountain Ledge'), + ('Turtle Rock Isolated Ledge Entrance', 'Turtle Rock Eye Bridge Portal'), + ('Turtle Rock Isolated Ledge Exit', 'Dark Death Mountain Isolated Ledge') ] open_default_dungeon_connections = [('Agahnims Tower', 'Agahnims Tower Portal'), ('Agahnims Tower Exit', 'Hyrule Castle Ledge'), - ('Ice Palace Exit', 'Dark Lake Hylia Central Island'), - ('Turtle Rock Exit (Front)', 'Dark Death Mountain (Top)'), ('Ganons Tower', 'Ganons Tower Portal'), ('Ganons Tower Exit', 'Dark Death Mountain (Top)') ] inverted_default_dungeon_connections = [('Agahnims Tower', 'Ganons Tower Portal'), ('Agahnims Tower Exit', 'Dark Death Mountain (Top)'), - ('Ice Palace Exit', 'Dark Lake Hylia Central Island'), - ('Turtle Rock Exit (Front)', 'Dark Death Mountain (Top)'), ('Ganons Tower', 'Agahnims Tower Portal'), ('Ganons Tower Exit', 'Hyrule Castle Ledge') ] @@ -2654,7 +2681,7 @@ door_addresses = {'Links House': (0x00, (0x0104, 0x2c, 0x0506, 0x0a9a, 0x0832, 0 'Chicken House': (0x4A, (0x0108, 0x18, 0x1120, 0x0837, 0x0106, 0x0888, 0x0188, 0x08a4, 0x0193, 0x07, 0xf9, 0x1530, 0x0000)), 'Aginahs Cave': (0x70, (0x010a, 0x30, 0x0656, 0x0cc6, 0x02aa, 0x0d18, 0x0328, 0x0d33, 0x032f, 0x08, 0xf8, 0x0000, 0x0000)), 'Sahasrahlas Hut': (0x44, (0x0105, 0x1e, 0x0610, 0x06d4, 0x0c76, 0x0727, 0x0cf0, 0x0743, 0x0cfb, 0x0a, 0xf6, 0x0000, 0x0000)), - 'Cave Shop (Lake Hylia)': (0x57, (0x0112, 0x35, 0x0022, 0x0c00, 0x0b1a, 0x0c26, 0x0b98, 0x0c6d, 0x0b9f, 0x00, 0x00, 0x0000, 0x0000)), + 'Lake Hylia Shop': (0x57, (0x0112, 0x35, 0x0022, 0x0c00, 0x0b1a, 0x0c26, 0x0b98, 0x0c6d, 0x0b9f, 0x00, 0x00, 0x0000, 0x0000)), 'Capacity Upgrade': (0x5C, (0x0115, 0x35, 0x0a46, 0x0d36, 0x0c2a, 0x0d88, 0x0ca8, 0x0da3, 0x0caf, 0x0a, 0xf6, 0x0000, 0x0000)), 'Kakariko Well Drop': ([0xDB85C, 0xDB85D], None), 'Blacksmiths Hut': (0x63, (0x0121, 0x22, 0x010c, 0x081a, 0x0466, 0x0868, 0x04d8, 0x0887, 0x04e3, 0x06, 0xfa, 0x041A, 0x0000)), @@ -2697,19 +2724,19 @@ door_addresses = {'Links House': (0x00, (0x0104, 0x2c, 0x0506, 0x0a9a, 0x0832, 0 'Brewery': (0x47, (0x0106, 0x58, 0x16a8, 0x08e4, 0x013e, 0x0938, 0x01b8, 0x0953, 0x01c3, 0x0a, 0xf6, 0x1AB6, 0x0000)), 'C-Shaped House': (0x53, (0x011c, 0x58, 0x09d8, 0x0744, 0x02ce, 0x0797, 0x0348, 0x07b3, 0x0353, 0x0a, 0xf6, 0x0DE8, 0x0000)), 'Chest Game': (0x46, (0x0106, 0x58, 0x078a, 0x0705, 0x004e, 0x0758, 0x00c8, 0x0774, 0x00d3, 0x09, 0xf7, 0x0B98, 0x0000)), - 'Dark World Hammer Peg Cave': (0x7E, (0x0127, 0x62, 0x0894, 0x091e, 0x0492, 0x09a6, 0x0508, 0x098b, 0x050f, 0x00, 0x00, 0x0000, 0x0000)), + 'Hammer Peg Cave': (0x7E, (0x0127, 0x62, 0x0894, 0x091e, 0x0492, 0x09a6, 0x0508, 0x098b, 0x050f, 0x00, 0x00, 0x0000, 0x0000)), 'Red Shield Shop': (0x74, (0x0110, 0x5a, 0x079a, 0x06e8, 0x04d6, 0x0738, 0x0548, 0x0755, 0x0553, 0x08, 0xf8, 0x0AA8, 0x0000)), 'Dark Sanctuary Hint': (0x59, (0x0112, 0x53, 0x001e, 0x0400, 0x06e2, 0x0446, 0x0758, 0x046d, 0x075f, 0x00, 0x00, 0x0000, 0x0000)), 'Fortune Teller (Dark)': (0x65, (0x0122, 0x51, 0x0610, 0x04b4, 0x027e, 0x0507, 0x02f8, 0x0523, 0x0303, 0x0a, 0xf6, 0x091E, 0x0000)), 'Dark World Shop': (0x5F, (0x010f, 0x58, 0x1058, 0x0814, 0x02be, 0x0868, 0x0338, 0x0883, 0x0343, 0x0a, 0xf6, 0x0000, 0x0000)), - 'Dark World Lumberjack Shop': (0x56, (0x010f, 0x42, 0x041c, 0x0074, 0x04e2, 0x00c7, 0x0558, 0x00e3, 0x055f, 0x0a, 0xf6, 0x0000, 0x0000)), - 'Dark World Potion Shop': (0x6E, (0x010f, 0x56, 0x080e, 0x04f4, 0x0c66, 0x0548, 0x0cd8, 0x0563, 0x0ce3, 0x0a, 0xf6, 0x0000, 0x0000)), + 'Dark Lumberjack Shop': (0x56, (0x010f, 0x42, 0x041c, 0x0074, 0x04e2, 0x00c7, 0x0558, 0x00e3, 0x055f, 0x0a, 0xf6, 0x0000, 0x0000)), + 'Dark Potion Shop': (0x6E, (0x010f, 0x56, 0x080e, 0x04f4, 0x0c66, 0x0548, 0x0cd8, 0x0563, 0x0ce3, 0x0a, 0xf6, 0x0000, 0x0000)), 'Archery Game': (0x58, (0x0111, 0x69, 0x069e, 0x0ac4, 0x02ea, 0x0b18, 0x0368, 0x0b33, 0x036f, 0x0a, 0xf6, 0x09AC, 0x0000)), 'Mire Shed': (0x5E, (0x010d, 0x70, 0x0384, 0x0c69, 0x001e, 0x0cb6, 0x0098, 0x0cd6, 0x00a3, 0x07, 0xf9, 0x0000, 0x0000)), 'Dark Desert Hint': (0x61, (0x0114, 0x70, 0x0654, 0x0cc5, 0x02aa, 0x0d16, 0x0328, 0x0d32, 0x032f, 0x09, 0xf7, 0x0000, 0x0000)), 'Dark Desert Fairy': (0x55, (0x0115, 0x70, 0x03a8, 0x0c6a, 0x013a, 0x0cb7, 0x01b8, 0x0cd7, 0x01bf, 0x06, 0xfa, 0x0000, 0x0000)), 'Spike Cave': (0x40, (0x0117, 0x43, 0x0ed4, 0x01e4, 0x08aa, 0x0236, 0x0928, 0x0253, 0x092f, 0x0a, 0xf6, 0x0000, 0x0000)), - 'Cave Shop (Dark Death Mountain)': (0x6D, (0x0112, 0x45, 0x0ee0, 0x01e3, 0x0d00, 0x0236, 0x0daa, 0x0252, 0x0d7d, 0x0b, 0xf5, 0x0000, 0x0000)), + 'Dark Death Mountain Shop': (0x6D, (0x0112, 0x45, 0x0ee0, 0x01e3, 0x0d00, 0x0236, 0x0daa, 0x0252, 0x0d7d, 0x0b, 0xf5, 0x0000, 0x0000)), 'Dark Death Mountain Fairy': (0x6F, (0x0115, 0x43, 0x1400, 0x0294, 0x0600, 0x02e8, 0x0678, 0x0303, 0x0685, 0x0a, 0xf6, 0x0000, 0x0000)), 'Mimic Cave': (0x4E, (0x010c, 0x05, 0x07e0, 0x0103, 0x0d00, 0x0156, 0x0d78, 0x0172, 0x0d7d, 0x0b, 0xf5, 0x0000, 0x0000)), 'Big Bomb Shop': (0x52, (0x011c, 0x6c, 0x0506, 0x0a9a, 0x0832, 0x0ae7, 0x08b8, 0x0b07, 0x08bf, 0x06, 0xfa, 0x0816, 0x0000)), @@ -2789,7 +2816,7 @@ exit_ids = {'Links House Exit': (0x01, 0x00), 'Bonk Fairy (Light)': 0x71, 'Bonk Fairy (Dark)': 0x71, 'Lake Hylia Healer Fairy': 0x5E, - 'Swamp Healer Fairy': 0x5E, + 'Light Hype Fairy': 0x5E, 'Desert Healer Fairy': 0x5E, 'Dark Lake Hylia Healer Fairy': 0x5E, 'Dark Lake Hylia Ledge Healer Fairy': 0x5E, @@ -2802,8 +2829,8 @@ exit_ids = {'Links House Exit': (0x01, 0x00), 'Chicken House': 0x4B, 'Aginahs Cave': 0x4D, 'Sahasrahlas Hut': 0x45, - 'Cave Shop (Lake Hylia)': 0x58, - 'Cave Shop (Dark Death Mountain)': 0x58, + 'Lake Hylia Shop': 0x58, + 'Dark Death Mountain Shop': 0x58, 'Capacity Upgrade': 0x5D, 'Blacksmiths Hut': 0x64, 'Sick Kids House': 0x40, @@ -2834,15 +2861,15 @@ exit_ids = {'Links House Exit': (0x01, 0x00), 'Big Bomb Shop': 0x53, 'Village of Outcasts Shop': 0x60, 'Dark Lake Hylia Shop': 0x60, - 'Dark World Lumberjack Shop': 0x60, - 'Dark World Potion Shop': 0x60, + 'Dark Lumberjack Shop': 0x60, + 'Dark Potion Shop': 0x60, 'Dark Lake Hylia Ledge Spike Cave': 0x70, 'Dark Lake Hylia Ledge Hint': 0x6A, 'Hype Cave': 0x3D, 'Brewery': 0x48, 'C-Shaped House': 0x54, 'Chest Game': 0x47, - 'Dark World Hammer Peg Cave': 0x83, + 'Hammer Peg Cave': 0x83, 'Red Shield Shop': 0x57, 'Dark Sanctuary Hint': 0x5A, 'Fortune Teller (Dark)': 0x66, @@ -2935,7 +2962,7 @@ ow_prize_table = {'Links House': (0x8b1, 0xb2d), 'Chicken House': (0x120, 0x880), 'Aginahs Cave': (0x2e0, 0xd00), 'Sahasrahlas Hut': (0xcf0, 0x6c0), - 'Cave Shop (Lake Hylia)': (0xbc0, 0xc00), + 'Lake Hylia Shop': (0xbc0, 0xc00), 'Capacity Upgrade': (0xca0, 0xda0), 'Kakariko Well Drop': None, 'Blacksmiths Hut': (0x4a0, 0x880), @@ -2975,19 +3002,19 @@ ow_prize_table = {'Links House': (0x8b1, 0xb2d), 'Hype Cave': (0x940, 0xc80), 'Bonk Fairy (Dark)': (0x740, 0xa80), 'Brewery': (0x170, 0x980), 'C-Shaped House': (0x310, 0x7a0), 'Chest Game': (0x800, 0x7a0), - 'Dark World Hammer Peg Cave': (0x4c0, 0x940), + 'Hammer Peg Cave': (0x4c0, 0x940), 'Red Shield Shop': (0x500, 0x680), 'Dark Sanctuary Hint': (0x720, 0x4a0), 'Fortune Teller (Dark)': (0x2c0, 0x4c0), 'Dark World Shop': (0x2e0, 0x880), - 'Dark World Lumberjack Shop': (0x4e0, 0x0d0), - 'Dark World Potion Shop': (0xc80, 0x4c0), + 'Dark Lumberjack Shop': (0x4e0, 0x0d0), + 'Dark Potion Shop': (0xc80, 0x4c0), 'Archery Game': (0x2f0, 0xaf0), 'Mire Shed': (0x060, 0xc90), 'Dark Desert Hint': (0x2e0, 0xd00), 'Dark Desert Fairy': (0x1c0, 0xc90), 'Spike Cave': (0x860, 0x180), - 'Cave Shop (Dark Death Mountain)': (0xd80, 0x180), + 'Dark Death Mountain Shop': (0xd80, 0x180), 'Dark Death Mountain Fairy': (0x620, 0x2c0), 'Mimic Cave': (0xc80, 0x180), 'Big Bomb Shop': (0x8b1, 0xb2d), diff --git a/ItemList.py b/ItemList.py index c17ce509..f0dd572f 100644 --- a/ItemList.py +++ b/ItemList.py @@ -435,7 +435,7 @@ def generate_itempool(world, player): take_any_locations = [ 'Snitch Lady (East)', 'Snitch Lady (West)', 'Bush Covered House', 'Light World Bomb Hut', 'Fortune Teller (Light)', 'Lake Hylia Fortune Teller', 'Lumberjack House', 'Bonk Fairy (Light)', - 'Bonk Fairy (Dark)', 'Lake Hylia Healer Fairy', 'Swamp Healer Fairy', 'Desert Healer Fairy', + 'Bonk Fairy (Dark)', 'Lake Hylia Healer Fairy', 'Light Hype Fairy', 'Desert Healer Fairy', 'Dark Lake Hylia Healer Fairy', 'Dark Lake Hylia Ledge Healer Fairy', 'Dark Desert Healer Fairy', 'Dark Death Mountain Healer Fairy', 'Long Fairy Cave', 'Good Bee Cave', '20 Rupee Cave', 'Kakariko Gamble Game', '50 Rupee Cave', 'Lost Woods Gamble', 'Hookshot Fairy', @@ -443,7 +443,7 @@ take_any_locations = [ 'Dark Lake Hylia Ledge Spike Cave', 'Fortune Teller (Dark)', 'Dark Sanctuary Hint', 'Dark Desert Hint'] fixed_take_anys = [ - 'Desert Healer Fairy', 'Swamp Healer Fairy', 'Dark Death Mountain Healer Fairy', + 'Desert Healer Fairy', 'Light Hype Fairy', 'Dark Death Mountain Healer Fairy', 'Dark Lake Hylia Ledge Healer Fairy', 'Bonk Fairy (Dark)'] @@ -781,7 +781,7 @@ def balance_prices(world, player): def check_hints(world, player): if world.shuffle[player] in ['simple', 'restricted', 'full', 'crossed', 'insanity']: for shop, location_list in shop_to_location_table.items(): - if shop in ['Capacity Upgrade', 'Light World Death Mountain Shop', 'Potion Shop']: + if shop in ['Capacity Upgrade', 'Paradox Shop', 'Potion Shop']: continue # near the queen, near potions, and near 7 chests are fine for loc_name in location_list: # other shops are indistinguishable in ER world.get_location(loc_name, player).hint_text = f'for sale' diff --git a/OverworldGlitchRules.py b/OverworldGlitchRules.py index 2268246e..ad9203fd 100644 --- a/OverworldGlitchRules.py +++ b/OverworldGlitchRules.py @@ -34,7 +34,7 @@ def get_invalid_mirror_bunny_entrances(): yield 'Hype Cave' yield 'Bonk Fairy (Dark)' yield 'Thieves Town' - yield 'Dark World Hammer Peg Cave' + yield 'Hammer Peg Cave' yield 'Brewery' yield 'Hookshot Cave' yield 'Dark Lake Hylia Ledge Fairy' @@ -135,23 +135,23 @@ def get_boots_clip_exits_lw(inverted = False): """ yield ('Bat Cave River Clip Spot', 'Light World', 'Bat Cave Ledge') - yield ('Light World DMA Clip Spot', 'Light World', 'Death Mountain (West Bottom)') - yield ('Hera Ascent', 'Death Mountain (West Bottom)', 'Death Mountain (Top)') + yield ('Light World DMA Clip Spot', 'Light World', 'West Death Mountain (Bottom)') + yield ('Hera Ascent', 'West Death Mountain (Bottom)', 'West Death Mountain (Top)') yield ('Death Mountain Return Ledge Clip Spot', 'Light World', 'Death Mountain Return Ledge') yield ('Death Mountain Entrance Clip Spot', 'Light World', 'Death Mountain Entrance') - yield ('Death Mountain Glitched Bridge', 'Death Mountain (West Bottom)', 'East Death Mountain (Top)') + yield ('Death Mountain Glitched Bridge', 'West Death Mountain (Bottom)', 'East Death Mountain (Top)') yield ('Zora Descent Clip Spot', 'East Death Mountain (Top)', 'Zoras Domain') yield ('Desert Northern Cliffs', 'Light World', 'Desert Northern Cliffs') yield ('Desert Ledge Dropdown', 'Desert Northern Cliffs', 'Desert Ledge') yield ('Desert Palace Entrance Dropdown', 'Desert Northern Cliffs', 'Desert Palace Entrance (North) Spot') yield ('Lake Hylia Island Clip Spot', 'Light World', 'Lake Hylia Island') - yield ('Death Mountain Descent', 'Death Mountain (West Bottom)', 'Light World') - yield ('Kings Grave Clip Spot', 'Death Mountain (West Bottom)', 'Kings Grave Area') + yield ('Death Mountain Descent', 'West Death Mountain (Bottom)', 'Light World') + yield ('Kings Grave Clip Spot', 'West Death Mountain (Bottom)', 'Kings Grave Area') if not inverted: - yield ('Graveyard Ledge Clip Spot', 'Death Mountain (West Bottom)', 'Graveyard Ledge') + yield ('Graveyard Ledge Clip Spot', 'West Death Mountain (Bottom)', 'Graveyard Ledge') yield ('Desert Ledge (Northeast) Dropdown', 'Desert Northern Cliffs', 'Desert Checkerboard Ledge') - yield ('Spectacle Rock Clip Spot', 'Death Mountain (Top)', 'Spectacle Rock') + yield ('Spectacle Rock Clip Spot', 'West Death Mountain (Top)', 'Spectacle Rock') yield ('Bombos Tablet Clip Spot', 'Light World', 'Bombos Tablet Ledge') yield ('Floating Island Clip Spot', 'East Death Mountain (Top)', 'Death Mountain Floating Island') yield ('Cave 45 Clip Spot', 'Light World', 'Cave 45 Ledge') @@ -162,19 +162,19 @@ def get_boots_clip_exits_dw(inverted): Special Dark World region exits that require boots clips. """ - yield ('Dark World DMA Clip Spot', 'West Dark World', 'Dark Death Mountain (West Bottom)') + yield ('Dark World DMA Clip Spot', 'West Dark World', 'West Dark Death Mountain (Bottom)') yield ('Bumper Cave Ledge Clip Spot', 'West Dark World', 'Bumper Cave Ledge') yield ('Bumper Cave Entrance Clip Spot', 'West Dark World', 'Bumper Cave Entrance') yield ('Catfish Descent', 'Dark Death Mountain (Top)', 'Catfish Area') yield ('Hammer Pegs River Clip Spot', 'East Dark World', 'Hammer Peg Area') yield ('Dark Lake Hylia Ledge Clip Spot', 'East Dark World', 'Southeast Dark World') yield ('Dark Desert Cliffs Clip Spot', 'South Dark World', 'Dark Desert') - yield ('DW Floating Island Clip Spot', 'Dark Death Mountain (East Bottom)', 'Death Mountain Floating Island (Dark World)') + yield ('DW Floating Island Clip Spot', 'East Dark Death Mountain (Bottom)', 'Dark Death Mountain Floating Island') if not inverted: - yield ('Dark Death Mountain Descent', 'Dark Death Mountain (West Bottom)', 'West Dark World') - yield ('Ganons Tower Ascent', 'Dark Death Mountain (West Bottom)', 'Dark Death Mountain (Top)') # This only gets you to the GT entrance - yield ('Dark Death Mountain Glitched Bridge', 'Dark Death Mountain (West Bottom)', 'Dark Death Mountain (Top)') + yield ('Dark Death Mountain Descent', 'West Dark Death Mountain (Bottom)', 'West Dark World') + yield ('Ganons Tower Ascent', 'West Dark Death Mountain (Bottom)', 'Dark Death Mountain (Top)') # This only gets you to the GT entrance + yield ('Dark Death Mountain Glitched Bridge', 'West Dark Death Mountain (Bottom)', 'Dark Death Mountain (Top)') yield ('Turtle Rock (Top) Clip Spot', 'Dark Death Mountain (Top)', 'Turtle Rock (Top)') else: yield ('Dark Desert Teleporter Clip Spot', 'Dark Desert', 'Dark Desert Ledge') @@ -191,8 +191,8 @@ def get_mirror_clip_spots_dw(): """ Out of bounds transitions using the mirror """ - yield ('Dark Death Mountain Bunny Descent Mirror Spot', 'Dark Death Mountain (West Bottom)', 'West Dark World') - yield ('Dark Death Mountain Bunny Mirror To East Jump', 'Dark Death Mountain (West Bottom)', 'Dark Death Mountain (East Bottom)') + yield ('Dark Death Mountain Bunny Descent Mirror Spot', 'West Dark Death Mountain (Bottom)', 'West Dark World') + yield ('Dark Death Mountain Bunny Mirror To East Jump', 'West Dark Death Mountain (Bottom)', 'East Dark Death Mountain (Bottom)') yield ('Desert East Mirror Clip', 'Dark Desert', 'Desert Palace Mouth') @@ -200,15 +200,15 @@ def get_mirror_offset_spots_dw(): """ Mirror shenanigans placing a mirror portal with a broken camera """ - yield ('Dark Death Mountain Offset Mirror', 'Dark Death Mountain (West Bottom)', 'East Dark World') + yield ('Dark Death Mountain Offset Mirror', 'West Dark Death Mountain (Bottom)', 'East Dark World') def get_mirror_offset_spots_lw(player): """ Mirror shenanigans placing a mirror portal with a broken camera """ - yield ('Death Mountain Offset Mirror', 'Death Mountain (West Bottom)', 'Light World') - yield ('Death Mountain Offset Mirror (Houlihan Exit)', 'Death Mountain (West Bottom)', 'Hyrule Castle Ledge', lambda state: state.has_Mirror(player) and state.can_boots_clip_dw(player) and state.has_Pearl(player)) + yield ('Death Mountain Offset Mirror', 'West Death Mountain (Bottom)', 'Light World') + yield ('Death Mountain Offset Mirror (Houlihan Exit)', 'West Death Mountain (Bottom)', 'Hyrule Castle Ledge', lambda state: state.has_Mirror(player) and state.can_boots_clip_dw(player) and state.has_Pearl(player)) def create_owg_connections(world, player): @@ -256,7 +256,7 @@ def overworld_glitches_rules(world, player): world.get_entrance('Dark Desert Teleporter', player).access_rule = lambda state: (state.can_flute(player) or state.can_boots_clip_dw(player)) and state.can_lift_heavy_rocks(player) add_alternate_rule(world.get_entrance('Dark Witch Rock (North)', player), lambda state: state.can_boots_clip_dw(player)) - add_alternate_rule(world.get_entrance('East Dark World Broken Bridge Pass', player), lambda state: state.can_boots_clip_dw(player)) + add_alternate_rule(world.get_entrance('Broken Bridge Pass (Top)', player), lambda state: state.can_boots_clip_dw(player)) add_alternate_rule(world.get_location('Zora\'s Ledge', player), lambda state: state.can_boots_clip_lw(player)) # assumes access to Waterwalk ability diff --git a/PotShuffle.py b/PotShuffle.py index 29a561c9..6a4df35e 100644 --- a/PotShuffle.py +++ b/PotShuffle.py @@ -851,10 +851,10 @@ vanilla_pots = { Pot(100, 22, PotItem.Heart, 'Dark Lake Hylia Ledge Spike Cave', obj=RoomObject(0x0AB62A, [0xCB, 0xB3, 0xFA])), Pot(88, 28, PotItem.Heart, 'Dark Lake Hylia Ledge Spike Cave', obj=RoomObject(0x0AB633, [0xB3, 0xE3, 0xFA])), Pot(100, 28, PotItem.Heart, 'Dark Lake Hylia Ledge Spike Cave', obj=RoomObject(0x0AB636, [0xCB, 0xE3, 0xFA]))], - 0x127: [Pot(24, 25, PotItem.Nothing, 'Dark World Hammer Peg Cave', obj=RoomObject(0x2B801A, [0x33, 0xCB, 0xFA])), - Pot(28, 25, PotItem.Nothing, 'Dark World Hammer Peg Cave', obj=RoomObject(0x2B801D, [0x3B, 0xCB, 0xFA])), - Pot(32, 25, PotItem.Nothing, 'Dark World Hammer Peg Cave', obj=RoomObject(0x2B8020, [0x43, 0xCB, 0xFA])), - Pot(36, 25, PotItem.Nothing, 'Dark World Hammer Peg Cave', obj=RoomObject(0x2B8023, [0x4B, 0xCB, 0xFA]))], + 0x127: [Pot(24, 25, PotItem.Nothing, 'Hammer Peg Cave', obj=RoomObject(0x2B801A, [0x33, 0xCB, 0xFA])), + Pot(28, 25, PotItem.Nothing, 'Hammer Peg Cave', obj=RoomObject(0x2B801D, [0x3B, 0xCB, 0xFA])), + Pot(32, 25, PotItem.Nothing, 'Hammer Peg Cave', obj=RoomObject(0x2B8020, [0x43, 0xCB, 0xFA])), + Pot(36, 25, PotItem.Nothing, 'Hammer Peg Cave', obj=RoomObject(0x2B8023, [0x4B, 0xCB, 0xFA]))], } diff --git a/Regions.py b/Regions.py index b98465ca..52cc2e0c 100644 --- a/Regions.py +++ b/Regions.py @@ -9,132 +9,83 @@ def create_regions(world, player): create_menu_region(player, 'Menu', None, ['Links House S&Q', 'Sanctuary S&Q', 'Old Man S&Q', 'Other World S&Q']), create_menu_region(player, 'Flute Sky', None, ['Flute Spot 1', 'Flute Spot 2', 'Flute Spot 3', 'Flute Spot 4', 'Flute Spot 5', 'Flute Spot 6', 'Flute Spot 7', 'Flute Spot 8']), create_lw_region(player, 'Light World', ['Mushroom', 'Bottle Merchant', 'Flute Spot', 'Sunken Treasure', 'Purple Chest'], - ['Blinds Hideout', 'Hyrule Castle Secret Entrance Drop', 'Kings Grave Outer Rocks', 'Dam', + ['Blinds Hideout', 'Hyrule Castle Secret Entrance Drop', 'Kings Grave Rocks (Outer)', 'Dam', 'Links House', 'Tavern North', 'Chicken House', 'Aginahs Cave', 'Sahasrahlas Hut', 'Kakariko Well Drop', 'Kakariko Well Cave', 'Blacksmiths Hut', 'Bat Cave Ledge Peg', 'Bat Cave Cave', 'Sick Kids House', 'Lost Woods Hideout Drop', 'Lost Woods Hideout Stump', 'Lumberjack Tree Tree', 'Lumberjack Tree Cave', 'Mini Moldorm Cave', 'Ice Rod Cave', 'Bonk Rock Cave', 'Library', 'Two Brothers House (East)', 'Desert Statue Move', 'Eastern Palace', 'Master Sword Meadow', 'Sanctuary', 'Sanctuary Grave', 'Death Mountain Entrance Rock', 'Light World Water Drop', 'LW Flute', 'East Hyrule Teleporter', 'South Hyrule Teleporter', 'Kakariko Teleporter', 'Elder House (East)', 'Elder House (West)', 'North Fairy Cave', 'North Fairy Cave Drop', 'Lost Woods Gamble', 'Snitch Lady (East)', 'Snitch Lady (West)', 'Tavern (Front)', - 'Kakariko Shop', 'Long Fairy Cave', 'Good Bee Cave', '20 Rupee Cave', 'Cave Shop (Lake Hylia)', 'Hyrule Castle Main Gate', - 'Bonk Fairy (Light)', '50 Rupee Cave', 'Fortune Teller (Light)', 'Lake Hylia Fairy', 'Light Hype Fairy', 'Desert Fairy', 'Lumberjack House', 'Lake Hylia Fortune Teller', 'Kakariko Gamble Game', 'Top of Pyramid', + 'Kakariko Shop', 'Long Fairy Cave', 'Good Bee Cave', '20 Rupee Cave', 'Lake Hylia Shop', 'Hyrule Castle Main Gate', + 'Bonk Fairy (Light)', '50 Rupee Cave', 'Fortune Teller (Light)', 'Lake Hylia Fairy', 'Light Hype Fairy', 'Desert Fairy', 'Lumberjack House', 'Lake Hylia Fortune Teller', 'Kakariko Gamble Game', 'Castle Gate Teleporter', 'East Dark World Mirror Spot', 'West Dark World Mirror Spot', 'South Dark World Mirror Spot', 'Cave 45 Approach', 'Checkerboard Ledge Approach', 'Mire Mirror Spot', 'Hammer Peg Area Mirror Spot', 'Shopping Mall Mirror Spot', 'Skull Woods Mirror Spot', 'Kakariko Yard Bush (South)', 'Bombos Tablet Ladder (Bottom)', 'Wooden Bridge Bush (South)', 'Graveyard Ladder (Bottom)', 'Kakariko Southwest Bush (North)']), + create_lw_region(player, 'West Death Mountain (Top)', ['Ether Tablet'], ['DM Hammer Bridge (West)', 'Tower of Hera', 'Death Mountain Drop', 'Spectacle Rock Approach', 'Death Mountain (Top) Mirror Spot']), + create_lw_region(player, 'West Death Mountain (Bottom)', None, ['Old Man Cave (East)', 'Old Man House (Bottom)', 'Old Man House (Top)', 'Death Mountain Return Cave (East)', 'Spectacle Rock Cave', + 'Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Bottom)', 'DM Broken Bridge (West)', 'Death Mountain Mirror Spot', 'DM Flute', 'Death Mountain Teleporter']), + create_lw_region(player, 'Spectacle Rock', ['Spectacle Rock'], ['Spectacle Rock Drop', 'Spectacle Rock Leave']), + create_lw_region(player, 'East Death Mountain (Top)', None, ['Paradox Cave (Top)', 'DM Hammer Bridge (East)', 'Floating Island Bridge (East)', 'Spiral Cave Ledge Access', 'East Death Mountain Drop', 'Turtle Rock Teleporter', 'East Death Mountain Mirror Spot (Top)', 'Fairy Ascension Ledge Access', 'Mimic Cave Ledge Access']), + create_lw_region(player, 'Death Mountain Floating Island', ['Floating Island'], ['Floating Island Bridge (West)', 'Floating Island Mirror Spot']), + create_lw_region(player, 'Spiral Cave Ledge', None, ['Spiral Cave', 'Spiral Cave Ledge Drop', 'Dark Death Mountain Ledge Mirror Spot (West)']), + create_lw_region(player, 'Mimic Cave Ledge', None, ['Mimic Cave', 'Mimic Cave Ledge Drop', 'Dark Death Mountain Ledge Mirror Spot (East)']), + create_lw_region(player, 'Fairy Ascension Ledge', None, ['Fairy Ascension Ledge Drop', 'Fairy Ascension Cave (Top)', 'Laser Bridge Mirror Spot']), + create_lw_region(player, 'East Death Mountain (Bottom)', None, ['DM Broken Bridge (East)', 'Paradox Cave (Bottom)', 'Paradox Cave (Middle)', 'East Death Mountain Mirror Spot (Bottom)', 'East Death Mountain Teleporter', 'Hookshot Fairy', + 'Fairy Ascension Rocks', 'Spiral Cave (Bottom)', 'EDM Flute']), + create_lw_region(player, 'Fairy Ascension Plateau', None, ['Fairy Ascension Drop', 'Fairy Ascension Cave (Bottom)']), + create_lw_region(player, 'Death Mountain Return Ledge', None, ['Death Mountain Return Ledge Drop', 'Death Mountain Return Cave (West)', 'Mountain Exit Ledge Mirror Spot'], 'a ledge in the foothills'), + create_lw_region(player, 'Death Mountain Entrance', None, ['Old Man Cave (West)', 'Death Mountain Entrance Drop', 'Mountain Entrance Mirror Spot']), + create_lw_region(player, 'Northeast Light World', None, ['Zoras Domain', 'Potion Shop Rock (North)', 'Catfish Mirror Spot', 'Northeast Light World Water Drop']), + create_lw_region(player, 'Zora Waterfall Entryway', None, ['Waterfall of Wishing', 'ZLW Flute', 'Zora Waterfall Water Drop']), + create_lw_region(player, 'Graveyard Ledge', None, ['Graveyard Cave', 'Graveyard Ledge Drop', 'Graveyard Ladder (Top)', 'Graveyard Cave Mirror Spot']), + create_lw_region(player, 'Kings Grave Area', None, ['Kings Grave', 'Kings Grave Rocks (Inner)']), + create_lw_region(player, 'Potion Shop Area', None, ['Potion Shop', 'Wooden Bridge Bush (North)', 'Potion Shop Rock (South)', 'NWLW Flute', 'Potion Shop Mirror Spot', 'Potion Shop Water Drop']), create_lw_region(player, 'Bush Covered Lawn', None, ['Bush Covered House', 'Kakariko Yard Bush (North)', 'Bush Covered Lawn Mirror Spot']), create_lw_region(player, 'Bomb Hut Area', None, ['Light World Bomb Hut', 'Kakariko Southwest Bush (South)', 'Bomb Hut Mirror Spot']), - create_lw_region(player, 'Death Mountain Entrance', None, ['Old Man Cave (West)', 'Death Mountain Entrance Drop']), - create_lw_region(player, 'Lake Hylia Central Island', None, ['Capacity Upgrade', 'Lake Hylia Central Island Water Drop', 'Lake Hylia Central Island Teleporter']), - create_cave_region(player, 'Blinds Hideout', 'a bounty of five items', [ - "Blind's Hideout - Left", - "Blind's Hideout - Right", - "Blind's Hideout - Far Left", - "Blind's Hideout - Far Right"], - ['Blinds Hideout N']), - create_cave_region(player, 'Blinds Hideout (Top)', 'a bounty of five items', ["Blind's Hideout - Top"]), - create_lw_region(player, 'Northeast Light World', None, ['Zoras Domain', 'Potion Shop Rock (North)', 'Catfish Mirror Spot', 'Northeast Light World Water Drop']), - create_lw_region(player, 'Potion Shop Area', None, ['Potion Shop', 'Wooden Bridge Bush (North)', 'Potion Shop Rock (South)', 'NWLW Flute', 'Potion Shop Mirror Spot', 'Potion Shop Water Drop']), - create_lw_region(player, 'Lake Hylia Water', None, ['Hobo Pier', 'Light World Pier', 'Potion Shop Pier', 'Lake Hylia Central Island Pier', 'Lake Hylia Island Pier', 'Lake Hylia Whirlpool', 'Waterfall Fairy Access']), - create_cave_region(player, 'Hyrule Castle Secret Entrance', 'a drop\'s exit', ['Link\'s Uncle', 'Secret Passage'], ['Hyrule Castle Secret Entrance Exit']), - create_lw_region(player, 'Zoras Domain', ['King Zora', 'Zora\'s Ledge']), - create_lw_region(player, 'Zora Waterfall Entryway', None, ['Waterfall of Wishing', 'ZLW Flute', 'Zora Waterfall Water Drop']), - create_cave_region(player, 'Waterfall of Wishing', 'a cave with two chests', ['Waterfall Fairy - Left', 'Waterfall Fairy - Right']), - create_lw_region(player, 'Kings Grave Area', None, ['Kings Grave', 'Kings Grave Inner Rocks']), - create_cave_region(player, 'Kings Grave', 'a cave with a chest', ['King\'s Tomb']), - create_cave_region(player, 'North Fairy Cave', 'a drop\'s exit', None, ['North Fairy Cave Exit']), - create_cave_region(player, 'Dam', 'the dam', ['Floodgate', 'Floodgate Chest']), - create_cave_region(player, 'Links House', 'your house', ['Link\'s House'], ['Links House Exit']), - create_cave_region(player, 'Chris Houlihan Room', 'I AM ERROR', None, ['Chris Houlihan Room Exit']), - create_cave_region(player, 'Tavern', 'the tavern', ['Kakariko Tavern']), - create_cave_region(player, 'Elder House', 'a connector', None, ['Elder House Exit (East)', 'Elder House Exit (West)']), - create_cave_region(player, 'Snitch Lady (East)', 'a boring house'), - create_cave_region(player, 'Snitch Lady (West)', 'a boring house'), - create_cave_region(player, 'Bush Covered House', 'the grass man'), - create_cave_region(player, 'Tavern (Front)', 'the tavern'), - create_cave_region(player, 'Light World Bomb Hut', 'a restock room'), - create_cave_region(player, 'Kakariko Shop', 'a common shop', ['Kakariko Shop - Left', 'Kakariko Shop - Middle', 'Kakariko Shop - Right']), - create_cave_region(player, 'Fortune Teller (Light)', 'a fortune teller'), - create_cave_region(player, 'Lake Hylia Fortune Teller', 'a fortune teller'), - create_cave_region(player, 'Lumberjack House', 'a boring house'), - create_cave_region(player, 'Bonk Fairy (Light)', 'a fairy fountain'), - create_cave_region(player, 'Bonk Fairy (Dark)', 'a fairy fountain'), - create_cave_region(player, 'Lake Hylia Healer Fairy', 'a fairy fountain'), - create_cave_region(player, 'Swamp Healer Fairy', 'a fairy fountain'), - create_cave_region(player, 'Desert Healer Fairy', 'a fairy fountain'), - create_cave_region(player, 'Dark Lake Hylia Healer Fairy', 'a fairy fountain'), - create_cave_region(player, 'Dark Lake Hylia Ledge Healer Fairy', 'a fairy fountain'), - create_cave_region(player, 'Dark Desert Healer Fairy', 'a fairy fountain'), - create_cave_region(player, 'Dark Death Mountain Healer Fairy', 'a fairy fountain'), - create_cave_region(player, 'Chicken House', 'a house with a chest', ['Chicken House']), - create_cave_region(player, 'Aginahs Cave', 'a cave with a chest', ['Aginah\'s Cave']), - create_cave_region(player, 'Sahasrahlas Hut', 'Sahasrahla', ['Sahasrahla\'s Hut - Left', 'Sahasrahla\'s Hut - Middle', 'Sahasrahla\'s Hut - Right', 'Sahasrahla']), - create_cave_region(player, 'Kakariko Well (top)', 'a drop', - ['Kakariko Well - Left', 'Kakariko Well - Middle', 'Kakariko Well - Right', - 'Kakariko Well - Bottom'], - ['Kakariko Well (top to bottom)', 'Kakariko Well (top to back)']), - create_cave_region(player, 'Kakariko Well (back)', 'a drop', ['Kakariko Well - Top']), - create_cave_region(player, 'Kakariko Well (bottom)', 'a drop\'s exit', None, ['Kakariko Well Exit']), - create_cave_region(player, 'Blacksmiths Hut', 'the smith', ['Blacksmith', 'Missing Smith']), + create_lw_region(player, 'Hyrule Castle Courtyard', None, ['Hyrule Castle Entrance (South)', 'Inverted Pyramid Entrance', 'Hyrule Castle Courtyard Bush (South)', 'Hyrule Castle Main Gate (North)']), + create_lw_region(player, 'Hyrule Castle Secret Entrance Area', None, ['Hyrule Castle Secret Entrance Stairs', 'Hyrule Castle Courtyard Bush (North)', 'Pyramid Uncle Mirror Spot']), + create_lw_region(player, 'Hyrule Castle Ledge', None, ['Hyrule Castle Entrance (East)', 'Hyrule Castle Entrance (West)', 'Agahnims Tower', 'Hyrule Castle Ledge Courtyard Drop', 'Hyrule Castle Ledge Drop', 'Inverted Pyramid Hole'], 'the castle rampart'), create_lw_region(player, 'Bat Cave Ledge', None, ['Bat Cave Drop', 'Bat Cave Ledge Peg (East)']), - create_cave_region(player, 'Bat Cave (right)', 'a drop', ['Magic Bat'], ['Bat Cave Door']), - create_cave_region(player, 'Bat Cave (left)', 'a drop\'s exit', None, ['Bat Cave Exit']), - create_cave_region(player, 'Sick Kids House', 'the sick kid', ['Sick Kid']), + create_lw_region(player, 'Maze Race Ledge', ['Maze Race'], ['Two Brothers House (West)', 'Maze Race Mirror Spot', 'Maze Race Ledge Drop'], 'a race against time'), + create_lw_region(player, 'Desert Palace Stairs', None, ['Desert Palace Entrance (South)', 'Desert Palace Stairs Mirror Spot']), + create_lw_region(player, 'Desert Palace Mouth', None, ['Desert Palace Mouth Drop', 'Desert Palace Entrance (East)'], 'a sandy vista'), + create_lw_region(player, 'Desert Ledge', ['Desert Ledge'], ['Desert Ledge Rocks (Outer)', 'Desert Palace Entrance (West)', 'Desert Ledge Drop'], 'the desert ledge'), + create_lw_region(player, 'Desert Palace Entrance (North) Spot', None, ['Desert Palace Entrance (North)', 'Desert Ledge Rocks (Inner)', 'Desert Palace North Mirror Spot'], 'the desert ledge'), + create_lw_region(player, 'Desert Checkerboard Ledge', None, ['Checkerboard Cave', 'Checkerboard Ledge Drop', 'Checkerboard Ledge Leave']), + create_lw_region(player, 'Desert Teleporter Ledge', None, ['Desert Teleporter Drop', 'Desert Teleporter']), + create_lw_region(player, 'Bombos Tablet Ledge', ['Bombos Tablet'], ['Bombos Tablet Ladder (Top)']), + create_lw_region(player, 'Desert Northern Cliffs'), + create_lw_region(player, 'Cave 45 Ledge', None, ['Cave 45', 'Cave 45 Ledge Drop', 'Cave 45 Leave']), + create_lw_region(player, 'Lake Hylia Water', None, ['Hobo Pier', 'Light World Pier', 'Potion Shop Pier', 'Lake Hylia Central Island Pier', 'Lake Hylia Island Pier', 'Lake Hylia Whirlpool', 'Waterfall Fairy Access']), + create_lw_region(player, 'Lake Hylia Island', ['Lake Hylia Island']), + create_lw_region(player, 'Lake Hylia Central Island', None, ['Capacity Upgrade', 'Lake Hylia Central Island Water Drop', 'Lake Hylia Teleporter']), + create_lw_region(player, 'Master Sword Meadow', ['Master Sword Pedestal']), create_lw_region(player, 'Hobo Bridge', ['Hobo']), + create_lw_region(player, 'Zoras Domain', ['King Zora', 'Zora\'s Ledge']), + + create_cave_region(player, 'Lost Woods Gamble', 'a game of chance'), create_cave_region(player, 'Lost Woods Hideout (top)', 'a drop\'s exit', ['Lost Woods Hideout'], ['Lost Woods Hideout (top to bottom)']), create_cave_region(player, 'Lost Woods Hideout (bottom)', 'a drop\'s exit', None, ['Lost Woods Hideout Exit']), create_cave_region(player, 'Lumberjack Tree (top)', 'a drop\'s exit', ['Lumberjack Tree'], ['Lumberjack Tree (top to bottom)']), create_cave_region(player, 'Lumberjack Tree (bottom)', 'a drop\'s exit', None, ['Lumberjack Tree Exit']), - create_lw_region(player, 'Cave 45 Ledge', None, ['Cave 45', 'Cave 45 Ledge Drop', 'Cave 45 Leave']), - create_cave_region(player, 'Cave 45', 'a cave with an item', ['Cave 45']), - create_lw_region(player, 'Graveyard Ledge', None, ['Graveyard Cave', 'Graveyard Ledge Drop', 'Graveyard Ladder (Top)', 'Graveyard Cave Mirror Spot']), - create_cave_region(player, 'Graveyard Cave', 'a cave with an item', ['Graveyard Cave']), - create_cave_region(player, 'Checkerboard Cave', 'a cave with an item', ['Checkerboard Cave']), - create_cave_region(player, 'Long Fairy Cave', 'a fairy fountain'), - create_cave_region(player, 'Mini Moldorm Cave', 'a bounty of five items', ['Mini Moldorm Cave - Far Left', 'Mini Moldorm Cave - Left', 'Mini Moldorm Cave - Right', - 'Mini Moldorm Cave - Far Right', 'Mini Moldorm Cave - Generous Guy']), - create_cave_region(player, 'Ice Rod Cave', 'a cave with a chest', ['Ice Rod Cave']), - create_cave_region(player, 'Good Bee Cave', 'a cold bee'), - create_cave_region(player, '20 Rupee Cave', 'a cave with some cash'), - create_cave_region(player, 'Cave Shop (Lake Hylia)', 'a common shop', ['Lake Hylia Shop - Left', 'Lake Hylia Shop - Middle', 'Lake Hylia Shop - Right']), - create_cave_region(player, 'Cave Shop (Dark Death Mountain)', 'a common shop', ['Dark Death Mountain Shop - Left', 'Dark Death Mountain Shop - Middle', 'Dark Death Mountain Shop - Right']), - create_cave_region(player, 'Bonk Rock Cave', 'a cave with a chest', ['Bonk Rock Cave']), - create_cave_region(player, 'Library', 'the library', ['Library']), - create_cave_region(player, 'Kakariko Gamble Game', 'a game of chance'), - create_cave_region(player, 'Potion Shop', 'the potion shop', ['Potion Shop', 'Potion Shop - Left', 'Potion Shop - Middle', 'Potion Shop - Right']), - create_lw_region(player, 'Lake Hylia Island', ['Lake Hylia Island']), - create_cave_region(player, 'Capacity Upgrade', 'the queen of fairies', ['Capacity Upgrade - Left', 'Capacity Upgrade - Right']), - create_cave_region(player, 'Two Brothers House', 'a connector', None, ['Two Brothers House Exit (East)', 'Two Brothers House Exit (West)']), - create_lw_region(player, 'Maze Race Ledge', ['Maze Race'], ['Two Brothers House (West)', 'Maze Race Mirror Spot', 'Maze Race Ledge Drop'], 'a race against time'), - create_cave_region(player, '50 Rupee Cave', 'a cave with some cash'), - create_lw_region(player, 'Desert Ledge', ['Desert Ledge'], ['Desert Palace Entrance (North) Rocks', 'Desert Palace Entrance (West)', 'Desert Ledge Drop'], 'the desert ledge'), - create_lw_region(player, 'Desert Checkerboard Ledge', None, ['Checkerboard Cave', 'Checkerboard Ledge Drop', 'Checkerboard Ledge Leave']), - create_lw_region(player, 'Desert Palace Stairs', None, ['Desert Palace Entrance (South)', 'Desert Palace Stairs Mirror Spot']), - create_lw_region(player, 'Desert Palace Mouth', None, ['Desert Palace Stairs Drop', 'Desert Palace Entrance (East)'], 'a sandy vista'), - create_lw_region(player, 'Desert Palace Entrance (North) Spot', None, ['Desert Palace Entrance (North)', 'Desert Ledge Return Rocks', 'Desert Palace North Mirror Spot'], 'the desert ledge'), - create_lw_region(player, 'Desert Teleporter Ledge', None, ['Desert Teleporter Drop', 'Desert Teleporter']), - create_lw_region(player, 'Master Sword Meadow', ['Master Sword Pedestal']), - create_cave_region(player, 'Lost Woods Gamble', 'a game of chance'), - create_lw_region(player, 'Hyrule Castle Courtyard', None, ['Hyrule Castle Entrance (South)', 'Inverted Pyramid Entrance', 'Hyrule Castle Courtyard Bush (South)', 'Hyrule Castle Main Gate (North)']), - create_lw_region(player, 'Hyrule Castle Ledge', None, ['Hyrule Castle Entrance (East)', 'Hyrule Castle Entrance (West)', 'Agahnims Tower', 'Hyrule Castle Ledge Courtyard Drop', 'Hyrule Castle Ledge Drop', 'Inverted Pyramid Hole'], 'the castle rampart'), - create_lw_region(player, 'Hyrule Castle Secret Entrance Area', None, ['Hyrule Castle Secret Entrance Stairs', 'Hyrule Castle Courtyard Bush (North)', 'Pyramid Uncle Mirror Spot']), - create_dungeon_region(player, 'Sewer Drop', 'a drop\'s exit', None, ['Sewer Drop']), # This exists only to be referenced for access checks - + create_cave_region(player, 'Lumberjack House', 'a boring house'), create_cave_region(player, 'Old Man Cave', 'a connector', ['Old Man'], ['Old Man Cave Exit (East)']), create_cave_region(player, 'Old Man Cave Ledge', 'a connector', None, ['Old Man Cave Exit (West)', 'Old Man Cave Dropdown']), create_cave_region(player, 'Old Man House', 'a connector', None, ['Old Man House Exit (Bottom)', 'Old Man House Front to Back']), create_cave_region(player, 'Old Man House Back', 'a connector', None, ['Old Man House Exit (Top)', 'Old Man House Back to Front']), - create_lw_region(player, 'Death Mountain (West Bottom)', None, ['Old Man Cave (East)', 'Old Man House (Bottom)', 'Old Man House (Top)', 'Death Mountain Return Cave (East)', 'Spectacle Rock Cave', - 'Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Bottom)', 'DM Broken Bridge (West)', 'Death Mountain Mirror Spot', 'DM Flute', 'Death Mountain Teleporter']), create_cave_region(player, 'Death Mountain Return Cave (left)', 'a connector', None, ['Death Mountain Return Cave Exit (West)', 'Death Mountain Return Cave E']), create_cave_region(player, 'Death Mountain Return Cave (right)', 'a connector', None, ['Death Mountain Return Cave Exit (East)', 'Death Mountain Return Cave W']), - create_lw_region(player, 'Death Mountain Return Ledge', None, ['Death Mountain Return Ledge Drop', 'Death Mountain Return Cave (West)', 'Mountain Exit Ledge Mirror Spot'], 'a ledge in the foothills'), create_cave_region(player, 'Spectacle Rock Cave (Top)', 'a connector', ['Spectacle Rock Cave'], ['Spectacle Rock Cave Drop', 'Spectacle Rock Cave Exit (Top)']), create_cave_region(player, 'Spectacle Rock Cave (Bottom)', 'a connector', None, ['Spectacle Rock Cave Exit']), create_cave_region(player, 'Spectacle Rock Cave (Peak)', 'a connector', None, ['Spectacle Rock Cave Peak Drop', 'Spectacle Rock Cave Exit (Peak)']), - create_lw_region(player, 'East Death Mountain (Bottom)', None, ['DM Broken Bridge (East)', 'Paradox Cave (Bottom)', 'Paradox Cave (Middle)', 'East Death Mountain Mirror Spot (Bottom)', 'East Death Mountain Teleporter', 'Hookshot Fairy', - 'Fairy Ascension Rocks', 'Spiral Cave (Bottom)', 'EDM Flute']), + create_cave_region(player, 'Spiral Cave (Top)', 'a connector', ['Spiral Cave'], ['Spiral Cave (top to bottom)', 'Spiral Cave Exit (Top)']), + create_cave_region(player, 'Spiral Cave (Bottom)', 'a connector', None, ['Spiral Cave Exit']), + create_cave_region(player, 'Mimic Cave', 'Mimic Cave', ['Mimic Cave']), + create_cave_region(player, 'Fairy Ascension Cave (Bottom)', 'a connector', None, ['Fairy Ascension Cave Climb', 'Fairy Ascension Cave Exit (Bottom)']), + create_cave_region(player, 'Fairy Ascension Cave (Drop)', 'a connector', None, ['Fairy Ascension Cave Pots']), + create_cave_region(player, 'Fairy Ascension Cave (Top)', 'a connector', None, ['Fairy Ascension Cave Exit (Top)', 'Fairy Ascension Cave Drop']), create_cave_region(player, 'Hookshot Fairy', 'fairies deep in a cave'), - create_cave_region(player, 'Paradox Cave Front', 'a connector', None, ['Paradox Cave Push Block Reverse', 'Paradox Cave Exit (Bottom)', 'Light World Death Mountain Shop']), + create_cave_region(player, 'Paradox Cave Front', 'a connector', None, ['Paradox Cave Push Block Reverse', 'Paradox Cave Exit (Bottom)', 'Paradox Shop']), create_cave_region(player, 'Paradox Cave Chest Area', 'a connector', ['Paradox Cave Lower - Far Left', 'Paradox Cave Lower - Left', 'Paradox Cave Lower - Right', @@ -144,93 +95,141 @@ def create_regions(world, player): create_cave_region(player, 'Paradox Cave Bomb Area', 'a connector', ['Paradox Cave Upper - Left', 'Paradox Cave Upper - Right']), create_cave_region(player, 'Paradox Cave', 'a connector', None, ['Paradox Cave Exit (Middle)', 'Paradox Cave Exit (Top)', 'Paradox Cave Drop']), - create_cave_region(player, 'Light World Death Mountain Shop', 'a common shop', ['Paradox Shop - Left', 'Paradox Shop - Middle', 'Paradox Shop - Right']), - create_lw_region(player, 'East Death Mountain (Top)', None, ['Paradox Cave (Top)', 'DM Hammer Bridge (East)', 'Floating Island Bridge (East)', 'Spiral Cave Ledge Access', 'East Death Mountain Drop', 'Turtle Rock Teleporter', 'East Death Mountain Mirror Spot (Top)', 'Fairy Ascension Ledge Access', 'Mimic Cave Ledge Access']), - create_lw_region(player, 'Spiral Cave Ledge', None, ['Spiral Cave', 'Spiral Cave Ledge Drop', 'Dark Death Mountain Ledge Mirror Spot (West)']), - create_cave_region(player, 'Spiral Cave (Top)', 'a connector', ['Spiral Cave'], ['Spiral Cave (top to bottom)', 'Spiral Cave Exit (Top)']), - create_cave_region(player, 'Spiral Cave (Bottom)', 'a connector', None, ['Spiral Cave Exit']), - create_lw_region(player, 'Fairy Ascension Plateau', None, ['Fairy Ascension Drop', 'Fairy Ascension Cave (Bottom)']), - create_cave_region(player, 'Fairy Ascension Cave (Bottom)', 'a connector', None, ['Fairy Ascension Cave Climb', 'Fairy Ascension Cave Exit (Bottom)']), - create_cave_region(player, 'Fairy Ascension Cave (Drop)', 'a connector', None, ['Fairy Ascension Cave Pots']), - create_cave_region(player, 'Fairy Ascension Cave (Top)', 'a connector', None, ['Fairy Ascension Cave Exit (Top)', 'Fairy Ascension Cave Drop']), - create_lw_region(player, 'Fairy Ascension Ledge', None, ['Fairy Ascension Ledge Drop', 'Fairy Ascension Cave (Top)', 'Laser Bridge Mirror Spot']), - create_lw_region(player, 'Death Mountain (Top)', ['Ether Tablet'], ['DM Hammer Bridge (West)', 'Tower of Hera', 'Death Mountain Drop', 'Spectacle Rock Approach', 'Death Mountain (Top) Mirror Spot']), - create_lw_region(player, 'Spectacle Rock', ['Spectacle Rock'], ['Spectacle Rock Drop', 'Spectacle Rock Leave']), + create_cave_region(player, 'Paradox Shop', 'a common shop', ['Paradox Shop - Left', 'Paradox Shop - Middle', 'Paradox Shop - Right']), + create_cave_region(player, 'Waterfall of Wishing', 'a cave with two chests', ['Waterfall Fairy - Left', 'Waterfall Fairy - Right']), + create_cave_region(player, 'Fortune Teller (Light)', 'a fortune teller'), + create_cave_region(player, 'Bonk Rock Cave', 'a cave with a chest', ['Bonk Rock Cave']), + create_dungeon_region(player, 'Sewer Drop', 'a drop\'s exit', None, ['Sewer Drop']), # This exists only to be referenced for access checks + create_cave_region(player, 'Graveyard Cave', 'a cave with an item', ['Graveyard Cave']), + create_cave_region(player, 'Kings Grave', 'a cave with a chest', ['King\'s Tomb']), + create_cave_region(player, 'North Fairy Cave', 'a drop\'s exit', None, ['North Fairy Cave Exit']), + create_cave_region(player, 'Potion Shop', 'the potion shop', ['Potion Shop', 'Potion Shop - Left', 'Potion Shop - Middle', 'Potion Shop - Right']), + create_cave_region(player, 'Kakariko Well (top)', 'a drop', + ['Kakariko Well - Left', 'Kakariko Well - Middle', 'Kakariko Well - Right', + 'Kakariko Well - Bottom'], + ['Kakariko Well (top to bottom)', 'Kakariko Well (top to back)']), + create_cave_region(player, 'Kakariko Well (back)', 'a drop', ['Kakariko Well - Top']), + create_cave_region(player, 'Kakariko Well (bottom)', 'a drop\'s exit', None, ['Kakariko Well Exit']), + create_cave_region(player, 'Blinds Hideout', 'a bounty of five items', [ + "Blind's Hideout - Left", + "Blind's Hideout - Right", + "Blind's Hideout - Far Left", + "Blind's Hideout - Far Right"], + ['Blinds Hideout N']), + create_cave_region(player, 'Blinds Hideout (Top)', 'a bounty of five items', ["Blind's Hideout - Top"]), + create_cave_region(player, 'Elder House', 'a connector', None, ['Elder House Exit (East)', 'Elder House Exit (West)']), + create_cave_region(player, 'Snitch Lady (East)', 'a boring house'), + create_cave_region(player, 'Snitch Lady (West)', 'a boring house'), + create_cave_region(player, 'Chicken House', 'a house with a chest', ['Chicken House']), + create_cave_region(player, 'Sick Kids House', 'the sick kid', ['Sick Kid']), + create_cave_region(player, 'Bush Covered House', 'the grass man'), + create_cave_region(player, 'Light World Bomb Hut', 'a restock room'), + create_cave_region(player, 'Kakariko Shop', 'a common shop', ['Kakariko Shop - Left', 'Kakariko Shop - Middle', 'Kakariko Shop - Right']), + create_cave_region(player, 'Tavern', 'the tavern', ['Kakariko Tavern']), + create_cave_region(player, 'Tavern (Front)', 'the tavern'), + create_cave_region(player, 'Hyrule Castle Secret Entrance', 'a drop\'s exit', ['Link\'s Uncle', 'Secret Passage'], ['Hyrule Castle Secret Entrance Exit']), + create_cave_region(player, 'Sahasrahlas Hut', 'Sahasrahla', ['Sahasrahla\'s Hut - Left', 'Sahasrahla\'s Hut - Middle', 'Sahasrahla\'s Hut - Right', 'Sahasrahla']), + create_cave_region(player, 'Blacksmiths Hut', 'the smith', ['Blacksmith', 'Missing Smith']), + create_cave_region(player, 'Bat Cave (right)', 'a drop', ['Magic Bat'], ['Bat Cave Door']), + create_cave_region(player, 'Bat Cave (left)', 'a drop\'s exit', None, ['Bat Cave Exit']), + create_cave_region(player, 'Two Brothers House', 'a connector', None, ['Two Brothers House Exit (East)', 'Two Brothers House Exit (West)']), + create_cave_region(player, 'Library', 'the library', ['Library']), + create_cave_region(player, 'Kakariko Gamble Game', 'a game of chance'), + create_cave_region(player, 'Bonk Fairy (Light)', 'a fairy fountain'), + create_cave_region(player, 'Links House', 'your house', ['Link\'s House'], ['Links House Exit']), + create_cave_region(player, 'Chris Houlihan Room', 'I AM ERROR', None, ['Chris Houlihan Room Exit']), + create_cave_region(player, 'Lake Hylia Healer Fairy', 'a fairy fountain'), + create_cave_region(player, 'Long Fairy Cave', 'a fairy fountain'), + create_cave_region(player, 'Checkerboard Cave', 'a cave with an item', ['Checkerboard Cave']), + create_cave_region(player, 'Aginahs Cave', 'a cave with a chest', ['Aginah\'s Cave']), + create_cave_region(player, 'Cave 45', 'a cave with an item', ['Cave 45']), + create_cave_region(player, 'Light Hype Fairy', 'a fairy fountain'), + create_cave_region(player, 'Lake Hylia Fortune Teller', 'a fortune teller'), + create_cave_region(player, 'Lake Hylia Shop', 'a common shop', ['Lake Hylia Shop - Left', 'Lake Hylia Shop - Middle', 'Lake Hylia Shop - Right']), + create_cave_region(player, 'Capacity Upgrade', 'the queen of fairies', ['Capacity Upgrade - Left', 'Capacity Upgrade - Right']), + create_cave_region(player, 'Mini Moldorm Cave', 'a bounty of five items', ['Mini Moldorm Cave - Far Left', 'Mini Moldorm Cave - Left', 'Mini Moldorm Cave - Right', + 'Mini Moldorm Cave - Far Right', 'Mini Moldorm Cave - Generous Guy']), + create_cave_region(player, 'Ice Rod Cave', 'a cave with a chest', ['Ice Rod Cave']), + create_cave_region(player, 'Good Bee Cave', 'a cold bee'), + create_cave_region(player, '20 Rupee Cave', 'a cave with some cash'), + create_cave_region(player, 'Desert Healer Fairy', 'a fairy fountain'), + create_cave_region(player, '50 Rupee Cave', 'a cave with some cash'), + create_cave_region(player, 'Dam', 'the dam', ['Floodgate', 'Floodgate Chest']), - create_dw_region(player, 'East Dark World', ['Pyramid'], ['Pyramid Fairy', 'Hammer Bridge Pegs (North)', 'Palace of Darkness', 'East Dark World Water Drop', - 'Hyrule Castle Ledge Mirror Spot', 'Dark Lake Hylia Fairy', 'Palace of Darkness Hint', 'East Dark World Hint', 'Pyramid Hole', 'Northeast Dark World Broken Bridge Pass', 'East Dark World Teleporter', 'EDW Flute']), - create_dw_region(player, 'Catfish Area', ['Catfish'], ['Dark Witch Rock (North)', 'Catfish Water Drop']), - create_dw_region(player, 'Northeast Dark World', None, ['West Dark World Gap', 'Dark World Potion Shop', 'East Dark World Broken Bridge Pass', 'Northeast Dark World Water Drop', 'Dark Witch Rock (South)', 'NEDW Flute']), - create_cave_region(player, 'Palace of Darkness Hint', 'a storyteller'), - create_cave_region(player, 'East Dark World Hint', 'a storyteller'), - create_dw_region(player, 'South Dark World', ['Stumpy', 'Digging Game'], ['Hype Cave', 'Swamp Palace', 'Village of Outcasts Heavy Rock', 'Dig Game Mirror Spot', - 'Cave 45 Mirror Spot', 'Hammer Bridge Pegs (South)', 'Big Bomb Shop', 'Archery Game', 'Bonk Fairy (Dark)', 'Dark Lake Hylia Shop', - 'Bombos Tablet Mirror Spot', 'South Dark World Water Drop', 'South Dark World Teleporter', 'Post Aga Teleporter', 'SDW Flute']), - create_lw_region(player, 'Bombos Tablet Ledge', ['Bombos Tablet'], ['Bombos Tablet Ladder (Top)']), - create_cave_region(player, 'Big Bomb Shop', 'the bomb shop'), - create_cave_region(player, 'Archery Game', 'a game of skill'), - create_dw_region(player, 'Dark Lake Hylia Water', None, ['Lake Hylia Island Mirror Spot', 'Northeast Dark World River Pier', 'East Dark World Pier', 'Southeast Dark World Pier', 'Ice Palace Approach']), - create_dw_region(player, 'Dark Lake Hylia Central Island', None, ['Ice Palace Leave Water Drop', 'Ice Island To East Pier', 'Ice Palace', 'Lake Hylia Central Island Mirror Spot', 'Dark Lake Hylia Central Island Teleporter']), - create_dw_region(player, 'Southeast Dark World', None, ['Southeast Dark World Water Drop', 'Dark Lake Hylia Ledge Fairy', 'Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Ledge Spike Cave', 'DLHL Flute']), - create_cave_region(player, 'Dark Lake Hylia Ledge Hint', 'a storyteller'), - create_cave_region(player, 'Dark Lake Hylia Ledge Spike Cave', 'a spiky hint'), - create_cave_region(player, 'Hype Cave', 'a bounty of five items', ['Hype Cave - Top', 'Hype Cave - Middle Right', 'Hype Cave - Middle Left', - 'Hype Cave - Bottom', 'Hype Cave - Generous Guy']), + create_dw_region(player, 'West Dark Death Mountain (Bottom)', None, ['Spike Cave', 'Spectacle Rock Mirror Spot', 'Dark Death Mountain Fairy', 'Dark Death Mountain Ladder (Bottom)', 'Dark Death Mountain Teleporter (West)', 'DDM Flute']), + create_dw_region(player, 'Dark Death Mountain (Top)', None, ['Dark Death Mountain Drop (East)', 'Dark Death Mountain Drop (West)', 'Ganons Tower', 'Superbunny Cave (Top)', + 'Hookshot Cave', 'East Death Mountain (Top) Mirror Spot', 'Dark Death Mountain Ladder (Top)', 'Turtle Rock Tail Drop', 'Turtle Rock']), + create_dw_region(player, 'Dark Death Mountain Floating Island', None, ['Floating Island Drop', 'Hookshot Cave Back Entrance', 'Dark Floating Island Mirror Spot'], 'a dark island'), + create_dw_region(player, 'Dark Death Mountain Ledge', None, ['Dark Death Mountain Ledge (East)', 'Dark Death Mountain Ledge (West)', 'Mimic Cave Mirror Spot', 'Spiral Cave Mirror Spot'], 'a dark ledge'), + create_dw_region(player, 'Dark Death Mountain Isolated Ledge', None, ['Isolated Ledge Mirror Spot', 'Turtle Rock Isolated Ledge Entrance'], 'a dark vista'), + create_dw_region(player, 'East Dark Death Mountain (Bottom)', None, ['Superbunny Cave (Bottom)', 'Dark Death Mountain Shop', 'Fairy Ascension Mirror Spot', 'East Dark Death Mountain Teleporter (Bottom)', 'EDDM Flute']), + create_dw_region(player, 'Turtle Rock (Top)', None, ['East Dark Death Mountain Teleporter (Top)', 'Turtle Rock Drop']), create_dw_region(player, 'West Dark World', ['Frog'], ['Village of Outcasts Drop', 'West Dark World Water Drop', 'Brewery', 'C-Shaped House', 'Chest Game', 'Thieves Town', 'Graveyard Ledge Mirror Spot', 'Kings Grave Mirror Spot', 'Bumper Cave Entrance Rock', - 'Skull Woods Forest', 'Village of Outcasts Pegs', 'Village of Outcasts Eastern Rocks', 'Red Shield Shop', 'Dark Sanctuary Hint', 'Fortune Teller (Dark)', 'Dark World Lumberjack Shop', + 'Skull Woods Forest', 'Grassy Lawn Pegs (Bottom)', 'Peg Area Rocks (Left)', 'Red Shield Shop', 'Dark Sanctuary Hint', 'Fortune Teller (Dark)', 'Dark Lumberjack Shop', 'West Dark World Teleporter', 'WDW Flute']), - create_dw_region(player, 'Dark Grassy Lawn', None, ['Grassy Lawn Pegs', 'Dark World Shop', 'Dark Grassy Lawn Mirror Spot', 'Dark Grassy Lawn Flute']), - create_dw_region(player, 'Hammer Peg Area', ['Dark Blacksmith Ruins'], ['Bat Cave Drop Ledge Mirror Spot', 'Dark World Hammer Peg Cave', 'Peg Area Rocks', 'Hammer Peg Area Flute']), - create_dw_region(player, 'Bumper Cave Entrance', None, ['Bumper Cave (Bottom)', 'Bumper Cave Entrance Mirror Spot', 'Bumper Cave Entrance Drop']), - create_cave_region(player, 'Fortune Teller (Dark)', 'a fortune teller'), - create_cave_region(player, 'Village of Outcasts Shop', 'a common shop', ['Village of Outcasts Shop - Left', 'Village of Outcasts Shop - Middle', 'Village of Outcasts Shop - Right']), - create_cave_region(player, 'Dark Lake Hylia Shop', 'a common shop', ['Dark Lake Hylia Shop - Left', 'Dark Lake Hylia Shop - Middle', 'Dark Lake Hylia Shop - Right']), - create_cave_region(player, 'Dark World Lumberjack Shop', 'a common shop', ['Dark Lumberjack Shop - Left', 'Dark Lumberjack Shop - Middle', 'Dark Lumberjack Shop - Right']), - create_cave_region(player, 'Dark World Potion Shop', 'a common shop', ['Dark Potion Shop - Left', 'Dark Potion Shop - Middle', 'Dark Potion Shop - Right']), - create_cave_region(player, 'Dark World Hammer Peg Cave', 'a cave with an item', ['Peg Cave']), - create_cave_region(player, 'Pyramid Fairy', 'a cave with two chests', ['Pyramid Fairy - Left', 'Pyramid Fairy - Right']), - create_cave_region(player, 'Brewery', 'a house with a chest', ['Brewery']), - create_cave_region(player, 'C-Shaped House', 'a house with a chest', ['C-Shaped House']), - create_cave_region(player, 'Chest Game', 'a game of 16 chests', ['Chest Game']), - create_cave_region(player, 'Red Shield Shop', 'the rare shop', ['Red Shield Shop - Left', 'Red Shield Shop - Middle', 'Red Shield Shop - Right']), - create_cave_region(player, 'Dark Sanctuary Hint', 'a storyteller', None, ['Dark Sanctuary Hint Exit']), - create_cave_region(player, 'Bumper Cave (bottom)', 'a connector', None, ['Bumper Cave Exit (Bottom)', 'Bumper Cave Bottom to Top']), - create_cave_region(player, 'Bumper Cave (top)', 'a connector', None, ['Bumper Cave Exit (Top)', 'Bumper Cave Top To Bottom']), - create_dw_region(player, 'Bumper Cave Ledge', ['Bumper Cave Ledge'], ['Bumper Cave Ledge Drop', 'Bumper Cave (Top)', 'Bumper Cave Ledge Mirror Spot'], 'a ledge with an item'), create_dw_region(player, 'Skull Woods Forest', None, ['Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', 'Skull Woods First Section Door', 'Skull Woods Second Section Door (East)']), create_dw_region(player, 'Skull Woods Forest (West)', None, ['Skull Woods Second Section Hole', 'Skull Woods Second Section Door (West)', 'Skull Woods Final Section'], 'a deep, dark forest'), - create_dw_region(player, 'Dark Desert', None, ['Misery Mire', 'Mire Shed', 'Dark Desert Hint', 'Dark Desert Fairy', 'Desert Ledge (Northeast) Mirror Spot', 'Desert Ledge Mirror Spot', 'Mire To Desert Palace Stairs Mirror Spot', - 'Desert Palace Entrance (North) Mirror Spot', 'DD Flute']), + create_dw_region(player, 'Bumper Cave Ledge', ['Bumper Cave Ledge'], ['Bumper Cave Ledge Drop', 'Bumper Cave (Top)', 'Bumper Cave Ledge Mirror Spot'], 'a ledge with an item'), + create_dw_region(player, 'Bumper Cave Entrance', None, ['Bumper Cave (Bottom)', 'Bumper Cave Entrance Mirror Spot', 'Bumper Cave Entrance Drop']), + create_dw_region(player, 'Dark Grassy Lawn', None, ['Grassy Lawn Pegs (Top)', 'Dark World Shop', 'Dark Grassy Lawn Mirror Spot', 'Dark Grassy Lawn Flute']), + create_dw_region(player, 'Hammer Peg Area', ['Dark Blacksmith Ruins'], ['Bat Cave Drop Ledge Mirror Spot', 'Hammer Peg Cave', 'Peg Area Rocks (Right)', 'Hammer Peg Area Flute']), + create_dw_region(player, 'Northeast Dark World', None, ['West Dark World Gap', 'Dark Potion Shop', 'Broken Bridge Pass (Top)', 'Northeast Dark World Water Drop', 'Dark Witch Rock (South)', 'NEDW Flute']), + create_dw_region(player, 'Catfish Area', ['Catfish'], ['Dark Witch Rock (North)', 'Catfish Water Drop']), + create_dw_region(player, 'East Dark World', ['Pyramid'], ['Pyramid Fairy', 'Hammer Bridge Pegs (North)', 'Palace of Darkness', 'East Dark World Water Drop', + 'Hyrule Castle Ledge Mirror Spot', 'Dark Lake Hylia Fairy', 'Palace of Darkness Hint', 'East Dark World Hint', 'Pyramid Hole', 'Broken Bridge Pass (Bottom)', 'East Dark World Teleporter', 'EDW Flute']), + create_dw_region(player, 'Pyramid Exit Ledge', None, ['Pyramid Entrance', 'Pyramid Drop']), + create_dw_region(player, 'Dark Desert', None, ['Misery Mire', 'Mire Shed', 'Dark Desert Hint', 'Dark Desert Fairy', 'Checkerboard Ledge Mirror Spot', 'Desert Ledge Mirror Spot', 'Mire To Desert Stairs Mirror Spot', + 'Desert Ledge Rocks Mirror Spot', 'DD Flute']), create_dw_region(player, 'Dark Desert Ledge', None, ['Dark Desert Drop', 'Dark Desert Teleporter']), - create_cave_region(player, 'Mire Shed', 'a cave with two chests', ['Mire Shed - Left', 'Mire Shed - Right']), - create_cave_region(player, 'Dark Desert Hint', 'a storyteller'), - create_dw_region(player, 'Dark Death Mountain (West Bottom)', None, ['Spike Cave', 'Spectacle Rock Mirror Spot', 'Dark Death Mountain Fairy', 'Dark Death Mountain Ladder (Bottom)', 'Dark Death Mountain Teleporter (West)', 'DDM Flute']), - create_dw_region(player, 'Dark Death Mountain (Top)', None, ['Dark Death Mountain Drop (East)', 'Dark Death Mountain Drop (West)', 'Ganons Tower', 'Superbunny Cave (Top)', - 'Hookshot Cave', 'East Death Mountain (Top) Mirror Spot', 'Dark Death Mountain Ladder (Top)', 'Turtle Rock Tail Drop', 'Turtle Rock']), - create_dw_region(player, 'Dark Death Mountain Ledge', None, ['Dark Death Mountain Ledge (East)', 'Dark Death Mountain Ledge (West)', 'Mimic Cave Mirror Spot', 'Spiral Cave Mirror Spot'], 'a dark ledge'), - create_dw_region(player, 'Dark Death Mountain Isolated Ledge', None, ['Isolated Ledge Mirror Spot', 'Turtle Rock Isolated Ledge Entrance'], 'a dark vista'), - create_dw_region(player, 'Dark Death Mountain (East Bottom)', None, ['Superbunny Cave (Bottom)', 'Cave Shop (Dark Death Mountain)', 'Fairy Ascension Mirror Spot', 'Dark Death Mountain Teleporter (East Bottom)', 'EDDM Flute']), - create_cave_region(player, 'Superbunny Cave (Top)', 'a connector', ['Superbunny Cave - Top', 'Superbunny Cave - Bottom'], ['Superbunny Cave Exit (Top)']), - create_cave_region(player, 'Superbunny Cave (Bottom)', 'a connector', None, ['Superbunny Cave Climb', 'Superbunny Cave Exit (Bottom)']), + create_dw_region(player, 'South Dark World', ['Stumpy', 'Digging Game'], ['Hype Cave', 'Swamp Palace', 'Village of Outcasts Heavy Rock', 'Dig Game Mirror Spot', + 'Cave 45 Mirror Spot', 'Hammer Bridge Pegs (South)', 'Big Bomb Shop', 'Archery Game', 'Bonk Fairy (Dark)', 'Dark Lake Hylia Shop', + 'Bombos Tablet Mirror Spot', 'South Dark World Water Drop', 'South Dark World Teleporter', 'Post Aga Teleporter', 'SDW Flute']), + create_dw_region(player, 'Dark Lake Hylia Water', None, ['Lake Hylia Island Mirror Spot', 'Northeast Dark World River Pier', 'East Dark World Pier', 'Southeast Dark World Pier', 'Ice Palace Approach']), + create_dw_region(player, 'Dark Lake Hylia Central Island', None, ['Ice Palace Leave Water Drop', 'Ice Island To East Pier', 'Ice Palace', 'Lake Hylia Central Island Mirror Spot', 'Dark Lake Hylia Teleporter']), + create_dw_region(player, 'Southeast Dark World', None, ['Southeast Dark World Water Drop', 'Dark Lake Hylia Ledge Fairy', 'Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Ledge Spike Cave', 'DLHL Flute']), + + create_cave_region(player, 'Dark Lumberjack Shop', 'a common shop', ['Dark Lumberjack Shop - Left', 'Dark Lumberjack Shop - Middle', 'Dark Lumberjack Shop - Right']), + create_cave_region(player, 'Dark Death Mountain Healer Fairy', 'a fairy fountain'), create_cave_region(player, 'Spike Cave', 'Spike Cave', ['Spike Cave']), create_cave_region(player, 'Hookshot Cave (Front)', 'a connector', None, ['Hookshot Cave Front to Middle', 'Hookshot Cave Front Exit', 'Hookshot Cave Bonk Path', 'Hookshot Cave Hook Path']), create_cave_region(player, 'Hookshot Cave (Bonk Islands)', 'a connector', ['Hookshot Cave - Bottom Right']), create_cave_region(player, 'Hookshot Cave (Hook Islands)', 'a connector', ['Hookshot Cave - Top Right', 'Hookshot Cave - Top Left', 'Hookshot Cave - Bottom Left']), - create_cave_region(player, 'Hookshot Cave (Back)', 'a connector', None, ['Hookshot Cave Back to Middle', 'Hookshot Cave Back Exit']), create_cave_region(player, 'Hookshot Cave (Middle)', 'a connector', None, ['Hookshot Cave Middle to Back', 'Hookshot Cave Middle to Front']), - - create_dw_region(player, 'Death Mountain Floating Island (Dark World)', None, ['Floating Island Drop', 'Hookshot Cave Back Entrance', 'Dark Floating Island Mirror Spot'], 'a dark island'), - create_lw_region(player, 'Death Mountain Floating Island', ['Floating Island'], ['Floating Island Bridge (West)', 'Floating Island Mirror Spot']), - create_dw_region(player, 'Turtle Rock (Top)', None, ['Dark Death Mountain Teleporter (East)', 'Turtle Rock Drop']), - create_lw_region(player, 'Mimic Cave Ledge', None, ['Mimic Cave', 'Mimic Cave Ledge Drop', 'Dark Death Mountain Ledge Mirror Spot (East)']), - create_cave_region(player, 'Mimic Cave', 'Mimic Cave', ['Mimic Cave']), - + create_cave_region(player, 'Hookshot Cave (Back)', 'a connector', None, ['Hookshot Cave Back to Middle', 'Hookshot Cave Back Exit']), + create_cave_region(player, 'Superbunny Cave (Top)', 'a connector', ['Superbunny Cave - Top', 'Superbunny Cave - Bottom'], ['Superbunny Cave Exit (Top)']), + create_cave_region(player, 'Superbunny Cave (Bottom)', 'a connector', None, ['Superbunny Cave Climb', 'Superbunny Cave Exit (Bottom)']), + create_cave_region(player, 'Dark Death Mountain Shop', 'a common shop', ['Dark Death Mountain Shop - Left', 'Dark Death Mountain Shop - Middle', 'Dark Death Mountain Shop - Right']), + create_cave_region(player, 'Bumper Cave (bottom)', 'a connector', None, ['Bumper Cave Exit (Bottom)', 'Bumper Cave Bottom to Top']), + create_cave_region(player, 'Bumper Cave (top)', 'a connector', None, ['Bumper Cave Exit (Top)', 'Bumper Cave Top To Bottom']), + create_cave_region(player, 'Fortune Teller (Dark)', 'a fortune teller'), + create_cave_region(player, 'Dark Sanctuary Hint', 'a storyteller', None, ['Dark Sanctuary Hint Exit']), + create_cave_region(player, 'Dark Potion Shop', 'a common shop', ['Dark Potion Shop - Left', 'Dark Potion Shop - Middle', 'Dark Potion Shop - Right']), + create_cave_region(player, 'Chest Game', 'a game of 16 chests', ['Chest Game']), + create_cave_region(player, 'C-Shaped House', 'a house with a chest', ['C-Shaped House']), + create_cave_region(player, 'Brewery', 'a house with a chest', ['Brewery']), + create_cave_region(player, 'Village of Outcasts Shop', 'a common shop', ['Village of Outcasts Shop - Left', 'Village of Outcasts Shop - Middle', 'Village of Outcasts Shop - Right']), + create_cave_region(player, 'Red Shield Shop', 'the rare shop', ['Red Shield Shop - Left', 'Red Shield Shop - Middle', 'Red Shield Shop - Right']), + create_cave_region(player, 'Pyramid Fairy', 'a cave with two chests', ['Pyramid Fairy - Left', 'Pyramid Fairy - Right']), create_cave_region(player, 'Pyramid', 'a drop\'s exit', ['Ganon'], ['Ganon Drop']), create_cave_region(player, 'Bottom of Pyramid', 'a drop\'s exit', None, ['Pyramid Exit']), - create_dw_region(player, 'Pyramid Ledge', None, ['Pyramid Entrance', 'Pyramid Drop']), - create_lw_region(player, 'Desert Northern Cliffs') + create_cave_region(player, 'Palace of Darkness Hint', 'a storyteller'), + create_cave_region(player, 'Hammer Peg Cave', 'a cave with an item', ['Peg Cave']), + create_cave_region(player, 'Archery Game', 'a game of skill'), + create_cave_region(player, 'Bonk Fairy (Dark)', 'a fairy fountain'), + create_cave_region(player, 'Big Bomb Shop', 'the bomb shop'), + create_cave_region(player, 'Dark Lake Hylia Healer Fairy', 'a fairy fountain'), + create_cave_region(player, 'East Dark World Hint', 'a storyteller'), + create_cave_region(player, 'Mire Shed', 'a cave with two chests', ['Mire Shed - Left', 'Mire Shed - Right']), + create_cave_region(player, 'Dark Desert Healer Fairy', 'a fairy fountain'), + create_cave_region(player, 'Dark Desert Hint', 'a storyteller'), + create_cave_region(player, 'Hype Cave', 'a bounty of five items', ['Hype Cave - Top', 'Hype Cave - Middle Right', 'Hype Cave - Middle Left', + 'Hype Cave - Bottom', 'Hype Cave - Generous Guy']), + create_cave_region(player, 'Dark Lake Hylia Shop', 'a common shop', ['Dark Lake Hylia Shop - Left', 'Dark Lake Hylia Shop - Middle', 'Dark Lake Hylia Shop - Right']), + create_cave_region(player, 'Dark Lake Hylia Ledge Healer Fairy', 'a fairy fountain'), + create_cave_region(player, 'Dark Lake Hylia Ledge Hint', 'a storyteller'), + create_cave_region(player, 'Dark Lake Hylia Ledge Spike Cave', 'a spiky hint') ] @@ -1124,16 +1123,16 @@ def pot_address(pot_index, super_tile): _basic_shop_defaults = [('Red Potion', 150), ('Small Heart', 10), ('Bombs (10)', 50)] _dark_world_shop_defaults = [('Red Potion', 150), ('Blue Shield', 50), ('Bombs (10)', 50)] shop_table = { - 'Cave Shop (Dark Death Mountain)': (0x0112, ShopType.Shop, 0xC1, False, False, _basic_shop_defaults, 0), + 'Dark Death Mountain Shop': (0x0112, ShopType.Shop, 0xC1, False, False, _basic_shop_defaults, 0), 'Red Shield Shop': (0x0110, ShopType.Shop, 0xC1, False, False, [('Red Shield', 500), ('Bee', 10), ('Arrows (10)', 30)], 3), 'Dark Lake Hylia Shop': (0x010F, ShopType.Shop, 0xC1, False, False, _dark_world_shop_defaults, 6), - 'Dark World Lumberjack Shop': (0x010F, ShopType.Shop, 0xC1, False, False, _dark_world_shop_defaults, 9), + 'Dark Lumberjack Shop': (0x010F, ShopType.Shop, 0xC1, False, False, _dark_world_shop_defaults, 9), 'Village of Outcasts Shop': (0x010F, ShopType.Shop, 0xC1, False, False, _dark_world_shop_defaults, 12), - 'Dark World Potion Shop': (0x010F, ShopType.Shop, 0xC1, False, False, _dark_world_shop_defaults, 15), - 'Light World Death Mountain Shop': (0x00FF, ShopType.Shop, 0xA0, False, False, _basic_shop_defaults, 18), + 'Dark Potion Shop': (0x010F, ShopType.Shop, 0xC1, False, False, _dark_world_shop_defaults, 15), + 'Paradox Shop': (0x00FF, ShopType.Shop, 0xA0, False, False, _basic_shop_defaults, 18), 'Kakariko Shop': (0x011F, ShopType.Shop, 0xA0, False, False, _basic_shop_defaults, 21), - 'Cave Shop (Lake Hylia)': (0x0112, ShopType.Shop, 0xA0, False, False, _basic_shop_defaults, 24), + 'Lake Hylia Shop': (0x0112, ShopType.Shop, 0xA0, False, False, _basic_shop_defaults, 24), 'Potion Shop': (0x0109, ShopType.Shop, 0xFF, False, True, [('Red Potion', 120), ('Green Potion', 60), ('Blue Potion', 160)], 27), 'Capacity Upgrade': (0x0115, ShopType.UpgradeShop, 0x04, True, True, @@ -1142,15 +1141,15 @@ shop_table = { shop_to_location_table = { - 'Cave Shop (Dark Death Mountain)': ['Dark Death Mountain Shop - Left', 'Dark Death Mountain Shop - Middle', 'Dark Death Mountain Shop - Right'], + 'Dark Death Mountain Shop': ['Dark Death Mountain Shop - Left', 'Dark Death Mountain Shop - Middle', 'Dark Death Mountain Shop - Right'], 'Red Shield Shop': ['Red Shield Shop - Left', 'Red Shield Shop - Middle', 'Red Shield Shop - Right'], 'Dark Lake Hylia Shop': ['Dark Lake Hylia Shop - Left', 'Dark Lake Hylia Shop - Middle', 'Dark Lake Hylia Shop - Right'], - 'Dark World Lumberjack Shop': ['Dark Lumberjack Shop - Left', 'Dark Lumberjack Shop - Middle', 'Dark Lumberjack Shop - Right'], + 'Dark Lumberjack Shop': ['Dark Lumberjack Shop - Left', 'Dark Lumberjack Shop - Middle', 'Dark Lumberjack Shop - Right'], 'Village of Outcasts Shop': ['Village of Outcasts Shop - Left', 'Village of Outcasts Shop - Middle', 'Village of Outcasts Shop - Right'], - 'Dark World Potion Shop': ['Dark Potion Shop - Left', 'Dark Potion Shop - Middle', 'Dark Potion Shop - Right'], - 'Light World Death Mountain Shop': ['Paradox Shop - Left', 'Paradox Shop - Middle', 'Paradox Shop - Right'], + 'Dark Potion Shop': ['Dark Potion Shop - Left', 'Dark Potion Shop - Middle', 'Dark Potion Shop - Right'], + 'Paradox Shop': ['Paradox Shop - Left', 'Paradox Shop - Middle', 'Paradox Shop - Right'], 'Kakariko Shop': ['Kakariko Shop - Left', 'Kakariko Shop - Middle', 'Kakariko Shop - Right'], - 'Cave Shop (Lake Hylia)': ['Lake Hylia Shop - Left', 'Lake Hylia Shop - Middle', 'Lake Hylia Shop - Right'], + 'Lake Hylia Shop': ['Lake Hylia Shop - Left', 'Lake Hylia Shop - Middle', 'Lake Hylia Shop - Right'], 'Potion Shop': ['Potion Shop - Left', 'Potion Shop - Middle', 'Potion Shop - Right'], 'Capacity Upgrade': ['Capacity Upgrade - Left', 'Capacity Upgrade - Right'], } diff --git a/Rom.py b/Rom.py index 10125e66..c07a1b1c 100644 --- a/Rom.py +++ b/Rom.py @@ -2105,7 +2105,7 @@ def write_strings(rom, world, player, team): if world.mode[player] == 'inverted': entrances_to_hint.update({'Inverted Pyramid Entrance': 'The extra castle passage'}) else: - entrances_to_hint.update({'Pyramid Ledge': 'The pyramid ledge'}) + entrances_to_hint.update({'Pyramid Entrance': 'The pyramid ledge'}) hint_count = 4 if world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull'] else 0 hint_count -= 2 if world.shuffle[player] not in ['simple', 'restricted'] else 0 for entrance in all_entrances: @@ -2723,7 +2723,7 @@ InconvenientDungeonEntrances = {'Turtle Rock': 'Turtle Rock Main', InconvenientOtherEntrances = {'Death Mountain Return Cave (West)': 'The SW DM foothills cave', 'Mimic Cave': 'Mimic Ledge', - 'Dark World Hammer Peg Cave': 'The rows of pegs', + 'Hammer Peg Cave': 'The rows of pegs', 'Pyramid Fairy': 'The crack on the pyramid' } @@ -2792,15 +2792,15 @@ ItemEntrances = {'Blinds Hideout': 'Blind\'s old house', 'Chest Game': 'The westmost building in the Village of Outcasts', } -ShopEntrances = {'Cave Shop (Lake Hylia)': 'The cave NW Lake Hylia', +ShopEntrances = {'Lake Hylia Shop': 'The cave NW Lake Hylia', 'Kakariko Shop': 'The old Kakariko shop', 'Capacity Upgrade': 'The cave on the island', 'Dark Lake Hylia Shop': 'The building NW dark Lake Hylia', 'Dark World Shop': 'The hammer sealed building', 'Red Shield Shop': 'The fenced in building', - 'Cave Shop (Dark Death Mountain)': 'The base of east dark DM', - 'Dark World Potion Shop': 'The building near the catfish', - 'Dark World Lumberjack Shop': 'The northmost Dark World building' + 'Dark Death Mountain Shop': 'The base of east dark DM', + 'Dark Potion Shop': 'The building near the catfish', + 'Dark Lumberjack Shop': 'The northmost Dark World building' } OtherEntrances = {'Lake Hylia Fairy': 'A cave NE of Lake Hylia', diff --git a/Rules.py b/Rules.py index a8bc939b..86897bfa 100644 --- a/Rules.py +++ b/Rules.py @@ -157,107 +157,7 @@ def global_rules(world, player): for exit in world.get_region('Menu', player).exits: exit.hide_path = True - set_rule(world.get_entrance('Old Man S&Q', player), lambda state: state.can_reach('Old Man', 'Location', player)) - - set_rule(world.get_location('Sunken Treasure', player), lambda state: state.has('Open Floodgate', player)) - set_rule(world.get_location('Dark Blacksmith Ruins', player), lambda state: state.has('Return Smith', player)) - set_rule(world.get_location('Purple Chest', player), lambda state: state.has('Pick Up Purple Chest', player)) # Can S&Q with chest - set_rule(world.get_location('Ether Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player)) - set_rule(world.get_location('Master Sword Pedestal', player), lambda state: state.has('Red Pendant', player) and state.has('Blue Pendant', player) and state.has('Green Pendant', player)) - - set_rule(world.get_location('Missing Smith', player), lambda state: state.has('Get Frog', player) and state.can_reach('Blacksmiths Hut', 'Region', player)) # Can't S&Q with smith - set_rule(world.get_location('Blacksmith', player), lambda state: state.has('Return Smith', player)) - set_rule(world.get_location('Magic Bat', player), lambda state: state.has('Magic Powder', player)) - set_rule(world.get_location('Sick Kid', player), lambda state: state.has_bottle(player)) - set_rule(world.get_location('Library', player), lambda state: state.has_Boots(player)) - set_rule(world.get_location('Mimic Cave', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_location('Sahasrahla', player), lambda state: state.has('Green Pendant', player)) - - set_rule(world.get_location('Spike Cave', player), lambda state: - state.has('Hammer', player) and state.can_lift_rocks(player) and - ((state.has('Cape', player) and state.can_extend_magic(player, 16, True)) or - (state.has('Cane of Byrna', player) and - (state.can_extend_magic(player, 12, True) or - (state.world.can_take_damage and (state.has_Boots(player) or state.has_hearts(player, 4)))))) - ) - - set_rule(world.get_location('Hookshot Cave - Top Right', player), lambda state: state.has('Hookshot', player)) - set_rule(world.get_location('Hookshot Cave - Top Left', player), lambda state: state.has('Hookshot', player)) - set_rule(world.get_location('Hookshot Cave - Bottom Right', player), lambda state: state.has('Hookshot', player) or state.has('Pegasus Boots', player)) - set_rule(world.get_location('Hookshot Cave - Bottom Left', player), lambda state: state.has('Hookshot', player)) - - set_rule(world.get_entrance('Hookshot Cave Bonk Path', player), lambda state: state.has('Hookshot', player) or state.has('Pegasus Boots', player)) - set_rule(world.get_entrance('Hookshot Cave Hook Path', player), lambda state: state.has('Hookshot', player)) - - set_rule(world.get_entrance('Old Man Cave Exit (West)', player), lambda state: False) # drop cannot be climbed up - - # s&q regions. link's house entrance is set to true so the filler knows the chest inside can always be reached - set_rule(world.get_entrance('Other World S&Q', player), lambda state: state.has_Mirror(player) and state.has('Beat Agahnim 1', player)) - - # overworld requirements - set_rule(world.get_entrance('Kings Grave', player), lambda state: state.has_Boots(player)) - set_rule(world.get_entrance('Kings Grave Outer Rocks', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Kings Grave Inner Rocks', player), lambda state: state.can_lift_heavy_rocks(player)) - # Caution: If king's grave is relaxed at all to account for reaching it via a two way cave's exit in insanity mode, then the bomb shop logic will need to be updated (that would involve create a small ledge-like Region for it) - set_rule(world.get_entrance('Potion Shop Rock (North)', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Potion Shop Rock (South)', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Bonk Fairy (Light)', player), lambda state: state.has_Boots(player)) - set_rule(world.get_entrance('Bat Cave Ledge Peg', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Bat Cave Ledge Peg (East)', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Lumberjack Tree Tree', player), lambda state: state.has_Boots(player) and state.has('Beat Agahnim 1', player)) - set_rule(world.get_entrance('Bonk Rock Cave', player), lambda state: state.has_Boots(player)) - set_rule(world.get_entrance('Desert Statue Move', player), lambda state: state.has('Book of Mudora', player)) - set_rule(world.get_entrance('Sanctuary Grave', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('20 Rupee Cave', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('50 Rupee Cave', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Death Mountain Entrance Rock', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_location('Flute Spot', player), lambda state: state.has('Shovel', player)) - - set_rule(world.get_location('Zora\'s Ledge', player), lambda state: state.has('Flippers', player)) - # can be fake flippered into, but is in weird state inside that might prevent you from doing things. - set_rule(world.get_entrance('Waterfall Fairy Access', player), lambda state: state.has('Flippers', player)) - - set_rule(world.get_location('Potion Shop', player), lambda state: state.has('Mushroom', player) and state.can_reach('Potion Shop Area', 'Region', player)) - set_rule(world.get_entrance('Desert Palace Entrance (North) Rocks', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Desert Ledge Return Rocks', player), lambda state: state.can_lift_rocks(player)) # should we decide to place something that is not a dungeon end up there at some point - set_rule(world.get_entrance('Checkerboard Cave', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has('Cape', player) or state.has_beam_sword(player)) - set_rule(world.get_entrance('DM Broken Bridge (West)', player), lambda state: state.has('Hookshot', player)) - set_rule(world.get_entrance('DM Broken Bridge (East)', player), lambda state: state.has('Hookshot', player)) - set_rule(world.get_entrance('East Death Mountain Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Fairy Ascension Rocks', player), lambda state: state.can_lift_heavy_rocks(player)) - # can erase block - overridden in noglitches - set_rule(world.get_entrance('Paradox Cave Push Block Reverse', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('DM Hammer Bridge (East)', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Turtle Rock Teleporter', player), lambda state: state.can_lift_heavy_rocks(player) and state.has('Hammer', player)) - set_rule(world.get_entrance('DM Hammer Bridge (West)', player), lambda state: state.has('Hammer', player)) - - set_rule(world.get_entrance('Dark Witch Rock (North)', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Dark Witch Rock (South)', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Northeast Dark World Broken Bridge Pass', player), lambda state: state.can_lift_rocks(player) or state.has('Hammer', player) or state.has('Flippers', player)) - set_rule(world.get_entrance('East Dark World Broken Bridge Pass', player), lambda state: state.can_lift_rocks(player) or state.has('Hammer', player)) - set_rule(world.get_entrance('Hammer Bridge Pegs (North)', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Bonk Fairy (Dark)', player), lambda state: state.has_Boots(player)) - set_rule(world.get_entrance('West Dark World Gap', player), lambda state: state.has('Hookshot', player)) - set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player)) - set_rule(world.get_entrance('Dark Lake Hylia Ledge Spike Cave', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Village of Outcasts Heavy Rock', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Hammer Bridge Pegs (South)', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Bumper Cave Entrance Rock', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Dark World Hammer Peg Cave', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Village of Outcasts Eastern Rocks', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Peg Area Rocks', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Village of Outcasts Pegs', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Grassy Lawn Pegs', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Bumper Cave Bottom to Top', player), lambda state: state.has('Cape', player)) - set_rule(world.get_entrance('Bumper Cave Top To Bottom', player), lambda state: state.has('Cape', player) or state.has('Hookshot', player)) - - set_rule(world.get_entrance('Skull Woods Final Section', player), lambda state: state.has('Fire Rod', player)) - set_rule(world.get_entrance('Hookshot Cave', player), lambda state: state.can_lift_rocks(player)) - - set_rule(world.get_entrance('Misery Mire', player), lambda state: state.has_sword(player) and state.has_misery_mire_medallion(player)) # sword required to cast magic (!) - set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has_sword(player) and state.has_turtle_rock_medallion(player) and state.can_reach('Turtle Rock (Top)', 'Region', player)) # sword required to cast magic (!) - + # flute rules set_rule(world.get_entrance('Flute Spot 1', player), lambda state: state.can_flute(player)) set_rule(world.get_entrance('Flute Spot 2', player), lambda state: state.can_flute(player)) set_rule(world.get_entrance('Flute Spot 3', player), lambda state: state.can_flute(player)) @@ -267,6 +167,103 @@ def global_rules(world, player): set_rule(world.get_entrance('Flute Spot 7', player), lambda state: state.can_flute(player)) set_rule(world.get_entrance('Flute Spot 8', player), lambda state: state.can_flute(player)) + # s&q regions. link's house entrance is set to true so the filler knows the chest inside can always be reached + set_rule(world.get_entrance('Old Man S&Q', player), lambda state: state.can_reach('Old Man', 'Location', player)) + set_rule(world.get_entrance('Other World S&Q', player), lambda state: state.has_Mirror(player) and state.has('Beat Agahnim 1', player)) + + # overworld location rules + set_rule(world.get_location('Master Sword Pedestal', player), lambda state: state.has('Red Pendant', player) and state.has('Blue Pendant', player) and state.has('Green Pendant', player)) + set_rule(world.get_location('Zora\'s Ledge', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_location('Sunken Treasure', player), lambda state: state.has('Open Floodgate', player)) + set_rule(world.get_location('Flute Spot', player), lambda state: state.has('Shovel', player)) + set_rule(world.get_location('Ether Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player)) + set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player)) + + set_rule(world.get_location('Missing Smith', player), lambda state: state.has('Get Frog', player) and state.can_reach('Blacksmiths Hut', 'Region', player)) # Can't S&Q with smith + set_rule(world.get_location('Dark Blacksmith Ruins', player), lambda state: state.has('Return Smith', player)) + set_rule(world.get_location('Purple Chest', player), lambda state: state.has('Pick Up Purple Chest', player)) # Can S&Q with chest + + # underworld rules + set_rule(world.get_entrance('Old Man Cave Exit (West)', player), lambda state: False) # drop cannot be climbed up + set_rule(world.get_location('Mimic Cave', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Paradox Cave Push Block Reverse', player), lambda state: state.has_Mirror(player)) # can erase block - overridden in noglitches + set_rule(world.get_location('Potion Shop', player), lambda state: state.has('Mushroom', player) and state.can_reach('Potion Shop Area', 'Region', player)) + set_rule(world.get_location('Sick Kid', player), lambda state: state.has_bottle(player)) + set_rule(world.get_location('Magic Bat', player), lambda state: state.has('Magic Powder', player)) + set_rule(world.get_location('Blacksmith', player), lambda state: state.has('Return Smith', player)) + set_rule(world.get_location('Library', player), lambda state: state.has_Boots(player)) + set_rule(world.get_location('Sahasrahla', player), lambda state: state.has('Green Pendant', player)) + set_rule(world.get_location('Spike Cave', player), lambda state: + state.has('Hammer', player) and state.can_lift_rocks(player) and + ((state.has('Cape', player) and state.can_extend_magic(player, 16, True)) or + (state.has('Cane of Byrna', player) and + (state.can_extend_magic(player, 12, True) or + (state.world.can_take_damage and (state.has_Boots(player) or state.has_hearts(player, 4)))))) + ) + set_rule(world.get_location('Hookshot Cave - Top Right', player), lambda state: state.has('Hookshot', player)) + set_rule(world.get_location('Hookshot Cave - Top Left', player), lambda state: state.has('Hookshot', player)) + set_rule(world.get_location('Hookshot Cave - Bottom Right', player), lambda state: state.has('Hookshot', player) or state.has('Pegasus Boots', player)) + set_rule(world.get_location('Hookshot Cave - Bottom Left', player), lambda state: state.has('Hookshot', player)) + set_rule(world.get_entrance('Hookshot Cave Bonk Path', player), lambda state: state.has('Hookshot', player) or state.has('Pegasus Boots', player)) + set_rule(world.get_entrance('Hookshot Cave Hook Path', player), lambda state: state.has('Hookshot', player)) + set_rule(world.get_entrance('Bumper Cave Bottom to Top', player), lambda state: state.has('Cape', player)) + set_rule(world.get_entrance('Bumper Cave Top To Bottom', player), lambda state: state.has('Cape', player) or state.has('Hookshot', player)) + + # terrain rules + set_rule(world.get_entrance('DM Hammer Bridge (West)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('DM Hammer Bridge (East)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('DM Broken Bridge (West)', player), lambda state: state.has('Hookshot', player)) + set_rule(world.get_entrance('DM Broken Bridge (East)', player), lambda state: state.has('Hookshot', player)) + set_rule(world.get_entrance('Fairy Ascension Rocks', player), lambda state: state.can_lift_heavy_rocks(player)) + # can be fake flippered into, but is in weird state inside that might prevent you from doing things. + set_rule(world.get_entrance('Waterfall Fairy Access', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Death Mountain Entrance Rock', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Kings Grave Rocks (Outer)', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Kings Grave Rocks (Inner)', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Potion Shop Rock (North)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Potion Shop Rock (South)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Bat Cave Ledge Peg', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Bat Cave Ledge Peg (East)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Desert Statue Move', player), lambda state: state.has('Book of Mudora', player)) + set_rule(world.get_entrance('Desert Ledge Rocks (Outer)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Desert Ledge Rocks (Inner)', player), lambda state: state.can_lift_rocks(player)) + + set_rule(world.get_entrance('Bumper Cave Entrance Rock', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Dark Witch Rock (North)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Dark Witch Rock (South)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Broken Bridge Pass (Bottom)', player), lambda state: state.can_lift_rocks(player) or state.has('Hammer', player) or state.has('Flippers', player)) + set_rule(world.get_entrance('Broken Bridge Pass (Top)', player), lambda state: state.can_lift_rocks(player) or state.has('Hammer', player)) + set_rule(world.get_entrance('West Dark World Gap', player), lambda state: state.has('Hookshot', player)) + set_rule(world.get_entrance('Grassy Lawn Pegs (Bottom)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Grassy Lawn Pegs (Top)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Peg Area Rocks (Left)', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Peg Area Rocks (Right)', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Village of Outcasts Heavy Rock', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Hammer Bridge Pegs (North)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Hammer Bridge Pegs (South)', player), lambda state: state.has('Hammer', player)) + + # entrance rules + # Caution: If king's grave is relaxed at all to account for reaching it via a two way cave's exit in insanity mode, then the bomb shop logic will need to be updated (that would involve create a small ledge-like Region for it) + # TODO: Not sure if this ^ is true anymore since Kings Grave is its own region now + set_rule(world.get_entrance('Lumberjack Tree Tree', player), lambda state: state.has_Boots(player) and state.has('Beat Agahnim 1', player)) + set_rule(world.get_entrance('Bonk Rock Cave', player), lambda state: state.has_Boots(player)) + set_rule(world.get_entrance('Sanctuary Grave', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Kings Grave', player), lambda state: state.has_Boots(player)) + set_rule(world.get_entrance('Bonk Fairy (Light)', player), lambda state: state.has_Boots(player)) + set_rule(world.get_entrance('Checkerboard Cave', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('20 Rupee Cave', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('50 Rupee Cave', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Hookshot Cave', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Hammer Peg Cave', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Bonk Fairy (Dark)', player), lambda state: state.has_Boots(player)) + set_rule(world.get_entrance('Dark Lake Hylia Ledge Spike Cave', player), lambda state: state.can_lift_rocks(player)) + + set_rule(world.get_entrance('Skull Woods Final Section', player), lambda state: state.has('Fire Rod', player)) + set_rule(world.get_entrance('Misery Mire', player), lambda state: state.has_sword(player) and state.has_misery_mire_medallion(player)) # sword required to cast magic (!) + set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has_sword(player) and state.has_turtle_rock_medallion(player) and state.can_reach('Turtle Rock (Top)', 'Region', player)) # sword required to cast magic (!) + + if not world.is_atgt_swapped(player): + set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has('Cape', player) or state.has_beam_sword(player)) set_rule(world.get_entrance('Ganons Tower' if not world.is_atgt_swapped(player) else 'Agahnims Tower', player), lambda state: state.has_crystals(world.crystals_needed_for_gt[player], player)) # Start of door rando rules @@ -697,7 +694,7 @@ def global_rules(world, player): def bomb_rules(world, player): # todo: kak well, pod hint (bonkable pots), hookshot pot, spike cave pots bonkable_doors = ['Two Brothers House Exit (West)', 'Two Brothers House Exit (East)'] # Technically this is incorrectly defined, but functionally the same as what is intended. - bombable_doors = ['Ice Rod Cave', 'Light World Bomb Hut', 'Light World Death Mountain Shop', 'Mini Moldorm Cave', + bombable_doors = ['Ice Rod Cave', 'Light World Bomb Hut', 'Paradox Shop', 'Mini Moldorm Cave', 'Hookshot Cave Back to Middle', 'Hookshot Cave Front to Middle', 'Hookshot Cave Middle to Front', 'Hookshot Cave Middle to Back', 'Dark Lake Hylia Ledge Fairy', 'Hype Cave', 'Brewery', 'Paradox Cave Chest Area NE', 'Blinds Hideout N', 'Kakariko Well (top to back)', @@ -857,181 +854,174 @@ def pot_rules(world, player): def ow_inverted_rules(world, player): if world.mode[player] != 'inverted': - set_rule(world.get_entrance('Kings Grave Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Spectacle Rock Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('East Death Mountain (Top) Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Dark Floating Island Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Spiral Cave Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Mimic Cave Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Isolated Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Fairy Ascension Mirror Spot', player), lambda state: state.has_Mirror(player) and state.has_Pearl(player)) # need to lift flowers + set_rule(world.get_entrance('Bumper Cave Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Bumper Cave Entrance Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Lake Hylia Central Island Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Desert Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('East Hyrule Teleporter', player), lambda state: state.has('Hammer', player) and state.can_lift_rocks(player) and state.has_Pearl(player)) # bunny cannot use hammer - set_rule(world.get_entrance('South Hyrule Teleporter', player), lambda state: state.has('Hammer', player) and state.can_lift_rocks(player) and state.has_Pearl(player)) # bunny cannot use hammer - set_rule(world.get_entrance('Kakariko Teleporter', player), lambda state: ((state.has('Hammer', player) and state.can_lift_rocks(player)) or state.can_lift_heavy_rocks(player)) and state.has_Pearl(player)) # bunny cannot lift bushes - set_rule(world.get_entrance('Top of Pyramid', player), lambda state: state.has('Beat Agahnim 1', player)) + set_rule(world.get_entrance('Graveyard Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Kings Grave Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Dark Grassy Lawn Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Hyrule Castle Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Hyrule Castle Main Gate', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Hyrule Castle Main Gate (North)', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Bat Cave Drop Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Dig Game Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Cave 45 Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Desert Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Mire To Desert Stairs Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Desert Ledge Rocks Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Checkerboard Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Bombos Tablet Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Lake Hylia Island Mirror Spot', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player) and state.has_Mirror(player)) # force flipper rule since fake flipper cannot mirror set_rule(world.get_entrance('Lake Hylia Central Island Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Graveyard Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Bumper Cave Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Bat Cave Drop Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Dark Grassy Lawn Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Desert Ledge (Northeast) Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Desert Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Mire To Desert Palace Stairs Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Desert Palace Entrance (North) Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Spectacle Rock Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('East Death Mountain (Top) Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Mimic Cave Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Spiral Cave Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Fairy Ascension Mirror Spot', player), lambda state: state.has_Mirror(player) and state.has_Pearl(player)) # need to lift flowers - set_rule(world.get_entrance('Isolated Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Dark Floating Island Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('East Death Mountain Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Turtle Rock Teleporter', player), lambda state: state.can_lift_heavy_rocks(player) and state.has('Hammer', player)) + set_rule(world.get_entrance('Kakariko Teleporter', player), lambda state: ((state.has('Hammer', player) and state.can_lift_rocks(player)) or state.can_lift_heavy_rocks(player)) and state.has_Pearl(player)) # bunny cannot lift bushes + set_rule(world.get_entrance('Castle Gate Teleporter', player), lambda state: state.has('Beat Agahnim 1', player)) + set_rule(world.get_entrance('East Hyrule Teleporter', player), lambda state: state.has('Hammer', player) and state.can_lift_rocks(player) and state.has_Pearl(player)) # bunny cannot use hammer + set_rule(world.get_entrance('South Hyrule Teleporter', player), lambda state: state.has('Hammer', player) and state.can_lift_rocks(player) and state.has_Pearl(player)) # bunny cannot use hammer + set_rule(world.get_entrance('Desert Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Lake Hylia Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Hyrule Castle Main Gate', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Hyrule Castle Main Gate (North)', player), lambda state: state.has_Mirror(player)) set_rule(world.get_location('Frog', player), lambda state: state.can_lift_heavy_rocks(player) and state.has_Pearl(player)) - set_rule(world.get_entrance('Pyramid Hole', player), lambda state: world.open_pyramid[player] or world.goal[player] == 'trinity' or state.has('Beat Agahnim 2', player)) else: - set_rule(world.get_entrance('Bumper Cave Entrance Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Skull Woods Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Death Mountain Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Death Mountain (Top) Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('East Death Mountain Mirror Spot (Top)', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Floating Island Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Dark Death Mountain Ledge Mirror Spot (West)', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Dark Death Mountain Ledge Mirror Spot (East)', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Laser Bridge Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('East Death Mountain Mirror Spot (Bottom)', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Mountain Exit Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Mountain Entrance Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Graveyard Cave Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Potion Shop Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Catfish Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('West Dark World Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Bomb Hut Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Bush Covered Lawn Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Hammer Peg Area Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('East Dark World Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Pyramid Uncle Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('South Dark World Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Maze Race Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Mire Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Desert Palace North Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Desert Palace Stairs Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Lake Hylia Central Island Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Dark Lake Hylia Central Island Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Dark Desert Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Shopping Mall Mirror Spot', player), lambda state: state.has_Mirror(player)) + + set_rule(world.get_entrance('East Dark Death Mountain Teleporter (Top)', player), lambda state: state.can_lift_heavy_rocks(player) and state.has('Hammer', player) and state.has_Pearl(player)) # bunny cannot use hammer + set_rule(world.get_entrance('East Dark Death Mountain Teleporter (Bottom)', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('West Dark World Teleporter', player), lambda state: ((state.has('Hammer', player) and state.can_lift_rocks(player)) or state.can_lift_heavy_rocks(player)) and state.has_Pearl(player)) + set_rule(world.get_entrance('Post Aga Teleporter', player), lambda state: state.has('Beat Agahnim 1', player)) set_rule(world.get_entrance('East Dark World Teleporter', player), lambda state: state.has('Hammer', player) and state.can_lift_rocks(player) and state.has_Pearl(player)) # bunny cannot use hammer set_rule(world.get_entrance('South Dark World Teleporter', player), lambda state: state.has('Hammer', player) and state.can_lift_rocks(player) and state.has_Pearl(player)) # bunny cannot use hammer - set_rule(world.get_entrance('West Dark World Teleporter', player), lambda state: ((state.has('Hammer', player) and state.can_lift_rocks(player)) or state.can_lift_heavy_rocks(player)) and state.has_Pearl(player)) - set_rule(world.get_entrance('Bush Covered Lawn Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Dark Death Mountain Teleporter (East Bottom)', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Dark Death Mountain Teleporter (East)', player), lambda state: state.can_lift_heavy_rocks(player) and state.has('Hammer', player) and state.has_Pearl(player)) # bunny cannot use hammer - set_rule(world.get_entrance('Lake Hylia Central Island Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Mountain Exit Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Hammer Peg Area Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Pyramid Uncle Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('East Death Mountain Mirror Spot (Top)', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Death Mountain (Top) Mirror Spot', player), lambda state: state.has_Mirror(player)) - - set_rule(world.get_entrance('East Death Mountain Mirror Spot (Bottom)', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Dark Death Mountain Ledge Mirror Spot (East)', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Dark Death Mountain Ledge Mirror Spot (West)', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Laser Bridge Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Floating Island Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Post Aga Teleporter', player), lambda state: state.has('Beat Agahnim 1', player)) - set_rule(world.get_entrance('Mire Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Desert Palace Stairs Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Death Mountain Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('East Dark World Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('West Dark World Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('South Dark World Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Catfish Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Potion Shop Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Shopping Mall Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Maze Race Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Desert Palace North Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Death Mountain (Top) Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Graveyard Cave Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Bomb Hut Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Skull Woods Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Dark Desert Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Dark Lake Hylia Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) set_rule(world.get_location('Frog', player), lambda state: state.can_lift_heavy_rocks(player) and (state.has_Pearl(player) or state.has('Beat Agahnim 1', player)) or (state.can_reach('Light World', 'Region', player) and state.has_Mirror(player))) # Need LW access using Mirror or Portal - set_rule(world.get_entrance('Inverted Pyramid Hole', player), lambda state: world.open_pyramid[player] or world.goal[player] == 'trinity' or state.has('Beat Agahnim 2', player)) def ow_bunny_rules(world, player): - add_bunny_rule(world.get_entrance('Kings Grave', player), player) - add_bunny_rule(world.get_entrance('Kings Grave Outer Rocks', player), player) - add_bunny_rule(world.get_entrance('Kings Grave Inner Rocks', player), player) - add_bunny_rule(world.get_entrance('Bonk Fairy (Light)', player), player) + # locations + add_bunny_rule(world.get_location('Mushroom', player), player) # need pearl to pick up bushes + add_bunny_rule(world.get_location('Zora\'s Ledge', player), player) + add_bunny_rule(world.get_location('Maze Race', player), player) + add_bunny_rule(world.get_location('Flute Spot', player), player) + + # terrain + add_bunny_rule(world.get_entrance('DM Hammer Bridge (West)', player), player) + add_bunny_rule(world.get_entrance('DM Hammer Bridge (East)', player), player) + add_bunny_rule(world.get_entrance('DM Broken Bridge (West)', player), player) + add_bunny_rule(world.get_entrance('DM Broken Bridge (East)', player), player) + add_bunny_rule(world.get_entrance('Fairy Ascension Rocks', player), player) + add_bunny_rule(world.get_entrance('Death Mountain Entrance Rock', player), player) + add_bunny_rule(world.get_entrance('Waterfall Fairy Access', player), player) + add_bunny_rule(world.get_entrance('Graveyard Ladder (Top)', player), player) + add_bunny_rule(world.get_entrance('Graveyard Ladder (Bottom)', player), player) + add_bunny_rule(world.get_entrance('Kings Grave Rocks (Outer)', player), player) + add_bunny_rule(world.get_entrance('Kings Grave Rocks (Inner)', player), player) + add_bunny_rule(world.get_entrance('Potion Shop Rock (North)', player), player) + add_bunny_rule(world.get_entrance('Potion Shop Rock (South)', player), player) + add_bunny_rule(world.get_entrance('Kakariko Yard Bush (North)', player), player) + add_bunny_rule(world.get_entrance('Kakariko Yard Bush (South)', player), player) + add_bunny_rule(world.get_entrance('Kakariko Southwest Bush (North)', player), player) + add_bunny_rule(world.get_entrance('Kakariko Southwest Bush (South)', player), player) + add_bunny_rule(world.get_entrance('Hyrule Castle Courtyard Bush (North)', player), player) + add_bunny_rule(world.get_entrance('Hyrule Castle Courtyard Bush (South)', player), player) + add_bunny_rule(world.get_entrance('Wooden Bridge Bush (North)', player), player) + add_bunny_rule(world.get_entrance('Wooden Bridge Bush (South)', player), player) add_bunny_rule(world.get_entrance('Bat Cave Ledge Peg', player), player) add_bunny_rule(world.get_entrance('Bat Cave Ledge Peg (East)', player), player) + add_bunny_rule(world.get_entrance('Desert Ledge Rocks (Outer)', player), player) + add_bunny_rule(world.get_entrance('Desert Ledge Rocks (Inner)', player), player) + + add_bunny_rule(world.get_entrance('Bumper Cave Entrance Rock', player), player) + add_bunny_rule(world.get_entrance('Dark Witch Rock (North)', player), player) + add_bunny_rule(world.get_entrance('Dark Witch Rock (South)', player), player) + add_bunny_rule(world.get_entrance('Grassy Lawn Pegs (Bottom)', player), player) + add_bunny_rule(world.get_entrance('Grassy Lawn Pegs (Top)', player), player) + add_bunny_rule(world.get_entrance('Broken Bridge Pass (Bottom)', player), player) + add_bunny_rule(world.get_entrance('Broken Bridge Pass (Top)', player), player) + add_bunny_rule(world.get_entrance('West Dark World Gap', player), player) + add_bunny_rule(world.get_entrance('Peg Area Rocks (Left)', player), player) + add_bunny_rule(world.get_entrance('Peg Area Rocks (Right)', player), player) + add_bunny_rule(world.get_entrance('Village of Outcasts Heavy Rock', player), player) + add_bunny_rule(world.get_entrance('Hammer Bridge Pegs (North)', player), player) + add_bunny_rule(world.get_entrance('Hammer Bridge Pegs (South)', player), player) + + # entrances + add_bunny_rule(world.get_entrance('Lost Woods Hideout Drop', player), player) add_bunny_rule(world.get_entrance('Lumberjack Tree Tree', player), player) add_bunny_rule(world.get_entrance('Bonk Rock Cave', player), player) add_bunny_rule(world.get_entrance('Sanctuary Grave', player), player) + add_bunny_rule(world.get_entrance('Kings Grave', player), player) + add_bunny_rule(world.get_entrance('North Fairy Cave Drop', player), player) + add_bunny_rule(world.get_entrance('Hyrule Castle Secret Entrance Drop', player), player) + add_bunny_rule(world.get_entrance('Bonk Fairy (Light)', player), player) + add_bunny_rule(world.get_entrance('Checkerboard Cave', player), player) add_bunny_rule(world.get_entrance('20 Rupee Cave', player), player) add_bunny_rule(world.get_entrance('50 Rupee Cave', player), player) - add_bunny_rule(world.get_entrance('Death Mountain Entrance Rock', player), player) - add_bunny_rule(world.get_location('Flute Spot', player), player) - add_bunny_rule(world.get_location('Zora\'s Ledge', player), player) - add_bunny_rule(world.get_entrance('Waterfall Fairy Access', player), player) - - add_bunny_rule(world.get_entrance('Desert Palace Entrance (North) Rocks', player), player) - add_bunny_rule(world.get_entrance('Desert Ledge Return Rocks', player), player) - add_bunny_rule(world.get_entrance('Checkerboard Cave', player), player) - add_bunny_rule(world.get_entrance('DM Broken Bridge (West)', player), player) - add_bunny_rule(world.get_entrance('DM Broken Bridge (East)', player), player) - add_bunny_rule(world.get_entrance('East Death Mountain Teleporter', player), player) - add_bunny_rule(world.get_entrance('Fairy Ascension Rocks', player), player) - add_bunny_rule(world.get_entrance('DM Hammer Bridge (East)', player), player) - add_bunny_rule(world.get_entrance('Turtle Rock Teleporter', player), player) - add_bunny_rule(world.get_entrance('DM Hammer Bridge (West)', player), player) - - add_bunny_rule(world.get_entrance('Dark Witch Rock (North)', player), player) - add_bunny_rule(world.get_entrance('Dark Witch Rock (South)', player), player) - add_bunny_rule(world.get_entrance('Northeast Dark World Broken Bridge Pass', player), player) - add_bunny_rule(world.get_entrance('East Dark World Broken Bridge Pass', player), player) - add_bunny_rule(world.get_entrance('Hammer Bridge Pegs (North)', player), player) - add_bunny_rule(world.get_entrance('Bonk Fairy (Dark)', player), player) - add_bunny_rule(world.get_entrance('West Dark World Gap', player), player) - add_bunny_rule(world.get_entrance('Palace of Darkness', player), player) # kiki needs pearl - add_bunny_rule(world.get_entrance('Dark Lake Hylia Ledge Spike Cave', player), player) - add_bunny_rule(world.get_entrance('Village of Outcasts Heavy Rock', player), player) - add_bunny_rule(world.get_entrance('Thieves Town', player), player) # bunny cannot pull add_bunny_rule(world.get_entrance('Skull Woods First Section Hole (North)', player), player) # bunny cannot lift bush add_bunny_rule(world.get_entrance('Skull Woods Second Section Hole', player), player) # bunny cannot lift bush - add_bunny_rule(world.get_entrance('Hammer Bridge Pegs (South)', player), player) - add_bunny_rule(world.get_entrance('Bumper Cave Entrance Rock', player), player) - add_bunny_rule(world.get_entrance('Dark World Hammer Peg Cave', player), player) - add_bunny_rule(world.get_entrance('Village of Outcasts Eastern Rocks', player), player) - add_bunny_rule(world.get_entrance('Peg Area Rocks', player), player) - add_bunny_rule(world.get_entrance('Village of Outcasts Pegs', player), player) - add_bunny_rule(world.get_entrance('Grassy Lawn Pegs', player), player) - add_bunny_rule(world.get_entrance('Bumper Cave Bottom to Top', player), player) - add_bunny_rule(world.get_entrance('Bumper Cave Top To Bottom', player), player) - add_bunny_rule(world.get_entrance('Skull Woods Final Section', player), player) # bunny cannot use fire rod add_bunny_rule(world.get_entrance('Hookshot Cave', player), player) - add_bunny_rule(world.get_entrance('Misery Mire', player), player) + add_bunny_rule(world.get_entrance('Thieves Town', player), player) # bunny cannot pull add_bunny_rule(world.get_entrance('Turtle Rock', player), player) - - #add_bunny_rule(world.get_location('Ice Rod Cave', player), player) - add_bunny_rule(world.get_location('Maze Race', player), player) - - add_bunny_rule(world.get_entrance('Wooden Bridge Bush (North)', player), player) - add_bunny_rule(world.get_entrance('Wooden Bridge Bush (South)', player), player) - add_bunny_rule(world.get_entrance('Potion Shop Rock (North)', player), player) - add_bunny_rule(world.get_entrance('Potion Shop Rock (South)', player), player) - add_bunny_rule(world.get_entrance('Graveyard Ladder (Top)', player), player) - add_bunny_rule(world.get_entrance('Graveyard Ladder (Bottom)', player), player) - add_bunny_rule(world.get_entrance('Hyrule Castle Courtyard Bush (North)', player), player) - add_bunny_rule(world.get_entrance('Hyrule Castle Courtyard Bush (South)', player), player) - - add_bunny_rule(world.get_location('Mushroom', player), player) # need pearl to pick up bushes - add_bunny_rule(world.get_entrance('Kakariko Yard Bush (North)', player), player) - add_bunny_rule(world.get_entrance('Kakariko Yard Bush (South)', player), player) - add_bunny_rule(world.get_entrance('Kakariko Southwest Bush (South)', player), player) - add_bunny_rule(world.get_entrance('Kakariko Southwest Bush (North)', player), player) - add_bunny_rule(world.get_entrance('North Fairy Cave Drop', player), player) - add_bunny_rule(world.get_entrance('Lost Woods Hideout Drop', player), player) - add_bunny_rule(world.get_entrance('Hyrule Castle Secret Entrance Drop', player), player) + add_bunny_rule(world.get_entrance('Palace of Darkness', player), player) # kiki needs pearl + add_bunny_rule(world.get_entrance('Hammer Peg Cave', player), player) + add_bunny_rule(world.get_entrance('Bonk Fairy (Dark)', player), player) + add_bunny_rule(world.get_entrance('Misery Mire', player), player) + add_bunny_rule(world.get_entrance('Dark Lake Hylia Ledge Spike Cave', player), player) if not world.is_atgt_swapped(player): add_bunny_rule(world.get_entrance('Agahnims Tower', player), player) - + #TODO: This needs to get applied after bunny rules, move somewhere else tho if not world.is_atgt_swapped(player): add_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has('Beat Agahnim 1', player), 'or') # barrier gets removed after killing agahnim, relevant for entrance shuffle def no_glitches_rules(world, player): - set_rule(world.get_entrance('Zora Waterfall Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Lake Hylia Central Island Water Drop', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Light World Water Drop', player), lambda state: state.has('Flippers', player)) # can be fake flippered to + set_rule(world.get_entrance('Zora Waterfall Water Drop', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Potion Shop Water Drop', player), lambda state: state.has('Flippers', player)) # can be fake flippered to set_rule(world.get_entrance('Northeast Light World Water Drop', player), lambda state: state.has('Flippers', player)) # can be fake flippered to + set_rule(world.get_entrance('Lake Hylia Central Island Water Drop', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('West Dark World Water Drop', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('South Dark World Water Drop', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('East Dark World Water Drop', player), lambda state: state.has('Flippers', player)) @@ -1039,12 +1029,12 @@ def no_glitches_rules(world, player): set_rule(world.get_entrance('Southeast Dark World Water Drop', player), lambda state: state.has('Flippers', player)) # can be fake flippered to set_rule(world.get_entrance('Catfish Water Drop', player), lambda state: state.has('Flippers', player)) # can be fake flippered to set_rule(world.get_entrance('Ice Palace Leave Water Drop', player), lambda state: state.has('Flippers', player)) - - add_bunny_rule(world.get_entrance('Zora Waterfall Water Drop', player), player) - add_bunny_rule(world.get_entrance('Lake Hylia Central Island Water Drop', player), player) + add_bunny_rule(world.get_entrance('Light World Water Drop', player), player) + add_bunny_rule(world.get_entrance('Zora Waterfall Water Drop', player), player) add_bunny_rule(world.get_entrance('Potion Shop Water Drop', player), player) add_bunny_rule(world.get_entrance('Northeast Light World Water Drop', player), player) + add_bunny_rule(world.get_entrance('Lake Hylia Central Island Water Drop', player), player) add_bunny_rule(world.get_entrance('West Dark World Water Drop', player), player) add_bunny_rule(world.get_entrance('South Dark World Water Drop', player), player) add_bunny_rule(world.get_entrance('East Dark World Water Drop', player), player) @@ -1292,7 +1282,7 @@ def standard_rules(world, player): for location in ['Mushroom', 'Bottle Merchant', 'Flute Spot', 'Sunken Treasure', 'Purple Chest']: add_rule(world.get_location(location, player), lambda state: state.has('Zelda Delivered', player)) - for entrance in ['Blinds Hideout', 'Kings Grave Outer Rocks', 'Dam', 'Tavern North', 'Chicken House', + for entrance in ['Blinds Hideout', 'Kings Grave Rocks (Outer)', 'Dam', 'Tavern North', 'Chicken House', 'Aginahs Cave', 'Sahasrahlas Hut', 'Kakariko Well Drop', 'Kakariko Well Cave', 'Blacksmiths Hut', 'Bat Cave Ledge Peg', 'Bat Cave Cave', 'Sick Kids House', 'Wooden Bridge Bush (South)', 'Lost Woods Hideout Drop', 'Lost Woods Hideout Stump', 'Lumberjack Tree Tree', @@ -1303,10 +1293,10 @@ def standard_rules(world, player): 'South Hyrule Teleporter', 'Kakariko Teleporter', 'Elder House (East)', 'Elder House (West)', 'North Fairy Cave', 'North Fairy Cave Drop', 'Lost Woods Gamble', 'Snitch Lady (East)', 'Snitch Lady (West)', 'Tavern (Front)', 'Kakariko Yard Bush (South)', 'Kakariko Southwest Bush (North)', - 'Kakariko Shop', 'Long Fairy Cave', 'Good Bee Cave', '20 Rupee Cave', 'Cave Shop (Lake Hylia)', + 'Kakariko Shop', 'Long Fairy Cave', 'Good Bee Cave', '20 Rupee Cave', 'Lake Hylia Shop', 'Waterfall of Wishing', 'Hyrule Castle Main Gate', '50 Rupee Cave', 'Bonk Fairy (Light)', 'Fortune Teller (Light)', 'Lake Hylia Fairy', 'Light Hype Fairy', 'Desert Fairy', - 'Lumberjack House', 'Lake Hylia Fortune Teller', 'Kakariko Gamble Game', 'Top of Pyramid']: + 'Lumberjack House', 'Lake Hylia Fortune Teller', 'Kakariko Gamble Game', 'Castle Gate Teleporter']: add_rule(world.get_entrance(entrance, player), lambda state: state.has('Zelda Delivered', player)) # don't allow bombs to get past here before zelda is rescued @@ -1351,7 +1341,7 @@ def set_big_bomb_rules(world, player): 'Chicken House', 'Aginahs Cave', 'Sahasrahlas Hut', - 'Cave Shop (Lake Hylia)', + 'Lake Hylia Shop', 'Blacksmiths Hut', 'Sick Kids House', 'Lost Woods Gamble', @@ -1397,12 +1387,12 @@ def set_big_bomb_rules(world, player): Northern_DW_entrances = ['Brewery', 'C-Shaped House', 'Chest Game', - 'Dark World Hammer Peg Cave', + 'Hammer Peg Cave', 'Red Shield Shop', 'Dark Sanctuary Hint', 'Fortune Teller (Dark)', 'Dark World Shop', - 'Dark World Lumberjack Shop', + 'Dark Lumberjack Shop', 'Thieves Town', 'Skull Woods First Section Door', 'Skull Woods Second Section Door (East)'] @@ -1413,7 +1403,7 @@ def set_big_bomb_rules(world, player): 'Dark Lake Hylia Shop', 'Swamp Palace'] Isolated_DW_entrances = ['Spike Cave', - 'Cave Shop (Dark Death Mountain)', + 'Dark Death Mountain Shop', 'Dark Death Mountain Fairy', 'Mimic Cave', 'Skull Woods Second Section Door (West)', @@ -1554,7 +1544,7 @@ def set_big_bomb_rules(world, player): # 2. (has South dark world access) use existing mirror spot, mirror again off ledge # -> (Flute or (M and South Dark World access) and BR add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: (state.can_flute(player) or (state.can_reach('South Dark World', 'Region', player) and state.has_Mirror(player))) and basic_routes(state)) - elif bombshop_entrance.name == 'Dark World Potion Shop': + elif bombshop_entrance.name == 'Dark Potion Shop': # 1. walk down by lifting rock: needs gloves and pearl` # 2. walk down by hammering peg: needs hammer and pearl # 3. mirror and basic routes @@ -1582,7 +1572,7 @@ def set_inverted_big_bomb_rules(world, player): 'Chicken House', 'Aginahs Cave', 'Sahasrahlas Hut', - 'Cave Shop (Lake Hylia)', + 'Lake Hylia Shop', 'Blacksmiths Hut', 'Sick Kids House', 'Lost Woods Gamble', @@ -1648,10 +1638,10 @@ def set_inverted_big_bomb_rules(world, player): Northern_DW_entrances = ['Brewery', 'C-Shaped House', 'Chest Game', - 'Dark World Hammer Peg Cave', + 'Hammer Peg Cave', 'Dark Sanctuary Hint', 'Fortune Teller (Dark)', - 'Dark World Lumberjack Shop', + 'Dark Lumberjack Shop', 'Thieves Town', 'Skull Woods First Section Door', 'Skull Woods Second Section Door (East)'] @@ -1662,7 +1652,7 @@ def set_inverted_big_bomb_rules(world, player): 'Dark Lake Hylia Shop', 'Swamp Palace'] Isolated_DW_entrances = ['Spike Cave', - 'Cave Shop (Dark Death Mountain)', + 'Dark Death Mountain Shop', 'Dark Death Mountain Fairy', 'Skull Woods Second Section Door (West)', 'Skull Woods Final Section', @@ -1734,7 +1724,7 @@ def set_inverted_big_bomb_rules(world, 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': + elif bombshop_entrance.name == 'Dark 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': @@ -1895,7 +1885,7 @@ def set_bunny_rules(world, player, inverted): for ext in region.exits: add_rule(ext, rule) - paradox_shop = world.get_region('Light World Death Mountain Shop', player) + paradox_shop = world.get_region('Paradox Shop', player) if is_bunny(paradox_shop): add_rule(paradox_shop.entrances[0], get_rule_to_add(paradox_shop)) diff --git a/source/item/District.py b/source/item/District.py index 96599cc6..cdfa7bbf 100644 --- a/source/item/District.py +++ b/source/item/District.py @@ -55,7 +55,7 @@ def create_district_helper(world, player): 'Desert Palace Entrance (North)', 'Desert Palace Entrance (East)', 'Desert Fairy', 'Aginahs Cave', '50 Rupee Cave', 'Checkerboard Cave'] lake_entrances = ['Capacity Upgrade', 'Mini Moldorm Cave', 'Good Bee Cave', '20 Rupee Cave', 'Ice Rod Cave', - 'Cave Shop (Lake Hylia)', 'Lake Hylia Fortune Teller'] + 'Lake Hylia Shop', 'Lake Hylia Fortune Teller'] east_lw_entrances = ['Eastern Palace', 'Waterfall of Wishing', 'Lake Hylia Fairy', 'Sahasrahlas Hut', 'Long Fairy Cave', 'Potion Shop'] lw_dm_entrances = ['Tower of Hera', 'Old Man Cave (East)', 'Old Man House (Bottom)', 'Old Man House (Top)', @@ -64,22 +64,22 @@ def create_district_helper(world, player): 'Paradox Cave (Top)', 'Fairy Ascension Cave (Bottom)', 'Fairy Ascension Cave (Top)', 'Spiral Cave', 'Spiral Cave (Bottom)', 'Hookshot Fairy', 'Mimic Cave'] east_dw_entrances = ['Palace of Darkness', 'Pyramid Entrance', 'Pyramid Fairy', 'East Dark World Hint', - 'Palace of Darkness Hint', 'Dark Lake Hylia Fairy', 'Dark World Potion Shop', 'Pyramid Hole'] + 'Palace of Darkness Hint', 'Dark Lake Hylia Fairy', 'Dark Potion Shop', 'Pyramid Hole'] south_dw_entrances = ['Ice Palace', 'Swamp Palace', 'Dark Lake Hylia Ledge Fairy', 'Dark Lake Hylia Ledge Spike Cave', 'Dark Lake Hylia Ledge Hint', 'Hype Cave', 'Bonk Fairy (Dark)', 'Archery Game', 'Big Bomb Shop', 'Dark Lake Hylia Shop', ] voo_north_entrances = ['Thieves Town', 'Skull Woods First Section Door', 'Skull Woods Second Section Door (East)', 'Skull Woods Second Section Door (West)', 'Skull Woods Final Section', 'Bumper Cave (Bottom)', 'Bumper Cave (Top)', 'Brewery', 'C-Shaped House', 'Chest Game', - 'Dark World Hammer Peg Cave', 'Red Shield Shop', 'Dark Sanctuary Hint', - 'Fortune Teller (Dark)', 'Dark World Shop', 'Dark World Lumberjack Shop', + 'Hammer Peg Cave', 'Red Shield Shop', 'Dark Sanctuary Hint', + 'Fortune Teller (Dark)', 'Dark World Shop', 'Dark Lumberjack Shop', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (North)', 'Skull Woods Second Section Hole'] mire_entrances = ['Misery Mire', 'Mire Shed', 'Dark Desert Hint', 'Dark Desert Fairy'] ddm_entrances = ['Turtle Rock', 'Dark Death Mountain Ledge (West)', 'Dark Death Mountain Ledge (East)', 'Turtle Rock Isolated Ledge Entrance', 'Superbunny Cave (Top)', 'Superbunny Cave (Bottom)', 'Hookshot Cave', 'Hookshot Cave Back Entrance', 'Ganons Tower', 'Spike Cave', - 'Cave Shop (Dark Death Mountain)', 'Dark Death Mountain Fairy'] + 'Dark Death Mountain Shop', 'Dark Death Mountain Fairy'] if inverted: east_dw_entrances.remove('Pyramid Entrance') @@ -152,7 +152,7 @@ def find_reachable_locations(state, player): inaccessible_regions_std = {'Desert Palace Mouth', 'Bumper Cave Ledge', 'Skull Woods Forest (West)', 'Dark Death Mountain Ledge', 'Dark Death Mountain Isolated Ledge', - 'Death Mountain Floating Island (Dark World)'} + 'Dark Death Mountain Floating Island'} inaccessible_regions_inv = {'Desert Palace Mouth', 'Maze Race Ledge', 'Desert Ledge', diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index 3f198733..37a63496 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -1197,9 +1197,9 @@ modes = { 'fixed_shops': { 'special': 'vanilla', 'condition': 'shopsanity', - 'entrances': ['Cave Shop (Dark Death Mountain)', 'Dark World Potion Shop', 'Dark World Lumberjack Shop', + 'entrances': ['Dark Death Mountain Shop', 'Dark Potion Shop', 'Dark Lumberjack Shop', 'Dark World Shop', 'Red Shield Shop', 'Kakariko Shop', 'Capacity Upgrade', - 'Cave Shop (Lake Hylia)'], + 'Lake Hylia Shop'], }, 'fixed_pottery': { 'special': 'vanilla', @@ -1211,14 +1211,14 @@ modes = { }, 'item_caves': { # shuffles shops/pottery if they weren't fixed in the last steps - 'entrances': ['Mimic Cave', 'Spike Cave', 'Mire Shed', 'Dark World Hammer Peg Cave', 'Chest Game', + 'entrances': ['Mimic Cave', 'Spike Cave', 'Mire Shed', 'Hammer Peg Cave', 'Chest Game', 'C-Shaped House', 'Brewery', 'Hype Cave', 'Big Bomb Shop', 'Pyramid Fairy', 'Ice Rod Cave', 'Dam', 'Bonk Rock Cave', 'Library', 'Potion Shop', 'Mini Moldorm Cave', 'Checkerboard Cave', 'Graveyard Cave', 'Cave 45', 'Sick Kids House', 'Blacksmiths Hut', 'Sahasrahlas Hut', 'Aginahs Cave', 'Chicken House', 'Kings Grave', 'Blinds Hideout', - 'Waterfall of Wishing', 'Cave Shop (Dark Death Mountain)', - 'Dark World Potion Shop', 'Dark World Lumberjack Shop', 'Dark World Shop', - 'Red Shield Shop', 'Kakariko Shop', 'Capacity Upgrade', 'Cave Shop (Lake Hylia)', + 'Waterfall of Wishing', 'Dark Death Mountain Shop', + 'Dark Potion Shop', 'Dark Lumberjack Shop', 'Dark World Shop', + 'Red Shield Shop', 'Kakariko Shop', 'Capacity Upgrade', 'Lake Hylia Shop', 'Lumberjack House', 'Snitch Lady (West)', 'Snitch Lady (East)', 'Tavern (Front)', 'Light World Bomb Hut', '20 Rupee Cave', '50 Rupee Cave', 'Hookshot Fairy', 'Palace of Darkness Hint', 'Dark Lake Hylia Ledge Spike Cave', @@ -1272,9 +1272,9 @@ modes = { 'fixed_shops': { 'special': 'vanilla', 'condition': 'shopsanity', - 'entrances': ['Cave Shop (Dark Death Mountain)', 'Dark World Potion Shop', 'Dark World Lumberjack Shop', + 'entrances': ['Dark Death Mountain Shop', 'Dark Potion Shop', 'Dark Lumberjack Shop', 'Dark World Shop', 'Red Shield Shop', 'Kakariko Shop', 'Capacity Upgrade', - 'Cave Shop (Lake Hylia)'], + 'Lake Hylia Shop'], }, 'fixed_pottery': { 'special': 'vanilla', @@ -1286,14 +1286,14 @@ modes = { }, 'item_caves': { # shuffles shops/pottery if they weren't fixed in the last steps - 'entrances': ['Mimic Cave', 'Spike Cave', 'Mire Shed', 'Dark World Hammer Peg Cave', 'Chest Game', + 'entrances': ['Mimic Cave', 'Spike Cave', 'Mire Shed', 'Hammer Peg Cave', 'Chest Game', 'C-Shaped House', 'Brewery', 'Hype Cave', 'Big Bomb Shop', 'Pyramid Fairy', 'Ice Rod Cave', 'Dam', 'Bonk Rock Cave', 'Library', 'Potion Shop', 'Mini Moldorm Cave', 'Checkerboard Cave', 'Graveyard Cave', 'Cave 45', 'Sick Kids House', 'Blacksmiths Hut', 'Sahasrahlas Hut', 'Aginahs Cave', 'Chicken House', 'Kings Grave', 'Blinds Hideout', - 'Waterfall of Wishing', 'Cave Shop (Dark Death Mountain)', - 'Dark World Potion Shop', 'Dark World Lumberjack Shop', 'Dark World Shop', - 'Red Shield Shop', 'Kakariko Shop', 'Capacity Upgrade', 'Cave Shop (Lake Hylia)', + 'Waterfall of Wishing', 'Dark Death Mountain Shop', + 'Dark Potion Shop', 'Dark Lumberjack Shop', 'Dark World Shop', + 'Red Shield Shop', 'Kakariko Shop', 'Capacity Upgrade', 'Lake Hylia Shop', 'Lumberjack House', 'Snitch Lady (West)', 'Snitch Lady (East)', 'Tavern (Front)', 'Light World Bomb Hut', '20 Rupee Cave', '50 Rupee Cave', 'Hookshot Fairy', 'Palace of Darkness Hint', 'Dark Lake Hylia Ledge Spike Cave', @@ -1567,12 +1567,12 @@ entrance_map = { single_entrance_map = { 'Mimic Cave': 'Mimic Cave', 'Dark Death Mountain Fairy': 'Dark Death Mountain Healer Fairy', - 'Cave Shop (Dark Death Mountain)': 'Cave Shop (Dark Death Mountain)', 'Spike Cave': 'Spike Cave', + 'Dark Death Mountain Shop': 'Dark Death Mountain Shop', 'Spike Cave': 'Spike Cave', 'Dark Desert Fairy': 'Dark Desert Healer Fairy', 'Dark Desert Hint': 'Dark Desert Hint', 'Mire Shed': 'Mire Shed', - 'Archery Game': 'Archery Game', 'Dark World Potion Shop': 'Dark World Potion Shop', - 'Dark World Lumberjack Shop': 'Dark World Lumberjack Shop', 'Dark World Shop': 'Village of Outcasts Shop', + 'Archery Game': 'Archery Game', 'Dark Potion Shop': 'Dark Potion Shop', + 'Dark Lumberjack Shop': 'Dark Lumberjack Shop', 'Dark World Shop': 'Village of Outcasts Shop', 'Fortune Teller (Dark)': 'Fortune Teller (Dark)', 'Dark Sanctuary Hint': 'Dark Sanctuary Hint', - 'Red Shield Shop': 'Red Shield Shop', 'Dark World Hammer Peg Cave': 'Dark World Hammer Peg Cave', + 'Red Shield Shop': 'Red Shield Shop', 'Hammer Peg Cave': 'Hammer Peg Cave', 'Chest Game': 'Chest Game', 'C-Shaped House': 'C-Shaped House', 'Brewery': 'Brewery', 'Bonk Fairy (Dark)': 'Bonk Fairy (Dark)', 'Hype Cave': 'Hype Cave', 'Dark Lake Hylia Ledge Hint': 'Dark Lake Hylia Ledge Hint', @@ -1591,9 +1591,9 @@ single_entrance_map = { 'Snitch Lady (West)': 'Snitch Lady (West)', 'Snitch Lady (East)': 'Snitch Lady (East)', 'Fortune Teller (Light)': 'Fortune Teller (Light)', 'Lost Woods Gamble': 'Lost Woods Gamble', 'Sick Kids House': 'Sick Kids House', 'Blacksmiths Hut': 'Blacksmiths Hut', 'Capacity Upgrade': 'Capacity Upgrade', - 'Cave Shop (Lake Hylia)': 'Cave Shop (Lake Hylia)', 'Sahasrahlas Hut': 'Sahasrahlas Hut', + 'Lake Hylia Shop': 'Lake Hylia Shop', 'Sahasrahlas Hut': 'Sahasrahlas Hut', 'Aginahs Cave': 'Aginahs Cave', 'Chicken House': 'Chicken House', 'Tavern North': 'Tavern', - 'Kings Grave': 'Kings Grave', 'Desert Fairy': 'Desert Healer Fairy', 'Light Hype Fairy': 'Swamp Healer Fairy', + 'Kings Grave': 'Kings Grave', 'Desert Fairy': 'Desert Healer Fairy', 'Light Hype Fairy': 'Light Hype Fairy', 'Lake Hylia Fortune Teller': 'Lake Hylia Fortune Teller', 'Lake Hylia Fairy': 'Lake Hylia Healer Fairy', 'Bonk Fairy (Light)': 'Bonk Fairy (Light)', 'Lumberjack House': 'Lumberjack House', 'Dam': 'Dam', 'Blinds Hideout': 'Blinds Hideout', 'Waterfall of Wishing': 'Waterfall of Wishing' @@ -1607,10 +1607,10 @@ default_dw = { 'Bumper Cave Exit (Bottom)', 'Superbunny Cave Exit (Top)', 'Superbunny Cave Exit (Bottom)', 'Hookshot Cave Front Exit', 'Hookshot Cave Back Exit', 'Pyramid Exit', 'Dark Lake Hylia Healer Fairy', 'Dark Lake Hylia Ledge Healer Fairy', 'Dark Desert Healer Fairy', - 'Dark Death Mountain Healer Fairy', 'Cave Shop (Dark Death Mountain)', 'Pyramid Fairy', 'East Dark World Hint', + 'Dark Death Mountain Healer Fairy', 'Dark Death Mountain Shop', 'Pyramid Fairy', 'East Dark World Hint', 'Palace of Darkness Hint', 'Village of Outcasts Shop', 'Dark Lake Hylia Shop', - 'Dark World Lumberjack Shop', 'Dark World Potion Shop', 'Dark Lake Hylia Ledge Spike Cave', - 'Dark Lake Hylia Ledge Hint', 'Hype Cave', 'Brewery', 'C-Shaped House', 'Chest Game', 'Dark World Hammer Peg Cave', + 'Dark Lumberjack Shop', 'Dark Potion Shop', 'Dark Lake Hylia Ledge Spike Cave', + 'Dark Lake Hylia Ledge Hint', 'Hype Cave', 'Brewery', 'C-Shaped House', 'Chest Game', 'Hammer Peg Cave', 'Red Shield Shop', 'Dark Sanctuary Hint', 'Fortune Teller (Dark)', 'Archery Game', 'Mire Shed', 'Dark Desert Hint', 'Spike Cave', 'Skull Back Drop', 'Skull Left Drop', 'Skull Pinball', 'Skull Pot Circle', 'Pyramid' #'Big Bomb Shop', 'Ganons Tower Exit', @@ -1629,8 +1629,8 @@ default_lw = { 'Paradox Cave Exit (Middle)', 'Paradox Cave Exit (Top)', 'Fairy Ascension Cave Exit (Bottom)', 'Fairy Ascension Cave Exit (Top)', 'Spiral Cave Exit', 'Spiral Cave Exit (Top)', 'Waterfall of Wishing', 'Dam', 'Blinds Hideout', 'Lumberjack House', 'Bonk Fairy (Light)', 'Bonk Fairy (Dark)', 'Lake Hylia Healer Fairy', - 'Swamp Healer Fairy', 'Desert Healer Fairy', 'Fortune Teller (Light)', 'Lake Hylia Fortune Teller', 'Kings Grave', 'Tavern', - 'Chicken House', 'Aginahs Cave', 'Sahasrahlas Hut', 'Cave Shop (Lake Hylia)', 'Capacity Upgrade', 'Blacksmiths Hut', + 'Light Hype Fairy', 'Desert Healer Fairy', 'Fortune Teller (Light)', 'Lake Hylia Fortune Teller', 'Kings Grave', 'Tavern', + 'Chicken House', 'Aginahs Cave', 'Sahasrahlas Hut', 'Lake Hylia Shop', 'Capacity Upgrade', 'Blacksmiths Hut', 'Sick Kids House', 'Lost Woods Gamble', 'Snitch Lady (East)', 'Snitch Lady (West)', 'Bush Covered House', 'Tavern (Front)', 'Light World Bomb Hut', 'Kakariko Shop', 'Cave 45', 'Graveyard Cave', 'Checkerboard Cave', 'Mini Moldorm Cave', 'Long Fairy Cave', 'Good Bee Cave', '20 Rupee Cave', '50 Rupee Cave', 'Ice Rod Cave', @@ -1647,7 +1647,7 @@ LW_Entrances = ['Elder House (East)', 'Elder House (West)', 'Two Brothers House 'Desert Palace Entrance (East)', 'Eastern Palace', 'Tower of Hera', 'Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)', 'Hyrule Castle Entrance (South)', 'Agahnims Tower', 'Blinds Hideout', 'Lake Hylia Fairy', 'Light Hype Fairy', 'Desert Fairy', 'Tavern North', 'Chicken House', 'Aginahs Cave', - 'Sahasrahlas Hut', 'Cave Shop (Lake Hylia)', 'Blacksmiths Hut', 'Sick Kids House', 'Lost Woods Gamble', + 'Sahasrahlas Hut', 'Lake Hylia Shop', 'Blacksmiths Hut', 'Sick Kids House', 'Lost Woods Gamble', 'Fortune Teller (Light)', 'Snitch Lady (East)', 'Snitch Lady (West)', 'Bush Covered House', 'Tavern (Front)', 'Light World Bomb Hut', 'Kakariko Shop', 'Mini Moldorm Cave', 'Long Fairy Cave', 'Good Bee Cave', '20 Rupee Cave', '50 Rupee Cave', 'Ice Rod Cave', 'Library', 'Potion Shop', 'Dam', @@ -1666,10 +1666,10 @@ DW_Entrances = ['Bumper Cave (Bottom)', 'Superbunny Cave (Top)', 'Superbunny Ca 'Bonk Fairy (Dark)', 'Dark Sanctuary Hint', 'Dark Lake Hylia Fairy', 'C-Shaped House', 'Big Bomb Shop', 'Dark Death Mountain Fairy', 'Dark Lake Hylia Shop', 'Dark World Shop', 'Red Shield Shop', 'Mire Shed', 'East Dark World Hint', 'Dark Desert Hint', 'Spike Cave', 'Palace of Darkness Hint', - 'Dark Lake Hylia Ledge Spike Cave', 'Cave Shop (Dark Death Mountain)', 'Dark World Potion Shop', - 'Pyramid Fairy', 'Archery Game', 'Dark World Lumberjack Shop', 'Hype Cave', 'Brewery', + 'Dark Lake Hylia Ledge Spike Cave', 'Dark Death Mountain Shop', 'Dark Potion Shop', + 'Pyramid Fairy', 'Archery Game', 'Dark Lumberjack Shop', 'Hype Cave', 'Brewery', 'Dark Lake Hylia Ledge Hint', 'Chest Game', 'Dark Desert Fairy', 'Dark Lake Hylia Ledge Fairy', - 'Fortune Teller (Dark)', 'Dark World Hammer Peg Cave', 'Pyramid Entrance', + 'Fortune Teller (Dark)', 'Hammer Peg Cave', 'Pyramid Entrance', 'Skull Woods First Section Door', 'Skull Woods Second Section Door (East)', 'Skull Woods Second Section Door (West)'] @@ -1689,16 +1689,16 @@ Inverted_DW_Must_Exit = [] Isolated_LH_Doors_Open = ['Mimic Cave', 'Kings Grave', 'Waterfall of Wishing', 'Desert Palace Entrance (South)', 'Desert Palace Entrance (North)', 'Capacity Upgrade', 'Ice Palace', 'Skull Woods Final Section', 'Skull Woods Second Section Door (West)', - 'Dark World Hammer Peg Cave', 'Turtle Rock Isolated Ledge Entrance', + 'Hammer Peg Cave', 'Turtle Rock Isolated Ledge Entrance', 'Dark Death Mountain Ledge (West)', 'Dark Death Mountain Ledge (East)', - 'Dark World Shop', 'Dark World Potion Shop'] + 'Dark World Shop', 'Dark Potion Shop'] Isolated_LH_Doors_Inv = ['Kings Grave', 'Waterfall of Wishing', 'Desert Palace Entrance (South)', 'Desert Palace Entrance (North)', 'Capacity Upgrade', 'Ice Palace', 'Skull Woods Final Section', 'Skull Woods Second Section Door (West)', - 'Dark World Hammer Peg Cave', 'Turtle Rock Isolated Ledge Entrance', + 'Hammer Peg Cave', 'Turtle Rock Isolated Ledge Entrance', 'Dark Death Mountain Ledge (West)', 'Dark Death Mountain Ledge (East)', - 'Dark World Shop', 'Dark World Potion Shop'] + 'Dark World Shop', 'Dark Potion Shop'] # inverted doesn't like really like - Paradox Top or Tower of Hera LH_DM_Connector_List = { @@ -1707,19 +1707,19 @@ LH_DM_Connector_List = { 'Tower of Hera', 'Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Bottom)', 'Spectacle Rock Cave', 'Paradox Cave (Bottom)', 'Paradox Cave (Middle)', 'Paradox Cave (Top)', 'Hookshot Fairy', 'Spike Cave', 'Dark Death Mountain Fairy', 'Ganons Tower', 'Superbunny Cave (Top)', 'Superbunny Cave (Bottom)', - 'Hookshot Cave', 'Cave Shop (Dark Death Mountain)', 'Turtle Rock'} + 'Hookshot Cave', 'Dark Death Mountain Shop', 'Turtle Rock'} LH_DM_Exit_Forbidden = { 'Turtle Rock Isolated Ledge Entrance', 'Mimic Cave', 'Hookshot Cave Back Entrance', 'Dark Death Mountain Ledge (West)', 'Dark Death Mountain Ledge (East)', 'Desert Palace Entrance (South)', - 'Ice Palace', 'Waterfall of Wishing', 'Kings Grave', 'Dark World Hammer Peg Cave', 'Capacity Upgrade', + 'Ice Palace', 'Waterfall of Wishing', 'Kings Grave', 'Hammer Peg Cave', 'Capacity Upgrade', 'Skull Woods Final Section', 'Skull Woods Second Section Door (West)' -} # omissions from Isolated Starts: 'Desert Palace Entrance (North)', 'Dark World Shop', 'Dark World Potion Shop' +} # omissions from Isolated Starts: 'Desert Palace Entrance (North)', 'Dark World Shop', 'Dark Potion Shop' # in inverted we put dark sanctuary in west dark world for now Inverted_Dark_Sanctuary_Doors = [ 'Dark Sanctuary Hint', 'Fortune Teller (Dark)', 'Brewery', 'C-Shaped House', 'Chest Game', - 'Dark World Lumberjack Shop', 'Red Shield Shop', 'Bumper Cave (Bottom)', 'Bumper Cave (Top)', 'Thieves Town' + 'Dark Lumberjack Shop', 'Red Shield Shop', 'Bumper Cave (Bottom)', 'Bumper Cave (Top)', 'Thieves Town' ] Connector_List = [['Elder House Exit (East)', 'Elder House Exit (West)'], @@ -1788,7 +1788,7 @@ Simple_DM_Non_Connectors = {'Old Man Cave Ledge', 'Spiral Cave (Top)', 'Superbun Blacksmith_Options = [ 'Blinds Hideout', 'Lake Hylia Fairy', 'Light Hype Fairy', 'Desert Fairy', 'Tavern North', 'Chicken House', - 'Aginahs Cave', 'Sahasrahlas Hut', 'Cave Shop (Lake Hylia)', 'Blacksmiths Hut', 'Sick Kids House', 'Lost Woods Gamble', + 'Aginahs Cave', 'Sahasrahlas Hut', 'Lake Hylia Shop', 'Blacksmiths Hut', 'Sick Kids House', 'Lost Woods Gamble', 'Fortune Teller (Light)', 'Snitch Lady (East)', 'Snitch Lady (West)', 'Bush Covered House', 'Tavern (Front)', 'Light World Bomb Hut', 'Kakariko Shop', 'Mini Moldorm Cave', 'Long Fairy Cave', 'Good Bee Cave', '20 Rupee Cave', '50 Rupee Cave', 'Ice Rod Cave', 'Library', 'Potion Shop', 'Dam', 'Lumberjack House', 'Lake Hylia Fortune Teller', @@ -1801,9 +1801,9 @@ Bomb_Shop_Options = [ 'Kings Grave', 'Bonk Fairy (Light)', 'Hookshot Fairy', 'East Dark World Hint', 'Palace of Darkness Hint', 'Dark Lake Hylia Fairy', 'Dark Lake Hylia Ledge Fairy', 'Dark Lake Hylia Ledge Spike Cave', 'Dark Lake Hylia Ledge Hint', 'Hype Cave', 'Bonk Fairy (Dark)', 'Brewery', 'C-Shaped House', 'Chest Game', - 'Dark World Hammer Peg Cave', 'Red Shield Shop', 'Dark Sanctuary Hint', 'Fortune Teller (Dark)', 'Dark World Shop', - 'Dark World Lumberjack Shop', 'Dark World Potion Shop', 'Archery Game', 'Mire Shed', 'Dark Desert Hint', - 'Dark Desert Fairy', 'Spike Cave', 'Cave Shop (Dark Death Mountain)', 'Dark Death Mountain Fairy', 'Mimic Cave', + 'Hammer Peg Cave', 'Red Shield Shop', 'Dark Sanctuary Hint', 'Fortune Teller (Dark)', 'Dark World Shop', + 'Dark Lumberjack Shop', 'Dark Potion Shop', 'Archery Game', 'Mire Shed', 'Dark Desert Hint', + 'Dark Desert Fairy', 'Spike Cave', 'Dark Death Mountain Shop', 'Dark Death Mountain Fairy', 'Mimic Cave', 'Big Bomb Shop', 'Dark Lake Hylia Shop', 'Bumper Cave (Top)', 'Links House', 'Hyrule Castle Entrance (South)', 'Misery Mire', 'Thieves Town', 'Bumper Cave (Bottom)', 'Swamp Palace', 'Hyrule Castle Secret Entrance Stairs', 'Skull Woods First Section Door', 'Skull Woods Second Section Door (East)', @@ -1823,9 +1823,9 @@ Inverted_Bomb_Shop_Options = [ 'Kings Grave', 'Bonk Fairy (Light)', 'Hookshot Fairy', 'East Dark World Hint', 'Palace of Darkness Hint', 'Dark Lake Hylia Fairy', 'Dark Lake Hylia Ledge Fairy', 'Dark Lake Hylia Ledge Spike Cave', 'Dark Lake Hylia Ledge Hint', 'Hype Cave', 'Bonk Fairy (Dark)', 'Brewery', 'C-Shaped House', 'Chest Game', - 'Dark World Hammer Peg Cave', 'Red Shield Shop', 'Fortune Teller (Dark)', 'Dark World Shop', - 'Dark World Lumberjack Shop', 'Dark World Potion Shop', 'Archery Game', 'Mire Shed', 'Dark Desert Hint', - 'Dark Desert Fairy', 'Spike Cave', 'Cave Shop (Dark Death Mountain)', 'Dark Death Mountain Fairy', 'Mimic Cave', + 'Hammer Peg Cave', 'Red Shield Shop', 'Fortune Teller (Dark)', 'Dark World Shop', + 'Dark Lumberjack Shop', 'Dark Potion Shop', 'Archery Game', 'Mire Shed', 'Dark Desert Hint', + 'Dark Desert Fairy', 'Spike Cave', 'Dark Death Mountain Shop', 'Dark Death Mountain Fairy', 'Mimic Cave', 'Dark Lake Hylia Shop', 'Bumper Cave (Top)', 'Hyrule Castle Entrance (South)', 'Misery Mire', 'Thieves Town', 'Bumper Cave (Bottom)', 'Swamp Palace', 'Hyrule Castle Secret Entrance Stairs', 'Skull Woods First Section Door', 'Skull Woods Second Section Door (East)', @@ -1844,136 +1844,153 @@ Inverted_Bomb_Shop_Options = [ # 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'), - ('Lake Hylia Central Island Pier', 'Lake Hylia Central Island'), - ('Lake Hylia Central Island Water Drop', 'Lake Hylia Water'), - ('Potion Shop Water Drop', 'Lake Hylia Water'), - ('Northeast Light World Water Drop', 'Lake Hylia Water'), - ('Zora Waterfall Water Drop', 'Lake Hylia Water'), - ('Light World Water Drop', 'Lake Hylia Water'), - ('East Dark World Water Drop', 'Dark Lake Hylia Water'), - ('South Dark World Water Drop', 'Dark Lake Hylia Water'), - ('Southeast Dark World Water Drop', 'Dark Lake Hylia Water'), - ('Northeast Dark World Water Drop', 'Dark Lake Hylia Water'), - ('Catfish Water Drop', 'Dark Lake Hylia Water'), - ('Ice Palace Leave Water Drop', 'Dark Lake Hylia Water'), - ('West Dark World Water Drop', 'Dark Lake Hylia Water'), - ('Zoras Domain', 'Zoras Domain'), - ('Kings Grave Outer Rocks', 'Kings Grave Area'), - ('Kings Grave Inner Rocks', 'Light World'), - ('Kakariko Well (top to bottom)', 'Kakariko Well (bottom)'), - ('Kakariko Well (top to back)', 'Kakariko Well (back)'), - ('Master Sword Meadow', 'Master Sword Meadow'), - ('Hobo Pier', 'Hobo Bridge'), - ('Bat Cave Ledge Peg', 'Bat Cave Ledge'), - ('Bat Cave Ledge Peg (East)', 'Light World'), - ('Bat Cave Door', 'Bat Cave (left)'), + + # underworld ('Lost Woods Hideout (top to bottom)', 'Lost Woods Hideout (bottom)'), ('Lumberjack Tree (top to bottom)', 'Lumberjack Tree (bottom)'), - ('Blinds Hideout N', 'Blinds Hideout (Top)'), - ('Light World Pier', 'Light World'), - ('Potion Shop Pier', 'Potion Shop Area'), - ('Wooden Bridge Bush (North)', 'Light World'), - ('Wooden Bridge Bush (South)', 'Potion Shop Area'), - ('Potion Shop Rock (South)', 'Northeast Light World'), - ('Potion Shop Rock (North)', 'Potion Shop Area'), - ('Desert Statue Move', 'Desert Palace Stairs'), - ('Desert Palace Stairs Drop', 'Light World'), - ('Desert Palace Entrance (North) Rocks', 'Desert Palace Entrance (North) Spot'), - ('Desert Ledge Return Rocks', 'Desert Ledge'), - ('Sewer Drop', 'Sewers Rat Path'), - ('Death Mountain Entrance Rock', 'Death Mountain Entrance'), - ('Death Mountain Entrance Drop', 'Light World'), - ('Spectacle Rock Cave Drop', 'Spectacle Rock Cave (Bottom)'), - ('Spectacle Rock Cave Peak Drop', 'Spectacle Rock Cave (Bottom)'), ('Death Mountain Return Cave E', 'Death Mountain Return Cave (right)'), ('Death Mountain Return Cave W', 'Death Mountain Return Cave (left)'), - ('Death Mountain Return Ledge Drop', 'Light World'), ('Old Man Cave Dropdown', 'Old Man Cave'), + ('Spectacle Rock Cave Drop', 'Spectacle Rock Cave (Bottom)'), + ('Spectacle Rock Cave Peak Drop', 'Spectacle Rock Cave (Bottom)'), ('Old Man House Front to Back', 'Old Man House Back'), ('Old Man House Back to Front', 'Old Man House'), - ('DM Broken Bridge (West)', 'East Death Mountain (Bottom)'), - ('DM Broken Bridge (East)', 'Death Mountain (West Bottom)'), - ('East Death Mountain Drop', 'East Death Mountain (Bottom)'), - ('Spiral Cave Ledge Access', 'Spiral Cave Ledge'), - ('Spiral Cave Ledge Drop', 'East Death Mountain (Bottom)'), ('Spiral Cave (top to bottom)', 'Spiral Cave (Bottom)'), - ('DM Hammer Bridge (West)', 'East Death Mountain (Top)'), - ('DM Hammer Bridge (East)', 'Death Mountain (Top)'), - ('Death Mountain Drop', 'Death Mountain (West Bottom)'), - ('East Dark World Pier', 'East Dark World'), - ('Hammer Bridge Pegs (North)', 'South Dark World'), - ('Hammer Bridge Pegs (South)', 'East Dark World'), - ('Village of Outcasts Heavy Rock', 'West Dark World'), - ('Village of Outcasts Drop', 'South Dark World'), - ('Village of Outcasts Eastern Rocks', 'Hammer Peg Area'), - ('Village of Outcasts Pegs', 'Dark Grassy Lawn'), - ('Peg Area Rocks', 'West Dark World'), - ('Grassy Lawn Pegs', 'West Dark World'), - ('West Dark World Gap', 'West Dark World'), - ('East Dark World Broken Bridge Pass', 'East Dark World'), - ('Dark Witch Rock (North)', 'Northeast Dark World'), - ('Dark Witch Rock (South)', 'Catfish Area'), - ('Northeast Dark World Broken Bridge Pass', 'Northeast Dark World'), - ('Bumper Cave Entrance Rock', 'Bumper Cave Entrance'), - ('Bumper Cave Entrance Drop', 'West Dark World'), - ('Bumper Cave Ledge Drop', 'West Dark World'), - ('Bumper Cave Bottom to Top', 'Bumper Cave (top)'), - ('Bumper Cave Top To Bottom', 'Bumper Cave (bottom)'), - ('Skull Woods Forest', 'Skull Woods Forest'), ('Paradox Cave Push Block Reverse', 'Paradox Cave Chest Area'), ('Paradox Cave Push Block', 'Paradox Cave Front'), ('Paradox Cave Chest Area NE', 'Paradox Cave Bomb Area'), ('Paradox Cave Bomb Jump', 'Paradox Cave'), ('Paradox Cave Drop', 'Paradox Cave Chest Area'), - ('Light World Death Mountain Shop', 'Light World Death Mountain Shop'), - ('Fairy Ascension Rocks', 'Fairy Ascension Plateau'), - ('Fairy Ascension Drop', 'East Death Mountain (Bottom)'), - ('Fairy Ascension Ledge Drop', 'Fairy Ascension Plateau'), + ('Paradox Shop', 'Paradox Shop'), ('Fairy Ascension Cave Climb', 'Fairy Ascension Cave (Top)'), ('Fairy Ascension Cave Pots', 'Fairy Ascension Cave (Bottom)'), ('Fairy Ascension Cave Drop', 'Fairy Ascension Cave (Drop)'), - ('Dark Death Mountain Drop (East)', 'Dark Death Mountain (East Bottom)'), - ('Superbunny Cave Climb', 'Superbunny Cave (Top)'), + ('Sewer Drop', 'Sewers Rat Path'), + ('Kakariko Well (top to bottom)', 'Kakariko Well (bottom)'), + ('Kakariko Well (top to back)', 'Kakariko Well (back)'), + ('Blinds Hideout N', 'Blinds Hideout (Top)'), + ('Bat Cave Door', 'Bat Cave (left)'), + ('Hookshot Cave Front to Middle', 'Hookshot Cave (Middle)'), ('Hookshot Cave Middle to Front', 'Hookshot Cave (Front)'), ('Hookshot Cave Middle to Back', 'Hookshot Cave (Back)'), ('Hookshot Cave Back to Middle', 'Hookshot Cave (Middle)'), ('Hookshot Cave Bonk Path', 'Hookshot Cave (Bonk Islands)'), ('Hookshot Cave Hook Path', 'Hookshot Cave (Hook Islands)'), + ('Superbunny Cave Climb', 'Superbunny Cave (Top)'), + ('Bumper Cave Bottom to Top', 'Bumper Cave (top)'), + ('Bumper Cave Top To Bottom', 'Bumper Cave (bottom)'), ('Ganon Drop', 'Bottom of Pyramid'), - ('Pyramid Drop', 'East Dark World'), - ('Maze Race Ledge Drop', 'Light World'), - ('Hyrule Castle Ledge Drop', 'Light World'), - ('Desert Ledge Drop', 'Light World'), + + # water entry + ('Light World Water Drop', 'Lake Hylia Water'), + ('Potion Shop Water Drop', 'Lake Hylia Water'), + ('Northeast Light World Water Drop', 'Lake Hylia Water'), + ('Lake Hylia Central Island Water Drop', 'Lake Hylia Water'), + ('Zora Waterfall Water Drop', 'Lake Hylia Water'), + + ('West Dark World Water Drop', 'Dark Lake Hylia Water'), + ('South Dark World Water Drop', 'Dark Lake Hylia Water'), + ('East Dark World Water Drop', 'Dark Lake Hylia Water'), + ('Northeast Dark World Water Drop', 'Dark Lake Hylia Water'), + ('Southeast Dark World Water Drop', 'Dark Lake Hylia Water'), + ('Catfish Water Drop', 'Dark Lake Hylia Water'), + ('Ice Palace Leave Water Drop', 'Dark Lake Hylia Water'), + + # water exit + ('Lake Hylia Central Island Pier', 'Lake Hylia Central Island'), + ('Hobo Pier', 'Hobo Bridge'), + ('Light World Pier', 'Light World'), # there are several piers in-game, only one needs to be modeled + ('Potion Shop Pier', 'Potion Shop Area'), ('Lake Hylia Whirlpool', 'Northeast Light World'), - ('Hyrule Castle Ledge Courtyard Drop', 'Hyrule Castle Courtyard'), + ('Waterfall Fairy Access', 'Zora Waterfall Entryway'), + + ('East Dark World Pier', 'East Dark World'), ('Southeast Dark World Pier', 'Southeast Dark World'), ('Northeast Dark World River Pier', 'Northeast Dark World'), - ('Fairy Ascension Ledge Access', 'Fairy Ascension Ledge'), - ('Hyrule Castle Courtyard Bush (North)', 'Hyrule Castle Courtyard'), - ('Hyrule Castle Courtyard Bush (South)', 'Hyrule Castle Secret Entrance Area'), - ('Turtle Rock Drop', 'Dark Death Mountain (Top)'), - ('Floating Island Drop', 'Dark Death Mountain (Top)'), - ('Dark Desert Drop', 'Dark Desert'), + + # terrain + ('Master Sword Meadow', 'Master Sword Meadow'), + ('DM Hammer Bridge (West)', 'East Death Mountain (Top)'), + ('DM Hammer Bridge (East)', 'West Death Mountain (Top)'), + ('DM Broken Bridge (West)', 'East Death Mountain (Bottom)'), + ('DM Broken Bridge (East)', 'West Death Mountain (Bottom)'), + ('Fairy Ascension Rocks', 'Fairy Ascension Plateau'), + ('Death Mountain Entrance Rock', 'Death Mountain Entrance'), + ('Zoras Domain', 'Zoras Domain'), + ('Kings Grave Rocks (Outer)', 'Kings Grave Area'), + ('Kings Grave Rocks (Inner)', 'Light World'), + ('Potion Shop Rock (South)', 'Northeast Light World'), + ('Potion Shop Rock (North)', 'Potion Shop Area'), ('Kakariko Yard Bush (North)', 'Light World'), ('Kakariko Yard Bush (South)', 'Bush Covered Lawn'), - ('Bush Covered Lawn Mirror Spot', 'Dark Grassy Lawn'), ('Kakariko Southwest Bush (South)', 'Light World'), ('Kakariko Southwest Bush (North)', 'Bomb Hut Area'), ('Hyrule Castle Main Gate', 'Hyrule Castle Courtyard'), - ('Spectacle Rock Drop', 'Death Mountain (Top)'), - ('Desert Teleporter Drop', 'Light World'), - ('Dark Death Mountain Drop (West)', 'Dark Death Mountain (West Bottom)'), + ('Hyrule Castle Main Gate (North)', 'Light World'), + ('Hyrule Castle Courtyard Bush (North)', 'Hyrule Castle Courtyard'), + ('Hyrule Castle Courtyard Bush (South)', 'Hyrule Castle Secret Entrance Area'), + ('Wooden Bridge Bush (North)', 'Light World'), + ('Wooden Bridge Bush (South)', 'Potion Shop Area'), + ('Bat Cave Ledge Peg', 'Bat Cave Ledge'), + ('Bat Cave Ledge Peg (East)', 'Light World'), + ('Desert Statue Move', 'Desert Palace Stairs'), + ('Desert Ledge Rocks (Outer)', 'Desert Palace Entrance (North) Spot'), + ('Desert Ledge Rocks (Inner)', 'Desert Ledge'), + + ('Skull Woods Forest', 'Skull Woods Forest'), + ('Bumper Cave Entrance Rock', 'Bumper Cave Entrance'), + ('Dark Witch Rock (North)', 'Northeast Dark World'), + ('Dark Witch Rock (South)', 'Catfish Area'), + ('Grassy Lawn Pegs (Bottom)', 'Dark Grassy Lawn'), + ('Grassy Lawn Pegs (Top)', 'West Dark World'), + ('West Dark World Gap', 'West Dark World'), + ('Broken Bridge Pass (Top)', 'East Dark World'), + ('Broken Bridge Pass (Bottom)', 'Northeast Dark World'), + ('Peg Area Rocks (Left)', 'Hammer Peg Area'), + ('Peg Area Rocks (Right)', 'West Dark World'), + ('Village of Outcasts Heavy Rock', 'West Dark World'), + ('Hammer Bridge Pegs (North)', 'South Dark World'), + ('Hammer Bridge Pegs (South)', 'East Dark World'), + + # ledge drops + ('Spectacle Rock Drop', 'West Death Mountain (Top)'), + ('Death Mountain Drop', 'West Death Mountain (Bottom)'), + ('Spiral Cave Ledge Access', 'Spiral Cave Ledge'), + ('Fairy Ascension Ledge Access', 'Fairy Ascension Ledge'), + ('East Death Mountain Drop', 'East Death Mountain (Bottom)'), + ('Spiral Cave Ledge Drop', 'East Death Mountain (Bottom)'), + ('Fairy Ascension Ledge Drop', 'Fairy Ascension Plateau'), + ('Fairy Ascension Drop', 'East Death Mountain (Bottom)'), + ('Death Mountain Entrance Drop', 'Light World'), + ('Death Mountain Return Ledge Drop', 'Light World'), ('Graveyard Ledge Drop', 'Light World'), - ('Cave 45 Ledge Drop', 'Light World'), + ('Hyrule Castle Ledge Courtyard Drop', 'Hyrule Castle Courtyard'), + ('Hyrule Castle Ledge Drop', 'Light World'), + ('Maze Race Ledge Drop', 'Light World'), + ('Desert Ledge Drop', 'Light World'), + ('Desert Palace Mouth Drop', 'Light World'), ('Checkerboard Ledge Drop', 'Light World'), - ('Hyrule Castle Main Gate (North)', 'Light World') + ('Desert Teleporter Drop', 'Light World'), + ('Cave 45 Ledge Drop', 'Light World'), + + ('Dark Death Mountain Drop (West)', 'West Dark Death Mountain (Bottom)'), + ('Dark Death Mountain Drop (East)', 'East Dark Death Mountain (Bottom)'), + ('Floating Island Drop', 'Dark Death Mountain (Top)'), + ('Turtle Rock Drop', 'Dark Death Mountain (Top)'), + ('Bumper Cave Entrance Drop', 'West Dark World'), + ('Bumper Cave Ledge Drop', 'West Dark World'), + ('Pyramid Drop', 'East Dark World'), + ('Village of Outcasts Drop', 'South Dark World'), + ('Dark Desert Drop', 'Dark Desert') ] open_mandatory_connections = [('Sanctuary S&Q', 'Sanctuary'), ('Old Man S&Q', 'Old Man House'), ('Other World S&Q', 'East Dark World'), - ('Flute Spot 1', 'Death Mountain (West Bottom)'), + + # flute + ('Flute Spot 1', 'West Death Mountain (Bottom)'), ('Flute Spot 2', 'Potion Shop Area'), ('Flute Spot 3', 'Light World'), ('Flute Spot 4', 'Light World'), @@ -1986,51 +2003,50 @@ open_mandatory_connections = [('Sanctuary S&Q', 'Sanctuary'), ('ZLW Flute', 'Flute Sky'), ('DM Flute', 'Flute Sky'), ('EDM Flute', 'Flute Sky'), - ('Lake Hylia Central Island Teleporter', 'Dark Lake Hylia Central Island'), - ('Kings Grave Mirror Spot', 'Kings Grave Area'), - ('Top of Pyramid', 'East Dark World'), - ('Lake Hylia Island Mirror Spot', 'Lake Hylia Island'), - ('Lake Hylia Central Island Mirror Spot', 'Lake Hylia Central Island'), - ('Hyrule Castle Ledge Mirror Spot', 'Hyrule Castle Ledge'), - ('Dig Game Mirror Spot', 'Maze Race Ledge'), - ('Bat Cave Drop Ledge Mirror Spot', 'Bat Cave Ledge'), - ('Bumper Cave Entrance Mirror Spot', 'Death Mountain Entrance'), - ('Bumper Cave Ledge Mirror Spot', 'Death Mountain Return Ledge'), - ('Desert Ledge Mirror Spot', 'Desert Ledge'), - ('Desert Ledge (Northeast) Mirror Spot', 'Desert Checkerboard Ledge'), - ('Desert Palace Entrance (North) Mirror Spot', 'Desert Palace Entrance (North) Spot'), - ('Desert Teleporter', 'Dark Desert'), - ('Mire To Desert Palace Stairs Mirror Spot', 'Desert Palace Stairs'), + + # portals + ('Death Mountain Teleporter', 'West Dark Death Mountain (Bottom)'), + ('East Death Mountain Teleporter', 'East Dark Death Mountain (Bottom)'), + ('Turtle Rock Teleporter', 'Turtle Rock (Top)'), + ('Kakariko Teleporter', 'West Dark World'), + ('Castle Gate Teleporter', 'East Dark World'), ('East Hyrule Teleporter', 'East Dark World'), ('South Hyrule Teleporter', 'South Dark World'), - ('Kakariko Teleporter', 'West Dark World'), - ('Death Mountain Teleporter', 'Dark Death Mountain (West Bottom)'), - ('Fairy Ascension Mirror Spot', 'Fairy Ascension Plateau'), + ('Desert Teleporter', 'Dark Desert'), + ('Lake Hylia Teleporter', 'Dark Lake Hylia Central Island'), + + # mirror ('Spectacle Rock Mirror Spot', 'Spectacle Rock'), + ('Fairy Ascension Mirror Spot', 'Fairy Ascension Plateau'), ('East Death Mountain (Top) Mirror Spot', 'East Death Mountain (Top)'), - ('Turtle Rock Teleporter', 'Turtle Rock (Top)'), - ('Dark Grassy Lawn Mirror Spot', 'Bush Covered Lawn'), ('Dark Floating Island Mirror Spot', 'Death Mountain Floating Island'), - ('East Death Mountain Teleporter', 'Dark Death Mountain (East Bottom)'), - ('Isolated Ledge Mirror Spot', 'Fairy Ascension Ledge'), ('Spiral Cave Mirror Spot', 'Spiral Cave Ledge'), ('Mimic Cave Mirror Spot', 'Mimic Cave Ledge'), - ('Cave 45 Mirror Spot', 'Cave 45 Ledge'), + ('Isolated Ledge Mirror Spot', 'Fairy Ascension Ledge'), + ('Bumper Cave Ledge Mirror Spot', 'Death Mountain Return Ledge'), + ('Bumper Cave Entrance Mirror Spot', 'Death Mountain Entrance'), + ('Kings Grave Mirror Spot', 'Kings Grave Area'), + ('Dark Grassy Lawn Mirror Spot', 'Bush Covered Lawn'), + ('Hyrule Castle Ledge Mirror Spot', 'Hyrule Castle Ledge'), + ('Bat Cave Drop Ledge Mirror Spot', 'Bat Cave Ledge'), + ('Dig Game Mirror Spot', 'Maze Race Ledge'), + ('Desert Ledge Rocks Mirror Spot', 'Desert Palace Entrance (North) Spot'), + ('Desert Ledge Mirror Spot', 'Desert Ledge'), + ('Mire To Desert Stairs Mirror Spot', 'Desert Palace Stairs'), + ('Checkerboard Ledge Mirror Spot', 'Desert Checkerboard Ledge'), ('Bombos Tablet Mirror Spot', 'Bombos Tablet Ledge'), + ('Cave 45 Mirror Spot', 'Cave 45 Ledge'), + ('Lake Hylia Island Mirror Spot', 'Lake Hylia Island'), + ('Lake Hylia Central Island Mirror Spot', 'Lake Hylia Central Island'), ('Graveyard Ledge Mirror Spot', 'Graveyard Ledge') ] inverted_mandatory_connections = [('Sanctuary S&Q', 'Dark Sanctuary Hint'), - ('Old Man S&Q', 'Dark Death Mountain (West Bottom)'), + ('Old Man S&Q', 'West Dark Death Mountain (Bottom)'), ('Other World S&Q', 'Hyrule Castle Ledge'), - ('Lake Hylia Island Pier', 'Lake Hylia Island'), - ('Spectacle Rock Leave', 'Death Mountain (Top)'), - ('Spectacle Rock Approach', 'Spectacle Rock'), - ('Checkerboard Ledge Approach', 'Desert Checkerboard Ledge'), - ('Checkerboard Ledge Leave', 'Light World'), - ('Cave 45 Approach', 'Cave 45 Ledge'), - ('Cave 45 Leave', 'Light World'), - ('Flute Spot 1', 'Dark Death Mountain (West Bottom)'), + + # flute + ('Flute Spot 1', 'West Dark Death Mountain (Bottom)'), ('Flute Spot 2', 'Northeast Dark World'), ('Flute Spot 3', 'West Dark World'), ('Flute Spot 4', 'South Dark World'), @@ -2048,250 +2064,266 @@ inverted_mandatory_connections = [('Sanctuary S&Q', 'Dark Sanctuary Hint'), ('EDDM Flute', 'Flute Sky'), ('Dark Grassy Lawn Flute', 'Flute Sky'), ('Hammer Peg Area Flute', 'Flute Sky'), + + # modified terrain + ('Lake Hylia Island Pier', 'Lake Hylia Island'), + ('Spectacle Rock Leave', 'West Death Mountain (Top)'), + ('Spectacle Rock Approach', 'Spectacle Rock'), + ('Checkerboard Ledge Approach', 'Desert Checkerboard Ledge'), + ('Checkerboard Ledge Leave', 'Light World'), + ('Cave 45 Approach', 'Cave 45 Ledge'), + ('Cave 45 Leave', 'Light World'), ('Dark Death Mountain Ladder (Bottom)', 'Dark Death Mountain (Top)'), - ('Dark Death Mountain Ladder (Top)', 'Dark Death Mountain (West Bottom)'), + ('Dark Death Mountain Ladder (Top)', 'West Dark Death Mountain (Bottom)'), ('Ice Palace Approach', 'Dark Lake Hylia Central Island'), ('Floating Island Bridge (East)', 'Death Mountain Floating Island'), ('Floating Island Bridge (West)', 'East Death Mountain (Top)'), - ('Post Aga Teleporter', 'Light World'), ('Graveyard Ladder (Top)', 'Light World'), ('Graveyard Ladder (Bottom)', 'Graveyard Ledge'), - ('Graveyard Cave Mirror Spot', 'West Dark World'), - ('Pyramid Uncle Mirror Spot', 'East Dark World'), ('Mimic Cave Ledge Access', 'Mimic Cave Ledge'), ('Mimic Cave Ledge Drop', 'East Death Mountain (Bottom)'), ('Turtle Rock Tail Drop', 'Turtle Rock (Top)'), - ('Dark Lake Hylia Central Island Teleporter', 'Lake Hylia Central Island'), - ('Dark Desert Teleporter', 'Light World'), - ('East Dark World Teleporter', 'Light World'), - ('South Dark World Teleporter', 'Light World'), - ('West Dark World Teleporter', 'Light World'), - ('Dark Death Mountain Teleporter (West)', 'Death Mountain (West Bottom)'), - ('Dark Death Mountain Teleporter (East)', 'East Death Mountain (Top)'), - ('Dark Death Mountain Teleporter (East Bottom)', 'East Death Mountain (Bottom)'), - ('Mire Mirror Spot', 'Dark Desert'), ('Bombos Tablet Ladder (Top)', 'Light World'), ('Bombos Tablet Ladder (Bottom)', 'Bombos Tablet Ledge'), - ('Desert Palace Stairs Mirror Spot', 'Dark Desert'), - ('Desert Palace North Mirror Spot', 'Dark Desert'), - ('Maze Race Mirror Spot', 'South Dark World'), - ('Lake Hylia Central Island Mirror Spot', 'Dark Lake Hylia Central Island'), - ('Hammer Peg Area Mirror Spot', 'Hammer Peg Area'), - ('Mountain Exit Ledge Mirror Spot', 'Bumper Cave Ledge'), - ('Bumper Cave Entrance Mirror Spot', 'Bumper Cave Entrance'), - ('Death Mountain Mirror Spot', 'Dark Death Mountain (West Bottom)'), - ('East Death Mountain Mirror Spot (Top)', 'Dark Death Mountain (Top)'), - ('East Death Mountain Mirror Spot (Bottom)', 'Dark Death Mountain (East Bottom)'), + + # portals + ('Dark Death Mountain Teleporter (West)', 'West Death Mountain (Bottom)'), + ('East Dark Death Mountain Teleporter (Bottom)', 'East Death Mountain (Bottom)'), + ('East Dark Death Mountain Teleporter (Top)', 'East Death Mountain (Top)'), + ('West Dark World Teleporter', 'Light World'), + ('Post Aga Teleporter', 'Light World'), + ('East Dark World Teleporter', 'Light World'), + ('South Dark World Teleporter', 'Light World'), + ('Dark Desert Teleporter', 'Light World'), + ('Dark Lake Hylia Teleporter', 'Lake Hylia Central Island'), + + # mirror + ('Skull Woods Mirror Spot', 'Skull Woods Forest (West)'), + ('Death Mountain Mirror Spot', 'West Dark Death Mountain (Bottom)'), ('Death Mountain (Top) Mirror Spot', 'Dark Death Mountain (Top)'), + ('East Death Mountain Mirror Spot (Top)', 'Dark Death Mountain (Top)'), + ('Floating Island Mirror Spot', 'Dark Death Mountain Floating Island'), ('Dark Death Mountain Ledge Mirror Spot (East)', 'Dark Death Mountain Ledge'), ('Dark Death Mountain Ledge Mirror Spot (West)', 'Dark Death Mountain Ledge'), - ('Floating Island Mirror Spot', 'Death Mountain Floating Island (Dark World)'), ('Laser Bridge Mirror Spot', 'Dark Death Mountain Isolated Ledge'), + ('East Death Mountain Mirror Spot (Bottom)', 'East Dark Death Mountain (Bottom)'), + ('Mountain Exit Ledge Mirror Spot', 'Bumper Cave Ledge'), + ('Mountain Entrance Mirror Spot', 'Bumper Cave Entrance'), + ('Catfish Mirror Spot', 'Catfish Area'), + ('Graveyard Cave Mirror Spot', 'West Dark World'), + ('Potion Shop Mirror Spot', 'Northeast Dark World'), + ('Bush Covered Lawn Mirror Spot', 'Dark Grassy Lawn'), + ('Bomb Hut Mirror Spot', 'West Dark World'), + ('Pyramid Uncle Mirror Spot', 'East Dark World'), + ('Hammer Peg Area Mirror Spot', 'Hammer Peg Area'), + ('Maze Race Mirror Spot', 'South Dark World'), + ('South Dark World Mirror Spot', 'South Dark World'), + ('Mire Mirror Spot', 'Dark Desert'), + ('Desert Palace Stairs Mirror Spot', 'Dark Desert'), + ('Desert Palace North Mirror Spot', 'Dark Desert'), + ('Lake Hylia Central Island Mirror Spot', 'Dark Lake Hylia Central Island'), ('East Dark World Mirror Spot', 'East Dark World'), ('West Dark World Mirror Spot', 'West Dark World'), - ('South Dark World Mirror Spot', 'South Dark World'), - ('Potion Shop Mirror Spot', 'Northeast Dark World'), - ('Catfish Mirror Spot', 'Catfish Area'), - ('Shopping Mall Mirror Spot', 'Southeast Dark World'), - ('Skull Woods Mirror Spot', 'Skull Woods Forest (West)'), - ('Bomb Hut Mirror Spot', 'West Dark World') + ('Shopping Mall Mirror Spot', 'Southeast Dark World') ] # non-shuffled entrance links -default_connections = {'Waterfall of Wishing': 'Waterfall of Wishing', - 'Blinds Hideout': 'Blinds Hideout', - 'Dam': 'Dam', - 'Lumberjack House': 'Lumberjack House', - 'Hyrule Castle Secret Entrance Drop': 'Hyrule Castle Secret Entrance', - 'Hyrule Castle Secret Entrance Stairs': 'Hyrule Castle Secret Entrance', - 'Hyrule Castle Secret Entrance Exit': 'Hyrule Castle Secret Entrance Area', - 'Bonk Fairy (Light)': 'Bonk Fairy (Light)', - 'Lake Hylia Fairy': 'Lake Hylia Healer Fairy', - 'Lake Hylia Fortune Teller': 'Lake Hylia Fortune Teller', - 'Light Hype Fairy': 'Swamp Healer Fairy', - 'Desert Fairy': 'Desert Healer Fairy', - 'Kings Grave': 'Kings Grave', - 'Tavern North': 'Tavern', - 'Chicken House': 'Chicken House', - 'Aginahs Cave': 'Aginahs Cave', - 'Sahasrahlas Hut': 'Sahasrahlas Hut', - 'Cave Shop (Lake Hylia)': 'Cave Shop (Lake Hylia)', - 'Capacity Upgrade': 'Capacity Upgrade', - 'Kakariko Well Drop': 'Kakariko Well (top)', - 'Kakariko Well Cave': 'Kakariko Well (bottom)', - 'Kakariko Well Exit': 'Light World', - 'Blacksmiths Hut': 'Blacksmiths Hut', - 'Bat Cave Drop': 'Bat Cave (right)', - 'Bat Cave Cave': 'Bat Cave (left)', - 'Bat Cave Exit': 'Light World', - 'Sick Kids House': 'Sick Kids House', - 'Elder House (East)': 'Elder House', - 'Elder House (West)': 'Elder House', - 'Elder House Exit (East)': 'Light World', - 'Elder House Exit (West)': 'Light World', - 'North Fairy Cave Drop': 'North Fairy Cave', - 'North Fairy Cave': 'North Fairy Cave', - 'North Fairy Cave Exit': 'Light World', - 'Lost Woods Gamble': 'Lost Woods Gamble', - 'Fortune Teller (Light)': 'Fortune Teller (Light)', - 'Snitch Lady (East)': 'Snitch Lady (East)', - 'Snitch Lady (West)': 'Snitch Lady (West)', - 'Bush Covered House': 'Bush Covered House', - 'Tavern (Front)': 'Tavern (Front)', - 'Light World Bomb Hut': 'Light World Bomb Hut', - 'Kakariko Shop': 'Kakariko Shop', +default_connections = {'Lost Woods Gamble': 'Lost Woods Gamble', 'Lost Woods Hideout Drop': 'Lost Woods Hideout (top)', 'Lost Woods Hideout Stump': 'Lost Woods Hideout (bottom)', 'Lost Woods Hideout Exit': 'Light World', + 'Lumberjack House': 'Lumberjack House', 'Lumberjack Tree Tree': 'Lumberjack Tree (top)', 'Lumberjack Tree Cave': 'Lumberjack Tree (bottom)', 'Lumberjack Tree Exit': 'Light World', - 'Cave 45': 'Cave 45', - 'Graveyard Cave': 'Graveyard Cave', - 'Checkerboard Cave': 'Checkerboard Cave', - 'Mini Moldorm Cave': 'Mini Moldorm Cave', - 'Long Fairy Cave': 'Long Fairy Cave', - 'Good Bee Cave': 'Good Bee Cave', - '20 Rupee Cave': '20 Rupee Cave', - '50 Rupee Cave': '50 Rupee Cave', - 'Ice Rod Cave': 'Ice Rod Cave', - 'Bonk Rock Cave': 'Bonk Rock Cave', - 'Library': 'Library', - 'Kakariko Gamble Game': 'Kakariko Gamble Game', - 'Potion Shop': 'Potion Shop', - 'Two Brothers House (East)': 'Two Brothers House', - 'Two Brothers House (West)': 'Two Brothers House', - 'Two Brothers House Exit (East)': 'Light World', - 'Two Brothers House Exit (West)': 'Maze Race Ledge', - 'Sanctuary': 'Sanctuary Portal', - 'Sanctuary Grave': 'Sewer Drop', - 'Sanctuary Exit': 'Light World', - 'Old Man House (Bottom)': 'Old Man House', - 'Old Man House Exit (Bottom)': 'Death Mountain (West Bottom)', - 'Old Man House (Top)': 'Old Man House Back', - 'Old Man House Exit (Top)': 'Death Mountain (West Bottom)', 'Death Mountain Return Cave (East)': 'Death Mountain Return Cave (right)', - 'Death Mountain Return Cave Exit (East)': 'Death Mountain (West Bottom)', + 'Death Mountain Return Cave Exit (East)': 'West Death Mountain (Bottom)', 'Spectacle Rock Cave Peak': 'Spectacle Rock Cave (Peak)', 'Spectacle Rock Cave (Bottom)': 'Spectacle Rock Cave (Bottom)', 'Spectacle Rock Cave': 'Spectacle Rock Cave (Top)', - 'Spectacle Rock Cave Exit': 'Death Mountain (West Bottom)', - 'Spectacle Rock Cave Exit (Top)': 'Death Mountain (West Bottom)', - 'Spectacle Rock Cave Exit (Peak)': 'Death Mountain (West Bottom)', + 'Spectacle Rock Cave Exit': 'West Death Mountain (Bottom)', + 'Spectacle Rock Cave Exit (Top)': 'West Death Mountain (Bottom)', + 'Spectacle Rock Cave Exit (Peak)': 'West Death Mountain (Bottom)', + 'Old Man House (Bottom)': 'Old Man House', + 'Old Man House Exit (Bottom)': 'West Death Mountain (Bottom)', + 'Old Man House (Top)': 'Old Man House Back', + 'Old Man House Exit (Top)': 'West Death Mountain (Bottom)', + 'Spiral Cave': 'Spiral Cave (Top)', + 'Spiral Cave (Bottom)': 'Spiral Cave (Bottom)', + 'Spiral Cave Exit': 'East Death Mountain (Bottom)', + 'Spiral Cave Exit (Top)': 'Spiral Cave Ledge', + 'Mimic Cave': 'Mimic Cave', + 'Fairy Ascension Cave (Bottom)': 'Fairy Ascension Cave (Bottom)', + 'Fairy Ascension Cave (Top)': 'Fairy Ascension Cave (Top)', + 'Fairy Ascension Cave Exit (Bottom)': 'Fairy Ascension Plateau', + 'Fairy Ascension Cave Exit (Top)': 'Fairy Ascension Ledge', + 'Hookshot Fairy': 'Hookshot Fairy', 'Paradox Cave (Bottom)': 'Paradox Cave Front', 'Paradox Cave (Middle)': 'Paradox Cave', 'Paradox Cave (Top)': 'Paradox Cave', 'Paradox Cave Exit (Bottom)': 'East Death Mountain (Bottom)', 'Paradox Cave Exit (Middle)': 'East Death Mountain (Bottom)', 'Paradox Cave Exit (Top)': 'East Death Mountain (Top)', - 'Hookshot Fairy': 'Hookshot Fairy', - 'Fairy Ascension Cave (Bottom)': 'Fairy Ascension Cave (Bottom)', - 'Fairy Ascension Cave (Top)': 'Fairy Ascension Cave (Top)', - 'Fairy Ascension Cave Exit (Bottom)': 'Fairy Ascension Plateau', - 'Fairy Ascension Cave Exit (Top)': 'Fairy Ascension Ledge', - 'Spiral Cave': 'Spiral Cave (Top)', - 'Spiral Cave (Bottom)': 'Spiral Cave (Bottom)', - 'Spiral Cave Exit': 'East Death Mountain (Bottom)', - 'Spiral Cave Exit (Top)': 'Spiral Cave Ledge', - 'Pyramid Fairy': 'Pyramid Fairy', - 'East Dark World Hint': 'East Dark World Hint', - 'Palace of Darkness Hint': 'Palace of Darkness Hint', - 'Dark Lake Hylia Shop': 'Dark Lake Hylia Shop', - 'Dark Lake Hylia Fairy': 'Dark Lake Hylia Healer Fairy', - 'Dark Lake Hylia Ledge Fairy': 'Dark Lake Hylia Ledge Healer Fairy', - 'Dark Lake Hylia Ledge Spike Cave': 'Dark Lake Hylia Ledge Spike Cave', - 'Dark Lake Hylia Ledge Hint': 'Dark Lake Hylia Ledge Hint', - 'Hype Cave': 'Hype Cave', - 'Bonk Fairy (Dark)': 'Bonk Fairy (Dark)', - 'Brewery': 'Brewery', - 'C-Shaped House': 'C-Shaped House', - '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', - 'Fortune Teller (Dark)': 'Fortune Teller (Dark)', - 'Dark World Shop': 'Village of Outcasts Shop', - 'Dark World Lumberjack Shop': 'Dark World Lumberjack Shop', - 'Dark World Potion Shop': 'Dark World Potion Shop', - 'Archery Game': 'Archery Game', - 'Mire Shed': 'Mire Shed', - 'Dark Desert Hint': 'Dark Desert Hint', - 'Dark Desert Fairy': 'Dark Desert Healer Fairy', + 'Waterfall of Wishing': 'Waterfall of Wishing', + 'Fortune Teller (Light)': 'Fortune Teller (Light)', + 'Bonk Rock Cave': 'Bonk Rock Cave', + 'Sanctuary': 'Sanctuary Portal', + 'Sanctuary Exit': 'Light World', + 'Sanctuary Grave': 'Sewer Drop', + 'Graveyard Cave': 'Graveyard Cave', + 'Kings Grave': 'Kings Grave', + 'North Fairy Cave Drop': 'North Fairy Cave', + 'North Fairy Cave': 'North Fairy Cave', + 'North Fairy Cave Exit': 'Light World', + 'Potion Shop': 'Potion Shop', + 'Kakariko Well Drop': 'Kakariko Well (top)', + 'Kakariko Well Cave': 'Kakariko Well (bottom)', + 'Kakariko Well Exit': 'Light World', + 'Blinds Hideout': 'Blinds Hideout', + 'Elder House (East)': 'Elder House', + 'Elder House (West)': 'Elder House', + 'Elder House Exit (East)': 'Light World', + 'Elder House Exit (West)': 'Light World', + 'Snitch Lady (West)': 'Snitch Lady (West)', + 'Snitch Lady (East)': 'Snitch Lady (East)', + 'Bush Covered House': 'Bush Covered House', + 'Chicken House': 'Chicken House', + 'Sick Kids House': 'Sick Kids House', + 'Light World Bomb Hut': 'Light World Bomb Hut', + 'Kakariko Shop': 'Kakariko Shop', + 'Tavern North': 'Tavern', + 'Tavern (Front)': 'Tavern (Front)', + 'Hyrule Castle Secret Entrance Drop': 'Hyrule Castle Secret Entrance', + 'Hyrule Castle Secret Entrance Stairs': 'Hyrule Castle Secret Entrance', + 'Hyrule Castle Secret Entrance Exit': 'Hyrule Castle Secret Entrance Area', + 'Sahasrahlas Hut': 'Sahasrahlas Hut', + 'Blacksmiths Hut': 'Blacksmiths Hut', + 'Bat Cave Drop': 'Bat Cave (right)', + 'Bat Cave Cave': 'Bat Cave (left)', + 'Bat Cave Exit': 'Light World', + 'Two Brothers House (West)': 'Two Brothers House', + 'Two Brothers House Exit (West)': 'Maze Race Ledge', + 'Two Brothers House (East)': 'Two Brothers House', + 'Two Brothers House Exit (East)': 'Light World', + 'Library': 'Library', + 'Kakariko Gamble Game': 'Kakariko Gamble Game', + 'Bonk Fairy (Light)': 'Bonk Fairy (Light)', + 'Lake Hylia Fairy': 'Lake Hylia Healer Fairy', + 'Long Fairy Cave': 'Long Fairy Cave', + 'Checkerboard Cave': 'Checkerboard Cave', + 'Aginahs Cave': 'Aginahs Cave', + 'Cave 45': 'Cave 45', + 'Light Hype Fairy': 'Light Hype Fairy', + 'Lake Hylia Fortune Teller': 'Lake Hylia Fortune Teller', + 'Lake Hylia Shop': 'Lake Hylia Shop', + 'Capacity Upgrade': 'Capacity Upgrade', + 'Mini Moldorm Cave': 'Mini Moldorm Cave', + 'Ice Rod Cave': 'Ice Rod Cave', + 'Good Bee Cave': 'Good Bee Cave', + '20 Rupee Cave': '20 Rupee Cave', + 'Desert Fairy': 'Desert Healer Fairy', + '50 Rupee Cave': '50 Rupee Cave', + 'Dam': 'Dam', + + 'Dark Lumberjack Shop': 'Dark Lumberjack Shop', 'Spike Cave': 'Spike Cave', + 'Hookshot Cave Back Exit': 'Dark Death Mountain Floating Island', + 'Hookshot Cave Back Entrance': 'Hookshot Cave (Back)', 'Hookshot Cave': 'Hookshot Cave (Front)', 'Hookshot Cave Front Exit': 'Dark Death Mountain (Top)', 'Superbunny Cave (Top)': 'Superbunny Cave (Top)', 'Superbunny Cave Exit (Top)': 'Dark Death Mountain (Top)', - 'Cave Shop (Dark Death Mountain)': 'Cave Shop (Dark Death Mountain)', 'Superbunny Cave (Bottom)': 'Superbunny Cave (Bottom)', - 'Superbunny Cave Exit (Bottom)': 'Dark Death Mountain (East Bottom)', - 'Hookshot Cave Back Exit': 'Death Mountain Floating Island (Dark World)', - 'Hookshot Cave Back Entrance': 'Hookshot Cave (Back)', - 'Mimic Cave': 'Mimic Cave' + 'Superbunny Cave Exit (Bottom)': 'East Dark Death Mountain (Bottom)', + 'Dark Death Mountain Shop': 'Dark Death Mountain Shop', + 'Fortune Teller (Dark)': 'Fortune Teller (Dark)', + 'Dark Sanctuary Hint': 'Dark Sanctuary Hint', + 'Dark Potion Shop': 'Dark Potion Shop', + 'Chest Game': 'Chest Game', + 'C-Shaped House': 'C-Shaped House', + 'Brewery': 'Brewery', + 'Dark World Shop': 'Village of Outcasts Shop', + 'Hammer Peg Cave': 'Hammer Peg Cave', + 'Red Shield Shop': 'Red Shield Shop', + 'Pyramid Fairy': 'Pyramid Fairy', + 'Palace of Darkness Hint': 'Palace of Darkness Hint', + 'Archery Game': 'Archery Game', + 'Bonk Fairy (Dark)': 'Bonk Fairy (Dark)', + 'Dark Lake Hylia Fairy': 'Dark Lake Hylia Healer Fairy', + 'East Dark World Hint': 'East Dark World Hint', + 'Mire Shed': 'Mire Shed', + 'Dark Desert Fairy': 'Dark Desert Healer Fairy', + 'Dark Desert Hint': 'Dark Desert Hint', + 'Hype Cave': 'Hype Cave', + 'Dark Lake Hylia Shop': 'Dark Lake Hylia Shop', + 'Dark Lake Hylia Ledge Fairy': 'Dark Lake Hylia Ledge Healer Fairy', + 'Dark Lake Hylia Ledge Hint': 'Dark Lake Hylia Ledge Hint', + 'Dark Lake Hylia Ledge Spike Cave': 'Dark Lake Hylia Ledge Spike Cave' } open_default_connections = {'Links House': 'Links House', 'Links House Exit': 'Light World', + 'Big Bomb Shop': 'Big Bomb Shop', 'Old Man Cave (West)': 'Old Man Cave Ledge', 'Old Man Cave (East)': 'Old Man Cave', 'Old Man Cave Exit (West)': 'Light World', - 'Old Man Cave Exit (East)': 'Death Mountain (West Bottom)', + 'Old Man Cave Exit (East)': 'West Death Mountain (Bottom)', 'Death Mountain Return Cave (West)': 'Death Mountain Return Cave (left)', 'Death Mountain Return Cave Exit (West)': 'Death Mountain Return Ledge', - 'Big Bomb Shop': 'Big Bomb Shop', 'Bumper Cave (Bottom)': 'Bumper Cave (bottom)', 'Bumper Cave (Top)': 'Bumper Cave (top)', 'Bumper Cave Exit (Top)': 'Bumper Cave Ledge', 'Bumper Cave Exit (Bottom)': 'West Dark World', 'Dark Death Mountain Fairy': 'Dark Death Mountain Healer Fairy', 'Pyramid Hole': 'Pyramid', - 'Pyramid Exit': 'Pyramid Ledge', - 'Pyramid Entrance': 'Bottom of Pyramid' + 'Pyramid Entrance': 'Bottom of Pyramid', + 'Pyramid Exit': 'Pyramid Exit Ledge' } inverted_default_connections = {'Links House': 'Big Bomb Shop', 'Links House Exit': 'South Dark World', + 'Big Bomb Shop': 'Links House', + 'Dark Sanctuary Hint Exit': 'West Dark World', 'Old Man Cave (West)': 'Bumper Cave (bottom)', 'Old Man Cave (East)': 'Death Mountain Return Cave (left)', 'Old Man Cave Exit (West)': 'West Dark World', - 'Old Man Cave Exit (East)': 'Dark Death Mountain (West Bottom)', + 'Old Man Cave Exit (East)': 'West Dark Death Mountain (Bottom)', 'Death Mountain Return Cave (West)': 'Bumper Cave (top)', - 'Death Mountain Return Cave Exit (West)': 'Death Mountain (West Bottom)', - 'Big Bomb Shop': 'Links House', + 'Death Mountain Return Cave Exit (West)': 'West Death Mountain (Bottom)', 'Bumper Cave (Bottom)': 'Old Man Cave Ledge', 'Bumper Cave (Top)': 'Dark Death Mountain Healer Fairy', 'Bumper Cave Exit (Top)': 'Death Mountain Return Ledge', 'Bumper Cave Exit (Bottom)': 'Light World', 'Dark Death Mountain Fairy': 'Old Man Cave', - 'Dark Sanctuary Hint Exit': 'West Dark World', 'Inverted Pyramid Hole': 'Pyramid', - 'Pyramid Exit': 'Hyrule Castle Courtyard', - 'Inverted Pyramid Entrance': 'Bottom of Pyramid' + 'Inverted Pyramid Entrance': 'Bottom of Pyramid', + 'Pyramid Exit': 'Hyrule Castle Courtyard' } # non shuffled dungeons -default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert South Portal'), - ('Desert Palace Entrance (West)', 'Desert West Portal'), - ('Desert Palace Entrance (North)', 'Desert Back Portal'), - ('Desert Palace Entrance (East)', 'Desert East Portal'), - ('Desert Palace Exit (South)', 'Desert Palace Stairs'), - ('Desert Palace Exit (West)', 'Desert Ledge'), - ('Desert Palace Exit (East)', 'Desert Palace Lone Stairs'), - ('Desert Palace Exit (North)', 'Desert Palace Entrance (North) Spot'), - ('Eastern Palace', 'Eastern Portal'), - ('Eastern Palace Exit', 'Light World'), - ('Tower of Hera', 'Hera Portal'), - ('Tower of Hera Exit', 'Death Mountain (Top)'), - - ('Hyrule Castle Entrance (South)', 'Hyrule Castle South Portal'), +default_dungeon_connections = [('Hyrule Castle Entrance (South)', 'Hyrule Castle South Portal'), ('Hyrule Castle Entrance (West)', 'Hyrule Castle West Portal'), ('Hyrule Castle Entrance (East)', 'Hyrule Castle East Portal'), ('Hyrule Castle Exit (South)', 'Hyrule Castle Courtyard'), ('Hyrule Castle Exit (West)', 'Hyrule Castle Ledge'), ('Hyrule Castle Exit (East)', 'Hyrule Castle Ledge'), - - ('Thieves Town', 'Thieves Town Portal'), - ('Thieves Town Exit', 'West Dark World'), + ('Desert Palace Entrance (South)', 'Desert South Portal'), + ('Desert Palace Entrance (West)', 'Desert West Portal'), + ('Desert Palace Entrance (North)', 'Desert Back Portal'), + ('Desert Palace Entrance (East)', 'Desert East Portal'), + ('Desert Palace Exit (South)', 'Desert Palace Stairs'), + ('Desert Palace Exit (West)', 'Desert Ledge'), + ('Desert Palace Exit (East)', 'Desert Palace Mouth'), + ('Desert Palace Exit (North)', 'Desert Palace Entrance (North) Spot'), + ('Eastern Palace', 'Eastern Portal'), + ('Eastern Palace Exit', 'Light World'), + ('Tower of Hera', 'Hera Portal'), + ('Tower of Hera Exit', 'West Death Mountain (Top)'), + + ('Palace of Darkness', 'Palace of Darkness Portal'), + ('Palace of Darkness Exit', 'East Dark World'), + ('Swamp Palace', 'Swamp Portal'), # requires additional patch for flooding moat if moved + ('Swamp Palace Exit', 'South Dark World'), ('Skull Woods First Section Hole (East)', 'Skull Pinball'), ('Skull Woods First Section Hole (West)', 'Skull Left Drop'), ('Skull Woods First Section Hole (North)', 'Skull Pot Circle'), @@ -2304,35 +2336,30 @@ default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert South ('Skull Woods Second Section Exit (West)', 'Skull Woods Forest (West)'), ('Skull Woods Final Section', 'Skull 3 Portal'), ('Skull Woods Final Section Exit', 'Skull Woods Forest (West)'), + ('Thieves Town', 'Thieves Town Portal'), + ('Thieves Town Exit', 'West Dark World'), ('Ice Palace', 'Ice Portal'), + ('Ice Palace Exit', 'Dark Lake Hylia Central Island'), ('Misery Mire', 'Mire Portal'), ('Misery Mire Exit', 'Dark Desert'), - ('Palace of Darkness', 'Palace of Darkness Portal'), - ('Palace of Darkness Exit', 'East Dark World'), - ('Swamp Palace', 'Swamp Portal'), # requires additional patch for flooding moat if moved - ('Swamp Palace Exit', 'South Dark World'), - ('Turtle Rock', 'Turtle Rock Main Portal'), - ('Turtle Rock Ledge Exit (West)', 'Dark Death Mountain Ledge'), - ('Turtle Rock Ledge Exit (East)', 'Dark Death Mountain Ledge'), + ('Turtle Rock Exit (Front)', 'Dark Death Mountain (Top)'), ('Dark Death Mountain Ledge (West)', 'Turtle Rock Lazy Eyes Portal'), ('Dark Death Mountain Ledge (East)', 'Turtle Rock Chest Portal'), - ('Turtle Rock Isolated Ledge Exit', 'Dark Death Mountain Isolated Ledge'), - ('Turtle Rock Isolated Ledge Entrance', 'Turtle Rock Eye Bridge Portal') + ('Turtle Rock Ledge Exit (West)', 'Dark Death Mountain Ledge'), + ('Turtle Rock Ledge Exit (East)', 'Dark Death Mountain Ledge'), + ('Turtle Rock Isolated Ledge Entrance', 'Turtle Rock Eye Bridge Portal'), + ('Turtle Rock Isolated Ledge Exit', 'Dark Death Mountain Isolated Ledge') ] open_default_dungeon_connections = [('Agahnims Tower', 'Agahnims Tower Portal'), ('Agahnims Tower Exit', 'Hyrule Castle Ledge'), - ('Ice Palace Exit', 'Dark Lake Hylia Central Island'), - ('Turtle Rock Exit (Front)', 'Dark Death Mountain (Top)'), ('Ganons Tower', 'Ganons Tower Portal'), ('Ganons Tower Exit', 'Dark Death Mountain (Top)') ] inverted_default_dungeon_connections = [('Agahnims Tower', 'Ganons Tower Portal'), ('Agahnims Tower Exit', 'Dark Death Mountain'), - ('Ice Palace Exit', 'Dark Lake Hylia Water'), - ('Turtle Rock Exit (Front)', 'Dark Death Mountain'), ('Ganons Tower', 'Agahnims Tower Portal'), ('Ganons Tower Exit', 'Hyrule Castle Ledge') ] @@ -2433,7 +2460,7 @@ door_addresses = {'Links House': (0x00, (0x0104, 0x2c, 0x0506, 0x0a9a, 0x0832, 0 'Chicken House': (0x4A, (0x0108, 0x18, 0x1120, 0x0837, 0x0106, 0x0888, 0x0188, 0x08a4, 0x0193, 0x07, 0xf9, 0x1530, 0x0000)), 'Aginahs Cave': (0x70, (0x010a, 0x30, 0x0656, 0x0cc6, 0x02aa, 0x0d18, 0x0328, 0x0d33, 0x032f, 0x08, 0xf8, 0x0000, 0x0000)), 'Sahasrahlas Hut': (0x44, (0x0105, 0x1e, 0x0610, 0x06d4, 0x0c76, 0x0727, 0x0cf0, 0x0743, 0x0cfb, 0x0a, 0xf6, 0x0000, 0x0000)), - 'Cave Shop (Lake Hylia)': (0x57, (0x0112, 0x35, 0x0022, 0x0c00, 0x0b1a, 0x0c26, 0x0b98, 0x0c6d, 0x0b9f, 0x00, 0x00, 0x0000, 0x0000)), + 'Lake Hylia Shop': (0x57, (0x0112, 0x35, 0x0022, 0x0c00, 0x0b1a, 0x0c26, 0x0b98, 0x0c6d, 0x0b9f, 0x00, 0x00, 0x0000, 0x0000)), 'Capacity Upgrade': (0x5C, (0x0115, 0x35, 0x0a46, 0x0d36, 0x0c2a, 0x0d88, 0x0ca8, 0x0da3, 0x0caf, 0x0a, 0xf6, 0x0000, 0x0000)), 'Kakariko Well Drop': ([0xDB85C, 0xDB85D], None), 'Blacksmiths Hut': (0x63, (0x0121, 0x22, 0x010c, 0x081a, 0x0466, 0x0868, 0x04d8, 0x0887, 0x04e3, 0x06, 0xfa, 0x041A, 0x0000)), @@ -2476,19 +2503,19 @@ door_addresses = {'Links House': (0x00, (0x0104, 0x2c, 0x0506, 0x0a9a, 0x0832, 0 'Brewery': (0x47, (0x0106, 0x58, 0x16a8, 0x08e4, 0x013e, 0x0938, 0x01b8, 0x0953, 0x01c3, 0x0a, 0xf6, 0x1AB6, 0x0000)), 'C-Shaped House': (0x53, (0x011c, 0x58, 0x09d8, 0x0744, 0x02ce, 0x0797, 0x0348, 0x07b3, 0x0353, 0x0a, 0xf6, 0x0DE8, 0x0000)), 'Chest Game': (0x46, (0x0106, 0x58, 0x078a, 0x0705, 0x004e, 0x0758, 0x00c8, 0x0774, 0x00d3, 0x09, 0xf7, 0x0B98, 0x0000)), - 'Dark World Hammer Peg Cave': (0x7E, (0x0127, 0x62, 0x0894, 0x091e, 0x0492, 0x09a6, 0x0508, 0x098b, 0x050f, 0x00, 0x00, 0x0000, 0x0000)), + 'Hammer Peg Cave': (0x7E, (0x0127, 0x62, 0x0894, 0x091e, 0x0492, 0x09a6, 0x0508, 0x098b, 0x050f, 0x00, 0x00, 0x0000, 0x0000)), 'Red Shield Shop': (0x74, (0x0110, 0x5a, 0x079a, 0x06e8, 0x04d6, 0x0738, 0x0548, 0x0755, 0x0553, 0x08, 0xf8, 0x0AA8, 0x0000)), 'Dark Sanctuary Hint': (0x59, (0x0112, 0x53, 0x001e, 0x0400, 0x06e2, 0x0446, 0x0758, 0x046d, 0x075f, 0x00, 0x00, 0x0000, 0x0000)), 'Fortune Teller (Dark)': (0x65, (0x0122, 0x51, 0x0610, 0x04b4, 0x027e, 0x0507, 0x02f8, 0x0523, 0x0303, 0x0a, 0xf6, 0x091E, 0x0000)), 'Dark World Shop': (0x5F, (0x010f, 0x58, 0x1058, 0x0814, 0x02be, 0x0868, 0x0338, 0x0883, 0x0343, 0x0a, 0xf6, 0x0000, 0x0000)), - 'Dark World Lumberjack Shop': (0x56, (0x010f, 0x42, 0x041c, 0x0074, 0x04e2, 0x00c7, 0x0558, 0x00e3, 0x055f, 0x0a, 0xf6, 0x0000, 0x0000)), - 'Dark World Potion Shop': (0x6E, (0x010f, 0x56, 0x080e, 0x04f4, 0x0c66, 0x0548, 0x0cd8, 0x0563, 0x0ce3, 0x0a, 0xf6, 0x0000, 0x0000)), + 'Dark Lumberjack Shop': (0x56, (0x010f, 0x42, 0x041c, 0x0074, 0x04e2, 0x00c7, 0x0558, 0x00e3, 0x055f, 0x0a, 0xf6, 0x0000, 0x0000)), + 'Dark Potion Shop': (0x6E, (0x010f, 0x56, 0x080e, 0x04f4, 0x0c66, 0x0548, 0x0cd8, 0x0563, 0x0ce3, 0x0a, 0xf6, 0x0000, 0x0000)), 'Archery Game': (0x58, (0x0111, 0x69, 0x069e, 0x0ac4, 0x02ea, 0x0b18, 0x0368, 0x0b33, 0x036f, 0x0a, 0xf6, 0x09AC, 0x0000)), 'Mire Shed': (0x5E, (0x010d, 0x70, 0x0384, 0x0c69, 0x001e, 0x0cb6, 0x0098, 0x0cd6, 0x00a3, 0x07, 0xf9, 0x0000, 0x0000)), 'Dark Desert Hint': (0x61, (0x0114, 0x70, 0x0654, 0x0cc5, 0x02aa, 0x0d16, 0x0328, 0x0d32, 0x032f, 0x09, 0xf7, 0x0000, 0x0000)), 'Dark Desert Fairy': (0x55, (0x0115, 0x70, 0x03a8, 0x0c6a, 0x013a, 0x0cb7, 0x01b8, 0x0cd7, 0x01bf, 0x06, 0xfa, 0x0000, 0x0000)), 'Spike Cave': (0x40, (0x0117, 0x43, 0x0ed4, 0x01e4, 0x08aa, 0x0236, 0x0928, 0x0253, 0x092f, 0x0a, 0xf6, 0x0000, 0x0000)), - 'Cave Shop (Dark Death Mountain)': (0x6D, (0x0112, 0x45, 0x0ee0, 0x01e3, 0x0d00, 0x0236, 0x0daa, 0x0252, 0x0d7d, 0x0b, 0xf5, 0x0000, 0x0000)), + 'Dark Death Mountain Shop': (0x6D, (0x0112, 0x45, 0x0ee0, 0x01e3, 0x0d00, 0x0236, 0x0daa, 0x0252, 0x0d7d, 0x0b, 0xf5, 0x0000, 0x0000)), 'Dark Death Mountain Fairy': (0x6F, (0x0115, 0x43, 0x1400, 0x0294, 0x0600, 0x02e8, 0x0678, 0x0303, 0x0685, 0x0a, 0xf6, 0x0000, 0x0000)), 'Mimic Cave': (0x4E, (0x010c, 0x05, 0x07e0, 0x0103, 0x0d00, 0x0156, 0x0d78, 0x0172, 0x0d7d, 0x0b, 0xf5, 0x0000, 0x0000)), 'Big Bomb Shop': (0x52, (0x011c, 0x6c, 0x0506, 0x0a9a, 0x0832, 0x0ae7, 0x08b8, 0x0b07, 0x08bf, 0x06, 0xfa, 0x0816, 0x0000)), @@ -2568,7 +2595,7 @@ exit_ids = {'Links House Exit': (0x01, 0x00), 'Bonk Fairy (Light)': 0x71, 'Bonk Fairy (Dark)': 0x71, 'Lake Hylia Healer Fairy': 0x5E, - 'Swamp Healer Fairy': 0x5E, + 'Light Hype Fairy': 0x5E, 'Desert Healer Fairy': 0x5E, 'Dark Lake Hylia Healer Fairy': 0x5E, 'Dark Lake Hylia Ledge Healer Fairy': 0x5E, @@ -2581,8 +2608,8 @@ exit_ids = {'Links House Exit': (0x01, 0x00), 'Chicken House': 0x4B, 'Aginahs Cave': 0x4D, 'Sahasrahlas Hut': 0x45, - 'Cave Shop (Lake Hylia)': 0x58, - 'Cave Shop (Dark Death Mountain)': 0x58, + 'Lake Hylia Shop': 0x58, + 'Dark Death Mountain Shop': 0x58, 'Capacity Upgrade': 0x5D, 'Blacksmiths Hut': 0x64, 'Sick Kids House': 0x40, @@ -2613,15 +2640,15 @@ exit_ids = {'Links House Exit': (0x01, 0x00), 'Big Bomb Shop': 0x53, 'Village of Outcasts Shop': 0x60, 'Dark Lake Hylia Shop': 0x60, - 'Dark World Lumberjack Shop': 0x60, - 'Dark World Potion Shop': 0x60, + 'Dark Lumberjack Shop': 0x60, + 'Dark Potion Shop': 0x60, 'Dark Lake Hylia Ledge Spike Cave': 0x70, 'Dark Lake Hylia Ledge Hint': 0x6A, 'Hype Cave': 0x3D, 'Brewery': 0x48, 'C-Shaped House': 0x54, 'Chest Game': 0x47, - 'Dark World Hammer Peg Cave': 0x83, + 'Hammer Peg Cave': 0x83, 'Red Shield Shop': 0x57, 'Dark Sanctuary Hint': 0x5A, 'Fortune Teller (Dark)': 0x66, @@ -2714,7 +2741,7 @@ ow_prize_table = {'Links House': (0x8b1, 0xb2d), 'Chicken House': (0x120, 0x880), 'Aginahs Cave': (0x2e0, 0xd00), 'Sahasrahlas Hut': (0xcf0, 0x6c0), - 'Cave Shop (Lake Hylia)': (0xbc0, 0xc00), + 'Lake Hylia Shop': (0xbc0, 0xc00), 'Capacity Upgrade': (0xca0, 0xda0), 'Kakariko Well Drop': None, 'Blacksmiths Hut': (0x4a0, 0x880), @@ -2754,19 +2781,19 @@ ow_prize_table = {'Links House': (0x8b1, 0xb2d), 'Hype Cave': (0x940, 0xc80), 'Bonk Fairy (Dark)': (0x740, 0xa80), 'Brewery': (0x170, 0x980), 'C-Shaped House': (0x310, 0x7a0), 'Chest Game': (0x800, 0x7a0), - 'Dark World Hammer Peg Cave': (0x4c0, 0x940), + 'Hammer Peg Cave': (0x4c0, 0x940), 'Red Shield Shop': (0x500, 0x680), 'Dark Sanctuary Hint': (0x720, 0x4a0), 'Fortune Teller (Dark)': (0x2c0, 0x4c0), 'Dark World Shop': (0x2e0, 0x880), - 'Dark World Lumberjack Shop': (0x4e0, 0x0d0), - 'Dark World Potion Shop': (0xc80, 0x4c0), + 'Dark Lumberjack Shop': (0x4e0, 0x0d0), + 'Dark Potion Shop': (0xc80, 0x4c0), 'Archery Game': (0x2f0, 0xaf0), 'Mire Shed': (0x060, 0xc90), 'Dark Desert Hint': (0x2e0, 0xd00), 'Dark Desert Fairy': (0x1c0, 0xc90), 'Spike Cave': (0x860, 0x180), - 'Cave Shop (Dark Death Mountain)': (0xd80, 0x180), + 'Dark Death Mountain Shop': (0xd80, 0x180), 'Dark Death Mountain Fairy': (0x620, 0x2c0), 'Mimic Cave': (0xc80, 0x180), 'Big Bomb Shop': (0x8b1, 0xb2d), From 86c8fd37e7bffdbdbf0b8e0813deb97c0b27f73b Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 14 Dec 2022 05:36:36 -0600 Subject: [PATCH 006/196] Reorganized and renamed regions, rules, and lists --- EntranceShuffle.py | 2 +- Regions.py | 169 ++++++++++++++------------- source/overworld/EntranceShuffle2.py | 2 +- 3 files changed, 91 insertions(+), 82 deletions(-) diff --git a/EntranceShuffle.py b/EntranceShuffle.py index a5dda17a..a89dbc12 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -2128,7 +2128,7 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('East Dark World Pier', 'East Dark World'), ('Southeast Dark World Pier', 'Southeast Dark World'), - ('Northeast Dark World River Pier', 'Northeast Dark World'), + ('Northeast Dark World Pier', 'Northeast Dark World'), # terrain ('Master Sword Meadow', 'Master Sword Meadow'), diff --git a/Regions.py b/Regions.py index 52cc2e0c..0c0e73a8 100644 --- a/Regions.py +++ b/Regions.py @@ -7,56 +7,67 @@ from PotShuffle import key_drop_data, vanilla_pots, choose_pots, PotSecretTable def create_regions(world, player): world.regions += [ create_menu_region(player, 'Menu', None, ['Links House S&Q', 'Sanctuary S&Q', 'Old Man S&Q', 'Other World S&Q']), - create_menu_region(player, 'Flute Sky', None, ['Flute Spot 1', 'Flute Spot 2', 'Flute Spot 3', 'Flute Spot 4', 'Flute Spot 5', 'Flute Spot 6', 'Flute Spot 7', 'Flute Spot 8']), + create_menu_region(player, 'Flute Sky', None, ['Flute Spot 1', 'Flute Spot 2', 'Flute Spot 3', 'Flute Spot 4', + 'Flute Spot 5', 'Flute Spot 6', 'Flute Spot 7', 'Flute Spot 8']), create_lw_region(player, 'Light World', ['Mushroom', 'Bottle Merchant', 'Flute Spot', 'Sunken Treasure', 'Purple Chest'], - ['Blinds Hideout', 'Hyrule Castle Secret Entrance Drop', 'Kings Grave Rocks (Outer)', 'Dam', - 'Links House', 'Tavern North', 'Chicken House', 'Aginahs Cave', 'Sahasrahlas Hut', 'Kakariko Well Drop', 'Kakariko Well Cave', - 'Blacksmiths Hut', 'Bat Cave Ledge Peg', 'Bat Cave Cave', 'Sick Kids House', 'Lost Woods Hideout Drop', 'Lost Woods Hideout Stump', - 'Lumberjack Tree Tree', 'Lumberjack Tree Cave', 'Mini Moldorm Cave', 'Ice Rod Cave', - 'Bonk Rock Cave', 'Library', 'Two Brothers House (East)', 'Desert Statue Move', 'Eastern Palace', 'Master Sword Meadow', - 'Sanctuary', 'Sanctuary Grave', 'Death Mountain Entrance Rock', 'Light World Water Drop', 'LW Flute', 'East Hyrule Teleporter', 'South Hyrule Teleporter', 'Kakariko Teleporter', - 'Elder House (East)', 'Elder House (West)', 'North Fairy Cave', 'North Fairy Cave Drop', 'Lost Woods Gamble', 'Snitch Lady (East)', 'Snitch Lady (West)', 'Tavern (Front)', - 'Kakariko Shop', 'Long Fairy Cave', 'Good Bee Cave', '20 Rupee Cave', 'Lake Hylia Shop', 'Hyrule Castle Main Gate', - 'Bonk Fairy (Light)', '50 Rupee Cave', 'Fortune Teller (Light)', 'Lake Hylia Fairy', 'Light Hype Fairy', 'Desert Fairy', 'Lumberjack House', 'Lake Hylia Fortune Teller', 'Kakariko Gamble Game', 'Castle Gate Teleporter', - 'East Dark World Mirror Spot', 'West Dark World Mirror Spot', 'South Dark World Mirror Spot', 'Cave 45 Approach', 'Checkerboard Ledge Approach', 'Mire Mirror Spot', 'Hammer Peg Area Mirror Spot', - 'Shopping Mall Mirror Spot', 'Skull Woods Mirror Spot', 'Kakariko Yard Bush (South)', 'Bombos Tablet Ladder (Bottom)', - 'Wooden Bridge Bush (South)', 'Graveyard Ladder (Bottom)', 'Kakariko Southwest Bush (North)']), - create_lw_region(player, 'West Death Mountain (Top)', ['Ether Tablet'], ['DM Hammer Bridge (West)', 'Tower of Hera', 'Death Mountain Drop', 'Spectacle Rock Approach', 'Death Mountain (Top) Mirror Spot']), - create_lw_region(player, 'West Death Mountain (Bottom)', None, ['Old Man Cave (East)', 'Old Man House (Bottom)', 'Old Man House (Top)', 'Death Mountain Return Cave (East)', 'Spectacle Rock Cave', - 'Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Bottom)', 'DM Broken Bridge (West)', 'Death Mountain Mirror Spot', 'DM Flute', 'Death Mountain Teleporter']), + ['Lost Woods Hideout Drop', 'Lost Woods Hideout Stump', 'Lost Woods Gamble', 'Lumberjack Tree Tree', 'Lumberjack Tree Cave', 'Lumberjack House', + 'Fortune Teller (Light)', 'Bonk Rock Cave', 'Sanctuary', 'Sanctuary Grave', 'North Fairy Cave', 'North Fairy Cave Drop', + 'Kakariko Well Drop', 'Kakariko Well Cave', 'Blinds Hideout', 'Elder House (West)', 'Elder House (East)', + 'Snitch Lady (West)', 'Snitch Lady (East)', 'Chicken House', 'Sick Kids House', 'Kakariko Shop', 'Tavern North', 'Tavern (Front)', + 'Hyrule Castle Secret Entrance Drop', 'Sahasrahlas Hut', 'Eastern Palace', 'Blacksmiths Hut', 'Bat Cave Cave', + 'Library', 'Two Brothers House (East)', 'Kakariko Gamble Game', 'Bonk Fairy (Light)', 'Links House', 'Lake Hylia Fairy', 'Long Fairy Cave', + 'Aginahs Cave', 'Light Hype Fairy', 'Lake Hylia Fortune Teller', 'Lake Hylia Shop', 'Mini Moldorm Cave', + 'Ice Rod Cave', 'Good Bee Cave', '20 Rupee Cave', 'Desert Fairy', '50 Rupee Cave', 'Dam', + + 'Master Sword Meadow', 'Death Mountain Entrance Rock', 'Graveyard Ladder (Bottom)', 'Kings Grave Rocks (Outer)', + 'Wooden Bridge Bush (South)', 'Kakariko Southwest Bush (North)', 'Kakariko Yard Bush (South)', 'Hyrule Castle Main Gate', 'Bat Cave Ledge Peg', + 'Light World Water Drop', 'Desert Statue Move', 'Checkerboard Ledge Approach', 'Cave 45 Approach', 'Bombos Tablet Ladder (Bottom)', + + 'Kakariko Teleporter', 'Castle Gate Teleporter', 'East Hyrule Teleporter', 'South Hyrule Teleporter', + + 'LW Flute', 'Skull Woods Mirror Spot', 'West Dark World Mirror Spot', 'Hammer Peg Area Mirror Spot', + 'East Dark World Mirror Spot', 'South Dark World Mirror Spot', 'Mire Mirror Spot', 'Shopping Mall Mirror Spot']), + create_lw_region(player, 'West Death Mountain (Top)', ['Ether Tablet'], ['Tower of Hera', 'Death Mountain Drop', 'Spectacle Rock Approach', + 'DM Hammer Bridge (West)', 'Death Mountain (Top) Mirror Spot']), + create_lw_region(player, 'West Death Mountain (Bottom)', None, ['Old Man Cave (East)', 'Old Man House (Bottom)', 'Old Man House (Top)', + 'Death Mountain Return Cave (East)', 'Spectacle Rock Cave', 'Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Bottom)', + 'DM Broken Bridge (West)',, 'Death Mountain Teleporter' 'DM Flute', 'Death Mountain Mirror Spot']), create_lw_region(player, 'Spectacle Rock', ['Spectacle Rock'], ['Spectacle Rock Drop', 'Spectacle Rock Leave']), - create_lw_region(player, 'East Death Mountain (Top)', None, ['Paradox Cave (Top)', 'DM Hammer Bridge (East)', 'Floating Island Bridge (East)', 'Spiral Cave Ledge Access', 'East Death Mountain Drop', 'Turtle Rock Teleporter', 'East Death Mountain Mirror Spot (Top)', 'Fairy Ascension Ledge Access', 'Mimic Cave Ledge Access']), + create_lw_region(player, 'East Death Mountain (Top)', None, ['Paradox Cave (Top)', 'DM Hammer Bridge (East)', 'Floating Island Bridge (East)', + 'Spiral Cave Ledge Access', 'Fairy Ascension Ledge Access', 'Mimic Cave Ledge Access', 'East Death Mountain Drop', + 'Turtle Rock Teleporter', 'East Death Mountain Mirror Spot (Top)']), create_lw_region(player, 'Death Mountain Floating Island', ['Floating Island'], ['Floating Island Bridge (West)', 'Floating Island Mirror Spot']), create_lw_region(player, 'Spiral Cave Ledge', None, ['Spiral Cave', 'Spiral Cave Ledge Drop', 'Dark Death Mountain Ledge Mirror Spot (West)']), create_lw_region(player, 'Mimic Cave Ledge', None, ['Mimic Cave', 'Mimic Cave Ledge Drop', 'Dark Death Mountain Ledge Mirror Spot (East)']), - create_lw_region(player, 'Fairy Ascension Ledge', None, ['Fairy Ascension Ledge Drop', 'Fairy Ascension Cave (Top)', 'Laser Bridge Mirror Spot']), - create_lw_region(player, 'East Death Mountain (Bottom)', None, ['DM Broken Bridge (East)', 'Paradox Cave (Bottom)', 'Paradox Cave (Middle)', 'East Death Mountain Mirror Spot (Bottom)', 'East Death Mountain Teleporter', 'Hookshot Fairy', - 'Fairy Ascension Rocks', 'Spiral Cave (Bottom)', 'EDM Flute']), - create_lw_region(player, 'Fairy Ascension Plateau', None, ['Fairy Ascension Drop', 'Fairy Ascension Cave (Bottom)']), - create_lw_region(player, 'Death Mountain Return Ledge', None, ['Death Mountain Return Ledge Drop', 'Death Mountain Return Cave (West)', 'Mountain Exit Ledge Mirror Spot'], 'a ledge in the foothills'), + create_lw_region(player, 'Fairy Ascension Ledge', None, ['Fairy Ascension Cave (Top)', 'Fairy Ascension Ledge Drop', 'Laser Bridge Mirror Spot']), + create_lw_region(player, 'East Death Mountain (Bottom)', None, ['Spiral Cave (Bottom)', 'Hookshot Fairy', 'Paradox Cave (Bottom)', 'Paradox Cave (Middle)', + 'DM Broken Bridge (East)', 'Fairy Ascension Rocks', 'East Death Mountain Teleporter', 'EDM Flute', 'East Death Mountain Mirror Spot (Bottom)']), + create_lw_region(player, 'Fairy Ascension Plateau', None, ['Fairy Ascension Cave (Bottom)', 'Fairy Ascension Drop']), + create_lw_region(player, 'Death Mountain Return Ledge', None, ['Death Mountain Return Cave (West)', 'Death Mountain Return Ledge Drop', 'Mountain Exit Ledge Mirror Spot'], 'a ledge in the foothills'), create_lw_region(player, 'Death Mountain Entrance', None, ['Old Man Cave (West)', 'Death Mountain Entrance Drop', 'Mountain Entrance Mirror Spot']), - create_lw_region(player, 'Northeast Light World', None, ['Zoras Domain', 'Potion Shop Rock (North)', 'Catfish Mirror Spot', 'Northeast Light World Water Drop']), - create_lw_region(player, 'Zora Waterfall Entryway', None, ['Waterfall of Wishing', 'ZLW Flute', 'Zora Waterfall Water Drop']), + create_lw_region(player, 'Northeast Light World', None, ['Zoras Domain', 'Potion Shop Rock (North)', 'Northeast Light World Water Drop', 'Catfish Mirror Spot']), + create_lw_region(player, 'Zora Waterfall Entryway', None, ['Waterfall of Wishing', 'Zora Waterfall Water Drop', 'ZLW Flute']), create_lw_region(player, 'Graveyard Ledge', None, ['Graveyard Cave', 'Graveyard Ledge Drop', 'Graveyard Ladder (Top)', 'Graveyard Cave Mirror Spot']), create_lw_region(player, 'Kings Grave Area', None, ['Kings Grave', 'Kings Grave Rocks (Inner)']), - create_lw_region(player, 'Potion Shop Area', None, ['Potion Shop', 'Wooden Bridge Bush (North)', 'Potion Shop Rock (South)', 'NWLW Flute', 'Potion Shop Mirror Spot', 'Potion Shop Water Drop']), + create_lw_region(player, 'Potion Shop Area', None, ['Potion Shop', 'Wooden Bridge Bush (North)', 'Potion Shop Rock (South)', 'Potion Shop Water Drop', 'NWLW Flute', 'Potion Shop Mirror Spot']), create_lw_region(player, 'Bush Covered Lawn', None, ['Bush Covered House', 'Kakariko Yard Bush (North)', 'Bush Covered Lawn Mirror Spot']), create_lw_region(player, 'Bomb Hut Area', None, ['Light World Bomb Hut', 'Kakariko Southwest Bush (South)', 'Bomb Hut Mirror Spot']), create_lw_region(player, 'Hyrule Castle Courtyard', None, ['Hyrule Castle Entrance (South)', 'Inverted Pyramid Entrance', 'Hyrule Castle Courtyard Bush (South)', 'Hyrule Castle Main Gate (North)']), create_lw_region(player, 'Hyrule Castle Secret Entrance Area', None, ['Hyrule Castle Secret Entrance Stairs', 'Hyrule Castle Courtyard Bush (North)', 'Pyramid Uncle Mirror Spot']), - create_lw_region(player, 'Hyrule Castle Ledge', None, ['Hyrule Castle Entrance (East)', 'Hyrule Castle Entrance (West)', 'Agahnims Tower', 'Hyrule Castle Ledge Courtyard Drop', 'Hyrule Castle Ledge Drop', 'Inverted Pyramid Hole'], 'the castle rampart'), + create_lw_region(player, 'Hyrule Castle Ledge', None, ['Hyrule Castle Entrance (West)', 'Agahnims Tower', 'Hyrule Castle Entrance (East)', 'Inverted Pyramid Hole', + 'Hyrule Castle Ledge Courtyard Drop', 'Hyrule Castle Ledge Drop'], 'the castle rampart'), create_lw_region(player, 'Bat Cave Ledge', None, ['Bat Cave Drop', 'Bat Cave Ledge Peg (East)']), - create_lw_region(player, 'Maze Race Ledge', ['Maze Race'], ['Two Brothers House (West)', 'Maze Race Mirror Spot', 'Maze Race Ledge Drop'], 'a race against time'), + create_lw_region(player, 'Maze Race Ledge', ['Maze Race'], ['Two Brothers House (West)', 'Maze Race Ledge Drop', 'Maze Race Mirror Spot'], 'a race against time'), create_lw_region(player, 'Desert Palace Stairs', None, ['Desert Palace Entrance (South)', 'Desert Palace Stairs Mirror Spot']), - create_lw_region(player, 'Desert Palace Mouth', None, ['Desert Palace Mouth Drop', 'Desert Palace Entrance (East)'], 'a sandy vista'), - create_lw_region(player, 'Desert Ledge', ['Desert Ledge'], ['Desert Ledge Rocks (Outer)', 'Desert Palace Entrance (West)', 'Desert Ledge Drop'], 'the desert ledge'), + create_lw_region(player, 'Desert Palace Mouth', None, ['Desert Palace Entrance (East)', 'Desert Palace Mouth Drop'], 'a sandy vista'), + create_lw_region(player, 'Desert Ledge', ['Desert Ledge'], ['Desert Palace Entrance (West)', 'Desert Ledge Rocks (Outer)', 'Desert Ledge Drop'], 'the desert ledge'), create_lw_region(player, 'Desert Palace Entrance (North) Spot', None, ['Desert Palace Entrance (North)', 'Desert Ledge Rocks (Inner)', 'Desert Palace North Mirror Spot'], 'the desert ledge'), create_lw_region(player, 'Desert Checkerboard Ledge', None, ['Checkerboard Cave', 'Checkerboard Ledge Drop', 'Checkerboard Ledge Leave']), create_lw_region(player, 'Desert Teleporter Ledge', None, ['Desert Teleporter Drop', 'Desert Teleporter']), create_lw_region(player, 'Bombos Tablet Ledge', ['Bombos Tablet'], ['Bombos Tablet Ladder (Top)']), create_lw_region(player, 'Desert Northern Cliffs'), create_lw_region(player, 'Cave 45 Ledge', None, ['Cave 45', 'Cave 45 Ledge Drop', 'Cave 45 Leave']), - create_lw_region(player, 'Lake Hylia Water', None, ['Hobo Pier', 'Light World Pier', 'Potion Shop Pier', 'Lake Hylia Central Island Pier', 'Lake Hylia Island Pier', 'Lake Hylia Whirlpool', 'Waterfall Fairy Access']), + create_lw_region(player, 'Lake Hylia Water', None, ['Light World Pier', 'Potion Shop Pier', 'Hobo Pier', 'Lake Hylia Island Pier', 'Lake Hylia Central Island Pier', 'Lake Hylia Whirlpool', 'Waterfall Fairy Access']), create_lw_region(player, 'Lake Hylia Island', ['Lake Hylia Island']), create_lw_region(player, 'Lake Hylia Central Island', None, ['Capacity Upgrade', 'Lake Hylia Central Island Water Drop', 'Lake Hylia Teleporter']), create_lw_region(player, 'Master Sword Meadow', ['Master Sword Pedestal']), @@ -86,14 +97,10 @@ def create_regions(world, player): create_cave_region(player, 'Fairy Ascension Cave (Top)', 'a connector', None, ['Fairy Ascension Cave Exit (Top)', 'Fairy Ascension Cave Drop']), create_cave_region(player, 'Hookshot Fairy', 'fairies deep in a cave'), create_cave_region(player, 'Paradox Cave Front', 'a connector', None, ['Paradox Cave Push Block Reverse', 'Paradox Cave Exit (Bottom)', 'Paradox Shop']), - create_cave_region(player, 'Paradox Cave Chest Area', 'a connector', ['Paradox Cave Lower - Far Left', - 'Paradox Cave Lower - Left', - 'Paradox Cave Lower - Right', - 'Paradox Cave Lower - Far Right', - 'Paradox Cave Lower - Middle'], - ['Paradox Cave Push Block', 'Paradox Cave Bomb Jump', 'Paradox Cave Chest Area NE']), - create_cave_region(player, 'Paradox Cave Bomb Area', 'a connector', ['Paradox Cave Upper - Left', - 'Paradox Cave Upper - Right']), + create_cave_region(player, 'Paradox Cave Chest Area', 'a connector', ['Paradox Cave Lower - Far Left', 'Paradox Cave Lower - Left', + 'Paradox Cave Lower - Right', 'Paradox Cave Lower - Far Right', 'Paradox Cave Lower - Middle'], + ['Paradox Cave Push Block', 'Paradox Cave Bomb Jump', 'Paradox Cave Chest Area NE']), + create_cave_region(player, 'Paradox Cave Bomb Area', 'a connector', ['Paradox Cave Upper - Left', 'Paradox Cave Upper - Right']), create_cave_region(player, 'Paradox Cave', 'a connector', None, ['Paradox Cave Exit (Middle)', 'Paradox Cave Exit (Top)', 'Paradox Cave Drop']), create_cave_region(player, 'Paradox Shop', 'a common shop', ['Paradox Shop - Left', 'Paradox Shop - Middle', 'Paradox Shop - Right']), create_cave_region(player, 'Waterfall of Wishing', 'a cave with two chests', ['Waterfall Fairy - Left', 'Waterfall Fairy - Right']), @@ -104,18 +111,12 @@ def create_regions(world, player): create_cave_region(player, 'Kings Grave', 'a cave with a chest', ['King\'s Tomb']), create_cave_region(player, 'North Fairy Cave', 'a drop\'s exit', None, ['North Fairy Cave Exit']), create_cave_region(player, 'Potion Shop', 'the potion shop', ['Potion Shop', 'Potion Shop - Left', 'Potion Shop - Middle', 'Potion Shop - Right']), - create_cave_region(player, 'Kakariko Well (top)', 'a drop', - ['Kakariko Well - Left', 'Kakariko Well - Middle', 'Kakariko Well - Right', - 'Kakariko Well - Bottom'], - ['Kakariko Well (top to bottom)', 'Kakariko Well (top to back)']), + create_cave_region(player, 'Kakariko Well (top)', 'a drop', ['Kakariko Well - Left', 'Kakariko Well - Middle', 'Kakariko Well - Right', 'Kakariko Well - Bottom'], + ['Kakariko Well (top to bottom)', 'Kakariko Well (top to back)']), create_cave_region(player, 'Kakariko Well (back)', 'a drop', ['Kakariko Well - Top']), create_cave_region(player, 'Kakariko Well (bottom)', 'a drop\'s exit', None, ['Kakariko Well Exit']), - create_cave_region(player, 'Blinds Hideout', 'a bounty of five items', [ - "Blind's Hideout - Left", - "Blind's Hideout - Right", - "Blind's Hideout - Far Left", - "Blind's Hideout - Far Right"], - ['Blinds Hideout N']), + create_cave_region(player, 'Blinds Hideout', 'a bounty of five items', [ "Blind's Hideout - Left", "Blind's Hideout - Right", + "Blind's Hideout - Far Left", "Blind's Hideout - Far Right"], ['Blinds Hideout N']), create_cave_region(player, 'Blinds Hideout (Top)', 'a bounty of five items', ["Blind's Hideout - Top"]), create_cave_region(player, 'Elder House', 'a connector', None, ['Elder House Exit (East)', 'Elder House Exit (West)']), create_cave_region(player, 'Snitch Lady (East)', 'a boring house'), @@ -147,8 +148,8 @@ def create_regions(world, player): create_cave_region(player, 'Lake Hylia Fortune Teller', 'a fortune teller'), create_cave_region(player, 'Lake Hylia Shop', 'a common shop', ['Lake Hylia Shop - Left', 'Lake Hylia Shop - Middle', 'Lake Hylia Shop - Right']), create_cave_region(player, 'Capacity Upgrade', 'the queen of fairies', ['Capacity Upgrade - Left', 'Capacity Upgrade - Right']), - create_cave_region(player, 'Mini Moldorm Cave', 'a bounty of five items', ['Mini Moldorm Cave - Far Left', 'Mini Moldorm Cave - Left', 'Mini Moldorm Cave - Right', - 'Mini Moldorm Cave - Far Right', 'Mini Moldorm Cave - Generous Guy']), + create_cave_region(player, 'Mini Moldorm Cave', 'a bounty of five items', ['Mini Moldorm Cave - Far Left', 'Mini Moldorm Cave - Left', + 'Mini Moldorm Cave - Right', 'Mini Moldorm Cave - Far Right', 'Mini Moldorm Cave - Generous Guy']), create_cave_region(player, 'Ice Rod Cave', 'a cave with a chest', ['Ice Rod Cave']), create_cave_region(player, 'Good Bee Cave', 'a cold bee'), create_cave_region(player, '20 Rupee Cave', 'a cave with some cash'), @@ -156,44 +157,52 @@ def create_regions(world, player): create_cave_region(player, '50 Rupee Cave', 'a cave with some cash'), create_cave_region(player, 'Dam', 'the dam', ['Floodgate', 'Floodgate Chest']), - create_dw_region(player, 'West Dark Death Mountain (Bottom)', None, ['Spike Cave', 'Spectacle Rock Mirror Spot', 'Dark Death Mountain Fairy', 'Dark Death Mountain Ladder (Bottom)', 'Dark Death Mountain Teleporter (West)', 'DDM Flute']), - create_dw_region(player, 'Dark Death Mountain (Top)', None, ['Dark Death Mountain Drop (East)', 'Dark Death Mountain Drop (West)', 'Ganons Tower', 'Superbunny Cave (Top)', - 'Hookshot Cave', 'East Death Mountain (Top) Mirror Spot', 'Dark Death Mountain Ladder (Top)', 'Turtle Rock Tail Drop', 'Turtle Rock']), - create_dw_region(player, 'Dark Death Mountain Floating Island', None, ['Floating Island Drop', 'Hookshot Cave Back Entrance', 'Dark Floating Island Mirror Spot'], 'a dark island'), - create_dw_region(player, 'Dark Death Mountain Ledge', None, ['Dark Death Mountain Ledge (East)', 'Dark Death Mountain Ledge (West)', 'Mimic Cave Mirror Spot', 'Spiral Cave Mirror Spot'], 'a dark ledge'), - create_dw_region(player, 'Dark Death Mountain Isolated Ledge', None, ['Isolated Ledge Mirror Spot', 'Turtle Rock Isolated Ledge Entrance'], 'a dark vista'), - create_dw_region(player, 'East Dark Death Mountain (Bottom)', None, ['Superbunny Cave (Bottom)', 'Dark Death Mountain Shop', 'Fairy Ascension Mirror Spot', 'East Dark Death Mountain Teleporter (Bottom)', 'EDDM Flute']), - create_dw_region(player, 'Turtle Rock (Top)', None, ['East Dark Death Mountain Teleporter (Top)', 'Turtle Rock Drop']), - create_dw_region(player, 'West Dark World', ['Frog'], ['Village of Outcasts Drop', 'West Dark World Water Drop', 'Brewery', 'C-Shaped House', 'Chest Game', 'Thieves Town', 'Graveyard Ledge Mirror Spot', 'Kings Grave Mirror Spot', 'Bumper Cave Entrance Rock', - 'Skull Woods Forest', 'Grassy Lawn Pegs (Bottom)', 'Peg Area Rocks (Left)', 'Red Shield Shop', 'Dark Sanctuary Hint', 'Fortune Teller (Dark)', 'Dark Lumberjack Shop', - 'West Dark World Teleporter', 'WDW Flute']), + create_dw_region(player, 'West Dark Death Mountain (Bottom)', None, ['Spike Cave', 'Dark Death Mountain Fairy', 'Dark Death Mountain Ladder (Bottom)', + 'Dark Death Mountain Teleporter (West)', 'DDM Flute', 'Spectacle Rock Mirror Spot']), + create_dw_region(player, 'Dark Death Mountain (Top)', None, ['Ganons Tower', 'Hookshot Cave', 'Superbunny Cave (Top)', 'Turtle Rock', 'Dark Death Mountain Drop (West)', + 'Dark Death Mountain Drop (East)', 'Dark Death Mountain Ladder (Top)', 'Turtle Rock Tail Drop', 'East Death Mountain (Top) Mirror Spot']), + create_dw_region(player, 'Dark Death Mountain Floating Island', None, ['Hookshot Cave Back Entrance', 'Floating Island Drop', 'Dark Floating Island Mirror Spot'], 'a dark island'), + create_dw_region(player, 'Dark Death Mountain Ledge', None, ['Dark Death Mountain Ledge (West)', 'Dark Death Mountain Ledge (East)', 'Mimic Cave Mirror Spot', 'Spiral Cave Mirror Spot'], 'a dark ledge'), + create_dw_region(player, 'Dark Death Mountain Isolated Ledge', None, ['Turtle Rock Isolated Ledge Entrance', 'Isolated Ledge Mirror Spot'], 'a dark vista'), + create_dw_region(player, 'East Dark Death Mountain (Bottom)', None, ['Superbunny Cave (Bottom)', 'Dark Death Mountain Shop', + 'East Dark Death Mountain Teleporter (Bottom)', 'EDDM Flute', 'Fairy Ascension Mirror Spot']), + create_dw_region(player, 'Turtle Rock (Top)', None, ['Turtle Rock Drop', 'East Dark Death Mountain Teleporter (Top)']), + create_dw_region(player, 'West Dark World', ['Frog'], ['Dark Lumberjack Shop', 'Dark Sanctuary Hint', 'Fortune Teller (Dark)', 'Chest Game', 'Thieves Town', + 'C-Shaped House', 'Brewery', 'Red Shield Shop', 'Skull Woods Forest', 'Bumper Cave Entrance Rock', + 'West Dark World Water Drop', 'Grassy Lawn Pegs (Bottom)', 'Peg Area Rocks (Left)', 'Village of Outcasts Drop', + 'West Dark World Teleporter', 'WDW Flute', 'Graveyard Ledge Mirror Spot', 'Kings Grave Mirror Spot']), create_dw_region(player, 'Skull Woods Forest', None, ['Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', - 'Skull Woods First Section Door', 'Skull Woods Second Section Door (East)']), + 'Skull Woods First Section Door', 'Skull Woods Second Section Door (East)']), create_dw_region(player, 'Skull Woods Forest (West)', None, ['Skull Woods Second Section Hole', 'Skull Woods Second Section Door (West)', 'Skull Woods Final Section'], 'a deep, dark forest'), - create_dw_region(player, 'Bumper Cave Ledge', ['Bumper Cave Ledge'], ['Bumper Cave Ledge Drop', 'Bumper Cave (Top)', 'Bumper Cave Ledge Mirror Spot'], 'a ledge with an item'), - create_dw_region(player, 'Bumper Cave Entrance', None, ['Bumper Cave (Bottom)', 'Bumper Cave Entrance Mirror Spot', 'Bumper Cave Entrance Drop']), - create_dw_region(player, 'Dark Grassy Lawn', None, ['Grassy Lawn Pegs (Top)', 'Dark World Shop', 'Dark Grassy Lawn Mirror Spot', 'Dark Grassy Lawn Flute']), - create_dw_region(player, 'Hammer Peg Area', ['Dark Blacksmith Ruins'], ['Bat Cave Drop Ledge Mirror Spot', 'Hammer Peg Cave', 'Peg Area Rocks (Right)', 'Hammer Peg Area Flute']), - create_dw_region(player, 'Northeast Dark World', None, ['West Dark World Gap', 'Dark Potion Shop', 'Broken Bridge Pass (Top)', 'Northeast Dark World Water Drop', 'Dark Witch Rock (South)', 'NEDW Flute']), + create_dw_region(player, 'Bumper Cave Ledge', ['Bumper Cave Ledge'], ['Bumper Cave (Top)', 'Bumper Cave Ledge Drop', 'Bumper Cave Ledge Mirror Spot'], 'a ledge with an item'), + create_dw_region(player, 'Bumper Cave Entrance', None, ['Bumper Cave (Bottom)', 'Bumper Cave Entrance Drop', 'Bumper Cave Entrance Mirror Spot']), + create_dw_region(player, 'Dark Grassy Lawn', None, ['Dark World Shop', 'Grassy Lawn Pegs (Top)', 'Dark Grassy Lawn Flute', 'Dark Grassy Lawn Mirror Spot']), + create_dw_region(player, 'Hammer Peg Area', ['Dark Blacksmith Ruins'], ['Hammer Peg Cave', 'Peg Area Rocks (Right)', 'Hammer Peg Area Flute', 'Bat Cave Drop Ledge Mirror Spot']), + create_dw_region(player, 'Northeast Dark World', None, ['Dark Potion Shop', 'Northeast Dark World Water Drop', 'Dark Witch Rock (South)', 'West Dark World Gap', + 'Broken Bridge Pass (Top)', 'NEDW Flute']), create_dw_region(player, 'Catfish Area', ['Catfish'], ['Dark Witch Rock (North)', 'Catfish Water Drop']), - create_dw_region(player, 'East Dark World', ['Pyramid'], ['Pyramid Fairy', 'Hammer Bridge Pegs (North)', 'Palace of Darkness', 'East Dark World Water Drop', - 'Hyrule Castle Ledge Mirror Spot', 'Dark Lake Hylia Fairy', 'Palace of Darkness Hint', 'East Dark World Hint', 'Pyramid Hole', 'Broken Bridge Pass (Bottom)', 'East Dark World Teleporter', 'EDW Flute']), + create_dw_region(player, 'East Dark World', ['Pyramid'], ['Pyramid Hole', 'Pyramid Fairy', 'Palace of Darkness Hint', 'Palace of Darkness', 'Dark Lake Hylia Fairy', + 'East Dark World Hint', 'Broken Bridge Pass (Bottom)', 'East Dark World Water Drop', 'Hammer Bridge Pegs (North)', + 'East Dark World Teleporter', 'EDW Flute', 'Hyrule Castle Ledge Mirror Spot']), create_dw_region(player, 'Pyramid Exit Ledge', None, ['Pyramid Entrance', 'Pyramid Drop']), - create_dw_region(player, 'Dark Desert', None, ['Misery Mire', 'Mire Shed', 'Dark Desert Hint', 'Dark Desert Fairy', 'Checkerboard Ledge Mirror Spot', 'Desert Ledge Mirror Spot', 'Mire To Desert Stairs Mirror Spot', - 'Desert Ledge Rocks Mirror Spot', 'DD Flute']), + create_dw_region(player, 'Dark Desert', None, ['Mire Shed', 'Misery Mire', 'Dark Desert Fairy', 'Dark Desert Hint', 'DD Flute', 'Checkerboard Ledge Mirror Spot', + 'Desert Ledge Mirror Spot', 'Mire To Desert Stairs Mirror Spot', 'Desert Ledge Rocks Mirror Spot']), create_dw_region(player, 'Dark Desert Ledge', None, ['Dark Desert Drop', 'Dark Desert Teleporter']), - create_dw_region(player, 'South Dark World', ['Stumpy', 'Digging Game'], ['Hype Cave', 'Swamp Palace', 'Village of Outcasts Heavy Rock', 'Dig Game Mirror Spot', - 'Cave 45 Mirror Spot', 'Hammer Bridge Pegs (South)', 'Big Bomb Shop', 'Archery Game', 'Bonk Fairy (Dark)', 'Dark Lake Hylia Shop', - 'Bombos Tablet Mirror Spot', 'South Dark World Water Drop', 'South Dark World Teleporter', 'Post Aga Teleporter', 'SDW Flute']), - create_dw_region(player, 'Dark Lake Hylia Water', None, ['Lake Hylia Island Mirror Spot', 'Northeast Dark World River Pier', 'East Dark World Pier', 'Southeast Dark World Pier', 'Ice Palace Approach']), - create_dw_region(player, 'Dark Lake Hylia Central Island', None, ['Ice Palace Leave Water Drop', 'Ice Island To East Pier', 'Ice Palace', 'Lake Hylia Central Island Mirror Spot', 'Dark Lake Hylia Teleporter']), - create_dw_region(player, 'Southeast Dark World', None, ['Southeast Dark World Water Drop', 'Dark Lake Hylia Ledge Fairy', 'Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Ledge Spike Cave', 'DLHL Flute']), + create_dw_region(player, 'South Dark World', ['Stumpy', 'Digging Game'], ['Archery Game', 'Bonk Fairy (Dark)', 'Big Bomb Shop', 'Hype Cave', 'Dark Lake Hylia Shop', 'Swamp Palace', + 'Village of Outcasts Heavy Rock', 'Hammer Bridge Pegs (South)', 'South Dark World Water Drop', 'Post Aga Teleporter', + 'South Dark World Teleporter', 'SDW Flute',, 'Dig Game Mirror Spot', 'Cave 45 Mirror Spot', 'Bombos Tablet Mirror Spot']), + create_dw_region(player, 'Dark Lake Hylia Water', None, ['Northeast Dark World Pier', 'East Dark World Pier', 'Southeast Dark World Pier', + 'Ice Palace Approach', 'Lake Hylia Island Mirror Spot']), + create_dw_region(player, 'Dark Lake Hylia Central Island', None, ['Ice Palace', 'Ice Palace Leave Water Drop', 'Ice Island To East Pier', + 'Dark Lake Hylia Teleporter', 'Lake Hylia Central Island Mirror Spot']), + create_dw_region(player, 'Southeast Dark World', None, ['Dark Lake Hylia Ledge Fairy', 'Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Ledge Spike Cave', + 'Southeast Dark World Water Drop', 'DLHL Flute']), create_cave_region(player, 'Dark Lumberjack Shop', 'a common shop', ['Dark Lumberjack Shop - Left', 'Dark Lumberjack Shop - Middle', 'Dark Lumberjack Shop - Right']), create_cave_region(player, 'Dark Death Mountain Healer Fairy', 'a fairy fountain'), create_cave_region(player, 'Spike Cave', 'Spike Cave', ['Spike Cave']), - create_cave_region(player, 'Hookshot Cave (Front)', 'a connector', None, - ['Hookshot Cave Front to Middle', 'Hookshot Cave Front Exit', 'Hookshot Cave Bonk Path', 'Hookshot Cave Hook Path']), + create_cave_region(player, 'Hookshot Cave (Front)', 'a connector', None, ['Hookshot Cave Front Exit', 'Hookshot Cave Front to Middle', + 'Hookshot Cave Bonk Path', 'Hookshot Cave Hook Path']), create_cave_region(player, 'Hookshot Cave (Bonk Islands)', 'a connector', ['Hookshot Cave - Bottom Right']), create_cave_region(player, 'Hookshot Cave (Hook Islands)', 'a connector', ['Hookshot Cave - Top Right', 'Hookshot Cave - Top Left', 'Hookshot Cave - Bottom Left']), create_cave_region(player, 'Hookshot Cave (Middle)', 'a connector', None, ['Hookshot Cave Middle to Back', 'Hookshot Cave Middle to Front']), @@ -225,7 +234,7 @@ def create_regions(world, player): create_cave_region(player, 'Dark Desert Healer Fairy', 'a fairy fountain'), create_cave_region(player, 'Dark Desert Hint', 'a storyteller'), create_cave_region(player, 'Hype Cave', 'a bounty of five items', ['Hype Cave - Top', 'Hype Cave - Middle Right', 'Hype Cave - Middle Left', - 'Hype Cave - Bottom', 'Hype Cave - Generous Guy']), + 'Hype Cave - Bottom', 'Hype Cave - Generous Guy']), create_cave_region(player, 'Dark Lake Hylia Shop', 'a common shop', ['Dark Lake Hylia Shop - Left', 'Dark Lake Hylia Shop - Middle', 'Dark Lake Hylia Shop - Right']), create_cave_region(player, 'Dark Lake Hylia Ledge Healer Fairy', 'a fairy fountain'), create_cave_region(player, 'Dark Lake Hylia Ledge Hint', 'a storyteller'), diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index 37a63496..76d8f049 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -1907,7 +1907,7 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('East Dark World Pier', 'East Dark World'), ('Southeast Dark World Pier', 'Southeast Dark World'), - ('Northeast Dark World River Pier', 'Northeast Dark World'), + ('Northeast Dark World Pier', 'Northeast Dark World'), # terrain ('Master Sword Meadow', 'Master Sword Meadow'), From 2d26954422d62e87a1d67cec8fb10e0940b76744 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 15 Dec 2022 17:26:02 -0600 Subject: [PATCH 007/196] Final fixes and reorganization to Inverted Region merging --- DoorShuffle.py | 2 +- EntranceShuffle.py | 68 +++++++++++------------ Regions.py | 14 ++--- Rules.py | 81 ++++++++++++++-------------- source/overworld/EntranceShuffle2.py | 75 +++++++++++++------------- test/stats/EntranceShuffleStats.py | 2 +- 6 files changed, 122 insertions(+), 120 deletions(-) diff --git a/DoorShuffle.py b/DoorShuffle.py index 4bbd53da..bff6da60 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -3229,7 +3229,7 @@ def find_accessible_entrances(world, player, builder): hc_std = True start_regions = ['Hyrule Castle Courtyard'] elif world.mode[player] != 'inverted': - start_regions = ['Links House', 'Sanctuary', 'West Dark World'] + start_regions = ['Links House', 'Sanctuary', 'East Dark World'] else: start_regions = ['Links House', 'Dark Sanctuary Hint', 'Hyrule Castle Ledge'] regs = convert_regions(start_regions, world, player) diff --git a/EntranceShuffle.py b/EntranceShuffle.py index a89dbc12..8a6a1454 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -2104,31 +2104,31 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Ganon Drop', 'Bottom of Pyramid'), # water entry + ('Waterfall Fairy Access', 'Zora Waterfall Entryway'), + ('Zora Waterfall Water Drop', 'Lake Hylia Water'), ('Light World Water Drop', 'Lake Hylia Water'), ('Potion Shop Water Drop', 'Lake Hylia Water'), ('Northeast Light World Water Drop', 'Lake Hylia Water'), ('Lake Hylia Central Island Water Drop', 'Lake Hylia Water'), - ('Zora Waterfall Water Drop', 'Lake Hylia Water'), ('West Dark World Water Drop', 'Dark Lake Hylia Water'), - ('South Dark World Water Drop', 'Dark Lake Hylia Water'), - ('East Dark World Water Drop', 'Dark Lake Hylia Water'), ('Northeast Dark World Water Drop', 'Dark Lake Hylia Water'), - ('Southeast Dark World Water Drop', 'Dark Lake Hylia Water'), ('Catfish Water Drop', 'Dark Lake Hylia Water'), + ('East Dark World Water Drop', 'Dark Lake Hylia Water'), + ('South Dark World Water Drop', 'Dark Lake Hylia Water'), + ('Southeast Dark World Water Drop', 'Dark Lake Hylia Water'), ('Ice Palace Leave Water Drop', 'Dark Lake Hylia Water'), # water exit - ('Lake Hylia Central Island Pier', 'Lake Hylia Central Island'), - ('Hobo Pier', 'Hobo Bridge'), ('Light World Pier', 'Light World'), # there are several piers in-game, only one needs to be modeled ('Potion Shop Pier', 'Potion Shop Area'), + ('Hobo Pier', 'Hobo Bridge'), + ('Lake Hylia Central Island Pier', 'Lake Hylia Central Island'), ('Lake Hylia Whirlpool', 'Northeast Light World'), - ('Waterfall Fairy Access', 'Zora Waterfall Entryway'), + ('Northeast Dark World Pier', 'Northeast Dark World'), ('East Dark World Pier', 'East Dark World'), ('Southeast Dark World Pier', 'Southeast Dark World'), - ('Northeast Dark World Pier', 'Northeast Dark World'), # terrain ('Master Sword Meadow', 'Master Sword Meadow'), @@ -2143,14 +2143,14 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Kings Grave Rocks (Inner)', 'Light World'), ('Potion Shop Rock (South)', 'Northeast Light World'), ('Potion Shop Rock (North)', 'Potion Shop Area'), + ('Kakariko Southwest Bush (North)', 'Bomb Hut Area'), + ('Kakariko Southwest Bush (South)', 'Light World'), ('Kakariko Yard Bush (North)', 'Light World'), ('Kakariko Yard Bush (South)', 'Bush Covered Lawn'), - ('Kakariko Southwest Bush (South)', 'Light World'), - ('Kakariko Southwest Bush (North)', 'Bomb Hut Area'), - ('Hyrule Castle Main Gate', 'Hyrule Castle Courtyard'), - ('Hyrule Castle Main Gate (North)', 'Light World'), ('Hyrule Castle Courtyard Bush (North)', 'Hyrule Castle Courtyard'), ('Hyrule Castle Courtyard Bush (South)', 'Hyrule Castle Secret Entrance Area'), + ('Hyrule Castle Main Gate', 'Hyrule Castle Courtyard'), + ('Hyrule Castle Main Gate (North)', 'Light World'), ('Wooden Bridge Bush (North)', 'Light World'), ('Wooden Bridge Bush (South)', 'Potion Shop Area'), ('Bat Cave Ledge Peg', 'Bat Cave Ledge'), @@ -2163,8 +2163,8 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Bumper Cave Entrance Rock', 'Bumper Cave Entrance'), ('Dark Witch Rock (North)', 'Northeast Dark World'), ('Dark Witch Rock (South)', 'Catfish Area'), - ('Grassy Lawn Pegs (Bottom)', 'Dark Grassy Lawn'), ('Grassy Lawn Pegs (Top)', 'West Dark World'), + ('Grassy Lawn Pegs (Bottom)', 'Dark Grassy Lawn'), ('West Dark World Gap', 'West Dark World'), ('Broken Bridge Pass (Top)', 'East Dark World'), ('Broken Bridge Pass (Bottom)', 'Northeast Dark World'), @@ -2173,6 +2173,7 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Village of Outcasts Heavy Rock', 'West Dark World'), ('Hammer Bridge Pegs (North)', 'South Dark World'), ('Hammer Bridge Pegs (South)', 'East Dark World'), + ('Ice Island To East Pier', 'East Dark World'), # ledge drops ('Spectacle Rock Drop', 'West Death Mountain (Top)'), @@ -2238,14 +2239,15 @@ open_mandatory_connections = [('Sanctuary S&Q', 'Sanctuary'), # mirror ('Spectacle Rock Mirror Spot', 'Spectacle Rock'), - ('Fairy Ascension Mirror Spot', 'Fairy Ascension Plateau'), ('East Death Mountain (Top) Mirror Spot', 'East Death Mountain (Top)'), ('Dark Floating Island Mirror Spot', 'Death Mountain Floating Island'), ('Spiral Cave Mirror Spot', 'Spiral Cave Ledge'), ('Mimic Cave Mirror Spot', 'Mimic Cave Ledge'), ('Isolated Ledge Mirror Spot', 'Fairy Ascension Ledge'), + ('Fairy Ascension Mirror Spot', 'Fairy Ascension Plateau'), ('Bumper Cave Ledge Mirror Spot', 'Death Mountain Return Ledge'), ('Bumper Cave Entrance Mirror Spot', 'Death Mountain Entrance'), + ('Graveyard Ledge Mirror Spot', 'Graveyard Ledge'), ('Kings Grave Mirror Spot', 'Kings Grave Area'), ('Dark Grassy Lawn Mirror Spot', 'Bush Covered Lawn'), ('Hyrule Castle Ledge Mirror Spot', 'Hyrule Castle Ledge'), @@ -2258,8 +2260,7 @@ open_mandatory_connections = [('Sanctuary S&Q', 'Sanctuary'), ('Bombos Tablet Mirror Spot', 'Bombos Tablet Ledge'), ('Cave 45 Mirror Spot', 'Cave 45 Ledge'), ('Lake Hylia Island Mirror Spot', 'Lake Hylia Island'), - ('Lake Hylia Central Island Mirror Spot', 'Lake Hylia Central Island'), - ('Graveyard Ledge Mirror Spot', 'Graveyard Ledge') + ('Lake Hylia Central Island Mirror Spot', 'Lake Hylia Central Island') ] inverted_mandatory_connections = [('Sanctuary S&Q', 'Dark Sanctuary Hint'), @@ -2287,25 +2288,25 @@ inverted_mandatory_connections = [('Sanctuary S&Q', 'Dark Sanctuary Hint'), ('Hammer Peg Area Flute', 'Flute Sky'), # modified terrain - ('Lake Hylia Island Pier', 'Lake Hylia Island'), - ('Spectacle Rock Leave', 'West Death Mountain (Top)'), ('Spectacle Rock Approach', 'Spectacle Rock'), - ('Checkerboard Ledge Approach', 'Desert Checkerboard Ledge'), - ('Checkerboard Ledge Leave', 'Light World'), - ('Cave 45 Approach', 'Cave 45 Ledge'), - ('Cave 45 Leave', 'Light World'), - ('Dark Death Mountain Ladder (Bottom)', 'Dark Death Mountain (Top)'), - ('Dark Death Mountain Ladder (Top)', 'West Dark Death Mountain (Bottom)'), - ('Ice Palace Approach', 'Dark Lake Hylia Central Island'), - ('Floating Island Bridge (East)', 'Death Mountain Floating Island'), + ('Spectacle Rock Leave', 'West Death Mountain (Top)'), ('Floating Island Bridge (West)', 'East Death Mountain (Top)'), + ('Floating Island Bridge (East)', 'Death Mountain Floating Island'), ('Graveyard Ladder (Top)', 'Light World'), ('Graveyard Ladder (Bottom)', 'Graveyard Ledge'), ('Mimic Cave Ledge Access', 'Mimic Cave Ledge'), ('Mimic Cave Ledge Drop', 'East Death Mountain (Bottom)'), - ('Turtle Rock Tail Drop', 'Turtle Rock (Top)'), + ('Checkerboard Ledge Approach', 'Desert Checkerboard Ledge'), + ('Checkerboard Ledge Leave', 'Light World'), + ('Cave 45 Approach', 'Cave 45 Ledge'), + ('Cave 45 Leave', 'Light World'), + ('Lake Hylia Island Pier', 'Lake Hylia Island'), ('Bombos Tablet Ladder (Top)', 'Light World'), ('Bombos Tablet Ladder (Bottom)', 'Bombos Tablet Ledge'), + ('Dark Death Mountain Ladder (Top)', 'West Dark Death Mountain (Bottom)'), + ('Dark Death Mountain Ladder (Bottom)', 'Dark Death Mountain (Top)'), + ('Turtle Rock Tail Drop', 'Turtle Rock (Top)'), + ('Ice Palace Approach', 'Dark Lake Hylia Central Island'), # portals ('Dark Death Mountain Teleporter (West)', 'West Death Mountain (Bottom)'), @@ -2320,8 +2321,9 @@ inverted_mandatory_connections = [('Sanctuary S&Q', 'Dark Sanctuary Hint'), # mirror ('Skull Woods Mirror Spot', 'Skull Woods Forest (West)'), - ('Death Mountain Mirror Spot', 'West Dark Death Mountain (Bottom)'), + ('West Dark World Mirror Spot', 'West Dark World'), ('Death Mountain (Top) Mirror Spot', 'Dark Death Mountain (Top)'), + ('Death Mountain Mirror Spot', 'West Dark Death Mountain (Bottom)'), ('East Death Mountain Mirror Spot (Top)', 'Dark Death Mountain (Top)'), ('Floating Island Mirror Spot', 'Dark Death Mountain Floating Island'), ('Dark Death Mountain Ledge Mirror Spot (East)', 'Dark Death Mountain Ledge'), @@ -2336,15 +2338,15 @@ inverted_mandatory_connections = [('Sanctuary S&Q', 'Dark Sanctuary Hint'), ('Bush Covered Lawn Mirror Spot', 'Dark Grassy Lawn'), ('Bomb Hut Mirror Spot', 'West Dark World'), ('Pyramid Uncle Mirror Spot', 'East Dark World'), + ('East Dark World Mirror Spot', 'East Dark World'), ('Hammer Peg Area Mirror Spot', 'Hammer Peg Area'), ('Maze Race Mirror Spot', 'South Dark World'), ('South Dark World Mirror Spot', 'South Dark World'), ('Mire Mirror Spot', 'Dark Desert'), + ('Dark Desert Ledge Mirror Spot', 'Dark Desert'), ('Desert Palace Stairs Mirror Spot', 'Dark Desert'), ('Desert Palace North Mirror Spot', 'Dark Desert'), - ('Lake Hylia Central Island Mirror Spot', 'Dark Lake Hylia Central Island'), - ('East Dark World Mirror Spot', 'East Dark World'), - ('West Dark World Mirror Spot', 'West Dark World'), + ('Ice Lake Central Island Mirror Spot', 'Lake Hylia Central Island'), ('Shopping Mall Mirror Spot', 'Southeast Dark World') ] @@ -2401,10 +2403,10 @@ default_connections = [('Lost Woods Gamble', 'Lost Woods Gamble'), ('Kakariko Well Cave', 'Kakariko Well (bottom)'), ('Kakariko Well Exit', 'Light World'), ('Blinds Hideout', 'Blinds Hideout'), - ('Elder House (East)', 'Elder House'), ('Elder House (West)', 'Elder House'), - ('Elder House Exit (East)', 'Light World'), + ('Elder House (East)', 'Elder House'), ('Elder House Exit (West)', 'Light World'), + ('Elder House Exit (East)', 'Light World'), ('Snitch Lady (West)', 'Snitch Lady (West)'), ('Snitch Lady (East)', 'Snitch Lady (East)'), ('Bush Covered House', 'Bush Covered House'), diff --git a/Regions.py b/Regions.py index 0c0e73a8..9a57dbc4 100644 --- a/Regions.py +++ b/Regions.py @@ -10,8 +10,8 @@ def create_regions(world, player): create_menu_region(player, 'Flute Sky', None, ['Flute Spot 1', 'Flute Spot 2', 'Flute Spot 3', 'Flute Spot 4', 'Flute Spot 5', 'Flute Spot 6', 'Flute Spot 7', 'Flute Spot 8']), create_lw_region(player, 'Light World', ['Mushroom', 'Bottle Merchant', 'Flute Spot', 'Sunken Treasure', 'Purple Chest'], - ['Lost Woods Hideout Drop', 'Lost Woods Hideout Stump', 'Lost Woods Gamble', 'Lumberjack Tree Tree', 'Lumberjack Tree Cave', 'Lumberjack House', - 'Fortune Teller (Light)', 'Bonk Rock Cave', 'Sanctuary', 'Sanctuary Grave', 'North Fairy Cave', 'North Fairy Cave Drop', + ['Lost Woods Gamble', 'Lost Woods Hideout Drop', 'Lost Woods Hideout Stump', 'Lumberjack Tree Tree', 'Lumberjack Tree Cave', 'Lumberjack House', + 'Fortune Teller (Light)', 'Bonk Rock Cave', 'Sanctuary', 'Sanctuary Grave', 'North Fairy Cave Drop', 'North Fairy Cave', 'Kakariko Well Drop', 'Kakariko Well Cave', 'Blinds Hideout', 'Elder House (West)', 'Elder House (East)', 'Snitch Lady (West)', 'Snitch Lady (East)', 'Chicken House', 'Sick Kids House', 'Kakariko Shop', 'Tavern North', 'Tavern (Front)', 'Hyrule Castle Secret Entrance Drop', 'Sahasrahlas Hut', 'Eastern Palace', 'Blacksmiths Hut', 'Bat Cave Cave', @@ -31,7 +31,7 @@ def create_regions(world, player): 'DM Hammer Bridge (West)', 'Death Mountain (Top) Mirror Spot']), create_lw_region(player, 'West Death Mountain (Bottom)', None, ['Old Man Cave (East)', 'Old Man House (Bottom)', 'Old Man House (Top)', 'Death Mountain Return Cave (East)', 'Spectacle Rock Cave', 'Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Bottom)', - 'DM Broken Bridge (West)',, 'Death Mountain Teleporter' 'DM Flute', 'Death Mountain Mirror Spot']), + 'DM Broken Bridge (West)', 'Death Mountain Teleporter', 'DM Flute', 'Death Mountain Mirror Spot']), create_lw_region(player, 'Spectacle Rock', ['Spectacle Rock'], ['Spectacle Rock Drop', 'Spectacle Rock Leave']), create_lw_region(player, 'East Death Mountain (Top)', None, ['Paradox Cave (Top)', 'DM Hammer Bridge (East)', 'Floating Island Bridge (East)', 'Spiral Cave Ledge Access', 'Fairy Ascension Ledge Access', 'Mimic Cave Ledge Access', 'East Death Mountain Drop', @@ -60,7 +60,7 @@ def create_regions(world, player): create_lw_region(player, 'Maze Race Ledge', ['Maze Race'], ['Two Brothers House (West)', 'Maze Race Ledge Drop', 'Maze Race Mirror Spot'], 'a race against time'), create_lw_region(player, 'Desert Palace Stairs', None, ['Desert Palace Entrance (South)', 'Desert Palace Stairs Mirror Spot']), create_lw_region(player, 'Desert Palace Mouth', None, ['Desert Palace Entrance (East)', 'Desert Palace Mouth Drop'], 'a sandy vista'), - create_lw_region(player, 'Desert Ledge', ['Desert Ledge'], ['Desert Palace Entrance (West)', 'Desert Ledge Rocks (Outer)', 'Desert Ledge Drop'], 'the desert ledge'), + create_lw_region(player, 'Desert Ledge', ['Desert Ledge'], ['Desert Palace Entrance (West)', 'Desert Ledge Rocks (Outer)', 'Desert Ledge Drop', 'Dark Desert Ledge Mirror Spot'], 'the desert ledge'), create_lw_region(player, 'Desert Palace Entrance (North) Spot', None, ['Desert Palace Entrance (North)', 'Desert Ledge Rocks (Inner)', 'Desert Palace North Mirror Spot'], 'the desert ledge'), create_lw_region(player, 'Desert Checkerboard Ledge', None, ['Checkerboard Cave', 'Checkerboard Ledge Drop', 'Checkerboard Ledge Leave']), create_lw_region(player, 'Desert Teleporter Ledge', None, ['Desert Teleporter Drop', 'Desert Teleporter']), @@ -69,7 +69,7 @@ def create_regions(world, player): create_lw_region(player, 'Cave 45 Ledge', None, ['Cave 45', 'Cave 45 Ledge Drop', 'Cave 45 Leave']), create_lw_region(player, 'Lake Hylia Water', None, ['Light World Pier', 'Potion Shop Pier', 'Hobo Pier', 'Lake Hylia Island Pier', 'Lake Hylia Central Island Pier', 'Lake Hylia Whirlpool', 'Waterfall Fairy Access']), create_lw_region(player, 'Lake Hylia Island', ['Lake Hylia Island']), - create_lw_region(player, 'Lake Hylia Central Island', None, ['Capacity Upgrade', 'Lake Hylia Central Island Water Drop', 'Lake Hylia Teleporter']), + create_lw_region(player, 'Lake Hylia Central Island', None, ['Capacity Upgrade', 'Lake Hylia Central Island Water Drop', 'Lake Hylia Teleporter', 'Ice Lake Central Island Mirror Spot']), create_lw_region(player, 'Master Sword Meadow', ['Master Sword Pedestal']), create_lw_region(player, 'Hobo Bridge', ['Hobo']), create_lw_region(player, 'Zoras Domain', ['King Zora', 'Zora\'s Ledge']), @@ -167,7 +167,7 @@ def create_regions(world, player): create_dw_region(player, 'East Dark Death Mountain (Bottom)', None, ['Superbunny Cave (Bottom)', 'Dark Death Mountain Shop', 'East Dark Death Mountain Teleporter (Bottom)', 'EDDM Flute', 'Fairy Ascension Mirror Spot']), create_dw_region(player, 'Turtle Rock (Top)', None, ['Turtle Rock Drop', 'East Dark Death Mountain Teleporter (Top)']), - create_dw_region(player, 'West Dark World', ['Frog'], ['Dark Lumberjack Shop', 'Dark Sanctuary Hint', 'Fortune Teller (Dark)', 'Chest Game', 'Thieves Town', + create_dw_region(player, 'West Dark World', ['Frog'], ['Dark Lumberjack Shop', 'Fortune Teller (Dark)', 'Dark Sanctuary Hint', 'Chest Game', 'Thieves Town', 'C-Shaped House', 'Brewery', 'Red Shield Shop', 'Skull Woods Forest', 'Bumper Cave Entrance Rock', 'West Dark World Water Drop', 'Grassy Lawn Pegs (Bottom)', 'Peg Area Rocks (Left)', 'Village of Outcasts Drop', 'West Dark World Teleporter', 'WDW Flute', 'Graveyard Ledge Mirror Spot', 'Kings Grave Mirror Spot']), @@ -190,7 +190,7 @@ def create_regions(world, player): create_dw_region(player, 'Dark Desert Ledge', None, ['Dark Desert Drop', 'Dark Desert Teleporter']), create_dw_region(player, 'South Dark World', ['Stumpy', 'Digging Game'], ['Archery Game', 'Bonk Fairy (Dark)', 'Big Bomb Shop', 'Hype Cave', 'Dark Lake Hylia Shop', 'Swamp Palace', 'Village of Outcasts Heavy Rock', 'Hammer Bridge Pegs (South)', 'South Dark World Water Drop', 'Post Aga Teleporter', - 'South Dark World Teleporter', 'SDW Flute',, 'Dig Game Mirror Spot', 'Cave 45 Mirror Spot', 'Bombos Tablet Mirror Spot']), + 'South Dark World Teleporter', 'SDW Flute', 'Dig Game Mirror Spot', 'Cave 45 Mirror Spot', 'Bombos Tablet Mirror Spot']), create_dw_region(player, 'Dark Lake Hylia Water', None, ['Northeast Dark World Pier', 'East Dark World Pier', 'Southeast Dark World Pier', 'Ice Palace Approach', 'Lake Hylia Island Mirror Spot']), create_dw_region(player, 'Dark Lake Hylia Central Island', None, ['Ice Palace', 'Ice Palace Leave Water Drop', 'Ice Island To East Pier', diff --git a/Rules.py b/Rules.py index 86897bfa..43013239 100644 --- a/Rules.py +++ b/Rules.py @@ -200,10 +200,6 @@ def global_rules(world, player): (state.can_extend_magic(player, 12, True) or (state.world.can_take_damage and (state.has_Boots(player) or state.has_hearts(player, 4)))))) ) - set_rule(world.get_location('Hookshot Cave - Top Right', player), lambda state: state.has('Hookshot', player)) - set_rule(world.get_location('Hookshot Cave - Top Left', player), lambda state: state.has('Hookshot', player)) - set_rule(world.get_location('Hookshot Cave - Bottom Right', player), lambda state: state.has('Hookshot', player) or state.has('Pegasus Boots', player)) - set_rule(world.get_location('Hookshot Cave - Bottom Left', player), lambda state: state.has('Hookshot', player)) set_rule(world.get_entrance('Hookshot Cave Bonk Path', player), lambda state: state.has('Hookshot', player) or state.has('Pegasus Boots', player)) set_rule(world.get_entrance('Hookshot Cave Hook Path', player), lambda state: state.has('Hookshot', player)) set_rule(world.get_entrance('Bumper Cave Bottom to Top', player), lambda state: state.has('Cape', player)) @@ -215,9 +211,9 @@ def global_rules(world, player): set_rule(world.get_entrance('DM Broken Bridge (West)', player), lambda state: state.has('Hookshot', player)) set_rule(world.get_entrance('DM Broken Bridge (East)', player), lambda state: state.has('Hookshot', player)) set_rule(world.get_entrance('Fairy Ascension Rocks', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Death Mountain Entrance Rock', player), lambda state: state.can_lift_rocks(player)) # can be fake flippered into, but is in weird state inside that might prevent you from doing things. set_rule(world.get_entrance('Waterfall Fairy Access', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Death Mountain Entrance Rock', player), lambda state: state.can_lift_rocks(player)) set_rule(world.get_entrance('Kings Grave Rocks (Outer)', player), lambda state: state.can_lift_heavy_rocks(player)) set_rule(world.get_entrance('Kings Grave Rocks (Inner)', player), lambda state: state.can_lift_heavy_rocks(player)) set_rule(world.get_entrance('Potion Shop Rock (North)', player), lambda state: state.can_lift_rocks(player)) @@ -231,11 +227,11 @@ def global_rules(world, player): set_rule(world.get_entrance('Bumper Cave Entrance Rock', player), lambda state: state.can_lift_rocks(player)) set_rule(world.get_entrance('Dark Witch Rock (North)', player), lambda state: state.can_lift_rocks(player)) set_rule(world.get_entrance('Dark Witch Rock (South)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Grassy Lawn Pegs (Bottom)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Grassy Lawn Pegs (Top)', player), lambda state: state.has('Hammer', player)) set_rule(world.get_entrance('Broken Bridge Pass (Bottom)', player), lambda state: state.can_lift_rocks(player) or state.has('Hammer', player) or state.has('Flippers', player)) set_rule(world.get_entrance('Broken Bridge Pass (Top)', player), lambda state: state.can_lift_rocks(player) or state.has('Hammer', player)) set_rule(world.get_entrance('West Dark World Gap', player), lambda state: state.has('Hookshot', player)) - set_rule(world.get_entrance('Grassy Lawn Pegs (Bottom)', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Grassy Lawn Pegs (Top)', player), lambda state: state.has('Hammer', player)) set_rule(world.get_entrance('Peg Area Rocks (Left)', player), lambda state: state.can_lift_heavy_rocks(player)) set_rule(world.get_entrance('Peg Area Rocks (Right)', player), lambda state: state.can_lift_heavy_rocks(player)) set_rule(world.get_entrance('Village of Outcasts Heavy Rock', player), lambda state: state.can_lift_heavy_rocks(player)) @@ -869,15 +865,15 @@ def ow_inverted_rules(world, player): set_rule(world.get_entrance('Hyrule Castle Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Bat Cave Drop Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Dig Game Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Cave 45 Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Desert Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Mire To Desert Stairs Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Desert Ledge Rocks Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Mire To Desert Stairs Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Checkerboard Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Bombos Tablet Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Cave 45 Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Lake Hylia Island Mirror Spot', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player) and state.has_Mirror(player)) # force flipper rule since fake flipper cannot mirror set_rule(world.get_entrance('Lake Hylia Central Island Mirror Spot', player), lambda state: state.has_Mirror(player)) - + set_rule(world.get_entrance('East Death Mountain Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) set_rule(world.get_entrance('Turtle Rock Teleporter', player), lambda state: state.can_lift_heavy_rocks(player) and state.has('Hammer', player)) set_rule(world.get_entrance('Kakariko Teleporter', player), lambda state: ((state.has('Hammer', player) and state.can_lift_rocks(player)) or state.can_lift_heavy_rocks(player)) and state.has_Pearl(player)) # bunny cannot lift bushes @@ -893,8 +889,9 @@ def ow_inverted_rules(world, player): set_rule(world.get_entrance('Pyramid Hole', player), lambda state: world.open_pyramid[player] or world.goal[player] == 'trinity' or state.has('Beat Agahnim 2', player)) else: set_rule(world.get_entrance('Skull Woods Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Death Mountain Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('West Dark World Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Death Mountain (Top) Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Death Mountain Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('East Death Mountain Mirror Spot (Top)', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Floating Island Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Dark Death Mountain Ledge Mirror Spot (West)', player), lambda state: state.has_Mirror(player)) @@ -903,21 +900,21 @@ def ow_inverted_rules(world, player): set_rule(world.get_entrance('East Death Mountain Mirror Spot (Bottom)', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Mountain Exit Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Mountain Entrance Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Catfish Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Graveyard Cave Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Potion Shop Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Catfish Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('West Dark World Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Bomb Hut Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Bush Covered Lawn Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Hammer Peg Area Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('East Dark World Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Pyramid Uncle Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('South Dark World Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('East Dark World Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Hammer Peg Area Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Maze Race Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('South Dark World Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Mire Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Dark Desert Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Desert Palace North Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Desert Palace Stairs Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Lake Hylia Central Island Mirror Spot', player), lambda state: state.has_Mirror(player)) + set_rule(world.get_entrance('Ice Lake Central Island Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Shopping Mall Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('East Dark Death Mountain Teleporter (Top)', player), lambda state: state.can_lift_heavy_rocks(player) and state.has('Hammer', player) and state.has_Pearl(player)) # bunny cannot use hammer @@ -942,6 +939,31 @@ def ow_bunny_rules(world, player): add_bunny_rule(world.get_location('Maze Race', player), player) add_bunny_rule(world.get_location('Flute Spot', player), player) + # entrances + add_bunny_rule(world.get_entrance('Lost Woods Hideout Drop', player), player) + add_bunny_rule(world.get_entrance('Lumberjack Tree Tree', player), player) + add_bunny_rule(world.get_entrance('Bonk Rock Cave', player), player) + add_bunny_rule(world.get_entrance('Sanctuary Grave', player), player) + add_bunny_rule(world.get_entrance('Kings Grave', player), player) + add_bunny_rule(world.get_entrance('North Fairy Cave Drop', player), player) + add_bunny_rule(world.get_entrance('Hyrule Castle Secret Entrance Drop', player), player) + add_bunny_rule(world.get_entrance('Bonk Fairy (Light)', player), player) + add_bunny_rule(world.get_entrance('Checkerboard Cave', player), player) + add_bunny_rule(world.get_entrance('20 Rupee Cave', player), player) + add_bunny_rule(world.get_entrance('50 Rupee Cave', player), player) + + add_bunny_rule(world.get_entrance('Skull Woods First Section Hole (North)', player), player) # bunny cannot lift bush + add_bunny_rule(world.get_entrance('Skull Woods Second Section Hole', player), player) # bunny cannot lift bush + add_bunny_rule(world.get_entrance('Skull Woods Final Section', player), player) # bunny cannot use fire rod + add_bunny_rule(world.get_entrance('Hookshot Cave', player), player) + add_bunny_rule(world.get_entrance('Thieves Town', player), player) # bunny cannot pull + add_bunny_rule(world.get_entrance('Turtle Rock', player), player) + add_bunny_rule(world.get_entrance('Palace of Darkness', player), player) # kiki needs pearl + add_bunny_rule(world.get_entrance('Hammer Peg Cave', player), player) + add_bunny_rule(world.get_entrance('Bonk Fairy (Dark)', player), player) + add_bunny_rule(world.get_entrance('Misery Mire', player), player) + add_bunny_rule(world.get_entrance('Dark Lake Hylia Ledge Spike Cave', player), player) + # terrain add_bunny_rule(world.get_entrance('DM Hammer Bridge (West)', player), player) add_bunny_rule(world.get_entrance('DM Hammer Bridge (East)', player), player) @@ -983,31 +1005,6 @@ def ow_bunny_rules(world, player): add_bunny_rule(world.get_entrance('Hammer Bridge Pegs (North)', player), player) add_bunny_rule(world.get_entrance('Hammer Bridge Pegs (South)', player), player) - # entrances - add_bunny_rule(world.get_entrance('Lost Woods Hideout Drop', player), player) - add_bunny_rule(world.get_entrance('Lumberjack Tree Tree', player), player) - add_bunny_rule(world.get_entrance('Bonk Rock Cave', player), player) - add_bunny_rule(world.get_entrance('Sanctuary Grave', player), player) - add_bunny_rule(world.get_entrance('Kings Grave', player), player) - add_bunny_rule(world.get_entrance('North Fairy Cave Drop', player), player) - add_bunny_rule(world.get_entrance('Hyrule Castle Secret Entrance Drop', player), player) - add_bunny_rule(world.get_entrance('Bonk Fairy (Light)', player), player) - add_bunny_rule(world.get_entrance('Checkerboard Cave', player), player) - add_bunny_rule(world.get_entrance('20 Rupee Cave', player), player) - add_bunny_rule(world.get_entrance('50 Rupee Cave', player), player) - - add_bunny_rule(world.get_entrance('Skull Woods First Section Hole (North)', player), player) # bunny cannot lift bush - add_bunny_rule(world.get_entrance('Skull Woods Second Section Hole', player), player) # bunny cannot lift bush - add_bunny_rule(world.get_entrance('Skull Woods Final Section', player), player) # bunny cannot use fire rod - add_bunny_rule(world.get_entrance('Hookshot Cave', player), player) - add_bunny_rule(world.get_entrance('Thieves Town', player), player) # bunny cannot pull - add_bunny_rule(world.get_entrance('Turtle Rock', player), player) - add_bunny_rule(world.get_entrance('Palace of Darkness', player), player) # kiki needs pearl - add_bunny_rule(world.get_entrance('Hammer Peg Cave', player), player) - add_bunny_rule(world.get_entrance('Bonk Fairy (Dark)', player), player) - add_bunny_rule(world.get_entrance('Misery Mire', player), player) - add_bunny_rule(world.get_entrance('Dark Lake Hylia Ledge Spike Cave', player), player) - if not world.is_atgt_swapped(player): add_bunny_rule(world.get_entrance('Agahnims Tower', player), player) diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index 76d8f049..a84d1aa4 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -644,7 +644,8 @@ def do_fixed_shuffle(avail, entrance_list): elif rules.fixed: choice = choices[i] elif rules.must_exit_to_lw: - lw_exits = default_lw + ['Big Bomb Shop', 'Ganons Tower Exit'] if avail.inverted else ['Links House Exit', 'Agahnims Tower Exit'] + lw_exits = set(default_lw) + lw_exits.update({'Big Bomb Shop', 'Ganons Tower Exit'} if avail.inverted else {'Links House Exit', 'Agahnims Tower Exit'}) filtered_choices = {i: opt for i, opt in choices.items() if all(t in lw_exits for t in opt[2])} index, choice = random.choice(list(filtered_choices.items())) else: @@ -774,7 +775,7 @@ def do_vanilla_connect(pool_def, avail): elif pool_def['condition'] == 'pottery': # this condition involves whether caves with pots are shuffled or not if avail.world.pottery[avail.player] not in ['none', 'keys', 'dungeon']: return - defaults = default_connections + (inverted_default_connections if avail.inverted else open_default_connections) + defaults = {**default_connections, **(inverted_default_connections if avail.inverted else open_default_connections)} for entrance in pool_def['entrances']: if entrance in avail.entrances: target = defaults[entrance] @@ -1883,31 +1884,31 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Ganon Drop', 'Bottom of Pyramid'), # water entry + ('Waterfall Fairy Access', 'Zora Waterfall Entryway'), + ('Zora Waterfall Water Drop', 'Lake Hylia Water'), ('Light World Water Drop', 'Lake Hylia Water'), ('Potion Shop Water Drop', 'Lake Hylia Water'), ('Northeast Light World Water Drop', 'Lake Hylia Water'), ('Lake Hylia Central Island Water Drop', 'Lake Hylia Water'), - ('Zora Waterfall Water Drop', 'Lake Hylia Water'), ('West Dark World Water Drop', 'Dark Lake Hylia Water'), - ('South Dark World Water Drop', 'Dark Lake Hylia Water'), - ('East Dark World Water Drop', 'Dark Lake Hylia Water'), ('Northeast Dark World Water Drop', 'Dark Lake Hylia Water'), - ('Southeast Dark World Water Drop', 'Dark Lake Hylia Water'), ('Catfish Water Drop', 'Dark Lake Hylia Water'), + ('East Dark World Water Drop', 'Dark Lake Hylia Water'), + ('South Dark World Water Drop', 'Dark Lake Hylia Water'), + ('Southeast Dark World Water Drop', 'Dark Lake Hylia Water'), ('Ice Palace Leave Water Drop', 'Dark Lake Hylia Water'), # water exit - ('Lake Hylia Central Island Pier', 'Lake Hylia Central Island'), - ('Hobo Pier', 'Hobo Bridge'), ('Light World Pier', 'Light World'), # there are several piers in-game, only one needs to be modeled ('Potion Shop Pier', 'Potion Shop Area'), + ('Hobo Pier', 'Hobo Bridge'), + ('Lake Hylia Central Island Pier', 'Lake Hylia Central Island'), ('Lake Hylia Whirlpool', 'Northeast Light World'), - ('Waterfall Fairy Access', 'Zora Waterfall Entryway'), + ('Northeast Dark World Pier', 'Northeast Dark World'), ('East Dark World Pier', 'East Dark World'), ('Southeast Dark World Pier', 'Southeast Dark World'), - ('Northeast Dark World Pier', 'Northeast Dark World'), # terrain ('Master Sword Meadow', 'Master Sword Meadow'), @@ -1922,14 +1923,14 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Kings Grave Rocks (Inner)', 'Light World'), ('Potion Shop Rock (South)', 'Northeast Light World'), ('Potion Shop Rock (North)', 'Potion Shop Area'), + ('Kakariko Southwest Bush (North)', 'Bomb Hut Area'), + ('Kakariko Southwest Bush (South)', 'Light World'), ('Kakariko Yard Bush (North)', 'Light World'), ('Kakariko Yard Bush (South)', 'Bush Covered Lawn'), - ('Kakariko Southwest Bush (South)', 'Light World'), - ('Kakariko Southwest Bush (North)', 'Bomb Hut Area'), - ('Hyrule Castle Main Gate', 'Hyrule Castle Courtyard'), - ('Hyrule Castle Main Gate (North)', 'Light World'), ('Hyrule Castle Courtyard Bush (North)', 'Hyrule Castle Courtyard'), ('Hyrule Castle Courtyard Bush (South)', 'Hyrule Castle Secret Entrance Area'), + ('Hyrule Castle Main Gate', 'Hyrule Castle Courtyard'), + ('Hyrule Castle Main Gate (North)', 'Light World'), ('Wooden Bridge Bush (North)', 'Light World'), ('Wooden Bridge Bush (South)', 'Potion Shop Area'), ('Bat Cave Ledge Peg', 'Bat Cave Ledge'), @@ -1942,8 +1943,8 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Bumper Cave Entrance Rock', 'Bumper Cave Entrance'), ('Dark Witch Rock (North)', 'Northeast Dark World'), ('Dark Witch Rock (South)', 'Catfish Area'), - ('Grassy Lawn Pegs (Bottom)', 'Dark Grassy Lawn'), ('Grassy Lawn Pegs (Top)', 'West Dark World'), + ('Grassy Lawn Pegs (Bottom)', 'Dark Grassy Lawn'), ('West Dark World Gap', 'West Dark World'), ('Broken Bridge Pass (Top)', 'East Dark World'), ('Broken Bridge Pass (Bottom)', 'Northeast Dark World'), @@ -1952,6 +1953,7 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Village of Outcasts Heavy Rock', 'West Dark World'), ('Hammer Bridge Pegs (North)', 'South Dark World'), ('Hammer Bridge Pegs (South)', 'East Dark World'), + ('Ice Island To East Pier', 'East Dark World'), # ledge drops ('Spectacle Rock Drop', 'West Death Mountain (Top)'), @@ -2017,14 +2019,15 @@ open_mandatory_connections = [('Sanctuary S&Q', 'Sanctuary'), # mirror ('Spectacle Rock Mirror Spot', 'Spectacle Rock'), - ('Fairy Ascension Mirror Spot', 'Fairy Ascension Plateau'), ('East Death Mountain (Top) Mirror Spot', 'East Death Mountain (Top)'), ('Dark Floating Island Mirror Spot', 'Death Mountain Floating Island'), ('Spiral Cave Mirror Spot', 'Spiral Cave Ledge'), ('Mimic Cave Mirror Spot', 'Mimic Cave Ledge'), ('Isolated Ledge Mirror Spot', 'Fairy Ascension Ledge'), + ('Fairy Ascension Mirror Spot', 'Fairy Ascension Plateau'), ('Bumper Cave Ledge Mirror Spot', 'Death Mountain Return Ledge'), ('Bumper Cave Entrance Mirror Spot', 'Death Mountain Entrance'), + ('Graveyard Ledge Mirror Spot', 'Graveyard Ledge'), ('Kings Grave Mirror Spot', 'Kings Grave Area'), ('Dark Grassy Lawn Mirror Spot', 'Bush Covered Lawn'), ('Hyrule Castle Ledge Mirror Spot', 'Hyrule Castle Ledge'), @@ -2037,8 +2040,7 @@ open_mandatory_connections = [('Sanctuary S&Q', 'Sanctuary'), ('Bombos Tablet Mirror Spot', 'Bombos Tablet Ledge'), ('Cave 45 Mirror Spot', 'Cave 45 Ledge'), ('Lake Hylia Island Mirror Spot', 'Lake Hylia Island'), - ('Lake Hylia Central Island Mirror Spot', 'Lake Hylia Central Island'), - ('Graveyard Ledge Mirror Spot', 'Graveyard Ledge') + ('Lake Hylia Central Island Mirror Spot', 'Lake Hylia Central Island') ] inverted_mandatory_connections = [('Sanctuary S&Q', 'Dark Sanctuary Hint'), @@ -2066,25 +2068,25 @@ inverted_mandatory_connections = [('Sanctuary S&Q', 'Dark Sanctuary Hint'), ('Hammer Peg Area Flute', 'Flute Sky'), # modified terrain - ('Lake Hylia Island Pier', 'Lake Hylia Island'), - ('Spectacle Rock Leave', 'West Death Mountain (Top)'), ('Spectacle Rock Approach', 'Spectacle Rock'), - ('Checkerboard Ledge Approach', 'Desert Checkerboard Ledge'), - ('Checkerboard Ledge Leave', 'Light World'), - ('Cave 45 Approach', 'Cave 45 Ledge'), - ('Cave 45 Leave', 'Light World'), - ('Dark Death Mountain Ladder (Bottom)', 'Dark Death Mountain (Top)'), - ('Dark Death Mountain Ladder (Top)', 'West Dark Death Mountain (Bottom)'), - ('Ice Palace Approach', 'Dark Lake Hylia Central Island'), - ('Floating Island Bridge (East)', 'Death Mountain Floating Island'), + ('Spectacle Rock Leave', 'West Death Mountain (Top)'), ('Floating Island Bridge (West)', 'East Death Mountain (Top)'), + ('Floating Island Bridge (East)', 'Death Mountain Floating Island'), ('Graveyard Ladder (Top)', 'Light World'), ('Graveyard Ladder (Bottom)', 'Graveyard Ledge'), ('Mimic Cave Ledge Access', 'Mimic Cave Ledge'), ('Mimic Cave Ledge Drop', 'East Death Mountain (Bottom)'), - ('Turtle Rock Tail Drop', 'Turtle Rock (Top)'), + ('Checkerboard Ledge Approach', 'Desert Checkerboard Ledge'), + ('Checkerboard Ledge Leave', 'Light World'), + ('Cave 45 Approach', 'Cave 45 Ledge'), + ('Cave 45 Leave', 'Light World'), + ('Lake Hylia Island Pier', 'Lake Hylia Island'), ('Bombos Tablet Ladder (Top)', 'Light World'), ('Bombos Tablet Ladder (Bottom)', 'Bombos Tablet Ledge'), + ('Dark Death Mountain Ladder (Top)', 'West Dark Death Mountain (Bottom)'), + ('Dark Death Mountain Ladder (Bottom)', 'Dark Death Mountain (Top)'), + ('Turtle Rock Tail Drop', 'Turtle Rock (Top)'), + ('Ice Palace Approach', 'Dark Lake Hylia Central Island'), # portals ('Dark Death Mountain Teleporter (West)', 'West Death Mountain (Bottom)'), @@ -2099,8 +2101,9 @@ inverted_mandatory_connections = [('Sanctuary S&Q', 'Dark Sanctuary Hint'), # mirror ('Skull Woods Mirror Spot', 'Skull Woods Forest (West)'), - ('Death Mountain Mirror Spot', 'West Dark Death Mountain (Bottom)'), + ('West Dark World Mirror Spot', 'West Dark World'), ('Death Mountain (Top) Mirror Spot', 'Dark Death Mountain (Top)'), + ('Death Mountain Mirror Spot', 'West Dark Death Mountain (Bottom)'), ('East Death Mountain Mirror Spot (Top)', 'Dark Death Mountain (Top)'), ('Floating Island Mirror Spot', 'Dark Death Mountain Floating Island'), ('Dark Death Mountain Ledge Mirror Spot (East)', 'Dark Death Mountain Ledge'), @@ -2115,15 +2118,15 @@ inverted_mandatory_connections = [('Sanctuary S&Q', 'Dark Sanctuary Hint'), ('Bush Covered Lawn Mirror Spot', 'Dark Grassy Lawn'), ('Bomb Hut Mirror Spot', 'West Dark World'), ('Pyramid Uncle Mirror Spot', 'East Dark World'), + ('East Dark World Mirror Spot', 'East Dark World'), ('Hammer Peg Area Mirror Spot', 'Hammer Peg Area'), ('Maze Race Mirror Spot', 'South Dark World'), ('South Dark World Mirror Spot', 'South Dark World'), ('Mire Mirror Spot', 'Dark Desert'), + ('Dark Desert Ledge Mirror Spot', 'Dark Desert'), ('Desert Palace Stairs Mirror Spot', 'Dark Desert'), ('Desert Palace North Mirror Spot', 'Dark Desert'), - ('Lake Hylia Central Island Mirror Spot', 'Dark Lake Hylia Central Island'), - ('East Dark World Mirror Spot', 'East Dark World'), - ('West Dark World Mirror Spot', 'West Dark World'), + ('Ice Lake Central Island Mirror Spot', 'Lake Hylia Central Island'), ('Shopping Mall Mirror Spot', 'Southeast Dark World') ] @@ -2180,10 +2183,10 @@ default_connections = {'Lost Woods Gamble': 'Lost Woods Gamble', 'Kakariko Well Cave': 'Kakariko Well (bottom)', 'Kakariko Well Exit': 'Light World', 'Blinds Hideout': 'Blinds Hideout', - 'Elder House (East)': 'Elder House', 'Elder House (West)': 'Elder House', - 'Elder House Exit (East)': 'Light World', + 'Elder House (East)': 'Elder House', 'Elder House Exit (West)': 'Light World', + 'Elder House Exit (East)': 'Light World', 'Snitch Lady (West)': 'Snitch Lady (West)', 'Snitch Lady (East)': 'Snitch Lady (East)', 'Bush Covered House': 'Bush Covered House', @@ -2359,7 +2362,7 @@ open_default_dungeon_connections = [('Agahnims Tower', 'Agahnims Tower Portal'), ] inverted_default_dungeon_connections = [('Agahnims Tower', 'Ganons Tower Portal'), - ('Agahnims Tower Exit', 'Dark Death Mountain'), + ('Agahnims Tower Exit', 'Dark Death Mountain (Top)'), ('Ganons Tower', 'Agahnims Tower Portal'), ('Ganons Tower Exit', 'Hyrule Castle Ledge') ] diff --git a/test/stats/EntranceShuffleStats.py b/test/stats/EntranceShuffleStats.py index 313b060d..41ff6d59 100644 --- a/test/stats/EntranceShuffleStats.py +++ b/test/stats/EntranceShuffleStats.py @@ -99,7 +99,7 @@ def test_loop(tests, entrance_set, exit_set, ctr, shuffle_mode, main_mode, links # seed = 635441530 random.seed(seed) world = World(1, {1: shuffle_mode}, {1: 'vanilla'}, {1: 'noglitches'}, {1: main_mode}, {}, {}, {}, - {}, {}, {}, {}, {}, True, {}, {}, [], {}) + {}, {}, {}, {}, {}, True, {}, [], {}) world.customizer = False world.shufflelinks = {1: links} world.shuffletavern = {1: False} From 6240061a65b03a3b3247327c0acab676ae87bdd7 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Fri, 16 Dec 2022 18:20:14 -0600 Subject: [PATCH 008/196] Final fixes and reorganization to Inverted Region merging --- KeyDoorShuffle.py | 4 ++-- source/overworld/EntranceShuffle2.py | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/KeyDoorShuffle.py b/KeyDoorShuffle.py index 97c3e0c2..92b7282d 100644 --- a/KeyDoorShuffle.py +++ b/KeyDoorShuffle.py @@ -1406,7 +1406,7 @@ def forced_big_key_avail(locations): def prize_relevance(key_layout, dungeon_entrance, is_atgt_swapped): if len(key_layout.start_regions) > 1 and dungeon_entrance and dungeon_table[key_layout.key_logic.dungeon].prize: - if dungeon_entrance.name == 'Agahnims Tower' if is_atgt_swapped else 'Ganons Tower': + if dungeon_entrance.name == ('Agahnims Tower' if is_atgt_swapped else 'Ganons Tower'): return 'GT' elif dungeon_entrance.name == 'Pyramid Fairy': return 'BigBomb' @@ -1415,7 +1415,7 @@ def prize_relevance(key_layout, dungeon_entrance, is_atgt_swapped): def prize_relevance_sig2(start_regions, d_name, dungeon_entrance, is_atgt_swapped): if len(start_regions) > 1 and dungeon_entrance and dungeon_table[d_name].prize: - if dungeon_entrance.name == 'Agahnims Tower' if is_atgt_swapped else 'Ganons Tower': + if dungeon_entrance.name == ('Agahnims Tower' if is_atgt_swapped else 'Ganons Tower'): return 'GT' elif dungeon_entrance.name == 'Pyramid Fairy': return 'BigBomb' diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index c78f85b2..801abc51 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -1572,7 +1572,6 @@ entrance_map = { 'Paradox Cave (Bottom)': 'Paradox Cave Exit (Bottom)', 'Paradox Cave (Middle)': 'Paradox Cave Exit (Middle)', 'Paradox Cave (Top)': 'Paradox Cave Exit (Top)', - 'Inverted Dark Sanctuary': 'Inverted Dark Sanctuary Exit', } From 4c53ef1f7b964da1d74ff3e040681d1ead1f438f Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 29 Dec 2022 22:53:45 -0600 Subject: [PATCH 009/196] Correcting and adding some Inverted Mirror Offset glitches in OWG logic --- OverworldGlitchRules.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OverworldGlitchRules.py b/OverworldGlitchRules.py index ad9203fd..890e8420 100644 --- a/OverworldGlitchRules.py +++ b/OverworldGlitchRules.py @@ -208,7 +208,8 @@ def get_mirror_offset_spots_lw(player): Mirror shenanigans placing a mirror portal with a broken camera """ yield ('Death Mountain Offset Mirror', 'West Death Mountain (Bottom)', 'Light World') - yield ('Death Mountain Offset Mirror (Houlihan Exit)', 'West Death Mountain (Bottom)', 'Hyrule Castle Ledge', lambda state: state.has_Mirror(player) and state.can_boots_clip_dw(player) and state.has_Pearl(player)) + yield ('Death Mountain Uncle Offset Mirror', 'West Death Mountain (Bottom)', 'Hyrule Castle Secret Entrance Area') + yield ('Death Mountain Castle Ledge Offset Mirror', 'West Death Mountain (Bottom)', 'Hyrule Castle Ledge') def create_owg_connections(world, player): From ce93770887862f71767862d960e370a67d118a80 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 29 Dec 2022 23:06:32 -0600 Subject: [PATCH 010/196] Moved DW regions to follow LW regions --- Regions.py | 82 +++++++++++++++++++++++++++--------------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/Regions.py b/Regions.py index 9a57dbc4..84a36844 100644 --- a/Regions.py +++ b/Regions.py @@ -74,6 +74,47 @@ def create_regions(world, player): create_lw_region(player, 'Hobo Bridge', ['Hobo']), create_lw_region(player, 'Zoras Domain', ['King Zora', 'Zora\'s Ledge']), + create_dw_region(player, 'West Dark Death Mountain (Bottom)', None, ['Spike Cave', 'Dark Death Mountain Fairy', 'Dark Death Mountain Ladder (Bottom)', + 'Dark Death Mountain Teleporter (West)', 'DDM Flute', 'Spectacle Rock Mirror Spot']), + create_dw_region(player, 'Dark Death Mountain (Top)', None, ['Ganons Tower', 'Hookshot Cave', 'Superbunny Cave (Top)', 'Turtle Rock', 'Dark Death Mountain Drop (West)', + 'Dark Death Mountain Drop (East)', 'Dark Death Mountain Ladder (Top)', 'Turtle Rock Tail Drop', 'East Death Mountain (Top) Mirror Spot']), + create_dw_region(player, 'Dark Death Mountain Floating Island', None, ['Hookshot Cave Back Entrance', 'Floating Island Drop', 'Dark Floating Island Mirror Spot'], 'a dark island'), + create_dw_region(player, 'Dark Death Mountain Ledge', None, ['Dark Death Mountain Ledge (West)', 'Dark Death Mountain Ledge (East)', 'Mimic Cave Mirror Spot', 'Spiral Cave Mirror Spot'], 'a dark ledge'), + create_dw_region(player, 'Dark Death Mountain Isolated Ledge', None, ['Turtle Rock Isolated Ledge Entrance', 'Isolated Ledge Mirror Spot'], 'a dark vista'), + create_dw_region(player, 'East Dark Death Mountain (Bottom)', None, ['Superbunny Cave (Bottom)', 'Dark Death Mountain Shop', + 'East Dark Death Mountain Teleporter (Bottom)', 'EDDM Flute', 'Fairy Ascension Mirror Spot']), + create_dw_region(player, 'Turtle Rock (Top)', None, ['Turtle Rock Drop', 'East Dark Death Mountain Teleporter (Top)']), + create_dw_region(player, 'West Dark World', ['Frog'], ['Dark Lumberjack Shop', 'Fortune Teller (Dark)', 'Dark Sanctuary Hint', 'Chest Game', 'Thieves Town', + 'C-Shaped House', 'Brewery', 'Red Shield Shop', 'Skull Woods Forest', 'Bumper Cave Entrance Rock', + 'West Dark World Water Drop', 'Grassy Lawn Pegs (Bottom)', 'Peg Area Rocks (Left)', 'Village of Outcasts Drop', + 'West Dark World Teleporter', 'WDW Flute', 'Graveyard Ledge Mirror Spot', 'Kings Grave Mirror Spot']), + create_dw_region(player, 'Skull Woods Forest', None, ['Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', + 'Skull Woods First Section Door', 'Skull Woods Second Section Door (East)']), + create_dw_region(player, 'Skull Woods Forest (West)', None, ['Skull Woods Second Section Hole', 'Skull Woods Second Section Door (West)', 'Skull Woods Final Section'], 'a deep, dark forest'), + create_dw_region(player, 'Bumper Cave Ledge', ['Bumper Cave Ledge'], ['Bumper Cave (Top)', 'Bumper Cave Ledge Drop', 'Bumper Cave Ledge Mirror Spot'], 'a ledge with an item'), + create_dw_region(player, 'Bumper Cave Entrance', None, ['Bumper Cave (Bottom)', 'Bumper Cave Entrance Drop', 'Bumper Cave Entrance Mirror Spot']), + create_dw_region(player, 'Dark Grassy Lawn', None, ['Dark World Shop', 'Grassy Lawn Pegs (Top)', 'Dark Grassy Lawn Flute', 'Dark Grassy Lawn Mirror Spot']), + create_dw_region(player, 'Hammer Peg Area', ['Dark Blacksmith Ruins'], ['Hammer Peg Cave', 'Peg Area Rocks (Right)', 'Hammer Peg Area Flute', 'Bat Cave Drop Ledge Mirror Spot']), + create_dw_region(player, 'Northeast Dark World', None, ['Dark Potion Shop', 'Northeast Dark World Water Drop', 'Dark Witch Rock (South)', 'West Dark World Gap', + 'Broken Bridge Pass (Top)', 'NEDW Flute']), + create_dw_region(player, 'Catfish Area', ['Catfish'], ['Dark Witch Rock (North)', 'Catfish Water Drop']), + create_dw_region(player, 'East Dark World', ['Pyramid'], ['Pyramid Hole', 'Pyramid Fairy', 'Palace of Darkness Hint', 'Palace of Darkness', 'Dark Lake Hylia Fairy', + 'East Dark World Hint', 'Broken Bridge Pass (Bottom)', 'East Dark World Water Drop', 'Hammer Bridge Pegs (North)', + 'East Dark World Teleporter', 'EDW Flute', 'Hyrule Castle Ledge Mirror Spot']), + create_dw_region(player, 'Pyramid Exit Ledge', None, ['Pyramid Entrance', 'Pyramid Drop']), + create_dw_region(player, 'Dark Desert', None, ['Mire Shed', 'Misery Mire', 'Dark Desert Fairy', 'Dark Desert Hint', 'DD Flute', 'Checkerboard Ledge Mirror Spot', + 'Desert Ledge Mirror Spot', 'Mire To Desert Stairs Mirror Spot', 'Desert Ledge Rocks Mirror Spot']), + create_dw_region(player, 'Dark Desert Ledge', None, ['Dark Desert Drop', 'Dark Desert Teleporter']), + create_dw_region(player, 'South Dark World', ['Stumpy', 'Digging Game'], ['Archery Game', 'Bonk Fairy (Dark)', 'Big Bomb Shop', 'Hype Cave', 'Dark Lake Hylia Shop', 'Swamp Palace', + 'Village of Outcasts Heavy Rock', 'Hammer Bridge Pegs (South)', 'South Dark World Water Drop', 'Post Aga Teleporter', + 'South Dark World Teleporter', 'SDW Flute', 'Dig Game Mirror Spot', 'Cave 45 Mirror Spot', 'Bombos Tablet Mirror Spot']), + create_dw_region(player, 'Dark Lake Hylia Water', None, ['Northeast Dark World Pier', 'East Dark World Pier', 'Southeast Dark World Pier', + 'Ice Palace Approach', 'Lake Hylia Island Mirror Spot']), + create_dw_region(player, 'Dark Lake Hylia Central Island', None, ['Ice Palace', 'Ice Palace Leave Water Drop', 'Ice Island To East Pier', + 'Dark Lake Hylia Teleporter', 'Lake Hylia Central Island Mirror Spot']), + create_dw_region(player, 'Southeast Dark World', None, ['Dark Lake Hylia Ledge Fairy', 'Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Ledge Spike Cave', + 'Southeast Dark World Water Drop', 'DLHL Flute']), + create_cave_region(player, 'Lost Woods Gamble', 'a game of chance'), create_cave_region(player, 'Lost Woods Hideout (top)', 'a drop\'s exit', ['Lost Woods Hideout'], ['Lost Woods Hideout (top to bottom)']), create_cave_region(player, 'Lost Woods Hideout (bottom)', 'a drop\'s exit', None, ['Lost Woods Hideout Exit']), @@ -157,47 +198,6 @@ def create_regions(world, player): create_cave_region(player, '50 Rupee Cave', 'a cave with some cash'), create_cave_region(player, 'Dam', 'the dam', ['Floodgate', 'Floodgate Chest']), - create_dw_region(player, 'West Dark Death Mountain (Bottom)', None, ['Spike Cave', 'Dark Death Mountain Fairy', 'Dark Death Mountain Ladder (Bottom)', - 'Dark Death Mountain Teleporter (West)', 'DDM Flute', 'Spectacle Rock Mirror Spot']), - create_dw_region(player, 'Dark Death Mountain (Top)', None, ['Ganons Tower', 'Hookshot Cave', 'Superbunny Cave (Top)', 'Turtle Rock', 'Dark Death Mountain Drop (West)', - 'Dark Death Mountain Drop (East)', 'Dark Death Mountain Ladder (Top)', 'Turtle Rock Tail Drop', 'East Death Mountain (Top) Mirror Spot']), - create_dw_region(player, 'Dark Death Mountain Floating Island', None, ['Hookshot Cave Back Entrance', 'Floating Island Drop', 'Dark Floating Island Mirror Spot'], 'a dark island'), - create_dw_region(player, 'Dark Death Mountain Ledge', None, ['Dark Death Mountain Ledge (West)', 'Dark Death Mountain Ledge (East)', 'Mimic Cave Mirror Spot', 'Spiral Cave Mirror Spot'], 'a dark ledge'), - create_dw_region(player, 'Dark Death Mountain Isolated Ledge', None, ['Turtle Rock Isolated Ledge Entrance', 'Isolated Ledge Mirror Spot'], 'a dark vista'), - create_dw_region(player, 'East Dark Death Mountain (Bottom)', None, ['Superbunny Cave (Bottom)', 'Dark Death Mountain Shop', - 'East Dark Death Mountain Teleporter (Bottom)', 'EDDM Flute', 'Fairy Ascension Mirror Spot']), - create_dw_region(player, 'Turtle Rock (Top)', None, ['Turtle Rock Drop', 'East Dark Death Mountain Teleporter (Top)']), - create_dw_region(player, 'West Dark World', ['Frog'], ['Dark Lumberjack Shop', 'Fortune Teller (Dark)', 'Dark Sanctuary Hint', 'Chest Game', 'Thieves Town', - 'C-Shaped House', 'Brewery', 'Red Shield Shop', 'Skull Woods Forest', 'Bumper Cave Entrance Rock', - 'West Dark World Water Drop', 'Grassy Lawn Pegs (Bottom)', 'Peg Area Rocks (Left)', 'Village of Outcasts Drop', - 'West Dark World Teleporter', 'WDW Flute', 'Graveyard Ledge Mirror Spot', 'Kings Grave Mirror Spot']), - create_dw_region(player, 'Skull Woods Forest', None, ['Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', - 'Skull Woods First Section Door', 'Skull Woods Second Section Door (East)']), - create_dw_region(player, 'Skull Woods Forest (West)', None, ['Skull Woods Second Section Hole', 'Skull Woods Second Section Door (West)', 'Skull Woods Final Section'], 'a deep, dark forest'), - create_dw_region(player, 'Bumper Cave Ledge', ['Bumper Cave Ledge'], ['Bumper Cave (Top)', 'Bumper Cave Ledge Drop', 'Bumper Cave Ledge Mirror Spot'], 'a ledge with an item'), - create_dw_region(player, 'Bumper Cave Entrance', None, ['Bumper Cave (Bottom)', 'Bumper Cave Entrance Drop', 'Bumper Cave Entrance Mirror Spot']), - create_dw_region(player, 'Dark Grassy Lawn', None, ['Dark World Shop', 'Grassy Lawn Pegs (Top)', 'Dark Grassy Lawn Flute', 'Dark Grassy Lawn Mirror Spot']), - create_dw_region(player, 'Hammer Peg Area', ['Dark Blacksmith Ruins'], ['Hammer Peg Cave', 'Peg Area Rocks (Right)', 'Hammer Peg Area Flute', 'Bat Cave Drop Ledge Mirror Spot']), - create_dw_region(player, 'Northeast Dark World', None, ['Dark Potion Shop', 'Northeast Dark World Water Drop', 'Dark Witch Rock (South)', 'West Dark World Gap', - 'Broken Bridge Pass (Top)', 'NEDW Flute']), - create_dw_region(player, 'Catfish Area', ['Catfish'], ['Dark Witch Rock (North)', 'Catfish Water Drop']), - create_dw_region(player, 'East Dark World', ['Pyramid'], ['Pyramid Hole', 'Pyramid Fairy', 'Palace of Darkness Hint', 'Palace of Darkness', 'Dark Lake Hylia Fairy', - 'East Dark World Hint', 'Broken Bridge Pass (Bottom)', 'East Dark World Water Drop', 'Hammer Bridge Pegs (North)', - 'East Dark World Teleporter', 'EDW Flute', 'Hyrule Castle Ledge Mirror Spot']), - create_dw_region(player, 'Pyramid Exit Ledge', None, ['Pyramid Entrance', 'Pyramid Drop']), - create_dw_region(player, 'Dark Desert', None, ['Mire Shed', 'Misery Mire', 'Dark Desert Fairy', 'Dark Desert Hint', 'DD Flute', 'Checkerboard Ledge Mirror Spot', - 'Desert Ledge Mirror Spot', 'Mire To Desert Stairs Mirror Spot', 'Desert Ledge Rocks Mirror Spot']), - create_dw_region(player, 'Dark Desert Ledge', None, ['Dark Desert Drop', 'Dark Desert Teleporter']), - create_dw_region(player, 'South Dark World', ['Stumpy', 'Digging Game'], ['Archery Game', 'Bonk Fairy (Dark)', 'Big Bomb Shop', 'Hype Cave', 'Dark Lake Hylia Shop', 'Swamp Palace', - 'Village of Outcasts Heavy Rock', 'Hammer Bridge Pegs (South)', 'South Dark World Water Drop', 'Post Aga Teleporter', - 'South Dark World Teleporter', 'SDW Flute', 'Dig Game Mirror Spot', 'Cave 45 Mirror Spot', 'Bombos Tablet Mirror Spot']), - create_dw_region(player, 'Dark Lake Hylia Water', None, ['Northeast Dark World Pier', 'East Dark World Pier', 'Southeast Dark World Pier', - 'Ice Palace Approach', 'Lake Hylia Island Mirror Spot']), - create_dw_region(player, 'Dark Lake Hylia Central Island', None, ['Ice Palace', 'Ice Palace Leave Water Drop', 'Ice Island To East Pier', - 'Dark Lake Hylia Teleporter', 'Lake Hylia Central Island Mirror Spot']), - create_dw_region(player, 'Southeast Dark World', None, ['Dark Lake Hylia Ledge Fairy', 'Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Ledge Spike Cave', - 'Southeast Dark World Water Drop', 'DLHL Flute']), - create_cave_region(player, 'Dark Lumberjack Shop', 'a common shop', ['Dark Lumberjack Shop - Left', 'Dark Lumberjack Shop - Middle', 'Dark Lumberjack Shop - Right']), create_cave_region(player, 'Dark Death Mountain Healer Fairy', 'a fairy fountain'), create_cave_region(player, 'Spike Cave', 'Spike Cave', ['Spike Cave']), From c6d0df5f4fff8b922104bfe4d48868529ad82b1b Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 26 Dec 2022 05:21:59 -0600 Subject: [PATCH 011/196] Modeling Fairy Ascension Mirror Spot more correctly --- EntranceShuffle.py | 1 + Regions.py | 5 +++-- Rules.py | 3 ++- source/overworld/EntranceShuffle2.py | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/EntranceShuffle.py b/EntranceShuffle.py index 8a6a1454..ebd4c283 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -2160,6 +2160,7 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Desert Ledge Rocks (Inner)', 'Desert Ledge'), ('Skull Woods Forest', 'Skull Woods Forest'), + ('East Dark Death Mountain Bushes', 'East Dark Death Mountain (Bushes)'), ('Bumper Cave Entrance Rock', 'Bumper Cave Entrance'), ('Dark Witch Rock (North)', 'Northeast Dark World'), ('Dark Witch Rock (South)', 'Catfish Area'), diff --git a/Regions.py b/Regions.py index 84a36844..53d056ca 100644 --- a/Regions.py +++ b/Regions.py @@ -81,8 +81,9 @@ def create_regions(world, player): create_dw_region(player, 'Dark Death Mountain Floating Island', None, ['Hookshot Cave Back Entrance', 'Floating Island Drop', 'Dark Floating Island Mirror Spot'], 'a dark island'), create_dw_region(player, 'Dark Death Mountain Ledge', None, ['Dark Death Mountain Ledge (West)', 'Dark Death Mountain Ledge (East)', 'Mimic Cave Mirror Spot', 'Spiral Cave Mirror Spot'], 'a dark ledge'), create_dw_region(player, 'Dark Death Mountain Isolated Ledge', None, ['Turtle Rock Isolated Ledge Entrance', 'Isolated Ledge Mirror Spot'], 'a dark vista'), - create_dw_region(player, 'East Dark Death Mountain (Bottom)', None, ['Superbunny Cave (Bottom)', 'Dark Death Mountain Shop', - 'East Dark Death Mountain Teleporter (Bottom)', 'EDDM Flute', 'Fairy Ascension Mirror Spot']), + create_dw_region(player, 'East Dark Death Mountain (Bottom)', None, ['East Dark Death Mountain Bushes', 'Superbunny Cave (Bottom)', 'Dark Death Mountain Shop', + 'East Dark Death Mountain Teleporter (Bottom)', 'EDDM Flute']), + create_dw_region(player, 'East Dark Death Mountain (Bushes)', None, ['Fairy Ascension Mirror Spot']), create_dw_region(player, 'Turtle Rock (Top)', None, ['Turtle Rock Drop', 'East Dark Death Mountain Teleporter (Top)']), create_dw_region(player, 'West Dark World', ['Frog'], ['Dark Lumberjack Shop', 'Fortune Teller (Dark)', 'Dark Sanctuary Hint', 'Chest Game', 'Thieves Town', 'C-Shaped House', 'Brewery', 'Red Shield Shop', 'Skull Woods Forest', 'Bumper Cave Entrance Rock', diff --git a/Rules.py b/Rules.py index 77a0fb65..69c4e21c 100644 --- a/Rules.py +++ b/Rules.py @@ -860,7 +860,7 @@ def ow_inverted_rules(world, player): set_rule(world.get_entrance('Spiral Cave Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Mimic Cave Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Isolated Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Fairy Ascension Mirror Spot', player), lambda state: state.has_Mirror(player) and state.has_Pearl(player)) # need to lift flowers + set_rule(world.get_entrance('Fairy Ascension Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Bumper Cave Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Bumper Cave Entrance Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Graveyard Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) @@ -995,6 +995,7 @@ def ow_bunny_rules(world, player): add_bunny_rule(world.get_entrance('Desert Ledge Rocks (Outer)', player), player) add_bunny_rule(world.get_entrance('Desert Ledge Rocks (Inner)', player), player) + add_bunny_rule(world.get_entrance('East Dark Death Mountain Bushes', player), player) add_bunny_rule(world.get_entrance('Bumper Cave Entrance Rock', player), player) add_bunny_rule(world.get_entrance('Dark Witch Rock (North)', player), player) add_bunny_rule(world.get_entrance('Dark Witch Rock (South)', player), player) diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index 801abc51..d13b4416 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -1949,6 +1949,7 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Desert Ledge Rocks (Inner)', 'Desert Ledge'), ('Skull Woods Forest', 'Skull Woods Forest'), + ('East Dark Death Mountain Bushes', 'East Dark Death Mountain (Bushes)'), ('Bumper Cave Entrance Rock', 'Bumper Cave Entrance'), ('Dark Witch Rock (North)', 'Northeast Dark World'), ('Dark Witch Rock (South)', 'Catfish Area'), From 118adabeb116e11e4ce613b8a7118906203bd62d Mon Sep 17 00:00:00 2001 From: codemann8 Date: Fri, 30 Dec 2022 06:17:54 -0600 Subject: [PATCH 012/196] Changing mirror exits to be dynamically created --- EntranceShuffle.py | 59 +--------------- Main.py | 3 + OverworldShuffle.py | 100 +++++++++++++++++++++++++++ Regions.py | 81 ++++++++++------------ Rules.py | 53 -------------- source/overworld/EntranceShuffle2.py | 59 +--------------- 6 files changed, 145 insertions(+), 210 deletions(-) create mode 100644 OverworldShuffle.py diff --git a/EntranceShuffle.py b/EntranceShuffle.py index ebd4c283..2e5162e4 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -2236,32 +2236,7 @@ open_mandatory_connections = [('Sanctuary S&Q', 'Sanctuary'), ('East Hyrule Teleporter', 'East Dark World'), ('South Hyrule Teleporter', 'South Dark World'), ('Desert Teleporter', 'Dark Desert'), - ('Lake Hylia Teleporter', 'Dark Lake Hylia Central Island'), - - # mirror - ('Spectacle Rock Mirror Spot', 'Spectacle Rock'), - ('East Death Mountain (Top) Mirror Spot', 'East Death Mountain (Top)'), - ('Dark Floating Island Mirror Spot', 'Death Mountain Floating Island'), - ('Spiral Cave Mirror Spot', 'Spiral Cave Ledge'), - ('Mimic Cave Mirror Spot', 'Mimic Cave Ledge'), - ('Isolated Ledge Mirror Spot', 'Fairy Ascension Ledge'), - ('Fairy Ascension Mirror Spot', 'Fairy Ascension Plateau'), - ('Bumper Cave Ledge Mirror Spot', 'Death Mountain Return Ledge'), - ('Bumper Cave Entrance Mirror Spot', 'Death Mountain Entrance'), - ('Graveyard Ledge Mirror Spot', 'Graveyard Ledge'), - ('Kings Grave Mirror Spot', 'Kings Grave Area'), - ('Dark Grassy Lawn Mirror Spot', 'Bush Covered Lawn'), - ('Hyrule Castle Ledge Mirror Spot', 'Hyrule Castle Ledge'), - ('Bat Cave Drop Ledge Mirror Spot', 'Bat Cave Ledge'), - ('Dig Game Mirror Spot', 'Maze Race Ledge'), - ('Desert Ledge Rocks Mirror Spot', 'Desert Palace Entrance (North) Spot'), - ('Desert Ledge Mirror Spot', 'Desert Ledge'), - ('Mire To Desert Stairs Mirror Spot', 'Desert Palace Stairs'), - ('Checkerboard Ledge Mirror Spot', 'Desert Checkerboard Ledge'), - ('Bombos Tablet Mirror Spot', 'Bombos Tablet Ledge'), - ('Cave 45 Mirror Spot', 'Cave 45 Ledge'), - ('Lake Hylia Island Mirror Spot', 'Lake Hylia Island'), - ('Lake Hylia Central Island Mirror Spot', 'Lake Hylia Central Island') + ('Lake Hylia Teleporter', 'Dark Lake Hylia Central Island') ] inverted_mandatory_connections = [('Sanctuary S&Q', 'Dark Sanctuary Hint'), @@ -2318,37 +2293,7 @@ inverted_mandatory_connections = [('Sanctuary S&Q', 'Dark Sanctuary Hint'), ('East Dark World Teleporter', 'Light World'), ('South Dark World Teleporter', 'Light World'), ('Dark Desert Teleporter', 'Light World'), - ('Dark Lake Hylia Teleporter', 'Lake Hylia Central Island'), - - # mirror - ('Skull Woods Mirror Spot', 'Skull Woods Forest (West)'), - ('West Dark World Mirror Spot', 'West Dark World'), - ('Death Mountain (Top) Mirror Spot', 'Dark Death Mountain (Top)'), - ('Death Mountain Mirror Spot', 'West Dark Death Mountain (Bottom)'), - ('East Death Mountain Mirror Spot (Top)', 'Dark Death Mountain (Top)'), - ('Floating Island Mirror Spot', 'Dark Death Mountain Floating Island'), - ('Dark Death Mountain Ledge Mirror Spot (East)', 'Dark Death Mountain Ledge'), - ('Dark Death Mountain Ledge Mirror Spot (West)', 'Dark Death Mountain Ledge'), - ('Laser Bridge Mirror Spot', 'Dark Death Mountain Isolated Ledge'), - ('East Death Mountain Mirror Spot (Bottom)', 'East Dark Death Mountain (Bottom)'), - ('Mountain Exit Ledge Mirror Spot', 'Bumper Cave Ledge'), - ('Mountain Entrance Mirror Spot', 'Bumper Cave Entrance'), - ('Catfish Mirror Spot', 'Catfish Area'), - ('Graveyard Cave Mirror Spot', 'West Dark World'), - ('Potion Shop Mirror Spot', 'Northeast Dark World'), - ('Bush Covered Lawn Mirror Spot', 'Dark Grassy Lawn'), - ('Bomb Hut Mirror Spot', 'West Dark World'), - ('Pyramid Uncle Mirror Spot', 'East Dark World'), - ('East Dark World Mirror Spot', 'East Dark World'), - ('Hammer Peg Area Mirror Spot', 'Hammer Peg Area'), - ('Maze Race Mirror Spot', 'South Dark World'), - ('South Dark World Mirror Spot', 'South Dark World'), - ('Mire Mirror Spot', 'Dark Desert'), - ('Dark Desert Ledge Mirror Spot', 'Dark Desert'), - ('Desert Palace Stairs Mirror Spot', 'Dark Desert'), - ('Desert Palace North Mirror Spot', 'Dark Desert'), - ('Ice Lake Central Island Mirror Spot', 'Lake Hylia Central Island'), - ('Shopping Mall Mirror Spot', 'Southeast Dark World') + ('Dark Lake Hylia Teleporter', 'Lake Hylia Central Island') ] # non-shuffled entrance links diff --git a/Main.py b/Main.py index ebfa461e..58669567 100644 --- a/Main.py +++ b/Main.py @@ -15,6 +15,7 @@ from KeyDoorShuffle import validate_key_placement from OverworldGlitchRules import create_owg_connections from PotShuffle import shuffle_pots, shuffle_pot_switches from Regions import create_regions, create_shops, mark_light_dark_world_regions, create_dungeon_regions, adjust_locations +from OverworldShuffle import create_dynamic_exits from EntranceShuffle import link_entrances from Rom import patch_rom, patch_race_rom, patch_enemizer, apply_rom_settings, LocalRom, JsonRom, get_hash_string from Doors import create_doors @@ -217,6 +218,7 @@ def main(args, seed=None, fish=None): logger.info(world.fish.translate("cli","cli","shuffling.world")) for player in range(1, world.players + 1): + create_dynamic_exits(world, player) if world.experimental[player] or world.shuffle[player] in ['lite', 'lean'] or world.shuffletavern[player] or (world.customizer and world.customizer.get_entrances()): link_entrances_new(world, player) else: @@ -485,6 +487,7 @@ def copy_world(world): for player in range(1, world.players + 1): create_regions(ret, player) + create_dynamic_exits(ret, player) create_dungeon_regions(ret, player) create_shops(ret, player) create_rooms(ret, player) diff --git a/OverworldShuffle.py b/OverworldShuffle.py new file mode 100644 index 00000000..64be6969 --- /dev/null +++ b/OverworldShuffle.py @@ -0,0 +1,100 @@ +from BaseClasses import RegionType, Entrance + +def get_mirror_exit_name(from_region, to_region): + if from_region in mirror_connections and to_region in mirror_connections[from_region]: + if len(mirror_connections[from_region]) == 1: + return f'Mirror From {from_region}' + else: + return f'Mirror To {to_region}' + return None + +def create_mirror_exits(world, player): + mirror_exits = set() + for region in (r for r in world.regions if r.player == player and r.name not in ['Zoras Domain', 'Master Sword Meadow', 'Hobo Bridge']): + if region.type == (RegionType.DarkWorld if world.mode[player] != 'inverted' else RegionType.LightWorld): + if region.name in mirror_connections: + for region_dest_name in mirror_connections[region.name]: + exitname = get_mirror_exit_name(region.name, region_dest_name) + + assert exitname not in mirror_exits, f'Mirror Exit with name already exists: {exitname}' + + exit = Entrance(region.player, exitname, region) + exit.spot_type = 'Mirror' + to_region = world.get_region(region_dest_name, player) + # if region.terrain == Terrain.Water or to_region.terrain == Terrain.Water: + if region.name == 'Dark Lake Hylia Water': # TODO: Uncomment line above when Terrain type is modeled + exit.access_rule = lambda state: state.has('Flippers', player) and state.has_Pearl(player) and state.has_Mirror(player) + else: + exit.access_rule = lambda state: state.has_Mirror(player) + exit.connect(to_region) + region.exits.append(exit) + + mirror_exits.add(exitname) + +def create_dynamic_exits(world, player): + create_mirror_exits(world, player) + world.initialize_regions() + + +mirror_connections = { + 'West Dark Death Mountain (Bottom)': ['Spectacle Rock'], + 'Dark Death Mountain (Top)': ['East Death Mountain (Top)'], + + 'Dark Death Mountain Floating Island': ['Death Mountain Floating Island'], + 'Dark Death Mountain Ledge': ['Spiral Cave Ledge', 'Mimic Cave Ledge'], + 'Dark Death Mountain Isolated Ledge': ['Fairy Ascension Ledge'], + 'East Dark Death Mountain (Bushes)': ['Fairy Ascension Plateau'], + + 'West Dark World': ['Graveyard Ledge', 'Kings Grave Area'], + + 'Bumper Cave Ledge': ['Death Mountain Return Ledge'], + 'Bumper Cave Entrance': ['Death Mountain Entrance'], + + 'Dark Grassy Lawn': ['Bush Covered Lawn'], + + 'Hammer Peg Area': ['Bat Cave Ledge'], + + 'East Dark World': ['Hyrule Castle Ledge'], + + 'Dark Desert': ['Desert Ledge', 'Desert Checkerboard Ledge', 'Desert Palace Stairs', 'Desert Palace Entrance (North) Spot'], + + 'South Dark World': ['Maze Race Ledge', 'Cave 45 Ledge', 'Bombos Tablet Ledge'], + + 'Dark Lake Hylia Water': ['Lake Hylia Island'], + 'Dark Lake Hylia Central Island': ['Lake Hylia Central Island'], + + + 'Light World': ['Skull Woods Forest (West)', 'West Dark World', 'Hammer Peg Area', 'East Dark World', 'South Dark World', 'Dark Desert', 'Southeast Dark World'], + + 'West Death Mountain (Top)': ['Dark Death Mountain (Top)'], + 'West Death Mountain (Bottom)': ['West Dark Death Mountain (Bottom)'], + + 'East Death Mountain (Top)': ['Dark Death Mountain (Top)'], + 'Death Mountain Floating Island': ['Dark Death Mountain Floating Island'], + 'Spiral Cave Ledge': ['Dark Death Mountain Ledge'], + 'Mimic Cave Ledge': ['Dark Death Mountain Ledge'], + 'Fairy Ascension Ledge': ['Dark Death Mountain Isolated Ledge'], + 'East Death Mountain (Bottom)': ['East Dark Death Mountain (Bottom)'], + + 'Death Mountain Return Ledge': ['Bumper Cave Ledge'], + 'Death Mountain Entrance': ['Bumper Cave Entrance'], + + 'Northeast Light World': ['Catfish Area'], + + 'Graveyard Ledge': ['West Dark World'], + + 'Potion Shop Area': ['Northeast Dark World'], + + 'Bush Covered Lawn': ['Dark Grassy Lawn'], + 'Bomb Hut Area': ['West Dark World'], + + 'Hyrule Castle Secret Entrance Area': ['East Dark World'], + + 'Maze Race Ledge': ['South Dark World'], + + 'Desert Palace Stairs': ['Dark Desert'], + 'Desert Ledge': ['Dark Desert'], + 'Desert Palace Entrance (North) Spot': ['Dark Desert'], + + 'Lake Hylia Central Island': ['Dark Lake Hylia Central Island'] +} \ No newline at end of file diff --git a/Regions.py b/Regions.py index 53d056ca..ca4ae24e 100644 --- a/Regions.py +++ b/Regions.py @@ -23,45 +23,42 @@ def create_regions(world, player): 'Wooden Bridge Bush (South)', 'Kakariko Southwest Bush (North)', 'Kakariko Yard Bush (South)', 'Hyrule Castle Main Gate', 'Bat Cave Ledge Peg', 'Light World Water Drop', 'Desert Statue Move', 'Checkerboard Ledge Approach', 'Cave 45 Approach', 'Bombos Tablet Ladder (Bottom)', - 'Kakariko Teleporter', 'Castle Gate Teleporter', 'East Hyrule Teleporter', 'South Hyrule Teleporter', - - 'LW Flute', 'Skull Woods Mirror Spot', 'West Dark World Mirror Spot', 'Hammer Peg Area Mirror Spot', - 'East Dark World Mirror Spot', 'South Dark World Mirror Spot', 'Mire Mirror Spot', 'Shopping Mall Mirror Spot']), + 'Kakariko Teleporter', 'Castle Gate Teleporter', 'East Hyrule Teleporter', 'South Hyrule Teleporter', 'LW Flute']), create_lw_region(player, 'West Death Mountain (Top)', ['Ether Tablet'], ['Tower of Hera', 'Death Mountain Drop', 'Spectacle Rock Approach', - 'DM Hammer Bridge (West)', 'Death Mountain (Top) Mirror Spot']), + 'DM Hammer Bridge (West)']), create_lw_region(player, 'West Death Mountain (Bottom)', None, ['Old Man Cave (East)', 'Old Man House (Bottom)', 'Old Man House (Top)', 'Death Mountain Return Cave (East)', 'Spectacle Rock Cave', 'Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Bottom)', - 'DM Broken Bridge (West)', 'Death Mountain Teleporter', 'DM Flute', 'Death Mountain Mirror Spot']), + 'DM Broken Bridge (West)', 'Death Mountain Teleporter', 'DM Flute']), create_lw_region(player, 'Spectacle Rock', ['Spectacle Rock'], ['Spectacle Rock Drop', 'Spectacle Rock Leave']), create_lw_region(player, 'East Death Mountain (Top)', None, ['Paradox Cave (Top)', 'DM Hammer Bridge (East)', 'Floating Island Bridge (East)', 'Spiral Cave Ledge Access', 'Fairy Ascension Ledge Access', 'Mimic Cave Ledge Access', 'East Death Mountain Drop', - 'Turtle Rock Teleporter', 'East Death Mountain Mirror Spot (Top)']), - create_lw_region(player, 'Death Mountain Floating Island', ['Floating Island'], ['Floating Island Bridge (West)', 'Floating Island Mirror Spot']), - create_lw_region(player, 'Spiral Cave Ledge', None, ['Spiral Cave', 'Spiral Cave Ledge Drop', 'Dark Death Mountain Ledge Mirror Spot (West)']), - create_lw_region(player, 'Mimic Cave Ledge', None, ['Mimic Cave', 'Mimic Cave Ledge Drop', 'Dark Death Mountain Ledge Mirror Spot (East)']), - create_lw_region(player, 'Fairy Ascension Ledge', None, ['Fairy Ascension Cave (Top)', 'Fairy Ascension Ledge Drop', 'Laser Bridge Mirror Spot']), + 'Turtle Rock Teleporter']), + create_lw_region(player, 'Death Mountain Floating Island', ['Floating Island'], ['Floating Island Bridge (West)']), + create_lw_region(player, 'Spiral Cave Ledge', None, ['Spiral Cave', 'Spiral Cave Ledge Drop']), + create_lw_region(player, 'Mimic Cave Ledge', None, ['Mimic Cave', 'Mimic Cave Ledge Drop']), + create_lw_region(player, 'Fairy Ascension Ledge', None, ['Fairy Ascension Cave (Top)', 'Fairy Ascension Ledge Drop']), create_lw_region(player, 'East Death Mountain (Bottom)', None, ['Spiral Cave (Bottom)', 'Hookshot Fairy', 'Paradox Cave (Bottom)', 'Paradox Cave (Middle)', - 'DM Broken Bridge (East)', 'Fairy Ascension Rocks', 'East Death Mountain Teleporter', 'EDM Flute', 'East Death Mountain Mirror Spot (Bottom)']), + 'DM Broken Bridge (East)', 'Fairy Ascension Rocks', 'East Death Mountain Teleporter', 'EDM Flute']), create_lw_region(player, 'Fairy Ascension Plateau', None, ['Fairy Ascension Cave (Bottom)', 'Fairy Ascension Drop']), - create_lw_region(player, 'Death Mountain Return Ledge', None, ['Death Mountain Return Cave (West)', 'Death Mountain Return Ledge Drop', 'Mountain Exit Ledge Mirror Spot'], 'a ledge in the foothills'), - create_lw_region(player, 'Death Mountain Entrance', None, ['Old Man Cave (West)', 'Death Mountain Entrance Drop', 'Mountain Entrance Mirror Spot']), - create_lw_region(player, 'Northeast Light World', None, ['Zoras Domain', 'Potion Shop Rock (North)', 'Northeast Light World Water Drop', 'Catfish Mirror Spot']), + create_lw_region(player, 'Death Mountain Return Ledge', None, ['Death Mountain Return Cave (West)', 'Death Mountain Return Ledge Drop'], 'a ledge in the foothills'), + create_lw_region(player, 'Death Mountain Entrance', None, ['Old Man Cave (West)', 'Death Mountain Entrance Drop']), + create_lw_region(player, 'Northeast Light World', None, ['Zoras Domain', 'Potion Shop Rock (North)', 'Northeast Light World Water Drop']), create_lw_region(player, 'Zora Waterfall Entryway', None, ['Waterfall of Wishing', 'Zora Waterfall Water Drop', 'ZLW Flute']), - create_lw_region(player, 'Graveyard Ledge', None, ['Graveyard Cave', 'Graveyard Ledge Drop', 'Graveyard Ladder (Top)', 'Graveyard Cave Mirror Spot']), + create_lw_region(player, 'Graveyard Ledge', None, ['Graveyard Cave', 'Graveyard Ledge Drop', 'Graveyard Ladder (Top)']), create_lw_region(player, 'Kings Grave Area', None, ['Kings Grave', 'Kings Grave Rocks (Inner)']), - create_lw_region(player, 'Potion Shop Area', None, ['Potion Shop', 'Wooden Bridge Bush (North)', 'Potion Shop Rock (South)', 'Potion Shop Water Drop', 'NWLW Flute', 'Potion Shop Mirror Spot']), - create_lw_region(player, 'Bush Covered Lawn', None, ['Bush Covered House', 'Kakariko Yard Bush (North)', 'Bush Covered Lawn Mirror Spot']), - create_lw_region(player, 'Bomb Hut Area', None, ['Light World Bomb Hut', 'Kakariko Southwest Bush (South)', 'Bomb Hut Mirror Spot']), + create_lw_region(player, 'Potion Shop Area', None, ['Potion Shop', 'Wooden Bridge Bush (North)', 'Potion Shop Rock (South)', 'Potion Shop Water Drop', 'NWLW Flute']), + create_lw_region(player, 'Bush Covered Lawn', None, ['Bush Covered House', 'Kakariko Yard Bush (North)']), + create_lw_region(player, 'Bomb Hut Area', None, ['Light World Bomb Hut', 'Kakariko Southwest Bush (South)']), create_lw_region(player, 'Hyrule Castle Courtyard', None, ['Hyrule Castle Entrance (South)', 'Inverted Pyramid Entrance', 'Hyrule Castle Courtyard Bush (South)', 'Hyrule Castle Main Gate (North)']), - create_lw_region(player, 'Hyrule Castle Secret Entrance Area', None, ['Hyrule Castle Secret Entrance Stairs', 'Hyrule Castle Courtyard Bush (North)', 'Pyramid Uncle Mirror Spot']), + create_lw_region(player, 'Hyrule Castle Secret Entrance Area', None, ['Hyrule Castle Secret Entrance Stairs', 'Hyrule Castle Courtyard Bush (North)']), create_lw_region(player, 'Hyrule Castle Ledge', None, ['Hyrule Castle Entrance (West)', 'Agahnims Tower', 'Hyrule Castle Entrance (East)', 'Inverted Pyramid Hole', 'Hyrule Castle Ledge Courtyard Drop', 'Hyrule Castle Ledge Drop'], 'the castle rampart'), create_lw_region(player, 'Bat Cave Ledge', None, ['Bat Cave Drop', 'Bat Cave Ledge Peg (East)']), - create_lw_region(player, 'Maze Race Ledge', ['Maze Race'], ['Two Brothers House (West)', 'Maze Race Ledge Drop', 'Maze Race Mirror Spot'], 'a race against time'), - create_lw_region(player, 'Desert Palace Stairs', None, ['Desert Palace Entrance (South)', 'Desert Palace Stairs Mirror Spot']), + create_lw_region(player, 'Maze Race Ledge', ['Maze Race'], ['Two Brothers House (West)', 'Maze Race Ledge Drop'], 'a race against time'), + create_lw_region(player, 'Desert Palace Stairs', None, ['Desert Palace Entrance (South)']), create_lw_region(player, 'Desert Palace Mouth', None, ['Desert Palace Entrance (East)', 'Desert Palace Mouth Drop'], 'a sandy vista'), - create_lw_region(player, 'Desert Ledge', ['Desert Ledge'], ['Desert Palace Entrance (West)', 'Desert Ledge Rocks (Outer)', 'Desert Ledge Drop', 'Dark Desert Ledge Mirror Spot'], 'the desert ledge'), - create_lw_region(player, 'Desert Palace Entrance (North) Spot', None, ['Desert Palace Entrance (North)', 'Desert Ledge Rocks (Inner)', 'Desert Palace North Mirror Spot'], 'the desert ledge'), + create_lw_region(player, 'Desert Ledge', ['Desert Ledge'], ['Desert Palace Entrance (West)', 'Desert Ledge Rocks (Outer)', 'Desert Ledge Drop'], 'the desert ledge'), + create_lw_region(player, 'Desert Palace Entrance (North) Spot', None, ['Desert Palace Entrance (North)', 'Desert Ledge Rocks (Inner)'], 'the desert ledge'), create_lw_region(player, 'Desert Checkerboard Ledge', None, ['Checkerboard Cave', 'Checkerboard Ledge Drop', 'Checkerboard Ledge Leave']), create_lw_region(player, 'Desert Teleporter Ledge', None, ['Desert Teleporter Drop', 'Desert Teleporter']), create_lw_region(player, 'Bombos Tablet Ledge', ['Bombos Tablet'], ['Bombos Tablet Ladder (Top)']), @@ -69,50 +66,48 @@ def create_regions(world, player): create_lw_region(player, 'Cave 45 Ledge', None, ['Cave 45', 'Cave 45 Ledge Drop', 'Cave 45 Leave']), create_lw_region(player, 'Lake Hylia Water', None, ['Light World Pier', 'Potion Shop Pier', 'Hobo Pier', 'Lake Hylia Island Pier', 'Lake Hylia Central Island Pier', 'Lake Hylia Whirlpool', 'Waterfall Fairy Access']), create_lw_region(player, 'Lake Hylia Island', ['Lake Hylia Island']), - create_lw_region(player, 'Lake Hylia Central Island', None, ['Capacity Upgrade', 'Lake Hylia Central Island Water Drop', 'Lake Hylia Teleporter', 'Ice Lake Central Island Mirror Spot']), + create_lw_region(player, 'Lake Hylia Central Island', None, ['Capacity Upgrade', 'Lake Hylia Central Island Water Drop', 'Lake Hylia Teleporter']), create_lw_region(player, 'Master Sword Meadow', ['Master Sword Pedestal']), create_lw_region(player, 'Hobo Bridge', ['Hobo']), create_lw_region(player, 'Zoras Domain', ['King Zora', 'Zora\'s Ledge']), create_dw_region(player, 'West Dark Death Mountain (Bottom)', None, ['Spike Cave', 'Dark Death Mountain Fairy', 'Dark Death Mountain Ladder (Bottom)', - 'Dark Death Mountain Teleporter (West)', 'DDM Flute', 'Spectacle Rock Mirror Spot']), + 'Dark Death Mountain Teleporter (West)', 'DDM Flute']), create_dw_region(player, 'Dark Death Mountain (Top)', None, ['Ganons Tower', 'Hookshot Cave', 'Superbunny Cave (Top)', 'Turtle Rock', 'Dark Death Mountain Drop (West)', - 'Dark Death Mountain Drop (East)', 'Dark Death Mountain Ladder (Top)', 'Turtle Rock Tail Drop', 'East Death Mountain (Top) Mirror Spot']), - create_dw_region(player, 'Dark Death Mountain Floating Island', None, ['Hookshot Cave Back Entrance', 'Floating Island Drop', 'Dark Floating Island Mirror Spot'], 'a dark island'), - create_dw_region(player, 'Dark Death Mountain Ledge', None, ['Dark Death Mountain Ledge (West)', 'Dark Death Mountain Ledge (East)', 'Mimic Cave Mirror Spot', 'Spiral Cave Mirror Spot'], 'a dark ledge'), - create_dw_region(player, 'Dark Death Mountain Isolated Ledge', None, ['Turtle Rock Isolated Ledge Entrance', 'Isolated Ledge Mirror Spot'], 'a dark vista'), + 'Dark Death Mountain Drop (East)', 'Dark Death Mountain Ladder (Top)', 'Turtle Rock Tail Drop']), + create_dw_region(player, 'Dark Death Mountain Floating Island', None, ['Hookshot Cave Back Entrance', 'Floating Island Drop'], 'a dark island'), + create_dw_region(player, 'Dark Death Mountain Ledge', None, ['Dark Death Mountain Ledge (West)', 'Dark Death Mountain Ledge (East)'], 'a dark ledge'), + create_dw_region(player, 'Dark Death Mountain Isolated Ledge', None, ['Turtle Rock Isolated Ledge Entrance'], 'a dark vista'), create_dw_region(player, 'East Dark Death Mountain (Bottom)', None, ['East Dark Death Mountain Bushes', 'Superbunny Cave (Bottom)', 'Dark Death Mountain Shop', 'East Dark Death Mountain Teleporter (Bottom)', 'EDDM Flute']), - create_dw_region(player, 'East Dark Death Mountain (Bushes)', None, ['Fairy Ascension Mirror Spot']), + create_dw_region(player, 'East Dark Death Mountain (Bushes)', None, []), create_dw_region(player, 'Turtle Rock (Top)', None, ['Turtle Rock Drop', 'East Dark Death Mountain Teleporter (Top)']), create_dw_region(player, 'West Dark World', ['Frog'], ['Dark Lumberjack Shop', 'Fortune Teller (Dark)', 'Dark Sanctuary Hint', 'Chest Game', 'Thieves Town', 'C-Shaped House', 'Brewery', 'Red Shield Shop', 'Skull Woods Forest', 'Bumper Cave Entrance Rock', 'West Dark World Water Drop', 'Grassy Lawn Pegs (Bottom)', 'Peg Area Rocks (Left)', 'Village of Outcasts Drop', - 'West Dark World Teleporter', 'WDW Flute', 'Graveyard Ledge Mirror Spot', 'Kings Grave Mirror Spot']), + 'West Dark World Teleporter', 'WDW Flute']), create_dw_region(player, 'Skull Woods Forest', None, ['Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', 'Skull Woods First Section Door', 'Skull Woods Second Section Door (East)']), create_dw_region(player, 'Skull Woods Forest (West)', None, ['Skull Woods Second Section Hole', 'Skull Woods Second Section Door (West)', 'Skull Woods Final Section'], 'a deep, dark forest'), - create_dw_region(player, 'Bumper Cave Ledge', ['Bumper Cave Ledge'], ['Bumper Cave (Top)', 'Bumper Cave Ledge Drop', 'Bumper Cave Ledge Mirror Spot'], 'a ledge with an item'), - create_dw_region(player, 'Bumper Cave Entrance', None, ['Bumper Cave (Bottom)', 'Bumper Cave Entrance Drop', 'Bumper Cave Entrance Mirror Spot']), - create_dw_region(player, 'Dark Grassy Lawn', None, ['Dark World Shop', 'Grassy Lawn Pegs (Top)', 'Dark Grassy Lawn Flute', 'Dark Grassy Lawn Mirror Spot']), - create_dw_region(player, 'Hammer Peg Area', ['Dark Blacksmith Ruins'], ['Hammer Peg Cave', 'Peg Area Rocks (Right)', 'Hammer Peg Area Flute', 'Bat Cave Drop Ledge Mirror Spot']), + create_dw_region(player, 'Bumper Cave Ledge', ['Bumper Cave Ledge'], ['Bumper Cave (Top)', 'Bumper Cave Ledge Drop'], 'a ledge with an item'), + create_dw_region(player, 'Bumper Cave Entrance', None, ['Bumper Cave (Bottom)', 'Bumper Cave Entrance Drop']), + create_dw_region(player, 'Dark Grassy Lawn', None, ['Dark World Shop', 'Grassy Lawn Pegs (Top)', 'Dark Grassy Lawn Flute']), + create_dw_region(player, 'Hammer Peg Area', ['Dark Blacksmith Ruins'], ['Hammer Peg Cave', 'Peg Area Rocks (Right)', 'Hammer Peg Area Flute']), create_dw_region(player, 'Northeast Dark World', None, ['Dark Potion Shop', 'Northeast Dark World Water Drop', 'Dark Witch Rock (South)', 'West Dark World Gap', 'Broken Bridge Pass (Top)', 'NEDW Flute']), create_dw_region(player, 'Catfish Area', ['Catfish'], ['Dark Witch Rock (North)', 'Catfish Water Drop']), create_dw_region(player, 'East Dark World', ['Pyramid'], ['Pyramid Hole', 'Pyramid Fairy', 'Palace of Darkness Hint', 'Palace of Darkness', 'Dark Lake Hylia Fairy', 'East Dark World Hint', 'Broken Bridge Pass (Bottom)', 'East Dark World Water Drop', 'Hammer Bridge Pegs (North)', - 'East Dark World Teleporter', 'EDW Flute', 'Hyrule Castle Ledge Mirror Spot']), + 'East Dark World Teleporter', 'EDW Flute']), create_dw_region(player, 'Pyramid Exit Ledge', None, ['Pyramid Entrance', 'Pyramid Drop']), - create_dw_region(player, 'Dark Desert', None, ['Mire Shed', 'Misery Mire', 'Dark Desert Fairy', 'Dark Desert Hint', 'DD Flute', 'Checkerboard Ledge Mirror Spot', - 'Desert Ledge Mirror Spot', 'Mire To Desert Stairs Mirror Spot', 'Desert Ledge Rocks Mirror Spot']), + create_dw_region(player, 'Dark Desert', None, ['Mire Shed', 'Misery Mire', 'Dark Desert Fairy', 'Dark Desert Hint', 'DD Flute']), create_dw_region(player, 'Dark Desert Ledge', None, ['Dark Desert Drop', 'Dark Desert Teleporter']), create_dw_region(player, 'South Dark World', ['Stumpy', 'Digging Game'], ['Archery Game', 'Bonk Fairy (Dark)', 'Big Bomb Shop', 'Hype Cave', 'Dark Lake Hylia Shop', 'Swamp Palace', 'Village of Outcasts Heavy Rock', 'Hammer Bridge Pegs (South)', 'South Dark World Water Drop', 'Post Aga Teleporter', - 'South Dark World Teleporter', 'SDW Flute', 'Dig Game Mirror Spot', 'Cave 45 Mirror Spot', 'Bombos Tablet Mirror Spot']), - create_dw_region(player, 'Dark Lake Hylia Water', None, ['Northeast Dark World Pier', 'East Dark World Pier', 'Southeast Dark World Pier', - 'Ice Palace Approach', 'Lake Hylia Island Mirror Spot']), + 'South Dark World Teleporter', 'SDW Flute']), + create_dw_region(player, 'Dark Lake Hylia Water', None, ['Northeast Dark World Pier', 'East Dark World Pier', 'Southeast Dark World Pier', 'Ice Palace Approach']), create_dw_region(player, 'Dark Lake Hylia Central Island', None, ['Ice Palace', 'Ice Palace Leave Water Drop', 'Ice Island To East Pier', - 'Dark Lake Hylia Teleporter', 'Lake Hylia Central Island Mirror Spot']), + 'Dark Lake Hylia Teleporter']), create_dw_region(player, 'Southeast Dark World', None, ['Dark Lake Hylia Ledge Fairy', 'Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Ledge Spike Cave', 'Southeast Dark World Water Drop', 'DLHL Flute']), diff --git a/Rules.py b/Rules.py index 69c4e21c..e23aa682 100644 --- a/Rules.py +++ b/Rules.py @@ -854,30 +854,6 @@ def pot_rules(world, player): def ow_inverted_rules(world, player): if world.mode[player] != 'inverted': - set_rule(world.get_entrance('Spectacle Rock Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('East Death Mountain (Top) Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Dark Floating Island Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Spiral Cave Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Mimic Cave Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Isolated Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Fairy Ascension Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Bumper Cave Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Bumper Cave Entrance Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Graveyard Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Kings Grave Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Dark Grassy Lawn Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Hyrule Castle Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Bat Cave Drop Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Dig Game Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Desert Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Desert Ledge Rocks Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Mire To Desert Stairs Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Checkerboard Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Bombos Tablet Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Cave 45 Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Lake Hylia Island Mirror Spot', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player) and state.has_Mirror(player)) # force flipper rule since fake flipper cannot mirror - set_rule(world.get_entrance('Lake Hylia Central Island Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('East Death Mountain Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) set_rule(world.get_entrance('Turtle Rock Teleporter', player), lambda state: state.can_lift_heavy_rocks(player) and state.has('Hammer', player)) set_rule(world.get_entrance('Kakariko Teleporter', player), lambda state: ((state.has('Hammer', player) and state.can_lift_rocks(player)) or state.can_lift_heavy_rocks(player)) and state.has_Pearl(player)) # bunny cannot lift bushes @@ -892,35 +868,6 @@ def ow_inverted_rules(world, player): set_rule(world.get_location('Frog', player), lambda state: state.can_lift_heavy_rocks(player) and state.has_Pearl(player)) set_rule(world.get_entrance('Pyramid Hole', player), lambda state: world.open_pyramid[player] or world.goal[player] == 'trinity' or state.has('Beat Agahnim 2', player)) else: - set_rule(world.get_entrance('Skull Woods Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('West Dark World Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Death Mountain (Top) Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Death Mountain Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('East Death Mountain Mirror Spot (Top)', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Floating Island Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Dark Death Mountain Ledge Mirror Spot (West)', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Dark Death Mountain Ledge Mirror Spot (East)', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Laser Bridge Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('East Death Mountain Mirror Spot (Bottom)', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Mountain Exit Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Mountain Entrance Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Catfish Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Graveyard Cave Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Potion Shop Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Bomb Hut Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Bush Covered Lawn Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Pyramid Uncle Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('East Dark World Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Hammer Peg Area Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Maze Race Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('South Dark World Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Mire Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Dark Desert Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Desert Palace North Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Desert Palace Stairs Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Ice Lake Central Island Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Shopping Mall Mirror Spot', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('East Dark Death Mountain Teleporter (Top)', player), lambda state: state.can_lift_heavy_rocks(player) and state.has('Hammer', player) and state.has_Pearl(player)) # bunny cannot use hammer set_rule(world.get_entrance('East Dark Death Mountain Teleporter (Bottom)', player), lambda state: state.can_lift_heavy_rocks(player)) set_rule(world.get_entrance('West Dark World Teleporter', player), lambda state: ((state.has('Hammer', player) and state.can_lift_rocks(player)) or state.can_lift_heavy_rocks(player)) and state.has_Pearl(player)) diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index d13b4416..8445c1ae 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -2025,32 +2025,7 @@ open_mandatory_connections = [('Sanctuary S&Q', 'Sanctuary'), ('East Hyrule Teleporter', 'East Dark World'), ('South Hyrule Teleporter', 'South Dark World'), ('Desert Teleporter', 'Dark Desert'), - ('Lake Hylia Teleporter', 'Dark Lake Hylia Central Island'), - - # mirror - ('Spectacle Rock Mirror Spot', 'Spectacle Rock'), - ('East Death Mountain (Top) Mirror Spot', 'East Death Mountain (Top)'), - ('Dark Floating Island Mirror Spot', 'Death Mountain Floating Island'), - ('Spiral Cave Mirror Spot', 'Spiral Cave Ledge'), - ('Mimic Cave Mirror Spot', 'Mimic Cave Ledge'), - ('Isolated Ledge Mirror Spot', 'Fairy Ascension Ledge'), - ('Fairy Ascension Mirror Spot', 'Fairy Ascension Plateau'), - ('Bumper Cave Ledge Mirror Spot', 'Death Mountain Return Ledge'), - ('Bumper Cave Entrance Mirror Spot', 'Death Mountain Entrance'), - ('Graveyard Ledge Mirror Spot', 'Graveyard Ledge'), - ('Kings Grave Mirror Spot', 'Kings Grave Area'), - ('Dark Grassy Lawn Mirror Spot', 'Bush Covered Lawn'), - ('Hyrule Castle Ledge Mirror Spot', 'Hyrule Castle Ledge'), - ('Bat Cave Drop Ledge Mirror Spot', 'Bat Cave Ledge'), - ('Dig Game Mirror Spot', 'Maze Race Ledge'), - ('Desert Ledge Rocks Mirror Spot', 'Desert Palace Entrance (North) Spot'), - ('Desert Ledge Mirror Spot', 'Desert Ledge'), - ('Mire To Desert Stairs Mirror Spot', 'Desert Palace Stairs'), - ('Checkerboard Ledge Mirror Spot', 'Desert Checkerboard Ledge'), - ('Bombos Tablet Mirror Spot', 'Bombos Tablet Ledge'), - ('Cave 45 Mirror Spot', 'Cave 45 Ledge'), - ('Lake Hylia Island Mirror Spot', 'Lake Hylia Island'), - ('Lake Hylia Central Island Mirror Spot', 'Lake Hylia Central Island') + ('Lake Hylia Teleporter', 'Dark Lake Hylia Central Island') ] inverted_mandatory_connections = [('Sanctuary S&Q', 'Dark Sanctuary Hint'), @@ -2107,37 +2082,7 @@ inverted_mandatory_connections = [('Sanctuary S&Q', 'Dark Sanctuary Hint'), ('East Dark World Teleporter', 'Light World'), ('South Dark World Teleporter', 'Light World'), ('Dark Desert Teleporter', 'Light World'), - ('Dark Lake Hylia Teleporter', 'Lake Hylia Central Island'), - - # mirror - ('Skull Woods Mirror Spot', 'Skull Woods Forest (West)'), - ('West Dark World Mirror Spot', 'West Dark World'), - ('Death Mountain (Top) Mirror Spot', 'Dark Death Mountain (Top)'), - ('Death Mountain Mirror Spot', 'West Dark Death Mountain (Bottom)'), - ('East Death Mountain Mirror Spot (Top)', 'Dark Death Mountain (Top)'), - ('Floating Island Mirror Spot', 'Dark Death Mountain Floating Island'), - ('Dark Death Mountain Ledge Mirror Spot (East)', 'Dark Death Mountain Ledge'), - ('Dark Death Mountain Ledge Mirror Spot (West)', 'Dark Death Mountain Ledge'), - ('Laser Bridge Mirror Spot', 'Dark Death Mountain Isolated Ledge'), - ('East Death Mountain Mirror Spot (Bottom)', 'East Dark Death Mountain (Bottom)'), - ('Mountain Exit Ledge Mirror Spot', 'Bumper Cave Ledge'), - ('Mountain Entrance Mirror Spot', 'Bumper Cave Entrance'), - ('Catfish Mirror Spot', 'Catfish Area'), - ('Graveyard Cave Mirror Spot', 'West Dark World'), - ('Potion Shop Mirror Spot', 'Northeast Dark World'), - ('Bush Covered Lawn Mirror Spot', 'Dark Grassy Lawn'), - ('Bomb Hut Mirror Spot', 'West Dark World'), - ('Pyramid Uncle Mirror Spot', 'East Dark World'), - ('East Dark World Mirror Spot', 'East Dark World'), - ('Hammer Peg Area Mirror Spot', 'Hammer Peg Area'), - ('Maze Race Mirror Spot', 'South Dark World'), - ('South Dark World Mirror Spot', 'South Dark World'), - ('Mire Mirror Spot', 'Dark Desert'), - ('Dark Desert Ledge Mirror Spot', 'Dark Desert'), - ('Desert Palace Stairs Mirror Spot', 'Dark Desert'), - ('Desert Palace North Mirror Spot', 'Dark Desert'), - ('Ice Lake Central Island Mirror Spot', 'Lake Hylia Central Island'), - ('Shopping Mall Mirror Spot', 'Southeast Dark World') + ('Dark Lake Hylia Teleporter', 'Lake Hylia Central Island') ] # non-shuffled entrance links From b725774d96314e73503bab533064400728aeaaa3 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Fri, 30 Dec 2022 06:48:06 -0600 Subject: [PATCH 013/196] Adding new mirror connections --- OverworldShuffle.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 64be6969..099d5a9c 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -37,6 +37,8 @@ def create_dynamic_exits(world, player): mirror_connections = { + 'Skull Woods Forest (West)': ['Light World'], + 'West Dark Death Mountain (Bottom)': ['Spectacle Rock'], 'Dark Death Mountain (Top)': ['East Death Mountain (Top)'], @@ -44,17 +46,20 @@ mirror_connections = { 'Dark Death Mountain Ledge': ['Spiral Cave Ledge', 'Mimic Cave Ledge'], 'Dark Death Mountain Isolated Ledge': ['Fairy Ascension Ledge'], 'East Dark Death Mountain (Bushes)': ['Fairy Ascension Plateau'], + 'East Dark Death Mountain (Bottom)': ['East Death Mountain (Bottom)'], 'West Dark World': ['Graveyard Ledge', 'Kings Grave Area'], 'Bumper Cave Ledge': ['Death Mountain Return Ledge'], 'Bumper Cave Entrance': ['Death Mountain Entrance'], + 'Northeast Dark World': ['Potion Shop Area'], + 'Dark Grassy Lawn': ['Bush Covered Lawn'], 'Hammer Peg Area': ['Bat Cave Ledge'], - 'East Dark World': ['Hyrule Castle Ledge'], + 'East Dark World': ['Hyrule Castle Ledge', 'Hyrule Castle Courtyard'], 'Dark Desert': ['Desert Ledge', 'Desert Checkerboard Ledge', 'Desert Palace Stairs', 'Desert Palace Entrance (North) Spot'], @@ -63,6 +68,8 @@ mirror_connections = { 'Dark Lake Hylia Water': ['Lake Hylia Island'], 'Dark Lake Hylia Central Island': ['Lake Hylia Central Island'], + 'Southeast Dark World': ['Light World'], + 'Light World': ['Skull Woods Forest (West)', 'West Dark World', 'Hammer Peg Area', 'East Dark World', 'South Dark World', 'Dark Desert', 'Southeast Dark World'], @@ -82,6 +89,7 @@ mirror_connections = { 'Northeast Light World': ['Catfish Area'], 'Graveyard Ledge': ['West Dark World'], + 'Kings Grave Area': ['West Dark World'], 'Potion Shop Area': ['Northeast Dark World'], @@ -92,9 +100,12 @@ mirror_connections = { 'Maze Race Ledge': ['South Dark World'], + 'Cave 45 Ledge': ['South Dark World'], + 'Desert Palace Stairs': ['Dark Desert'], 'Desert Ledge': ['Dark Desert'], 'Desert Palace Entrance (North) Spot': ['Dark Desert'], + 'Desert Checkerboard Ledge': ['Dark Desert'], 'Lake Hylia Central Island': ['Dark Lake Hylia Central Island'] } \ No newline at end of file From cdf3d5b7768644045c1a79026ed4adf07eff1566 Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 15 Feb 2023 20:22:47 -0500 Subject: [PATCH 014/196] Update BaseClasses.py Fix --jsonout --- BaseClasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BaseClasses.py b/BaseClasses.py index edef87bd..3aa08442 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -2985,7 +2985,7 @@ class Spoiler(object): if self.shops: out['Shops'] = self.shops out['playthrough'] = self.playthrough - out['paths'] = {l:p for (l, p) in self.paths if l not in self.suppress_spoiler_locations} + out['paths'] = {l:p for (l, p) in self.paths.items() if l not in self.suppress_spoiler_locations} out['Bosses'] = self.bosses out['meta'] = self.metadata From d23d2d8323a82141b9a282b7b5de74037c21adc5 Mon Sep 17 00:00:00 2001 From: aerinon Date: Fri, 24 Feb 2023 15:45:37 -0700 Subject: [PATCH 015/196] Better support for customized start_inverntory with dungeon items (can be mixed with item pool) --- ItemList.py | 17 ++++++++++++++--- KeyDoorShuffle.py | 6 ++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/ItemList.py b/ItemList.py index b708b284..53524e6c 100644 --- a/ItemList.py +++ b/ItemList.py @@ -1014,8 +1014,19 @@ item_alternates = { def modify_pool_for_start_inventory(start_inventory, world, player): - # skips custom item pools - these shouldn't be adjusted if (world.customizer and world.customizer.get_item_pool()) or world.custom: + # custom item pools only adjust in dungeon items + for item in start_inventory: + if item.dungeon: + d = world.get_dungeon(item.dungeon, item.player) + match = next((i for i in d.all_items if i.name == item.name), None) + if match: + if match.map or match.compass: + d.dungeon_items.remove(match) + elif match.smallkey: + d.small_keys.remove(match) + elif match.bigkey and d.big_key == match: + d.big_key = None return for item in start_inventory: if item.player == player: @@ -1041,8 +1052,8 @@ def modify_pool_for_start_inventory(start_inventory, world, player): d.dungeon_items.remove(match) elif match.smallkey: d.small_keys.remove(match) - elif match.bigkey: - d.big_key.remove(match) + elif match.bigkey and d.big_key == match: + d.big_key = None def make_custom_item_pool(world, player, progressive, shuffle, difficulty, timer, goal, mode, swords, bombbag, customitemarray): diff --git a/KeyDoorShuffle.py b/KeyDoorShuffle.py index 2a39f38c..f8bda68e 100644 --- a/KeyDoorShuffle.py +++ b/KeyDoorShuffle.py @@ -2094,6 +2094,12 @@ def validate_key_placement(key_layout, world, player): if world.bigkeyshuffle[player]: max_counter = find_max_counter(key_layout) big_key_outside = bigkey_name not in (l.item.name for l in max_counter.free_locations if l.item) + for i in world.precollected_items: + if i.player == player and i.name == bigkey_name: + big_key_outside = True + break + if i.player == player and i.name == smallkey_name: + keys_outside += 1 for code, counter in key_layout.key_counters.items(): if len(counter.child_doors) == 0: From 7397d779ad8c87cb184b9c2cdc6af932705422b1 Mon Sep 17 00:00:00 2001 From: aerinon Date: Fri, 24 Feb 2023 16:20:29 -0700 Subject: [PATCH 016/196] Changing colorizing pots defaults --- BaseClasses.py | 2 +- CLI.py | 2 +- Rom.py | 5 ++--- source/tools/MysteryUtils.py | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index dd39cfc9..0dc89695 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -142,7 +142,7 @@ class World(object): set_player_attr('pot_contents', None) set_player_attr('pseudoboots', False) set_player_attr('collection_rate', False) - set_player_attr('colorizepots', False) + set_player_attr('colorizepots', True) set_player_attr('pot_pool', {}) set_player_attr('decoupledoors', False) set_player_attr('door_type_mode', 'original') diff --git a/CLI.py b/CLI.py index 536543f2..d1bc47d3 100644 --- a/CLI.py +++ b/CLI.py @@ -205,7 +205,7 @@ def parse_settings(): 'keydropshuffle': False, 'dropshuffle': False, 'pottery': 'none', - 'colorizepots': False, + 'colorizepots': True, 'shufflepots': False, 'mapshuffle': False, 'compassshuffle': False, diff --git a/Rom.py b/Rom.py index 1dd05a8f..6be923da 100644 --- a/Rom.py +++ b/Rom.py @@ -1585,9 +1585,8 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): Room0127.write_to_rom(snes_to_pc(0x2B8000), rom) if world.pot_contents[player]: - colorize_pots = is_mystery or (world.pottery[player] not in ['vanilla', 'lottery'] - and (world.colorizepots[player] - or world.pottery[player] in ['reduced', 'clustered'])) + colorize_pots = (world.pottery[player] != 'vanilla' + and (world.colorizepots[player] or world.pottery[player] in ['reduced', 'clustered'])) if world.pot_contents[player].size() > 0x2800: raise Exception('Pot table is too big for current area') world.pot_contents[player].write_pot_data_to_rom(rom, colorize_pots) diff --git a/source/tools/MysteryUtils.py b/source/tools/MysteryUtils.py index 322ed447..2bdcdcd7 100644 --- a/source/tools/MysteryUtils.py +++ b/source/tools/MysteryUtils.py @@ -102,7 +102,7 @@ def roll_settings(weights): ret.dropshuffle = get_choice('dropshuffle') == 'on' or keydropshuffle ret.pottery = get_choice('pottery') if 'pottery' in weights else 'none' ret.pottery = 'keys' if ret.pottery == 'none' and keydropshuffle else ret.pottery - ret.colorizepots = get_choice('colorizepots') == 'on' + ret.colorizepots = get_choice_default('colorizepots', default='on') == 'on' ret.shufflepots = get_choice('pot_shuffle') == 'on' ret.mixed_travel = get_choice('mixed_travel') if 'mixed_travel' in weights else 'prevent' ret.standardize_palettes = (get_choice('standardize_palettes') if 'standardize_palettes' in weights From 6c0da515b440827c40050d9d916b1d51d899eb16 Mon Sep 17 00:00:00 2001 From: aerinon Date: Fri, 24 Feb 2023 17:00:25 -0700 Subject: [PATCH 017/196] Fix dungeon_only + pottery modes --- source/item/FillUtil.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/source/item/FillUtil.py b/source/item/FillUtil.py index 0252673f..f581f3fb 100644 --- a/source/item/FillUtil.py +++ b/source/item/FillUtil.py @@ -3,7 +3,7 @@ import logging from collections import defaultdict from source.item.District import resolve_districts -from BaseClasses import PotItem, PotFlags +from BaseClasses import PotItem, PotFlags, LocationType from DoorShuffle import validate_vanilla_reservation from Dungeons import dungeon_table from Items import item_table, ItemFactory @@ -82,8 +82,8 @@ def create_item_pool_config(world): if pot.item not in [PotItem.Key, PotItem.Hole, PotItem.Switch]: item = pot_items[pot.item] descriptor = 'Large Block' if pot.flags & PotFlags.Block else f'Pot #{pot_index+1}' - location = f'{pot.room} {descriptor}' - config.static_placement[player][item].append(location) + loc = f'{pot.room} {descriptor}' + config.static_placement[player][item].append(loc) if world.shopsanity[player]: for item, locs in shop_vanilla_mapping.items(): config.static_placement[player][item].extend(locs) @@ -164,6 +164,10 @@ def create_item_pool_config(world): mode_grouping['Heart Containers'] + mode_grouping['GT Trash'] + mode_grouping['Small Keys'] + mode_grouping['Compasses'] + mode_grouping['Maps'] + mode_grouping['Key Drops'] + mode_grouping['Pot Keys'] + mode_grouping['Big Key Drops']) + dungeon_set = set(dungeon_set) + for loc in world.get_locations(): + if loc.parent_region.dungeon and loc.type in [LocationType.Pot, LocationType.Drop]: + dungeon_set.add(loc.name) for player in range(1, world.players + 1): config.item_pool[player] = determine_major_items(world, player) config.location_groups[0].locations = set(dungeon_set) From 3047826808deb0d5feebefb34945d8d56c4d52d8 Mon Sep 17 00:00:00 2001 From: aerinon Date: Mon, 27 Feb 2023 14:41:43 -0700 Subject: [PATCH 018/196] Fix AllowAccidentalGlitches flag --- Rom.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rom.py b/Rom.py index 6be923da..5b137612 100644 --- a/Rom.py +++ b/Rom.py @@ -1489,7 +1489,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): rom.write_byte(0x1800A3, 0x01) # enable correct world setting behaviour after agahnim kills rom.write_byte(0x1800A4, 0x01 if world.logic[player] != 'nologic' else 0x00) # enable POD EG fix rom.write_byte(0x180042, 0x01 if world.save_and_quit_from_boss else 0x00) # Allow Save and Quit after boss kill - rom.write_byte(0x180358, 0x01 if world.logic[player] == 'nologic' else 0x00) + rom.write_byte(0x180358, 0x01 if (world.logic[player] in ['owglitches', 'nologic']) else 0x00) # remove shield from uncle rom.write_bytes(0x6D253, [0x00, 0x00, 0xf6, 0xff, 0x00, 0x0E]) From 1dc3b13449fa3fbcee462e70a7e97d7aaa231f90 Mon Sep 17 00:00:00 2001 From: aerinon Date: Mon, 27 Feb 2023 14:42:52 -0700 Subject: [PATCH 019/196] Change info message to debug for cleaner output Possible generation error --- DungeonGenerator.py | 2 +- Rules.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/DungeonGenerator.py b/DungeonGenerator.py index e429719a..f97f8ecf 100644 --- a/DungeonGenerator.py +++ b/DungeonGenerator.py @@ -3572,7 +3572,7 @@ def check_for_valid_layout(builder, sector_list, builder_info): builder.exception_list = list(sector_list) return True, {}, package except (GenerationException, NeutralizingException, OtherGenException) as e: - logging.getLogger('').info(f'Bailing on this layout for {builder.name}', exc_info=1) + logging.getLogger('').debug(f'Bailing on this layout for {builder.name}', exc_info=1) builder.split_dungeon_map = None builder.valid_proposal = None if temp_builder.name == 'Hyrule Castle' and temp_builder.throne_door: diff --git a/Rules.py b/Rules.py index ed6367dd..5015c019 100644 --- a/Rules.py +++ b/Rules.py @@ -2110,6 +2110,8 @@ def eval_small_key_door_main(state, door_name, dungeon, player): if state.is_door_open(door_name, player): return True key_logic = state.world.key_logic[player][dungeon] + if door_name not in key_logic.door_rules: + return False door_rule = key_logic.door_rules[door_name] door_openable = False for ruleType, number in door_rule.new_rules.items(): From a75b36e2eb7d1e4388f3e2eaa994c71e9a27ce7d Mon Sep 17 00:00:00 2001 From: aerinon Date: Wed, 1 Mar 2023 16:23:03 -0700 Subject: [PATCH 020/196] ER2 Minor issues --- source/overworld/EntranceShuffle2.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index a89e6085..51a702dd 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -1630,7 +1630,7 @@ default_dw = { 'Palace of Darkness Exit', 'Swamp Palace Exit', 'Turtle Rock Exit (Front)', 'Turtle Rock Ledge Exit (West)', 'Turtle Rock Ledge Exit (East)', 'Turtle Rock Isolated Ledge Exit', 'Bumper Cave Exit (Top)', 'Bumper Cave Exit (Bottom)', 'Superbunny Cave Exit (Top)', 'Superbunny Cave Exit (Bottom)', - 'Hookshot Cave Front Exit', 'Hookshot Cave Back Exit', 'Ganons Tower Exit', 'Pyramid Exit', + 'Hookshot Cave Front Exit', 'Hookshot Cave Back Exit', 'Ganons Tower Exit', 'Pyramid Exit', 'Bonk Fairy (Dark)', 'Dark Lake Hylia Healer Fairy', 'Dark Lake Hylia Ledge Healer Fairy', 'Dark Desert Healer Fairy', 'Dark Death Mountain Healer Fairy', 'Cave Shop (Dark Death Mountain)', 'Pyramid Fairy', 'East Dark World Hint', 'Palace of Darkness Hint', 'Big Bomb Shop', 'Village of Outcasts Shop', 'Dark Lake Hylia Shop', @@ -1653,7 +1653,7 @@ default_lw = { 'Spectacle Rock Cave Exit (Top)', 'Spectacle Rock Cave Exit (Peak)', 'Paradox Cave Exit (Bottom)', 'Paradox Cave Exit (Middle)', 'Paradox Cave Exit (Top)', 'Fairy Ascension Cave Exit (Bottom)', 'Fairy Ascension Cave Exit (Top)', 'Spiral Cave Exit', 'Spiral Cave Exit (Top)', 'Waterfall of Wishing', 'Dam', - 'Blinds Hideout', 'Lumberjack House', 'Bonk Fairy (Light)', 'Bonk Fairy (Dark)', 'Lake Hylia Healer Fairy', + 'Blinds Hideout', 'Lumberjack House', 'Bonk Fairy (Light)', 'Lake Hylia Healer Fairy', 'Swamp Healer Fairy', 'Desert Healer Fairy', 'Fortune Teller (Light)', 'Lake Hylia Fortune Teller', 'Kings Grave', 'Tavern', 'Chicken House', 'Aginahs Cave', 'Sahasrahlas Hut', 'Cave Shop (Lake Hylia)', 'Capacity Upgrade', 'Blacksmiths Hut', 'Sick Kids House', 'Lost Woods Gamble', 'Snitch Lady (East)', 'Snitch Lady (West)', 'Bush Covered House', @@ -1698,7 +1698,7 @@ DW_Entrances = ['Bumper Cave (Bottom)', 'Superbunny Cave (Top)', 'Superbunny Ca 'Dark Lake Hylia Ledge Hint', 'Chest Game', 'Dark Desert Fairy', 'Dark Lake Hylia Ledge Fairy', 'Fortune Teller (Dark)', 'Dark World Hammer Peg Cave', 'Pyramid Entrance', 'Skull Woods First Section Door', 'Skull Woods Second Section Door (East)', - 'Skull Woods Second Section Door (West)', + 'Skull Woods Second Section Door (West)', 'Ganons Tower', 'Inverted Dark Sanctuary', 'Inverted Links House', 'Inverted Agahnims Tower'] LW_Must_Exit = ['Desert Palace Entrance (East)'] From 00b06c53d64eb9832507148008e31f061b3c82e0 Mon Sep 17 00:00:00 2001 From: aerinon Date: Wed, 1 Mar 2023 16:28:47 -0700 Subject: [PATCH 021/196] Rom updates and version update --- Main.py | 2 +- RELEASENOTES.md | 8 ++++++++ Rom.py | 2 +- data/base2current.bps | Bin 93908 -> 93872 bytes 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Main.py b/Main.py index 7266628d..52073cce 100644 --- a/Main.py +++ b/Main.py @@ -34,7 +34,7 @@ from source.overworld.EntranceShuffle2 import link_entrances_new from source.tools.BPS import create_bps_from_data from source.classes.CustomSettings import CustomSettings -__version__ = '1.2.0.9-u' +__version__ = '1.2.0.10u' from source.classes.BabelFish import BabelFish diff --git a/RELEASENOTES.md b/RELEASENOTES.md index d5a492b1..6cb841e6 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -108,6 +108,14 @@ These are now independent of retro mode and have three options: None, Random, an * Bonk Fairy (Dark) # Bug Fixes and Notes +* 1.2.0.10u + * Fixed overrun issues with edge transitions + * Better support for customized start_inventory with dungeon items + * Colorized pots now available with lottery. Default is on. + * Dungeon_only support pottery + * Fix AllowAccidentalGlitches flag in OWG + * Potential fix for mirror portal and entering cave on same frame + * A few other minor issues, generation and graphical * 1.2.0.9-u * Disallowed standard exits (due to ER) are now graphically half blocked instead of missing * Graphical issues with Sanctuary and Swamp Hub lobbies are fixed diff --git a/Rom.py b/Rom.py index 5b137612..0d9b0849 100644 --- a/Rom.py +++ b/Rom.py @@ -37,7 +37,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '67279b96a589f09e3ba8393a5bc5f071' +RANDOMIZERBASEHASH = 'd981a1fc7408ecbb30fa44135c7239b7' class JsonRom(object): diff --git a/data/base2current.bps b/data/base2current.bps index be3d11ea1f94a232964df475e95479bc094ec0cc..b5582c3f917243a2eedb422ae856bbf82f7f21cd 100644 GIT binary patch delta 3335 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 delta 3375 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 HciH~|=+T7u From c3dd6bac795cb0fb65e9988cccd18862a6847571 Mon Sep 17 00:00:00 2001 From: aerinon Date: Fri, 3 Mar 2023 16:52:29 -0700 Subject: [PATCH 022/196] Murderdactyl ohko rule --- Rules.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Rules.py b/Rules.py index 5015c019..9e048b38 100644 --- a/Rules.py +++ b/Rules.py @@ -873,6 +873,9 @@ def default_rules(world, player): set_rule(world.get_entrance('Graveyard Ledge Mirror Spot', player), lambda state: state.has_Pearl(player) and state.has_Mirror(player)) set_rule(world.get_entrance('Bumper Cave Entrance Rock', player), lambda state: state.has_Pearl(player) and state.can_lift_rocks(player)) set_rule(world.get_entrance('Bumper Cave Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) + # this more like an ohko rule - dependent on bird being present too - so enemizer could turn this off? + set_rule(world.get_entrance('Bumper Cave Ledge Drop', player), lambda state: state.has_Pearl(player) and + (state.has('Cape', player) or state.has('Cane of Byrna', player) or state.has_sword(player))) set_rule(world.get_entrance('Bat Cave Drop Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Dark World Hammer Peg Cave', player), lambda state: state.has_Pearl(player) and state.has('Hammer', player)) set_rule(world.get_entrance('Village of Outcasts Eastern Rocks', player), lambda state: state.has_Pearl(player) and state.can_lift_heavy_rocks(player)) From 9aab5a2c955e70dd2e6205273f509eb275c54c58 Mon Sep 17 00:00:00 2001 From: aerinon Date: Fri, 3 Mar 2023 16:53:23 -0700 Subject: [PATCH 023/196] Beemizer fix for shopsanity, pottery, etc. --- ItemList.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/ItemList.py b/ItemList.py index 53524e6c..845d0d78 100644 --- a/ItemList.py +++ b/ItemList.py @@ -372,21 +372,7 @@ def generate_itempool(world, player): for i in range(4): next(adv_heart_pieces).advancement = True - beeweights = {'0': {None: 100}, - '1': {None: 75, 'trap': 25}, - '2': {None: 40, 'trap': 40, 'bee': 20}, - '3': {'trap': 50, 'bee': 50}, - '4': {'trap': 100}} - def beemizer(item): - if world.beemizer[item.player] and not item.advancement and not item.priority and not item.type: - choice = random.choices(list(beeweights[world.beemizer[item.player]].keys()), weights=list(beeweights[world.beemizer[item.player]].values()))[0] - return item if not choice else ItemFactory("Bee Trap", player) if choice == 'trap' else ItemFactory("Bee", player) - return item - - if not skip_pool_adjustments: - world.itempool += [beemizer(item) for item in items] - else: - world.itempool += items + world.itempool += items # shuffle medallions mm_medallion, tr_medallion = None, None @@ -439,6 +425,20 @@ def generate_itempool(world, player): # modfiy based on start inventory, if any modify_pool_for_start_inventory(start_inventory, world, player) + beeweights = {'0': {None: 100}, + '1': {None: 75, 'trap': 25}, + '2': {None: 40, 'trap': 40, 'bee': 20}, + '3': {'trap': 50, 'bee': 50}, + '4': {'trap': 100}} + def beemizer(item): + if world.beemizer[item.player] and not item.advancement and not item.priority and not item.type: + choice = random.choices(list(beeweights[world.beemizer[item.player]].keys()), weights=list(beeweights[world.beemizer[item.player]].values()))[0] + return item if not choice else ItemFactory("Bee Trap", player) if choice == 'trap' else ItemFactory("Bee", player) + return item + + if not skip_pool_adjustments: + world.itempool = [beemizer(item) for item in world.itempool] + # increase pool if not enough items ttl_locations = sum(1 for x in world.get_unfilled_locations(player) if '- Prize' not in x.name) pool_size = count_player_dungeon_item_pool(world, player) From a5da504b90862a92b0fac742e53503628cb97bbd Mon Sep 17 00:00:00 2001 From: aerinon Date: Fri, 3 Mar 2023 16:53:50 -0700 Subject: [PATCH 024/196] Fix for district shuffle's placeholder issue --- source/item/FillUtil.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/item/FillUtil.py b/source/item/FillUtil.py index f581f3fb..c3881e7a 100644 --- a/source/item/FillUtil.py +++ b/source/item/FillUtil.py @@ -426,7 +426,8 @@ def filter_locations(item_to_place, locations, world, vanilla_skip=False, potion return filtered if len(filtered) > 0 else locations if world.algorithm == 'district': config = world.item_pool_config - if item_to_place == 'Placeholder' or item_to_place.name in config.item_pool[item_to_place.player]: + if ((isinstance(item_to_place,str) and item_to_place == 'Placeholder') + or item_to_place.name in config.item_pool[item_to_place.player]): restricted = config.location_groups[0].locations filtered = [l for l in locations if l.name in restricted and l.player in restricted[l.name]] return filtered if len(filtered) > 0 else locations From 060092a53eeecbf59e3cf6f3d397f56e842f884e Mon Sep 17 00:00:00 2001 From: Thomas Prescott Date: Fri, 3 Mar 2023 21:55:02 -0600 Subject: [PATCH 025/196] add ability to disable forfeits --- MultiServer.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MultiServer.py b/MultiServer.py index 4108b8dd..cf9cd952 100644 --- a/MultiServer.py +++ b/MultiServer.py @@ -46,6 +46,9 @@ class Context: self.lookup_name_to_id = {} self.lookup_id_to_name = {} + self.disable_client_forfeit = False + + async def send_msgs(websocket, msgs): if not websocket or not websocket.open or websocket.closed: return @@ -281,6 +284,9 @@ async def process_client_cmd(ctx : Context, client : Client, cmd, args): if args.startswith('!players'): notify_all(ctx, get_connected_players_string(ctx)) if args.startswith('!forfeit'): + if ctx.disable_client_forfeit: + notify_client(client, 'Forfeit is currently disabled server-side.') + return forfeit_player(ctx, client.team, client.slot) if args.startswith('!countdown'): try: From 2f61dceb0e6af90ba7aec2bd70400a5a9c43164d Mon Sep 17 00:00:00 2001 From: codemann8 Date: Fri, 3 Mar 2023 20:29:19 -0600 Subject: [PATCH 026/196] Placing Sanc Drop in DW if HC in DW and non-crossworld --- source/overworld/EntranceShuffle2.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index fe3a2f89..349af41c 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -442,14 +442,18 @@ def do_holes_and_linked_drops(entrances, exits, avail, cross_world, keep_togethe hole_targets.append((target_exit, target_drop)) random.shuffle(hole_entrances) - if not cross_world and avail.is_sanc_forced_in_hc() and 'Sanctuary Grave' in holes_to_shuffle: - lw_entrance = next(entrance for entrance in hole_entrances if entrance[0] in LW_Entrances) - hole_entrances.remove(lw_entrance) + if not cross_world and 'Sanctuary Grave' in holes_to_shuffle: + hc = avail.world.get_entrance('Hyrule Castle Exit (South)', avail.player) + if hc.connected_region and hc.connected_region.type == RegionType.DarkWorld: + chosen_entrance = next(entrance for entrance in hole_entrances if entrance[0] in DW_Entrances) + if not chosen_entrance: + chosen_entrance = next(entrance for entrance in hole_entrances if entrance[0] in LW_Entrances) + hole_entrances.remove(chosen_entrance) sanc_interior = next(target for target in hole_targets if target[0] == 'Sanctuary Exit') hole_targets.remove(sanc_interior) - connect_two_way(lw_entrance[0], sanc_interior[0], avail) # two-way exit - connect_entrance(lw_entrance[1], sanc_interior[1], avail) # hole - remove_from_list(entrances, [lw_entrance[0], lw_entrance[1]]) + connect_two_way(chosen_entrance[0], sanc_interior[0], avail) # two-way exit + connect_entrance(chosen_entrance[1], sanc_interior[1], avail) # hole + remove_from_list(entrances, [chosen_entrance[0], chosen_entrance[1]]) remove_from_list(exits, [sanc_interior[0], sanc_interior[1]]) random.shuffle(hole_targets) From cc84c4e9b441d22ce2d2c767f3e063d835889d69 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 5 Mar 2023 01:26:24 -0600 Subject: [PATCH 027/196] Adding OWR Tile Flip to Customizer --- OverworldShuffle.py | 51 ++++++++++++++++++++++++++++---- docs/Customizer.md | 29 ++++++++++++++---- docs/customizer_example.yaml | 8 +++++ docs/standardinverted.yaml | 10 +++++++ source/classes/CustomSettings.py | 6 ++++ 5 files changed, 93 insertions(+), 11 deletions(-) create mode 100644 docs/standardinverted.yaml diff --git a/OverworldShuffle.py b/OverworldShuffle.py index c73c5ea6..0854d1e1 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -632,17 +632,56 @@ def shuffle_tiles(world, groups, result_list, do_grouped, player): parity[5] -= 1 group_parity[group[0]] = parity - attempts = 1000 + # customizer adjustments + undefined_chance = 50 + flipped_groups = list() + always_removed = list() + if world.customizer: + if not do_grouped: + custom_flips = world.customizer.get_owtileflips() + if custom_flips: + nonflipped_groups = list() + forced_flips = list() + forced_nonflips = list() + player_key = player + if 'undefined_chance' in custom_flips[player_key]: + undefined_chance = custom_flips[player_key]['undefined_chance'] + if 'force_flip' in custom_flips[player_key]: + forced_flips = custom_flips[player_key]['force_flip'] + if 'force_no_flip' in custom_flips[player_key]: + forced_nonflips = custom_flips[player_key]['force_no_flip'] + + for group in groups: + if any(owid in group[0] for owid in forced_nonflips): + nonflipped_groups.append(group) + if any(owid in group[0] for owid in forced_flips): + flipped_groups.append(group) + + # Check if there are any groups that appear in both sets + if any(group in flipped_groups for group in nonflipped_groups): + raise GenerationException('Conflict found when flipping tiles') + + for g in nonflipped_groups: + always_removed.append(g) + if undefined_chance == 0: + for g in [g for g in groups if g not in flipped_groups + always_removed]: + always_removed.append(g) + + attempts = 1 + if 0 < undefined_chance < 100: + # do roughly 1000 attempts at a full list + attempts = len(groups) - len(always_removed) + attempts = (attempts ** 1.9) + (attempts * 10) + 1 while True: if attempts == 0: # expected to only occur with custom flips raise GenerationException('Could not find valid tile flips') # tile shuffle happens here - removed = list() - for group in groups: - #if 0x1b in group[0] or 0x13 in group[0] or (0x1a in group[0] and world.owCrossed[player] == 'none'): # TODO: Standard + Inverted - if random.randint(0, 1): - removed.append(group) + removed = copy.deepcopy(always_removed) + if 0 < undefined_chance < 100: + for group in [g for g in groups if g not in always_removed]: + if group not in flipped_groups and random.randint(1, 100) > undefined_chance: + removed.append(group) # save shuffled tiles to list new_results = [[],[],[]] diff --git a/docs/Customizer.md b/docs/Customizer.md index b95081bd..9e45635a 100644 --- a/docs/Customizer.md +++ b/docs/Customizer.md @@ -86,7 +86,30 @@ You may define an item, and a list of locations. The locations may be weighted i #### NotPlacementGroup You may define an item and a list of locations that an item should not be placed at. This will apply to all items of that type. The logic is considered for this. If it is otherwise impossible, the item will be considered for the listed locations. This is important for small key layouts mostly, but it will try other locations first. - + +### ow-tileflips + +This must be defined by player. Each player number should be listed with the appropriate sections and each of these players MUST have `ow_mixed: true` in the `settings` section in order for any values here to take effect. This section has three primary subsections: `force_flip`, `force_no_flip`, and `undefined`. + +#### force_flip / force_no_flip + +`force_flip` and `force_no_flip` should be used for tiles you want to flip or not flip. These sections are optional but must contain a list of OW Screen IDs. It is common to reference OW Screen IDs in hexadecimal (altho decimal is okay to use, if preferred), which range from: + 0x00 to 0x3f - Light World + 0x40 to 0x7f - Dark World + 0x80 - Pedestal/Hobo + 0x81 - Zoras Domain + +Here is an example which forces Links House and Sanctuary screens to stay in their original worlds. Note: It is unnecessary to supply both worlds' IDs. Links House is 0x2c and Big Bomb Shop is 0x6c. +``` +force_no_flip: + - 0x2c + - 0x13 +``` + +#### undefined_chance + +`undefined_chance` should be used to determine how to handle all the remaining tiles that aren't explicitly defined in the earlier step. This represents the percent chance a tile will flip. This value can be set from 0 to 100 (default is 50). A value of 0 means there is a 0% chance it will be flipped. + ### entrances This must be defined by player. Each player number should be listed with the appropriate sections. This section has three primary subsections: `entrances`, `exits`, and `two-way`. @@ -111,10 +134,6 @@ This must be defined by player. Each player number should be listed with the app `Chicken House: Kakariko Shop` if you walk into Chicken House door, you will in the Kakariko Shop. -##### Known Issues - -Chris Houlihan and Links House should be specified together or not at all. - ### doors This must be defined by player. Each player number should be listed with the appropriate sections. This section has three primary subsections: `lobbies` and `doors`. diff --git a/docs/customizer_example.yaml b/docs/customizer_example.yaml index 3d0c7624..188c17d6 100644 --- a/docs/customizer_example.yaml +++ b/docs/customizer_example.yaml @@ -61,6 +61,14 @@ placements: Palace of Darkness - Big Chest: Hammer Capacity Upgrade - Left: Moon Pearl Turtle Rock - Pokey 2 Key Drop: Ice Rod +ow-tileflips: + 1: + force_flip: + - 0x1b + force_no_flip: + - 0x2c + - 0x18 + undefined_chance: 50 entrances: 1: entrances: diff --git a/docs/standardinverted.yaml b/docs/standardinverted.yaml new file mode 100644 index 00000000..c5590090 --- /dev/null +++ b/docs/standardinverted.yaml @@ -0,0 +1,10 @@ +meta: + players: 1 +settings: + 1: + mode: standard + ow_mixed: true +ow-tileflips: + 1: + undefined_chance: 100 + diff --git a/source/classes/CustomSettings.py b/source/classes/CustomSettings.py index fd15253f..8108712e 100644 --- a/source/classes/CustomSettings.py +++ b/source/classes/CustomSettings.py @@ -72,6 +72,7 @@ class CustomSettings(object): args.mystery = True else: settings = defaultdict(lambda: None, player_setting) + args.ow_mixed[p] = get_setting(settings['ow_mixed'], args.ow_mixed[p]) args.shuffle[p] = get_setting(settings['shuffle'], args.shuffle[p]) args.door_shuffle[p] = get_setting(settings['door_shuffle'], args.door_shuffle[p]) args.logic[p] = get_setting(settings['logic'], args.logic[p]) @@ -176,6 +177,11 @@ class CustomSettings(object): return self.file_source['advanced_placements'] return None + def get_owtileflips(self): + if 'ow-tileflips' in self.file_source: + return self.file_source['ow-tileflips'] + return None + def get_entrances(self): if 'entrances' in self.file_source: return self.file_source['entrances'] From 074894750213ac80097f54ab003c7db2726e5284 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 5 Mar 2023 19:31:15 -0600 Subject: [PATCH 028/196] Version bump 0.3.0.1 --- CHANGELOG.md | 9 ++++++++- OverworldShuffle.py | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48a0a29b..f782574c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,14 @@ # Changelog +## 0.3.0.1 +- \~Merged in DR v1.2.0.10~ + - Fixed some door landing issues +- Added Customizer support for OWR Tile Flips + - Added 'Standard+Inverted' template customizer yaml +- Fixed some ER issues with placing Sanc Drop in non-crossed ER + ## 0.3.0.0 -- Merged in all DR Customizer features since its initial release up to v1.2.0.9 +- \~Merged in all DR Customizer features since its initial release up to v1.2.0.9~ - Major revamp of Aerinon's ER 2.0 to better support OWR modes - Fixed various incorrect logic issues (Inverted flute spots, Bomb Shop start, etc) - Flute is disabled in rain state except glitched modes diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 0854d1e1..a49a6db5 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -7,7 +7,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType from OverworldGlitchRules import create_owg_connections from Utils import bidict -version_number = '0.3.0.0' +version_number = '0.3.0.1' # branch indicator is intentionally different across branches version_branch = '-u' From da71e9ba12dc110a91e3a95c5b7ce1bef498d57d Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 6 Mar 2023 15:16:23 -0600 Subject: [PATCH 029/196] Placing Sanc Drop in DW if HC in DW and non-crossworld --- source/overworld/EntranceShuffle2.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index 349af41c..e7010520 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -444,17 +444,19 @@ def do_holes_and_linked_drops(entrances, exits, avail, cross_world, keep_togethe random.shuffle(hole_entrances) if not cross_world and 'Sanctuary Grave' in holes_to_shuffle: hc = avail.world.get_entrance('Hyrule Castle Exit (South)', avail.player) + chosen_entrance = None if hc.connected_region and hc.connected_region.type == RegionType.DarkWorld: chosen_entrance = next(entrance for entrance in hole_entrances if entrance[0] in DW_Entrances) if not chosen_entrance: chosen_entrance = next(entrance for entrance in hole_entrances if entrance[0] in LW_Entrances) - hole_entrances.remove(chosen_entrance) - sanc_interior = next(target for target in hole_targets if target[0] == 'Sanctuary Exit') - hole_targets.remove(sanc_interior) - connect_two_way(chosen_entrance[0], sanc_interior[0], avail) # two-way exit - connect_entrance(chosen_entrance[1], sanc_interior[1], avail) # hole - remove_from_list(entrances, [chosen_entrance[0], chosen_entrance[1]]) - remove_from_list(exits, [sanc_interior[0], sanc_interior[1]]) + if chosen_entrance: + hole_entrances.remove(chosen_entrance) + sanc_interior = next(target for target in hole_targets if target[0] == 'Sanctuary Exit') + hole_targets.remove(sanc_interior) + connect_two_way(chosen_entrance[0], sanc_interior[0], avail) # two-way exit + connect_entrance(chosen_entrance[1], sanc_interior[1], avail) # hole + remove_from_list(entrances, [chosen_entrance[0], chosen_entrance[1]]) + remove_from_list(exits, [sanc_interior[0], sanc_interior[1]]) random.shuffle(hole_targets) for entrance, drop in hole_entrances: From 87ab4a8c8ad45f09203158e274b5f1be42f3a1e2 Mon Sep 17 00:00:00 2001 From: aerinon Date: Mon, 6 Mar 2023 16:10:07 -0700 Subject: [PATCH 030/196] Update baserom and release notes --- Main.py | 2 +- RELEASENOTES.md | 6 ++++++ Rom.py | 8 +++++++- data/base2current.bps | Bin 93872 -> 93909 bytes 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Main.py b/Main.py index 52073cce..2a334081 100644 --- a/Main.py +++ b/Main.py @@ -34,7 +34,7 @@ from source.overworld.EntranceShuffle2 import link_entrances_new from source.tools.BPS import create_bps_from_data from source.classes.CustomSettings import CustomSettings -__version__ = '1.2.0.10u' +__version__ = '1.2.0.11u' from source.classes.BabelFish import BabelFish diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 6cb841e6..ac51ccda 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -108,6 +108,12 @@ These are now independent of retro mode and have three options: None, Random, an * Bonk Fairy (Dark) # Bug Fixes and Notes +* 1.2.0.11u + * Fixed an issue with lower layer doors in Standard + * Fix for doors in cave state (will no longer be vanilla) + * Added a logic rule for th murderdactyl near bumper ledge for OHKO purposes + * Fix for beemizer including modes with an increased item pool + * Fix for district algoritm * 1.2.0.10u * Fixed overrun issues with edge transitions * Better support for customized start_inventory with dungeon items diff --git a/Rom.py b/Rom.py index 0d9b0849..981b554a 100644 --- a/Rom.py +++ b/Rom.py @@ -37,7 +37,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = 'd981a1fc7408ecbb30fa44135c7239b7' +RANDOMIZERBASEHASH = 'badc0c787f7ab5e0ad05fb517953849a' class JsonRom(object): @@ -1591,6 +1591,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): raise Exception('Pot table is too big for current area') world.pot_contents[player].write_pot_data_to_rom(rom, colorize_pots) + write_enemizer_tweaks(rom, world, player) write_strings(rom, world, player, team) # write initial sram @@ -1681,6 +1682,11 @@ def write_custom_shops(rom, world, player): rom.write_bytes(0x184900, items_data) +def write_enemizer_tweaks(rom, world, player): + if world.enemy_shuffle[player] != 'none': + rom.write_byte(snes_to_pc(0x1DF6D8, 0)) # lets enemies walk on water instead of clipping into infinity? + rom.write_byte(snes_to_pc(0x0DB6B3, 0x82)) # hovers don't need water necessarily? + def hud_format_text(text): output = bytes() for char in text.lower(): diff --git a/data/base2current.bps b/data/base2current.bps index b5582c3f917243a2eedb422ae856bbf82f7f21cd..57c2f8b618b86d3c6a8124c7723b85ac68063570 100644 GIT binary patch delta 1985 zcmW-hdr(u^9mnàjz0YX4|T`r&A0~ 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 Date: Mon, 6 Mar 2023 16:29:58 -0700 Subject: [PATCH 031/196] Update for enemizer bits --- RELEASENOTES.md | 3 ++- Rom.py | 4 ++-- source/classes/CustomSettings.py | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index ac51ccda..e87d4a22 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -112,8 +112,9 @@ These are now independent of retro mode and have three options: None, Random, an * Fixed an issue with lower layer doors in Standard * Fix for doors in cave state (will no longer be vanilla) * Added a logic rule for th murderdactyl near bumper ledge for OHKO purposes + * Enemizer alteration for Hovers and normal enemies in shallow water * Fix for beemizer including modes with an increased item pool - * Fix for district algoritm + * Fix for district algorithm * 1.2.0.10u * Fixed overrun issues with edge transitions * Better support for customized start_inventory with dungeon items diff --git a/Rom.py b/Rom.py index 981b554a..13b4f133 100644 --- a/Rom.py +++ b/Rom.py @@ -1684,8 +1684,8 @@ def write_custom_shops(rom, world, player): def write_enemizer_tweaks(rom, world, player): if world.enemy_shuffle[player] != 'none': - rom.write_byte(snes_to_pc(0x1DF6D8, 0)) # lets enemies walk on water instead of clipping into infinity? - rom.write_byte(snes_to_pc(0x0DB6B3, 0x82)) # hovers don't need water necessarily? + rom.write_byte(snes_to_pc(0x1DF6D8), 0) # lets enemies walk on water instead of clipping into infinity? + rom.write_byte(snes_to_pc(0x0DB6B3), 0x82) # hovers don't need water necessarily? def hud_format_text(text): output = bytes() diff --git a/source/classes/CustomSettings.py b/source/classes/CustomSettings.py index fd15253f..53105764 100644 --- a/source/classes/CustomSettings.py +++ b/source/classes/CustomSettings.py @@ -129,8 +129,8 @@ class CustomSettings(object): args.mapshuffle[p] = True args.compassshuffle[p] = True - args.shufflebosses[p] = get_setting(settings['shufflebosses'], args.shufflebosses[p]) - args.shuffleenemies[p] = get_setting(settings['shuffleenemies'], args.shuffleenemies[p]) + args.shufflebosses[p] = get_setting(settings['boss_shuffle'], args.shufflebosses[p]) + args.shuffleenemies[p] = get_setting(settings['enemy_shuffle'], args.shuffleenemies[p]) args.enemy_health[p] = get_setting(settings['enemy_health'], args.enemy_health[p]) args.enemy_damage[p] = get_setting(settings['enemy_damage'], args.enemy_damage[p]) args.shufflepots[p] = get_setting(settings['shufflepots'], args.shufflepots[p]) From 35e7784445dc2b67dd50a4393e10617b481094a9 Mon Sep 17 00:00:00 2001 From: Thomas Prescott Date: Mon, 6 Mar 2023 23:21:24 -0600 Subject: [PATCH 032/196] clarify forfeit disabled --- MultiServer.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MultiServer.py b/MultiServer.py index cf9cd952..a9f9e9e2 100644 --- a/MultiServer.py +++ b/MultiServer.py @@ -285,9 +285,9 @@ async def process_client_cmd(ctx : Context, client : Client, cmd, args): notify_all(ctx, get_connected_players_string(ctx)) if args.startswith('!forfeit'): if ctx.disable_client_forfeit: - notify_client(client, 'Forfeit is currently disabled server-side.') - return - forfeit_player(ctx, client.team, client.slot) + notify_client(client, 'Client-initiated forfeits are disabled. Please ask the host of this game to forfeit on your behalf.') + else: + forfeit_player(ctx, client.team, client.slot) if args.startswith('!countdown'): try: timer = int(args.split()[1]) From 4563f96fd5d6c8066c23e3868379b1b39e6ef15a Mon Sep 17 00:00:00 2001 From: aerinon Date: Wed, 8 Mar 2023 08:25:46 -0700 Subject: [PATCH 033/196] Fix for mirror portal in inverted Yet another fix for blocked doors in Standard ER, minor alteration for the swamp entrance fix to work when blocked as well. --- RELEASENOTES.md | 3 +++ Rom.py | 2 +- data/base2current.bps | Bin 93909 -> 93952 bytes 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index e87d4a22..317db6b2 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -108,6 +108,9 @@ These are now independent of retro mode and have three options: None, Random, an * Bonk Fairy (Dark) # Bug Fixes and Notes +* 1.2.0.12u + * Fix for mirror portal in inverted + * Yet another fix for blocked door in Standard ER * 1.2.0.11u * Fixed an issue with lower layer doors in Standard * Fix for doors in cave state (will no longer be vanilla) diff --git a/Rom.py b/Rom.py index 13b4f133..0ca8e140 100644 --- a/Rom.py +++ b/Rom.py @@ -37,7 +37,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = 'badc0c787f7ab5e0ad05fb517953849a' +RANDOMIZERBASEHASH = '4faba57f154a2263bf91af041a0d8700' class JsonRom(object): diff --git a/data/base2current.bps b/data/base2current.bps index 57c2f8b618b86d3c6a8124c7723b85ac68063570..5a239f15ad6edbb9e939796d1ecad384d3162259 100644 GIT binary patch delta 1256 zcmX9)e^8TU9Dl$2#RljGylhMnpS_5V#0xbEMU5-7LOSf^N)vUFoY>5(oC}DgTt6iTHxXkKN4K*brQmKm+HNRlwZXMcGv;L}CNVWCr{e zYoWhgE6Mc4YBmq<0y+kXvI+>0aw!;f(k9o)+EOVVf8Y?w5+_>d znD%)o+uNZyvutQsR*aJ>Ud95dY{xTrjV!Rg(~X)OsD=$R4aRnoAJs4?Z|{jq?G9dw zLY*e$a_|U!;wY}9(63~s1`5h*hAeXb&IZ@5{$XLXI7Nkc3N>-8gijNRi28ZCO9t5A zjJO^N@^CE0XObijx*)SKEM`m!U%Ev{Yw)xA*svL2|9%9OY9a*fW>oBR_ zjZYu_x@EXjKrFeE1Fq~>#aP{qV~(xKBu5S#B)5KJfNX+;rreGBOKd!4zoQ=!IxXF*nV;RQTW+(U^S)>X z+T)9^M655mmjt!Iv^uBpTY-XlEoRTsfn~e2*sDM-;ZZu^di4Zf8IXx&k`A0tB3Bc{Z*@S~nDw=S@p9I}^$0+^V^R8Oa&CA=sk_Rrt0#r6(E zi_)TFzL?(K~%Uh44I#?LU*=9BU73t_5Csad_F J=fd8H%)iX72q6Ff delta 1257 zcmW+ze@s(n6n(cpXrY8sCi3+ak{ug&4llD zJksKzeSOxiv?DF(TU!iiUCpXXu;_Gax3FO%iPJcR#Dx7JdphPEE_BcRb)W`KP%8N>%?&`gvdoE`4`DYzB+I+oE#=del~YEEue!7V8qCyUjv(kduo zKmOT4>fU)i*?K?5jAaD{8uNrCSc>wwOjaoKAK%XYBhqrTn-$3c7R|WK)-vn=)a@6P z#gkg!(m(#YTf~c5RONml^HL_%mGfOW8COGT-hMaQ#01~Jkk~|K)lk{ldTH`gH!nqz zZYyHkJVGwFv4KLry15EW>s@vlarV(`CSGaGQVeA^X2JZBA}cP_^1#7;o`=Ju!VOW0 z@D$q5F%n)OHX<74r#Bhdw2AZ-LQzHg zx3tn_ACdDiq+@4B`)@ERZm2ikYE%bykxPY8lT)WJ#Y{7qDg-_B5t#;FflP9VM!a$D zWe#h{(&R)DY*4FD+olV- z9bQj)g}WC2L2ebn)|>+@{RXKgreau>`{6EUpw{LLRFLLk(e*v@Nipo#9P_z`h~*Hz zdhUmgQImjQONgoj8Z?K_1nP0Gxb``5(D|g@ zPIi@mZc84?!{?{Y9%LqscY2zJr%kDl5H@GW<~q<*pZKn`1>Fpk|_ZLEF(`!;4MvlrQfMDSX~)b@B9AT z9ik#@bkMl!Fz-~x=3L#;3C*-ATFUI0eIOw%IRXBf$u_s#nG(9`Gr0v{KW?pe(&)TD zu0qZJ_?xKBA3s8V)`4CX{9v~ZGuO4jlQsgSu&DE>O^3Z*s3ZDJ`%{GZci_s-S7~Qd znH#>wuy_W2HE;z($uwf|xY!(cyva>W=8LNYGB&_UdqNS9OPt$lpEX&E@klg%nw1 z?d|15nY!e*<^B<~!{Bg4X0%3!BhAGJBj&Ur?MOGRC*>t2c$~=-1I~BGr95Se0@w~V zP!<>FEd+X zJtU{*bVfh4ke!)H2|_rN%?jEZp^3-j;|)Gq;j*(5Jc*}>@ihrv(%oi$=BYXmpmPGS z`B73=29{jdNA^~OK_c6n?5zehfRYU8VXb;~r-MDP(iRHEYF~E;RwiflFT~2^LJiC} NDXTUj^o_@2{STKc5XJxi From 44afe50bf4ca08504006eb9ec300d0f9a14196f0 Mon Sep 17 00:00:00 2001 From: aerinon Date: Wed, 8 Mar 2023 08:26:50 -0700 Subject: [PATCH 034/196] Version bump --- Main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Main.py b/Main.py index 2a334081..f731df8a 100644 --- a/Main.py +++ b/Main.py @@ -34,7 +34,7 @@ from source.overworld.EntranceShuffle2 import link_entrances_new from source.tools.BPS import create_bps_from_data from source.classes.CustomSettings import CustomSettings -__version__ = '1.2.0.11u' +__version__ = '1.2.0.12u' from source.classes.BabelFish import BabelFish From d549a2c323d261db4d164ca8602772f1c721d103 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 8 Mar 2023 16:19:29 -0600 Subject: [PATCH 035/196] Adding OWR modes to Customizer settings --- source/classes/CustomSettings.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/classes/CustomSettings.py b/source/classes/CustomSettings.py index 55796263..6d297347 100644 --- a/source/classes/CustomSettings.py +++ b/source/classes/CustomSettings.py @@ -72,7 +72,13 @@ class CustomSettings(object): args.mystery = True else: settings = defaultdict(lambda: None, player_setting) + args.ow_shuffle[p] = get_setting(settings['ow_shuffle'], args.ow_shuffle[p]) + args.ow_terrain[p] = get_setting(settings['ow_terrain'], args.ow_terrain[p]) + args.ow_crossed[p] = get_setting(settings['ow_crossed'], args.ow_crossed[p]) + args.ow_keepsimilar[p] = get_setting(settings['ow_keepsimilar'], args.ow_keepsimilar[p]) args.ow_mixed[p] = get_setting(settings['ow_mixed'], args.ow_mixed[p]) + args.ow_whirlpool[p] = get_setting(settings['ow_whirlpool'], args.ow_whirlpool[p]) + args.ow_fluteshuffle[p] = get_setting(settings['ow_fluteshuffle'], args.ow_fluteshuffle[p]) args.shuffle[p] = get_setting(settings['shuffle'], args.shuffle[p]) args.door_shuffle[p] = get_setting(settings['door_shuffle'], args.door_shuffle[p]) args.logic[p] = get_setting(settings['logic'], args.logic[p]) From 252f9ba1a701dacc4a1e79a84d2b458b7635d2c5 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 8 Mar 2023 20:41:16 -0600 Subject: [PATCH 036/196] Remove 5 Arrow items from bonk drop locations --- Fill.py | 2 +- ItemList.py | 2 ++ Items.py | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Fill.py b/Fill.py index 4507ddeb..d549e969 100644 --- a/Fill.py +++ b/Fill.py @@ -538,7 +538,7 @@ def ensure_good_pots(world, write_skips=False): and (loc.type != LocationType.Pot or loc.item.player != loc.player)): loc.item = ItemFactory(invalid_location_replacement[loc.item.name], loc.item.player) if (loc.item.name in {'Arrows (5)'} - and (loc.type not in [LocationType.Pot, LocationType.Bonk] or loc.item.player != loc.player)): + and (loc.type != LocationType.Pot or loc.item.player != loc.player)): loc.item = ItemFactory(invalid_location_replacement[loc.item.name], loc.item.player) # # can be placed here by multiworld balancing or shop balancing # # change it to something normal for the player it got swapped to diff --git a/ItemList.py b/ItemList.py index aebb6489..956b8153 100644 --- a/ItemList.py +++ b/ItemList.py @@ -1104,6 +1104,8 @@ def get_pool_core(world, player, progressive, shuffle, difficulty, treasure_hunt pool.remove('Fighter Sword') pool.extend(['Rupees (50)']) + #TODO: Remove test placements + #place_item('Purple Chest', 'Magic Mirror') if timer in ['timed', 'timed-countdown']: pool.extend(diff.timedother) clock_mode = 'stopwatch' if timer == 'timed' else 'countdown' diff --git a/Items.py b/Items.py index 6bde89ef..d0f6ba84 100644 --- a/Items.py +++ b/Items.py @@ -80,7 +80,7 @@ item_table = {'Bow': (True, False, None, 0x0B, 200, 'You have\nchosen the\narche 'Arrow Upgrade (+10)': (False, False, None, 0x54, 100, 'Increase arrow\nstorage, low\nlow price', 'and the quiver', 'quiver-enlarging kid', 'arrow boost for sale', 'witch and more skewers', 'upgrade boy sews more again', 'arrow capacity'), 'Arrow Upgrade (+5)': (False, False, None, 0x53, 100, 'Increase arrow\nstorage, low\nlow price', 'and the quiver', 'quiver-enlarging kid', 'arrow boost for sale', 'witch and more skewers', 'upgrade boy sews more again', 'arrow capacity'), 'Single Bomb': (False, False, None, 0x27, 5, 'I make things\ngo BOOM! But\njust once.', 'and the explosion', 'the bomb-holding kid', 'firecracker for sale', 'blend fungus into bomb', '\'splosion boy explodes again', 'a bomb'), - 'Arrows (5)': (False, False, None, 0xB5, 15, 'This will give\nyou five shots\nwith your bow!', 'and the arrow pack', 'stick-collecting kid', 'sewing kit for sale', 'fungus for arrows', 'archer boy sews again', 'five arrows'), + 'Arrows (5)': (False, False, None, 0x5A, 15, 'This will give\nyou five shots\nwith your bow!', 'and the arrow pack', 'stick-collecting kid', 'sewing kit for sale', 'fungus for arrows', 'archer boy sews again', 'five arrows'), 'Small Magic': (False, False, None, 0x45, 5, 'A bit of magic', 'and the bit of magic', 'bit-o-magic kid', 'magic bit for sale', 'fungus for magic', 'magic boy conjures again', 'a bit of magic'), 'Big Magic': (False, False, None, 0xB4, 40, 'A lot of magic', 'and lots of magic', 'lot-o-magic kid', 'magic refill for sale', 'fungus for magic', 'magic boy conjures again', 'a magic refill'), 'Chicken': (False, False, None, 0xB3, 5, 'Cucco of Legend', 'and the legendary cucco', 'chicken kid', 'fried chicken for sale', 'fungus for chicken', 'cucco boy clucks again', 'a cucco'), From 1bb4d5f03b7fa5a1dda2a9d1925abc9e27355078 Mon Sep 17 00:00:00 2001 From: aerinon Date: Thu, 9 Mar 2023 11:14:13 -0700 Subject: [PATCH 037/196] Version bump and note --- Main.py | 2 +- RELEASENOTES.md | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Main.py b/Main.py index 11138c65..7d3ae0eb 100644 --- a/Main.py +++ b/Main.py @@ -31,7 +31,7 @@ from Utils import output_path, parse_player_names from source.item.FillUtil import create_item_pool_config, massage_item_pool, district_item_pool_config from source.tools.BPS import create_bps_from_data -__version__ = '1.1.4-dev' +__version__ = '1.1.5-dev' from source.classes.BabelFish import BabelFish diff --git a/RELEASENOTES.md b/RELEASENOTES.md index fd66faff..4c65204f 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -181,6 +181,8 @@ Same as above but both small keys and bigs keys of the dungeon are not allowed o # Bug Fixes and Notes +* 1.1.5 + * MultiServer can not disable forfeits if desired * 1.1.4 * Removed a Triforce text * Fix for Desert Tiles 1 key door From affd7568cb47ba33b10ab1ef68040045d8e516e4 Mon Sep 17 00:00:00 2001 From: aerinon Date: Thu, 9 Mar 2023 16:48:14 -0700 Subject: [PATCH 038/196] Minor adjustments to world model refactor --- Main.py | 1 - Rules.py | 9 ++++----- source/overworld/EntranceShuffle2.py | 1 - 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Main.py b/Main.py index cda30701..e624c1fd 100644 --- a/Main.py +++ b/Main.py @@ -241,7 +241,6 @@ def main(args, seed=None, fish=None): for player in range(1, world.players + 1): set_rules(world, player) - reg = world.get_region('Dark Desert', 1) district_item_pool_config(world) for player in range(1, world.players + 1): if world.shopsanity[player]: diff --git a/Rules.py b/Rules.py index cfb79894..05364af8 100644 --- a/Rules.py +++ b/Rules.py @@ -246,6 +246,10 @@ def global_rules(world, player): set_rule(world.get_entrance('Hammer Bridge Pegs (North)', player), lambda state: state.has('Hammer', player)) set_rule(world.get_entrance('Hammer Bridge Pegs (South)', player), lambda state: state.has('Hammer', player)) + # this more like an ohko rule - dependent on bird being present too - so enemizer could turn this off? + set_rule(world.get_entrance('Bumper Cave Ledge Drop', player), lambda state: state.has_Pearl(player) and + (state.has('Cape', player) or state.has('Cane of Byrna', player) or state.has_sword(player))) + # entrance rules # Caution: If king's grave is relaxed at all to account for reaching it via a two way cave's exit in insanity mode, then the bomb shop logic will need to be updated (that would involve create a small ledge-like Region for it) # TODO: Not sure if this ^ is true anymore since Kings Grave is its own region now @@ -900,11 +904,6 @@ def ow_inverted_rules(world, player): or (state.can_reach('Light World', 'Region', player) and state.has_Mirror(player))) # Need LW access using Mirror or Portal set_rule(world.get_entrance('Inverted Pyramid Hole', player), lambda state: world.open_pyramid[player] or world.goal[player] == 'trinity' or state.has('Beat Agahnim 2', player)) - # todo: this needs a new home - # # this more like an ohko rule - dependent on bird being present too - so enemizer could turn this off? - # set_rule(world.get_entrance('Bumper Cave Ledge Drop', player), lambda state: state.has_Pearl(player) and - # (state.has('Cape', player) or state.has('Cane of Byrna', player) or state.has_sword(player))) - def ow_bunny_rules(world, player): # locations diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index c2b3d71b..dfed84c6 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -976,7 +976,6 @@ def find_entrances_and_exits(avail_pool, entrance_pool): inverted_sub_table = { - #TODO: Confirm this is correct #'Ganons Tower': 'Agahnims Tower', #'Agahnims Tower': 'Ganons Tower', #'Links House': 'Big Bomb Shop', From 93eea0b40f780eec2cb791378ae43cdcec3a7066 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 9 Mar 2023 20:35:39 -0600 Subject: [PATCH 039/196] Added Cold Fairy Statue to bonkable locations --- Items.py | 1 + Regions.py | 5 +- Rom.py | 15 +++-- Rules.py | 4 +- Tables.py | 1 + asm/owrando.asm | 146 ++++++++++++++++++++++++++++++++++++---- data/base2current.bps | Bin 105527 -> 105775 bytes source/item/FillUtil.py | 2 +- 8 files changed, 153 insertions(+), 21 deletions(-) diff --git a/Items.py b/Items.py index d0f6ba84..1b7a041d 100644 --- a/Items.py +++ b/Items.py @@ -175,6 +175,7 @@ item_table = {'Bow': (True, False, None, 0x0B, 200, 'You have\nchosen the\narche 'Green Potion': (False, False, None, 0x2F, 60, 'Refreshing green goop!', 'and the green goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has green goo again', 'a green potion'), 'Blue Potion': (False, False, None, 0x30, 160, 'Delicious blue goop!', 'and the blue goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has blue goo again', 'a blue potion'), 'Bee': (False, False, None, 0x0E, 10, 'I will sting your foes a few times', 'and the sting buddy', 'the beekeeper kid', 'insect for sale', 'shroom pollenation', 'bottle boy has mad bee again', 'a bee'), + 'Good Bee': (False, False, None, 0xB5, 10, 'I will sting your foes a lot', 'and the cold buddy', 'the beekeeper kid', 'cold insect for sale', 'shroom pollenation', 'bottle boy has cold bee again', 'a good bee'), 'Small Heart': (False, False, None, 0x42, 10, 'Just a little\npiece of love!', 'and the heart', 'the life-giving kid', 'little love for sale', 'fungus for life', 'life boy feels some love again', 'a heart'), 'Apples': (False, False, None, 0xB1, 30, 'Just a few pieces of fruit!', 'and the juicy fruit', 'the fruity kid', 'the fruit stand', 'expired fruit', 'bottle boy has fruit again', 'an apple hoard'), 'Fairy': (False, False, None, 0xB2, 50, 'Just a pixie!', 'and the pixie', 'the pixie kid', 'pixie for sale', 'pixie fungus', 'bottle boy has pixie again', 'a pixie'), diff --git a/Regions.py b/Regions.py index 0bbca8b0..4f8e85de 100644 --- a/Regions.py +++ b/Regions.py @@ -688,6 +688,8 @@ def create_dungeon_regions(world, player): create_dungeon_region(player, 'Thieves Big Chest Nook', 'Thieves\' Town', ['Thieves\' Town - Big Key Chest'], ['Thieves Big Chest Nook ES Edge']), create_dungeon_region(player, 'Thieves Hallway', 'Thieves\' Town', ['Thieves\' Town - Hallway Pot Key'], ['Thieves Hallway SE', 'Thieves Hallway NE', 'Thieves Hallway WN', 'Thieves Hallway WS']), create_dungeon_region(player, 'Thieves Boss', 'Thieves\' Town', ['Revealing Light', 'Thieves\' Town - Boss', 'Thieves\' Town - Prize'], ['Thieves Boss SE']), + #create_dungeon_region(player, 'Thieves Boss', 'Thieves\' Town', ['Thieves\' Town - Boss', 'Thieves\' Town - Prize'], ['Revealing Light', 'Thieves Boss SE']), + #create_dungeon_region(player, 'Thieves Revealing Light', 'Thieves\' Town', ['Revealing Light'], ['Thieves Boss Room']), create_dungeon_region(player, 'Thieves Pot Alcove Mid', 'Thieves\' Town', None, ['Thieves Pot Alcove Mid ES', 'Thieves Pot Alcove Mid WS']), create_dungeon_region(player, 'Thieves Pot Alcove Bottom', 'Thieves\' Town', None, ['Thieves Pot Alcove Bottom SW']), create_dungeon_region(player, 'Thieves Pot Alcove Top', 'Thieves\' Town', None, ['Thieves Pot Alcove Top NW']), @@ -1304,7 +1306,8 @@ bonk_prize_table = { 'Dark Tree Line Tree 2': (0x26, 0x10, False, '', 'Dark Tree Line Area', 'in a tree'), 'Dark Tree Line Tree 3': (0x27, 0x08, False, '', 'Dark Tree Line Area', 'in a tree'), 'Dark Tree Line Tree 4': (0x28, 0x04, False, '', 'Dark Tree Line Area', 'in a tree'), - 'Hype Cave Statue': (0x29, 0x10, False, '', 'Hype Cave Area', 'encased in stone') + 'Hype Cave Statue': (0x29, 0x10, False, '', 'Hype Cave Area', 'encased in stone'), + 'Cold Fairy Statue': (0x2a, 0x02, False, '', 'Good Bee Cave', 'encased in stone') } bonk_table_by_location_id = {0x2ABB00+(data[0]*6)+3: name for name, data in bonk_prize_table.items()} diff --git a/Rom.py b/Rom.py index ffa91963..3a5c689c 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '2b14cd0bbab8a7fb943c8bc1ca75ed1f' +RANDOMIZERBASEHASH = '4458a348e3040d79d0e28d572579fcb5' class JsonRom(object): @@ -686,7 +686,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): flute_spots = default_flute_connections else: flute_spots = world.owflutespots[player] - owFlags |= 0x100 + owFlags |= 0x0100 for o in range(0, len(flute_spots)): owslot = flute_spots[o] @@ -740,12 +740,12 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): owMode = 2 if world.owKeepSimilar[player] and (world.owShuffle[player] != 'vanilla' or world.owCrossed[player] in ['limited', 'chaos']): - owMode |= 0x100 + owMode |= 0x0100 if world.owCrossed[player] != 'none' and (world.owCrossed[player] != 'polar' or world.owMixed[player]): - owMode |= 0x200 + owMode |= 0x0200 world.fix_fake_world[player] = True if world.owMixed[player]: - owMode |= 0x400 + owMode |= 0x0400 # patches map data specific for OW Shuffle #inverted_buffer[0x03] = inverted_buffer[0x03] | 0x2 # convenient portal on WDM @@ -793,7 +793,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): # for prize, address in zip(bonk_prizes, bonk_addresses): # rom.write_byte(address, prize) - owFlags |= 0x200 + owFlags |= 0x0200 # setting spriteID to D8, a placeholder sprite we use to inform ROM to spawn a dynamic item #for address in bonk_addresses: @@ -803,6 +803,8 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): rom.write_byte(snes_to_pc(0x09AE32), 0xD8) rom.write_byte(snes_to_pc(0x09AE35), 0xD8) + rom.write_byte(snes_to_pc(0x06918E), 0x80) # skip good bee bottle check + write_int16(rom, 0x150002, owMode) write_int16(rom, 0x150004, owFlags) @@ -1649,6 +1651,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): if world.shuffle_bonk_drops[player]: # warning, this temporary patch might cause fairies to respawn differently?, limiting this to bonk drop mode only rom.write_byte(snes_to_pc(0x0DB808), 0x03) # patch fairies sprites to not permadeath like enemies + rom.write_byte(snes_to_pc(0x1DF6D8), 0) # allows sprites to travel across water / same flag as write_enemizer_tweaks # allow smith into multi-entrance caves in appropriate shuffles if world.shuffle[player] in ['restricted', 'full', 'lite', 'lean', 'crossed', 'insanity'] or (world.shuffle[player] == 'simple' and world.mode[player] == 'inverted'): diff --git a/Rules.py b/Rules.py index 5bf4f76e..1cb91819 100644 --- a/Rules.py +++ b/Rules.py @@ -862,7 +862,9 @@ def default_rules(world, player): from Regions import bonk_prize_table for location_name, (_, _, aga_required, _, _, _) in bonk_prize_table.items(): loc = world.get_location(location_name, player) - if not aga_required: + if location_name == 'Cold Fairy Statue': + set_rule(loc, lambda state: state.can_use_bombs(player) and state.can_collect_bonkdrops(player)) + elif not aga_required: set_rule(loc, lambda state: state.can_collect_bonkdrops(player)) else: set_rule(loc, lambda state: state.can_collect_bonkdrops(player) and state.has_beaten_aga(player)) diff --git a/Tables.py b/Tables.py index a30f24f0..52f96488 100644 --- a/Tables.py +++ b/Tables.py @@ -130,6 +130,7 @@ bonk_prize_lookup = { 'Chicken': (0x0b, 0, None), 'Bee Trap': (0x79, 6, None), 'Apples': (0xac, 8, None), + 'Good Bee': (0xb2, 1, None), 'Small Heart': (0xd8, 2, None), 'Rupee (1)': (0xd9, 0, None), 'Rupees (5)': (0xda, 3, None), # TODO: add in murahdahla tree rupee diff --git a/asm/owrando.asm b/asm/owrando.asm index 09fe010d..3f3a7be0 100644 --- a/asm/owrando.asm +++ b/asm/owrando.asm @@ -157,6 +157,14 @@ and #$7f : eor #$40 : nop #2 org $06AD4C jsl.l OWBonkDrops : nop #4 +org $1EDE6F +jsl.l OWBonkGoodBeeDrop : bra + +GoldBee_SpawnSelf_SetProperties: +phb : lda.b #$1E : pha : plb ; switch to bank 1E + jsr GoldBee_SpawnSelf+12 +plb : rtl +nop #3 ++ ;Code org $aa8800 @@ -395,6 +403,112 @@ LoadMapDarkOrMixed: dw $0400+$0210 ; bottom right } +OWBonkGoodBeeDrop: +{ + LDA.l OWFlags+1 : AND.b #$02 : BNE .shuffled + .vanilla ; what we wrote over + STZ.w $0DD0,X + LDA.l BottleContentsOne : ORA.l BottleContentsTwo + ORA.l BottleContentsThree : ORA.l BottleContentsFour + RTL + .shuffled + PHY : TXY + LDA.l RoomDataWRAM[$0120].high : AND.b #$02 : PHA : BNE + ; check if collected + LDA.b #$1B : STA $12F ; JSL Sound_SetSfx3PanLong ; seems that when you bonk, there is a pending bonk sfx, so we clear that out and replace with reveal secret sfx + + + LDA.l OWBonkPrizeData+(42*6+4) : BEQ + ; multiworld item + LDA.l OWBonkPrizeData+(42*6+3) + JMP .spawn_item + + + + .determine_type ; S = Collected, FlagBitmask, X (row + 2) + LDA.l OWBonkPrizeData+(42*6+3) ; A = item id + CMP.b #$B0 : BNE + + LDA.b #$79 : JMP .sprite_transform ; transform to bees + + CMP.b #$42 : BNE + + JSL.l Sprite_TransmuteToBomb ; transform a heart to bomb, vanilla behavior + JMP .mark_collected + + CMP.b #$34 : BNE + + LDA.b #$D9 : JMP .sprite_transform ; transform to single rupee + + CMP.b #$35 : BNE + + LDA.b #$DA : JMP .sprite_transform ; transform to blue rupee + + CMP.b #$36 : BNE + + LDA.b #$DB : BRA .sprite_transform ; transform to red rupee + + CMP.b #$27 : BNE + + LDA.b #$DC : BRA .sprite_transform ; transform to 1 bomb + + CMP.b #$28 : BNE + + LDA.b #$DD : BRA .sprite_transform ; transform to 4 bombs + + CMP.b #$31 : BNE + + LDA.b #$DE : BRA .sprite_transform ; transform to 8 bombs + + CMP.b #$45 : BNE + + LDA.b #$DF : BRA .sprite_transform ; transform to small magic + + CMP.b #$B4 : BNE + + LDA.b #$E0 : BRA .sprite_transform ; transform to big magic + + CMP.b #$B5 : BNE + + LDA.b #$79 : JSL.l OWBonkSpritePrep + JSL.l GoldBee_SpawnSelf_SetProperties ; transform to good bee + BRA .mark_collected + + CMP.b #$44 : BNE + + LDA.b #$E2 : BRA .sprite_transform ; transform to 10 arrows + + CMP.b #$B1 : BNE + + LDA.b #$AC : BRA .sprite_transform ; transform to apples + + CMP.b #$B2 : BNE + + LDA.b #$E3 : BRA .sprite_transform ; transform to fairy + + CMP.b #$B3 : BNE .spawn_item + INX : INX : LDA.l OWBonkPrizeData+(42*6+5) + CLC : ADC.b #$08 : PHA + LDA.w $0D00,Y : SEC : SBC.b 1,S : STA.w $0D00,Y + LDA.w $0D20,Y : SBC.b #$00 : STA.w $0D20,Y : PLX + LDA.b #$0B : SEC ; BRA .sprite_transform ; transform to chicken + + .sprite_transform + JSL.l OWBonkSpritePrep + + .mark_collected ; S = Collected + PLA : BNE .return + LDA.l RoomDataWRAM[$0120].high : ORA.b #$02 : STA.l RoomDataWRAM[$0120].high + + REP #$20 + LDA.l TotalItemCounter : INC : STA.l TotalItemCounter + SEP #$20 + BRA .return + + ; spawn itemget item + .spawn_item ; A = item id ; Y = bonk sprite slot ; S = Collected + PLX : BEQ + : LDA.b #$00 : STA.w $0DD0,Y : BRA .return + + LDA.l OWBonkPrizeData+(42*6+4) : STA.l !MULTIWORLD_SPRITEITEM_PLAYER_ID + + LDA.b #$01 : STA !REDRAW + + LDA.b #$EB : STA.l $7FFE00 + JSL Sprite_SpawnDynamically+15 ; +15 to skip finding a new slot, use existing sprite + + ; affects the rate the item moves in the Y/X direction + LDA.b #$00 : STA.w $0D40,Y + LDA.b #$0A : STA.w $0D50,Y + + LDA.b #$20 : STA.w $0F80,Y ; amount of force (gives height to the arch) + LDA.b #$FF : STA.w $0B58,Y ; stun timer + LDA.b #$30 : STA.w $0F10,Y ; aux delay timer 4 ?? dunno what that means + + LDA.b #$00 : STA.w $0F20,Y ; layer the sprite is on + + ; sets OW event bitmask flag, uses free RAM + LDA.l OWBonkPrizeData+(42*6+2) : STA.w $0ED0,Y + + ; determines the initial spawn point of item + LDA.w $0D00,Y : SEC : SBC.l OWBonkPrizeData+(42*6+5) : STA.w $0D00,Y + LDA.w $0D20,Y : SBC #$00 : STA.w $0D20,Y + + LDA.b #$01 : STA !REDRAW : STA !FORCE_HEART_SPAWN + + .return + PLY + LDA #$08 ; makes original good bee not spawn + RTL + nop #20 +} + ; Y = sprite slot index of bonk sprite OWBonkDrops: { @@ -439,7 +553,7 @@ OWBonkDrops: + CMP.b #$34 : BNE + LDA.b #$D9 : CLC : JMP .sprite_transform ; transform to single rupee + CMP.b #$35 : BNE + - LDA.b #$DA : CLC : BRA .sprite_transform ; transform to blue rupee + LDA.b #$DA : CLC : JMP .sprite_transform ; transform to blue rupee + CMP.b #$36 : BNE + LDA.b #$DB : CLC : BRA .sprite_transform ; transform to red rupee + CMP.b #$27 : BNE + @@ -453,7 +567,9 @@ OWBonkDrops: + CMP.b #$B4 : BNE + LDA.b #$E0 : CLC : BRA .sprite_transform ; transform to big magic + CMP.b #$B5 : BNE + - LDA.b #$E1 : CLC : BRA .sprite_transform ; transform to 5 arrows + LDA.b #$79 : JSL.l OWBonkSpritePrep + JSL.l GoldBee_SpawnSelf_SetProperties ; transform to good bee + BRA .mark_collected + CMP.b #$44 : BNE + LDA.b #$E2 : CLC : BRA .sprite_transform ; transform to 10 arrows + CMP.b #$B1 : BNE + @@ -468,14 +584,7 @@ OWBonkDrops: LDA.b #$0B : SEC ; BRA .sprite_transform ; transform to chicken .sprite_transform - STA.w $0E20,Y - TYX : JSL.l Sprite_LoadProperties - BEQ + - ; these are sprite properties that make it fall out of the tree to the east - LDA #$30 : STA $0F80,Y ; amount of force (related to speed) - LDA #$10 : STA $0D50,Y ; eastward rate of speed - LDA #$FF : STA $0B58,Y ; expiration timer - + + JSL.l OWBonkSpritePrep .mark_collected ; S = Collected, FlagBitmask, X (row + 2) PLA : BNE + ; S = FlagBitmask, X (row + 2) @@ -495,8 +604,7 @@ OWBonkDrops: LDA.b #$01 : STA !REDRAW - LDA.b #$EB - STA.l $7FFE00 + LDA.b #$EB : STA.l $7FFE00 JSL Sprite_SpawnDynamically+15 ; +15 to skip finding a new slot, use existing sprite ; affects the rate the item moves in the Y/X direction @@ -525,6 +633,19 @@ OWBonkDrops: PLA : PLA : PLB : RTL } +; A = SpriteID, Y = Sprite Slot Index, X = free/overwritten +OWBonkSpritePrep: +{ + STA.w $0E20,Y + TYX : JSL.l Sprite_LoadProperties + BEQ + + ; these are sprite properties that make it fall out of the tree to the east + LDA #$30 : STA $0F80,Y ; amount of force (related to speed) + LDA #$10 : STA $0D50,Y ; eastward rate of speed + LDA #$FF : STA $0B58,Y ; expiration timer + + RTL +} + org $aa9000 OWDetectEdgeTransition: { @@ -1539,6 +1660,7 @@ db $6e, $8c, $10, $35, $00, $10 db $6e, $90, $08, $b0, $00, $10 db $6e, $a4, $04, $b1, $00, $10 db $74, $4e, $10, $b1, $00, $1c +db $ff, $00, $02, $b5, $00, $08 ; temporary fix - murahdahla replaces one of the bonk tree prizes ; so we copy the sprite table here and update the pointer diff --git a/data/base2current.bps b/data/base2current.bps index 0d2e6dd4428d2baf700f9943f65fef0e500a0053..f12897a42e34bbc4aaa14a6c175c0ec7b49f9d35 100644 GIT binary patch delta 1808 zcmW-hYgAKL7RT?sdGZRP0s-U|P~;&Xk%wBaiXlP5!(u50q*|p7TxU_n)&gCSb0eWf z2r(YX9k@|iQ>ML1Y0$JHL!COV)xk@ra;>XtAyjnX%vzKWW0rI}4l^xt;{CAyd;Ry_ z=j`+Qu*YwRJ%199HR3|YTgU(4ZNiU8h-(ec>f2xQgr^4z5!6geZfoVV--^aAcy;s&m78D z{e#-FmQg-+Px0GFx#N(M{*#oWNxz$9>WqbKs`u9@>7 z`+T6sHY^5E-TKtF#!J~!Cc723l_W~lHA^N|$aKJuN*u%n2=}Pd@eW9;{TC4 zwyDv#o8G0pUJVXN9a&UR;=K3eg!#9?!JX4H1y`@H3tNHfG|J#BWcyhOwc2pTaPT~= z(B$rCCf*x)qvv<=R?oJe>sget(xmH_ z=H7*yRPbv}B%$huvzpCB`zTz~Y$9}@!`RZ(#PKmWP`Vu_yi=uxBBJSgD6UK<-u@nD zRBDMmJnX29$KUe~Remic3ZKKe+M1%;C}94TkA^Y866UE}p%cRaC9xVuw3|m+A<6y5 z?_%;Iz_2qCNj^>0y_~GH0S3A)F5-5!V<2fd}-@L}h zIAh}h-4Fqs`#n(Gy>`jG07oAxj4crYD^XmxOsV%@F(B@x*Xhf>U zYGk4<7Van??yTDa%!QtTPujM?JGwfeF#~R{%M5!xbq)sV=B=-00<%V{p&Q|ey1zrWRamQ)J>m|BgO*s zZ19J8ebk~zpAXi1gQ@G~;`;4>qw|#T&Rqvy1siA5iHTeF_hmtVr=hVmxx-C-=`AvVbqAZ&W%++&O<+~hQDGhYI;OE|vZ@%qANX6^}xpt}#F%`3O z@C{Qb$U}7J<)95w6|q0cK?}kvVjs$Z;Y|cq#4gCe5kywRK9Yk&h^&ZxEWh8>Js@Hi zR3Oa}pF zQcxZ16z`US@#I%_hh F`#)n48tDK4 delta 1627 zcmW+$ZBSEJ8qU2p2?0zBTHrz|#26X@1^JTrK@pmSAmO8>MGT0#TiWQgqHR~FQsKQw zr~zZdQ@F-}ahp|pgK2=<8qwM^o$lI8OTCWM8H3$&j4+I6Xuli0jzzY6D zLBY!0M;F>bvKagk=P}AM9Xj}UV`NL{{6u@Cz!$y8b2%w!A|f~|RXTPvxvl3MgMSjecK^1CSXphL)8gIc`^r|^!Mcd(j^eu^#E4(iqM##KI(e~oJgOz%- z(MRS%y!;%pm1kkusJlEBFX=&7%J-)Cmy2sFo(E4FXStPIujkOkvX8m#nuo8zbDJmc z8b+^cE6<@!OMWZ?7xggNd~&Dt0@`mWOmn`zaJ24Z5uHtgE6)s|>fDs-rh!|1V6qK} zA#~HCR@WN8osyr|yxR}hc?a5W%O>BD553+{zfYF}&R>KSqy|@fsBwXLH38@- zcjskmdXSY;{Qre5UOWkWt5SfDb$2>N+Iza6V4tOU31d!yDNG<(BgNz5W};X##V-l# zy#)Bw9SqxckI~F z3a38ap7#Di3q!B+uS*8+Y3G5Eoe4NvM*Ll((+q!Mvgi=iqK|f|H&=+aM4=awA)M!6 z&N!C@wSRvaFqui0u4+LqBv)}k@1Zj5gh$nZKf3^%)+d&DOz(SwT+ zB_!IU>)oB+6qk$NDn%tPObrX0nH&)vLa_@2O``tI<6TBtX?omD}qSgi<{fT1p9iKDX zrV!WKOB^fx7gu`tQ%r?$%TEJG>O1Kg?~@JPDE_tXsLE`b1{BL(e63ZL)YwYjj!1cY zB-+ldxP&z&eJ_ z)BZ!@m;~&izGEm79Vh1>L@;J=wG_U_1(~)XD5u0nyWI2ce`X}NgoOF=fnyuaPVJH? zmybBaPhReslL+`QHHoBML-1h!w&d2dg;}G*p|oo)W)Wnp+LeR(iNLaASuPRTq}_U= zchb&}i0YeGQ!ig8L}?p3f^utfFJBA{YwosI(NjT1L62U_fj_`UB{FMYdzfJ@* zB<$gHMevA(dfp_0SrV$m)RD1sBpAiWk+I*Bu$4E8;5!oX#7vX2*C12OFDd&Nv|?)2 z&o4V7_bV*pk`ATeF&5Cs=?@p#Sc6BSx}_y=xFSyks+8ba@-)QSg=D7e;2lOs^>Mo2 zL!b4>-o*%WL^E?+M1DN*+bp+dqJ5I7Et~Of>!uHSTha$yY>cPYyE*@!|7hJj+FAW* z-0l%ni}UmI;}WIe7s;(*TRQNZyMHupJWDqFmGUj)C&Nk?IRqmSA73#P%^s&tr=* zH_Zjt8dLpotzBVV9Y#orgoA_O%$=A+m8gf+HA*1pyh0W9*P11gk@0X*UifwkcA!Xc Nd}hmmr~m%e?60;cyTt$i diff --git a/source/item/FillUtil.py b/source/item/FillUtil.py index 3f82db2a..1ed455b3 100644 --- a/source/item/FillUtil.py +++ b/source/item/FillUtil.py @@ -821,7 +821,7 @@ trash_items = { 'Nothing': -1, 'Bee Trap': 0, 'Rupee (1)': 1, 'Rupees (5)': 1, 'Small Heart': 1, 'Bee': 1, 'Arrows (5)': 1, 'Chicken': 1, 'Single Bomb': 1, - 'Rupees (20)': 2, 'Small Magic': 2, + 'Rupees (20)': 2, 'Small Magic': 2, 'Good Bee': 2, 'Bombs (3)': 3, 'Arrows (10)': 3, 'Bombs (10)': 3, 'Apples': 3, 'Fairy': 4, 'Big Magic': 4, 'Red Potion': 4, 'Blue Shield': 4, 'Rupees (50)': 4, 'Rupees (100)': 4, 'Rupees (300)': 5, From ab5670c64fc43c40a73d641a969e9101bfd0ca90 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 9 Mar 2023 22:23:32 -0600 Subject: [PATCH 040/196] Adding Lean/Lite ER support for new Good Bee Cave location --- source/overworld/EntranceShuffle2.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index e7010520..ecadaee9 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -1134,6 +1134,9 @@ def do_vanilla_connect(pool_def, avail): elif pool_def['condition'] == 'takeany': if avail.world.take_any[avail.player] == 'fixed': return + elif pool_def['condition'] == 'bonk': + if avail.world.shuffle_bonk_drops[avail.player]: + return defaults = {**default_connections, **(inverted_default_connections if avail.inverted != avail.world.is_tile_swapped(0x1b, avail.player) else open_default_connections)} for entrance in pool_def['entrances']: if entrance in avail.entrances: @@ -1574,7 +1577,11 @@ modes = { 'Light World Bomb Hut', '20 Rupee Cave', '50 Rupee Cave', 'Hookshot Fairy', 'Palace of Darkness Hint', 'Dark Lake Hylia Ledge Spike Cave', 'Dark Desert Hint'] - + }, + 'fixed_bonk': { + 'special': 'vanilla', + 'condition': 'bonk', + 'entrances': ['Good Bee Cave'] }, 'item_caves': { # shuffles shops/pottery if they weren't fixed in the last steps 'entrances': ['Mimic Cave', 'Spike Cave', 'Mire Shed', 'Dark World Hammer Peg Cave', 'Chest Game', @@ -1661,7 +1668,11 @@ modes = { 'Light World Bomb Hut', '20 Rupee Cave', '50 Rupee Cave', 'Hookshot Fairy', 'Palace of Darkness Hint', 'Dark Lake Hylia Ledge Spike Cave', 'Dark Desert Hint'] - + }, + 'fixed_bonk': { + 'special': 'vanilla', + 'condition': 'bonk', + 'entrances': ['Good Bee Cave'] }, 'item_caves': { # shuffles shops/pottery if they weren't fixed in the last steps 'entrances': ['Mimic Cave', 'Spike Cave', 'Mire Shed', 'Dark World Hammer Peg Cave', 'Chest Game', From 4108370849d3f2e3fd9875392a6d6f592e967a0a Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 9 Mar 2023 22:23:32 -0600 Subject: [PATCH 041/196] Adding Lean/Lite ER support for new Good Bee Cave location --- source/overworld/EntranceShuffle2.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index e7010520..3515fa47 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -1134,6 +1134,9 @@ def do_vanilla_connect(pool_def, avail): elif pool_def['condition'] == 'takeany': if avail.world.take_any[avail.player] == 'fixed': return + elif pool_def['condition'] == 'bonk': + if avail.world.shuffle_bonk_drops[avail.player]: + return defaults = {**default_connections, **(inverted_default_connections if avail.inverted != avail.world.is_tile_swapped(0x1b, avail.player) else open_default_connections)} for entrance in pool_def['entrances']: if entrance in avail.entrances: @@ -1550,7 +1553,7 @@ modes = { 'condition': '', 'entrances': ['Dark Desert Fairy', 'Archery Game', 'Fortune Teller (Dark)', 'Dark Sanctuary Hint', 'Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Fairy', 'Dark Lake Hylia Shop', - 'East Dark World Hint', 'Kakariko Gamble Game', 'Good Bee Cave', 'Long Fairy Cave', + 'East Dark World Hint', 'Kakariko Gamble Game', 'Long Fairy Cave', 'Bush Covered House', 'Fortune Teller (Light)', 'Lost Woods Gamble', 'Lake Hylia Fortune Teller', 'Lake Hylia Fairy', 'Bonk Fairy (Light)', 'Inverted Dark Sanctuary'], }, @@ -1574,7 +1577,11 @@ modes = { 'Light World Bomb Hut', '20 Rupee Cave', '50 Rupee Cave', 'Hookshot Fairy', 'Palace of Darkness Hint', 'Dark Lake Hylia Ledge Spike Cave', 'Dark Desert Hint'] - + }, + 'fixed_bonk': { + 'special': 'vanilla', + 'condition': 'bonk', + 'entrances': ['Good Bee Cave'] }, 'item_caves': { # shuffles shops/pottery if they weren't fixed in the last steps 'entrances': ['Mimic Cave', 'Spike Cave', 'Mire Shed', 'Dark World Hammer Peg Cave', 'Chest Game', @@ -1582,7 +1589,7 @@ modes = { 'Ice Rod Cave', 'Dam', 'Bonk Rock Cave', 'Library', 'Potion Shop', 'Mini Moldorm Cave', 'Checkerboard Cave', 'Graveyard Cave', 'Cave 45', 'Sick Kids House', 'Blacksmiths Hut', 'Sahasrahlas Hut', 'Aginahs Cave', 'Chicken House', 'Kings Grave', 'Blinds Hideout', - 'Waterfall of Wishing', 'Cave Shop (Dark Death Mountain)', + 'Waterfall of Wishing', 'Cave Shop (Dark Death Mountain)', 'Good Bee Cave', 'Dark World Potion Shop', 'Dark World Lumberjack Shop', 'Dark World Shop', 'Red Shield Shop', 'Kakariko Shop', 'Capacity Upgrade', 'Cave Shop (Lake Hylia)', 'Lumberjack House', 'Snitch Lady (West)', 'Snitch Lady (East)', 'Tavern (Front)', @@ -1637,7 +1644,7 @@ modes = { 'condition': '', 'entrances': ['Dark Desert Fairy', 'Archery Game', 'Fortune Teller (Dark)', 'Dark Sanctuary Hint', 'Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Fairy', 'Dark Lake Hylia Shop', - 'East Dark World Hint', 'Kakariko Gamble Game', 'Good Bee Cave', 'Long Fairy Cave', + 'East Dark World Hint', 'Kakariko Gamble Game', 'Long Fairy Cave', 'Bush Covered House', 'Fortune Teller (Light)', 'Lost Woods Gamble', 'Lake Hylia Fortune Teller', 'Lake Hylia Fairy', 'Bonk Fairy (Light)', 'Inverted Dark Sanctuary'], }, @@ -1661,7 +1668,11 @@ modes = { 'Light World Bomb Hut', '20 Rupee Cave', '50 Rupee Cave', 'Hookshot Fairy', 'Palace of Darkness Hint', 'Dark Lake Hylia Ledge Spike Cave', 'Dark Desert Hint'] - + }, + 'fixed_bonk': { + 'special': 'vanilla', + 'condition': 'bonk', + 'entrances': ['Good Bee Cave'] }, 'item_caves': { # shuffles shops/pottery if they weren't fixed in the last steps 'entrances': ['Mimic Cave', 'Spike Cave', 'Mire Shed', 'Dark World Hammer Peg Cave', 'Chest Game', @@ -1669,7 +1680,7 @@ modes = { 'Ice Rod Cave', 'Dam', 'Bonk Rock Cave', 'Library', 'Potion Shop', 'Mini Moldorm Cave', 'Checkerboard Cave', 'Graveyard Cave', 'Cave 45', 'Sick Kids House', 'Blacksmiths Hut', 'Sahasrahlas Hut', 'Aginahs Cave', 'Chicken House', 'Kings Grave', 'Blinds Hideout', - 'Waterfall of Wishing', 'Cave Shop (Dark Death Mountain)', + 'Waterfall of Wishing', 'Cave Shop (Dark Death Mountain)', 'Good Bee Cave', 'Dark World Potion Shop', 'Dark World Lumberjack Shop', 'Dark World Shop', 'Red Shield Shop', 'Kakariko Shop', 'Capacity Upgrade', 'Cave Shop (Lake Hylia)', 'Lumberjack House', 'Snitch Lady (West)', 'Snitch Lady (East)', 'Tavern (Front)', From 76da44f6582b8d167b8346404ae9e6f9684e924d Mon Sep 17 00:00:00 2001 From: codemann8 Date: Fri, 10 Mar 2023 23:48:04 -0600 Subject: [PATCH 042/196] Adding more OWR examples to customizer example yaml --- docs/customizer_example.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/customizer_example.yaml b/docs/customizer_example.yaml index 188c17d6..cd70004c 100644 --- a/docs/customizer_example.yaml +++ b/docs/customizer_example.yaml @@ -17,6 +17,13 @@ settings: shopsanity: true shuffle: crossed shufflelinks: true + ow_shuffle: parallel + ow_terrain: true + ow_crossed: grouped + ow_keepsimilar: true + ow_mixed: true + ow_whirlpool: true + ow_fluteshuffle: balanced shufflebosses: unique item_pool: 1: From 6283a880deb267dae1114f2473d768ba6841bfc9 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Fri, 10 Mar 2023 23:56:40 -0600 Subject: [PATCH 043/196] Version bump 0.3.0.2 --- CHANGELOG.md | 7 +++++++ OverworldShuffle.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f782574c..522421f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 0.3.0.2 +- \~Merged in DR v1.2.0.12~ + - Fixed some door landing issues +- Added Cold Fairy Statue as a new Bonk Location in Bonk Drop Shuffle +- Added Customizer support for enabling OWR Options +- Removed `Arrows (5)` item from Item Table, replaces with `Arrows (10)` + ## 0.3.0.1 - \~Merged in DR v1.2.0.10~ - Fixed some door landing issues diff --git a/OverworldShuffle.py b/OverworldShuffle.py index a49a6db5..264c5a19 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -7,7 +7,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType from OverworldGlitchRules import create_owg_connections from Utils import bidict -version_number = '0.3.0.1' +version_number = '0.3.0.2' # branch indicator is intentionally different across branches version_branch = '-u' From 6811ab29b2540c2d0120cb219c9c1a695caacbc2 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 12 Mar 2023 03:33:18 -0500 Subject: [PATCH 044/196] Adding bonk drops to Customizer settings --- source/classes/CustomSettings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/source/classes/CustomSettings.py b/source/classes/CustomSettings.py index 6d297347..008258da 100644 --- a/source/classes/CustomSettings.py +++ b/source/classes/CustomSettings.py @@ -79,6 +79,7 @@ class CustomSettings(object): args.ow_mixed[p] = get_setting(settings['ow_mixed'], args.ow_mixed[p]) args.ow_whirlpool[p] = get_setting(settings['ow_whirlpool'], args.ow_whirlpool[p]) args.ow_fluteshuffle[p] = get_setting(settings['ow_fluteshuffle'], args.ow_fluteshuffle[p]) + args.bonk_drops[p] = get_setting(settings['bonk_drops'], args.bonk_drops[p]) args.shuffle[p] = get_setting(settings['shuffle'], args.shuffle[p]) args.door_shuffle[p] = get_setting(settings['door_shuffle'], args.door_shuffle[p]) args.logic[p] = get_setting(settings['logic'], args.logic[p]) From 30deb1d5bc46484a160bba63461cf4bcd52b0a33 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 12 Mar 2023 19:25:35 -0500 Subject: [PATCH 045/196] Fix for Bonk Locations in Multiworld --- MultiClient.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/MultiClient.py b/MultiClient.py index fd0e8b4f..5b8ebd30 100644 --- a/MultiClient.py +++ b/MultiClient.py @@ -144,6 +144,7 @@ location_table_uw = {"Blind's Hideout - Top": (0x11d, 0x10), 'Mini Moldorm Cave - Far Right': (0x123, 0x80), 'Mini Moldorm Cave - Generous Guy': (0x123, 0x400), 'Ice Rod Cave': (0x120, 0x10), + 'Cold Fairy Statue': (0x120, 0x200), 'Bonk Rock Cave': (0x124, 0x10), 'Desert Palace - Big Chest': (0x73, 0x10), 'Desert Palace - Torch': (0x73, 0x400), @@ -936,10 +937,11 @@ async def track_locations(ctx : Context, roomid, roomdata): from OWEdges import OWTileRegions for location, (_, flag, _, _, region_name, _) in bonk_prize_table.items(): if location not in ctx.locations_checked: - screenid = OWTileRegions[region_name] - ow_unchecked[location] = (screenid, flag) - ow_begin = min(ow_begin, screenid) - ow_end = max(ow_end, screenid + 1) + if region_name in OWTileRegions: + screenid = OWTileRegions[region_name] + ow_unchecked[location] = (screenid, flag) + ow_begin = min(ow_begin, screenid) + ow_end = max(ow_end, screenid + 1) if ow_begin < ow_end: ow_data = await snes_read(ctx, SAVEDATA_START + 0x280 + ow_begin, ow_end - ow_begin) if ow_data is not None: From d140679c1313793ea8646afee046cec3e7bfbf21 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 12 Mar 2023 19:29:51 -0500 Subject: [PATCH 046/196] Reversing water collision fix and replacing with a sprite targeted fix for Bonk Drops --- Rom.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Rom.py b/Rom.py index 3a5c689c..8c329293 100644 --- a/Rom.py +++ b/Rom.py @@ -1651,7 +1651,8 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): if world.shuffle_bonk_drops[player]: # warning, this temporary patch might cause fairies to respawn differently?, limiting this to bonk drop mode only rom.write_byte(snes_to_pc(0x0DB808), 0x03) # patch fairies sprites to not permadeath like enemies - rom.write_byte(snes_to_pc(0x1DF6D8), 0) # allows sprites to travel across water / same flag as write_enemizer_tweaks + rom.write_byte(snes_to_pc(0x0DB810), 0x8A) # allows heart pieces to travel across water + rom.write_byte(snes_to_pc(0x0DB730), 0x08) # allows chickens to travel across water # allow smith into multi-entrance caves in appropriate shuffles if world.shuffle[player] in ['restricted', 'full', 'lite', 'lean', 'crossed', 'insanity'] or (world.shuffle[player] == 'simple' and world.mode[player] == 'inverted'): From a158cb6b75b6a9ec9e42515174c24b3575cfd26e Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 12 Mar 2023 19:38:30 -0500 Subject: [PATCH 047/196] Fixed some bad assert syntax --- OverworldGlitchRules.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/OverworldGlitchRules.py b/OverworldGlitchRules.py index 2372993f..d135a9b6 100644 --- a/OverworldGlitchRules.py +++ b/OverworldGlitchRules.py @@ -148,7 +148,7 @@ def get_boots_clip_exits_lw(world, player): for names, parent_regions, target_regions in boots_clips: region_pair = get_world_pair(world, player, get_region_pairs(world, player, names, parent_regions, target_regions), True) if region_pair and region_pair[2]: - assert(region_pair[0], f'Exit name missing in OWG pairing from {region_pair[1]} to {region_pair[2]}') + assert region_pair[0], f'Exit name missing in OWG pairing from {region_pair[1]} to {region_pair[2]}' yield(region_pair[0], region_pair[1], region_pair[2]) @@ -164,7 +164,7 @@ def get_boots_clip_exits_dw(world, player): for names, parent_regions, target_regions in boots_clips: region_pair = get_world_pair(world, player, get_region_pairs(world, player, names, parent_regions, target_regions), False) if region_pair and region_pair[2]: - assert(region_pair[0], f'Exit name missing in OWG pairing from {region_pair[1]} to {region_pair[2]}') + assert region_pair[0], f'Exit name missing in OWG pairing from {region_pair[1]} to {region_pair[2]}' yield(region_pair[0], region_pair[1], region_pair[2]) @@ -191,7 +191,7 @@ def get_mirror_clip_spots(world, player): for names, parent_regions, target_regions in mirror_clips: region_pair = get_world_pair(world, player, get_region_pairs(world, player, names, parent_regions, target_regions), False) if region_pair and region_pair[2] and not world.is_tile_lw_like(OWTileRegions[region_pair[1]], player): - assert(region_pair[0], f'Exit name missing in OWG pairing from {region_pair[1]} to {region_pair[2]}') + assert region_pair[0], f'Exit name missing in OWG pairing from {region_pair[1]} to {region_pair[2]}' yield(region_pair[0], region_pair[1], region_pair[2]) @@ -205,7 +205,7 @@ def get_mirror_offset_spots(world, player): for names, parent_regions, target_regions, path_to in mirror_offsets: region_pair = get_world_pair(world, player, get_region_pairs(world, player, names, parent_regions, target_regions, path_to), False) if region_pair and region_pair[2] and not world.is_tile_lw_like(OWTileRegions[region_pair[1]], player): - assert(region_pair[0], f'Exit name missing in OWG pairing from {region_pair[1]} to {region_pair[2]}') + assert region_pair[0], f'Exit name missing in OWG pairing from {region_pair[1]} to {region_pair[2]}' yield(region_pair[0], region_pair[1], region_pair[2], region_pair[3]) From 142f158c2749de86457d181ffe06cad7634fcefa Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 12 Mar 2023 20:06:40 -0500 Subject: [PATCH 048/196] Reversing chicken fix for Bonk Drops --- Rom.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rom.py b/Rom.py index 8c329293..c2d0533d 100644 --- a/Rom.py +++ b/Rom.py @@ -1652,7 +1652,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): # warning, this temporary patch might cause fairies to respawn differently?, limiting this to bonk drop mode only rom.write_byte(snes_to_pc(0x0DB808), 0x03) # patch fairies sprites to not permadeath like enemies rom.write_byte(snes_to_pc(0x0DB810), 0x8A) # allows heart pieces to travel across water - rom.write_byte(snes_to_pc(0x0DB730), 0x08) # allows chickens to travel across water + # rom.write_byte(snes_to_pc(0x0DB730), 0x08) # allows chickens to travel across water # allow smith into multi-entrance caves in appropriate shuffles if world.shuffle[player] in ['restricted', 'full', 'lite', 'lean', 'crossed', 'insanity'] or (world.shuffle[player] == 'simple' and world.mode[player] == 'inverted'): From 4c887ca0443f6a024f9505bb5182f74c32638abe Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 12 Mar 2023 21:46:10 -0500 Subject: [PATCH 049/196] Fixed issue with forced HP on Good Bee Bonk Location --- Rom.py | 2 +- asm/owrando.asm | 19 +++++++++---------- data/base2current.bps | Bin 105775 -> 105783 bytes 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Rom.py b/Rom.py index c2d0533d..f351d017 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '4458a348e3040d79d0e28d572579fcb5' +RANDOMIZERBASEHASH = 'c27bdd316ea8312214643e0a4ea32c10' class JsonRom(object): diff --git a/asm/owrando.asm b/asm/owrando.asm index 3f3a7be0..c65ca10c 100644 --- a/asm/owrando.asm +++ b/asm/owrando.asm @@ -416,13 +416,13 @@ OWBonkGoodBeeDrop: LDA.l RoomDataWRAM[$0120].high : AND.b #$02 : PHA : BNE + ; check if collected LDA.b #$1B : STA $12F ; JSL Sound_SetSfx3PanLong ; seems that when you bonk, there is a pending bonk sfx, so we clear that out and replace with reveal secret sfx + - LDA.l OWBonkPrizeData+(42*6+4) : BEQ + ; multiworld item - LDA.l OWBonkPrizeData+(42*6+3) + LDA.l OWBonkPrizeTable[42].mw_player : BEQ + ; multiworld item + LDA.l OWBonkPrizeTable[42].loot JMP .spawn_item + .determine_type ; S = Collected, FlagBitmask, X (row + 2) - LDA.l OWBonkPrizeData+(42*6+3) ; A = item id + LDA.l OWBonkPrizeTable[42].loot ; A = item id CMP.b #$B0 : BNE + LDA.b #$79 : JMP .sprite_transform ; transform to bees + CMP.b #$42 : BNE + @@ -455,7 +455,7 @@ OWBonkGoodBeeDrop: + CMP.b #$B2 : BNE + LDA.b #$E3 : BRA .sprite_transform ; transform to fairy + CMP.b #$B3 : BNE .spawn_item - INX : INX : LDA.l OWBonkPrizeData+(42*6+5) + INX : INX : LDA.l OWBonkPrizeTable[42].vert_offset CLC : ADC.b #$08 : PHA LDA.w $0D00,Y : SEC : SBC.b 1,S : STA.w $0D00,Y LDA.w $0D20,Y : SBC.b #$00 : STA.w $0D20,Y : PLX @@ -469,14 +469,14 @@ OWBonkGoodBeeDrop: LDA.l RoomDataWRAM[$0120].high : ORA.b #$02 : STA.l RoomDataWRAM[$0120].high REP #$20 - LDA.l TotalItemCounter : INC : STA.l TotalItemCounter + LDA.l TotalItemCounter : INC : STA.l TotalItemCounter SEP #$20 BRA .return ; spawn itemget item .spawn_item ; A = item id ; Y = bonk sprite slot ; S = Collected PLX : BEQ + : LDA.b #$00 : STA.w $0DD0,Y : BRA .return - + LDA.l OWBonkPrizeData+(42*6+4) : STA.l !MULTIWORLD_SPRITEITEM_PLAYER_ID + + LDA.l OWBonkPrizeTable[42].mw_player : STA.l !MULTIWORLD_SPRITEITEM_PLAYER_ID LDA.b #$01 : STA !REDRAW @@ -494,10 +494,10 @@ OWBonkGoodBeeDrop: LDA.b #$00 : STA.w $0F20,Y ; layer the sprite is on ; sets OW event bitmask flag, uses free RAM - LDA.l OWBonkPrizeData+(42*6+2) : STA.w $0ED0,Y + LDA.l OWBonkPrizeTable[42].flag : STA.w $0ED0,Y ; determines the initial spawn point of item - LDA.w $0D00,Y : SEC : SBC.l OWBonkPrizeData+(42*6+5) : STA.w $0D00,Y + LDA.w $0D00,Y : SEC : SBC.l OWBonkPrizeTable[42].vert_offset : STA.w $0D00,Y LDA.w $0D20,Y : SBC #$00 : STA.w $0D20,Y LDA.b #$01 : STA !REDRAW : STA !FORCE_HEART_SPAWN @@ -506,7 +506,6 @@ OWBonkGoodBeeDrop: PLY LDA #$08 ; makes original good bee not spawn RTL - nop #20 } ; Y = sprite slot index of bonk sprite @@ -591,7 +590,7 @@ OWBonkDrops: LDX.b $8A : LDA.l OverworldEventDataWRAM,X : ORA 1,S : STA.l OverworldEventDataWRAM,X REP #$20 - LDA.l TotalItemCounter : INC : STA.l TotalItemCounter + LDA.l TotalItemCounter : INC : STA.l TotalItemCounter SEP #$20 + JMP .return diff --git a/data/base2current.bps b/data/base2current.bps index f12897a42e34bbc4aaa14a6c175c0ec7b49f9d35..afa8a1642722bfba64456decd9b60135f452e931 100644 GIT binary patch delta 8557 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 Date: Sun, 12 Mar 2023 21:57:21 -0500 Subject: [PATCH 050/196] Version bump 0.3.0.3 --- CHANGELOG.md | 5 +++++ OverworldShuffle.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 522421f8..3329232e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 0.3.0.3 +- Fixed issue with new Cold Fairy Statue location not dropping correct item +- Fixed issue with Multiworld due to new Cold Fairy Statue location +- Improved water collision to only target Heart Piece sprites (rando items) + ## 0.3.0.2 - \~Merged in DR v1.2.0.12~ - Fixed some door landing issues diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 264c5a19..4623610a 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -7,7 +7,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType from OverworldGlitchRules import create_owg_connections from Utils import bidict -version_number = '0.3.0.2' +version_number = '0.3.0.3' # branch indicator is intentionally different across branches version_branch = '-u' From b44caa76a7c7178e4696355c8706f2dd8c9f063d Mon Sep 17 00:00:00 2001 From: aerinon Date: Mon, 13 Mar 2023 14:26:25 -0600 Subject: [PATCH 051/196] Customize certain potions refills. --- Fill.py | 7 ++++--- Main.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Fill.py b/Fill.py index 4859ebc3..9acf7d45 100644 --- a/Fill.py +++ b/Fill.py @@ -661,9 +661,10 @@ def sell_potions(world, player): for potion in ['Green Potion', 'Blue Potion', 'Red Potion']: location = random.choice(filter_locations(ItemFactory(potion, player), locations, world, potion=True)) locations.remove(location) - p_item = next(item for item in world.itempool if item.name == potion and item.player == player) - world.push_item(location, p_item, collect=False) - world.itempool.remove(p_item) + p_item = next((item for item in world.itempool if item.name == potion and item.player == player), None) + if p_item: + world.push_item(location, p_item, collect=False) + world.itempool.remove(p_item) def sell_keys(world, player): diff --git a/Main.py b/Main.py index f731df8a..f6631ce5 100644 --- a/Main.py +++ b/Main.py @@ -250,6 +250,7 @@ def main(args, seed=None, fish=None): set_rules(world, player) district_item_pool_config(world) + fill_specific_items(world) for player in range(1, world.players + 1): if world.shopsanity[player]: sell_potions(world, player) @@ -262,7 +263,6 @@ def main(args, seed=None, fish=None): if args.print_custom_yaml: world.settings.record_item_pool(world) dungeon_tracking(world) - fill_specific_items(world) logger.info(world.fish.translate("cli", "cli", "placing.dungeon.prizes")) fill_prizes(world) From f4524d8a871c104b605da39590d30bdf5c6a7cef Mon Sep 17 00:00:00 2001 From: aerinon Date: Mon, 13 Mar 2023 16:28:11 -0600 Subject: [PATCH 052/196] Fix Snitch Lady (West) location on map --- source/overworld/EntranceShuffle2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index 51a702dd..0aa18e92 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -3001,7 +3001,7 @@ ow_prize_table = {'Links House': (0x8b1, 0xb2d), 'Inverted Big Bomb Shop': (0x8b 'Lost Woods Gamble': (0x240, 0x080), 'Fortune Teller (Light)': (0x2c0, 0x4c0), 'Snitch Lady (East)': (0x310, 0x7a0), - 'Snitch Lady (West)': (0x800, 0x7a0), + 'Snitch Lady (West)': (0x080, 0x7a0), 'Bush Covered House': (0x2e0, 0x880), 'Tavern (Front)': (0x270, 0x980), 'Light World Bomb Hut': (0x070, 0x980), From 02c7a5279cde735a0a149199034d7bc4b107a841 Mon Sep 17 00:00:00 2001 From: aerinon Date: Mon, 13 Mar 2023 20:40:45 -0600 Subject: [PATCH 053/196] Fix some paired doors --- DoorShuffle.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DoorShuffle.py b/DoorShuffle.py index 6bafd806..6a954f3c 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -1813,7 +1813,8 @@ def shuffle_door_types(door_type_pools, paths, world, player): for dungeon, doors in custom_dict.items(): all_custom[dungeon].extend(doors) - world.paired_doors[player].clear() + for pd in world.paired_doors[player]: + pd.pair = False used_doors = shuffle_trap_doors(door_type_pools, paths, start_regions_map, all_custom, world, player) # big keys used_doors = shuffle_big_key_doors(door_type_pools, used_doors, start_regions_map, all_custom, world, player) From b2b3d789cad2a9553cf3789cc507c97fe9e55414 Mon Sep 17 00:00:00 2001 From: aerinon Date: Mon, 13 Mar 2023 20:42:55 -0600 Subject: [PATCH 054/196] Some rom fixes: - standing item data now cleared on dungeon exit Escape assist won't fill arrows resulting in free quiver in retro bow mode --- Rom.py | 2 +- data/base2current.bps | Bin 93952 -> 93980 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Rom.py b/Rom.py index 0ca8e140..2fa2dee5 100644 --- a/Rom.py +++ b/Rom.py @@ -37,7 +37,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '4faba57f154a2263bf91af041a0d8700' +RANDOMIZERBASEHASH = '15edc718abbbd94ee34e15ae24b219a3' class JsonRom(object): diff --git a/data/base2current.bps b/data/base2current.bps index 5a239f15ad6edbb9e939796d1ecad384d3162259..aa3b0b2195ea6804734645a963163a4ac524d11b 100644 GIT binary patch delta 9289 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 From 5ce983513f9f4d6b46ac5bae87624419aff384fa Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 13 Mar 2023 21:57:11 -0500 Subject: [PATCH 055/196] Fixed incorrect edge coord data for Desert Pass WS --- OWEdges.py | 4 ++-- asm/owrando.asm | 4 ++-- data/base2current.bps | Bin 105783 -> 105783 bytes 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/OWEdges.py b/OWEdges.py index 1e40a0c4..cf397f18 100644 --- a/OWEdges.py +++ b/OWEdges.py @@ -143,7 +143,7 @@ def create_owedges(world, player): create_owedge(player, 'Tree Line WC', 0x2e, We, Wr, 0x1a) .coordInfo(0x0b3c, 0x0660), create_owedge(player, 'Eastern Nook NE', 0x2f, No, Ld, 0x16) .coordInfo(0x0f78, 0x1820), create_owedge(player, 'Desert EC', 0x30, Ea, Ld, 0x1e, 0x39).coordInfo(0x0ee4, 0x1480), - create_owedge(player, 'Desert ES', 0x30, Ea, Ld, 0x1f, 0x39).coordInfo(0x0f8c, 0x1980), + create_owedge(player, 'Desert ES', 0x30, Ea, Ld, 0x1f, 0x39).coordInfo(0x0f90, 0x1980), create_owedge(player, 'Flute Boy Approach NW', 0x32, No, Ld, 0x17) .coordInfo(0x044c, 0x1800), create_owedge(player, 'Flute Boy Approach NC', 0x32, No, Ld, 0x18) .coordInfo(0x04e8, 0x180c), create_owedge(player, 'Flute Boy Approach EC', 0x32, Ea, Ld, 0x1a) .coordInfo(0x0d04, 0x05c0), @@ -167,7 +167,7 @@ def create_owedges(world, player): create_owedge(player, 'Ice Cave SW', 0x37, So, Wr, 0x1e) .coordInfo(0x0e80, 0x1002), create_owedge(player, 'Ice Cave SE', 0x37, So, Ld, 0x1f) .coordInfo(0x0f50, 0x101c), create_owedge(player, 'Desert Pass WC', 0x3a, We, Ld, 0x1f) .coordInfo(0x0ee4, 0x03e0), - create_owedge(player, 'Desert Pass WS', 0x3a, We, Ld, 0x20) .coordInfo(0x0f8c, 0x0860), + create_owedge(player, 'Desert Pass WS', 0x3a, We, Ld, 0x20) .coordInfo(0x0f90, 0x0860), create_owedge(player, 'Desert Pass EC', 0x3a, Ea, Ld, 0x20) .coordInfo(0x0f18, 0x0640), create_owedge(player, 'Desert Pass ES', 0x3a, Ea, Ld, 0x21) .coordInfo(0x0fcb, 0x08c0), create_owedge(player, 'Dam NC', 0x3b, No, Ld, 0x1e) .coordInfo(0x0728, 0x1816), diff --git a/asm/owrando.asm b/asm/owrando.asm index c65ca10c..c6878285 100644 --- a/asm/owrando.asm +++ b/asm/owrando.asm @@ -1407,7 +1407,7 @@ dw $0c78, $0ce3, $006b, $0cad, $3434, $0000, $0000, $001b dw $0ce4, $0d33, $004f, $0d0b, $3434, $0000, $0001, $001c dw $0d34, $0db8, $0084, $0d76, $3434, $0000, $0000, $001d dw $0ea8, $0f20, $0078, $0ee4, $3a3a, $0000, $0000, $001e -dw $0f70, $0fa8, $0038, $0f8c, $3a3a, $0000, $0000, $001f +dw $0f78, $0fa8, $0030, $0f90, $3a3a, $0000, $0000, $001f dw $0f18, $0f18, $0000, $0f18, $3b3b, $0000, $0000, $0020 dw $0fc8, $0fc8, $0000, $0fc8, $3b3b, $0000, $0000, $0021 dw $0e28, $0fb8, $0190, $0ef0, $3c3c, $0000, $0000, $0022 @@ -1482,7 +1482,7 @@ dw $0c78, $0ce3, $006b, $0cad, $3333, $0000, $0000, $001c dw $0ce4, $0d33, $004f, $0d0b, $3333, $0000, $0001, $001d dw $0d34, $0db8, $0084, $0d76, $3333, $0000, $0000, $001e dw $0ea8, $0f20, $0078, $0ee4, $3039, $0000, $0000, $001f -dw $0f70, $0fa8, $0038, $0f8c, $3039, $0000, $0000, $0020 +dw $0f78, $0fa8, $0030, $0f90, $3039, $0000, $0000, $0020 dw $0f18, $0f18, $0000, $0f18, $3a3a, $0000, $0000, $0021 dw $0fc8, $0fc8, $0000, $0fc8, $3a3a, $0000, $0000, $0022 dw $0e28, $0fb8, $0190, $0ef0, $3b3b, $0000, $0000, $0023 diff --git a/data/base2current.bps b/data/base2current.bps index afa8a1642722bfba64456decd9b60135f452e931..0ed1d01ce03f420c88e1cac5ad40768007df7aa9 100644 GIT binary patch delta 74 zcmV-Q0JZ19P=jd!w`l<{9 From 2338b3e4e782f19caff77de81eb8ce0403215054 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Tue, 14 Mar 2023 06:20:26 -0500 Subject: [PATCH 056/196] Fixed item duping issue on OW --- asm/owrando.asm | 30 ++++++++++++++++++++++++++++++ data/base2current.bps | Bin 105783 -> 105806 bytes 2 files changed, 30 insertions(+) diff --git a/asm/owrando.asm b/asm/owrando.asm index c6878285..627b5503 100644 --- a/asm/owrando.asm +++ b/asm/owrando.asm @@ -40,6 +40,10 @@ JSL OWAdjustExitPosition org $02c1a9 JSL OWEndScrollTransition +; org $09AFFB +; jsl OWDestroyDuplicateSprites : nop #2 ; LDA.w $0C9A,X : CMP.w $040A +; db $B0 ; changing following opcode to BCS + org $04E881 Overworld_LoadSpecialOverworld_RoomId: org $04E8B4 @@ -238,6 +242,28 @@ OWWhirlpoolEnd: RTL } +OWDestroyItemSprites: +{ + LDX.b #$0F + .nextSprite + LDA.w $0E20,X + CPY.b #$D8 : BCC .continue + CPY.b #$EC : BCS .continue + .killSprite ; need to kill sprites from D8 to EB on screen transition + STZ.w $0DD0,X + .continue + DEX : BPL .nextSprite + RTL + ; LDA.w $0C9A,X : CMP.w $040A ; what we wrote over + ; BNE .killSprite + ; ; need to kill sprites from D8 to EB + ; CPY.b #$D8 : BCC .keepSprite + ; CPY.b #$EC : BCS .keepSprite + ; .killSprite + ; CLC : RTL + ; .keepSprite + ; SEC : RTL +} OWMirrorSpriteOnMap: { lda.w $1ac0,x : bit.b #$f0 : beq .continue @@ -648,6 +674,10 @@ OWBonkSpritePrep: org $aa9000 OWDetectEdgeTransition: { + PHY : PHX + JSL OWDestroyItemSprites + PLX : PLY + STZ.w $06FC LDA.l OWMode : ORA.l OWMode+1 : BEQ .vanilla JSR OWShuffle diff --git a/data/base2current.bps b/data/base2current.bps index 0ed1d01ce03f420c88e1cac5ad40768007df7aa9..6905656b3ffb644a3b43466e4ea408bce0341e38 100644 GIT binary patch delta 1096 zcmWksdrVVz6u#%Sy={4vG6py%qbce@9x~pOS6iHbc7kqW8v_R!nz}2vOicoZbqK`WJs(uLk3bQw>QdvLAyHS!Bj=0pW{^_gU<>gAF zMSW~wp*iXNgi2zJS#422WzR{nAcOrza#%TF=9ZW1j83)2%$ZJ?KXIp0tt4D$XJzSd z&iz#O2w=ti(65_>R@NGL^M!*JZdqf#sBX7iQkUK7?T9SsS_v&}wdAtL6p7$wdlW~3 zb^8b9C4=6*SNp@i4W2f-+BGDS@>Iw1l8&+JVERhXq)IV;>wdU86# z!t)|0K}Wi}O6u*G>0uG#Vo6@gRvkx1zyTlr(kUID`|B((W2>KdeL(jqy+J;aYRPOc z7|QPsOKiH`eZR|w79!-D=7oq#Vc?7}H#vi(J-$GJl&?B|G;YQ<_{%JalAR2RLPoir z##334`CNTYV;>*T_t>lPQBGjF;kU3n8>%1^)7fw`ZjY6*o-uk|K8f>`e!JDH^GVh3 z3{m<-t2b59Zf|I50$9>-$BG=tgfd)^1Gz%`A_v|Ki+Q;h2gkP!F)1Yt^-dY>y~P7g z#(WOsrG-9EB2zTjWeO54Iz-%qNn)aKqwtbBgMPVb&S1M@nr(8NpSjs29HX4KH|b|_ zbuPRgR}ejhx6mzaRYre{zO;Fb$2D~%niQaeKZlO zzz2P+y!H=e-8-ntZymgsME9g3BZsx89i6;l$~DF}ji? z()@RpUfM@UC#DE9$H)=;N`M$y3h$}#OCO7nvDjW}yT~=hYBtpnQdmVM|u}25la0Wltff_tGG#?VTdfF;&;`m5p^s`s? zEc!%x)XoU8@e(}ggoQmQ$>(P;z=nK?C*}FLBOi(aYCq{`cuTmCv`J6km3&Cwp{(m4 zs;-y@Ushj*SInoeGiF#{U4j#76)C delta 1035 zcmW-feM}p57{~9qw%3DEU^3V!Af><@!k{1^Nr9H~x=|eiU33=4k~&Kcm{G#pCR`^N zN+BIw;TPyemz6SmT3c5Q0wQRFrp(#0__mp4xEQn5L~pu(G+?~?&+~lq`967`JWrl) zmWjn>!uu)+cR#?7``VxmV4v?gehlDK1{dCi$IP}c3v!r9(aWj37g_Ael>EDQ=R=`Z zqe*`DT3}o;v?3E34?UWYhnNc@CFC)miO$3_BWx(tWpv5aBkb@w-L|ign8aa@`HC!t zPT#-e9{@l2eviC_!vJHJ+(Gx8r>rxZP30xSJ;+<{iw=Yp10nKLN zoY)!bkKq9IG|tY5J)3_Ga3rID><y)L3ht1vPo;44@q}G8lfH!NLzWs zm7^PWiRXe6Uh5t?zBMMJ>hse~BJwC9iEM~VrHv8xN_0yJB~LV#jXJp~=bwIckZ=LR zdJd!HQaBA6XrL5&vy06Z^IJy0Hz;!TX%ozTO;9X<$xUdbW`7~iZiiVBFYag)P+A$3 zKn*%s2IYL3DT5ahu&3rxTej70d8T2o-$hdXANiFck)Rw@MICWCJ)92qRtZjTIRxy3 zRcxg$95~UYLHqsKronb~*f-`F+E^UphY_yZ2edxaQx2!HQ`47F1~uX9Enb+=YR3QJ zP<0nhukzA?vk$^OEHmo^o6pj%T?kZgI9_1Qt95K$+95nR&BpK-=15s4s#if0F=Q>F zY$d2&1-eAle*QEGfeRn&n+;#&8y0ZqkWS^o9SZcb3gR=AlkeSEP;-T}kwy9E95Y<> zns>kyH&y1#WBqntFGDy7N3HURlFNSW5)Wq(up7Q{8V927 z8;{vLZI{{6EcJm7Ol&)jUQ9SL3W2C)zZYwCz_D)&&pYdZH?t;KkS`m!2pF(d}LJodf zgFdW;BT+4HELb?x{vdAa=|V&m6z{{j7To&gbqFe*&3++Q#B4BP)KCS9_<0GUs-PmZ zLK8=C{JK}~rQY8mIN{A5g1XoJIo@=$rZbwh*Dl_uf_90J8tQuoDI39@9D5y;<$gqZ zFF>Mqwh65z;i3Nk!<(H3 From e55d23915cf3f7bd10276efe5bee6579a1328d6c Mon Sep 17 00:00:00 2001 From: codemann8 Date: Tue, 14 Mar 2023 06:21:42 -0500 Subject: [PATCH 057/196] Improved Standard+Inverted preset yaml --- docs/standardinverted.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/standardinverted.yaml b/docs/standardinverted.yaml index c5590090..8195851a 100644 --- a/docs/standardinverted.yaml +++ b/docs/standardinverted.yaml @@ -4,7 +4,15 @@ settings: 1: mode: standard ow_mixed: true +entrances: + 1: + entrances: + Sanctuary Grave: Sewer Drop + two-way: + Sanctuary: Sanctuary Exit ow-tileflips: 1: + force_no_flip: + - 0x13 undefined_chance: 100 From 636819ffc00c27e7befe0e9aa800ca02fc529606 Mon Sep 17 00:00:00 2001 From: aerinon Date: Tue, 14 Mar 2023 16:05:28 -0600 Subject: [PATCH 058/196] Versioning update --- Main.py | 4 +++- RELEASENOTES.md | 9 +++++++-- Rom.py | 4 +++- data/base2current.bps | Bin 93980 -> 93979 bytes 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Main.py b/Main.py index f6631ce5..69476418 100644 --- a/Main.py +++ b/Main.py @@ -34,7 +34,9 @@ from source.overworld.EntranceShuffle2 import link_entrances_new from source.tools.BPS import create_bps_from_data from source.classes.CustomSettings import CustomSettings -__version__ = '1.2.0.12u' +version_number = '1.2.0.13' +version_branch = '-u' +__version__ = f'{version_number}{version_branch}' from source.classes.BabelFish import BabelFish diff --git a/RELEASENOTES.md b/RELEASENOTES.md index fbfdfe5c..e2c23a11 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -109,8 +109,13 @@ These are now independent of retro mode and have three options: None, Random, an # Bug Fixes and Notes -* Unreleased Version - * MultiServer can not disable forfeits if desired +* 1.2.0.13u + * Allow green/blue potion refills to be customized + * OW Map showing dungeon entrance at Snitch Lady (West) fixed (instead of @ HC Courtyard) + * Standing item data is cleared on transition to overworld (enemy drops won't bleed to overworld sprites) + * Escape assist won't give you a free quiver in retro bow mode + * Fixed an issue where a door would be opened magically (due to original pairing) + * MultiServer can now disable forfeits if desired * 1.2.0.12u * Fix for mirror portal in inverted * Yet another fix for blocked door in Standard ER diff --git a/Rom.py b/Rom.py index 2fa2dee5..49ab7804 100644 --- a/Rom.py +++ b/Rom.py @@ -37,7 +37,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '15edc718abbbd94ee34e15ae24b219a3' +RANDOMIZERBASEHASH = '29863ca305a8474c452cd13b3f921898' class JsonRom(object): @@ -1608,6 +1608,8 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): rom.name.extend([0] * (21 - len(rom.name))) rom.write_bytes(0x7FC0, rom.name) + rom.write_bytes(0x138010, bytearray(__version__, 'utf8')) + # set player names for p in range(1, min(world.players, 255) + 1): rom.write_bytes(0x195FFC + ((p - 1) * 32), hud_format_text(world.player_names[p][team])) diff --git a/data/base2current.bps b/data/base2current.bps index aa3b0b2195ea6804734645a963163a4ac524d11b..832779a30453f400fad4258196d067eb09eafe59 100644 GIT binary patch delta 2651 zcmW+#dstLu8b9xuE0+-lW`;o#4+m66@tPT8;b`r8EidbuspXW2u%o7}SLE`Y0|y-O zFqhBagBf*3;dmI793CvnG_>_bTf4JQ`m}3nn5B>5RiMTV+RTF7mVQHOUC@(X88E zw#qFJ+Pg(|d#jw^EVBRZ?%3t=4zd-Zyt2NP4U2LV99ic?_Ci3;Z}PMM2*`tjPy1Yx zF10hr%RX+92X_e~`{(AcofG@;4LAT}@EbHc^7ekY&?T}P-|YB%7km0znBD%FVa+GC z?e+$deG_-n&rEoIzbtjfwawcKzgv!60}Zm87uj4!prwIVww)~-i5d2X$s9#r#Q*0En6TvA6C9I(6GlW-a5XRB(JE2>np zDFw7nKGQbw(D(REGUsKT7^!{-`S_}8MU8}HkN&F279*Le^|NpNY6>i)2W11a{|8F;ep`_J3FKD<~$gYxba1OOVL!YLcIec-e22GXHda(;!!RyzKSn@L*Q0 zmz|p7t_09?SQ_21HZH||VWZJ5<0Uy#`HCS^4CrJl6JB>?80bxEZFi}8oa)iAMVzQIM) ziDJ*ylwLJWH}{C9GdAFR78EO~ZXBGo2y%Mv&Z-)rh|<-)8^P9-edVR1n!c@De`qTk za~|hU4t!x^zC+Ozi89S@RtyQT?h|B6G@J7M&}E(X(Yz`0(gC2VO;5feus52wnmkif6QI&ke8Bp}vy{n3@NGO-NO*4BOw6CRDgY{_2R*ZjKe$Pa(y#>uN1;RFCN*=m{FMyrPa5|S~XiOLd}#?+DND5?G1 zb5tDe_UY=#DGlV%nmY2S26ACJ`B4Lf8QlZZ&e6`U5_N3)!tX0^z3Y$r=`V9i$U-gT z4%<>EuQ4~$%~}T{Og5?1!aQSaQ@o8&ORNInIdvc3$LXoB?h>=&0FR*jz(%m zTQ5+|D6&8YMeqUZHjs+C-Q^9 zw6WS&j>bDMp1*-cu0Rz9taU=PT75%EPY|`$0_U$p`C6239&OiMR%f3sXMl`Z4EIQU`+OS@lLlhP<&r3 z>An-is-wQOG{UdHnuY}9b-947G{7X?%uz-ZO3Nlq24K=J;>}&Y7esIW5EV-Zm@9bv z1UYYj%H=CJ@5AM*1Ks@)*GT(pcIQbglF6>s0W$lPm+c7i&Y)&=Ah09h8_9W-QbpAv zDqbBdof7!l;nT@$tnV0<`x=PqZ7Kc3JoJ?-L3hwNj(CSblO`{(g{&iaDX_KVmM=^z z?3#%ChvL@2i%#D|g?<{Q)~h)CyiB5}&|!7_>U#8xYqPJf)Y8Z$xjV$UUdE0?en};S z>$HDb`tDh^4aE{9wEzlNkwH?2D(n4>%fpnA$0;x}dlm1%UmxG`&b1bgq*4gyU}TTP zFx?)Tonn3@Po+ZcGwG$i+ns0Q7i~jSheRqQ|69~F}wwv=FQF8MeWSZxKHfrM@3zM?~vSdB0S z?)A&|lu7osnhu~8W{@Ea68_#;J^tI<hi4IqAyVDhPkkWJ* zr<%%Og41C#txF&m(_y?Z(BeKy7Hvl7+b>t2og8NZ1Wd3bAvI08wK$N~WR(eKq%R{l zm6vo>Otokki5T-wW)CCBOfZW1&@WqS?)c@7K1W<`ea>>_O5}c?BHPv$#*gR~(%m+} zX!9_e2?d|8Jun?tt+Sxe zJTf~2md%Mtt3qukUMc8 z@F=R1C}#w~S#GBmT?}+uod>v;&Ffg<2o+m=@=;ul=a2#4^5y%3Rb(Ioo-w~s$4)=g z?A&=Gl(tEBB~ymriX9ioG%HM0&0Og1U2lb-bSX7^YA<|6 TJ0cGrF3@Xc=0Chs#n${E3=cYS delta 2633 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 From 6166151b331b56a48bf8120c6c096e1e66d63577 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Tue, 14 Mar 2023 17:50:55 -0500 Subject: [PATCH 059/196] Burning OWR Version to ROM --- Rom.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Rom.py b/Rom.py index bfe4d259..60d4eadc 100644 --- a/Rom.py +++ b/Rom.py @@ -1710,6 +1710,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): # set rom name # 21 bytes from Main import __version__ + from OverworldShuffle import __version__ as ORVersion seedstring = f'{world.seed:09}' if isinstance(world.seed, int) else world.seed # todo: change to DR when Enemizer is okay with DR rom.name = bytearray(f'ER{__version__.split("-")[0].replace(".","")[0:3]}_{team+1}_{player}_{seedstring}O\0', 'utf8')[:21] @@ -1717,6 +1718,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): rom.write_bytes(0x7FC0, rom.name) rom.write_bytes(0x138010, bytearray(__version__, 'utf8')) + rom.write_bytes(0x150010, bytearray(ORVersion, 'utf8')) # set player names for p in range(1, min(world.players, 255) + 1): From a14ca50a7148304a152fed7d665e0f42794f6308 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 15 Mar 2023 05:44:18 -0500 Subject: [PATCH 060/196] Adjusting Bonk Sprite landing position and water ripple --- Rom.py | 2 +- asm/owrando.asm | 17 ++++++++++------- data/base2current.bps | Bin 105834 -> 105866 bytes 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Rom.py b/Rom.py index 60d4eadc..5c1c2ced 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = 'baa1135c06e1e38d4005ba3c7acb977b' +RANDOMIZERBASEHASH = '8e95ee70d7afec407016449e86439550' class JsonRom(object): diff --git a/asm/owrando.asm b/asm/owrando.asm index 7b51e697..614fffd0 100644 --- a/asm/owrando.asm +++ b/asm/owrando.asm @@ -436,7 +436,7 @@ OWBonkGoodBeeDrop: JMP .spawn_item + - .determine_type ; S = Collected, FlagBitmask, X (row + 2) + .determine_type ; S = Collected LDA.l OWBonkPrizeTable[42].loot ; A = item id CMP.b #$B0 : BNE + LDA.b #$79 : JMP .sprite_transform ; transform to bees @@ -480,13 +480,13 @@ OWBonkGoodBeeDrop: JSL.l OWBonkSpritePrep .mark_collected ; S = Collected - PLA : BNE .return + PLA : BNE + LDA.l RoomDataWRAM[$0120].high : ORA.b #$02 : STA.l RoomDataWRAM[$0120].high REP #$20 LDA.l TotalItemCounter : INC : STA.l TotalItemCounter SEP #$20 - BRA .return + + BRA .return ; spawn itemget item .spawn_item ; A = item id ; Y = bonk sprite slot ; S = Collected @@ -498,15 +498,18 @@ OWBonkGoodBeeDrop: LDA.b #$EB : STA.l $7FFE00 JSL Sprite_SpawnDynamically+15 ; +15 to skip finding a new slot, use existing sprite + TYX : STZ.w $0F20,X ; layer the sprite is on + ; affects the rate the item moves in the Y/X direction - LDA.b #$00 : STA.w $0D40,Y + STZ.w $0D40,X LDA.b #$0A : STA.w $0D50,Y - LDA.b #$20 : STA.w $0F80,Y ; amount of force (gives height to the arch) + LDA.b #$1A : STA.w $0F80,Y ; amount of force (gives height to the arch) LDA.b #$FF : STA.w $0B58,Y ; stun timer LDA.b #$30 : STA.w $0F10,Y ; aux delay timer 4 ?? dunno what that means - LDA.b #$00 : STA.w $0F20,Y ; layer the sprite is on + ; sets the tile type that is underneath the sprite, water + LDA.b #$09 : STA.l $7FF9C2,X ; TODO: Figure out how to get the game to set this ; sets OW event bitmask flag, uses free RAM LDA.l OWBonkPrizeTable[42].flag : STA.w $0ED0,Y @@ -625,7 +628,7 @@ OWBonkDrops: LDA.b #$00 : STA.w $0D40,Y LDA.b #$0A : STA.w $0D50,Y - LDA.b #$20 : STA.w $0F80,Y ; amount of force (gives height to the arch) + LDA.b #$1A : STA.w $0F80,Y ; amount of force (gives height to the arch) LDA.b #$FF : STA.w $0B58,Y ; stun timer LDA.b #$30 : STA.w $0F10,Y ; aux delay timer 4 ?? dunno what that means diff --git a/data/base2current.bps b/data/base2current.bps index 6c525c078e1b9a39e6135af37015e0a77dc69c9c..9ddd927b64f3e3b5fba5e9fdd002f1b1f72f4d04 100644 GIT binary patch delta 8862 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 delta 8802 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 From 7b939a91669984b5169abac2a632f71d9a1daccd Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 15 Mar 2023 21:04:27 -0500 Subject: [PATCH 061/196] Fix ... issue in credits --- Text.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Text.py b/Text.py index 5d023818..3df1e679 100644 --- a/Text.py +++ b/Text.py @@ -1309,6 +1309,7 @@ class GoldCreditMapper(CharTextMapper): class GreenCreditMapper(CharTextMapper): char_map = {' ': 0x9F, + '.': 0x52, '·': 0x52} alpha_offset = -0x29 alpha_lower_offset = -0x29 From 61846c0f816a19f313828f739971980f73615c69 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 16 Mar 2023 06:31:05 -0500 Subject: [PATCH 062/196] Load correct Link/Bunny palette on transition --- Rom.py | 2 +- asm/owrando.asm | 32 ++++++++++++++++++++++---------- data/base2current.bps | Bin 105866 -> 105904 bytes 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/Rom.py b/Rom.py index 5c1c2ced..6bdff514 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '8e95ee70d7afec407016449e86439550' +RANDOMIZERBASEHASH = '8862307c3bdf3ae838f7e07b5df6596b' class JsonRom(object): diff --git a/asm/owrando.asm b/asm/owrando.asm index 614fffd0..25eb1fc9 100644 --- a/asm/owrando.asm +++ b/asm/owrando.asm @@ -985,17 +985,17 @@ OWWorldTerrainUpdate: ; x = owid of destination screen, y = 1 for land to water, lda #$38 : sta $012f ; play sfx - #$3b is an alternative ; toggle bunny mode - lda MoonPearlEquipment : bne .nobunny - lda.l InvertedMode : bne .inverted + lda MoonPearlEquipment : beq + : jmp .nobunny + + lda.l InvertedMode : bne .inverted lda CurrentWorld : bra + .inverted lda CurrentWorld : eor #$40 + and #$40 : beq .nobunny - LDA.w $0703 : BEQ + ; check if forced transition - CPY.b #$03 : BEQ .end_forced_whirlpool - LDA.b #$17 : STA.b $5D - LDA.b #$01 : STA.w $02E0 : STA.b $56 - LDA.w $0703 : BRA .end_forced_edge + CPY.b #$03 : BEQ ++ + LDA.b #$17 : STA.b $5D + LDA.b #$01 : STA.w $02E0 : STA.b $56 + LDA.w $0703 : JSR OWLoadGearPalettes : BRA .end_forced_edge + ++ JSR OWLoadGearPalettes : BRA .end_forced_whirlpool + CPY.b #$01 : BEQ .auto ; check if going from land to water CPY.b #$02 : BEQ .to_bunny_reset_swim ; bunny state if swimming to land @@ -1014,8 +1014,8 @@ OWWorldTerrainUpdate: ; x = owid of destination screen, y = 1 for land to water, STZ.b $5D PLX BRA .to_pseudo_bunny - .whirlpool - PLX : RTS + .whirlpool + PLX : JMP OWLoadGearPalettes .to_bunny_reset_swim LDA.b $5D : CMP.b #$04 : BNE .to_bunny ; check if swimming JSL Link_ResetSwimmingState @@ -1024,7 +1024,7 @@ OWWorldTerrainUpdate: ; x = owid of destination screen, y = 1 for land to water, LDA.b #$17 : STA.b $5D .to_pseudo_bunny LDA.b #$01 : STA.w $02E0 : STA.b $56 - RTS + JMP OWLoadGearPalettes .nobunny lda $5d : cmp #$17 : bne + ; retain current state unless bunny @@ -1073,6 +1073,18 @@ OWWorldTerrainUpdate: ; x = owid of destination screen, y = 1 for land to water, .return RTS } +OWLoadGearPalettes: +{ + PHX : PHY : LDA $00 : PHA + LDA.w $02E0 : BEQ + + JSL LoadGearPalettes_bunny + BRA .return + + + JSL LoadGearPalettes_link + .return + PLA : STA $00 : PLY : PLX + RTS +} OWAdjustExitPosition: { LDA.w $06FC : CMP.b #$60 : BEQ .stone_bridge diff --git a/data/base2current.bps b/data/base2current.bps index 9ddd927b64f3e3b5fba5e9fdd002f1b1f72f4d04..80b9ff4c47ccae58a2488fd7c379e255ff6ee04e 100644 GIT binary patch delta 361 zcmeC$&9(uEQW;s2g6FQ;oXJ?j%%nJN@^cmq#>i#?*6jkUj8p9DyQlV_`doLC;RDl3 z#`9hc1{b*IThD83Sj^loaivACKI8OEVeW>FK6O*qgCyD30~Jr#5#esw>FJ>9@S$ie zGy4ab1I!Sbm> zFij(;ow31{S$CZT%YL(tRjr;WvA-HbfBCRa11o1&(wf0O$CY_?PSLXI3=N&)7no*C zmQJ^JVKfU?Dp|HRCH4U01#6Jf52lk(PFCgPY&gpYJ*=>dV`zzdQO&Fl9sbnm=qG wSkC@o%f4TBkV*cGTOMD-{M^*(jINB*%)A-h+vQyulOs4dzP~J6=jL=60RE1Ung9R* delta 344 zcmdn6o2_d%+lEv|7L}yib2n!))-W^um^%46iw2`XvjFRM0anH-cJ(z=`%itYJIU~Y zX(i)%uLgq)T=T8xH8w0}ZrHohqF0}Befa0P3pMLOGLtV&@7?L?py}`-Z7nnV2ayBJ zA1YS!Ixk~v0CF3W4={e7WnXKCz7mJ7zWRx&P&eZX>oQL2}j{lGMhoc5ot%M?uJ{Lzl`O5Xa~zlxZh4Y87Pzz zJN>2$qrRP|lW@b)XM!mkve*1!`@nMc4_o&AvV%;{XWjDn8s^)lHD9kR5^h+Xr#){r nzhU3}1d& Date: Sat, 18 Mar 2023 05:47:49 -0500 Subject: [PATCH 063/196] Correcting OW screen palette on transition --- Rom.py | 2 +- asm/owrando.asm | 42 +++++++++++++++++++++++++++++++++++++++++- data/base2current.bps | Bin 105904 -> 105983 bytes 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/Rom.py b/Rom.py index 6bdff514..8a5bf3b8 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '8862307c3bdf3ae838f7e07b5df6596b' +RANDOMIZERBASEHASH = '155051ece07ef1b60c875a5746189c26' class JsonRom(object): diff --git a/asm/owrando.asm b/asm/owrando.asm index 25eb1fc9..8818a35e 100644 --- a/asm/owrando.asm +++ b/asm/owrando.asm @@ -47,6 +47,9 @@ Overworld_LoadSpecialOverworld_RoomId: org $04E8B4 Overworld_LoadSpecialOverworld: +org $02A9DA +JSL OWSkipMosiac + org $07982A Link_ResetSwimmingState: @@ -945,7 +948,20 @@ OWNewDestination: ; crossed OW shuffle and terrain ldx $05 : ldy $08 : jsr OWWorldTerrainUpdate - lda $05 : sta $8a + lda $8a : JSR OWDetermineScreensPaletteSet : STX $04 + lda $05 : sta $8a : JSR OWDetermineScreensPaletteSet + + ;PLA : AND.b #$3F : BEQ .leaving_woods + ;LDA $8A : AND.b #$3F : BEQ .entering_woods + CPX $04 : BEQ .skip_palette ; check if next screen's palette is different + LDA $00 : PHA + JSL OverworldLoadScreensPaletteSet_long ; loading correct OW palette + PLA : STA $00 + ;.leaving_woods + ;.entering_woods + .skip_palette + lda $8a + rep #$30 : rts } OWLoadSpecialArea: @@ -1085,6 +1101,30 @@ OWLoadGearPalettes: PLA : STA $00 : PLY : PLX RTS } +OWDetermineScreensPaletteSet: ; A = OWID to check +{ + LDX.b #$02 + PHA : AND.b #$3F + CMP.b #$03 : BEQ .death_mountain + CMP.b #$05 : BEQ .death_mountain + CMP.b #$07 : BEQ .death_mountain + LDX.b #$00 + .death_mountain + PLA : PHX : TAX : LDA.l OWTileWorldAssoc,x : BEQ + + PLX : INX : RTS + + PLX : RTS +} +OWSkipMosiac: +{ + LDA.l OWMode : ORA.l OWMode+1 : BEQ .vanilla + PLA : PLA : PEA $A9F2 + RTL + .vanilla + LDA.b $8A : AND.b #$3F : BNE + ; what we wrote over, kinda + PLA : PLA : PEA $A9E3 + + + RTL +} OWAdjustExitPosition: { LDA.w $06FC : CMP.b #$60 : BEQ .stone_bridge diff --git a/data/base2current.bps b/data/base2current.bps index 80b9ff4c47ccae58a2488fd7c379e255ff6ee04e..f789ffebafedccb4a6aa51508e7aa5e7b26b5775 100644 GIT binary patch delta 2576 zcmW+#YgAKL7S7I#@P37NfWzfs!o!MHK}1Xi1zRX}YCDWd8|w>=THCS|1>q!cfq;R8 zOE`I;;dQ+R#u_HIX-6&8wo0b8r8BFmt2(u=5j#pdZQ7}A$FYmK%%8izZ|{B1zGv_K zxi3l=E=t|Ip(RN9;BycN1>Oa(Tj#aEA~{nzsk78uhPSgej=E^$G!g08LQVH@7?=^o zT{ETc<>u9sM#^F1lmkZUhsm=ICi6UX%*fTW+bE}zbAv`PZKUSyoU+G4E!esF`Qko9 z)|X=lo2mbHaPtkck^00sq}Caym^tW&Oy-!7f;nc8|9Y4y;o7`ICpmV~FCC~a{C*2I z-0I-OdLu;{IW^5vN_y<}f?tLe11;)n8G3_@QHc~WqdnZNRwGsO&oLP$A?2+yy_tHE z*(%b*66Q(Kn`5n`%g zU|i5@rt5a)D>taUFVk!NzsLl ziJNLX{C;npyM`XZTYCE(jSZ2QX;xbqVZpB!#Sow*{it52AbMR5=}drBxJ1q-z+vg7 z_8|ef;7v({TL3G`Z%Gg*IkjEzo1P>ppe}MXeHJ44sR?z7t@QxFP_H3-2EgXwd0)pTM8t3-Bv^ z;E(r--SIx*tdx1B+YsgxkrLzEv*Ihu;x$*66>3mQyGcdj$i-yHmQxv4-O*mXt!eSP z4j{|1vzGiP8J57)BrOHxD;hiaAL#2aMUp-yv-yq)7dGGVv0`6?z%6mL2ymFMVex1S zb4aHP7>#@^5<5c3z7#kKYst?kkPaavF%{B7Lb@0+W(u0E2Gl?{r9x5QabXgEz&EI# zoJ@se2qfdF@Km1oNEE&+kKawv)U5F9^sYtpEI*M5I)Kl$_X56vcnHYejW!bs!JAM` zzCcj2N@1oc*H1W@pJfdXucoxalI zq$&-T$CcUN4&#f6XT`4D7`bM!V(LZKv6T#@L1xI&K^rS9yzBCZILgSiG{}P8?%|Aom?J#TMRgpvBgp_HK{(8*%#z zxPz~tt|!N*1V3^!+AC&SgFbB@{2_M5|--2K^&>nMK&*T$*Iy5Ce^Kutc{jA-{ zZ$z*&r_H8X(4LoKjx^NR$vSUR2H*6St9?U4e(9qa--18her%ihKhq0-3EFGsoug*- zU2mZ#Uh{v~twq=G`le!2V)6CwO+3jlqYTqxoE6bSZPNEnymeWu!n1*_myJGA6*7NkqpQ*oHCA+{`_ zpr2gI;)nc+_f8h1K=2fU<eN?iA+l; z)MniZ^7{yb&P4X;NRvTVII15my4H*fsD#cDhfHj6REHZJMI=ZCi4aFJRj?lv#H51c zq}t8hY}C~4pPJExwReORJ*j(l>{|2XWqve4W>ioulWpsu{Xp_aYBsEn+DVuQJsTjH z6;&H&AV6MecC)1Ys`on z9Ztu61}R!gp2^|gp(5HGNJ(%K)7l3x3T2T3oeLP;tQRoQouhpk$hVK zXW%$t3SoWtvGh)JU6FQZ=zR5SCP$Qat`H&s!o3ex!wLWy$zH=N_(M{$Xm*f2Yrq2K zSH zH1env3KVGrY^_f`8$e}S0|qyUCeUkVhyWYnW`&L_Qe6fGOP{Ylb8c7dG|aA9%=E8h ze9Rxh0`c`Qp2qoQE-_s@s1|8%BpO8lqfe7J$^bpSBXP{A84*^zQ?-uJbvKxzPMcr! z@Sf(OX0)(z)F!Q~`{_rQmWY~?@g~fZJ3P5j21|=`s|-CGdM{}I_(C& delta 2573 zcmW+$3sh4_8qS{=l=maVpb1;XKk(4N>^!Z)7`pl-JWHyduGne|M%P?Dpuuh^*8ffRM>sfm9KL)}PiCSGBZno0~ zyj5ZbExs*TC_ZY&YU$gWx^}+IYp1_!;HN&fJZj=k+Ah#vbbF@Wij&f5_>ojiU1{J) zSh@=H^Gz(hrEBN`Gc}dbY^i1j_BJwqZwcZ|*=$&aH_1xHN85Zvb_hV~iwau%d7g$)L@4*pZ9_ zDrl!l>XC$cv7Q5+{yD0esR_wEa_XI?;m`D_?<(1w3~8AfVm58T<_VPmk_05daB8c$ zcb^m`U?p;;qBHD1DK$oZn+&hZ#~M8%>K(s!CVT-Y3)lU495-4Hwu!$=t4=_ySH{Hm zFWQ0n=zqR%Hj;ET)WnxE$5Aq#X}F+NsAxu6&WaZV?Y$j2!w^y0SKuA(h*fa9F*gO zt(KU8gy`8zLFtu3mElTZv4Ki$wCPAP`9K3Xij0hI(-EuLdGhITO+e-%cNGz*Kz8=} zym(}abem1FR^S*WoywD(68Db#d} zAbyzU{fVK@9^TV!663=duh}g|mU2z2tGrx{*zy*g9G7{>LGn@>%$>2S=TeLifHWxe z-bIx6I#Q3n%(=D`cN%0y9qV;+;^IkfD9W{p1k)f3c9WmdpeRW>@Pi_7%%&`Uc$ATL zN2vBlhp2gE1r4-3X}~0LRTCo(b72R0lZM4mNIs(>DX~AyfPDqJISVOj@LrOyJg${86vInL`!Do7sj+^m3 z(wYt@H5>M~;L43XtWfbtcW#4IH*LHqM?5*cxrZ$CXJmi|p1;=N5erS8hy&9hRnM_) z_Fpbfhh$WZT`&&Vsqd}D29@FeraMnf8#~5TDN1xBWD}G;JC$jB>gObkr$PSyY0{nv zGfvmq1g^N3jQZxidq%25K@}%ua9lqVig1_oIgm6V~qx?&Bjqw zmrbV^QFm=vjZC!AQxrCjT`A{^f@?ns!wVc8v(&aZ=--X>|wp#G@ooCKWHI2BSLC%RmNIe zi(@UM(^-724kdbJc*5HDbg+Z7g0ltE&ep+ekV2d~(9Ei;Y~>Qh@BUavo$t2xlhU=O ziGgc%V}&8=Jo!Wi72y%vnwSuf0;0`QBYD|O}z2ii^>DeOWrsw8=+(s zN;XBw-d9@PGL$i+Uo7&9M5@!DJ9yRUpB?Q`gQj!Cb!JwZn)tg z+T%}*x5ig@^F!2;Zb58Wi}TEQBN@&G9lT6#=E9PA5%gG;T7xxUr>(aKZV7bH$b(#H zCF}E`I#TW$iKH&}j4Y-m$ao%TODB3pUUw^ZDiQO6!kxcQiJWq(&U;ni?%4V+r*}&Q z<$=O&CK-au(I99)D~2ltxLZlm@`1|VDadCU)9SqW=LA&BE+t|c(&~(4#imxrGh9R< zPDBcpvn=NcEc8oBZ9b&u$X!oHB%H|T1u*W>i^{+48B!TLO`E%R(oCNySaI=5h!3Ta zJNOiNFCUgkUaEh=Kb;RN!edXLsQ=LBtYLd2jWxaeDu3ldhz2MiRYjnM?WDN~mJ8dT zi-c^b$m1dygp;JV7?#JLNN={+lo~yrixmfLE`|S5F~kAH`~O=4^C2~Y`VUV4iHuxa zKp_fA>2=LRMtbj*c(BDIp+-sNBH=&TN%k)S2dpHr#ZU~J{7V+Ys}g7?+*0@pjFLlo zC=?>$^umE9{#$xDB!(nXu>w+Lqn(_LA#E!lCt|N&CyD(uMn76 zN4^)_@~|$nmkJ}PWl*FJ>*96C2)Q?ux#vu2;UG<+HJCKNmYjfXp#m;GW8x%cc`|5U=VvhGu(KW69&Xurpb9neq M4-db!YWe&B1CZ_kCIA2c From 504f2e6a3abbaa30803c2fa12db887aa05771710 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 19 Mar 2023 11:01:22 -0500 Subject: [PATCH 064/196] Fixed issue with MW Player ID on Bonk Locations --- Rom.py | 2 +- asm/owrando.asm | 11 +++-------- data/base2current.bps | Bin 105983 -> 105928 bytes 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/Rom.py b/Rom.py index 8a5bf3b8..87860b0c 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '155051ece07ef1b60c875a5746189c26' +RANDOMIZERBASEHASH = '109fde24581211c605a1d4836dd8d470' class JsonRom(object): diff --git a/asm/owrando.asm b/asm/owrando.asm index 8818a35e..4730478d 100644 --- a/asm/owrando.asm +++ b/asm/owrando.asm @@ -494,9 +494,7 @@ OWBonkGoodBeeDrop: ; spawn itemget item .spawn_item ; A = item id ; Y = bonk sprite slot ; S = Collected PLX : BEQ + : LDA.b #$00 : STA.w $0DD0,Y : BRA .return - + LDA.l OWBonkPrizeTable[42].mw_player : STA.l !MULTIWORLD_SPRITEITEM_PLAYER_ID - - LDA.b #$01 : STA !REDRAW + + LDA.b #$01 : STA !REDRAW LDA.b #$EB : STA.l $7FFE00 JSL Sprite_SpawnDynamically+15 ; +15 to skip finding a new slot, use existing sprite @@ -618,9 +616,7 @@ OWBonkDrops: ; spawn itemget item .spawn_item ; A = item id ; Y = tree sprite slot ; S = Collected, FlagBitmask, X (row + 2) PLX : BEQ + : LDA.b #$00 : STA.w $0DD0,Y : JMP .return ; S = FlagBitmask, X (row + 2) - + LDA 2,S : TAX : INX : INX - LDA.w OWBonkPrizeData,X : STA.l !MULTIWORLD_SPRITEITEM_PLAYER_ID - DEX + + LDA 2,S : TAX : INX LDA.b #$01 : STA !REDRAW @@ -948,12 +944,11 @@ OWNewDestination: ; crossed OW shuffle and terrain ldx $05 : ldy $08 : jsr OWWorldTerrainUpdate - lda $8a : JSR OWDetermineScreensPaletteSet : STX $04 lda $05 : sta $8a : JSR OWDetermineScreensPaletteSet ;PLA : AND.b #$3F : BEQ .leaving_woods ;LDA $8A : AND.b #$3F : BEQ .entering_woods - CPX $04 : BEQ .skip_palette ; check if next screen's palette is different + CPX.w $0AB3 : BEQ .skip_palette ; check if next screen's palette is different LDA $00 : PHA JSL OverworldLoadScreensPaletteSet_long ; loading correct OW palette PLA : STA $00 diff --git a/data/base2current.bps b/data/base2current.bps index f789ffebafedccb4a6aa51508e7aa5e7b26b5775..13b9ab4e536d50ae220897ada064df65d5f345af 100644 GIT binary patch delta 10112 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 delta 10247 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 From b549860fb8e2b1d82d85bd1e5e196e493cb63188 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 19 Mar 2023 12:21:43 -0500 Subject: [PATCH 065/196] Fixed issue with no Woods mosiac on exit in vanilla OW --- Rom.py | 2 +- asm/owrando.asm | 5 +++-- data/base2current.bps | Bin 105928 -> 105930 bytes 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Rom.py b/Rom.py index 87860b0c..9760d525 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '109fde24581211c605a1d4836dd8d470' +RANDOMIZERBASEHASH = '281fb186ab9e30f98e9705398653a754' class JsonRom(object): diff --git a/asm/owrando.asm b/asm/owrando.asm index 4730478d..6bafb688 100644 --- a/asm/owrando.asm +++ b/asm/owrando.asm @@ -1111,11 +1111,12 @@ OWDetermineScreensPaletteSet: ; A = OWID to check } OWSkipMosiac: { + PHA LDA.l OWMode : ORA.l OWMode+1 : BEQ .vanilla - PLA : PLA : PEA $A9F2 + PLA : PLA : PLA : PEA $A9F2 RTL .vanilla - LDA.b $8A : AND.b #$3F : BNE + ; what we wrote over, kinda + PLA : AND.b #$3F : BNE + ; what we wrote over, kinda PLA : PLA : PEA $A9E3 + RTL diff --git a/data/base2current.bps b/data/base2current.bps index 13b9ab4e536d50ae220897ada064df65d5f345af..5b85faf181a91c9020324b8e6b46453dbb8ecb1f 100644 GIT binary patch delta 115 zcmV-(0F3|0y9Ua;2C!uT17|syvuFW?0|9fB?F1w-*HgygwYB@B{kjVESN4 zqdW2Ji&U{03{^cEJKy$wqDt VfS*aXKScq7SP0VtSmJGRK$6CBFmwO_ delta 113 zcmV-%0FM94y9UU+2C!uT15-JyvuFW?0|9cA?F1to#P>1kL;gYu|Rk0$a&OZVrH- TOSeHq0fATuO7?LUyF185gt9O< From c9c510ae212dff1f80b3a7a523a729436a1b1c35 Mon Sep 17 00:00:00 2001 From: aerinon Date: Wed, 22 Mar 2023 14:58:07 -0600 Subject: [PATCH 066/196] Minor fixes for customized vanilla doors --- DoorShuffle.py | 14 ++++++++++++++ KeyDoorShuffle.py | 19 ++++++++++++------- Main.py | 2 +- RELEASENOTES.md | 3 +++ 4 files changed, 30 insertions(+), 8 deletions(-) diff --git a/DoorShuffle.py b/DoorShuffle.py index 6a954f3c..d7255077 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -322,6 +322,11 @@ def connect_simple_door(world, exit_name, region_name, player): d.dest = region +def connect_simple_door_to_region(exit_door, region): + exit_door.entrance.connect(region) + exit_door.dest = region + + def connect_door_only(world, exit_name, region, player): d = world.check_for_door(exit_name, player) if d is not None: @@ -354,6 +359,12 @@ def connect_two_way(world, entrancename, exitname, player): x.dest = y if y is not None: y.dest = x + if x.dependents: + for dep in x.dependents: + connect_simple_door_to_region(dep, ext.parent_region) + if y.dependents: + for dep in y.dependents: + connect_simple_door_to_region(dep, entrance.parent_region) def connect_one_way(world, entrancename, exitname, player): @@ -373,6 +384,9 @@ def connect_one_way(world, entrancename, exitname, player): y = world.check_for_door(exitname, player) if x is not None: x.dest = y + if x.dependents: + for dep in x.dependents: + connect_simple_door_to_region(dep, ext.parent_region) def unmark_ugly_smalls(world, player): for d in ['Eastern Hint Tile Blocked Path SE', 'Eastern Darkness S', 'Thieves Hallway SE', 'Mire Left Bridge S', diff --git a/KeyDoorShuffle.py b/KeyDoorShuffle.py index f8bda68e..81e5a527 100644 --- a/KeyDoorShuffle.py +++ b/KeyDoorShuffle.py @@ -1561,13 +1561,18 @@ def validate_key_layout_sub_loop(key_layout, state, checked_states, flat_proposa def invalid_self_locking_key(key_layout, state, prev_state, prev_avail, world, player): if prev_state is None or state.used_smalls == prev_state.used_smalls: return False - new_bk_doors = set(state.big_doors).difference(set(prev_state.big_doors)) - state_copy = state.copy() - while len(new_bk_doors) > 0: - for door in new_bk_doors: - open_a_door(door.door, state_copy, key_layout.flat_prop, world, player) - new_bk_doors = set(state_copy.big_doors).difference(set(prev_state.big_doors)) - expand_key_state(state_copy, key_layout.flat_prop, world, player) + if state.found_forced_bk() and not prev_state.found_forced_bk(): + return False + if state.big_key_opened: + new_bk_doors = set(state.big_doors).difference(set(prev_state.big_doors)) + state_copy = state.copy() + while len(new_bk_doors) > 0: + for door in new_bk_doors: + open_a_door(door.door, state_copy, key_layout.flat_prop, world, player) + new_bk_doors = set(state_copy.big_doors).difference(set(prev_state.big_doors)) + expand_key_state(state_copy, key_layout.flat_prop, world, player) + else: + state_copy = state new_locations = set(state_copy.found_locations).difference(set(prev_state.found_locations)) important_found = False for loc in new_locations: diff --git a/Main.py b/Main.py index 69476418..fe8fd123 100644 --- a/Main.py +++ b/Main.py @@ -34,7 +34,7 @@ from source.overworld.EntranceShuffle2 import link_entrances_new from source.tools.BPS import create_bps_from_data from source.classes.CustomSettings import CustomSettings -version_number = '1.2.0.13' +version_number = '1.2.0.14' version_branch = '-u' __version__ = f'{version_number}{version_branch}' diff --git a/RELEASENOTES.md b/RELEASENOTES.md index e2c23a11..71d39a67 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -109,6 +109,9 @@ These are now independent of retro mode and have three options: None, Random, an # Bug Fixes and Notes +* 1.2.0.14u + * Small fix for key logic validation (got rid of a false negative) + * Customized doors in ice cross work properly now * 1.2.0.13u * Allow green/blue potion refills to be customized * OW Map showing dungeon entrance at Snitch Lady (West) fixed (instead of @ HC Courtyard) From 7212284ba07c8cd73a03cb189fafd754e300b282 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 22 Mar 2023 16:00:37 -0500 Subject: [PATCH 067/196] Fixed disconnected Dark Chapel Exit with Inverted + Vanilla ER --- source/overworld/EntranceShuffle2.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index 3515fa47..c6898b3a 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -171,6 +171,9 @@ def do_vanilla_connections(avail_pool): connect_vanilla_two_way(ent, avail_pool.default_map[ent], avail_pool) if ent in avail_pool.one_way_map and avail_pool.one_way_map[ent] in avail_pool.exits: connect_vanilla(ent, avail_pool.one_way_map[ent], avail_pool) + if avail_pool.inverted: + ext = avail_pool.world.get_entrance('Dark Sanctuary Hint Exit', avail_pool.player) + ext.connect(avail_pool.world.get_region('Dark Chapel Area', avail_pool.player)) def do_main_shuffle(entrances, exits, avail, mode_def): From f14657ad74379a83ffeaa3c51f9e24e5cf65287e Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 22 Mar 2023 16:00:58 -0500 Subject: [PATCH 068/196] Minor text tweak --- Text.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Text.py b/Text.py index 3df1e679..bf4f22cb 100644 --- a/Text.py +++ b/Text.py @@ -113,7 +113,7 @@ Triforce_texts = [ " Cool seed,\n\n right?", "\n We did it!", " Spam those\n emotes in\n wilds chat", - "\n O M G", + "\n O M G", " Hello. Will you\n you be my friend?", " Beetorp\n was\n here!", " The Wind Fish\n will wake soon.\n Hoot!", From 2de64ef5658797c4a1a4c945a887dfe4677cb99b Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 22 Mar 2023 16:07:39 -0500 Subject: [PATCH 069/196] Set up code structure for future OW palette changes and return to safer changes --- Rom.py | 2 +- asm/owrando.asm | 66 +++++++++++++++++++++++++++--------------- data/base2current.bps | Bin 105930 -> 105965 bytes 3 files changed, 43 insertions(+), 25 deletions(-) diff --git a/Rom.py b/Rom.py index 9760d525..cc784646 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '281fb186ab9e30f98e9705398653a754' +RANDOMIZERBASEHASH = '0a3d1d4bbec659013be5ed876c2658bd' class JsonRom(object): diff --git a/asm/owrando.asm b/asm/owrando.asm index 6bafb688..a308a9fc 100644 --- a/asm/owrando.asm +++ b/asm/owrando.asm @@ -48,7 +48,8 @@ org $04E8B4 Overworld_LoadSpecialOverworld: org $02A9DA -JSL OWSkipMosiac +JSL OWSkipPalettes +BCC OverworldHandleTransitions_change_palettes : NOP #4 org $07982A Link_ResetSwimmingState: @@ -943,20 +944,12 @@ OWNewDestination: ; crossed OW shuffle and terrain ldx $05 : ldy $08 : jsr OWWorldTerrainUpdate - - lda $05 : sta $8a : JSR OWDetermineScreensPaletteSet - - ;PLA : AND.b #$3F : BEQ .leaving_woods - ;LDA $8A : AND.b #$3F : BEQ .entering_woods - CPX.w $0AB3 : BEQ .skip_palette ; check if next screen's palette is different - LDA $00 : PHA - JSL OverworldLoadScreensPaletteSet_long ; loading correct OW palette - PLA : STA $00 - ;.leaving_woods - ;.entering_woods - .skip_palette - lda $8a + ldx $8a : lda $05 : sta $8a : stx $05 ; $05 is prev screen id, $8a is dest screen + + jsr OWGfxUpdate + + lda $8a rep #$30 : rts } OWLoadSpecialArea: @@ -1084,6 +1077,23 @@ OWWorldTerrainUpdate: ; x = owid of destination screen, y = 1 for land to water, .return RTS } +OWGfxUpdate: +{ + REP #$20 : LDA.l OWMode : AND.w #$0207 : BEQ .is_only_mixed : SEP #$20 + ;;;;PLA : AND.b #$3F : BEQ .leaving_woods + LDA.b $8A : AND.b #$3F : BEQ .entering_woods + ;LDA.b $05 : JSL OWSkipPalettes : BCS .skip_palettes + LDA.b $8A : JSR OWDetermineScreensPaletteSet + CPX.w $0AB3 : BEQ .skip_palettes ; check if next screen's palette is different + LDA $00 : PHA + JSL OverworldLoadScreensPaletteSet_long ; loading correct OW palette + PLA : STA $00 + .leaving_woods + .entering_woods + .is_only_mixed + .skip_palettes + SEP #$20 +} OWLoadGearPalettes: { PHX : PHY : LDA $00 : PHA @@ -1105,21 +1115,29 @@ OWDetermineScreensPaletteSet: ; A = OWID to check CMP.b #$07 : BEQ .death_mountain LDX.b #$00 .death_mountain - PLA : PHX : TAX : LDA.l OWTileWorldAssoc,x : BEQ + + PLA : PHX : TAX : LDA.l OWTileWorldAssoc,X : BEQ + PLX : INX : RTS + PLX : RTS } -OWSkipMosiac: +OWSkipPalettes: { - PHA - LDA.l OWMode : ORA.l OWMode+1 : BEQ .vanilla - PLA : PLA : PLA : PEA $A9F2 - RTL + STA.b $05 ; A = previous screen, also stored in $05 + ; only skip mosaic if OWR Layout or Crossed + PHP : REP #$20 : LDA.l OWMode : AND.w #$0207 : BEQ .vanilla : PLP + ; checks to see if going to from any DM screens + ;LDA.b $05 : JSR OWDetermineScreensPaletteSet : TXA : AND.b #$FE : STA $04 + ;LDA.b $8A : JSR OWDetermineScreensPaletteSet : TXA : AND.b #$FE + ;CMP.b $04 : BNE .skip_palettes + BRA .vanilla+1 + .vanilla - PLA : AND.b #$3F : BNE + ; what we wrote over, kinda - PLA : PLA : PEA $A9E3 - + - RTL + PLP + LDA.b $05 : AND.b #$3F : BEQ .skip_palettes ; what we + LDA.b $8A : AND.b #$BF : BNE .change_palettes ; wrote over, kinda + .skip_palettes + SEC : RTL ; mosaic transition occurs + .change_palettes + CLC : RTL } OWAdjustExitPosition: { diff --git a/data/base2current.bps b/data/base2current.bps index 5b85faf181a91c9020324b8e6b46453dbb8ecb1f..d492f90b61065409a0fa2cfbfa8766eb30c23ef7 100644 GIT binary patch delta 454 zcmV;%0XhE4y9VvM2C!uT1hOqn(z9s+tO5+BB6OCjkQ3_a>gq(38wAk-mXqxSDFM!d z7X`N$1pyy60lK$0I{`uj0g;z_KLH&Ci;Q`Imz+NVKmkXW-9G_r0lK$JKmpnUEIEL^ z5C#}y0i6&AXyP!X1Svllc_xSojQ|Ix1*8Zdx|F7hr3HnGh6NxHmX}*Y0V@)^lwg|( zEFFM>3ZGP-(a-}-l$V%80VM&4m%c**BnCN_fNUT+m*_(QHyt^arCrGc&<7$am8Natz=!m0nj_8UC9LSHIvDcHx3Da%?_nq$rtbl zsRV^xoInF$+8T`m2cs+w34nco`lVgT7tjZ(1C0X*WL;pwAg=;|swoEo@EqbGrHUy( z@D!zrAXAp?vkLGEr2t4G^235?g#h9p+FGRmNUh)kt}H->lSdh(jbNezD@eXgKbM7Q z+LJnnrSJp#=wSL_g#`$wQWB(@11Nw2D5V9WVds(@DU~sRm-R#eE+1b-6M)6$5oEAy wto#P>1kL;gYu|Rk0!zq7ZVrH-1D8QX0UQH4X^6LAMFC=12#FQY0*s delta 397 zcmV;80doHBy9Ua;2C!uT1ZO#z#>)nLIeSvmw-P39R&q}Ae@w!p+5mY0X3K6KLKn3#kWsD0onoqWtS>L0Uj8| zl%)lQiXb(X?6V5+3Z(!@BJ#t6XoUcmRYL(Q62+8Yn+Pl&fPo61RG!h$15BTnl0yL{ z0g{)vLjfcP8W&r0!Y41KbM7Q+LJnno$v$t=wSL_NTWb{qkVt}XlQ8k@~LZR zDL>E!XlV4~scV-PMFB27ODz+Cjzy2PYpnbR@C42L25aAT!2(ywMs5y(pGjnc*LiXi rfU9mRo|_Lbj-Ox@nwMNhj++!QsmfetinoJB0b*DP(*s!IZE`@8VCkJP From 37750c55cfe33d8257d8e3b2f7f3cf5a12de36c9 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 22 Mar 2023 16:09:01 -0500 Subject: [PATCH 070/196] Remove Polar from Crossed if Mixed not enabled --- BaseClasses.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/BaseClasses.py b/BaseClasses.py index 40b48ec9..39a032fb 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -26,9 +26,10 @@ class World(object): self.teams = 1 self.owShuffle = owShuffle.copy() self.owTerrain = {} - self.owCrossed = owCrossed.copy() self.owKeepSimilar = {} self.owMixed = owMixed.copy() + self.owCrossed = owCrossed.copy() + self.owCrossed = self.owCrossed if self.owCrossed != 'polar' or self.owMixed else 'none' self.owWhirlpoolShuffle = {} self.owFluteShuffle = {} self.shuffle = shuffle.copy() From 4cbd45c17b41aad896ad6e1eadf938574a67298d Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 22 Mar 2023 17:49:32 -0500 Subject: [PATCH 071/196] Version bump 0.3.0.4 --- CHANGELOG.md | 8 ++++++++ OverworldShuffle.py | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3329232e..42ae2fb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 0.3.0.4 +- \~Merged in DR v1.2.0.14~ + - Fixed issue with enemy drops on OW enemies + - Fixed issue with magically opened doors +- Inverted + Vanilla ER can now generate +- Fixed issue with Multiworld bonk items not sending to correct player +- Minor improvements to OW Palettes on screen transition + ## 0.3.0.3 - Fixed issue with new Cold Fairy Statue location not dropping correct item - Fixed issue with Multiworld due to new Cold Fairy Statue location diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 4623610a..b9e2dc8f 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -7,7 +7,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType from OverworldGlitchRules import create_owg_connections from Utils import bidict -version_number = '0.3.0.3' +version_number = '0.3.0.4' # branch indicator is intentionally different across branches version_branch = '-u' From c3266a904ad27eabbcc60f66dd249dca5f5f9ea6 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 22 Mar 2023 18:38:26 -0500 Subject: [PATCH 072/196] Disallow some LH placements in DM in Lite/Lean ER --- source/overworld/EntranceShuffle2.py | 51 +++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index c6898b3a..d456f64e 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -528,9 +528,14 @@ def do_links_house(entrances, exits, avail, cross_world): # can't have links house on eddm in restricted because Inverted Aga Tower isn't available # todo: inverted full may have the same problem if both links house and a mandatory connector is chosen # from the 3 inverted options - if avail.world.shuffle[avail.player] in ['restricted'] and avail.world.is_tile_swapped(0x03, avail.player): + if avail.world.shuffle[avail.player] in ['restricted', 'lite', 'lean'] and avail.world.is_tile_swapped(0x03, avail.player): avail.links_on_mountain = True forbidden.extend(['Spike Cave', 'Dark Death Mountain Fairy']) + + if avail.world.shuffle[avail.player] in ['lite', 'lean']: + if avail.world.is_tile_swapped(0x05, avail.player): + avail.links_on_mountain = True + forbidden.extend(['Cave Shop (Dark Death Mountain)']) else: avail.links_on_mountain = True @@ -558,15 +563,26 @@ def do_links_house(entrances, exits, avail, cross_world): if links_house in dm_spots and avail.world.owShuffle[avail.player] == 'vanilla': if avail.links_on_mountain: return # connector is fine - multi_exit_caves = figure_out_connectors(exits) - entrance_pool = entrances if avail.coupled else avail.decoupled_entrances - if cross_world: - possible_dm_exits = [e for e in entrances if e in LH_DM_Connector_List] - possible_exits = [e for e in entrance_pool if e not in dm_spots] + if avail.world.shuffle[avail.player] in ['lite', 'lean']: + rem_exits = [e for e in avail.exits if e in Connector_Exit_Set and e not in Dungeon_Exit_Set] + multi_exit_caves = figure_out_connectors(rem_exits) + if cross_world: + possible_dm_exits = [e for e in avail.entrances if e not in entrances and e in LH_DM_Connector_List] + possible_exits = [e for e in avail.entrances if e not in entrances and e not in dm_spots] + else: + world_list = LW_Entrances if not avail.inverted else DW_Entrances + possible_dm_exits = [e for e in avail.entrances if e not in entrances and e in LH_DM_Connector_List and e in world_list] + possible_exits = [e for e in avail.entrances if e not in entrances and e not in dm_spots and e in world_list] else: - world_list = LW_Entrances if not avail.inverted else DW_Entrances - possible_dm_exits = [e for e in entrances if e in LH_DM_Connector_List and e in world_list] - possible_exits = [e for e in entrance_pool if e not in dm_spots and e in world_list] + multi_exit_caves = figure_out_connectors(exits) + entrance_pool = entrances if avail.coupled else avail.decoupled_entrances + if cross_world: + possible_dm_exits = [e for e in entrances if e in LH_DM_Connector_List] + possible_exits = [e for e in entrance_pool if e not in dm_spots] + else: + world_list = LW_Entrances if not avail.inverted else DW_Entrances + possible_dm_exits = [e for e in entrances if e in LH_DM_Connector_List and e in world_list] + possible_exits = [e for e in entrance_pool if e not in dm_spots and e in world_list] chosen_cave = random.choice(multi_exit_caves) shuffle_connector_exits(chosen_cave) possible_dm_exits.sort() @@ -2036,6 +2052,23 @@ Connector_Exit_Set = { 'Turtle Rock Isolated Ledge Exit', 'Turtle Rock Ledge Exit (West)' } +Dungeon_Exit_Set = { + 'Eastern Palace Exit', + 'Tower of Hera Exit', + 'Agahnims Tower Exit', + 'Palace of Darkness Exit', + 'Swamp Palace Exit', + 'Skull Woods Final Section Exit', + 'Thieves Town Exit', + 'Ice Palace Exit', + 'Misery Mire Exit', + 'Ganons Tower Exit', + 'Skull Woods First Section Exit', 'Skull Woods Second Section Exit (East)', 'Skull Woods Second Section Exit (West)', + 'Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)', + 'Desert Palace Exit (South)', 'Desert Palace Exit (East)', 'Desert Palace Exit (West)', + 'Turtle Rock Exit (Front)', 'Turtle Rock Isolated Ledge Exit', 'Turtle Rock Ledge Exit (West)' +} + # Entrances that cannot be used to access a must_exit entrance - symmetrical to allow reverse lookups Must_Exit_Invalid_Connections = defaultdict(set) From b513bbef1b8d946e5496ea468552564729906911 Mon Sep 17 00:00:00 2001 From: aerinon Date: Thu, 23 Mar 2023 15:33:29 -0600 Subject: [PATCH 073/196] Logic fix: hookshot needed for pots in GT Conveyor Cross --- DoorShuffle.py | 2 ++ Doors.py | 2 ++ Dungeons.py | 14 ++++++++------ Regions.py | 3 ++- Rules.py | 4 ++-- 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/DoorShuffle.py b/DoorShuffle.py index d7255077..56fda019 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -3806,6 +3806,8 @@ logical_connections = [ ('GT Blocked Stairs Block Path', 'GT Big Chest'), ('GT Speed Torch South Path', 'GT Speed Torch'), ('GT Speed Torch North Path', 'GT Speed Torch Upper'), + ('GT Conveyor Cross Hammer Path', 'GT Conveyor Cross Across Pits'), + ('GT Conveyor Cross Hookshot Path', 'GT Conveyor Cross'), ('GT Hookshot East-Mid Path', 'GT Hookshot Mid Platform'), ('GT Hookshot Mid-East Path', 'GT Hookshot East Platform'), ('GT Hookshot North-Mid Path', 'GT Hookshot Mid Platform'), diff --git a/Doors.py b/Doors.py index 0bd13742..e97505ee 100644 --- a/Doors.py +++ b/Doors.py @@ -1115,6 +1115,8 @@ def create_doors(world, player): create_door(player, 'GT Invisible Catwalk NE', Nrml).dir(No, 0x9c, Right, High).pos(2), create_door(player, 'GT Conveyor Cross EN', Nrml).dir(Ea, 0x8b, Top, High).pos(2), create_door(player, 'GT Conveyor Cross WN', Intr).dir(We, 0x8b, Top, High).pos(0), + create_door(player, 'GT Conveyor Cross Hammer Path', Lgcl), + create_door(player, 'GT Conveyor Cross Hookshot Path', Lgcl), create_door(player, 'GT Hookshot EN', Intr).dir(Ea, 0x8b, Top, High).pos(0), create_door(player, 'GT Hookshot East-Mid Path', Lgcl), create_door(player, 'GT Hookshot Mid-East Path', Lgcl), diff --git a/Dungeons.py b/Dungeons.py index 9d862b05..3835ef62 100644 --- a/Dungeons.py +++ b/Dungeons.py @@ -190,10 +190,11 @@ gt_regions = [ 'GT Tile Room', 'GT Speed Torch', 'GT Speed Torch Upper', 'GT Pots n Blocks', 'GT Crystal Conveyor', 'GT Crystal Conveyor Corner', 'GT Crystal Conveyor Left', 'GT Crystal Conveyor - Ranged Crystal', 'GT Crystal Conveyor Corner - Ranged Crystal', 'GT Compass Room', 'GT Invisible Bridges', 'GT Invisible Catwalk', - 'GT Conveyor Cross', 'GT Hookshot East Platform', 'GT Hookshot Mid Platform', 'GT Hookshot North Platform', - 'GT Hookshot South Platform', 'GT Hookshot South Entry', 'GT Hookshot South Entry - Ranged Crystal', 'GT Map Room', - 'GT Double Switch Entry', 'GT Double Switch Pot Corners - Ranged Switches', 'GT Double Switch Pot Corners', - 'GT Double Switch Left', 'GT Double Switch Left - Crystal', 'GT Double Switch Entry - Ranged Switches', + 'GT Conveyor Cross', 'GT Conveyor Cross Across Pits', 'GT Hookshot East Platform', 'GT Hookshot Mid Platform', + 'GT Hookshot North Platform', 'GT Hookshot South Platform', 'GT Hookshot South Entry', + 'GT Hookshot South Entry - Ranged Crystal', 'GT Map Room', 'GT Double Switch Entry', + 'GT Double Switch Pot Corners - Ranged Switches', 'GT Double Switch Pot Corners', 'GT Double Switch Left', + 'GT Double Switch Left - Crystal', 'GT Double Switch Entry - Ranged Switches', 'GT Double Switch Exit', 'GT Spike Crystal Left', 'GT Spike Crystal Right', 'GT Warp Maze - Left Section', 'GT Warp Maze - Mid Section', 'GT Warp Maze - Right Section', 'GT Warp Maze - Pit Section', 'GT Warp Maze - Pit Exit Warp Spot', @@ -204,8 +205,9 @@ gt_regions = [ 'GT Dash Hall', 'GT Hidden Spikes', 'GT Cannonball Bridge', 'GT Refill', 'GT Gauntlet 1', 'GT Gauntlet 2', 'GT Gauntlet 3', 'GT Gauntlet 4', 'GT Gauntlet 5', 'GT Beam Dash', 'GT Lanmolas 2', 'GT Quad Pot', 'GT Wizzrobes 1', 'GT Dashing Bridge', 'GT Wizzrobes 2', 'GT Conveyor Bridge', 'GT Torch Cross', 'GT Staredown', 'GT Falling Torches', - 'GT Mini Helmasaur Room', 'GT Bomb Conveyor', 'GT Crystal Circles', 'GT Crystal Inner Circle', 'GT Crystal Circles - Ranged Crystal', - 'GT Left Moldorm Ledge', 'GT Right Moldorm Ledge', 'GT Moldorm', 'GT Moldorm Pit', 'GT Validation', 'GT Validation Door', + 'GT Mini Helmasaur Room', 'GT Bomb Conveyor', 'GT Crystal Circles', 'GT Crystal Inner Circle', + 'GT Crystal Circles - Ranged Crystal', 'GT Left Moldorm Ledge', 'GT Right Moldorm Ledge', 'GT Moldorm', + 'GT Moldorm Pit', 'GT Validation', 'GT Validation Door', 'GT Frozen Over', 'GT Brightly Lit Hall', 'GT Agahnim 2', 'Ganons Tower Portal' ] diff --git a/Regions.py b/Regions.py index 6be2bbf3..a90e9f99 100644 --- a/Regions.py +++ b/Regions.py @@ -769,7 +769,8 @@ def create_dungeon_regions(world, player): ['GT Compass Room EN', 'GT Compass Room Warp']), create_dungeon_region(player, 'GT Invisible Bridges', 'Ganon\'s Tower', None, ['GT Invisible Bridges WS']), create_dungeon_region(player, 'GT Invisible Catwalk', 'Ganon\'s Tower', None, ['GT Invisible Catwalk ES', 'GT Invisible Catwalk WS', 'GT Invisible Catwalk NW', 'GT Invisible Catwalk NE']), - create_dungeon_region(player, 'GT Conveyor Cross', 'Ganon\'s Tower', ['Ganons Tower - Conveyor Cross Pot Key'], ['GT Conveyor Cross EN', 'GT Conveyor Cross WN']), + create_dungeon_region(player, 'GT Conveyor Cross', 'Ganon\'s Tower', ['Ganons Tower - Conveyor Cross Pot Key'], ['GT Conveyor Cross EN', 'GT Conveyor Cross Hammer Path']), + create_dungeon_region(player, 'GT Conveyor Cross Across Pits', 'Ganon\'s Tower', None, ['GT Conveyor Cross Hookshot Path', 'GT Conveyor Cross WN']), create_dungeon_region(player, 'GT Hookshot East Platform', 'Ganon\'s Tower', None, ['GT Hookshot EN', 'GT Hookshot East-Mid Path']), create_dungeon_region(player, 'GT Hookshot Mid Platform', 'Ganon\'s Tower', None, ['GT Hookshot Mid-East Path', 'GT Hookshot Mid-South Path', 'GT Hookshot Mid-North Path']), create_dungeon_region(player, 'GT Hookshot North Platform', 'Ganon\'s Tower', None, ['GT Hookshot NW', 'GT Hookshot North-Mid Path']), diff --git a/Rules.py b/Rules.py index 9e048b38..576fa5a0 100644 --- a/Rules.py +++ b/Rules.py @@ -387,8 +387,8 @@ def global_rules(world, player): set_rule(world.get_location('Ganons Tower - Bob\'s Torch', player), lambda state: state.has_Boots(player)) set_rule(world.get_entrance('GT Hope Room EN', player), lambda state: state.has('Cane of Somaria', player)) - set_rule(world.get_entrance('GT Conveyor Cross WN', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('GT Conveyor Cross EN', player), lambda state: state.has('Hookshot', player)) + set_rule(world.get_entrance('GT Conveyor Cross Hammer Path', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('GT Conveyor Cross Hookshot Path', player), lambda state: state.has('Hookshot', player)) if not world.get_door('GT Speed Torch SE', player).entranceFlag: set_rule(world.get_entrance('GT Speed Torch SE', player), lambda state: state.has('Fire Rod', player)) set_rule(world.get_entrance('GT Hookshot South-Mid Path', player), lambda state: state.has('Hookshot', player)) From 4a1efb141ab124f0007b1addffb4b9322e40d3af Mon Sep 17 00:00:00 2001 From: aerinon Date: Fri, 24 Mar 2023 09:12:46 -0600 Subject: [PATCH 074/196] Add collection_rate to customizer --- source/classes/CustomSettings.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/classes/CustomSettings.py b/source/classes/CustomSettings.py index 53105764..ba5bd705 100644 --- a/source/classes/CustomSettings.py +++ b/source/classes/CustomSettings.py @@ -116,6 +116,7 @@ class CustomSettings(object): args.crystals_gt[p] = get_setting(settings['crystals_gt'], args.crystals_gt[p]) args.crystals_ganon[p] = get_setting(settings['crystals_ganon'], args.crystals_ganon[p]) args.experimental[p] = get_setting(settings['experimental'], args.experimental[p]) + args.collection_rate[p] = get_setting(settings['collection_rate'], args.collection_rate[p]) args.openpyramid[p] = get_setting(settings['openpyramid'], args.openpyramid[p]) args.bigkeyshuffle[p] = get_setting(settings['bigkeyshuffle'], args.bigkeyshuffle[p]) args.keyshuffle[p] = get_setting(settings['keyshuffle'], args.keyshuffle[p]) @@ -244,6 +245,7 @@ class CustomSettings(object): settings_dict[p]['crystals_gt'] = world.crystals_gt_orig[p] settings_dict[p]['crystals_ganon'] = world.crystals_ganon_orig[p] settings_dict[p]['experimental'] = world.experimental[p] + settings_dict[p]['collection_rate'] = world.collection_rate[p] settings_dict[p]['openpyramid'] = world.open_pyramid[p] settings_dict[p]['bigkeyshuffle'] = world.bigkeyshuffle[p] settings_dict[p]['keyshuffle'] = world.keyshuffle[p] From 28e5b7503d9edbbe9e26c0de92f0bcfef5216fa7 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 27 Mar 2023 21:28:46 -0500 Subject: [PATCH 075/196] Improved can_reach_smith search --- OverworldShuffle.py | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/OverworldShuffle.py b/OverworldShuffle.py index b9e2dc8f..4d137416 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -973,27 +973,26 @@ def can_reach_smith(world, player): region = world.get_region(region_name, player) for exit in region.exits: if not found and exit.connected_region is not None: - if any(map(lambda i: i.name in ['Ocarina', 'Ocarina (Activated)'], world.precollected_items)) and exit.spot_type == 'Flute': - fluteregion = exit.connected_region - for flutespot in fluteregion.exits: - if flutespot.connected_region and flutespot.connected_region.name not in explored_regions: - explore_region(flutespot.connected_region.name, flutespot.connected_region) - elif exit.connected_region.name not in explored_regions \ - and exit.connected_region.type in [RegionType.LightWorld, RegionType.DarkWorld] \ - and exit.access_rule(blank_state): - explore_region(exit.connected_region.name, exit.connected_region) - elif exit.name == 'Sanctuary S': - sanc_region = exit.connected_region - if len(sanc_region.exits) and sanc_region.exits[0].name == 'Sanctuary Exit': - explore_region(sanc_region.exits[0].connected_region.name, sanc_region.exits[0].connected_region) + if exit.spot_type == 'Flute': + if any(map(lambda i: i.name == 'Ocarina (Activated)', world.precollected_items)): + for flutespot in exit.connected_region.exits: + if flutespot.connected_region and flutespot.connected_region.name not in explored_regions: + explore_region(flutespot.connected_region.name, flutespot.connected_region) elif exit.connected_region.name == 'Blacksmiths Hut' and exit.access_rule(blank_state): found = True + return + elif exit.connected_region.name not in explored_regions: + if (region.type == RegionType.Dungeon and exit.connected_region.name.endswith(' Portal')) \ + or (exit.connected_region.type in [RegionType.LightWorld, RegionType.DarkWorld] \ + and exit.access_rule(blank_state)): + explore_region(exit.connected_region.name, exit.connected_region) blank_state = CollectionState(world) if world.mode[player] == 'standard': blank_state.collect(ItemFactory('Zelda Delivered', player), True) - if world.logic[player] in ['noglitches', 'minorglitches'] and world.get_region('Frog Prison', player).type == (RegionType.DarkWorld if not invFlag else RegionType.LightWorld): + if world.logic[player] in ['noglitches', 'minorglitches'] and not world.is_tile_swapped(0x29, player): blank_state.collect(ItemFactory('Titans Mitts', player), True) + blank_state.collect(ItemFactory('Moon Pearl', player), True) found = False explored_regions = list() @@ -1004,7 +1003,11 @@ def can_reach_smith(world, player): explore_region(start_region) if not found: if not invFlag: - explore_region('Sanctuary') + if world.intensity[player] >= 3 and world.doorShuffle[player] != 'vanilla': + sanc_mirror = world.get_entrance('Sanctuary Mirror Route', player) + explore_region(sanc_mirror.connected_region.name, sanc_mirror.connected_region) + else: + explore_region('Sanctuary') else: explore_region('Dark Sanctuary Hint') return found From f1f75ec760de99b742228812746f8df470c386e5 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 29 Mar 2023 09:58:48 -0500 Subject: [PATCH 076/196] Major GUI reorganization --- Gui.py | 8 +- .../app/gui/custom/overview/widgets.json | 18 ++ resources/app/gui/lang/en.json | 127 +++++++------- .../app/gui/randomize/dungeon/keysanity.json | 8 + .../app/gui/randomize/dungeon/widgets.json | 57 +++--- .../app/gui/randomize/entrando/widgets.json | 74 ++++---- .../gui/randomize/generation/checkboxes.json | 5 +- resources/app/gui/randomize/item/widgets.json | 165 ++++++++++++------ .../app/gui/randomize/overworld/widgets.json | 32 ++-- source/classes/constants.py | 79 +++++---- source/gui/bottom.py | 18 +- source/gui/custom/overview.py | 23 ++- source/gui/loadcliargs.py | 37 ++-- source/gui/randomize/dungeon.py | 14 +- source/gui/randomize/entrando.py | 5 +- source/gui/randomize/item.py | 43 ++++- source/gui/randomize/overworld.py | 21 +-- source/gui/startinventory/overview.py | 23 ++- source/gui/widgets.py | 67 ++++++- 19 files changed, 517 insertions(+), 307 deletions(-) diff --git a/Gui.py b/Gui.py index 5ca88ac1..a0f4726f 100755 --- a/Gui.py +++ b/Gui.py @@ -144,14 +144,14 @@ def guiMain(args=None): self.pages["randomizer"].pages["entrance"] = entrando_page(self.pages["randomizer"].notebook) self.pages["randomizer"].notebook.add(self.pages["randomizer"].pages["entrance"], text="Entrances") + # Dungeons + self.pages["randomizer"].pages["dungeon"] = dungeon_page(self.pages["randomizer"].notebook) + self.pages["randomizer"].notebook.add(self.pages["randomizer"].pages["dungeon"], text="Dungeons") + # Enemizer self.pages["randomizer"].pages["enemizer"],self.settings = enemizer_page(self.pages["randomizer"].notebook,self.settings) self.pages["randomizer"].notebook.add(self.pages["randomizer"].pages["enemizer"], text="Enemizer") - # Dungeon Shuffle - self.pages["randomizer"].pages["dungeon"] = dungeon_page(self.pages["randomizer"].notebook) - self.pages["randomizer"].notebook.add(self.pages["randomizer"].pages["dungeon"], text="Dungeon Shuffle") - # Multiworld # self.pages["randomizer"].pages["multiworld"],self.settings = multiworld_page(self.pages["randomizer"].notebook,self.settings) # self.pages["randomizer"].notebook.add(self.pages["randomizer"].pages["multiworld"], text="Multiworld") diff --git a/resources/app/gui/custom/overview/widgets.json b/resources/app/gui/custom/overview/widgets.json index ee7be421..03c7fbaf 100644 --- a/resources/app/gui/custom/overview/widgets.json +++ b/resources/app/gui/custom/overview/widgets.json @@ -1,4 +1,22 @@ { + "startHeader": { + "usestartinventory": { + "type": "checkbox", + "config": { + "padx": [10,0], + "pady": [10,10] + } + } + }, + "customHeader": { + "usecustompool": { + "type": "checkbox", + "config": { + "padx": [10,0], + "pady": [10,10] + } + } + }, "itemList1": { "bow": { "type": "textbox", diff --git a/resources/app/gui/lang/en.json b/resources/app/gui/lang/en.json index 5598f292..feadd457 100644 --- a/resources/app/gui/lang/en.json +++ b/resources/app/gui/lang/en.json @@ -57,21 +57,7 @@ "randomizer.dungeon.smallkeyshuffle.wild": "Randomized", "randomizer.dungeon.smallkeyshuffle.universal": "Universal", "randomizer.dungeon.bigkeyshuffle": "Big Keys", - "randomizer.dungeon.keydropshuffle": "Key Drop Shuffle (Legacy)", "randomizer.dungeon.decoupledoors": "Decouple Doors", - "randomizer.dungeon.dropshuffle": "Shuffle Enemy Key Drops", - "randomizer.dungeon.potshuffle": "Pot Shuffle (Legacy)", - "randomizer.dungeon.pottery": "Pottery", - "randomizer.dungeon.pottery.none": "None", - "randomizer.dungeon.pottery.keys": "Key Pots", - "randomizer.dungeon.pottery.cave": "Cave Pots", - "randomizer.dungeon.pottery.cavekeys": "Cave+Key Pots", - "randomizer.dungeon.pottery.reduced": "Reduced Dungeon Pots (Dynamic)", - "randomizer.dungeon.pottery.clustered": "Clustered Dungeon Pots (Dynamic)", - "randomizer.dungeon.pottery.nonempty": "Excludes Empty Pots", - "randomizer.dungeon.pottery.dungeon": "Dungeon Pots", - "randomizer.dungeon.pottery.lottery": "Lottery (All Pots and Large Blocks)", - "randomizer.dungeon.colorizepots": "Colorize Randomized Pots", "randomizer.dungeon.dungeondoorshuffle": "Dungeon Door Shuffle", "randomizer.dungeon.dungeondoorshuffle.vanilla": "Vanilla", @@ -123,7 +109,7 @@ "randomizer.enemizer.enemyshuffle.none": "None", "randomizer.enemizer.enemyshuffle.shuffled": "Shuffled", "randomizer.enemizer.enemyshuffle.random": "Random", - "randomizer.enemizer.enemyshuffle.legacy": "Random (including Thieves)", + "randomizer.enemizer.enemyshuffle.legacy": "Random (50/50 Thieves)", "randomizer.enemizer.bossshuffle": "Boss Shuffle", "randomizer.enemizer.bossshuffle.none": "None", @@ -168,8 +154,6 @@ "randomizer.overworld.whirlpool": "Whirlpool Shuffle", - "randomizer.overworld.bonk_drops": "Bonk Drops", - "randomizer.overworld.overworldflute": "Flute Shuffle", "randomizer.overworld.overworldflute.vanilla": "Vanilla", "randomizer.overworld.overworldflute.balanced": "Balanced", @@ -200,11 +184,6 @@ "randomizer.entrance.entranceshuffle.dungeonsfull": "Dungeons + Full", "randomizer.entrance.entranceshuffle.dungeonssimple": "Dungeons + Simple", - "randomizer.entrance.take_any": "Take Any Caves", - "randomizer.entrance.take_any.none": "None", - "randomizer.entrance.take_any.random": "Random", - "randomizer.entrance.take_any.fixed": "Fixed", - "randomizer.gameoptions.nobgm": "Disable Music & MSU-1", "randomizer.gameoptions.quickswap": "L/R Quickswapping", "randomizer.gameoptions.reduce_flashing": "Reduce Flashing", @@ -253,9 +232,6 @@ "randomizer.generation.createrom": "Create Patched ROM", "randomizer.generation.calcplaythrough": "Calculate Playthrough", "randomizer.generation.print_custom_yaml": "Print Customizer File", - "randomizer.generation.usestartinventory": "Use Starting Inventory", - "randomizer.generation.usecustompool": "Use Custom Item Pool", - "randomizer.generation.race": "Generate \"Race\" ROM", "randomizer.generation.saveonexit": "Save Settings on Exit", "randomizer.generation.saveonexit.ask": "Ask Me", @@ -267,10 +243,10 @@ "randomizer.generation.rom.dialog.romfiles": "Rom Files", "randomizer.generation.rom.dialog.allfiles": "All Files", - "randomizer.item.hints": "Include Helpful Hints", + "randomizer.item.hints": "Hints", + "randomizer.item.race": "Generate \"Race\" ROM", "randomizer.item.retro": "Retro mode", - "randomizer.item.pseudoboots": "Start with Pseudo Boots", - "randomizer.item.bombbag": "Bombbag", + "randomizer.item.pseudoboots": "Pseudoboots", "randomizer.item.worldstate": "World State", "randomizer.item.worldstate.standard": "Standard", @@ -322,24 +298,66 @@ "randomizer.item.weapons.swordless": "Swordless", "randomizer.item.weapons.vanilla": "Vanilla", - "randomizer.item.beemizer": "Beemizer", - "randomizer.item.beemizer.0": "No Bee Traps", - "randomizer.item.beemizer.1": "25% Bee Traps", - "randomizer.item.beemizer.2": "40% Traps, 20% Refills", - "randomizer.item.beemizer.3": "50% Traps, 50% Refills", - "randomizer.item.beemizer.4": "100% Bee Traps", + "randomizer.item.sortingalgo": "Item Fill", + "randomizer.item.sortingalgo.balanced": "Balanced", + "randomizer.item.sortingalgo.vanilla_fill": "Vanilla Fill", + "randomizer.item.sortingalgo.major_only": "Major Location Restriction", + "randomizer.item.sortingalgo.dungeon_only": "Dungeon Restriction", + "randomizer.item.sortingalgo.district": "District Restriction", - "randomizer.item.itempool": "Item Pool", - "randomizer.item.itempool.normal": "Normal", - "randomizer.item.itempool.hard": "Hard", - "randomizer.item.itempool.expert": "Expert", + "randomizer.item.accessibility": "Accessibility", + "randomizer.item.accessibility.items": "100% Inventory", + "randomizer.item.accessibility.locations": "100% Locations", + "randomizer.item.accessibility.none": "Beatable", - "randomizer.item.shopsanity": "Shopsanity", + "randomizer.item.restrict_boss_items": "Forbidden Boss Items", + "randomizer.item.restrict_boss_items.none": "None", + "randomizer.item.restrict_boss_items.mapcompass": "Map & Compass", + "randomizer.item.restrict_boss_items.dungeon": "Map & Compass & Keys", "randomizer.item.itemfunction": "Item Functionality", "randomizer.item.itemfunction.normal": "Normal", "randomizer.item.itemfunction.hard": "Hard", "randomizer.item.itemfunction.expert": "Expert", + + "randomizer.item.timer": "Timer Setting", + "randomizer.item.timer.none": "No Timer", + "randomizer.item.timer.display": "Stopwatch", + "randomizer.item.timer.timed": "Timed", + "randomizer.item.timer.timed-ohko": "Timed OHKO", + "randomizer.item.timer.ohko": "OHKO", + "randomizer.item.timer.timed-countdown": "Timed Countdown", + + "randomizer.item.shopsanity": "Shopsanity", + + "randomizer.item.bonk_drops": "Bonk Drops", + + "randomizer.item.pottery": "Pottery", + "randomizer.item.pottery.none": "None", + "randomizer.item.pottery.keys": "Key Pots", + "randomizer.item.pottery.cave": "Cave Pots", + "randomizer.item.pottery.cavekeys": "Cave+Key Pots", + "randomizer.item.pottery.reduced": "Reduced Dungeon Pots (Dynamic)", + "randomizer.item.pottery.clustered": "Clustered Dungeon Pots (Dynamic)", + "randomizer.item.pottery.nonempty": "Excludes Empty Pots", + "randomizer.item.pottery.dungeon": "Dungeon Pots", + "randomizer.item.pottery.lottery": "Lottery (All Pots and Large Blocks)", + + "randomizer.item.colorizepots": "Colorize Randomized Pots", + "randomizer.item.potshuffle": "Pot Shuffle (Legacy)", + + "randomizer.item.dropshuffle": "Shuffle Enemy Key Drops", + "randomizer.item.keydropshuffle": "Key Drop Shuffle (Legacy)", + + "randomizer.item.take_any": "Take Any Caves", + "randomizer.item.take_any.none": "None", + "randomizer.item.take_any.random": "Random", + "randomizer.item.take_any.fixed": "Fixed", + + "randomizer.item.itempool": "Item Pool", + "randomizer.item.itempool.normal": "Normal", + "randomizer.item.itempool.hard": "Hard", + "randomizer.item.itempool.expert": "Expert", "randomizer.item.flute_mode": "Flute Mode", "randomizer.item.flute_mode.normal": "Normal", @@ -351,30 +369,17 @@ "randomizer.item.bow_mode.retro": "Retro (Progressive)", "randomizer.item.bow_mode.retro_silvers": "Retro + Silvers", - "randomizer.item.timer": "Timer Setting", - "randomizer.item.timer.none": "No Timer", - "randomizer.item.timer.display": "Stopwatch", - "randomizer.item.timer.timed": "Timed", - "randomizer.item.timer.timed-ohko": "Timed OHKO", - "randomizer.item.timer.ohko": "OHKO", - "randomizer.item.timer.timed-countdown": "Timed Countdown", + "randomizer.item.beemizer": "Beemizer", + "randomizer.item.beemizer.0": "No Bee Traps", + "randomizer.item.beemizer.1": "25% Bee Traps", + "randomizer.item.beemizer.2": "40% Traps, 20% Refills", + "randomizer.item.beemizer.3": "50% Traps, 50% Refills", + "randomizer.item.beemizer.4": "100% Bee Traps", - "randomizer.item.accessibility": "Accessibility", - "randomizer.item.accessibility.items": "100% Inventory", - "randomizer.item.accessibility.locations": "100% Locations", - "randomizer.item.accessibility.none": "Beatable", + "randomizer.item.bombbag": "Bombbag", - "randomizer.item.sortingalgo": "Item Sorting", - "randomizer.item.sortingalgo.balanced": "Balanced", - "randomizer.item.sortingalgo.vanilla_fill": "Vanilla Fill", - "randomizer.item.sortingalgo.major_only": "Major Location Restriction", - "randomizer.item.sortingalgo.dungeon_only": "Dungeon Restriction", - "randomizer.item.sortingalgo.district": "District Restriction", - - "randomizer.item.restrict_boss_items": "Forbidden Boss Items", - "randomizer.item.restrict_boss_items.none": "None", - "randomizer.item.restrict_boss_items.mapcompass": "Map & Compass", - "randomizer.item.restrict_boss_items.dungeon": "Map & Compass & Keys", + "startinventory.usestartinventory": "Use Starting Inventory", + "custom.usecustompool": "Use Custom Item Pool", "bottom.content.worlds": "Worlds", "bottom.content.names": "Player names", diff --git a/resources/app/gui/randomize/dungeon/keysanity.json b/resources/app/gui/randomize/dungeon/keysanity.json index ffd9bc92..ec3ae380 100644 --- a/resources/app/gui/randomize/dungeon/keysanity.json +++ b/resources/app/gui/randomize/dungeon/keysanity.json @@ -1,5 +1,13 @@ { "keysanity": { + "smallkeyshuffle": { + "type": "selectbox", + "options": [ + "none", + "wild", + "universal" + ] + }, "mapshuffle": { "type": "checkbox" }, "compassshuffle": { "type": "checkbox" }, "bigkeyshuffle": { "type": "checkbox" } diff --git a/resources/app/gui/randomize/dungeon/widgets.json b/resources/app/gui/randomize/dungeon/widgets.json index e0cd2bdd..3f0abe94 100644 --- a/resources/app/gui/randomize/dungeon/widgets.json +++ b/resources/app/gui/randomize/dungeon/widgets.json @@ -1,12 +1,17 @@ { "widgets": { - "smallkeyshuffle": { + "key_logic_algorithm": { "type": "selectbox", + "default": "default", "options": [ - "none", - "wild", - "universal" - ] + "default", + "partial", + "strict" + ], + "config": { + "padx": [20,0], + "pady": [0,20] + } }, "dungeondoorshuffle": { "type": "selectbox", @@ -28,7 +33,8 @@ "random" ], "config": { - "width": 45 + "width": 45, + "padx": [20,0] } }, "door_type_mode": { @@ -41,7 +47,8 @@ "chaos" ], "config": { - "width": 45 + "width": 45, + "padx": [20,0] } }, "trap_door_mode": { @@ -54,41 +61,17 @@ "oneway" ], "config": { - "width": 30 + "width": 30, + "padx": [20,0] } }, - "key_logic_algorithm": { - "type": "selectbox", - "default": "default", - "options": [ - "default", - "partial", - "strict" - ] - }, - "decoupledoors": { "type": "checkbox" }, - "keydropshuffle": { "type": "checkbox" }, - "pottery": { - "type": "selectbox", - "default": "none", - "options": [ - "none", - "keys", - "cave", - "cavekeys", - "reduced", - "clustered", - "nonempty", - "dungeon", - "lottery" - ], + "decoupledoors": { + "type": "checkbox", "config": { - "width": 35 + "padx": [20,0], + "pady": [0,20] } }, - "colorizepots": { "type": "checkbox" }, - "dropshuffle": { "type": "checkbox" }, - "potshuffle": { "type": "checkbox" }, "experimental": { "type": "checkbox" }, "dungeon_counters": { "type": "selectbox", diff --git a/resources/app/gui/randomize/entrando/widgets.json b/resources/app/gui/randomize/entrando/widgets.json index 41413ebd..adc16d18 100644 --- a/resources/app/gui/randomize/entrando/widgets.json +++ b/resources/app/gui/randomize/entrando/widgets.json @@ -1,38 +1,5 @@ { "widgets": { - "openpyramid": { - "type": "selectbox", - "options": [ - "auto", - "yes", - "no" - ], - "config": { - "width": 10 - } - }, - "take_any": { - "type": "selectbox", - "options": [ - "none", - "random", - "fixed" - ] - }, - "shuffleganon": { "type": "checkbox" }, - "shufflelinks": { "type": "checkbox" }, - "shuffletavern": { "type": "checkbox" }, - "overworld_map": { - "type": "selectbox", - "options": [ - "default", - "compass", - "map" - ], - "config": { - "width": 45 - } - }, "entranceshuffle": { "type": "selectbox", "options": [ @@ -47,6 +14,47 @@ "dungeonsfull", "dungeonssimple" ] + }, + "shuffleganon": { + "type": "checkbox", + "config": { + "padx": [20,0] + } + }, + "shufflelinks": { + "type": "checkbox", + "config": { + "padx": [20,0] + } + }, + "shuffletavern": { + "type": "checkbox", + "config": { + "padx": [20,0] + } + }, + "openpyramid": { + "type": "selectbox", + "options": [ + "auto", + "yes", + "no" + ], + "config": { + "width": 6, + "pady": [20,0] + } + }, + "overworld_map": { + "type": "selectbox", + "options": [ + "default", + "compass", + "map" + ], + "config": { + "width": 45 + } } } } diff --git a/resources/app/gui/randomize/generation/checkboxes.json b/resources/app/gui/randomize/generation/checkboxes.json index b1ee4c84..6e377027 100644 --- a/resources/app/gui/randomize/generation/checkboxes.json +++ b/resources/app/gui/randomize/generation/checkboxes.json @@ -4,9 +4,6 @@ "bps": { "type": "checkbox" }, "createspoiler": { "type": "checkbox" }, "calcplaythrough": { "type": "checkbox" }, - "print_custom_yaml": { "type": "checkbox" }, - "usestartinventory": { "type": "checkbox" }, - "usecustompool": { "type": "checkbox" }, - "race": { "type": "checkbox" } + "print_custom_yaml": { "type": "checkbox" } } } diff --git a/resources/app/gui/randomize/item/widgets.json b/resources/app/gui/randomize/item/widgets.json index a2cde0ea..9bb62bfe 100644 --- a/resources/app/gui/randomize/item/widgets.json +++ b/resources/app/gui/randomize/item/widgets.json @@ -1,12 +1,8 @@ { "checkboxes": { - "retro": { "type": "checkbox" }, - "bombbag": { "type": "checkbox" }, - "shopsanity": { "type": "checkbox" }, - "hints": { - "type": "checkbox" - }, - "pseudoboots": { "type": "checkbox" } + "hints": { "type": "checkbox" }, + "pseudoboots": { "type": "checkbox" }, + "race": { "type": "checkbox" } }, "leftItemFrame": { "worldstate": { @@ -17,7 +13,10 @@ "open", "inverted", "retro" - ] + ], + "config": { + "command": "worldstate" + } }, "logiclevel": { "type": "selectbox", @@ -63,16 +62,38 @@ "swordless", "vanilla" ] - }, - "beemizer": { - "type": "selectbox", - "options": [ - "0", "1", "2", "3", "4" - ] } }, "rightItemFrame": { - "itempool": { + "sortingalgo": { + "type": "selectbox", + "default": "balanced", + "options": [ + "balanced", + "vanilla_fill", + "major_only", + "dungeon_only", + "district" + ] + }, + "accessibility": { + "type": "selectbox", + "options": [ + "items", + "locations", + "none" + ] + }, + "restrict_boss_items": { + "type": "selectbox", + "default": "none", + "options": [ + "none", + "mapcompass", + "dungeon" + ] + }, + "itemfunction": { "type": "selectbox", "options": [ "normal", @@ -80,7 +101,78 @@ "expert" ] }, - "itemfunction": { + "timer": { + "type": "selectbox", + "options": [ + "none", + "display", + "timed", + "timed-ohko", + "ohko", + "timed-countdown" + ] + } + }, + "leftPoolHeader": { + "shopsanity": { + "type": "checkbox" + }, + "bonk_drops": { + "type": "checkbox", + "default": false + } + }, + "leftPoolFrame": { + "pottery": { + "type": "selectbox", + "default": "none", + "options": [ + "none", + "keys", + "cave", + "cavekeys", + "reduced", + "clustered", + "nonempty", + "dungeon", + "lottery" + ], + "config": { + "width": 35 + } + }, + "colorizepots": { + "type": "checkbox", + "config": { + "padx": [50,0] + } + }, + "potshuffle": { + "type": "checkbox", + "config": { + "padx": [50,0] + } + }, + "dropshuffle": { + "type": "checkbox" + }, + "keydropshuffle": { + "type": "checkbox", + "config": { + "command": "keydropshuffle" + } + }, + "take_any": { + "type": "selectbox", + "options": [ + "none", + "random", + "fixed" + ] + } + }, + "rightPoolFrame": { + "itempool": { "type": "selectbox", "options": [ "normal", @@ -104,44 +196,17 @@ "retro_silvers" ] }, - "timer": { + "beemizer": { "type": "selectbox", "options": [ - "none", - "display", - "timed", - "timed-ohko", - "ohko", - "timed-countdown" + "0", "1", "2", "3", "4" ] }, - "accessibility": { - "type": "selectbox", - "options": [ - "items", - "locations", - "none" - ] - }, - "sortingalgo": { - "type": "selectbox", - "default": "balanced", - "options": [ - "balanced", - "vanilla_fill", - "major_only", - "dungeon_only", - "district" - ] - }, - "restrict_boss_items": { - "type": "selectbox", - "default": "none", - "options": [ - "none", - "mapcompass", - "dungeon" - ] + "bombbag": { + "type": "checkbox", + "config": { + "padx": [64,0] + } } } } diff --git a/resources/app/gui/randomize/overworld/widgets.json b/resources/app/gui/randomize/overworld/widgets.json index d349cfc0..c9438deb 100644 --- a/resources/app/gui/randomize/overworld/widgets.json +++ b/resources/app/gui/randomize/overworld/widgets.json @@ -1,10 +1,5 @@ { - "topOverworldFrame": { - "bonk_drops": { - "type": "checkbox", - "default": false - } - }, + "topOverworldFrame": {}, "leftOverworldFrame": { "overworldshuffle": { "type": "selectbox", @@ -28,11 +23,17 @@ }, "mixed": { "type": "checkbox", - "default": false + "default": false, + "config": { + "padx": [79,0] + } }, "whirlpool": { "type": "checkbox", - "default": false + "default": false, + "config": { + "padx": [79,0] + } }, "overworldflute": { "type": "selectbox", @@ -41,17 +42,26 @@ "vanilla", "balanced", "random" - ] + ], + "config": { + "pady": [20,0] + } } }, "rightOverworldFrame": { "terrain": { "type": "checkbox", - "default": false + "default": false, + "config": { + "pady": [3,0] + } }, "keepsimilar": { "type": "checkbox", - "default": false + "default": false, + "config": { + "pady": [6,0] + } } } } \ No newline at end of file diff --git a/source/classes/constants.py b/source/classes/constants.py index e816f61b..19b93027 100644 --- a/source/classes/constants.py +++ b/source/classes/constants.py @@ -56,25 +56,36 @@ SETTINGSTOPROCESS = { "randomizer": { "item": { "hints": "hints", - "retro": "retro", - "bombbag": "bombbag", - "shopsanity": "shopsanity", "pseudoboots": "pseudoboots", + "race": "race", + "worldstate": "mode", "logiclevel": "logic", "goal": "goal", "crystals_gt": "crystals_gt", "crystals_ganon": "crystals_ganon", "weapons": "swords", - "itempool": "difficulty", + + "sortingalgo": "algorithm", + "accessibility": "accessibility", + "restrict_boss_items": "restrict_boss_items", "itemfunction": "item_functionality", + "timer": "timer", + + "shopsanity": "shopsanity", + "bonk_drops": "bonk_drops", + "pottery": "pottery", + "colorizepots": "colorizepots", + "potshuffle": "shufflepots", + "dropshuffle": "dropshuffle", + "keydropshuffle": "keydropshuffle", + "take_any": "take_any", + + "itempool": "difficulty", "flute_mode": "flute_mode", "bow_mode": "bow_mode", - "timer": "timer", - "accessibility": "accessibility", - "sortingalgo": "algorithm", "beemizer": "beemizer", - "restrict_boss_items": "restrict_boss_items" + "bombbag": "bombbag" }, "overworld": { "overworldshuffle": "ow_shuffle", @@ -83,17 +94,31 @@ SETTINGSTOPROCESS = { "keepsimilar": "ow_keepsimilar", "mixed": "ow_mixed", "whirlpool": "ow_whirlpool", - "bonk_drops": "bonk_drops", "overworldflute": "ow_fluteshuffle" }, "entrance": { - "openpyramid": "openpyramid", + "entranceshuffle": "shuffle", "shuffleganon": "shuffleganon", "shufflelinks": "shufflelinks", "shuffletavern": "shuffletavern", - "entranceshuffle": "shuffle", + "openpyramid": "openpyramid", "overworld_map": "overworld_map", - "take_any": "take_any", + }, + "dungeon": { + "smallkeyshuffle": "keyshuffle", + "mapshuffle": "mapshuffle", + "compassshuffle": "compassshuffle", + "bigkeyshuffle": "bigkeyshuffle", + "key_logic_algorithm": "key_logic_algorithm", + "dungeondoorshuffle": "door_shuffle", + "dungeonintensity": "intensity", + "door_type_mode": "door_type_mode", + "trap_door_mode": "trap_door_mode", + "decoupledoors": "decoupledoors", + "experimental": "experimental", + "dungeon_counters": "dungeon_counters", + "mixed_travel": "mixed_travel", + "standardize_palettes": "standardize_palettes" }, "enemizer": { "enemyshuffle": "shuffleenemies", @@ -101,27 +126,6 @@ SETTINGSTOPROCESS = { "enemydamage": "enemy_damage", "enemyhealth": "enemy_health" }, - "dungeon": { - "mapshuffle": "mapshuffle", - "compassshuffle": "compassshuffle", - "smallkeyshuffle": "keyshuffle", - "bigkeyshuffle": "bigkeyshuffle", - "dungeondoorshuffle": "door_shuffle", - "dungeonintensity": "intensity", - "door_type_mode": "door_type_mode", - "trap_door_mode": "trap_door_mode", - "key_logic_algorithm": "key_logic_algorithm", - "decoupledoors": "decoupledoors", - "keydropshuffle": "keydropshuffle", - "dropshuffle": "dropshuffle", - "pottery": "pottery", - "colorizepots": "colorizepots", - "potshuffle": "shufflepots", - "experimental": "experimental", - "dungeon_counters": "dungeon_counters", - "mixed_travel": "mixed_travel", - "standardize_palettes": "standardize_palettes" - }, "gameoptions": { "nobgm": "disablemusic", "quickswap": "quickswap", @@ -141,12 +145,15 @@ SETTINGSTOPROCESS = { "createrom": "create_rom", "calcplaythrough": "calc_playthrough", "print_custom_yaml": "print_custom_yaml", - "usestartinventory": "usestartinventory", - "usecustompool": "custom", - "race": "race", "saveonexit": "saveonexit" } }, + "startinventory": { + "usestartinventory": "usestartinventory" + }, + "custom": { + "usecustompool": "custom" + }, "bottom": { "content": { "names": "names", diff --git a/source/gui/bottom.py b/source/gui/bottom.py index 27a22217..93976c75 100644 --- a/source/gui/bottom.py +++ b/source/gui/bottom.py @@ -203,13 +203,19 @@ def create_guiargs(parent): # Cycle through each page for mainpage in options: + subpage = None + _, v = next(iter(options[mainpage].items())) + if isinstance(v, str): + subpage = "" # Cycle through each subpage (in case of Item Randomizer) - for subpage in options[mainpage]: + for subpage in (options[mainpage] if subpage is None else [subpage]): # Cycle through each widget - for widget in options[mainpage][subpage]: + for widget in (options[mainpage][subpage] if subpage != "" else options[mainpage]): # Get the value and set it - arg = options[mainpage][subpage][widget] - setattr(guiargs, arg, parent.pages[mainpage].pages[subpage].widgets[widget].storageVar.get()) + arg = options[mainpage][subpage][widget] if subpage != "" else options[mainpage][widget] + page = parent.pages[mainpage].pages[subpage] if subpage != "" else parent.pages[mainpage] + pagewidgets = page.content.customWidgets if mainpage == "custom" else page.content.startingWidgets if mainpage == "startinventory" else page.widgets + setattr(guiargs, arg, pagewidgets[widget].storageVar.get()) # Get EnemizerCLI setting guiargs.enemizercli = parent.pages["randomizer"].pages["enemizer"].widgets["enemizercli"].storageVar.get() @@ -226,7 +232,7 @@ def create_guiargs(parent): guiargs.customizer = customizer_value # Get if we're using the Custom Item Pool - guiargs.custom = bool(parent.pages["randomizer"].pages["generation"].widgets["usecustompool"].storageVar.get()) + guiargs.custom = bool(parent.pages["custom"].content.customWidgets["usecustompool"].storageVar.get()) # Get Seed ID guiargs.seed = None @@ -285,7 +291,7 @@ def create_guiargs(parent): guiargs.dropshuffle = 1 guiargs.pottery = 'keys' if guiargs.pottery == 'none' else guiargs.pottery - if guiargs.retro or guiargs.mode == 'retro': + if (hasattr(guiargs, 'retro') and guiargs.retro) or guiargs.mode == 'retro': if guiargs.bow_mode == 'progressive': guiargs.bow_mode = 'retro' elif guiargs.bow_mode == 'silvers': diff --git a/source/gui/custom/overview.py b/source/gui/custom/overview.py index c51c35be..b62bff71 100644 --- a/source/gui/custom/overview.py +++ b/source/gui/custom/overview.py @@ -1,4 +1,4 @@ -from tkinter import ttk, Frame, N, E, W, LEFT, X, VERTICAL, Y +from tkinter import ttk, Frame, N, E, W, LEFT, TOP, X, VERTICAL, Y import source.gui.widgets as widgets import json import os @@ -11,10 +11,10 @@ def custom_page(top,parent): # Create uniform list columns def create_list_frame(parent, framename): - parent.frames[framename] = Frame(parent) - parent.frames[framename].pack(side=LEFT, padx=(0,0), anchor=N) - parent.frames[framename].thisRow = 0 - parent.frames[framename].thisCol = 0 + self.frames[framename] = Frame(parent) + self.frames[framename].pack(side=LEFT, padx=(0,0), anchor=N) + self.frames[framename].thisRow = 0 + self.frames[framename].thisCol = 0 # Create a vertical rule to help with splitting columns visually def create_vertical_rule(num=1): @@ -34,6 +34,8 @@ def custom_page(top,parent): # Custom Item Pool option sections self.frames = {} + self.frames["customHeader"] = Frame(self) + self.frames["customHeader"].pack(side=TOP, anchor=W) # Create 5 columns with 2 vertical rules in between each create_list_frame(self, "itemList1") create_vertical_rule(2) @@ -50,9 +52,14 @@ def custom_page(top,parent): with open(os.path.join("resources", "app", "gui", "custom", "overview", "widgets.json")) as widgetDefns: myDict = json.load(widgetDefns) for framename,theseWidgets in myDict.items(): - dictWidgets = widgets.make_widgets_from_dict(self, theseWidgets, self.frames[framename]) - for key in dictWidgets: - self.customWidgets[key] = dictWidgets[key] + if framename in self.frames: + dictWidgets = widgets.make_widgets_from_dict(self, theseWidgets, self.frames[framename]) + for key in dictWidgets: + self.customWidgets[key] = dictWidgets[key] + if framename == "customHeader": + packAttrs = {"anchor":W} + packAttrs = widgets.add_padding_from_config(packAttrs, theseWidgets[key]) + self.customWidgets[key].pack(packAttrs) # Load Custom Item Pool settings from settings file for key in CONST.CUSTOMITEMS: diff --git a/source/gui/loadcliargs.py b/source/gui/loadcliargs.py index 0130f8ad..6d358853 100644 --- a/source/gui/loadcliargs.py +++ b/source/gui/loadcliargs.py @@ -23,34 +23,41 @@ def loadcliargs(gui, args, settings=None): # Cycle through each page for mainpage in options: + subpage = None + _, v = next(iter(options[mainpage].items())) + if isinstance(v, str): + subpage = "" # Cycle through each subpage (in case of Item Randomizer) - for subpage in options[mainpage]: + for subpage in (options[mainpage] if subpage is None else [subpage]): # Cycle through each widget - for widget in options[mainpage][subpage]: - if widget in gui.pages[mainpage].pages[subpage].widgets: + for widget in (options[mainpage][subpage] if subpage != "" else options[mainpage]): + page = gui.pages[mainpage].pages[subpage] if subpage != "" else gui.pages[mainpage] + pagewidgets = page.content.customWidgets if mainpage == "custom" else page.content.startingWidgets if mainpage == "startinventory" else page.widgets + if widget in pagewidgets: thisType = "" # Get the value and set it - arg = options[mainpage][subpage][widget] + arg = options[mainpage][subpage][widget] if subpage != "" else options[mainpage][widget] if args[arg] == None: args[arg] = "" - label = fish.translate("gui","gui",mainpage + '.' + subpage + '.' + widget) - if hasattr(gui.pages[mainpage].pages[subpage].widgets[widget],"type"): - thisType = gui.pages[mainpage].pages[subpage].widgets[widget].type + label_ref = mainpage + ('.' + subpage if subpage != "" else '') + '.' + widget + label = fish.translate("gui","gui", label_ref) + if hasattr(pagewidgets[widget],"type"): + thisType = pagewidgets[widget].type if thisType == "checkbox": - gui.pages[mainpage].pages[subpage].widgets[widget].checkbox.configure(text=label) + pagewidgets[widget].checkbox.configure(text=label) elif thisType == "selectbox": - theseOptions = gui.pages[mainpage].pages[subpage].widgets[widget].selectbox.options - gui.pages[mainpage].pages[subpage].widgets[widget].label.configure(text=label) + theseOptions = pagewidgets[widget].selectbox.options + pagewidgets[widget].label.configure(text=label) i = 0 for value in theseOptions["values"]: - gui.pages[mainpage].pages[subpage].widgets[widget].selectbox.options["labels"][i] = fish.translate("gui","gui",mainpage + '.' + subpage + '.' + widget + '.' + str(value)) + pagewidgets[widget].selectbox.options["labels"][i] = fish.translate("gui","gui", label_ref + '.' + str(value)) i += 1 for i in range(0, len(theseOptions["values"])): - gui.pages[mainpage].pages[subpage].widgets[widget].selectbox["menu"].entryconfigure(i, label=theseOptions["labels"][i]) - gui.pages[mainpage].pages[subpage].widgets[widget].selectbox.options = theseOptions + pagewidgets[widget].selectbox["menu"].entryconfigure(i, label=theseOptions["labels"][i]) + pagewidgets[widget].selectbox.options = theseOptions elif thisType == "spinbox": - gui.pages[mainpage].pages[subpage].widgets[widget].label.configure(text=label) - gui.pages[mainpage].pages[subpage].widgets[widget].storageVar.set(args[arg]) + pagewidgets[widget].label.configure(text=label) + pagewidgets[widget].storageVar.set(args[arg]) # If we're on the Game Options page and it's not about Hints if subpage == "gameoptions" and widget not in ["hints", "collection_rate"]: # Check if we've got settings diff --git a/source/gui/randomize/dungeon.py b/source/gui/randomize/dungeon.py index 01985982..7400dbe4 100644 --- a/source/gui/randomize/dungeon.py +++ b/source/gui/randomize/dungeon.py @@ -1,4 +1,4 @@ -from tkinter import ttk, Frame, Label, E, W, LEFT, RIGHT +from tkinter import ttk, Frame, Label, E, W, LEFT, RIGHT, TOP import source.gui.widgets as widgets import json import os @@ -16,8 +16,8 @@ def dungeon_page(parent): self.frames["keysanity"].pack(anchor=W) ## Dungeon Item Shuffle - mscbLabel = Label(self.frames["keysanity"], text="Shuffle: ") - mscbLabel.pack(side=LEFT) + mscbLabel = Label(self.frames["keysanity"], text="Dungeon Items: ") + mscbLabel.pack(side=TOP, anchor=W) # Load Dungeon Shuffle option widgets as defined by JSON file # Defns include frame name, widget type, widget options, widget placement attributes @@ -28,7 +28,9 @@ def dungeon_page(parent): dictWidgets = widgets.make_widgets_from_dict(self, myDict, self.frames["keysanity"]) for key in dictWidgets: self.widgets[key] = dictWidgets[key] - self.widgets[key].pack(side=LEFT) + packAttrs = {"side":LEFT} + packAttrs = widgets.add_padding_from_config(packAttrs, myDict[key]) + self.widgets[key].pack(packAttrs) # These get split left & right self.frames["widgets"] = Frame(self) @@ -39,6 +41,8 @@ def dungeon_page(parent): dictWidgets = widgets.make_widgets_from_dict(self, myDict, self.frames["widgets"]) for key in dictWidgets: self.widgets[key] = dictWidgets[key] - self.widgets[key].pack(anchor=W) + packAttrs = {"anchor":W} + packAttrs = widgets.add_padding_from_config(packAttrs, myDict[key]) + self.widgets[key].pack(packAttrs) return self diff --git a/source/gui/randomize/entrando.py b/source/gui/randomize/entrando.py index bfc911b4..ba2bc365 100644 --- a/source/gui/randomize/entrando.py +++ b/source/gui/randomize/entrando.py @@ -26,9 +26,8 @@ def entrando_page(parent): dictWidgets = widgets.make_widgets_from_dict(self, theseWidgets, self.frames[framename]) for key in dictWidgets: self.widgets[key] = dictWidgets[key] - packAttrs = {"anchor":E} - if self.widgets[key].type == "checkbox" or key in ["openpyramid", "take_any"]: - packAttrs["anchor"] = W + packAttrs = {"anchor":W} + packAttrs = widgets.add_padding_from_config(packAttrs, theseWidgets[key]) self.widgets[key].pack(packAttrs) return self diff --git a/source/gui/randomize/item.py b/source/gui/randomize/item.py index 81c957ce..6898c75f 100644 --- a/source/gui/randomize/item.py +++ b/source/gui/randomize/item.py @@ -1,4 +1,4 @@ -from tkinter import ttk, Frame, E, W, LEFT, RIGHT, Label +from tkinter import ttk, font, Frame, E, W, NW, TOP, LEFT, RIGHT, Y, Label import source.gui.widgets as widgets import json import os @@ -17,13 +17,39 @@ def item_page(parent): self.frames["checkboxes"] = Frame(self) self.frames["checkboxes"].pack(anchor=W) - various_options = Label(self.frames["checkboxes"], text="") + various_options = Label(self.frames["checkboxes"], text="Options: ") various_options.pack(side=LEFT) - self.frames["leftItemFrame"] = Frame(self) - self.frames["rightItemFrame"] = Frame(self) + self.frames["mainFrame"] = Frame(self) + self.frames["mainFrame"].pack(side=TOP, pady=(20,0)) + + self.frames["poolFrame"] = Frame(self) + self.frames["poolFrame"].pack(fill=Y) + + self.frames["leftItemFrame"] = Frame(self.frames["mainFrame"]) self.frames["leftItemFrame"].pack(side=LEFT) + self.frames["rightItemFrame"] = Frame(self.frames["mainFrame"]) self.frames["rightItemFrame"].pack(side=RIGHT) + + self.frames["leftPoolContainer"] = Frame(self.frames["poolFrame"]) + self.frames["leftPoolContainer"].pack(side=LEFT, padx=(0,20)) + + base_font = font.nametofont('TkTextFont').actual() + underline_font = f'"{base_font["family"]}" {base_font["size"]} underline' + various_options = Label(self.frames["leftPoolContainer"], text="Pool Expansions", font=underline_font) + various_options.pack(side=TOP, pady=(20,0)) + + self.frames["leftPoolHeader"] = Frame(self.frames["leftPoolContainer"]) + self.frames["leftPoolHeader"].pack(side=TOP, anchor=W) + + self.frames["leftPoolFrame"] = Frame(self.frames["leftPoolContainer"]) + self.frames["leftPoolFrame"].pack(side=LEFT, fill=Y) + + self.frames["rightPoolFrame"] = Frame(self.frames["poolFrame"]) + self.frames["rightPoolFrame"].pack(side=RIGHT) + + various_options = Label(self.frames["rightPoolFrame"], text="Pool Modifications", font=underline_font) + various_options.pack(side=TOP, pady=(20,0)) # Load Item Randomizer option widgets as defined by JSON file # Defns include frame name, widget type, widget options, widget placement attributes @@ -36,8 +62,15 @@ def item_page(parent): for key in dictWidgets: self.widgets[key] = dictWidgets[key] packAttrs = {"anchor":E} - if self.widgets[key].type == "checkbox": + if self.widgets[key].type == "checkbox" or framename == "leftPoolFrame": + packAttrs["anchor"] = W + if framename == "checkboxes": packAttrs["side"] = LEFT + packAttrs["padx"] = (10,0) + elif framename == "leftPoolHeader": + packAttrs["side"] = LEFT + packAttrs["padx"] = (0,20) + packAttrs = widgets.add_padding_from_config(packAttrs, theseWidgets[key]) self.widgets[key].pack(packAttrs) return self diff --git a/source/gui/randomize/overworld.py b/source/gui/randomize/overworld.py index 190a750a..54120417 100644 --- a/source/gui/randomize/overworld.py +++ b/source/gui/randomize/overworld.py @@ -15,33 +15,24 @@ def overworld_page(parent): # Load Overworld Shuffle option widgets as defined by JSON file # Defns include frame name, widget type, widget options, widget placement attributes - self.frames["topOverworldFrame"] = Frame(self) self.frames["leftOverworldFrame"] = Frame(self) self.frames["rightOverworldFrame"] = Frame(self) - self.frames["topOverworldFrame"].pack(side=TOP, anchor=NW) self.frames["leftOverworldFrame"].pack(side=LEFT, anchor=NW, fill=Y) self.frames["rightOverworldFrame"].pack(anchor=NW, fill=Y) - - shuffleLabel = Label(self.frames["topOverworldFrame"], text="Shuffle: ") - shuffleLabel.pack(side=LEFT) with open(os.path.join("resources","app","gui","randomize","overworld","widgets.json")) as overworldWidgets: myDict = json.load(overworldWidgets) for framename,theseWidgets in myDict.items(): + if not theseWidgets: + continue dictWidgets = widgets.make_widgets_from_dict(self, theseWidgets, self.frames[framename]) for key in dictWidgets: self.widgets[key] = dictWidgets[key] - packAttrs = {"anchor":E} - if key == "terrain": - packAttrs = {"anchor":W, "pady":(3,0)} - elif key == "keepsimilar": - packAttrs = {"anchor":W, "pady":(6,0)} - elif key == "overworldflute": - packAttrs["pady"] = (20,0) - elif key in ["mixed", "whirlpool"]: - packAttrs = {"anchor":W, "padx":(79,0)} - + packAttrs = {"anchor":W} + if self.widgets[key].type != "checkbox": + packAttrs["anchor"] = E + packAttrs = widgets.add_padding_from_config(packAttrs, theseWidgets[key]) self.widgets[key].pack(packAttrs) return self diff --git a/source/gui/startinventory/overview.py b/source/gui/startinventory/overview.py index fce40e5f..97784521 100644 --- a/source/gui/startinventory/overview.py +++ b/source/gui/startinventory/overview.py @@ -1,4 +1,4 @@ -from tkinter import ttk, Frame, N, E, W, LEFT, X, VERTICAL, Y +from tkinter import ttk, Frame, N, E, W, LEFT, TOP, X, VERTICAL, Y import source.gui.widgets as widgets import json import os @@ -11,10 +11,10 @@ def startinventory_page(top,parent): # Create uniform list columns def create_list_frame(parent, framename): - parent.frames[framename] = Frame(parent) - parent.frames[framename].pack(side=LEFT, padx=(0,0), anchor=N) - parent.frames[framename].thisRow = 0 - parent.frames[framename].thisCol = 0 + self.frames[framename] = Frame(parent) + self.frames[framename].pack(side=LEFT, padx=(0,0), anchor=N) + self.frames[framename].thisRow = 0 + self.frames[framename].thisCol = 0 # Create a vertical rule to help with splitting columns visually def create_vertical_rule(num=1): @@ -34,6 +34,8 @@ def startinventory_page(top,parent): # Starting Inventory option sections self.frames = {} + self.frames["startHeader"] = Frame(self) + self.frames["startHeader"].pack(side=TOP, anchor=W) # Create 5 columns with 2 vertical rules in between each create_list_frame(self,"itemList1") create_vertical_rule(2) @@ -55,9 +57,14 @@ def startinventory_page(top,parent): if key in myDict[thisList]: del myDict[thisList][key] for framename,theseWidgets in myDict.items(): - dictWidgets = widgets.make_widgets_from_dict(self, theseWidgets, self.frames[framename]) - for key in dictWidgets: - self.startingWidgets[key] = dictWidgets[key] + if framename in self.frames: + dictWidgets = widgets.make_widgets_from_dict(self, theseWidgets, self.frames[framename]) + for key in dictWidgets: + self.startingWidgets[key] = dictWidgets[key] + if framename == "startHeader": + packAttrs = {"anchor":W} + packAttrs = widgets.add_padding_from_config(packAttrs, theseWidgets[key]) + self.startingWidgets[key].pack(packAttrs) # Load Custom Starting Inventory settings from settings file, ignoring ones to be excluded for key in CONST.CUSTOMITEMS: diff --git a/source/gui/widgets.py b/source/gui/widgets.py index aedb573d..0198a43a 100644 --- a/source/gui/widgets.py +++ b/source/gui/widgets.py @@ -1,4 +1,4 @@ -from tkinter import Checkbutton, Entry, Frame, IntVar, Label, OptionMenu, Spinbox, StringVar, LEFT, RIGHT, X +from tkinter import messagebox, Checkbutton, Entry, Frame, IntVar, Label, OptionMenu, Spinbox, StringVar, LEFT, RIGHT, X from source.classes.Empty import Empty # Override Spinbox to include mousewheel support for changing value @@ -16,7 +16,7 @@ class mySpinbox(Spinbox): self.invoke('buttonup') # Make a Checkbutton with a label -def make_checkbox(self, parent, label, storageVar, manager, managerAttrs): +def make_checkbox(self, parent, label, storageVar, manager, managerAttrs, config): self = Frame(parent) self.storageVar = storageVar if managerAttrs is not None and "default" in managerAttrs: @@ -25,7 +25,10 @@ def make_checkbox(self, parent, label, storageVar, manager, managerAttrs): elif managerAttrs["default"] == "false" or managerAttrs["default"] == False: self.storageVar.set(False) del managerAttrs["default"] - self.checkbox = Checkbutton(self, text=label, variable=self.storageVar) + options = {"text":label, "variable":self.storageVar} + if config and "command" in config: + options.update({"command":lambda m=config["command"]: widget_command(self, m)}) + self.checkbox = Checkbutton(self, options) if managerAttrs is not None: self.checkbox.pack(managerAttrs) else: @@ -43,7 +46,11 @@ def make_selectbox(self, parent, label, options, storageVar, manager, managerAtt self.labelVar = StringVar() self.storageVar = storageVar - self.selectbox = OptionMenu(self, self.labelVar, *labels) + if config and "command" in config: + self.command = config["command"] + self.selectbox = OptionMenu(self, self.labelVar, *labels, command=lambda m: widget_command(self, self.command)) + else: + self.selectbox = OptionMenu(self, self.labelVar, *labels) self.selectbox.options = {} if isinstance(options,dict): @@ -96,7 +103,7 @@ def make_selectbox(self, parent, label, options, storageVar, manager, managerAtt else: self.label.pack(side=LEFT) - self.selectbox.config(width=config['width'] if config and config['width'] else 20) + self.selectbox.config(width=config['width'] if config and 'width' in config else 20) idx = 0 default = self.selectbox.options["values"][idx] if managerAttrs is not None and "default" in managerAttrs: @@ -181,7 +188,7 @@ def make_widget(self, type, parent, label, storageVar=None, manager=None, manage if type == "checkbox": if thisStorageVar is None: thisStorageVar = IntVar() - widget = make_checkbox(self, parent, label, thisStorageVar, manager, managerAttrs) + widget = make_checkbox(self, parent, label, thisStorageVar, manager, managerAttrs, config) elif type == "selectbox": if thisStorageVar is None: thisStorageVar = StringVar() @@ -221,3 +228,51 @@ def make_widgets_from_dict(self, defns, parent): for key,defn in defns.items(): widgets[key] = make_widget_from_dict(self, defn, parent) return widgets + +# Add padding to widget +def add_padding_from_config(packAttrs, defn): + if "config" in defn: + config = defn["config"] + if 'padx' in config: + packAttrs["padx"] = config['padx'] + if 'pady' in config: + packAttrs["pady"] = config['pady'] + return packAttrs + +# Callback when a widget issues a command +def widget_command(widget, command=""): + root = widget.winfo_toplevel() + text_output = "" + if command == "worldstate": + if widget.storageVar.get() == 'retro': + temp_widget = root.pages["randomizer"].pages["dungeon"].widgets["smallkeyshuffle"] + text_output += f'\n {temp_widget.label.cget("text")}' + temp_widget.storageVar.set('universal') + + temp_widget = root.pages["randomizer"].pages["item"].widgets["bow_mode"] + text_output += f'\n {temp_widget.label.cget("text")}' + if temp_widget.storageVar.get() == 'progressive': + temp_widget.storageVar.set('retro') + elif temp_widget.storageVar.get() == 'silvers': + temp_widget.storageVar.set('retro_silvers') + + temp_widget = root.pages["randomizer"].pages["item"].widgets["take_any"] + text_output += f'\n {temp_widget.label.cget("text")}' + if temp_widget.storageVar.get() == 'none': + temp_widget.storageVar.set('random') + + widget.storageVar.set('open') + messagebox.showinfo('', f'The following settings were changed:{text_output}') + elif command == "keydropshuffle": + if widget.storageVar.get() > 0: + temp_widget = root.pages["randomizer"].pages["item"].widgets["pottery"] + text_output += f'\n {temp_widget.label.cget("text")}' + if temp_widget.storageVar.get() == 'none': + temp_widget.storageVar.set('keys') + + temp_widget = root.pages["randomizer"].pages["item"].widgets["dropshuffle"] + temp_widget.storageVar.set(1) + text_output += f'\n {temp_widget.checkbox.cget("text")}' + + widget.storageVar.set(0) + messagebox.showinfo('', f'The following settings were changed:{text_output}') From 6f18c4c4a5f02a15a54e4266841261e8878663a7 Mon Sep 17 00:00:00 2001 From: aerinon Date: Thu, 30 Mar 2023 16:42:56 -0600 Subject: [PATCH 077/196] Fix lamp logic in partitioned --- Rules.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Rules.py b/Rules.py index 9e048b38..f29dea4a 100644 --- a/Rules.py +++ b/Rules.py @@ -1191,9 +1191,9 @@ def add_conditional_lamps(world, player): is_dark = False if not world.sewer_light_cone[player]: is_dark = True - elif world.doorShuffle[player] != 'crossed' and not info['sewer']: + elif world.doorShuffle[player] not in ['crossed', 'partitioned'] and not info['sewer']: is_dark = True - elif world.doorShuffle[player] == 'crossed': + elif world.doorShuffle[player] in ['crossed', 'partitioned']: sewer_builder = world.dungeon_layouts[player]['Hyrule Castle'] is_dark = region not in sewer_builder.master_sector.region_set() if is_dark: From d216cb337b3d2f71f1aedb4caf6a8c18b9717d9b Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 30 Mar 2023 22:52:44 -0500 Subject: [PATCH 078/196] Adding missing bunny rule for Water D Leave --- Rules.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Rules.py b/Rules.py index 1cb91819..edaa928e 100644 --- a/Rules.py +++ b/Rules.py @@ -1214,6 +1214,7 @@ def ow_bunny_rules(world, player): add_bunny_rule(world.get_entrance('Lake Hylia Northeast Water Drop', player), player) add_bunny_rule(world.get_entrance('Lake Hylia Central Water Drop', player), player) add_bunny_rule(world.get_entrance('Lake Hylia Island Water Drop', player), player) + add_bunny_rule(world.get_entrance('Lake Hylia Water D Leave', player), player) add_bunny_rule(world.get_entrance('Ice Cave SW', player), player) add_bunny_rule(world.get_entrance('Octoballoon Water Drop', player), player) add_bunny_rule(world.get_entrance('Octoballoon Waterfall Water Drop', player), player) From d9c18407e435b6b7e75fda14576f6a14e12665f2 Mon Sep 17 00:00:00 2001 From: aerinon Date: Fri, 31 Mar 2023 09:29:01 -0600 Subject: [PATCH 079/196] Fix starting flute logic --- BaseClasses.py | 2 -- Main.py | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index 0dc89695..d5bea2c7 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -1191,8 +1191,6 @@ class CollectionState(object): def can_flute(self, player): if self.world.mode[player] == 'standard' and not self.has('Zelda Delivered', player): return False # can't flute in rain state - if any(map(lambda i: i.name in ['Ocarina', 'Ocarina (Activated)'], self.world.precollected_items)): - return True lw = self.world.get_region('Light World', player) return self.has('Ocarina (Activated)', player) or (self.has('Ocarina', player) and lw.can_reach(self) and self.is_not_bunny(lw, player)) diff --git a/Main.py b/Main.py index 69476418..3b54fb8d 100644 --- a/Main.py +++ b/Main.py @@ -252,6 +252,7 @@ def main(args, seed=None, fish=None): set_rules(world, player) district_item_pool_config(world) + dungeon_tracking(world) fill_specific_items(world) for player in range(1, world.players + 1): if world.shopsanity[player]: @@ -264,7 +265,6 @@ def main(args, seed=None, fish=None): massage_item_pool(world) if args.print_custom_yaml: world.settings.record_item_pool(world) - dungeon_tracking(world) logger.info(world.fish.translate("cli", "cli", "placing.dungeon.prizes")) fill_prizes(world) From a4f3afdf5de7769c73c8ec5bdfe6491781ef8ac7 Mon Sep 17 00:00:00 2001 From: aerinon Date: Fri, 31 Mar 2023 16:00:15 -0600 Subject: [PATCH 080/196] Reduce retro keys slightly --- ItemList.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ItemList.py b/ItemList.py index 845d0d78..23e79174 100644 --- a/ItemList.py +++ b/ItemList.py @@ -967,10 +967,7 @@ def get_pool_core(world, player, progressive, shuffle, difficulty, treasure_hunt if world.keyshuffle[player] == 'universal': pool.extend(diff.retro) if door_shuffle != 'vanilla': # door shuffle needs more keys for universal keys - replace = 'Rupees (20)' if difficulty == 'normal' else 'Rupees (5)' - indices = [i for i, x in enumerate(pool) if x == replace] - for i in range(0, min(10, len(indices))): - pool[indices[i]] = 'Small Key (Universal)' + pool.extend(['Small Key (Universal)'] * 5) # reduce to 5 for now if mode == 'standard': if door_shuffle == 'vanilla': key_location = random.choice(['Secret Passage', 'Hyrule Castle - Boomerang Chest', 'Hyrule Castle - Map Chest', 'Hyrule Castle - Zelda\'s Chest', 'Sewers - Dark Cross']) From 3eeeda363b3531b5b87aac9692b7fefc43680f6b Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sat, 1 Apr 2023 07:59:13 -0500 Subject: [PATCH 081/196] Fixed various Flute logic issues and improved logic efficiency --- BaseClasses.py | 6 +----- ItemList.py | 17 +++++++++++++++++ OverworldShuffle.py | 2 +- Rom.py | 3 +-- Rules.py | 7 +++++++ 5 files changed, 27 insertions(+), 8 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index 39a032fb..6ce354b1 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -1299,11 +1299,7 @@ class CollectionState(object): def can_flute(self, player): if self.world.mode[player] == 'standard' and not self.has('Zelda Delivered', player): return False # can't flute in rain state - if any(map(lambda i: i.name in ['Ocarina', 'Ocarina (Activated)'], self.world.precollected_items)): - return True - lw = self.world.get_region('Kakariko Area', player) - return self.has('Ocarina (Activated)', player) or (self.has('Ocarina', player) and lw.can_reach(self) - and self.is_not_bunny(lw, player)) + return self.has('Ocarina (Activated)', player) def can_melt_things(self, player): return self.has('Fire Rod', player) or (self.has('Bombos', player) and self.has_sword(player)) diff --git a/ItemList.py b/ItemList.py index 956b8153..3665c414 100644 --- a/ItemList.py +++ b/ItemList.py @@ -212,6 +212,20 @@ def generate_itempool(world, player): loc.locked = True loc.forced_item = loc.item + if not world.is_tile_swapped(0x18, player): + region = world.get_region('Kakariko Area',player) + + loc = Location(player, "Flute Activation", parent=region) + region.locations.append(loc) + world.dynamic_locations.append(loc) + + world.clear_location_cache() + + world.push_item(loc, ItemFactory('Ocarina (Activated)', player), False) + loc.event = True + loc.locked = True + loc.forced_item = loc.item + world.get_location('Ganon', player).event = True world.get_location('Ganon', player).locked = True world.push_item(world.get_location('Agahnim 1', player), ItemFactory('Beat Agahnim 1', player), False) @@ -1433,6 +1447,9 @@ def make_customizer_pool(world, player): place_item('Master Sword Pedestal', 'Triforce') guaranteed_items = alwaysitems + ['Magic Mirror', 'Moon Pearl'] + if world.is_tile_swapped(0x18, player) or world.flute_mode[player] == 'active': + guaranteed_items.remove('Ocarina') + guaranteed_items.append('Ocarina (Activated)') missing_items = [] if world.shopsanity[player]: guaranteed_items.extend(['Blue Potion', 'Green Potion', 'Red Potion']) diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 4d137416..9a789b7a 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -1092,7 +1092,7 @@ def build_accessible_region_list(world, start_region, player, build_copy_world=F region = base_world.get_region(region_name, player) for exit in region.exits: if exit.connected_region is not None: - if any(map(lambda i: i.name in ['Ocarina', 'Ocarina (Activated)'], base_world.precollected_items)) and exit.spot_type == 'Flute': + if any(map(lambda i: i.name == 'Ocarina (Activated)', base_world.precollected_items)) and exit.spot_type == 'Flute': fluteregion = exit.connected_region for flutespot in fluteregion.exits: if flutespot.connected_region and flutespot.connected_region.name not in explored_regions: diff --git a/Rom.py b/Rom.py index cc784646..63544102 100644 --- a/Rom.py +++ b/Rom.py @@ -2308,10 +2308,9 @@ def write_strings(rom, world, player, team): # of how many exist. This supports many settings well. items_to_hint = RelevantItems.copy() flute_item = 'Ocarina' - if world.is_tile_swapped(0x18, player): + if world.is_tile_swapped(0x18, player) or world.flute_mode[player] == 'active': items_to_hint.remove(flute_item) flute_item = 'Ocarina (Activated)' - items_to_hint.append(flute_item) if world.owShuffle[player] != 'vanilla' or world.owMixed[player]: # Adding a guaranteed hint for the Flute in overworld shuffle. this_location = world.find_items_not_key_only(flute_item, player) diff --git a/Rules.py b/Rules.py index edaa928e..9e03ad3b 100644 --- a/Rules.py +++ b/Rules.py @@ -70,6 +70,13 @@ def set_rules(world, player): elif world.goal[player] == 'completionist': add_rule(world.get_location('Ganon', player), lambda state: state.everything(player)) + if not world.is_tile_swapped(0x18, player): + if not world.is_copied_world: + # Commented out below, this would be needed for rando implementations where Inverted requires flute activation in bunny territory + # kak_region = self.world.get_region('Kakariko Area', player) + # add_rule(world.get_location('Flute Activation', player), lambda state: state.has('Ocarina', player) and state.is_not_bunny(kak_region, player)) + add_rule(world.get_location('Flute Activation', player), lambda state: state.has('Ocarina', player)) + # if swamp and dam have not been moved we require mirror for swamp palace if not world.swamp_patch_required[player]: add_rule(world.get_entrance('Swamp Lobby Moat', player), lambda state: state.has_Mirror(player)) From 1005c7f8441ff480be28ad7ff5fb6f0e0bdbdbc1 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sat, 1 Apr 2023 08:16:27 -0500 Subject: [PATCH 082/196] Reorganized spoiler log based on UI reorg --- BaseClasses.py | 45 ++++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index 6ce354b1..93691104 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -2872,6 +2872,7 @@ class Spoiler(object): 'dungeon_counters': self.world.dungeon_counters, 'item_pool': self.world.difficulty, 'item_functionality': self.world.difficulty_adjustments, + 'beemizer': self.world.beemizer, 'gt_crystals': self.world.crystals_needed_for_gt, 'ganon_crystals': self.world.crystals_needed_for_ganon, 'open_pyramid': self.world.open_pyramid, @@ -3051,25 +3052,33 @@ class Spoiler(object): if self.world.players > 1: outfile.write('\nPlayer %d: %s\n' % (player, self.world.get_player_names(player))) outfile.write('Settings Code:'.ljust(line_width) + '%s\n' % self.metadata["code"][player]) - outfile.write('Logic:'.ljust(line_width) + '%s\n' % self.metadata['logic'][player]) + outfile.write('\n') outfile.write('Mode:'.ljust(line_width) + '%s\n' % self.metadata['mode'][player]) - outfile.write('Swords:'.ljust(line_width) + '%s\n' % self.metadata['weapons'][player]) + outfile.write('Logic:'.ljust(line_width) + '%s\n' % self.metadata['logic'][player]) outfile.write('Goal:'.ljust(line_width) + '%s\n' % self.metadata['goal'][player]) if self.metadata['goal'][player] in ['triforcehunt', 'trinity', 'ganonhunt']: outfile.write('Triforce Pieces Required:'.ljust(line_width) + '%s\n' % self.metadata['triforcegoal'][player]) outfile.write('Triforce Pieces Total:'.ljust(line_width) + '%s\n' % self.metadata['triforcepool'][player]) outfile.write('Crystals Required for GT:'.ljust(line_width) + '%s\n' % str(self.world.crystals_gt_orig[player])) outfile.write('Crystals Required for Ganon:'.ljust(line_width) + '%s\n' % str(self.world.crystals_ganon_orig[player])) + outfile.write('Swords:'.ljust(line_width) + '%s\n' % self.metadata['weapons'][player]) + outfile.write('\n') outfile.write('Accessibility:'.ljust(line_width) + '%s\n' % self.metadata['accessibility'][player]) outfile.write('Restricted Boss Items:'.ljust(line_width) + '%s\n' % self.metadata['restricted_boss_items'][player]) - outfile.write('Difficulty:'.ljust(line_width) + '%s\n' % self.metadata['item_pool'][player]) outfile.write('Item Functionality:'.ljust(line_width) + '%s\n' % self.metadata['item_functionality'][player]) + outfile.write('Difficulty:'.ljust(line_width) + '%s\n' % self.metadata['item_pool'][player]) outfile.write('Flute Mode:'.ljust(line_width) + '%s\n' % self.metadata['flute_mode'][player]) outfile.write('Bow Mode:'.ljust(line_width) + '%s\n' % self.metadata['bow_mode'][player]) - outfile.write('Take Any Caves:'.ljust(line_width) + '%s\n' % self.metadata['take_any'][player]) - outfile.write('Shopsanity:'.ljust(line_width) + '%s\n' % yn(self.metadata['shopsanity'][player])) + outfile.write('Beemizer:'.ljust(line_width) + '%s\n' % self.metadata['beemizer'][player]) outfile.write('Bombbag:'.ljust(line_width) + '%s\n' % yn(self.metadata['bombbag'][player])) - outfile.write('Pseudoboots:'.ljust(line_width) + '%s\n' % yn(self.metadata['pseudoboots'][player])) + outfile.write('\n') + outfile.write('Shopsanity:'.ljust(line_width) + '%s\n' % yn(self.metadata['shopsanity'][player])) + outfile.write('Bonk Drops:'.ljust(line_width) + '%s\n' % yn(self.metadata['bonk_drops'][player])) + outfile.write('Pottery Mode:'.ljust(line_width) + '%s\n' % self.metadata['pottery'][player]) + outfile.write('Pot Shuffle (Legacy):'.ljust(line_width) + '%s\n' % yn(self.metadata['potshuffle'][player])) + outfile.write('Enemy Drop Shuffle:'.ljust(line_width) + '%s\n' % yn(self.metadata['dropshuffle'][player])) + outfile.write('Take Any Caves:'.ljust(line_width) + '%s\n' % self.metadata['take_any'][player]) + outfile.write('\n') outfile.write('Overworld Layout Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['ow_shuffle'][player]) if self.metadata['ow_shuffle'][player] != 'vanilla': outfile.write('Free Terrain:'.ljust(line_width) + '%s\n' % yn(self.metadata['ow_terrain'][player])) @@ -3079,35 +3088,37 @@ class Spoiler(object): outfile.write('OW Tile Flip (Mixed):'.ljust(line_width) + '%s\n' % yn(self.metadata['ow_mixed'][player])) outfile.write('Whirlpool Shuffle:'.ljust(line_width) + '%s\n' % yn(self.metadata['ow_whirlpool'][player])) outfile.write('Flute Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['ow_fluteshuffle'][player]) - outfile.write('Bonk Drops:'.ljust(line_width) + '%s\n' % yn(self.metadata['bonk_drops'][player])) + outfile.write('\n') outfile.write('Entrance Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['shuffle'][player]) if self.metadata['shuffle'][player] != 'vanilla': outfile.write('Shuffle GT/Ganon:'.ljust(line_width) + '%s\n' % yn(self.metadata['shuffleganon'][player])) outfile.write('Shuffle Links:'.ljust(line_width) + '%s\n' % yn(self.metadata['shufflelinks'][player])) outfile.write('Shuffle Tavern:'.ljust(line_width) + '%s\n' % yn(self.metadata['shuffletavern'][player])) + outfile.write('Pyramid Hole Pre-opened:'.ljust(line_width) + '%s\n' % self.metadata['open_pyramid'][player]) if self.metadata['shuffle'][player] != 'vanilla' or self.metadata['ow_mixed'][player]: outfile.write('Overworld Map:'.ljust(line_width) + '%s\n' % self.metadata['overworld_map'][player]) - outfile.write('Pyramid Hole Pre-opened:'.ljust(line_width) + '%s\n' % self.metadata['open_pyramid'][player]) + outfile.write('\n') + outfile.write('Map Shuffle:'.ljust(line_width) + '%s\n' % yn(self.metadata['mapshuffle'][player])) + outfile.write('Compass Shuffle:'.ljust(line_width) + '%s\n' % yn(self.metadata['compassshuffle'][player])) + outfile.write('Small Key Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['keyshuffle'][player]) + outfile.write('Big Key Shuffle:'.ljust(line_width) + '%s\n' % yn(self.metadata['bigkeyshuffle'][player])) + outfile.write('Key Logic Algorithm:'.ljust(line_width) + '%s\n' % self.metadata['key_logic'][player]) + outfile.write('\n') outfile.write('Door Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['door_shuffle'][player]) if self.metadata['door_shuffle'][player] != 'vanilla': outfile.write('Intensity:'.ljust(line_width) + '%s\n' % self.metadata['intensity'][player]) outfile.write('Door Type Mode:'.ljust(line_width) + '%s\n' % self.metadata['door_type_mode'][player]) outfile.write('Trap Door Mode:'.ljust(line_width) + '%s\n' % self.metadata['trap_door_mode'][player]) - outfile.write('Key Logic Algorithm:'.ljust(line_width) + '%s\n' % self.metadata['key_logic'][player]) outfile.write('Decouple Doors:'.ljust(line_width) + '%s\n' % yn(self.metadata['decoupledoors'][player])) - outfile.write('Experimental:'.ljust(line_width) + '%s\n' % yn(self.metadata['experimental'][player])) + outfile.write('Experimental:'.ljust(line_width) + '%s\n' % yn(self.metadata['experimental'][player])) outfile.write('Dungeon Counters:'.ljust(line_width) + '%s\n' % self.metadata['dungeon_counters'][player]) - outfile.write('Enemy Drop Shuffle:'.ljust(line_width) + '%s\n' % yn(self.metadata['dropshuffle'][player])) - outfile.write('Pottery Mode:'.ljust(line_width) + '%s\n' % self.metadata['pottery'][player]) - outfile.write('Pot Shuffle (Legacy):'.ljust(line_width) + '%s\n' % yn(self.metadata['potshuffle'][player])) - outfile.write('Map Shuffle:'.ljust(line_width) + '%s\n' % yn(self.metadata['mapshuffle'][player])) - outfile.write('Compass Shuffle:'.ljust(line_width) + '%s\n' % yn(self.metadata['compassshuffle'][player])) - outfile.write('Small Key Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['keyshuffle'][player]) - outfile.write('Big Key Shuffle:'.ljust(line_width) + '%s\n' % yn(self.metadata['bigkeyshuffle'][player])) + outfile.write('\n') outfile.write('Boss Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['boss_shuffle'][player]) outfile.write('Enemy Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['enemy_shuffle'][player]) outfile.write('Enemy Health:'.ljust(line_width) + '%s\n' % self.metadata['enemy_health'][player]) outfile.write('Enemy Damage:'.ljust(line_width) + '%s\n' % self.metadata['enemy_damage'][player]) + outfile.write('\n') + outfile.write('Pseudoboots:'.ljust(line_width) + '%s\n' % yn(self.metadata['pseudoboots'][player])) outfile.write('Hints:'.ljust(line_width) + '%s\n' % yn(self.metadata['hints'][player])) outfile.write('Race:'.ljust(line_width) + '%s\n' % yn(self.world.settings.world_rep['meta']['race'])) From 09ea7dd9a97093d3d04c8ae223f0ee9762a112e1 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sat, 1 Apr 2023 09:11:13 -0500 Subject: [PATCH 083/196] Fixed various Flute logic issues and improved logic efficiency --- Main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Main.py b/Main.py index 5b1a2384..8d2e5895 100644 --- a/Main.py +++ b/Main.py @@ -785,7 +785,7 @@ def create_playthrough(world): # get locations containing progress items prog_locations = [location for location in world.get_filled_locations() if location.item.advancement or world.goal[location.player] == 'completionist'] - optional_locations = ['Trench 1 Switch', 'Trench 2 Switch', 'Ice Block Drop', 'Skull Star Tile'] + optional_locations = ['Trench 1 Switch', 'Trench 2 Switch', 'Ice Block Drop', 'Skull Star Tile', 'Flute Activation'] optional_locations.extend(['Hyrule Castle Courtyard Tree Pull', 'Mountain Entry Area Tree Pull']) # adding pre-aga tree pulls optional_locations.extend(['Lumberjack Area Crab Drop', 'South Pass Area Crab Drop']) # adding pre-aga bush crabs state_cache = [None] From b66b2b24b7437d41817abe19ded69d0f7a87f433 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 2 Apr 2023 06:47:11 -0500 Subject: [PATCH 084/196] Fixed dungeon revival fake world behavior in glitched --- Rom.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rom.py b/Rom.py index 63544102..f93abec6 100644 --- a/Rom.py +++ b/Rom.py @@ -1364,7 +1364,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): rom.write_byte(0x180212, warningflags) # Warning flags # assorted fixes - rom.write_byte(0x1800A2, 0x01 if world.fix_fake_world else 0x00) # remain in real dark world when dying in dark world dungeon before killing aga1 + rom.write_byte(0x1800A2, 0x01 if world.fix_fake_world[player] else 0x00) # remain in real dark world when dying in dark world dungeon before killing aga1 rom.write_byte(0x180169, 0x01 if world.lock_aga_door_in_escape else 0x00) # Lock or unlock aga tower door during escape sequence. if world.is_atgt_swapped(player): rom.write_byte(0x180169, 0x02) # lock aga/ganon tower door with crystals in inverted From 034598c85ecf074663afbd06edf592eca4845915 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 2 Apr 2023 06:49:20 -0500 Subject: [PATCH 085/196] Added logic for mirror offset to Pyramid Area --- OverworldGlitchRules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OverworldGlitchRules.py b/OverworldGlitchRules.py index d135a9b6..dd306ac4 100644 --- a/OverworldGlitchRules.py +++ b/OverworldGlitchRules.py @@ -512,5 +512,5 @@ mirror_clips = [ mirror_offsets = [ (['DM Offset Mirror', 'DDM Offset Mirror'], ['West Death Mountain (Bottom)', 'West Dark Death Mountain (Bottom)'], ['Hyrule Castle Courtyard Northeast', 'Pyramid Crack'], ['Pyramid Area', 'Hyrule Castle Courtyard']), - (['DM To HC Ledge Offset Mirror', 'DDM To HC Ledge Offset Mirror'], ['West Death Mountain (Bottom)', 'West Dark Death Mountain (Bottom)'], ['Hyrule Castle Ledge', None], ['Pyramid Area', None]) + (['DM To HC Ledge Offset Mirror', 'DDM To Pyramid Offset Mirror'], ['West Death Mountain (Bottom)', 'West Dark Death Mountain (Bottom)'], ['Hyrule Castle Ledge', 'Pyramid Area'], ['Pyramid Area', 'Hyrule Castle Area']) ] \ No newline at end of file From 7f38b31d55a606488d4d7cb4f490cc3298c25883 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 2 Apr 2023 07:42:27 -0500 Subject: [PATCH 086/196] Fixed Old Man Death causing fake world in glitched --- Rom.py | 6 +++++- data/base2current.bps | Bin 105965 -> 105975 bytes 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Rom.py b/Rom.py index f93abec6..fb0cf141 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '0a3d1d4bbec659013be5ed876c2658bd' +RANDOMIZERBASEHASH = '0dd61456cc38a4792d99d23047163660' class JsonRom(object): @@ -935,6 +935,10 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): old_man_house = world.get_region('Old Man House', player) if should_be_bunny(old_man_house, world.mode[player]): rom.write_bytes(0x13fff4, [0xe4, 0x00]) + + old_man_cave = world.get_entrance('Old Man Cave Exit (East)', player) + if old_man_cave.connected_region.type == RegionType.DarkWorld: + rom.write_byte(0x13fff6, 0x40) # patch doors if world.doorShuffle[player] not in ['vanilla', 'basic']: diff --git a/data/base2current.bps b/data/base2current.bps index d492f90b61065409a0fa2cfbfa8766eb30c23ef7..617b02c3657f10d281afa5b62b17ac7efbe2b7d0 100644 GIT binary patch delta 8809 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 delta 8881 zcmX{*30xD$*O^>|8$lp)xh%*f2#5%x2nr|)Dxx9+Dqb}h5Adph!fqt!0!s)ZtPnAa zfH5M5ifz0osI?j|;`OgmEeL?Zzkctonx<1*_~_!g?jskd!MM7N6lh_#$T2)s-Tj80kp$~f|Vc= z>IKW~ZS^d_zK+lT#QE~&OGr3D*+D=uV<_`lxadQG@pkzgc})Awj=+ z#10v$S--L8l=$&u>`?9Gm3Q=DVnw!$#@!oOJE9KfRchJ=L+7Zn2DYE-Jix}2)Q$tJ z8$sbA4XU7wk`SVy>;Q|+{hQz`C^6agqJeF90@--T0k&QI%jP8|VmZYj4(+eO&%;bJ ztXO)C{n8XUpB{;hIC+z8r}4I%Y&zl&GswQA9=~G6q<*&iC#v-o8@s0lzu(Flu$R>0 zM{I2npgY^^IM&*#Iy-BvXB}p(wXd}wD@#Vgx_FVz9+oY>;x}d$ZB*i2kJ#)9YB~!s zCPdbN7q_w|ZuU^1+=s?_1MCDs{?|1{f1-@St*w6UfJG_Ew_C>0OaOFp5j4wpRA8V)PUF&`>j3o=#FJ$5_5h z?*CWrzB;^wIyyAep1hmNx;6-bQ6!_@wz6AWsBjo$E_OK4#dcF!4J@Xn@%ctpQcL|8 zE;dg{YWtNkj6D|qScrgKQypeMG(EMsFcpKebanj zne_|0{kgIl-0l_9{$r{M{z!;ve;`d(W=(q0Jd}+{)DJdap^O#m{a+T2L%iDv8?C&- z3HY!Z}SADRK;S5xIY=M9Vbr7+e@oR&zEi6^y|A8q^_nq-4EPuBW-}a^%kx1hRO+jjd!x-muFdpuA?ihPW z#a5^+S2e{WQboN<&@+WoAMi-#Ub==LV`+w8)E#55BD?$f7^L5V#2R*^vwNKcMmIe zC8&|N*m^uuHVl6#9d1)jQhO>j5>lBZMHUj7kHh_JJ5|xo<{~ckp(_eEF1f!G>CDby z1DcE8Ka+_hbBXHdd5_Z%P}6R)I|#)Nh3EiZ;?81waQk)@RNF_v?<2LCc_DAUW7xCpjQI}GCC!s)X?L5F&JArHiM zxX!Q;AmEd91I+iTXS05K*bK)JG%vZVPPI6yuEf4$;X@w7my zyZ*LFiX%;yyGwB|cz164s>2QJ5&UKYi|1)r#s2Q11JAkLK1N3vdWW<n& zFxGQkL=)0P9VA0c94%0wOI^>$n z0Y~BV4(d`ufG6xvaS^g=!+?fgJ%8;eR;_jB_=QpOvgKWH2G^YB<8z> zd~H^V<)qWu1cJ2dla*hs6L5_2okkm#`MfJiGoAU_qneHLu8`9P2hUo{>(E12=PS7g zEKS{P|FzjLS%cAJ!r)TbSucu4!;e$X6pz;!!ZhO{Ie!q1*3$?z(*)F$ssE2=45JGW z>hSNZP~%chE<~vNzo@^)yPjNxP{F_GF^yF{nfCwaZ^P(fgjy2gfb5F zx=|?Vc~=DYkwJ{C5tC}iNev&2{t!(&w7R2htrapwnlquE52Z`uimfb(w`0A~T+Lkoj`Mvh05=4)G(<~Q62VCt+$a{4#mmvAf@8ydL#WR{K)ru5rD~Vr(!T0UFVG6TGlM|_T$t%^>)3(Uv@y&5d*QmwUlrl7B6EyQ zuZ~p&bQdYccNa7kluYl2%X#6Y!Tx!a~cHt6ZeA!Ptq<1T zVSSY4afUN5bqTX$Q=CtCyfba(#legB+k1layIUMni z^G|i{MBd{o=f?;*J{uQGPnoRGMZk<~FIV{~#*Ft*o5*CY_3`^L;#7msnOVvGhx%{w z4Y)ts9c}(YcF?2?XV``z`>y{W5a7@?gupt7t}h52b?CA`i{>1tq2oH1#TnF%jIw?}b&yd86F~_EU3P+@(uWKt zM!}aW(%e0Q47Ug(dH~bOi4X(P9;SmS#YP96Tyd0H1edRjjC|E;Sk0;8B`5!Auo#A| zKN`R=wCGxG!SI6()`TeX`7_>A3*xQZs{5mH3UJRq1=2&Dq<1}C?|lEvnuM_43=y*uHm*vKn(6fE zG{FvF+OG<1f;pnd-Batt9oDM;6N$xC3^>giwt z+`f8C@#pjGQOx{8!AGVz`EOOh?7th6le=43^pJH^Sm@_BhACBVwFJ%a#Jn$PZ4n$M zjlxVeTFwid+9T|93&BOcDJP{^mkOAox3@q5KLy zs)|dsBhmimMj(|)B>uIIyZV$_Z_0(zrWFydP6H07Oq@fE7`_MtA^X)C{8vH51-op_ z8!FdKo&pzTy}9xJf;N^G#2paEA?W0(&7hq2*7TIse%!{(>NiCOK;PJ~klK4di zk2hHoR5EcRsm}&Fp>TN5yMq%+wnVwgN+u0{vUXF*h2lQ6K%wRU6Jz#2IT~EtN}Tw! zri7fKu^|_b)+FP=y{56}UTfl$3IQq45UB(yrQZz;anh5^CSCy%UZ7f0{Ad~xh?QNz zo?phF?iN<@u%lP7Z1{5RC{g>*SJ011gVvG>@iCcY4SfrcU=L!qO#euk9Mt0DIN~O$~4=zLAfLXJb|5(`5wW+ z*V<5Eg%r-8$BD8y!hB%*9C+uxTfXyChDXq#YZKW#Wm=3 zI)U&fjAs2-CLXr=>Xm2cmmPI=>eU%nQ?I67T?X&0o6dcI6*^0Ozy&x}I?8^GUj>}r z?MNWaZq5F5^~+T*%#nt=1c2X>A66i@)7q5L+t^YqUIpaUk^&eGPf8~*-}yih*}!Z& zK-v$=^x?-;8<3q%RGIH?kx0*>s16=ur3^3cIgH)2pcCJY1D zSi%eq;GG>P`Wv3#4`U}2Z3b_nTL$Zm$9BwJ?+85Uo9rci74I4GXIJG-mYJ3IFo!I& zusGVKxXIGbQo59|WWxlv{OfHmQ_yH9XMW@pQ3Gc_-JjCQo&Ut5fr*57H+Va3yRP^i z1?SZ3Z?B^Oz4K=wG9Z85fHoWb%-Ea5H3A5uH;(cW<&X%VXib+(_?ihko^BX&))AUR!!2 zQHK*DMm{dQ&FZ}V?fKkR6^WrKce>*yyPnh2`mDv$e}iNU#mGfXd^j`D7u<)N@&YWT z^(zg$Dz8Xp25ib(@7;R`2}aDUo%x|LQmUKxw#ekxtBUkNf)Dz!c9q})IZwrbVVi?M zC|t4G4Yfs^qo*woM#(;0Tvro%uRF?Ut)G}gQj?ADnw%uECoqX52zeYDZ6MXSz&wMprb5wF@y{Sk;K332863{#V5j(z8kTJ#G{n0@$|RZZFi~D())1(N1Nsp>d4S z0(Y!sv3>BkV!_@9M29b$xeDQ{tsccE;TdHZLi=G^V?>p8cT~GM7N<5N8>7%sQ_xY4 zkVBGFnqH96O=6;PDjJPNqbpz;nb-u$Swpy?r zrf)90x%+6&`;3i+G((eNax&iV|Cy?GZ4wsFC~eCH%8!5*UKP#nFHZHxw@z9=cHM zkA_|rzc81^e4tS2SY-wKiFEO%T(Z-IoJza7L~F%@tWg63Nd&Q33{%KiU<9lu!@wDM zlT7efnNBEC>}Rw)m>Trlk>GOLXJdu0r3NJLX;>i)m3bh_Qe+swV4f__CUfCm%EY5x zu`<=DPgEhiAX^0zq0jDbKpdoZhXFA>zuN=&!v5WPuCh05*6TN{)S5cela`_b=@iZ*ZD^%z1hh zxborxCQaip?{!gY(@tF|n94>u!N zh+qMNytMbQQ$E3#87=s=!49d-k#{;169~nn^~h&;lm=O^TJ)aYPpoUH<`C*A_^LG1 z(lKv<&N}wdOqH7p7wnk~#zMuO(KCGiK6+4h08W>_Kh&%XmcEz!{#}1iK7graNZ!ls zzpviiny`zk$!_6jI9(k(IWqZ$5LNhw_wxL|RfmV0BV<0aRSMtjSs+}p^UIdw$#Blz z2FC?Mr{hzKqY?)&X^R62RV>fM1Neil{JVTM% z+e3E9exGI510D3+zsSZJeNjQ>5#7!Xn-a>eqkR7cFCoYMtlBE8$9E+-te{Zs~K!pKYU++rFQUBZzXG+r77R&<=bln;P648J@^ z?D$EMMe8PpS5{}G%VA*>Os=b~s)22NQA% z%Hhg_axxK~t>H^h{Y=6vnpfUpK*@tZ3l4FlOoF4V?FveUM7nKch|z(7c5urzUl7xw zx^@rsUNZ#o|-o%Ns6>UZ~(YlJb*C75h{( zgDaGFayMz>>ovZlT(`V6#1VnHsu)KS3e5?)axP7AO+se*R0Ui;RY3uhFO!7&MVCoe z%}Op=zuBQuzG=5Q7G~az0;^%|&C!UVKir(@iHey_R_JxcDV%^4WTZ$Pg{mu@c@;Id zK*j3zsKTK~&je49|DX=n-D3SdN}1^S4dq||l;U=M%~=tG2eFBHD$p zu4m$ijHP6aPL23s$84-lAn-KU-xCTFI_!-}z%g%i#c8AEA$=X&Z-@N~iBMeyv!i44 zt-}C3hokNsbX=QPq5dYXLK)!TLI*NsaCu;bdK|od=MvJb>bvi`R_i;;?zM2ambozW zzSo!}9w2H2aaucC$nZ6^1nKo_el~|taHkVWJCuJ|Hf?f;`S&r0b*^9PS9*U(-mI0; zHY0SuG90IlWA~E*G7^73nCy_tt0eg<*%(4NzgWxV$ocpwII}kuajL#IZ}OXs}0 zqpA$3zJMKKie@zaleZU!=F%{IZW&xPx2!H3Wm_oMV$yPH(x9G`OUtzc^)I&gYtOI6WkXDe5@$btj59{zh?$wJu04kyfJe*s7SSmbiCC zMsr=zyP_z@B9=)Lf;4`}kZL{CE(9(UN_$!SoSw~K#dz3VwgBJp(fVVL4M`){7@!LB zP}J<<7(H5!Fp0d%2gZ?p!%=n^^F;^}#m=J?7du)|=q=1Rf(H4~lzjXpv&;-Q z3BKJ`$)qy*W*}nx()krii4xRQ)%mJ6*(l1-l%Fj>URP%8`>sggt3Y2G z(S_K6Zl|3YGhhbBik5m+$rT%$#Ehc|OcVI8s$_haOc9t0HZk=g;0j(cKZt-2z?erO zAO(5MEORih15ckc8lcbjmaCb53?zXfeV`|}!%c9M&nC9k|UWw;eJLc*e|aV)~-3x zAiaPYaA34jZ^+Sq^afM-&M8w2=d*(dkya8!@U+F4f_u3r8w!{?{-DHdkyLS-%dz9w zaKs#YjuXd%GZG%G6|Sve?6xtl{DJ$(kW;KKfe7*cY6L1#<{r5TFyV|x00?$-Out8( zG_ecs$yYJZPS#?^K|$IoMmxe!=f>m&fK8Tb^6Hc(A=bISbtf|z0J^z57BVek!784R zQ_olif<+*PSrLdtGMOn31ih9K(`XvK^hCXdGqXAftN}Bat3kjUtkAy>0@noGor%o3 zFfaxr=m)~Ub>KLW+l$<6lQ+>=@KMqtdiVILR28Sc7!D%1pqKe40=RR{XEH94;9D*? zjDe9L2!t``BZ0eM@#ZR(i+(T?=?gbEgZXn32;o`X-FcrKMtd}Y~vKW30Sim)(!7PaZ;at%irYZ*1 zi1YHB>P$9W?Wd3SK(8F4rfgQMv`pHRrH_sUd%0XkYv%HF;0ZGH&!+<+7tCZ#@raG7 wdYc5WaRPT;5>u29oWOd0O+Kg=ik7(iRJ-XQT&WKxK)1Vyax`))4$TYuU-=<*;{X5v From 2ed1edbc2006ecc3b921850fe167279eb250d7a9 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 2 Apr 2023 08:28:29 -0500 Subject: [PATCH 087/196] Fixed issue with some Cliff Drop connections in Mixed + OWG --- OverworldShuffle.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 9a789b7a..44e7ab02 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -1451,11 +1451,6 @@ mandatory_connections = [('Old Man S&Q', 'Old Man House'), ('Bomber Corner Pier', 'Bomber Corner Area'), # OWG In-Bounds Connections - ('Stone Bridge EC Cliff Water Drop', 'Stone Bridge Water'), #fake flipper - ('Tree Line WC Cliff Water Drop', 'Tree Line Water'), #fake flipper, - - ('Hammer Bridge EC Cliff Water Drop', 'Hammer Bridge Water'), #fake flipper - ('Dark Tree Line WC Cliff Water Drop', 'Dark Tree Line Water'), #fake flipper ('Ice Lake Northeast Pier Hop', 'Ice Lake Northeast Bank'), ('Ice Lake Moat Bomb Jump', 'Ice Lake Moat') ] @@ -1470,7 +1465,7 @@ default_whirlpool_connections = [ default_flute_connections = [ 0x0b, 0x16, 0x18, 0x2c, 0x2f, 0x38, 0x3b, 0x3f ] - + ow_connections = { 0x03: ([ ('West Death Mountain Teleporter', 'West Dark Death Mountain (Bottom)') @@ -1555,12 +1550,20 @@ ow_connections = { ('Stone Bridge East Ledge Drop', 'Stone Bridge North Area'), # OWG ('Hammer Bridge North Ledge Drop', 'Hammer Bridge North Area'), # OWG ('Stone Bridge Cliff Ledge Drop', 'Stone Bridge South Area'), # OWG - ('Hammer Bridge South Cliff Ledge Drop', 'Hammer Bridge South Area') # OWG + ('Hammer Bridge South Cliff Ledge Drop', 'Hammer Bridge South Area'), # OWG + ('Stone Bridge EC Cliff Water Drop', 'Stone Bridge Water'), # fake flipper + ('Hammer Bridge EC Cliff Water Drop', 'Hammer Bridge Water'), # fake flipper + ('Tree Line WC Cliff Water Drop', 'Tree Line Water'), # fake flipper + ('Dark Tree Line WC Cliff Water Drop', 'Dark Tree Line Water') # fake flipper ], [ ('Stone Bridge East Ledge Drop', 'Hammer Bridge North Area'), # OWG ('Hammer Bridge North Ledge Drop', 'Stone Bridge North Area'), # OWG ('Stone Bridge Cliff Ledge Drop', 'Hammer Bridge South Area'), # OWG - ('Hammer Bridge South Cliff Ledge Drop', 'Stone Bridge South Area') # OWG + ('Hammer Bridge South Cliff Ledge Drop', 'Stone Bridge South Area'), # OWG + ('Stone Bridge EC Cliff Water Drop', 'Hammer Bridge Water'), # fake flipper + ('Hammer Bridge EC Cliff Water Drop', 'Stone Bridge Water'), # fake flipper + ('Tree Line WC Cliff Water Drop', 'Dark Tree Line Water'), # fake flipper + ('Dark Tree Line WC Cliff Water Drop', 'Tree Line Water') # fake flipper ]), 0x2e: ([ ('Tree Line Ledge Drop', 'Tree Line Area'), # OWG From bbf254d6f64d281ecc9238adc26c71dd82a8a501 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 2 Apr 2023 09:03:17 -0500 Subject: [PATCH 088/196] Adding missing region to Tile Regions list --- OWEdges.py | 1 + 1 file changed, 1 insertion(+) diff --git a/OWEdges.py b/OWEdges.py index cf397f18..f5982ee2 100644 --- a/OWEdges.py +++ b/OWEdges.py @@ -1182,6 +1182,7 @@ OWTileRegions = bidict({ 'East Dark Death Mountain (Top)': 0x45, 'East Dark Death Mountain (Bottom Left)': 0x45, 'East Dark Death Mountain (Bottom)': 0x45, + 'East Dark Death Mountain (Bushes)': 0x45, 'Dark Death Mountain Ledge': 0x45, 'Dark Death Mountain Isolated Ledge': 0x45, 'Dark Death Mountain Floating Island': 0x45, From 9cef1ff32ecba701b7ccec40a8cc6483625df31a Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 3 Apr 2023 08:21:34 -0500 Subject: [PATCH 089/196] Temporary fix for avoiding VRAM issues in non-layout OWR modes --- Rom.py | 2 +- asm/owrando.asm | 36 +++++++++++++++++++----------------- data/base2current.bps | Bin 105975 -> 105987 bytes 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/Rom.py b/Rom.py index fb0cf141..c164e845 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '0dd61456cc38a4792d99d23047163660' +RANDOMIZERBASEHASH = '92c16c60f26218c9aec838ce204c0b1e' class JsonRom(object): diff --git a/asm/owrando.asm b/asm/owrando.asm index a308a9fc..c4f512b0 100644 --- a/asm/owrando.asm +++ b/asm/owrando.asm @@ -860,31 +860,33 @@ OWNewDestination: { tya : sta $4202 : lda #16 : sta $4203 ;wait 8 cycles rep #$20 : txa : nop : !add $4216 : tax ;a = offset to dest record - lda.w $0006,x : sta $06 ;set coord lda.w $0008,x : sta $04 ;save dest OW slot/ID - lda.w $000a,x : sta $84 ;VRAM - + ldy $20 : lda $418 : dec #2 : bpl + : ldy $22 : + sty $06 + ;;22 e0 e2 61c 61e - X ;;20 e6 e8 618 61a - Y ;keep current position if within incoming gap lda.w $0000,x : and #$01ff : pha : lda.w $0002,x : and #$01ff : pha - ldy $20 : lda $418 : dec #2 : bpl + : ldy $22 - + tya : and #$01ff : cmp 3,s : !blt .adjustMainAxis - dec : cmp 1,s : !bge .adjustMainAxis - inc : pha : lda $06 : and #$fe00 : !add 1,s : sta $06 : pla + LDA.l OWMode : AND.w #$0007 : BEQ .noLayoutShuffle ;temporary fix until VRAM issues are solved + lda.w $0006,x : sta $06 ;set coord + lda.w $000a,x : sta $84 ;VRAM + tya : and #$01ff : cmp 3,s : !blt .adjustMainAxis + dec : cmp 1,s : !bge .adjustMainAxis + inc : pha : lda $06 : and #$fe00 : !add 1,s : sta $06 : pla - ; adjust and set other VRAM addresses - lda.w $0006,x : pha : lda $06 : !sub 1,s - jsl DivideByTwoPreserveSign : jsl DivideByTwoPreserveSign : jsl DivideByTwoPreserveSign : jsl DivideByTwoPreserveSign : pha ; number of tiles - lda $418 : dec #2 : bmi + - pla : pea $0000 : bra ++ ;pla : asl #7 : pha : bra ++ ; y-axis shifts VRAM by increments of 0x80 (disabled for now) - + pla : asl : pha ; x-axis shifts VRAM by increments of 0x02 - ++ lda $84 : !add 1,s : sta $84 : pla : pla + ; adjust and set other VRAM addresses + lda.w $0006,x : pha : lda $06 : !sub 1,s + jsl DivideByTwoPreserveSign : jsl DivideByTwoPreserveSign : jsl DivideByTwoPreserveSign : jsl DivideByTwoPreserveSign : pha ; number of tiles + lda $418 : dec #2 : bmi + + pla : pea $0000 : bra ++ ;pla : asl #7 : pha : bra ++ ; y-axis shifts VRAM by increments of 0x80 (disabled for now) + + pla : asl : pha ; x-axis shifts VRAM by increments of 0x02 + ++ lda $84 : !add 1,s : sta $84 : pla : pla - .adjustMainAxis - LDA $84 : SEC : SBC #$0400 : AND #$0F00 : ASL : XBA : STA $88 ; vram - LDA $84 : SEC : SBC #$0010 : AND #$003E : LSR : STA $86 + .adjustMainAxis + LDA $84 : SEC : SBC #$0400 : AND #$0F00 : ASL : XBA : STA $88 ; vram + LDA $84 : SEC : SBC #$0010 : AND #$003E : LSR : STA $86 + .noLayoutShuffle LDA.w $000F,X : AND.w #$00FF : STA.w $06FC ; position to walk to after transition (if non-zero) LDY.w #$0000 diff --git a/data/base2current.bps b/data/base2current.bps index 617b02c3657f10d281afa5b62b17ac7efbe2b7d0..6efe11ee423d08175e56237349ff9b06c40a44eb 100644 GIT binary patch delta 435 zcmV;k0Zjh)y9R^22C!uT1o%Y_#R1Oc3via!Az1qFd1oRpWVKLJ1iHJ9u^0c-)qw^={|9|1iLfWjb(>KJVnLaMz8 z0EGmkAgve#Iyw*nq#}d{y#N3y{{cw70+UjLlVxd@QGf>k@Nm5b0EGs<3IK(Km#aYm zC?Hg7m4Qf;H-ODB259sE0DuE%3P`1d7-Ip2glK4+T@jb?K>Tori!Hng^Gp+ARCunLjf!j#gt&12rM0dfeN2gp3%?) zOrMvWLjffLl9$3m0VD=QmVj&^M3?MC0XH2)mZe?E1keW}DwqeHMFXogLkobH0Dy@X z&;px5mq0`THxx>ArmbXMzyZ)ZrCrGc@HLaklTDY4L;)EpLJkRl!TP0L$rsQEsRNAz z2V`Af!XTG>iXngk@EqbGrHUy(@D!zrAYPZyL;)WHR}Gi(L;)NDP?rux0YL$Emrz9k d76~87Ms5y(pKW8eZ$$xsSO_8Z;054YAG+hym?Z!J delta 458 zcmV;*0X6=EyaxBX2C!uT1gJ_^wX_#R1Obtkia!Az1dEJ$fS0U40YCvqm+e0RYyrBrT0j9G0W$%B!XS$37;P3ps=WpP zg$BI{0EGm-3IK(Ky#N3y{{cw70+URFMS!Frtr!G4IuHV+BA2#70Vo~nfk>0_%`gUN z^Z)>W1853JrGyw`0fmHUXqycZm;ONkM*(J+MnVCN0(}gZ)j|O)0WOyTLjgPjbyb%? zLjfTSx|F7hr3HnGh6NxHmuy1;EE2kuV4Dam9e{xfpH!aF&;v}Am#RYnB>{(*&_e+v z20501Y#=$8`a=OX9XXbzUC9K{2O=t%2b@I%s~|%QfR_M(i5JiUn=6-2L;*KhG<2q| zWL>}k&^x7F$pr8yfPH}arCrGv z&uL6LoDF*`Z9O59QiYY(v6s3wFQ1kL;gYu|Rk0!zq7ZVrH-17x>*MFD_V2yXp*z6tzCs2B{T A2mk;8 From 9406f408df9ff769cf795767867413d95d94077d Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 3 Apr 2023 08:25:14 -0500 Subject: [PATCH 090/196] Fix for HC dark rooms not getting correct lamp logic in partitioned DR --- Rules.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Rules.py b/Rules.py index 9e03ad3b..99058d17 100644 --- a/Rules.py +++ b/Rules.py @@ -1376,9 +1376,9 @@ def add_conditional_lamps(world, player): is_dark = False if not world.sewer_light_cone[player]: is_dark = True - elif world.doorShuffle[player] != 'crossed' and not info['sewer']: + elif world.doorShuffle[player] not in ['partitioned', 'crossed'] and not info['sewer']: is_dark = True - elif world.doorShuffle[player] == 'crossed': + elif world.doorShuffle[player] in ['partitioned', 'crossed']: sewer_builder = world.dungeon_layouts[player]['Hyrule Castle'] is_dark = region not in sewer_builder.master_sector.region_set() if is_dark: From 46ed496669c3eec71901d2f7d4a63bb3339c7910 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 3 Apr 2023 08:33:28 -0500 Subject: [PATCH 091/196] Version bump 0.3.0.5 --- CHANGELOG.md | 6 ++++++ OverworldShuffle.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42ae2fb2..35763257 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 0.3.0.5 +- Major reorganization to GUI Options +- Corrected various fake world behavior in glitched modes +- Fixed various issues with glitched mode logic +- Various minor logic fixes + ## 0.3.0.4 - \~Merged in DR v1.2.0.14~ - Fixed issue with enemy drops on OW enemies diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 44e7ab02..a91db720 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -7,7 +7,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType from OverworldGlitchRules import create_owg_connections from Utils import bidict -version_number = '0.3.0.4' +version_number = '0.3.0.5' # branch indicator is intentionally different across branches version_branch = '-u' From 3e65deda1420c245d16f174168bad2b92c8f63cb Mon Sep 17 00:00:00 2001 From: aerinon Date: Mon, 3 Apr 2023 16:37:29 -0600 Subject: [PATCH 092/196] Minor fixes --- ItemList.py | 3 +++ Rom.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ItemList.py b/ItemList.py index 4559c5fb..b9e3f4c8 100644 --- a/ItemList.py +++ b/ItemList.py @@ -1256,6 +1256,9 @@ def make_customizer_pool(world, player): place_item('Master Sword Pedestal', 'Triforce') guaranteed_items = alwaysitems + ['Magic Mirror', 'Moon Pearl'] + if world.flute_mode[player] == 'active': + guaranteed_items.remove('Ocarina') + guaranteed_items.append('Ocarina (Activated)') missing_items = [] if world.shopsanity[player]: guaranteed_items.extend(['Blue Potion', 'Green Potion', 'Red Potion']) diff --git a/Rom.py b/Rom.py index 78fc0ddb..388d28c8 100644 --- a/Rom.py +++ b/Rom.py @@ -1291,7 +1291,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): rom.write_byte(0x180211, gametype) # Game type # assorted fixes - rom.write_byte(0x1800A2, 0x01 if world.fix_fake_world else 0x00) # remain in real dark world when dying in dark world dungeon before killing aga1 + rom.write_byte(0x1800A2, 0x01 if world.fix_fake_world[player] else 0x00) # remain in real dark world when dying in dark world dungeon before killing aga1 rom.write_byte(0x180169, 0x01 if world.lock_aga_door_in_escape else 0x00) # Lock or unlock aga tower door during escape sequence. if world.mode[player] == 'inverted': rom.write_byte(0x180169, 0x02) # lock aga/ganon tower door with crystals in inverted From 09550cd5461969fe5a8c24944558857c5bbd8121 Mon Sep 17 00:00:00 2001 From: aerinon Date: Tue, 4 Apr 2023 16:53:45 -0600 Subject: [PATCH 093/196] Minor fix --- source/overworld/EntranceShuffle2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index 0bbc8533..f696df01 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -446,7 +446,7 @@ def do_links_house(entrances, exits, avail, cross_world): forbidden.extend(['Spike Cave', 'Dark Death Mountain Fairy']) # lobby shuffle means you ought to keep links house in the same world - sanc_spawn_can_be_dark = (not avail.inverted and avail.world.doorShuffle[avail.player] == 'crossed' + sanc_spawn_can_be_dark = (not avail.inverted and avail.world.doorShuffle[avail.player] in ['partitioned', 'crossed'] and avail.world.intensity[avail.player] >= 3) entrance_pool = entrances if avail.coupled else avail.decoupled_entrances if cross_world and not sanc_spawn_can_be_dark: From f13880eee9814417fbd0da028956e1fb71963c35 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 29 Mar 2023 08:58:48 -0600 Subject: [PATCH 094/196] Major GUI reorganization --- BaseClasses.py | 19 +- CLI.py | 2 +- Gui.py | 8 +- Rom.py | 2 +- Rules.py | 2 +- mystery_example.yml | 10 ++ resources/app/cli/args.json | 7 +- .../app/gui/custom/overview/widgets.json | 18 ++ resources/app/gui/lang/en.json | 128 ++++++++------ .../app/gui/randomize/dungeon/keysanity.json | 8 + .../app/gui/randomize/dungeon/widgets.json | 57 +++--- .../app/gui/randomize/entrando/widgets.json | 46 +++-- .../gui/randomize/generation/checkboxes.json | 5 +- resources/app/gui/randomize/item/widgets.json | 165 +++++++++++++----- source/classes/constants.py | 76 ++++---- source/gui/bottom.py | 18 +- source/gui/custom/overview.py | 23 ++- source/gui/loadcliargs.py | 37 ++-- source/gui/randomize/dungeon.py | 14 +- source/gui/randomize/entrando.py | 5 +- source/gui/randomize/item.py | 43 ++++- source/gui/startinventory/overview.py | 23 ++- source/gui/widgets.py | 67 ++++++- source/tools/MysteryUtils.py | 2 +- 24 files changed, 522 insertions(+), 263 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index 216c0d3f..d34e0b67 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -133,7 +133,7 @@ class World(object): set_player_attr('crystals_needed_for_gt', 7) set_player_attr('crystals_ganon_orig', {}) set_player_attr('crystals_gt_orig', {}) - set_player_attr('open_pyramid', False) + set_player_attr('open_pyramid', 'auto') set_player_attr('take_any', 'none') set_player_attr('treasure_hunt_icon', 'Triforce Piece') set_player_attr('treasure_hunt_count', 0) @@ -275,6 +275,19 @@ class World(object): def is_atgt_swapped(self, player): return self.mode[player] == 'inverted' + def is_pyramid_open(self, player): + if self.open_pyramid[player] == 'yes': + return True + elif self.open_pyramid[player] == 'no': + return False + else: + if self.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull']: + return False + elif self.goal[player] in ['crystals', 'trinity']: + return True + else: + return False + def check_for_door(self, doorname, player): if isinstance(doorname, Door): return doorname @@ -2659,7 +2672,7 @@ class Spoiler(object): outfile.write(f"Overworld Map: {self.metadata['overworld_map'][player]}\n") outfile.write(f"Take Any Caves: {self.metadata['take_any'][player]}\n") if self.metadata['goal'][player] != 'trinity': - outfile.write('Pyramid hole pre-opened: %s\n' % ('Yes' if self.metadata['open_pyramid'][player] else 'No')) + outfile.write('Pyramid hole pre-opened: %s\n' % (self.metadata['open_pyramid'][player])) outfile.write('Door Shuffle: %s\n' % self.metadata['door_shuffle'][player]) if self.metadata['door_shuffle'][player] != 'vanilla': outfile.write(f"Intensity: {self.metadata['intensity'][player]}\n") @@ -2997,7 +3010,7 @@ class Settings(object): | (counter_mode[w.dungeon_counters[p]] << 1) | (1 if w.experimental[p] else 0), ((8 if w.crystals_ganon_orig[p] == "random" else int(w.crystals_ganon_orig[p])) << 3) - | (0x4 if w.open_pyramid[p] else 0) | access_mode[w.accessibility[p]], + | (0x4 if w.is_pyramid_open[p] else 0) | access_mode[w.accessibility[p]], (0x80 if w.bigkeyshuffle[p] else 0) | (0x20 if w.mapshuffle[p] else 0) | (0x10 if w.compassshuffle[p] else 0) diff --git a/CLI.py b/CLI.py index d1bc47d3..312c1d80 100644 --- a/CLI.py +++ b/CLI.py @@ -186,7 +186,7 @@ def parse_settings(): "restrict_boss_items": "none", # Shuffle Ganon defaults to TRUE - "openpyramid": False, + "openpyramid": 'auto', "shuffleganon": True, "shuffle": "vanilla", "shufflelinks": False, diff --git a/Gui.py b/Gui.py index d8ebf356..35d7a36b 100755 --- a/Gui.py +++ b/Gui.py @@ -137,14 +137,14 @@ def guiMain(args=None): self.pages["randomizer"].pages["entrance"] = entrando_page(self.pages["randomizer"].notebook) self.pages["randomizer"].notebook.add(self.pages["randomizer"].pages["entrance"], text="Entrances") + # Dungeons + self.pages["randomizer"].pages["dungeon"] = dungeon_page(self.pages["randomizer"].notebook) + self.pages["randomizer"].notebook.add(self.pages["randomizer"].pages["dungeon"], text="Dungeons") + # Enemizer self.pages["randomizer"].pages["enemizer"],self.settings = enemizer_page(self.pages["randomizer"].notebook,self.settings) self.pages["randomizer"].notebook.add(self.pages["randomizer"].pages["enemizer"], text="Enemizer") - # Dungeon Shuffle - self.pages["randomizer"].pages["dungeon"] = dungeon_page(self.pages["randomizer"].notebook) - self.pages["randomizer"].notebook.add(self.pages["randomizer"].pages["dungeon"], text="Dungeon Shuffle") - # Multiworld # self.pages["randomizer"].pages["multiworld"],self.settings = multiworld_page(self.pages["randomizer"].notebook,self.settings) # self.pages["randomizer"].notebook.add(self.pages["randomizer"].pages["multiworld"], text="Multiworld") diff --git a/Rom.py b/Rom.py index 388d28c8..b7285b2e 100644 --- a/Rom.py +++ b/Rom.py @@ -1303,7 +1303,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): rom.write_bytes(0x50563, [0x3F, 0x14]) # disable below ganon chest rom.write_byte(0x50599, 0x00) # disable below ganon chest rom.write_bytes(0xE9A5, [0x7E, 0x00, 0x24]) # disable below ganon chest - if world.open_pyramid[player] or (world.goal[player] in ['trinity', 'crystals'] and world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull']): + if world.is_pyramid_open(player): rom.initial_sram.pre_open_pyramid_hole() if world.crystals_needed_for_gt[player] == 0: rom.initial_sram.pre_open_ganons_tower() diff --git a/Rules.py b/Rules.py index a634d487..e1ee26cb 100644 --- a/Rules.py +++ b/Rules.py @@ -902,7 +902,7 @@ def ow_inverted_rules(world, player): set_rule(world.get_location('Frog', player), lambda state: state.can_lift_heavy_rocks(player) and (state.has_Pearl(player) or state.has('Beat Agahnim 1', player)) or (state.can_reach('Light World', 'Region', player) and state.has_Mirror(player))) # Need LW access using Mirror or Portal - set_rule(world.get_entrance('Inverted Pyramid Hole', player), lambda state: world.open_pyramid[player] or world.goal[player] == 'trinity' or state.has('Beat Agahnim 2', player)) + set_rule(world.get_entrance('Inverted Pyramid Hole', player), lambda state: world.is_pyramid_open(player) or state.has('Beat Agahnim 2', player)) def ow_bunny_rules(world, player): diff --git a/mystery_example.yml b/mystery_example.yml index 47d44e00..344875f4 100644 --- a/mystery_example.yml +++ b/mystery_example.yml @@ -70,6 +70,16 @@ full: 2 crossed: 3 insanity: 1 + open_pyramid: + auto: 1 + yes: 0 + no: 0 + shufflelinks: + on: 1 + off: 1 + shuffleganon: + on: 1 + off: 1 overworld_map: # control how the overworld map operates when entrance shuffle is on default: 1 compass: 10 diff --git a/resources/app/cli/args.json b/resources/app/cli/args.json index f85e51cd..5254a1c4 100644 --- a/resources/app/cli/args.json +++ b/resources/app/cli/args.json @@ -240,8 +240,11 @@ ] }, "openpyramid": { - "action": "store_true", - "type": "bool" + "choices": [ + "auto", + "yes", + "no" + ] }, "rom": {}, "loglevel": { diff --git a/resources/app/gui/custom/overview/widgets.json b/resources/app/gui/custom/overview/widgets.json index ee7be421..03c7fbaf 100644 --- a/resources/app/gui/custom/overview/widgets.json +++ b/resources/app/gui/custom/overview/widgets.json @@ -1,4 +1,22 @@ { + "startHeader": { + "usestartinventory": { + "type": "checkbox", + "config": { + "padx": [10,0], + "pady": [10,10] + } + } + }, + "customHeader": { + "usecustompool": { + "type": "checkbox", + "config": { + "padx": [10,0], + "pady": [10,10] + } + } + }, "itemList1": { "bow": { "type": "textbox", diff --git a/resources/app/gui/lang/en.json b/resources/app/gui/lang/en.json index b8166baa..0395b3bc 100644 --- a/resources/app/gui/lang/en.json +++ b/resources/app/gui/lang/en.json @@ -57,21 +57,7 @@ "randomizer.dungeon.smallkeyshuffle.wild": "Randomized", "randomizer.dungeon.smallkeyshuffle.universal": "Universal", "randomizer.dungeon.bigkeyshuffle": "Big Keys", - "randomizer.dungeon.keydropshuffle": "Key Drop Shuffle (Legacy)", "randomizer.dungeon.decoupledoors": "Decouple Doors", - "randomizer.dungeon.dropshuffle": "Shuffle Enemy Key Drops", - "randomizer.dungeon.potshuffle": "Pot Shuffle (Legacy)", - "randomizer.dungeon.pottery": "Pottery", - "randomizer.dungeon.pottery.none": "None", - "randomizer.dungeon.pottery.keys": "Key Pots", - "randomizer.dungeon.pottery.cave": "Cave Pots", - "randomizer.dungeon.pottery.cavekeys": "Cave+Key Pots", - "randomizer.dungeon.pottery.reduced": "Reduced Dungeon Pots (Dynamic)", - "randomizer.dungeon.pottery.clustered": "Clustered Dungeon Pots (Dynamic)", - "randomizer.dungeon.pottery.nonempty": "Excludes Empty Pots", - "randomizer.dungeon.pottery.dungeon": "Dungeon Pots", - "randomizer.dungeon.pottery.lottery": "Lottery (All Pots and Large Blocks)", - "randomizer.dungeon.colorizepots": "Colorize Randomized Pots", "randomizer.dungeon.dungeondoorshuffle": "Dungeon Door Shuffle", "randomizer.dungeon.dungeondoorshuffle.vanilla": "Vanilla", @@ -123,7 +109,7 @@ "randomizer.enemizer.enemyshuffle.none": "None", "randomizer.enemizer.enemyshuffle.shuffled": "Shuffled", "randomizer.enemizer.enemyshuffle.random": "Random", - "randomizer.enemizer.enemyshuffle.legacy": "Random (including Thieves)", + "randomizer.enemizer.enemyshuffle.legacy": "Random (50/50 Thieves)", "randomizer.enemizer.bossshuffle": "Boss Shuffle", "randomizer.enemizer.bossshuffle.none": "None", @@ -147,8 +133,10 @@ "randomizer.enemizer.enemizercli": "EnemizerCLI path: ", "randomizer.enemizer.enemizercli.online": "(get online)", - "randomizer.entrance.openpyramid": "Pre-open Pyramid Hole", + "randomizer.entrance.openpyramid.auto": "Auto", + "randomizer.entrance.openpyramid.yes": "Yes", + "randomizer.entrance.openpyramid.no": "No", "randomizer.entrance.shuffleganon": "Include Ganon's Tower and Pyramid Hole in shuffle pool", "randomizer.entrance.shufflelinks": "Include Link's House in the shuffle pool", "randomizer.entrance.shuffletavern": "Include the back of the tavern in the entrance shuffle pool", @@ -169,11 +157,6 @@ "randomizer.entrance.entranceshuffle.dungeonsfull": "Dungeons + Full", "randomizer.entrance.entranceshuffle.dungeonssimple": "Dungeons + Simple", - "randomizer.entrance.take_any": "Take Any Caves", - "randomizer.entrance.take_any.none": "None", - "randomizer.entrance.take_any.random": "Random", - "randomizer.entrance.take_any.fixed": "Fixed", - "randomizer.gameoptions.nobgm": "Disable Music & MSU-1", "randomizer.gameoptions.quickswap": "L/R Quickswapping", "randomizer.gameoptions.reduce_flashing": "Reduce Flashing", @@ -222,9 +205,6 @@ "randomizer.generation.createrom": "Create Patched ROM", "randomizer.generation.calcplaythrough": "Calculate Playthrough", "randomizer.generation.print_custom_yaml": "Print Customizer File", - "randomizer.generation.usestartinventory": "Use Starting Inventory", - "randomizer.generation.usecustompool": "Use Custom Item Pool", - "randomizer.generation.race": "Generate \"Race\" ROM", "randomizer.generation.saveonexit": "Save Settings on Exit", "randomizer.generation.saveonexit.ask": "Ask Me", @@ -236,10 +216,10 @@ "randomizer.generation.rom.dialog.romfiles": "Rom Files", "randomizer.generation.rom.dialog.allfiles": "All Files", - "randomizer.item.hints": "Include Helpful Hints", + "randomizer.item.hints": "Hints", + "randomizer.item.race": "Generate \"Race\" ROM", "randomizer.item.retro": "Retro mode", - "randomizer.item.pseudoboots": "Start with Pseudo Boots", - "randomizer.item.bombbag": "Bombbag", + "randomizer.item.pseudoboots": "Pseudoboots", "randomizer.item.worldstate": "World State", "randomizer.item.worldstate.standard": "Standard", @@ -291,20 +271,67 @@ "randomizer.item.weapons.swordless": "Swordless", "randomizer.item.weapons.vanilla": "Vanilla", - "randomizer.item.beemizer": "Beemizer", - "randomizer.item.beemizer.0": "No Bee Traps", - "randomizer.item.beemizer.1": "25% Bee Traps", - "randomizer.item.beemizer.2": "40% Traps, 20% Refills", - "randomizer.item.beemizer.3": "50% Traps, 50% Refills", - "randomizer.item.beemizer.4": "100% Bee Traps", + "randomizer.item.sortingalgo": "Item Fill", + "randomizer.item.sortingalgo.balanced": "Balanced", + "randomizer.item.sortingalgo.vanilla_fill": "Vanilla Fill", + "randomizer.item.sortingalgo.major_only": "Major Location Restriction", + "randomizer.item.sortingalgo.dungeon_only": "Dungeon Restriction", + "randomizer.item.sortingalgo.district": "District Restriction", + + "randomizer.item.accessibility": "Accessibility", + "randomizer.item.accessibility.items": "100% Inventory", + "randomizer.item.accessibility.locations": "100% Locations", + "randomizer.item.accessibility.none": "Beatable", + + "randomizer.item.restrict_boss_items": "Forbidden Boss Items", + "randomizer.item.restrict_boss_items.none": "None", + "randomizer.item.restrict_boss_items.mapcompass": "Map & Compass", + "randomizer.item.restrict_boss_items.dungeon": "Map & Compass & Keys", + + "randomizer.item.itemfunction": "Item Functionality", + "randomizer.item.itemfunction.normal": "Normal", + "randomizer.item.itemfunction.hard": "Hard", + "randomizer.item.itemfunction.expert": "Expert", + + "randomizer.item.timer": "Timer Setting", + "randomizer.item.timer.none": "No Timer", + "randomizer.item.timer.display": "Stopwatch", + "randomizer.item.timer.timed": "Timed", + "randomizer.item.timer.timed-ohko": "Timed OHKO", + "randomizer.item.timer.ohko": "OHKO", + "randomizer.item.timer.timed-countdown": "Timed Countdown", + + "randomizer.item.shopsanity": "Shopsanity", + + "randomizer.item.bonk_drops": "Bonk Drops", + + "randomizer.item.pottery": "Pottery", + "randomizer.item.pottery.none": "None", + "randomizer.item.pottery.keys": "Key Pots", + "randomizer.item.pottery.cave": "Cave Pots", + "randomizer.item.pottery.cavekeys": "Cave+Key Pots", + "randomizer.item.pottery.reduced": "Reduced Dungeon Pots (Dynamic)", + "randomizer.item.pottery.clustered": "Clustered Dungeon Pots (Dynamic)", + "randomizer.item.pottery.nonempty": "Excludes Empty Pots", + "randomizer.item.pottery.dungeon": "Dungeon Pots", + "randomizer.item.pottery.lottery": "Lottery (All Pots and Large Blocks)", + + "randomizer.item.colorizepots": "Colorize Randomized Pots", + "randomizer.item.potshuffle": "Pot Shuffle (Legacy)", + + "randomizer.item.dropshuffle": "Shuffle Enemy Key Drops", + "randomizer.item.keydropshuffle": "Key Drop Shuffle (Legacy)", + + "randomizer.item.take_any": "Take Any Caves", + "randomizer.item.take_any.none": "None", + "randomizer.item.take_any.random": "Random", + "randomizer.item.take_any.fixed": "Fixed", "randomizer.item.itempool": "Item Pool", "randomizer.item.itempool.normal": "Normal", "randomizer.item.itempool.hard": "Hard", "randomizer.item.itempool.expert": "Expert", - "randomizer.item.shopsanity": "Shopsanity", - "randomizer.item.flute_mode": "Flute Mode", "randomizer.item.flute_mode.normal": "Normal", "randomizer.item.flute_mode.active": "Pre-Activated", @@ -315,30 +342,17 @@ "randomizer.item.bow_mode.retro": "Retro (Progressive)", "randomizer.item.bow_mode.retro_silvers": "Retro + Silvers", - "randomizer.item.timer": "Timer Setting", - "randomizer.item.timer.none": "No Timer", - "randomizer.item.timer.display": "Stopwatch", - "randomizer.item.timer.timed": "Timed", - "randomizer.item.timer.timed-ohko": "Timed OHKO", - "randomizer.item.timer.ohko": "OHKO", - "randomizer.item.timer.timed-countdown": "Timed Countdown", + "randomizer.item.beemizer": "Beemizer", + "randomizer.item.beemizer.0": "No Bee Traps", + "randomizer.item.beemizer.1": "25% Bee Traps", + "randomizer.item.beemizer.2": "40% Traps, 20% Refills", + "randomizer.item.beemizer.3": "50% Traps, 50% Refills", + "randomizer.item.beemizer.4": "100% Bee Traps", - "randomizer.item.accessibility": "Accessibility", - "randomizer.item.accessibility.items": "100% Inventory", - "randomizer.item.accessibility.locations": "100% Locations", - "randomizer.item.accessibility.none": "Beatable", + "randomizer.item.bombbag": "Bombbag", - "randomizer.item.sortingalgo": "Item Sorting", - "randomizer.item.sortingalgo.balanced": "Balanced", - "randomizer.item.sortingalgo.vanilla_fill": "Vanilla Fill", - "randomizer.item.sortingalgo.major_only": "Major Location Restriction", - "randomizer.item.sortingalgo.dungeon_only": "Dungeon Restriction", - "randomizer.item.sortingalgo.district": "District Restriction", - - "randomizer.item.restrict_boss_items": "Forbidden Boss Items", - "randomizer.item.restrict_boss_items.none": "None", - "randomizer.item.restrict_boss_items.mapcompass": "Map & Compass", - "randomizer.item.restrict_boss_items.dungeon": "Map & Compass & Keys", + "startinventory.usestartinventory": "Use Starting Inventory", + "custom.usecustompool": "Use Custom Item Pool", "bottom.content.worlds": "Worlds", "bottom.content.names": "Player names", diff --git a/resources/app/gui/randomize/dungeon/keysanity.json b/resources/app/gui/randomize/dungeon/keysanity.json index ffd9bc92..ec3ae380 100644 --- a/resources/app/gui/randomize/dungeon/keysanity.json +++ b/resources/app/gui/randomize/dungeon/keysanity.json @@ -1,5 +1,13 @@ { "keysanity": { + "smallkeyshuffle": { + "type": "selectbox", + "options": [ + "none", + "wild", + "universal" + ] + }, "mapshuffle": { "type": "checkbox" }, "compassshuffle": { "type": "checkbox" }, "bigkeyshuffle": { "type": "checkbox" } diff --git a/resources/app/gui/randomize/dungeon/widgets.json b/resources/app/gui/randomize/dungeon/widgets.json index 9749486e..bcf7232a 100644 --- a/resources/app/gui/randomize/dungeon/widgets.json +++ b/resources/app/gui/randomize/dungeon/widgets.json @@ -1,12 +1,17 @@ { "widgets": { - "smallkeyshuffle": { + "key_logic_algorithm": { "type": "selectbox", + "default": "default", "options": [ - "none", - "wild", - "universal" - ] + "default", + "partial", + "strict" + ], + "config": { + "padx": [20,0], + "pady": [0,20] + } }, "dungeondoorshuffle": { "type": "selectbox", @@ -28,7 +33,8 @@ "random" ], "config": { - "width": 45 + "width": 45, + "padx": [20,0] } }, "door_type_mode": { @@ -41,7 +47,8 @@ "chaos" ], "config": { - "width": 45 + "width": 45, + "padx": [20,0] } }, "trap_door_mode": { @@ -54,41 +61,17 @@ "oneway" ], "config": { - "width": 30 + "width": 30, + "padx": [20,0] } }, - "key_logic_algorithm": { - "type": "selectbox", - "default": "default", - "options": [ - "default", - "partial", - "strict" - ] - }, - "decoupledoors": { "type": "checkbox" }, - "keydropshuffle": { "type": "checkbox" }, - "pottery": { - "type": "selectbox", - "default": "none", - "options": [ - "none", - "keys", - "cave", - "cavekeys", - "reduced", - "clustered", - "nonempty", - "dungeon", - "lottery" - ], + "decoupledoors": { + "type": "checkbox", "config": { - "width": 35 + "padx": [20,0], + "pady": [0,20] } }, - "colorizepots": { "type": "checkbox" }, - "dropshuffle": { "type": "checkbox" }, - "potshuffle": { "type": "checkbox" }, "experimental": { "type": "checkbox" }, "dungeon_counters": { "type": "selectbox", diff --git a/resources/app/gui/randomize/entrando/widgets.json b/resources/app/gui/randomize/entrando/widgets.json index a136de91..a3104bf1 100644 --- a/resources/app/gui/randomize/entrando/widgets.json +++ b/resources/app/gui/randomize/entrando/widgets.json @@ -1,24 +1,50 @@ { "widgets": { - "openpyramid": { "type": "checkbox" }, - "shuffleganon": { "type": "checkbox" }, "entranceshuffle": { "type": "selectbox", "options": [ "vanilla", - "lite", - "lean", "simple", "restricted", "full", + "lite", + "lean", "crossed", "insanity", "dungeonsfull", "dungeonssimple" ] }, - "shufflelinks": { "type": "checkbox" }, - "shuffletavern": { "type": "checkbox" }, + "shuffleganon": { + "type": "checkbox", + "config": { + "padx": [20,0] + } + }, + "shufflelinks": { + "type": "checkbox", + "config": { + "padx": [20,0] + } + }, + "shuffletavern": { + "type": "checkbox", + "config": { + "padx": [20,0] + } + }, + "openpyramid": { + "type": "selectbox", + "options": [ + "auto", + "yes", + "no" + ], + "config": { + "width": 6, + "pady": [20,0] + } + }, "overworld_map": { "type": "selectbox", "options": [ @@ -29,14 +55,6 @@ "config": { "width": 45 } - }, - "take_any": { - "type": "selectbox", - "options": [ - "none", - "random", - "fixed" - ] } } } diff --git a/resources/app/gui/randomize/generation/checkboxes.json b/resources/app/gui/randomize/generation/checkboxes.json index b1ee4c84..6e377027 100644 --- a/resources/app/gui/randomize/generation/checkboxes.json +++ b/resources/app/gui/randomize/generation/checkboxes.json @@ -4,9 +4,6 @@ "bps": { "type": "checkbox" }, "createspoiler": { "type": "checkbox" }, "calcplaythrough": { "type": "checkbox" }, - "print_custom_yaml": { "type": "checkbox" }, - "usestartinventory": { "type": "checkbox" }, - "usecustompool": { "type": "checkbox" }, - "race": { "type": "checkbox" } + "print_custom_yaml": { "type": "checkbox" } } } diff --git a/resources/app/gui/randomize/item/widgets.json b/resources/app/gui/randomize/item/widgets.json index 8e64f916..fad77e14 100644 --- a/resources/app/gui/randomize/item/widgets.json +++ b/resources/app/gui/randomize/item/widgets.json @@ -1,12 +1,8 @@ { "checkboxes": { - "retro": { "type": "checkbox" }, - "bombbag": { "type": "checkbox" }, - "shopsanity": { "type": "checkbox" }, - "hints": { - "type": "checkbox" - }, - "pseudoboots": { "type": "checkbox" } + "hints": { "type": "checkbox" }, + "pseudoboots": { "type": "checkbox" }, + "race": { "type": "checkbox" } }, "leftItemFrame": { "worldstate": { @@ -17,7 +13,10 @@ "open", "inverted", "retro" - ] + ], + "config": { + "command": "worldstate" + } }, "logiclevel": { "type": "selectbox", @@ -63,15 +62,112 @@ "swordless", "vanilla" ] - }, - "beemizer": { - "type": "selectbox", - "options": [ - "0", "1", "2", "3", "4" - ] } }, "rightItemFrame": { + "sortingalgo": { + "type": "selectbox", + "default": "balanced", + "options": [ + "balanced", + "vanilla_fill", + "major_only", + "dungeon_only", + "district" + ] + }, + "accessibility": { + "type": "selectbox", + "options": [ + "items", + "locations", + "none" + ] + }, + "restrict_boss_items": { + "type": "selectbox", + "default": "none", + "options": [ + "none", + "mapcompass", + "dungeon" + ] + }, + "itemfunction": { + "type": "selectbox", + "options": [ + "normal", + "hard", + "expert" + ] + }, + "timer": { + "type": "selectbox", + "options": [ + "none", + "display", + "timed", + "timed-ohko", + "ohko", + "timed-countdown" + ] + } + }, + "leftPoolHeader": { + "shopsanity": { + "type": "checkbox" + } + }, + "leftPoolFrame": { + "pottery": { + "type": "selectbox", + "default": "none", + "options": [ + "none", + "keys", + "cave", + "cavekeys", + "reduced", + "clustered", + "nonempty", + "dungeon", + "lottery" + ], + "config": { + "width": 35 + } + }, + "colorizepots": { + "type": "checkbox", + "config": { + "padx": [50,0] + } + }, + "potshuffle": { + "type": "checkbox", + "config": { + "padx": [50,0] + } + }, + "dropshuffle": { + "type": "checkbox" + }, + "keydropshuffle": { + "type": "checkbox", + "config": { + "command": "keydropshuffle" + } + }, + "take_any": { + "type": "selectbox", + "options": [ + "none", + "random", + "fixed" + ] + } + }, + "rightPoolFrame": { "itempool": { "type": "selectbox", "options": [ @@ -96,44 +192,17 @@ "retro_silvers" ] }, - "timer": { + "beemizer": { "type": "selectbox", "options": [ - "none", - "display", - "timed", - "timed-ohko", - "ohko", - "timed-countdown" + "0", "1", "2", "3", "4" ] }, - "accessibility": { - "type": "selectbox", - "options": [ - "items", - "locations", - "none" - ] - }, - "sortingalgo": { - "type": "selectbox", - "default": "balanced", - "options": [ - "balanced", - "vanilla_fill", - "major_only", - "dungeon_only", - "district" - ] - }, - "restrict_boss_items": { - "type": "selectbox", - "default": "none", - "options": [ - "none", - "mapcompass", - "dungeon" - ] + "bombbag": { + "type": "checkbox", + "config": { + "padx": [64,0] + } } } } diff --git a/source/classes/constants.py b/source/classes/constants.py index d6624d8f..3f0fb620 100644 --- a/source/classes/constants.py +++ b/source/classes/constants.py @@ -56,33 +56,59 @@ SETTINGSTOPROCESS = { "randomizer": { "item": { "hints": "hints", - "retro": "retro", - "bombbag": "bombbag", - "shopsanity": "shopsanity", "pseudoboots": "pseudoboots", + "race": "race", + "worldstate": "mode", "logiclevel": "logic", "goal": "goal", "crystals_gt": "crystals_gt", "crystals_ganon": "crystals_ganon", "weapons": "swords", + + "sortingalgo": "algorithm", + "accessibility": "accessibility", + "restrict_boss_items": "restrict_boss_items", + "itemfunction": "item_functionality", + "timer": "timer", + + "shopsanity": "shopsanity", + "pottery": "pottery", + "colorizepots": "colorizepots", + "potshuffle": "shufflepots", + "dropshuffle": "dropshuffle", + "keydropshuffle": "keydropshuffle", + "take_any": "take_any", + "itempool": "difficulty", "flute_mode": "flute_mode", "bow_mode": "bow_mode", - "timer": "timer", - "accessibility": "accessibility", - "sortingalgo": "algorithm", "beemizer": "beemizer", - "restrict_boss_items": "restrict_boss_items" + "bombbag": "bombbag" }, "entrance": { - "openpyramid": "openpyramid", + "entranceshuffle": "shuffle", "shuffleganon": "shuffleganon", "shufflelinks": "shufflelinks", "shuffletavern": "shuffletavern", - "entranceshuffle": "shuffle", + "openpyramid": "openpyramid", "overworld_map": "overworld_map", - "take_any": "take_any", + }, + "dungeon": { + "smallkeyshuffle": "keyshuffle", + "mapshuffle": "mapshuffle", + "compassshuffle": "compassshuffle", + "bigkeyshuffle": "bigkeyshuffle", + "key_logic_algorithm": "key_logic_algorithm", + "dungeondoorshuffle": "door_shuffle", + "dungeonintensity": "intensity", + "door_type_mode": "door_type_mode", + "trap_door_mode": "trap_door_mode", + "decoupledoors": "decoupledoors", + "experimental": "experimental", + "dungeon_counters": "dungeon_counters", + "mixed_travel": "mixed_travel", + "standardize_palettes": "standardize_palettes", }, "enemizer": { "enemyshuffle": "shuffleenemies", @@ -90,27 +116,6 @@ SETTINGSTOPROCESS = { "enemydamage": "enemy_damage", "enemyhealth": "enemy_health" }, - "dungeon": { - "mapshuffle": "mapshuffle", - "compassshuffle": "compassshuffle", - "smallkeyshuffle": "keyshuffle", - "bigkeyshuffle": "bigkeyshuffle", - "dungeondoorshuffle": "door_shuffle", - "dungeonintensity": "intensity", - "door_type_mode": "door_type_mode", - "trap_door_mode": "trap_door_mode", - "key_logic_algorithm": "key_logic_algorithm", - "decoupledoors": "decoupledoors", - "keydropshuffle": "keydropshuffle", - "dropshuffle": "dropshuffle", - "pottery": "pottery", - "colorizepots": "colorizepots", - "potshuffle": "shufflepots", - "experimental": "experimental", - "dungeon_counters": "dungeon_counters", - "mixed_travel": "mixed_travel", - "standardize_palettes": "standardize_palettes", - }, "gameoptions": { "nobgm": "disablemusic", "quickswap": "quickswap", @@ -130,12 +135,15 @@ SETTINGSTOPROCESS = { "createrom": "create_rom", "calcplaythrough": "calc_playthrough", "print_custom_yaml": "print_custom_yaml", - "usestartinventory": "usestartinventory", - "usecustompool": "custom", - "race": "race", "saveonexit": "saveonexit" } }, + "startinventory": { + "usestartinventory": "usestartinventory" + }, + "custom": { + "usecustompool": "custom" + }, "bottom": { "content": { "names": "names", diff --git a/source/gui/bottom.py b/source/gui/bottom.py index 27a22217..93976c75 100644 --- a/source/gui/bottom.py +++ b/source/gui/bottom.py @@ -203,13 +203,19 @@ def create_guiargs(parent): # Cycle through each page for mainpage in options: + subpage = None + _, v = next(iter(options[mainpage].items())) + if isinstance(v, str): + subpage = "" # Cycle through each subpage (in case of Item Randomizer) - for subpage in options[mainpage]: + for subpage in (options[mainpage] if subpage is None else [subpage]): # Cycle through each widget - for widget in options[mainpage][subpage]: + for widget in (options[mainpage][subpage] if subpage != "" else options[mainpage]): # Get the value and set it - arg = options[mainpage][subpage][widget] - setattr(guiargs, arg, parent.pages[mainpage].pages[subpage].widgets[widget].storageVar.get()) + arg = options[mainpage][subpage][widget] if subpage != "" else options[mainpage][widget] + page = parent.pages[mainpage].pages[subpage] if subpage != "" else parent.pages[mainpage] + pagewidgets = page.content.customWidgets if mainpage == "custom" else page.content.startingWidgets if mainpage == "startinventory" else page.widgets + setattr(guiargs, arg, pagewidgets[widget].storageVar.get()) # Get EnemizerCLI setting guiargs.enemizercli = parent.pages["randomizer"].pages["enemizer"].widgets["enemizercli"].storageVar.get() @@ -226,7 +232,7 @@ def create_guiargs(parent): guiargs.customizer = customizer_value # Get if we're using the Custom Item Pool - guiargs.custom = bool(parent.pages["randomizer"].pages["generation"].widgets["usecustompool"].storageVar.get()) + guiargs.custom = bool(parent.pages["custom"].content.customWidgets["usecustompool"].storageVar.get()) # Get Seed ID guiargs.seed = None @@ -285,7 +291,7 @@ def create_guiargs(parent): guiargs.dropshuffle = 1 guiargs.pottery = 'keys' if guiargs.pottery == 'none' else guiargs.pottery - if guiargs.retro or guiargs.mode == 'retro': + if (hasattr(guiargs, 'retro') and guiargs.retro) or guiargs.mode == 'retro': if guiargs.bow_mode == 'progressive': guiargs.bow_mode = 'retro' elif guiargs.bow_mode == 'silvers': diff --git a/source/gui/custom/overview.py b/source/gui/custom/overview.py index c51c35be..b62bff71 100644 --- a/source/gui/custom/overview.py +++ b/source/gui/custom/overview.py @@ -1,4 +1,4 @@ -from tkinter import ttk, Frame, N, E, W, LEFT, X, VERTICAL, Y +from tkinter import ttk, Frame, N, E, W, LEFT, TOP, X, VERTICAL, Y import source.gui.widgets as widgets import json import os @@ -11,10 +11,10 @@ def custom_page(top,parent): # Create uniform list columns def create_list_frame(parent, framename): - parent.frames[framename] = Frame(parent) - parent.frames[framename].pack(side=LEFT, padx=(0,0), anchor=N) - parent.frames[framename].thisRow = 0 - parent.frames[framename].thisCol = 0 + self.frames[framename] = Frame(parent) + self.frames[framename].pack(side=LEFT, padx=(0,0), anchor=N) + self.frames[framename].thisRow = 0 + self.frames[framename].thisCol = 0 # Create a vertical rule to help with splitting columns visually def create_vertical_rule(num=1): @@ -34,6 +34,8 @@ def custom_page(top,parent): # Custom Item Pool option sections self.frames = {} + self.frames["customHeader"] = Frame(self) + self.frames["customHeader"].pack(side=TOP, anchor=W) # Create 5 columns with 2 vertical rules in between each create_list_frame(self, "itemList1") create_vertical_rule(2) @@ -50,9 +52,14 @@ def custom_page(top,parent): with open(os.path.join("resources", "app", "gui", "custom", "overview", "widgets.json")) as widgetDefns: myDict = json.load(widgetDefns) for framename,theseWidgets in myDict.items(): - dictWidgets = widgets.make_widgets_from_dict(self, theseWidgets, self.frames[framename]) - for key in dictWidgets: - self.customWidgets[key] = dictWidgets[key] + if framename in self.frames: + dictWidgets = widgets.make_widgets_from_dict(self, theseWidgets, self.frames[framename]) + for key in dictWidgets: + self.customWidgets[key] = dictWidgets[key] + if framename == "customHeader": + packAttrs = {"anchor":W} + packAttrs = widgets.add_padding_from_config(packAttrs, theseWidgets[key]) + self.customWidgets[key].pack(packAttrs) # Load Custom Item Pool settings from settings file for key in CONST.CUSTOMITEMS: diff --git a/source/gui/loadcliargs.py b/source/gui/loadcliargs.py index 0130f8ad..6d358853 100644 --- a/source/gui/loadcliargs.py +++ b/source/gui/loadcliargs.py @@ -23,34 +23,41 @@ def loadcliargs(gui, args, settings=None): # Cycle through each page for mainpage in options: + subpage = None + _, v = next(iter(options[mainpage].items())) + if isinstance(v, str): + subpage = "" # Cycle through each subpage (in case of Item Randomizer) - for subpage in options[mainpage]: + for subpage in (options[mainpage] if subpage is None else [subpage]): # Cycle through each widget - for widget in options[mainpage][subpage]: - if widget in gui.pages[mainpage].pages[subpage].widgets: + for widget in (options[mainpage][subpage] if subpage != "" else options[mainpage]): + page = gui.pages[mainpage].pages[subpage] if subpage != "" else gui.pages[mainpage] + pagewidgets = page.content.customWidgets if mainpage == "custom" else page.content.startingWidgets if mainpage == "startinventory" else page.widgets + if widget in pagewidgets: thisType = "" # Get the value and set it - arg = options[mainpage][subpage][widget] + arg = options[mainpage][subpage][widget] if subpage != "" else options[mainpage][widget] if args[arg] == None: args[arg] = "" - label = fish.translate("gui","gui",mainpage + '.' + subpage + '.' + widget) - if hasattr(gui.pages[mainpage].pages[subpage].widgets[widget],"type"): - thisType = gui.pages[mainpage].pages[subpage].widgets[widget].type + label_ref = mainpage + ('.' + subpage if subpage != "" else '') + '.' + widget + label = fish.translate("gui","gui", label_ref) + if hasattr(pagewidgets[widget],"type"): + thisType = pagewidgets[widget].type if thisType == "checkbox": - gui.pages[mainpage].pages[subpage].widgets[widget].checkbox.configure(text=label) + pagewidgets[widget].checkbox.configure(text=label) elif thisType == "selectbox": - theseOptions = gui.pages[mainpage].pages[subpage].widgets[widget].selectbox.options - gui.pages[mainpage].pages[subpage].widgets[widget].label.configure(text=label) + theseOptions = pagewidgets[widget].selectbox.options + pagewidgets[widget].label.configure(text=label) i = 0 for value in theseOptions["values"]: - gui.pages[mainpage].pages[subpage].widgets[widget].selectbox.options["labels"][i] = fish.translate("gui","gui",mainpage + '.' + subpage + '.' + widget + '.' + str(value)) + pagewidgets[widget].selectbox.options["labels"][i] = fish.translate("gui","gui", label_ref + '.' + str(value)) i += 1 for i in range(0, len(theseOptions["values"])): - gui.pages[mainpage].pages[subpage].widgets[widget].selectbox["menu"].entryconfigure(i, label=theseOptions["labels"][i]) - gui.pages[mainpage].pages[subpage].widgets[widget].selectbox.options = theseOptions + pagewidgets[widget].selectbox["menu"].entryconfigure(i, label=theseOptions["labels"][i]) + pagewidgets[widget].selectbox.options = theseOptions elif thisType == "spinbox": - gui.pages[mainpage].pages[subpage].widgets[widget].label.configure(text=label) - gui.pages[mainpage].pages[subpage].widgets[widget].storageVar.set(args[arg]) + pagewidgets[widget].label.configure(text=label) + pagewidgets[widget].storageVar.set(args[arg]) # If we're on the Game Options page and it's not about Hints if subpage == "gameoptions" and widget not in ["hints", "collection_rate"]: # Check if we've got settings diff --git a/source/gui/randomize/dungeon.py b/source/gui/randomize/dungeon.py index 01985982..7400dbe4 100644 --- a/source/gui/randomize/dungeon.py +++ b/source/gui/randomize/dungeon.py @@ -1,4 +1,4 @@ -from tkinter import ttk, Frame, Label, E, W, LEFT, RIGHT +from tkinter import ttk, Frame, Label, E, W, LEFT, RIGHT, TOP import source.gui.widgets as widgets import json import os @@ -16,8 +16,8 @@ def dungeon_page(parent): self.frames["keysanity"].pack(anchor=W) ## Dungeon Item Shuffle - mscbLabel = Label(self.frames["keysanity"], text="Shuffle: ") - mscbLabel.pack(side=LEFT) + mscbLabel = Label(self.frames["keysanity"], text="Dungeon Items: ") + mscbLabel.pack(side=TOP, anchor=W) # Load Dungeon Shuffle option widgets as defined by JSON file # Defns include frame name, widget type, widget options, widget placement attributes @@ -28,7 +28,9 @@ def dungeon_page(parent): dictWidgets = widgets.make_widgets_from_dict(self, myDict, self.frames["keysanity"]) for key in dictWidgets: self.widgets[key] = dictWidgets[key] - self.widgets[key].pack(side=LEFT) + packAttrs = {"side":LEFT} + packAttrs = widgets.add_padding_from_config(packAttrs, myDict[key]) + self.widgets[key].pack(packAttrs) # These get split left & right self.frames["widgets"] = Frame(self) @@ -39,6 +41,8 @@ def dungeon_page(parent): dictWidgets = widgets.make_widgets_from_dict(self, myDict, self.frames["widgets"]) for key in dictWidgets: self.widgets[key] = dictWidgets[key] - self.widgets[key].pack(anchor=W) + packAttrs = {"anchor":W} + packAttrs = widgets.add_padding_from_config(packAttrs, myDict[key]) + self.widgets[key].pack(packAttrs) return self diff --git a/source/gui/randomize/entrando.py b/source/gui/randomize/entrando.py index 0759218c..ba2bc365 100644 --- a/source/gui/randomize/entrando.py +++ b/source/gui/randomize/entrando.py @@ -26,9 +26,8 @@ def entrando_page(parent): dictWidgets = widgets.make_widgets_from_dict(self, theseWidgets, self.frames[framename]) for key in dictWidgets: self.widgets[key] = dictWidgets[key] - packAttrs = {"anchor":E} - if self.widgets[key].type == "checkbox": - packAttrs["anchor"] = W + packAttrs = {"anchor":W} + packAttrs = widgets.add_padding_from_config(packAttrs, theseWidgets[key]) self.widgets[key].pack(packAttrs) return self diff --git a/source/gui/randomize/item.py b/source/gui/randomize/item.py index 81c957ce..6898c75f 100644 --- a/source/gui/randomize/item.py +++ b/source/gui/randomize/item.py @@ -1,4 +1,4 @@ -from tkinter import ttk, Frame, E, W, LEFT, RIGHT, Label +from tkinter import ttk, font, Frame, E, W, NW, TOP, LEFT, RIGHT, Y, Label import source.gui.widgets as widgets import json import os @@ -17,13 +17,39 @@ def item_page(parent): self.frames["checkboxes"] = Frame(self) self.frames["checkboxes"].pack(anchor=W) - various_options = Label(self.frames["checkboxes"], text="") + various_options = Label(self.frames["checkboxes"], text="Options: ") various_options.pack(side=LEFT) - self.frames["leftItemFrame"] = Frame(self) - self.frames["rightItemFrame"] = Frame(self) + self.frames["mainFrame"] = Frame(self) + self.frames["mainFrame"].pack(side=TOP, pady=(20,0)) + + self.frames["poolFrame"] = Frame(self) + self.frames["poolFrame"].pack(fill=Y) + + self.frames["leftItemFrame"] = Frame(self.frames["mainFrame"]) self.frames["leftItemFrame"].pack(side=LEFT) + self.frames["rightItemFrame"] = Frame(self.frames["mainFrame"]) self.frames["rightItemFrame"].pack(side=RIGHT) + + self.frames["leftPoolContainer"] = Frame(self.frames["poolFrame"]) + self.frames["leftPoolContainer"].pack(side=LEFT, padx=(0,20)) + + base_font = font.nametofont('TkTextFont').actual() + underline_font = f'"{base_font["family"]}" {base_font["size"]} underline' + various_options = Label(self.frames["leftPoolContainer"], text="Pool Expansions", font=underline_font) + various_options.pack(side=TOP, pady=(20,0)) + + self.frames["leftPoolHeader"] = Frame(self.frames["leftPoolContainer"]) + self.frames["leftPoolHeader"].pack(side=TOP, anchor=W) + + self.frames["leftPoolFrame"] = Frame(self.frames["leftPoolContainer"]) + self.frames["leftPoolFrame"].pack(side=LEFT, fill=Y) + + self.frames["rightPoolFrame"] = Frame(self.frames["poolFrame"]) + self.frames["rightPoolFrame"].pack(side=RIGHT) + + various_options = Label(self.frames["rightPoolFrame"], text="Pool Modifications", font=underline_font) + various_options.pack(side=TOP, pady=(20,0)) # Load Item Randomizer option widgets as defined by JSON file # Defns include frame name, widget type, widget options, widget placement attributes @@ -36,8 +62,15 @@ def item_page(parent): for key in dictWidgets: self.widgets[key] = dictWidgets[key] packAttrs = {"anchor":E} - if self.widgets[key].type == "checkbox": + if self.widgets[key].type == "checkbox" or framename == "leftPoolFrame": + packAttrs["anchor"] = W + if framename == "checkboxes": packAttrs["side"] = LEFT + packAttrs["padx"] = (10,0) + elif framename == "leftPoolHeader": + packAttrs["side"] = LEFT + packAttrs["padx"] = (0,20) + packAttrs = widgets.add_padding_from_config(packAttrs, theseWidgets[key]) self.widgets[key].pack(packAttrs) return self diff --git a/source/gui/startinventory/overview.py b/source/gui/startinventory/overview.py index fce40e5f..97784521 100644 --- a/source/gui/startinventory/overview.py +++ b/source/gui/startinventory/overview.py @@ -1,4 +1,4 @@ -from tkinter import ttk, Frame, N, E, W, LEFT, X, VERTICAL, Y +from tkinter import ttk, Frame, N, E, W, LEFT, TOP, X, VERTICAL, Y import source.gui.widgets as widgets import json import os @@ -11,10 +11,10 @@ def startinventory_page(top,parent): # Create uniform list columns def create_list_frame(parent, framename): - parent.frames[framename] = Frame(parent) - parent.frames[framename].pack(side=LEFT, padx=(0,0), anchor=N) - parent.frames[framename].thisRow = 0 - parent.frames[framename].thisCol = 0 + self.frames[framename] = Frame(parent) + self.frames[framename].pack(side=LEFT, padx=(0,0), anchor=N) + self.frames[framename].thisRow = 0 + self.frames[framename].thisCol = 0 # Create a vertical rule to help with splitting columns visually def create_vertical_rule(num=1): @@ -34,6 +34,8 @@ def startinventory_page(top,parent): # Starting Inventory option sections self.frames = {} + self.frames["startHeader"] = Frame(self) + self.frames["startHeader"].pack(side=TOP, anchor=W) # Create 5 columns with 2 vertical rules in between each create_list_frame(self,"itemList1") create_vertical_rule(2) @@ -55,9 +57,14 @@ def startinventory_page(top,parent): if key in myDict[thisList]: del myDict[thisList][key] for framename,theseWidgets in myDict.items(): - dictWidgets = widgets.make_widgets_from_dict(self, theseWidgets, self.frames[framename]) - for key in dictWidgets: - self.startingWidgets[key] = dictWidgets[key] + if framename in self.frames: + dictWidgets = widgets.make_widgets_from_dict(self, theseWidgets, self.frames[framename]) + for key in dictWidgets: + self.startingWidgets[key] = dictWidgets[key] + if framename == "startHeader": + packAttrs = {"anchor":W} + packAttrs = widgets.add_padding_from_config(packAttrs, theseWidgets[key]) + self.startingWidgets[key].pack(packAttrs) # Load Custom Starting Inventory settings from settings file, ignoring ones to be excluded for key in CONST.CUSTOMITEMS: diff --git a/source/gui/widgets.py b/source/gui/widgets.py index aedb573d..0198a43a 100644 --- a/source/gui/widgets.py +++ b/source/gui/widgets.py @@ -1,4 +1,4 @@ -from tkinter import Checkbutton, Entry, Frame, IntVar, Label, OptionMenu, Spinbox, StringVar, LEFT, RIGHT, X +from tkinter import messagebox, Checkbutton, Entry, Frame, IntVar, Label, OptionMenu, Spinbox, StringVar, LEFT, RIGHT, X from source.classes.Empty import Empty # Override Spinbox to include mousewheel support for changing value @@ -16,7 +16,7 @@ class mySpinbox(Spinbox): self.invoke('buttonup') # Make a Checkbutton with a label -def make_checkbox(self, parent, label, storageVar, manager, managerAttrs): +def make_checkbox(self, parent, label, storageVar, manager, managerAttrs, config): self = Frame(parent) self.storageVar = storageVar if managerAttrs is not None and "default" in managerAttrs: @@ -25,7 +25,10 @@ def make_checkbox(self, parent, label, storageVar, manager, managerAttrs): elif managerAttrs["default"] == "false" or managerAttrs["default"] == False: self.storageVar.set(False) del managerAttrs["default"] - self.checkbox = Checkbutton(self, text=label, variable=self.storageVar) + options = {"text":label, "variable":self.storageVar} + if config and "command" in config: + options.update({"command":lambda m=config["command"]: widget_command(self, m)}) + self.checkbox = Checkbutton(self, options) if managerAttrs is not None: self.checkbox.pack(managerAttrs) else: @@ -43,7 +46,11 @@ def make_selectbox(self, parent, label, options, storageVar, manager, managerAtt self.labelVar = StringVar() self.storageVar = storageVar - self.selectbox = OptionMenu(self, self.labelVar, *labels) + if config and "command" in config: + self.command = config["command"] + self.selectbox = OptionMenu(self, self.labelVar, *labels, command=lambda m: widget_command(self, self.command)) + else: + self.selectbox = OptionMenu(self, self.labelVar, *labels) self.selectbox.options = {} if isinstance(options,dict): @@ -96,7 +103,7 @@ def make_selectbox(self, parent, label, options, storageVar, manager, managerAtt else: self.label.pack(side=LEFT) - self.selectbox.config(width=config['width'] if config and config['width'] else 20) + self.selectbox.config(width=config['width'] if config and 'width' in config else 20) idx = 0 default = self.selectbox.options["values"][idx] if managerAttrs is not None and "default" in managerAttrs: @@ -181,7 +188,7 @@ def make_widget(self, type, parent, label, storageVar=None, manager=None, manage if type == "checkbox": if thisStorageVar is None: thisStorageVar = IntVar() - widget = make_checkbox(self, parent, label, thisStorageVar, manager, managerAttrs) + widget = make_checkbox(self, parent, label, thisStorageVar, manager, managerAttrs, config) elif type == "selectbox": if thisStorageVar is None: thisStorageVar = StringVar() @@ -221,3 +228,51 @@ def make_widgets_from_dict(self, defns, parent): for key,defn in defns.items(): widgets[key] = make_widget_from_dict(self, defn, parent) return widgets + +# Add padding to widget +def add_padding_from_config(packAttrs, defn): + if "config" in defn: + config = defn["config"] + if 'padx' in config: + packAttrs["padx"] = config['padx'] + if 'pady' in config: + packAttrs["pady"] = config['pady'] + return packAttrs + +# Callback when a widget issues a command +def widget_command(widget, command=""): + root = widget.winfo_toplevel() + text_output = "" + if command == "worldstate": + if widget.storageVar.get() == 'retro': + temp_widget = root.pages["randomizer"].pages["dungeon"].widgets["smallkeyshuffle"] + text_output += f'\n {temp_widget.label.cget("text")}' + temp_widget.storageVar.set('universal') + + temp_widget = root.pages["randomizer"].pages["item"].widgets["bow_mode"] + text_output += f'\n {temp_widget.label.cget("text")}' + if temp_widget.storageVar.get() == 'progressive': + temp_widget.storageVar.set('retro') + elif temp_widget.storageVar.get() == 'silvers': + temp_widget.storageVar.set('retro_silvers') + + temp_widget = root.pages["randomizer"].pages["item"].widgets["take_any"] + text_output += f'\n {temp_widget.label.cget("text")}' + if temp_widget.storageVar.get() == 'none': + temp_widget.storageVar.set('random') + + widget.storageVar.set('open') + messagebox.showinfo('', f'The following settings were changed:{text_output}') + elif command == "keydropshuffle": + if widget.storageVar.get() > 0: + temp_widget = root.pages["randomizer"].pages["item"].widgets["pottery"] + text_output += f'\n {temp_widget.label.cget("text")}' + if temp_widget.storageVar.get() == 'none': + temp_widget.storageVar.set('keys') + + temp_widget = root.pages["randomizer"].pages["item"].widgets["dropshuffle"] + temp_widget.storageVar.set(1) + text_output += f'\n {temp_widget.checkbox.cget("text")}' + + widget.storageVar.set(0) + messagebox.showinfo('', f'The following settings were changed:{text_output}') diff --git a/source/tools/MysteryUtils.py b/source/tools/MysteryUtils.py index 2bdcdcd7..8f371b6c 100644 --- a/source/tools/MysteryUtils.py +++ b/source/tools/MysteryUtils.py @@ -119,7 +119,7 @@ def roll_settings(weights): 'ganonhunt': 'ganonhunt', 'completionist': 'completionist' }[goal] - ret.openpyramid = goal in ['fast_ganon', 'trinity'] if ret.shuffle in ['vanilla', 'dungeonsfull', 'dungeonssimple'] else False + ret.openpyramid = get_choice('open_pyramid') if 'open_pyramid' in weights else 'auto' ret.crystals_gt = get_choice('tower_open') From 1bf95fe2d77fe55906d0f16e9d78f9f5ede4c118 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 5 Apr 2023 08:31:39 -0500 Subject: [PATCH 095/196] Symmetrical GTCutscene Crystals --- Rom.py | 2 +- data/base2current.bps | Bin 105987 -> 106066 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Rom.py b/Rom.py index c164e845..832bbacf 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '92c16c60f26218c9aec838ce204c0b1e' +RANDOMIZERBASEHASH = '9f8084cde45565b76db290f4a38cbffa' class JsonRom(object): diff --git a/data/base2current.bps b/data/base2current.bps index 6efe11ee423d08175e56237349ff9b06c40a44eb..eaed4faa1ced33c2c8c1964039efbe3256c2e715 100644 GIT binary patch delta 6650 zcmX9?30xD$_s?uX2zP?WsS?%;JP=P16;V7;Q9;oPM#TdS##?I<`-9zJlt7jw4lu%s z31JZvrK`OtLCs?O^M&Eo!bK@ySF_Ws!pye0^vU#gG9nvA&Uf#c&;x)3nWKKH#Cf&jsT*V{~vj=p!oe-S!&h zfNZb{UIo)7@&}xRDkpz}eTWc0zJ}{)Wynn~F0xqb^AJuW`g;^XF7CO69QzP%Bi8pc z>bN$Byg*s@F=PQU_uExYMz+B}h_S@9r*OD13|Qc7;b(&<-{)??9xd9A6Xuvw?LWs3 z^(tb>utxJLjdt!{t{-hA+mX2=RnL&$!mGl?KnDklV!=tcQnWz2{XX|nLw@loffA{; zWNaI35z+A)BezLIi<%g+>6Q6gBRRFQzN6Qic5jy$~{g{$dC%SP;yUN=HjO8q3hXHf|l#G zNsr)Uk0!|y$SH8#zJp>qGp>}|&yZ=QTsmhY7t-dA7Ng=a{KtDf5&8no^BF$2hV;_?8#hBbc4*5hvv*;+ zLiHMp0!}bwnbxK#p#Jmrl@mUyt{VAs?VaS6Iy0cs&VW*1>n`nCQ z(Mqz^$dRQm#y8O8tdaA^Mi09I=lTW()Ix3(WmIHoZ5@e4)#UfAndIzwzD)$q_E=f? zocWN;#j$^WoeM6cRikKalBs*T78<#iT5|sWTG?mXQ55ep#}GhOlg~{5n!Zm<`k7fl z1lwvGSv42nvHwvfh@3^z>%yF2xMcC*id%2EWyiERQ=A1adc8mXf z0{8w$Ky=uOQZA9EDV%kQjpnTH8V6}a6fOFWAqSMgi9Iukq*BQCY#ydj9tk6}sRM9H%koCN33*YH|ko!Y4{qF=CT`md^uu~qa-+sOYujHEsR3d*Q``aU$2(cLVZictGf zGiSqXiAzB(yq=g#1nBIuC#4Gmceiu;d&Uh;ck+8wT)q)=(Icp{pO~@^fN$-6r>zzB zjBVqrfO$@kR~~RYq+?uet`{(wsn>DF##9*miu`WY6?0*lqhVMjIBd8cx)xzHNF^9V=jQsNfr?QUJw4n6`8m$+v zLNhn-sM$`*!Ox0T5~F{IO+^qW?5W!8z8+7Wa^#tx&Ey^X zkbNg3J4;^CZ$Vp07_df6%aZu>%5$2dkoYcZZm#a<=?aX#Kh*iclo7MjIDWH3D-6AlJxH`gLj?GB~nCRktl*N8Lmhgy2LK& z{w{IthBV#HD9R=I%Iue^K=|c}D-xH8%(yDi!^=*Q;=W+G9W|=X#rkl=I-COG}BUFnID(VaSv|f57aWC2;A^5;_^4DHkcN zcnVQkDop=T@7qg=_6Dt_wFTR0cI;62`o}TE_GlRO(+ncY0Jr_rKQKVApGMKqP)*Om zlnd3?I(^D1c=V@8VrwG2`%~naz@$CrqW)6xrBn=dO_P>LI%pLu&*-2%pc+n% z*Oi7&piGP6Vb0}9@mAlrCT~B8F8Ar}Y2g pK0jYL4_Nt0%8th?ZfT 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�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 aF&T!f3)^}>0IGMSBmaEh^kC(PGyeysJc=p+ From 50f92e7aeeebdae9551afba31d4065c5fa2b5d97 Mon Sep 17 00:00:00 2001 From: aerinon Date: Wed, 5 Apr 2023 15:55:30 -0600 Subject: [PATCH 096/196] Release notes and minor cleanup --- BaseClasses.py | 2 +- Main.py | 2 +- RELEASENOTES.md | 9 +++++++++ source/gui/widgets.py | 23 +++++++++++++++++------ source/overworld/EntranceShuffle2.py | 10 ++++++---- 5 files changed, 34 insertions(+), 12 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index d34e0b67..a7170779 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -3010,7 +3010,7 @@ class Settings(object): | (counter_mode[w.dungeon_counters[p]] << 1) | (1 if w.experimental[p] else 0), ((8 if w.crystals_ganon_orig[p] == "random" else int(w.crystals_ganon_orig[p])) << 3) - | (0x4 if w.is_pyramid_open[p] else 0) | access_mode[w.accessibility[p]], + | (0x4 if w.is_pyramid_open(p) else 0) | access_mode[w.accessibility[p]], (0x80 if w.bigkeyshuffle[p] else 0) | (0x20 if w.mapshuffle[p] else 0) | (0x10 if w.compassshuffle[p] else 0) diff --git a/Main.py b/Main.py index fa6b7a2f..2894194e 100644 --- a/Main.py +++ b/Main.py @@ -34,7 +34,7 @@ from source.overworld.EntranceShuffle2 import link_entrances_new from source.tools.BPS import create_bps_from_data from source.classes.CustomSettings import CustomSettings -version_number = '1.2.0.13' +version_number = '1.2.0.14' version_branch = '-u' __version__ = f'{version_number}{version_branch}' diff --git a/RELEASENOTES.md b/RELEASENOTES.md index e2c23a11..e91b6ef4 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -109,6 +109,15 @@ These are now independent of retro mode and have three options: None, Random, an # Bug Fixes and Notes +* 1.2.0.14u + * GUI reorganization + * Auto option for pyramid open (trinity or ER + crystals goal) + * World model refactor (combining inverted and normal world models) + * Partitioned fix for lamp logic and links house + * Fix starting flute logic + * Reduced universal keys in pool slightly for non-vanilla dungeons + * Fake world fix finally + * Some extra restrictions on links house placement for lite/lean * 1.2.0.13u * Allow green/blue potion refills to be customized * OW Map showing dungeon entrance at Snitch Lady (West) fixed (instead of @ HC Courtyard) diff --git a/source/gui/widgets.py b/source/gui/widgets.py index 0198a43a..4723a526 100644 --- a/source/gui/widgets.py +++ b/source/gui/widgets.py @@ -266,13 +266,24 @@ def widget_command(widget, command=""): elif command == "keydropshuffle": if widget.storageVar.get() > 0: temp_widget = root.pages["randomizer"].pages["item"].widgets["pottery"] - text_output += f'\n {temp_widget.label.cget("text")}' if temp_widget.storageVar.get() == 'none': + text_output += f'\n {temp_widget.label.cget("text")}' temp_widget.storageVar.set('keys') temp_widget = root.pages["randomizer"].pages["item"].widgets["dropshuffle"] - temp_widget.storageVar.set(1) - text_output += f'\n {temp_widget.checkbox.cget("text")}' - - widget.storageVar.set(0) - messagebox.showinfo('', f'The following settings were changed:{text_output}') + if temp_widget.storageVar.get() == 0: + temp_widget.storageVar.set(1) + text_output += f'\n {temp_widget.checkbox.cget("text")}' + if text_output: + messagebox.showinfo('', f'The following settings were changed:{text_output}') + else: + temp_widget = root.pages["randomizer"].pages["item"].widgets["pottery"] + if temp_widget.storageVar.get() == 'keys': + text_output += f'\n {temp_widget.label.cget("text")}' + temp_widget.storageVar.set('none') + temp_widget = root.pages["randomizer"].pages["item"].widgets["dropshuffle"] + if temp_widget.storageVar.get() == 1: + temp_widget.storageVar.set(0) + text_output += f'\n {temp_widget.checkbox.cget("text")}' + if text_output: + messagebox.showinfo('', f'The following settings were changed:{text_output}') diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index f696df01..77790bda 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -425,10 +425,11 @@ def do_links_house(entrances, exits, avail, cross_world): if not avail.world.shufflelinks[avail.player]: links_house = 'Big Bomb Shop' if avail.inverted else 'Links House' else: - forbidden = list(Isolated_LH_Doors_Inv + Inverted_Dark_Sanctuary_Doors + forbidden = list((Isolated_LH_Doors_Inv + Inverted_Dark_Sanctuary_Doors) if avail.inverted else Isolated_LH_Doors_Open) + shuffle_mode = avail.world.shuffle[avail.player] # simple shuffle - - if avail.world.shuffle[avail.player] == 'simple': + if shuffle_mode == 'simple': avail.links_on_mountain = True # taken care of by the logic below if avail.inverted: # in inverted, links house cannot be on the mountain forbidden.extend(['Spike Cave', 'Dark Death Mountain Fairy', 'Hookshot Fairy']) @@ -441,10 +442,11 @@ def do_links_house(entrances, exits, avail, cross_world): # can't have links house on eddm in restricted because Inverted Aga Tower isn't available # todo: inverted full may have the same problem if both links house and a mandatory connector is chosen # from the 3 inverted options - if avail.world.shuffle[avail.player] in ['restricted'] and avail.inverted: + if shuffle_mode in ['restricted'] and avail.inverted: avail.links_on_mountain = True forbidden.extend(['Spike Cave', 'Dark Death Mountain Fairy']) - + if shuffle_mode in ['lite', 'lean']: + forbidden.extend(['Spike Cave', 'Mire Shed']) # lobby shuffle means you ought to keep links house in the same world sanc_spawn_can_be_dark = (not avail.inverted and avail.world.doorShuffle[avail.player] in ['partitioned', 'crossed'] and avail.world.intensity[avail.player] >= 3) From abb11558d8a39029256ecd3d4c638f06938e00b3 Mon Sep 17 00:00:00 2001 From: aerinon Date: Wed, 5 Apr 2023 15:58:16 -0600 Subject: [PATCH 097/196] Correct version bump --- Main.py | 2 +- RELEASENOTES.md | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Main.py b/Main.py index 2894194e..8f97ef46 100644 --- a/Main.py +++ b/Main.py @@ -34,7 +34,7 @@ from source.overworld.EntranceShuffle2 import link_entrances_new from source.tools.BPS import create_bps_from_data from source.classes.CustomSettings import CustomSettings -version_number = '1.2.0.14' +version_number = '1.2.0.15' version_branch = '-u' __version__ = f'{version_number}{version_branch}' diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 8ee37b73..730f7bda 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -109,9 +109,7 @@ These are now independent of retro mode and have three options: None, Random, an # Bug Fixes and Notes -* 1.2.0.14u - * Small fix for key logic validation (got rid of a false negative) - * Customized doors in ice cross work properly now +* 1.2.0.15u * GUI reorganization * Auto option for pyramid open (trinity or ER + crystals goal) * World model refactor (combining inverted and normal world models) @@ -120,6 +118,9 @@ These are now independent of retro mode and have three options: None, Random, an * Reduced universal keys in pool slightly for non-vanilla dungeons * Fake world fix finally * Some extra restrictions on links house placement for lite/lean +* 1.2.0.14u + * Small fix for key logic validation (got rid of a false negative) + * Customized doors in ice cross work properly now * 1.2.0.13u * Allow green/blue potion refills to be customized * OW Map showing dungeon entrance at Snitch Lady (West) fixed (instead of @ HC Courtyard) From 3c18dc6e3a4bb9d8e795d6808045ac48d65ec0aa Mon Sep 17 00:00:00 2001 From: aerinon Date: Thu, 6 Apr 2023 11:22:12 -0600 Subject: [PATCH 098/196] Re-vamp multiple settings as buttons. Minor logic clean up. --- DoorShuffle.py | 2 +- Rules.py | 1 - resources/app/gui/lang/en.json | 3 +- resources/app/gui/randomize/item/widgets.json | 30 ++++--- source/classes/constants.py | 1 + source/gui/loadcliargs.py | 5 +- source/gui/randomize/item.py | 13 ++- source/gui/widgets.py | 87 ++++++++++--------- 8 files changed, 85 insertions(+), 57 deletions(-) diff --git a/DoorShuffle.py b/DoorShuffle.py index a0a6a8f8..407509c8 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -3295,7 +3295,7 @@ def find_inaccessible_regions(world, player): while len(queue) > 0: next_region = queue.popleft() visited_regions.add(next_region) - if next_region.name == 'Dark Sanctuary Hint': # special spawn point in cave + if world.mode[player] == 'inverted' and next_region.name == 'Dark Sanctuary Hint': # special spawn point in cave for ent in next_region.entrances: parent = ent.parent_region if parent and parent.type is not RegionType.Dungeon and parent not in queue and parent not in visited_regions: diff --git a/Rules.py b/Rules.py index e1ee26cb..a1c795a3 100644 --- a/Rules.py +++ b/Rules.py @@ -192,7 +192,6 @@ def global_rules(world, player): set_rule(world.get_location('Purple Chest', player), lambda state: state.has('Pick Up Purple Chest', player)) # Can S&Q with chest # underworld rules - set_rule(world.get_entrance('Old Man Cave Exit (West)', player), lambda state: False) # drop cannot be climbed up set_rule(world.get_location('Mimic Cave', player), lambda state: state.has('Hammer', player)) set_rule(world.get_entrance('Paradox Cave Push Block Reverse', player), lambda state: state.has_Mirror(player)) # can erase block - overridden in noglitches set_rule(world.get_location('Potion Shop', player), lambda state: state.has('Mushroom', player) and state.can_reach('Potion Shop Area', 'Region', player)) diff --git a/resources/app/gui/lang/en.json b/resources/app/gui/lang/en.json index 0395b3bc..eb53f640 100644 --- a/resources/app/gui/lang/en.json +++ b/resources/app/gui/lang/en.json @@ -226,6 +226,7 @@ "randomizer.item.worldstate.open": "Open", "randomizer.item.worldstate.inverted": "Inverted", "randomizer.item.worldstate.retro": "Retro", + "randomizer.item.retro": "Enable Retro", "randomizer.item.logiclevel": "Logic Level", "randomizer.item.logiclevel.noglitches": "No Glitches", @@ -320,7 +321,7 @@ "randomizer.item.potshuffle": "Pot Shuffle (Legacy)", "randomizer.item.dropshuffle": "Shuffle Enemy Key Drops", - "randomizer.item.keydropshuffle": "Key Drop Shuffle (Legacy)", + "randomizer.item.keydropshuffle": "Enable Key Drop Shuffle (Legacy)", "randomizer.item.take_any": "Take Any Caves", "randomizer.item.take_any.none": "None", diff --git a/resources/app/gui/randomize/item/widgets.json b/resources/app/gui/randomize/item/widgets.json index fad77e14..9857c45e 100644 --- a/resources/app/gui/randomize/item/widgets.json +++ b/resources/app/gui/randomize/item/widgets.json @@ -11,12 +11,8 @@ "options": [ "standard", "open", - "inverted", - "retro" - ], - "config": { - "command": "worldstate" - } + "inverted" + ] }, "logiclevel": { "type": "selectbox", @@ -65,6 +61,12 @@ } }, "rightItemFrame": { + "retro": { + "type": "button", + "config": { + "command": "retro" + } + }, "sortingalgo": { "type": "selectbox", "default": "balanced", @@ -140,20 +142,28 @@ "colorizepots": { "type": "checkbox", "config": { - "padx": [50,0] + "padx": [ + 50, + 0 + ] } }, "potshuffle": { "type": "checkbox", "config": { - "padx": [50,0] + "padx": [ + 50, + 0 + ] } }, "dropshuffle": { "type": "checkbox" - }, + } + }, + "leftPoolFrame2": { "keydropshuffle": { - "type": "checkbox", + "type": "button", "config": { "command": "keydropshuffle" } diff --git a/source/classes/constants.py b/source/classes/constants.py index 3f0fb620..812042b8 100644 --- a/source/classes/constants.py +++ b/source/classes/constants.py @@ -66,6 +66,7 @@ SETTINGSTOPROCESS = { "crystals_ganon": "crystals_ganon", "weapons": "swords", + "retro": "retro", "sortingalgo": "algorithm", "accessibility": "accessibility", "restrict_boss_items": "restrict_boss_items", diff --git a/source/gui/loadcliargs.py b/source/gui/loadcliargs.py index 6d358853..aec14a72 100644 --- a/source/gui/loadcliargs.py +++ b/source/gui/loadcliargs.py @@ -57,7 +57,10 @@ def loadcliargs(gui, args, settings=None): pagewidgets[widget].selectbox.options = theseOptions elif thisType == "spinbox": pagewidgets[widget].label.configure(text=label) - pagewidgets[widget].storageVar.set(args[arg]) + elif thisType == 'button': + pagewidgets[widget].button.configure(text=label) + if hasattr(pagewidgets[widget], 'storageVar'): + pagewidgets[widget].storageVar.set(args[arg]) # If we're on the Game Options page and it's not about Hints if subpage == "gameoptions" and widget not in ["hints", "collection_rate"]: # Check if we've got settings diff --git a/source/gui/randomize/item.py b/source/gui/randomize/item.py index 6898c75f..63a96997 100644 --- a/source/gui/randomize/item.py +++ b/source/gui/randomize/item.py @@ -43,7 +43,10 @@ def item_page(parent): self.frames["leftPoolHeader"].pack(side=TOP, anchor=W) self.frames["leftPoolFrame"] = Frame(self.frames["leftPoolContainer"]) - self.frames["leftPoolFrame"].pack(side=LEFT, fill=Y) + self.frames["leftPoolFrame"].pack(side=TOP, fill=Y) + + self.frames["leftPoolFrame2"] = Frame(self.frames["leftPoolContainer"]) + self.frames["leftPoolFrame2"].pack(side=LEFT, fill=Y) self.frames["rightPoolFrame"] = Frame(self.frames["poolFrame"]) self.frames["rightPoolFrame"].pack(side=RIGHT) @@ -62,14 +65,16 @@ def item_page(parent): for key in dictWidgets: self.widgets[key] = dictWidgets[key] packAttrs = {"anchor":E} - if self.widgets[key].type == "checkbox" or framename == "leftPoolFrame": + if key == "retro": + packAttrs["side"] = RIGHT + if self.widgets[key].type == "checkbox" or framename.startswith("leftPoolFrame"): packAttrs["anchor"] = W if framename == "checkboxes": packAttrs["side"] = LEFT - packAttrs["padx"] = (10,0) + packAttrs["padx"] = (10, 0) elif framename == "leftPoolHeader": packAttrs["side"] = LEFT - packAttrs["padx"] = (0,20) + packAttrs["padx"] = (0, 20) packAttrs = widgets.add_padding_from_config(packAttrs, theseWidgets[key]) self.widgets[key].pack(packAttrs) diff --git a/source/gui/widgets.py b/source/gui/widgets.py index 4723a526..be664369 100644 --- a/source/gui/widgets.py +++ b/source/gui/widgets.py @@ -1,4 +1,6 @@ + from tkinter import messagebox, Checkbutton, Entry, Frame, IntVar, Label, OptionMenu, Spinbox, StringVar, LEFT, RIGHT, X +from tkinter import Button from source.classes.Empty import Empty # Override Spinbox to include mousewheel support for changing value @@ -172,6 +174,22 @@ def make_textbox(self, parent, label, storageVar, manager, managerAttrs): widget.textbox.pack(managerAttrs["textbox"] if managerAttrs is not None and "textbox" in managerAttrs else None) return widget + +def make_button(self, parent, label, manager, managerAttrs, config): + self = Frame(parent) + if config and "command" in config: + self.command = config["command"] + else: + self.command = lambda: None + + self.button = Button(parent, text=label, command=lambda: widget_command(self, self.command)) + if managerAttrs is not None: + self.button.pack(managerAttrs) + else: + self.button.pack(anchor='w') + return self + + # Make a generic widget def make_widget(self, type, parent, label, storageVar=None, manager=None, managerAttrs=dict(), options=None, config=None): @@ -201,6 +219,8 @@ def make_widget(self, type, parent, label, storageVar=None, manager=None, manage if thisStorageVar is None: thisStorageVar = StringVar() widget = make_textbox(self, parent, label, thisStorageVar, manager, managerAttrs) + elif type == 'button': + widget = make_button(self, parent, label, manager, managerAttrs, config) widget.type = type return widget @@ -243,47 +263,36 @@ def add_padding_from_config(packAttrs, defn): def widget_command(widget, command=""): root = widget.winfo_toplevel() text_output = "" - if command == "worldstate": - if widget.storageVar.get() == 'retro': - temp_widget = root.pages["randomizer"].pages["dungeon"].widgets["smallkeyshuffle"] - text_output += f'\n {temp_widget.label.cget("text")}' - temp_widget.storageVar.set('universal') + if command == "retro": + temp_widget = root.pages["randomizer"].pages["dungeon"].widgets["smallkeyshuffle"] + text_output += f'\n {temp_widget.label.cget("text")}' + temp_widget.storageVar.set('universal') - temp_widget = root.pages["randomizer"].pages["item"].widgets["bow_mode"] - text_output += f'\n {temp_widget.label.cget("text")}' - if temp_widget.storageVar.get() == 'progressive': - temp_widget.storageVar.set('retro') - elif temp_widget.storageVar.get() == 'silvers': - temp_widget.storageVar.set('retro_silvers') + temp_widget = root.pages["randomizer"].pages["item"].widgets["bow_mode"] + text_output += f'\n {temp_widget.label.cget("text")}' + if temp_widget.storageVar.get() == 'progressive': + temp_widget.storageVar.set('retro') + elif temp_widget.storageVar.get() == 'silvers': + temp_widget.storageVar.set('retro_silvers') - temp_widget = root.pages["randomizer"].pages["item"].widgets["take_any"] - text_output += f'\n {temp_widget.label.cget("text")}' - if temp_widget.storageVar.get() == 'none': - temp_widget.storageVar.set('random') + temp_widget = root.pages["randomizer"].pages["item"].widgets["take_any"] + text_output += f'\n {temp_widget.label.cget("text")}' + if temp_widget.storageVar.get() == 'none': + temp_widget.storageVar.set('random') - widget.storageVar.set('open') - messagebox.showinfo('', f'The following settings were changed:{text_output}') + messagebox.showinfo('', f'The following settings were changed:{text_output}') elif command == "keydropshuffle": - if widget.storageVar.get() > 0: - temp_widget = root.pages["randomizer"].pages["item"].widgets["pottery"] - if temp_widget.storageVar.get() == 'none': - text_output += f'\n {temp_widget.label.cget("text")}' - temp_widget.storageVar.set('keys') + temp_widget = root.pages["randomizer"].pages["item"].widgets["pottery"] + text_output += f'\n {temp_widget.label.cget("text")}' + if temp_widget.storageVar.get() == 'none': + + temp_widget.storageVar.set('keys') + + temp_widget = root.pages["randomizer"].pages["item"].widgets["dropshuffle"] + text_output += f'\n {temp_widget.checkbox.cget("text")}' + if temp_widget.storageVar.get() == 0: + temp_widget.storageVar.set(1) + + if text_output: + messagebox.showinfo('', f'The following settings were changed:{text_output}') - temp_widget = root.pages["randomizer"].pages["item"].widgets["dropshuffle"] - if temp_widget.storageVar.get() == 0: - temp_widget.storageVar.set(1) - text_output += f'\n {temp_widget.checkbox.cget("text")}' - if text_output: - messagebox.showinfo('', f'The following settings were changed:{text_output}') - else: - temp_widget = root.pages["randomizer"].pages["item"].widgets["pottery"] - if temp_widget.storageVar.get() == 'keys': - text_output += f'\n {temp_widget.label.cget("text")}' - temp_widget.storageVar.set('none') - temp_widget = root.pages["randomizer"].pages["item"].widgets["dropshuffle"] - if temp_widget.storageVar.get() == 1: - temp_widget.storageVar.set(0) - text_output += f'\n {temp_widget.checkbox.cget("text")}' - if text_output: - messagebox.showinfo('', f'The following settings were changed:{text_output}') From 10eac87922ccd381425ba2a00ff85cd7d312a30d Mon Sep 17 00:00:00 2001 From: aerinon Date: Thu, 6 Apr 2023 11:23:04 -0600 Subject: [PATCH 099/196] Logic fix: hookshot needed for pots in GT conveyor cross --- DoorShuffle.py | 2 ++ Doors.py | 2 ++ Dungeons.py | 14 ++++++++------ Regions.py | 3 ++- Rules.py | 4 ++-- 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/DoorShuffle.py b/DoorShuffle.py index 407509c8..b236cd9e 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -3806,6 +3806,8 @@ logical_connections = [ ('GT Blocked Stairs Block Path', 'GT Big Chest'), ('GT Speed Torch South Path', 'GT Speed Torch'), ('GT Speed Torch North Path', 'GT Speed Torch Upper'), + ('GT Conveyor Cross Hammer Path', 'GT Conveyor Cross Across Pits'), + ('GT Conveyor Cross Hookshot Path', 'GT Conveyor Cross'), ('GT Hookshot East-Mid Path', 'GT Hookshot Mid Platform'), ('GT Hookshot Mid-East Path', 'GT Hookshot East Platform'), ('GT Hookshot North-Mid Path', 'GT Hookshot Mid Platform'), diff --git a/Doors.py b/Doors.py index 0bd13742..e97505ee 100644 --- a/Doors.py +++ b/Doors.py @@ -1115,6 +1115,8 @@ def create_doors(world, player): create_door(player, 'GT Invisible Catwalk NE', Nrml).dir(No, 0x9c, Right, High).pos(2), create_door(player, 'GT Conveyor Cross EN', Nrml).dir(Ea, 0x8b, Top, High).pos(2), create_door(player, 'GT Conveyor Cross WN', Intr).dir(We, 0x8b, Top, High).pos(0), + create_door(player, 'GT Conveyor Cross Hammer Path', Lgcl), + create_door(player, 'GT Conveyor Cross Hookshot Path', Lgcl), create_door(player, 'GT Hookshot EN', Intr).dir(Ea, 0x8b, Top, High).pos(0), create_door(player, 'GT Hookshot East-Mid Path', Lgcl), create_door(player, 'GT Hookshot Mid-East Path', Lgcl), diff --git a/Dungeons.py b/Dungeons.py index 9d862b05..3835ef62 100644 --- a/Dungeons.py +++ b/Dungeons.py @@ -190,10 +190,11 @@ gt_regions = [ 'GT Tile Room', 'GT Speed Torch', 'GT Speed Torch Upper', 'GT Pots n Blocks', 'GT Crystal Conveyor', 'GT Crystal Conveyor Corner', 'GT Crystal Conveyor Left', 'GT Crystal Conveyor - Ranged Crystal', 'GT Crystal Conveyor Corner - Ranged Crystal', 'GT Compass Room', 'GT Invisible Bridges', 'GT Invisible Catwalk', - 'GT Conveyor Cross', 'GT Hookshot East Platform', 'GT Hookshot Mid Platform', 'GT Hookshot North Platform', - 'GT Hookshot South Platform', 'GT Hookshot South Entry', 'GT Hookshot South Entry - Ranged Crystal', 'GT Map Room', - 'GT Double Switch Entry', 'GT Double Switch Pot Corners - Ranged Switches', 'GT Double Switch Pot Corners', - 'GT Double Switch Left', 'GT Double Switch Left - Crystal', 'GT Double Switch Entry - Ranged Switches', + 'GT Conveyor Cross', 'GT Conveyor Cross Across Pits', 'GT Hookshot East Platform', 'GT Hookshot Mid Platform', + 'GT Hookshot North Platform', 'GT Hookshot South Platform', 'GT Hookshot South Entry', + 'GT Hookshot South Entry - Ranged Crystal', 'GT Map Room', 'GT Double Switch Entry', + 'GT Double Switch Pot Corners - Ranged Switches', 'GT Double Switch Pot Corners', 'GT Double Switch Left', + 'GT Double Switch Left - Crystal', 'GT Double Switch Entry - Ranged Switches', 'GT Double Switch Exit', 'GT Spike Crystal Left', 'GT Spike Crystal Right', 'GT Warp Maze - Left Section', 'GT Warp Maze - Mid Section', 'GT Warp Maze - Right Section', 'GT Warp Maze - Pit Section', 'GT Warp Maze - Pit Exit Warp Spot', @@ -204,8 +205,9 @@ gt_regions = [ 'GT Dash Hall', 'GT Hidden Spikes', 'GT Cannonball Bridge', 'GT Refill', 'GT Gauntlet 1', 'GT Gauntlet 2', 'GT Gauntlet 3', 'GT Gauntlet 4', 'GT Gauntlet 5', 'GT Beam Dash', 'GT Lanmolas 2', 'GT Quad Pot', 'GT Wizzrobes 1', 'GT Dashing Bridge', 'GT Wizzrobes 2', 'GT Conveyor Bridge', 'GT Torch Cross', 'GT Staredown', 'GT Falling Torches', - 'GT Mini Helmasaur Room', 'GT Bomb Conveyor', 'GT Crystal Circles', 'GT Crystal Inner Circle', 'GT Crystal Circles - Ranged Crystal', - 'GT Left Moldorm Ledge', 'GT Right Moldorm Ledge', 'GT Moldorm', 'GT Moldorm Pit', 'GT Validation', 'GT Validation Door', + 'GT Mini Helmasaur Room', 'GT Bomb Conveyor', 'GT Crystal Circles', 'GT Crystal Inner Circle', + 'GT Crystal Circles - Ranged Crystal', 'GT Left Moldorm Ledge', 'GT Right Moldorm Ledge', 'GT Moldorm', + 'GT Moldorm Pit', 'GT Validation', 'GT Validation Door', 'GT Frozen Over', 'GT Brightly Lit Hall', 'GT Agahnim 2', 'Ganons Tower Portal' ] diff --git a/Regions.py b/Regions.py index 44f065db..bcbb76d4 100644 --- a/Regions.py +++ b/Regions.py @@ -786,7 +786,8 @@ def create_dungeon_regions(world, player): ['GT Compass Room EN', 'GT Compass Room Warp']), create_dungeon_region(player, 'GT Invisible Bridges', 'Ganon\'s Tower', None, ['GT Invisible Bridges WS']), create_dungeon_region(player, 'GT Invisible Catwalk', 'Ganon\'s Tower', None, ['GT Invisible Catwalk ES', 'GT Invisible Catwalk WS', 'GT Invisible Catwalk NW', 'GT Invisible Catwalk NE']), - create_dungeon_region(player, 'GT Conveyor Cross', 'Ganon\'s Tower', ['Ganons Tower - Conveyor Cross Pot Key'], ['GT Conveyor Cross EN', 'GT Conveyor Cross WN']), + create_dungeon_region(player, 'GT Conveyor Cross', 'Ganon\'s Tower', ['Ganons Tower - Conveyor Cross Pot Key'], ['GT Conveyor Cross EN', 'GT Conveyor Cross Hammer Path']), + create_dungeon_region(player, 'GT Conveyor Cross Across Pits', 'Ganon\'s Tower', None, ['GT Conveyor Cross Hookshot Path', 'GT Conveyor Cross WN']), create_dungeon_region(player, 'GT Hookshot East Platform', 'Ganon\'s Tower', None, ['GT Hookshot EN', 'GT Hookshot East-Mid Path']), create_dungeon_region(player, 'GT Hookshot Mid Platform', 'Ganon\'s Tower', None, ['GT Hookshot Mid-East Path', 'GT Hookshot Mid-South Path', 'GT Hookshot Mid-North Path']), create_dungeon_region(player, 'GT Hookshot North Platform', 'Ganon\'s Tower', None, ['GT Hookshot NW', 'GT Hookshot North-Mid Path']), diff --git a/Rules.py b/Rules.py index a1c795a3..e8dc7aa5 100644 --- a/Rules.py +++ b/Rules.py @@ -467,8 +467,8 @@ def global_rules(world, player): set_rule(world.get_location('Ganons Tower - Bob\'s Torch', player), lambda state: state.has_Boots(player)) set_rule(world.get_entrance('GT Hope Room EN', player), lambda state: state.has('Cane of Somaria', player)) - set_rule(world.get_entrance('GT Conveyor Cross WN', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('GT Conveyor Cross EN', player), lambda state: state.has('Hookshot', player)) + set_rule(world.get_entrance('GT Conveyor Cross Hammer Path', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('GT Conveyor Cross Hookshot Path', player), lambda state: state.has('Hookshot', player)) if not world.get_door('GT Speed Torch SE', player).entranceFlag: set_rule(world.get_entrance('GT Speed Torch SE', player), lambda state: state.has('Fire Rod', player)) set_rule(world.get_entrance('GT Hookshot South-Mid Path', player), lambda state: state.has('Hookshot', player)) From 85afd0c09ebb415511fbb95efe06a29292b89b16 Mon Sep 17 00:00:00 2001 From: aerinon Date: Thu, 6 Apr 2023 11:23:54 -0600 Subject: [PATCH 100/196] Add collection_rate to customizer --- source/classes/CustomSettings.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/classes/CustomSettings.py b/source/classes/CustomSettings.py index 53105764..ba5bd705 100644 --- a/source/classes/CustomSettings.py +++ b/source/classes/CustomSettings.py @@ -116,6 +116,7 @@ class CustomSettings(object): args.crystals_gt[p] = get_setting(settings['crystals_gt'], args.crystals_gt[p]) args.crystals_ganon[p] = get_setting(settings['crystals_ganon'], args.crystals_ganon[p]) args.experimental[p] = get_setting(settings['experimental'], args.experimental[p]) + args.collection_rate[p] = get_setting(settings['collection_rate'], args.collection_rate[p]) args.openpyramid[p] = get_setting(settings['openpyramid'], args.openpyramid[p]) args.bigkeyshuffle[p] = get_setting(settings['bigkeyshuffle'], args.bigkeyshuffle[p]) args.keyshuffle[p] = get_setting(settings['keyshuffle'], args.keyshuffle[p]) @@ -244,6 +245,7 @@ class CustomSettings(object): settings_dict[p]['crystals_gt'] = world.crystals_gt_orig[p] settings_dict[p]['crystals_ganon'] = world.crystals_ganon_orig[p] settings_dict[p]['experimental'] = world.experimental[p] + settings_dict[p]['collection_rate'] = world.collection_rate[p] settings_dict[p]['openpyramid'] = world.open_pyramid[p] settings_dict[p]['bigkeyshuffle'] = world.bigkeyshuffle[p] settings_dict[p]['keyshuffle'] = world.keyshuffle[p] From ef63511bd8305b2d44845b44b4ffc7d64f6063e1 Mon Sep 17 00:00:00 2001 From: aerinon Date: Thu, 6 Apr 2023 11:25:32 -0600 Subject: [PATCH 101/196] Update notes --- RELEASENOTES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 730f7bda..71b3ec75 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -111,6 +111,7 @@ These are now independent of retro mode and have three options: None, Random, an * 1.2.0.15u * GUI reorganization + * Logic fix for pots in GT conveyor cross * Auto option for pyramid open (trinity or ER + crystals goal) * World model refactor (combining inverted and normal world models) * Partitioned fix for lamp logic and links house @@ -118,6 +119,7 @@ These are now independent of retro mode and have three options: None, Random, an * Reduced universal keys in pool slightly for non-vanilla dungeons * Fake world fix finally * Some extra restrictions on links house placement for lite/lean + * Collection_rate works in customizer files * 1.2.0.14u * Small fix for key logic validation (got rid of a false negative) * Customized doors in ice cross work properly now From 793f3b30b08b3fe227b52b326ce08854b4807e0b Mon Sep 17 00:00:00 2001 From: codemann8 Date: Fri, 7 Apr 2023 12:04:12 -0500 Subject: [PATCH 102/196] Merged in DR v1.2.0.14 (2nd) --- BaseClasses.py | 9 +- DoorShuffle.py | 22 +- ER_hint_reference.txt | 14 +- EntranceShuffle.py | 94 ++-- ItemList.py | 15 +- KeyDoorShuffle.py | 2 +- Main.py | 2 +- OWEdges.py | 4 +- OverworldGlitchRules.py | 4 +- OverworldShuffle.py | 4 +- PotShuffle.py | 20 +- RELEASENOTES.md | 8 + Regions.py | 109 ++--- Rom.py | 14 +- Rules.py | 439 +++++++++--------- resources/app/gui/lang/en.json | 1 - .../app/gui/randomize/entrando/widgets.json | 2 +- source/classes/constants.py | 4 +- source/item/District.py | 8 +- source/item/FillUtil.py | 2 +- source/overworld/EntranceShuffle2.py | 402 ++++++++-------- test/inverted/TestInverted.py | 8 +- test/inverted/TestInvertedBombRules.py | 5 +- test/inverted/TestInvertedEntrances.py | 42 +- test/inverted_owg/TestInvertedOWG.py | 8 +- test/owg/TestVanillaOWG.py | 4 +- test/stats/EntranceShuffleStats.py | 1 + test/vanilla/TestVanilla.py | 4 +- 28 files changed, 633 insertions(+), 618 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index 93691104..55d586a7 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -351,7 +351,7 @@ class World(object): return True else: return False - + def check_for_door(self, doorname, player): if isinstance(doorname, Door): return doorname @@ -3092,7 +3092,7 @@ class Spoiler(object): outfile.write('Entrance Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['shuffle'][player]) if self.metadata['shuffle'][player] != 'vanilla': outfile.write('Shuffle GT/Ganon:'.ljust(line_width) + '%s\n' % yn(self.metadata['shuffleganon'][player])) - outfile.write('Shuffle Links:'.ljust(line_width) + '%s\n' % yn(self.metadata['shufflelinks'][player])) + outfile.write('Shuffle Link\'s House:'.ljust(line_width) + '%s\n' % yn(self.metadata['shufflelinks'][player])) outfile.write('Shuffle Tavern:'.ljust(line_width) + '%s\n' % yn(self.metadata['shuffletavern'][player])) outfile.write('Pyramid Hole Pre-opened:'.ljust(line_width) + '%s\n' % self.metadata['open_pyramid'][player]) if self.metadata['shuffle'][player] != 'vanilla' or self.metadata['ow_mixed'][player]: @@ -3380,6 +3380,9 @@ class Pot(object): item = self.item if not self.indicator else self.standing_item_code return [self.x, high_byte, item] + def get_region(self, world, player): + return world.get_region(self.room, 1) + def __eq__(self, other): return self.x == other.x and self.y == other.y and self.room == other.room @@ -3485,7 +3488,7 @@ class Settings(object): | (counter_mode[w.dungeon_counters[p]] << 1) | (1 if w.experimental[p] else 0), ((8 if w.crystals_ganon_orig[p] == "random" else int(w.crystals_ganon_orig[p])) << 3) - | (0x4 if w.open_pyramid[p] else 0) | access_mode[w.accessibility[p]], + | (0x4 if w.is_pyramid_open(p) else 0) | access_mode[w.accessibility[p]], (0x80 if w.bigkeyshuffle[p] else 0) | (0x20 if w.mapshuffle[p] else 0) | (0x10 if w.compassshuffle[p] else 0) diff --git a/DoorShuffle.py b/DoorShuffle.py index 3ec1b985..f4c55de2 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -436,7 +436,6 @@ def pair_existing_key_doors(world, player, door_a, door_b): def choose_portals(world, player): - if world.doorShuffle[player] != ['vanilla']: shuffle_flag = world.doorShuffle[player] != 'basic' allowed = {} @@ -3286,7 +3285,8 @@ def remove_pair_type_if_present(door, world, player): def find_inaccessible_regions(world, player): world.inaccessible_regions[player] = [] - start_regions = ['Links House' if not world.is_bombshop_start(player) else 'Big Bomb Shop', 'Sanctuary' if world.mode[player] != 'inverted' else 'Dark Sanctuary Hint'] + start_regions = ['Links House' if not world.is_bombshop_start(player) else 'Big Bomb Shop'] + start_regions.append('Sanctuary' if world.mode[player] != 'inverted' else 'Dark Sanctuary Hint') regs = convert_regions(start_regions, world, player) if all(all(not e.connected_region for e in r.exits) for r in regs): # if attempting to find inaccessible regions before any connections made above, assume eventual access to Pyramid S&Q @@ -3328,9 +3328,10 @@ def find_accessible_entrances(world, player, builder): hc_std = True start_regions = ['Hyrule Castle Courtyard'] else: - start_regions = ['Links House' if not world.is_bombshop_start(player) else 'Big Bomb Shop', 'Sanctuary' if world.mode[player] != 'inverted' else 'Dark Sanctuary Hint'] - if world.is_tile_swapped(0x1b, player): - start_regions.append('Hyrule Castle Ledge') + start_regions = ['Links House' if not world.is_bombshop_start(player) else 'Big Bomb Shop'] + start_regions.append('Sanctuary' if world.mode[player] != 'inverted' else 'Dark Sanctuary Hint') + start_regions.append('Pyramid Area' if not world.is_tile_swapped(0x1b, player) else 'Hyrule Castle Ledge') + regs = convert_regions(start_regions, world, player) visited_regions = set() visited_entrances = [] @@ -3350,12 +3351,12 @@ def find_accessible_entrances(world, player, builder): if connect not in queue and connect not in visited_regions: queue.append(connect) for ext in next_region.exits: - if hc_std and ext.name == 'Hyrule Castle Main Gate (North)': # just skip it + if hc_std and ext.name in ['Hyrule Castle Main Gate (North)', 'Castle Gate Teleporter (Inner)', 'Hyrule Castle Ledge Drop']: # just skip it continue connect = ext.connected_region if connect is None or ext.door and ext.door.blocked: continue - if world.mode[player] == 'standard' and builder.name == 'Hyrule Castle' and (ext.name.startswith('Flute From') or ext.name in ['Hyrule Castle Main Gate (North)', 'Top of Pyramid (Inner)', 'Inverted Pyramid Entrance']): + if world.mode[player] == 'standard' and builder.name == 'Hyrule Castle' and (ext.name.startswith('Flute From') or ext.name in ['Hyrule Castle Main Gate (North)', 'Castle Gate Teleporter (Inner)', 'Inverted Pyramid Entrance']): continue if connect.name in entrances and connect not in visited_entrances: visited_entrances.append(connect.name) @@ -3388,10 +3389,7 @@ def create_doors_for_inaccessible_region(inaccessible_region, world, player): region = world.get_region(inaccessible_region, player) for ext in region.exits: create_door(world, player, ext.name, region.name) - if ext.connected_region is None: - # TODO: Since Open/Inverted regions are merged into one world model, some exits are left disconnected intentionally - logging.getLogger('').debug('Exit not connected to any region: %s', ext.name) - elif ext.connected_region.name.endswith(' Portal'): + if ext.connected_region and ext.connected_region.name.endswith(' Portal'): for more_exts in ext.connected_region.exits: create_door(world, player, more_exts.name, ext.connected_region.name) @@ -3401,7 +3399,7 @@ def create_door(world, player, entName, region_name): connect = entrance.connected_region if connect is not None: for ext in connect.exits: - if ext.connected_region is not None and ext.connected_region.name == region_name: + if ext.connected_region and ext.connected_region.name == region_name: d = Door(player, ext.name, DoorType.Logical, ext), world.doors += d connect_door_only(world, ext.name, ext.connected_region, player) diff --git a/ER_hint_reference.txt b/ER_hint_reference.txt index a4972fba..c86ca335 100644 --- a/ER_hint_reference.txt +++ b/ER_hint_reference.txt @@ -98,7 +98,7 @@ Ice Palace: Ice Palace Skull Woods Final Section: The back of Skull Woods Death Mountain Return Cave (West): The SW DM Foothills Cave Mimic Cave: Mimic Ledge -Dark World Hammer Peg Cave: The rows of pegs +Hammer Peg Cave: The rows of pegs Pyramid Fairy: The crack on the pyramid Eastern Palace: Eastern Palace Elder House (East): Elder House @@ -145,7 +145,7 @@ Chicken House: The chicken lady's house Tavern North: A backdoor Aginahs Cave: The open desert cave Sahasrahlas Hut: The house near armos -Cave Shop (Lake Hylia): The cave NW Lake Hylia +Lake Hylia Shop: The cave NW Lake Hylia Blacksmiths Hut: The old smithery Sick Kids House: The central house in Kakariko Lost Woods Gamble: A tree trunk door @@ -188,19 +188,19 @@ Dark World Shop: The hammer sealed building Red Shield Shop: The fenced in building Mire Shed: The western hut in the mire East Dark World Hint: The dark cave near the eastmost portal -Dark Desert Hint: The cave east of the mire +Mire Hint: The cave east of the mire Spike Cave: The ledge cave on west dark DM Palace of Darkness Hint: The building south of Kiki Dark Lake Hylia Ledge Spike Cave: The rock SE dark Lake Hylia -Cave Shop (Dark Death Mountain): The base of east dark DM -Dark World Potion Shop: The building near the catfish +Dark Death Mountain Shop: The base of east dark DM +Dark Potion Shop: The building near the catfish Archery Game: The old archery game -Dark World Lumberjack Shop: The northmost Dark World building +Dark Lumberjack Shop: The northmost Dark World building Hype Cave: The cave south of the old bomb shop Brewery: The Village of Outcasts building with no door Dark Lake Hylia Ledge Hint: The open cave SE dark Lake Hylia Chest Game: The westmost building in the Village of Outcasts -Dark Desert Fairy: The eastern hut in the mire +Mire Fairy: The eastern hut in the mire Dark Lake Hylia Ledge Fairy: The sealed cave SE dark Lake Hylia Fortune Teller (Dark): The building NE the Village of Outcasts Sanctuary: Sanctuary diff --git a/EntranceShuffle.py b/EntranceShuffle.py index bc754b89..93ad21d4 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -671,7 +671,7 @@ def link_entrances(world, player): world.ganon_at_pyramid[player] = False # check for Ganon's Tower location - if world.get_entrance('Ganons Tower' if not world.is_atgt_swapped(player) else 'Agahnims Tower', player).connected_region.name != 'Ganons Tower Portal' if not invFlag else 'GT Lobby': + if world.get_entrance('Ganons Tower' if not world.is_atgt_swapped(player) else 'Agahnims Tower', player).connected_region.name != 'Ganons Tower Portal': world.ganonstower_vanilla[player] = False @@ -1943,7 +1943,7 @@ Entrance_Pool_Base = ['Links House', 'Desert Fairy', 'Dark Lake Hylia Fairy', 'Dark Lake Hylia Ledge Fairy', - 'Dark Desert Fairy', + 'Mire Fairy', 'Dark Death Mountain Fairy', 'Fortune Teller (Light)', 'Lake Hylia Fortune Teller', @@ -1951,8 +1951,8 @@ Entrance_Pool_Base = ['Links House', 'Chicken House', 'Aginahs Cave', 'Sahasrahlas Hut', - 'Cave Shop (Lake Hylia)', - 'Cave Shop (Dark Death Mountain)', + 'Lake Hylia Shop', + 'Dark Death Mountain Shop', 'Capacity Upgrade', 'Blacksmiths Hut', 'Sick Kids House', @@ -1983,21 +1983,21 @@ Entrance_Pool_Base = ['Links House', 'Big Bomb Shop', 'Dark World Shop', 'Dark Lake Hylia Shop', - 'Dark World Lumberjack Shop', - 'Dark World Potion Shop', + 'Dark Lumberjack Shop', + 'Dark Potion Shop', 'Dark Lake Hylia Ledge Spike Cave', 'Dark Lake Hylia Ledge Hint', 'Hype Cave', 'Brewery', 'C-Shaped House', 'Chest Game', - 'Dark World Hammer Peg Cave', + 'Hammer Peg Cave', 'Red Shield Shop', 'Dark Sanctuary Hint', 'Fortune Teller (Dark)', 'Archery Game', 'Mire Shed', - 'Dark Desert Hint', + 'Mire Hint', 'Spike Cave', 'Mimic Cave', 'Kakariko Well Drop', @@ -2079,11 +2079,11 @@ Exit_Pool_Base = ['Links House Exit', 'Bonk Fairy (Light)', 'Bonk Fairy (Dark)', 'Lake Hylia Healer Fairy', - 'Swamp Healer Fairy', + 'Light Hype Fairy', 'Desert Healer Fairy', 'Dark Lake Hylia Healer Fairy', 'Dark Lake Hylia Ledge Healer Fairy', - 'Dark Desert Healer Fairy', + 'Mire Healer Fairy', 'Dark Death Mountain Healer Fairy', 'Fortune Teller (Light)', 'Lake Hylia Fortune Teller', @@ -2091,8 +2091,8 @@ Exit_Pool_Base = ['Links House Exit', 'Chicken House', 'Aginahs Cave', 'Sahasrahlas Hut', - 'Cave Shop (Lake Hylia)', - 'Cave Shop (Dark Death Mountain)', + 'Lake Hylia Shop', + 'Dark Death Mountain Shop', 'Capacity Upgrade', 'Blacksmiths Hut', 'Sick Kids House', @@ -2123,21 +2123,21 @@ Exit_Pool_Base = ['Links House Exit', 'Big Bomb Shop', 'Village of Outcasts Shop', 'Dark Lake Hylia Shop', - 'Dark World Lumberjack Shop', - 'Dark World Potion Shop', + 'Dark Lumberjack Shop', + 'Dark Potion Shop', 'Dark Lake Hylia Ledge Spike Cave', 'Dark Lake Hylia Ledge Hint', 'Hype Cave', 'Brewery', 'C-Shaped House', 'Chest Game', - 'Dark World Hammer Peg Cave', + 'Hammer Peg Cave', 'Red Shield Shop', 'Dark Sanctuary Hint', 'Fortune Teller (Dark)', 'Archery Game', 'Mire Shed', - 'Dark Desert Hint', + 'Mire Hint', 'Spike Cave', 'Mimic Cave', 'Kakariko Well (top)', @@ -2170,7 +2170,7 @@ mandatory_connections = [('Lost Woods Hideout (top to bottom)', 'Lost Woods Hide ('Death Mountain Return Cave E', 'Death Mountain Return Cave (right)'), ('Death Mountain Return Cave W', 'Death Mountain Return Cave (left)'), ('Spiral Cave (top to bottom)', 'Spiral Cave (Bottom)'), - ('Light World Death Mountain Shop', 'Light World Death Mountain Shop'), + ('Paradox Shop', 'Paradox Shop'), ('Paradox Cave Push Block Reverse', 'Paradox Cave Chest Area'), ('Paradox Cave Push Block', 'Paradox Cave Front'), ('Paradox Cave Chest Area NE', 'Paradox Cave Bomb Area'), @@ -2209,10 +2209,10 @@ default_connections = [('Bonk Fairy (Light)', 'Bonk Fairy (Light)'), ('Dark Sanctuary Hint', 'Dark Sanctuary Hint'), ('Fortune Teller (Dark)', 'Fortune Teller (Dark)'), ('Archery Game', 'Archery Game'), - ('Dark Desert Fairy', 'Dark Desert Healer Fairy') + ('Mire Fairy', 'Mire Healer Fairy') ] -default_takeany_connections = [('Light Hype Fairy', 'Swamp Healer Fairy'), +default_takeany_connections = [('Light Hype Fairy', 'Light Hype Fairy'), ('Desert Fairy', 'Desert Healer Fairy'), ('Dark Lake Hylia Ledge Fairy', 'Dark Lake Hylia Ledge Healer Fairy'), ('Bonk Fairy (Dark)', 'Bonk Fairy (Dark)'), @@ -2229,7 +2229,7 @@ default_pot_connections = [('Lumberjack House', 'Lumberjack House'), ('Hookshot Fairy', 'Hookshot Fairy'), ('Palace of Darkness Hint', 'Palace of Darkness Hint'), ('Dark Lake Hylia Ledge Spike Cave', 'Dark Lake Hylia Ledge Spike Cave'), - ('Dark Desert Hint', 'Dark Desert Hint') + ('Mire Hint', 'Mire Hint') ] default_connector_connections = [('Old Man Cave (West)', 'Old Man Cave Exit (West)'), @@ -2284,18 +2284,18 @@ default_item_connections = [('Links House', 'Links House Exit'), ('C-Shaped House', 'C-Shaped House'), ('Brewery', 'Brewery'), ('Pyramid Fairy', 'Pyramid Fairy'), - ('Dark World Hammer Peg Cave', 'Dark World Hammer Peg Cave'), + ('Hammer Peg Cave', 'Hammer Peg Cave'), ('Big Bomb Shop', 'Big Bomb Shop'), ('Mire Shed', 'Mire Shed'), ('Hype Cave', 'Hype Cave') ] default_shop_connections = [('Kakariko Shop', 'Kakariko Shop'), - ('Cave Shop (Lake Hylia)', 'Cave Shop (Lake Hylia)'), + ('Lake Hylia Shop', 'Lake Hylia Shop'), ('Capacity Upgrade', 'Capacity Upgrade'), - ('Dark World Lumberjack Shop', 'Dark World Lumberjack Shop'), - ('Cave Shop (Dark Death Mountain)', 'Cave Shop (Dark Death Mountain)'), - ('Dark World Potion Shop', 'Dark World Potion Shop'), + ('Dark Lumberjack Shop', 'Dark Lumberjack Shop'), + ('Dark Death Mountain Shop', 'Dark Death Mountain Shop'), + ('Dark Potion Shop', 'Dark Potion Shop'), ('Dark World Shop', 'Village of Outcasts Shop'), ('Red Shield Shop', 'Red Shield Shop'), ('Dark Lake Hylia Shop', 'Dark Lake Hylia Shop') @@ -2449,7 +2449,7 @@ door_addresses = {'Links House': (0x00, (0x0104, 0x2c 'Chicken House': (0x4A, (0x0108, 0x18, 0x1120, 0x0837, 0x0106, 0x0888, 0x0188, 0x08a4, 0x0193, 0x07, 0xf9, 0x1530, 0x0000), 0x00), 'Aginahs Cave': (0x70, (0x010a, 0x30, 0x0656, 0x0cc6, 0x02aa, 0x0d18, 0x0328, 0x0d33, 0x032f, 0x08, 0xf8, 0x0000, 0x0000), 0x00), 'Sahasrahlas Hut': (0x44, (0x0105, 0x1e, 0x0610, 0x06d4, 0x0c76, 0x0727, 0x0cf0, 0x0743, 0x0cfb, 0x0a, 0xf6, 0x0000, 0x0000), 0x00), - 'Cave Shop (Lake Hylia)': (0x57, (0x0112, 0x35, 0x0022, 0x0c00, 0x0b1a, 0x0c26, 0x0b98, 0x0c6d, 0x0b9f, 0x00, 0x00, 0x0000, 0x0000), 0x00), + 'Lake Hylia Shop': (0x57, (0x0112, 0x35, 0x0022, 0x0c00, 0x0b1a, 0x0c26, 0x0b98, 0x0c6d, 0x0b9f, 0x00, 0x00, 0x0000, 0x0000), 0x00), 'Capacity Upgrade': (0x5C, (0x0115, 0x35, 0x0a46, 0x0d36, 0x0c2a, 0x0d88, 0x0ca8, 0x0da3, 0x0caf, 0x0a, 0xf6, 0x0000, 0x0000), 0x00), 'Kakariko Well Drop': ([0xDB85C, 0xDB85D], None), 'Blacksmiths Hut': (0x63, (0x0121, 0x22, 0x010c, 0x081a, 0x0466, 0x0868, 0x04d8, 0x0887, 0x04e3, 0x06, 0xfa, 0x041A, 0x0000), 0x00), @@ -2492,19 +2492,19 @@ door_addresses = {'Links House': (0x00, (0x0104, 0x2c 'Brewery': (0x47, (0x0106, 0x58, 0x16a8, 0x08e4, 0x013e, 0x0938, 0x01b8, 0x0953, 0x01c3, 0x0a, 0xf6, 0x1AB6, 0x0000), 0x02), 'C-Shaped House': (0x53, (0x011c, 0x58, 0x09d8, 0x0744, 0x02ce, 0x0797, 0x0348, 0x07b3, 0x0353, 0x0a, 0xf6, 0x0DE8, 0x0000), 0x00), 'Chest Game': (0x46, (0x0106, 0x58, 0x078a, 0x0705, 0x004e, 0x0758, 0x00c8, 0x0774, 0x00d3, 0x09, 0xf7, 0x0B98, 0x0000), 0x00), - 'Dark World Hammer Peg Cave': (0x7E, (0x0127, 0x62, 0x0894, 0x091e, 0x0492, 0x09a6, 0x0508, 0x098b, 0x050f, 0x00, 0x00, 0x0000, 0x0000), 0x20), + 'Hammer Peg Cave': (0x7E, (0x0127, 0x62, 0x0894, 0x091e, 0x0492, 0x09a6, 0x0508, 0x098b, 0x050f, 0x00, 0x00, 0x0000, 0x0000), 0x20), 'Red Shield Shop': (0x74, (0x0110, 0x5a, 0x079a, 0x06e8, 0x04d6, 0x0738, 0x0548, 0x0755, 0x0553, 0x08, 0xf8, 0x0AA8, 0x0000), 0x00), 'Dark Sanctuary Hint': (0x59, (0x0112, 0x53, 0x001e, 0x0400, 0x06e2, 0x0446, 0x0758, 0x046d, 0x075f, 0x00, 0x00, 0x0000, 0x0000), 0x00), 'Fortune Teller (Dark)': (0x65, (0x0122, 0x51, 0x0610, 0x04b4, 0x027e, 0x0507, 0x02f8, 0x0523, 0x0303, 0x0a, 0xf6, 0x091E, 0x0000), 0x00), 'Dark World Shop': (0x5F, (0x010f, 0x58, 0x1058, 0x0814, 0x02be, 0x0868, 0x0338, 0x0883, 0x0343, 0x0a, 0xf6, 0x0000, 0x0000), 0x00), - 'Dark World Lumberjack Shop': (0x56, (0x010f, 0x42, 0x041c, 0x0074, 0x04e2, 0x00c7, 0x0558, 0x00e3, 0x055f, 0x0a, 0xf6, 0x0000, 0x0000), 0x00), - 'Dark World Potion Shop': (0x6E, (0x010f, 0x56, 0x080e, 0x04f4, 0x0c66, 0x0548, 0x0cd8, 0x0563, 0x0ce3, 0x0a, 0xf6, 0x0000, 0x0000), 0x00), + 'Dark Lumberjack Shop': (0x56, (0x010f, 0x42, 0x041c, 0x0074, 0x04e2, 0x00c7, 0x0558, 0x00e3, 0x055f, 0x0a, 0xf6, 0x0000, 0x0000), 0x00), + 'Dark Potion Shop': (0x6E, (0x010f, 0x56, 0x080e, 0x04f4, 0x0c66, 0x0548, 0x0cd8, 0x0563, 0x0ce3, 0x0a, 0xf6, 0x0000, 0x0000), 0x00), 'Archery Game': (0x58, (0x0111, 0x69, 0x069e, 0x0ac4, 0x02ea, 0x0b18, 0x0368, 0x0b33, 0x036f, 0x0a, 0xf6, 0x09AC, 0x0000), 0x00), 'Mire Shed': (0x5E, (0x010d, 0x70, 0x0384, 0x0c69, 0x001e, 0x0cb6, 0x0098, 0x0cd6, 0x00a3, 0x07, 0xf9, 0x0000, 0x0000), 0x00), - 'Dark Desert Hint': (0x61, (0x0114, 0x70, 0x0654, 0x0cc5, 0x02aa, 0x0d16, 0x0328, 0x0d32, 0x032f, 0x09, 0xf7, 0x0000, 0x0000), 0x00), - 'Dark Desert Fairy': (0x55, (0x0115, 0x70, 0x03a8, 0x0c6a, 0x013a, 0x0cb7, 0x01b8, 0x0cd7, 0x01bf, 0x06, 0xfa, 0x0000, 0x0000), 0x00), + 'Mire Hint': (0x61, (0x0114, 0x70, 0x0654, 0x0cc5, 0x02aa, 0x0d16, 0x0328, 0x0d32, 0x032f, 0x09, 0xf7, 0x0000, 0x0000), 0x00), + 'Mire Fairy': (0x55, (0x0115, 0x70, 0x03a8, 0x0c6a, 0x013a, 0x0cb7, 0x01b8, 0x0cd7, 0x01bf, 0x06, 0xfa, 0x0000, 0x0000), 0x00), 'Spike Cave': (0x40, (0x0117, 0x43, 0x0ed4, 0x01e4, 0x08aa, 0x0236, 0x0928, 0x0253, 0x092f, 0x0a, 0xf6, 0x0000, 0x0000), 0x00), - 'Cave Shop (Dark Death Mountain)': (0x6D, (0x0112, 0x45, 0x0ee0, 0x01e3, 0x0d00, 0x0236, 0x0daa, 0x0252, 0x0d7d, 0x0b, 0xf5, 0x0000, 0x0000), 0x00), + 'Dark Death Mountain Shop': (0x6D, (0x0112, 0x45, 0x0ee0, 0x01e3, 0x0d00, 0x0236, 0x0daa, 0x0252, 0x0d7d, 0x0b, 0xf5, 0x0000, 0x0000), 0x00), 'Dark Death Mountain Fairy': (0x6F, (0x0115, 0x43, 0x1400, 0x0294, 0x0600, 0x02e8, 0x0678, 0x0303, 0x0685, 0x0a, 0xf6, 0x0000, 0x0000), 0x00), 'Mimic Cave': (0x4E, (0x010c, 0x05, 0x07e0, 0x0103, 0x0d00, 0x0156, 0x0d78, 0x0172, 0x0d7d, 0x0b, 0xf5, 0x0000, 0x0000), 0x00), 'Big Bomb Shop': (0x52, (0x011c, 0x6c, 0x0506, 0x0a9a, 0x0832, 0x0ae7, 0x08b8, 0x0b07, 0x08bf, 0x06, 0xfa, 0x0816, 0x0000), 0x00), @@ -2584,11 +2584,11 @@ exit_ids = {'Links House Exit': (0x01, 0x00), 'Bonk Fairy (Light)': 0x71, 'Bonk Fairy (Dark)': 0x71, 'Lake Hylia Healer Fairy': 0x5E, - 'Swamp Healer Fairy': 0x5E, + 'Light Hype Fairy': 0x5E, 'Desert Healer Fairy': 0x5E, 'Dark Lake Hylia Healer Fairy': 0x5E, 'Dark Lake Hylia Ledge Healer Fairy': 0x5E, - 'Dark Desert Healer Fairy': 0x5E, + 'Mire Healer Fairy': 0x5E, 'Dark Death Mountain Healer Fairy': 0x5E, 'Fortune Teller (Light)': 0x65, 'Lake Hylia Fortune Teller': 0x65, @@ -2597,8 +2597,8 @@ exit_ids = {'Links House Exit': (0x01, 0x00), 'Chicken House': 0x4B, 'Aginahs Cave': 0x4D, 'Sahasrahlas Hut': 0x45, - 'Cave Shop (Lake Hylia)': 0x58, - 'Cave Shop (Dark Death Mountain)': 0x58, + 'Lake Hylia Shop': 0x58, + 'Dark Death Mountain Shop': 0x58, 'Capacity Upgrade': 0x5D, 'Blacksmiths Hut': 0x64, 'Sick Kids House': 0x40, @@ -2629,21 +2629,21 @@ exit_ids = {'Links House Exit': (0x01, 0x00), 'Big Bomb Shop': 0x53, 'Village of Outcasts Shop': 0x60, 'Dark Lake Hylia Shop': 0x60, - 'Dark World Lumberjack Shop': 0x60, - 'Dark World Potion Shop': 0x60, + 'Dark Lumberjack Shop': 0x60, + 'Dark Potion Shop': 0x60, 'Dark Lake Hylia Ledge Spike Cave': 0x70, 'Dark Lake Hylia Ledge Hint': 0x6A, 'Hype Cave': 0x3D, 'Brewery': 0x48, 'C-Shaped House': 0x54, 'Chest Game': 0x47, - 'Dark World Hammer Peg Cave': 0x83, + 'Hammer Peg Cave': 0x83, 'Red Shield Shop': 0x57, 'Dark Sanctuary Hint': 0x5A, 'Fortune Teller (Dark)': 0x66, 'Archery Game': 0x59, 'Mire Shed': 0x5F, - 'Dark Desert Hint': 0x62, + 'Mire Hint': 0x62, 'Spike Cave': 0x41, 'Mimic Cave': 0x4F, 'Kakariko Well (top)': 0x80, @@ -2730,7 +2730,7 @@ ow_prize_table = {'Links House': (0x8b1, 0xb2d), 'Chicken House': (0x120, 0x880), 'Aginahs Cave': (0x2e0, 0xd00), 'Sahasrahlas Hut': (0xcf0, 0x6c0), - 'Cave Shop (Lake Hylia)': (0xbc0, 0xc00), + 'Lake Hylia Shop': (0xbc0, 0xc00), 'Capacity Upgrade': (0xca0, 0xda0), 'Kakariko Well Drop': None, 'Blacksmiths Hut': (0x4a0, 0x880), @@ -2770,19 +2770,19 @@ ow_prize_table = {'Links House': (0x8b1, 0xb2d), 'Hype Cave': (0x940, 0xc80), 'Bonk Fairy (Dark)': (0x740, 0xa80), 'Brewery': (0x170, 0x980), 'C-Shaped House': (0x310, 0x7a0), 'Chest Game': (0x800, 0x7a0), - 'Dark World Hammer Peg Cave': (0x4c0, 0x940), + 'Hammer Peg Cave': (0x4c0, 0x940), 'Red Shield Shop': (0x500, 0x680), 'Dark Sanctuary Hint': (0x720, 0x4a0), 'Fortune Teller (Dark)': (0x2c0, 0x4c0), 'Dark World Shop': (0x2e0, 0x880), - 'Dark World Lumberjack Shop': (0x4e0, 0x0d0), - 'Dark World Potion Shop': (0xc80, 0x4c0), + 'Dark Lumberjack Shop': (0x4e0, 0x0d0), + 'Dark Potion Shop': (0xc80, 0x4c0), 'Archery Game': (0x2f0, 0xaf0), 'Mire Shed': (0x060, 0xc90), - 'Dark Desert Hint': (0x2e0, 0xd00), - 'Dark Desert Fairy': (0x1c0, 0xc90), + 'Mire Hint': (0x2e0, 0xd00), + 'Mire Fairy': (0x1c0, 0xc90), 'Spike Cave': (0x860, 0x180), - 'Cave Shop (Dark Death Mountain)': (0xd80, 0x180), + 'Dark Death Mountain Shop': (0xd80, 0x180), 'Dark Death Mountain Fairy': (0x620, 0x2c0), 'Mimic Cave': (0xc80, 0x180), 'Big Bomb Shop': (0x8b1, 0xb2d), diff --git a/ItemList.py b/ItemList.py index 3665c414..437e422e 100644 --- a/ItemList.py +++ b/ItemList.py @@ -494,15 +494,15 @@ def generate_itempool(world, player): take_any_locations = [ 'Snitch Lady (East)', 'Snitch Lady (West)', 'Bush Covered House', 'Light World Bomb Hut', 'Fortune Teller (Light)', 'Lake Hylia Fortune Teller', 'Lumberjack House', 'Bonk Fairy (Light)', - 'Bonk Fairy (Dark)', 'Lake Hylia Healer Fairy', 'Swamp Healer Fairy', 'Desert Healer Fairy', - 'Dark Lake Hylia Healer Fairy', 'Dark Lake Hylia Ledge Healer Fairy', 'Dark Desert Healer Fairy', + 'Bonk Fairy (Dark)', 'Lake Hylia Healer Fairy', 'Light Hype Fairy', 'Desert Healer Fairy', + 'Dark Lake Hylia Healer Fairy', 'Dark Lake Hylia Ledge Healer Fairy', 'Mire Healer Fairy', 'Dark Death Mountain Healer Fairy', 'Long Fairy Cave', 'Good Bee Cave', '20 Rupee Cave', 'Kakariko Gamble Game', '50 Rupee Cave', 'Lost Woods Gamble', 'Hookshot Fairy', 'Palace of Darkness Hint', 'East Dark World Hint', 'Archery Game', 'Dark Lake Hylia Ledge Hint', - 'Dark Lake Hylia Ledge Spike Cave', 'Fortune Teller (Dark)', 'Dark Sanctuary Hint', 'Dark Desert Hint'] + 'Dark Lake Hylia Ledge Spike Cave', 'Fortune Teller (Dark)', 'Dark Sanctuary Hint', 'Mire Hint'] fixed_take_anys = [ - 'Desert Healer Fairy', 'Swamp Healer Fairy', 'Dark Death Mountain Healer Fairy', + 'Desert Healer Fairy', 'Light Hype Fairy', 'Dark Death Mountain Healer Fairy', 'Dark Lake Hylia Ledge Healer Fairy', 'Bonk Fairy (Dark)'] @@ -966,7 +966,7 @@ def balance_prices(world, player): def check_hints(world, player): if world.shuffle[player] in ['simple', 'restricted', 'full', 'lite', 'lean', 'crossed', 'insanity']: for shop, location_list in shop_to_location_table.items(): - if shop in ['Capacity Upgrade', 'Light World Death Mountain Shop', 'Potion Shop']: + if shop in ['Capacity Upgrade', 'Paradox Shop', 'Potion Shop']: continue # near the queen, near potions, and near 7 chests are fine for loc_name in location_list: # other shops are indistinguishable in ER world.get_location(loc_name, player).hint_text = f'for sale' @@ -1144,10 +1144,7 @@ def get_pool_core(world, player, progressive, shuffle, difficulty, treasure_hunt if world.keyshuffle[player] == 'universal': pool.extend(diff.retro) if door_shuffle != 'vanilla': # door shuffle needs more keys for universal keys - replace = 'Rupees (20)' if difficulty == 'normal' else 'Rupees (5)' - indices = [i for i, x in enumerate(pool) if x == replace] - for i in range(0, min(10, len(indices))): - pool[indices[i]] = 'Small Key (Universal)' + pool.extend(['Small Key (Universal)'] * 5) # reduce to 5 for now if mode == 'standard': if door_shuffle == 'vanilla': key_location = random.choice(['Secret Passage', 'Hyrule Castle - Boomerang Chest', 'Hyrule Castle - Map Chest', 'Hyrule Castle - Zelda\'s Chest', 'Sewers - Dark Cross']) diff --git a/KeyDoorShuffle.py b/KeyDoorShuffle.py index 54ebbf23..61b1f377 100644 --- a/KeyDoorShuffle.py +++ b/KeyDoorShuffle.py @@ -1421,7 +1421,7 @@ def prize_relevance(key_layout, dungeon_entrance, is_atgt_swapped): def prize_relevance_sig2(start_regions, d_name, dungeon_entrance, is_atgt_swapped): if len(start_regions) > 1 and dungeon_entrance and dungeon_table[d_name].prize: - if dungeon_entrance.name == ('Agahmins Tower' if is_atgt_swapped else 'Ganons Tower'): + if dungeon_entrance.name == ('Agahnims Tower' if is_atgt_swapped else 'Ganons Tower'): return 'GT' elif dungeon_entrance.name == 'Pyramid Fairy': return 'BigBomb' diff --git a/Main.py b/Main.py index 8d2e5895..52e79490 100644 --- a/Main.py +++ b/Main.py @@ -267,6 +267,7 @@ def main(args, seed=None, fish=None): set_rules(world, player) district_item_pool_config(world) + dungeon_tracking(world) fill_specific_items(world) for player in range(1, world.players + 1): if world.shopsanity[player]: @@ -279,7 +280,6 @@ def main(args, seed=None, fish=None): massage_item_pool(world) if args.print_custom_yaml: world.settings.record_item_pool(world) - dungeon_tracking(world) logger.info(world.fish.translate("cli", "cli", "placing.dungeon.prizes")) fill_prizes(world) diff --git a/OWEdges.py b/OWEdges.py index f5982ee2..813d36c2 100644 --- a/OWEdges.py +++ b/OWEdges.py @@ -1707,8 +1707,8 @@ OWExitTypes = { 'East Death Mountain Teleporter', 'TR Pegs Teleporter', 'Kakariko Teleporter', - 'Top of Pyramid', - 'Top of Pyramid (Inner)', + 'Castle Gate Teleporter', + 'Castle Gate Teleporter (Inner)', 'East Hyrule Teleporter', 'Desert Teleporter', 'South Hyrule Teleporter', diff --git a/OverworldGlitchRules.py b/OverworldGlitchRules.py index dd306ac4..ec8e2fe7 100644 --- a/OverworldGlitchRules.py +++ b/OverworldGlitchRules.py @@ -37,7 +37,7 @@ def get_invalid_mirror_bunny_entrances(): yield 'Hype Cave' yield 'Bonk Fairy (Dark)' yield 'Thieves Town' - yield 'Dark World Hammer Peg Cave' + yield 'Hammer Peg Cave' yield 'Brewery' yield 'Hookshot Cave' yield 'Dark Lake Hylia Ledge Fairy' @@ -359,7 +359,7 @@ boots_clips_local = [ # (name, from_region, to_region) ('Floating Island Clip', 'East Death Mountain (Top East)', 'Death Mountain Floating Island'), ('Floating Island Return Clip', 'Death Mountain Floating Island', 'East Death Mountain (Top East)'), - #('DW Floating Island Clip', 'East Dark Death Mountain (Bottom)', 'Dark Death Mountain Floating Island'), #cannot guarantee camera correction + #('DW Floating Island Clip', 'East Dark Death Mountain (Bottom)', 'Death Mountain Floating Island'), #cannot guarantee camera correction ('EDM East Dropdown Clip', 'East Death Mountain (Top East)', 'East Death Mountain (Bottom Left)'), ('EDM Hammer Bypass Teleport', 'East Death Mountain (Top West)', 'East Death Mountain (Top East)'), ('EDDM West Dropdown Clip', 'East Dark Death Mountain (Top)', 'East Dark Death Mountain (Bottom Left)'), diff --git a/OverworldShuffle.py b/OverworldShuffle.py index a91db720..09128163 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -1506,8 +1506,8 @@ ow_connections = { ('Graveyard Ladder (Bottom)', 'Graveyard Ledge') ]), 0x1b: ([ - ('Top of Pyramid', 'Pyramid Area'), - ('Top of Pyramid (Inner)', 'Pyramid Area') + ('Castle Gate Teleporter', 'Pyramid Area'), + ('Castle Gate Teleporter (Inner)', 'Pyramid Area') ], [ ('Post Aga Inverted Teleporter', 'Hyrule Castle Area') ]), diff --git a/PotShuffle.py b/PotShuffle.py index 152f6756..5378943e 100644 --- a/PotShuffle.py +++ b/PotShuffle.py @@ -788,12 +788,12 @@ vanilla_pots = { 0x108: [Pot(166, 19, PotItem.Chicken, 'Chicken House', obj=RoomObject(0x03EFA9, [0x4F, 0x9F, 0xFA]))], 0x10C: [Pot(88, 14, PotItem.Heart, 'Hookshot Fairy', obj=RoomObject(0x03F329, [0xB3, 0x73, 0xFA]))], # note: these addresses got moved thanks to waterfall fairy edit - 0x114: [Pot(92, 4, PotItem.Heart, 'Dark Desert Hint', obj=RoomObject(0x03F79A, [0xBB, 0x23, 0xFA])), - Pot(96, 4, PotItem.Heart, 'Dark Desert Hint', obj=RoomObject(0x03F79D, [0xC3, 0x23, 0xFA])), - Pot(92, 5, PotItem.Bomb, 'Dark Desert Hint', obj=RoomObject(0x03F7A0, [0xBB, 0x2B, 0xFA])), - Pot(96, 5, PotItem.Bomb, 'Dark Desert Hint', obj=RoomObject(0x03F7A3, [0xC3, 0x2B, 0xFA])), - Pot(92, 10, PotItem.FiveArrows, 'Dark Desert Hint', obj=RoomObject(0x03F7A6, [0xBB, 0x53, 0xFA])), - Pot(96, 10, PotItem.Heart, 'Dark Desert Hint', obj=RoomObject(0x03F7A9, [0xC3, 0x53, 0xFA]))], + 0x114: [Pot(92, 4, PotItem.Heart, 'Mire Hint', obj=RoomObject(0x03F79A, [0xBB, 0x23, 0xFA])), + Pot(96, 4, PotItem.Heart, 'Mire Hint', obj=RoomObject(0x03F79D, [0xC3, 0x23, 0xFA])), + Pot(92, 5, PotItem.Bomb, 'Mire Hint', obj=RoomObject(0x03F7A0, [0xBB, 0x2B, 0xFA])), + Pot(96, 5, PotItem.Bomb, 'Mire Hint', obj=RoomObject(0x03F7A3, [0xC3, 0x2B, 0xFA])), + Pot(92, 10, PotItem.FiveArrows, 'Mire Hint', obj=RoomObject(0x03F7A6, [0xBB, 0x53, 0xFA])), + Pot(96, 10, PotItem.Heart, 'Mire Hint', obj=RoomObject(0x03F7A9, [0xC3, 0x53, 0xFA]))], 0x117: [Pot(138, 3, PotItem.Heart, 'Spike Cave', obj=RoomObject(0x03FCB2, [0x17, 0x1F, 0xFA])), # 0x38A -> 38A Pot(142, 3, PotItem.Heart, 'Spike Cave', obj=RoomObject(0x03FCB8, [0x1F, 0x1F, 0xFA])), Pot(166, 3, PotItem.Heart, 'Spike Cave', obj=RoomObject(0x03FCC1, [0x4F, 0x1F, 0xFA])), @@ -851,10 +851,10 @@ vanilla_pots = { Pot(100, 22, PotItem.Heart, 'Dark Lake Hylia Ledge Spike Cave', obj=RoomObject(0x0AB62A, [0xCB, 0xB3, 0xFA])), Pot(88, 28, PotItem.Heart, 'Dark Lake Hylia Ledge Spike Cave', obj=RoomObject(0x0AB633, [0xB3, 0xE3, 0xFA])), Pot(100, 28, PotItem.Heart, 'Dark Lake Hylia Ledge Spike Cave', obj=RoomObject(0x0AB636, [0xCB, 0xE3, 0xFA]))], - 0x127: [Pot(24, 25, PotItem.Nothing, 'Dark World Hammer Peg Cave', obj=RoomObject(0x2B801A, [0x33, 0xCB, 0xFA])), - Pot(28, 25, PotItem.Nothing, 'Dark World Hammer Peg Cave', obj=RoomObject(0x2B801D, [0x3B, 0xCB, 0xFA])), - Pot(32, 25, PotItem.Nothing, 'Dark World Hammer Peg Cave', obj=RoomObject(0x2B8020, [0x43, 0xCB, 0xFA])), - Pot(36, 25, PotItem.Nothing, 'Dark World Hammer Peg Cave', obj=RoomObject(0x2B8023, [0x4B, 0xCB, 0xFA]))], + 0x127: [Pot(24, 25, PotItem.Nothing, 'Hammer Peg Cave', obj=RoomObject(0x2B801A, [0x33, 0xCB, 0xFA])), + Pot(28, 25, PotItem.Nothing, 'Hammer Peg Cave', obj=RoomObject(0x2B801D, [0x3B, 0xCB, 0xFA])), + Pot(32, 25, PotItem.Nothing, 'Hammer Peg Cave', obj=RoomObject(0x2B8020, [0x43, 0xCB, 0xFA])), + Pot(36, 25, PotItem.Nothing, 'Hammer Peg Cave', obj=RoomObject(0x2B8023, [0x4B, 0xCB, 0xFA]))], } diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 71d39a67..8ee37b73 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -112,6 +112,14 @@ These are now independent of retro mode and have three options: None, Random, an * 1.2.0.14u * Small fix for key logic validation (got rid of a false negative) * Customized doors in ice cross work properly now + * GUI reorganization + * Auto option for pyramid open (trinity or ER + crystals goal) + * World model refactor (combining inverted and normal world models) + * Partitioned fix for lamp logic and links house + * Fix starting flute logic + * Reduced universal keys in pool slightly for non-vanilla dungeons + * Fake world fix finally + * Some extra restrictions on links house placement for lite/lean * 1.2.0.13u * Allow green/blue potion refills to be customized * OW Map showing dungeon entrance at Snitch Lady (West) fixed (instead of @ HC Courtyard) diff --git a/Regions.py b/Regions.py index 4f8e85de..8f46c004 100644 --- a/Regions.py +++ b/Regions.py @@ -62,9 +62,9 @@ def create_regions(world, player): create_lw_region(player, 'Kakariko Southwest', None, ['Kakariko Southwest Bush (South)', 'Light World Bomb Hut']), create_lw_region(player, 'Kakariko Grass Yard', None, ['Kakariko Yard Bush (North)', 'Bush Covered House']), create_lw_region(player, 'Forgotten Forest Area', None, ['Forgotten Forest NW', 'Forgotten Forest NE', 'Forgotten Forest ES']), - create_lw_region(player, 'Hyrule Castle Area', None, ['Hyrule Castle Secret Entrance Drop', 'Hyrule Castle Main Gate (South)', 'Hyrule Castle Inner East Rock', 'Hyrule Castle Southwest Bush (North)', 'Top of Pyramid', 'Hyrule Castle WN', 'Hyrule Castle SE']), + create_lw_region(player, 'Hyrule Castle Area', None, ['Hyrule Castle Secret Entrance Drop', 'Hyrule Castle Main Gate (South)', 'Hyrule Castle Inner East Rock', 'Hyrule Castle Southwest Bush (North)', 'Castle Gate Teleporter', 'Hyrule Castle WN', 'Hyrule Castle SE']), create_lw_region(player, 'Hyrule Castle Southwest', None, ['Hyrule Castle Southwest Bush (South)', 'Hyrule Castle SW']), - create_lw_region(player, 'Hyrule Castle Courtyard', None, ['Hyrule Castle Courtyard Bush (South)', 'Hyrule Castle Main Gate (North)', 'Hyrule Castle Entrance (South)', 'Top of Pyramid (Inner)']), + create_lw_region(player, 'Hyrule Castle Courtyard', None, ['Hyrule Castle Courtyard Bush (South)', 'Hyrule Castle Main Gate (North)', 'Hyrule Castle Entrance (South)', 'Castle Gate Teleporter (Inner)']), create_lw_region(player, 'Hyrule Castle Courtyard Northeast', None, ['Hyrule Castle Courtyard Bush (North)', 'Hyrule Castle Secret Entrance Stairs']), create_lw_region(player, 'Hyrule Castle Ledge', None, ['Hyrule Castle Ledge Drop', 'Hyrule Castle Ledge Courtyard Drop', 'Inverted Pyramid Entrance', 'Hyrule Castle Entrance (West)', 'Agahnims Tower', 'Hyrule Castle Entrance (East)', 'Inverted Pyramid Hole'], 'the castle rampart'), create_lw_region(player, 'Hyrule Castle East Entry', None, ['Hyrule Castle Outer East Rock', 'Hyrule Castle ES']), @@ -111,7 +111,7 @@ def create_regions(world, player): create_lw_region(player, 'C Whirlpool Outer Area', None, ['C Whirlpool Rock (Top)', 'C Whirlpool WC', 'C Whirlpool NW']), create_lw_region(player, 'Statues Area', None, ['Statues Water Entry', 'Light Hype Fairy', 'Statues NC', 'Statues WN', 'Statues WS', 'Statues SC']), create_lw_region(player, 'Statues Water', None, ['Statues Landing', 'Statues WC'], 'Light World', Terrain.Water), - create_lw_region(player, 'Lake Hylia Area', None, ['Lake Hylia Water Drop', 'Lake Hylia Fortune Teller', 'Cave Shop (Lake Hylia)', 'Lake Hylia NW']), + create_lw_region(player, 'Lake Hylia Area', None, ['Lake Hylia Water Drop', 'Lake Hylia Fortune Teller', 'Lake Hylia Shop', 'Lake Hylia NW']), create_lw_region(player, 'Lake Hylia South Shore', None, ['Lake Hylia South Water Drop', 'Mini Moldorm Cave', 'Lake Hylia WS', 'Lake Hylia ES']), create_lw_region(player, 'Lake Hylia Northeast Bank', None, ['Lake Hylia Northeast Water Drop', 'Lake Hylia NE']), create_lw_region(player, 'Lake Hylia Central Island', None, ['Lake Hylia Central Water Drop', 'Capacity Upgrade', 'Lake Hylia Teleporter']), @@ -135,12 +135,12 @@ def create_regions(world, player): create_dw_region(player, 'Skull Woods Forest (West)', None, ['Skull Woods Second Section Hole', 'Skull Woods Second Section Door (West)', 'Skull Woods Final Section'], 'a deep, dark forest'), create_dw_region(player, 'Skull Woods Forgotten Path (Southwest)', None, ['Skull Woods Forgotten Bush (West)', 'Skull Woods SW']), create_dw_region(player, 'Skull Woods Forgotten Path (Northeast)', None, ['Skull Woods Forgotten Bush (East)', 'Skull Woods EN']), - create_dw_region(player, 'Dark Lumberjack Area', None, ['Dark World Lumberjack Shop', 'Dark Lumberjack WN', 'Dark Lumberjack SW']), + create_dw_region(player, 'Dark Lumberjack Area', None, ['Dark Lumberjack Shop', 'Dark Lumberjack WN', 'Dark Lumberjack SW']), create_dw_region(player, 'West Dark Death Mountain (Top)', None, ['Dark Death Mountain Drop (West)', 'GT Entry Approach', 'West Dark Death Mountain EN']), create_dw_region(player, 'GT Approach', None, ['GT Entry Leave', 'Ganons Tower']), create_dw_region(player, 'West Dark Death Mountain (Bottom)', None, ['Spike Cave', 'Dark Death Mountain Fairy', 'Dark Death Mountain Teleporter (West)', 'West Dark Death Mountain ES']), create_dw_region(player, 'East Dark Death Mountain (Top)', None, ['Dark Death Mountain Drop (East)', 'Superbunny Cave (Top)', 'Hookshot Cave', 'East Dark Death Mountain WN', 'East Dark Death Mountain EN']), - create_dw_region(player, 'East Dark Death Mountain (Bottom)', None, ['East Dark Death Mountain Bushes', 'Superbunny Cave (Bottom)', 'Cave Shop (Dark Death Mountain)', 'Dark Death Mountain Teleporter (East)']), + create_dw_region(player, 'East Dark Death Mountain (Bottom)', None, ['East Dark Death Mountain Bushes', 'Superbunny Cave (Bottom)', 'Dark Death Mountain Shop', 'Dark Death Mountain Teleporter (East)']), create_dw_region(player, 'East Dark Death Mountain (Bushes)', None, []), create_dw_region(player, 'East Dark Death Mountain (Bottom Left)', None, ['East Dark Death Mountain WS']), create_dw_region(player, 'Dark Death Mountain Ledge', None, ['Dark Death Mountain Ledge (East)', 'Dark Death Mountain Ledge (West)'], 'a dark ledge'), @@ -164,7 +164,7 @@ def create_regions(world, player): create_dw_region(player, 'Qirn Jump Area', None, ['Qirn Jump Water Drop', 'Qirn Jump WC', 'Qirn Jump SW']), create_dw_region(player, 'Qirn Jump East Bank', None, ['Qirn Jump East Water Drop', 'Qirn Jump SE', 'Qirn Jump EC', 'Qirn Jump ES']), create_dw_region(player, 'Qirn Jump Water', None, ['Qirn Jump Pier', 'Qirn Jump Whirlpool', 'Qirn Jump EN', 'Qirn Jump SC'], 'Dark World', Terrain.Water), - create_dw_region(player, 'Dark Witch Area', None, ['Dark Witch Water Drop', 'Dark Witch Rock (South)', 'Dark World Potion Shop', 'Dark Witch WC', 'Dark Witch WS']), + create_dw_region(player, 'Dark Witch Area', None, ['Dark Witch Water Drop', 'Dark Witch Rock (South)', 'Dark Potion Shop', 'Dark Witch WC', 'Dark Witch WS']), create_dw_region(player, 'Dark Witch Northeast', None, ['Dark Witch Northeast Water Drop', 'Dark Witch Rock (North)', 'Dark Witch EC']), create_dw_region(player, 'Dark Witch Water', None, ['Dark Witch WN', 'Dark Witch EN'], 'Dark World', Terrain.Water), create_dw_region(player, 'Catfish Approach Area', None, ['Catfish Approach Rocks (West)', 'Catfish Approach Bottom Ledge Drop', 'Catfish Approach Water Drop', 'Catfish Approach WC']), @@ -186,7 +186,7 @@ def create_regions(world, player): create_dw_region(player, 'Palace of Darkness Area', None, ['Palace of Darkness Hint', 'Palace of Darkness', 'Palace of Darkness SW', 'Palace of Darkness SE']), create_dw_region(player, 'Darkness Cliff', None, ['Dark Dunes Ledge Drop', 'Hammer Bridge North Ledge Drop', 'Dark Tree Line Ledge Drop', 'Palace of Darkness Ledge Drop']), create_dw_region(player, 'Hammer Pegs Entry', None, ['Peg Area Rocks (West)', 'Hammer Pegs WS']), - create_dw_region(player, 'Hammer Pegs Area', ['Dark Blacksmith Ruins'], ['Peg Area Rocks (East)', 'Dark World Hammer Peg Cave']), + create_dw_region(player, 'Hammer Pegs Area', ['Dark Blacksmith Ruins'], ['Peg Area Rocks (East)', 'Hammer Peg Cave']), create_dw_region(player, 'Dark Dunes Area', None, ['Dark Dunes NW', 'Dark Dunes WN', 'Dark Dunes SC']), create_dw_region(player, 'Dig Game Area', ['Digging Game'], ['Dig Game To Ledge Drop', 'Dig Game ES']), create_dw_region(player, 'Dig Game Ledge', None, ['Dig Game Ledge Drop', 'Dig Game EC']), @@ -205,7 +205,7 @@ def create_regions(world, player): create_dw_region(player, 'Dark Tree Line Area', None, ['Dark Lake Hylia Fairy', 'Dark Tree Line WN', 'Dark Tree Line NW', 'Dark Tree Line SE']), create_dw_region(player, 'Dark Tree Line Water', None, ['Dark Tree Line WC', 'Dark Tree Line SC'], 'Dark World', Terrain.Water), create_dw_region(player, 'Palace of Darkness Nook Area', None, ['East Dark World Hint', 'East Dark World Teleporter', 'Palace of Darkness Nook NE']), - create_dw_region(player, 'Misery Mire Area', None, ['Mire Shed', 'Misery Mire', 'Dark Desert Fairy', 'Dark Desert Hint']), + create_dw_region(player, 'Misery Mire Area', None, ['Mire Shed', 'Misery Mire', 'Mire Fairy', 'Mire Hint']), create_dw_region(player, 'Misery Mire Teleporter Ledge', None, ['Misery Mire Teleporter Ledge Drop', 'Misery Mire Teleporter']), create_dw_region(player, 'Mire Northeast Cliffs', None, ['Mire Cliff Ledge Drop', 'Dark Checkerboard Cliff Ledge Drop', 'Archery Game Cliff Ledge Drop', 'Stumpy Approach Cliff Ledge Drop', 'Mire C Whirlpool Cliff Ledge Drop', 'Swamp Nook Cliff Ledge Drop', 'Swamp Cliff Ledge Drop', 'Mirror To Bombos Tablet Ledge']), create_dw_region(player, 'Stumpy Approach Area', None, ['Stumpy Approach Bush (South)', 'Stumpy Approach NW', 'Stumpy Approach EC']), @@ -246,37 +246,38 @@ def create_regions(world, player): create_cave_region(player, 'Spectacle Rock Cave (Top)', 'a connector', ['Spectacle Rock Cave'], ['Spectacle Rock Cave Drop', 'Spectacle Rock Cave Exit (Top)']), create_cave_region(player, 'Spectacle Rock Cave (Bottom)', 'a connector', None, ['Spectacle Rock Cave Exit']), create_cave_region(player, 'Spectacle Rock Cave (Peak)', 'a connector', None, ['Spectacle Rock Cave Peak Drop', 'Spectacle Rock Cave Exit (Peak)']), - create_cave_region(player, 'Hookshot Fairy', 'fairies deep in a cave'), - create_cave_region(player, 'Paradox Cave Front', 'a connector', None, ['Paradox Cave Push Block Reverse', 'Paradox Cave Exit (Bottom)', 'Light World Death Mountain Shop']), - create_cave_region(player, 'Paradox Cave Chest Area', 'a connector', ['Paradox Cave Lower - Far Left', 'Paradox Cave Lower - Left', 'Paradox Cave Lower - Right', 'Paradox Cave Lower - Far Right', 'Paradox Cave Lower - Middle'], - ['Paradox Cave Push Block', 'Paradox Cave Bomb Jump', 'Paradox Cave Chest Area NE']), - create_cave_region(player, 'Paradox Cave Bomb Area', 'a connector', ['Paradox Cave Upper - Left', 'Paradox Cave Upper - Right']), - create_cave_region(player, 'Paradox Cave', 'a connector', None, ['Paradox Cave Exit (Middle)', 'Paradox Cave Exit (Top)', 'Paradox Cave Drop']), - create_cave_region(player, 'Light World Death Mountain Shop', 'a common shop', ['Paradox Shop - Left', 'Paradox Shop - Middle', 'Paradox Shop - Right']), - create_cave_region(player, 'Fairy Ascension Cave (Bottom)', 'a connector', None, ['Fairy Ascension Cave Climb', 'Fairy Ascension Cave Exit (Bottom)']), - create_cave_region(player, 'Fairy Ascension Cave (Drop)', 'a connector', None, ['Fairy Ascension Cave Pots']), - create_cave_region(player, 'Fairy Ascension Cave (Top)', 'a connector', None, ['Fairy Ascension Cave Exit (Top)', 'Fairy Ascension Cave Drop']), create_cave_region(player, 'Spiral Cave (Top)', 'a connector', ['Spiral Cave'], ['Spiral Cave (top to bottom)', 'Spiral Cave Exit (Top)']), create_cave_region(player, 'Spiral Cave (Bottom)', 'a connector', None, ['Spiral Cave Exit']), create_cave_region(player, 'Mimic Cave', 'Mimic Cave', ['Mimic Cave']), + create_cave_region(player, 'Fairy Ascension Cave (Bottom)', 'a connector', None, ['Fairy Ascension Cave Climb', 'Fairy Ascension Cave Exit (Bottom)']), + create_cave_region(player, 'Fairy Ascension Cave (Drop)', 'a connector', None, ['Fairy Ascension Cave Pots']), + create_cave_region(player, 'Fairy Ascension Cave (Top)', 'a connector', None, ['Fairy Ascension Cave Exit (Top)', 'Fairy Ascension Cave Drop']), + create_cave_region(player, 'Hookshot Fairy', 'fairies deep in a cave'), + create_cave_region(player, 'Paradox Cave Front', 'a connector', None, ['Paradox Cave Push Block Reverse', 'Paradox Cave Exit (Bottom)', 'Paradox Shop']), + create_cave_region(player, 'Paradox Cave Chest Area', 'a connector', ['Paradox Cave Lower - Far Left', 'Paradox Cave Lower - Left', + 'Paradox Cave Lower - Right', 'Paradox Cave Lower - Far Right', 'Paradox Cave Lower - Middle'], + ['Paradox Cave Push Block', 'Paradox Cave Bomb Jump', 'Paradox Cave Chest Area NE']), + create_cave_region(player, 'Paradox Cave Bomb Area', 'a connector', ['Paradox Cave Upper - Left', 'Paradox Cave Upper - Right']), + create_cave_region(player, 'Paradox Cave', 'a connector', None, ['Paradox Cave Exit (Middle)', 'Paradox Cave Exit (Top)', 'Paradox Cave Drop']), + create_cave_region(player, 'Paradox Shop', 'a common shop', ['Paradox Shop - Left', 'Paradox Shop - Middle', 'Paradox Shop - Right']), create_cave_region(player, 'Waterfall of Wishing', 'a cave with two chests', ['Waterfall Fairy - Left', 'Waterfall Fairy - Right']), create_cave_region(player, 'Fortune Teller (Light)', 'a fortune teller'), create_cave_region(player, 'Bonk Rock Cave', 'a cave with a chest', ['Bonk Rock Cave']), - create_dungeon_region(player, 'Sewer Drop', 'a drop\'s exit', None, ['Sewer Drop']), # This exists only to be referenced for access checks + create_dungeon_region(player, 'Sewer Drop', 'a drop\'s exit', None, ['Sewer Drop']), # This exists only to be referenced for access checks create_cave_region(player, 'Graveyard Cave', 'a cave with an item', ['Graveyard Cave']), create_cave_region(player, 'Kings Grave', 'a cave with a chest', ['King\'s Tomb']), create_cave_region(player, 'North Fairy Cave', 'a drop\'s exit', None, ['North Fairy Cave Exit']), create_cave_region(player, 'Potion Shop', 'the potion shop', ['Potion Shop', 'Potion Shop - Left', 'Potion Shop - Middle', 'Potion Shop - Right']), - create_cave_region(player, 'Kakariko Well (top)', 'a drop', ['Kakariko Well - Left', 'Kakariko Well - Middle', 'Kakariko Well - Right', - 'Kakariko Well - Bottom'], ['Kakariko Well (top to bottom)', 'Kakariko Well (top to back)']), + create_cave_region(player, 'Kakariko Well (top)', 'a drop', ['Kakariko Well - Left', 'Kakariko Well - Middle', 'Kakariko Well - Right', 'Kakariko Well - Bottom'], + ['Kakariko Well (top to bottom)', 'Kakariko Well (top to back)']), create_cave_region(player, 'Kakariko Well (back)', 'a drop', ['Kakariko Well - Top']), create_cave_region(player, 'Kakariko Well (bottom)', 'a drop\'s exit', None, ['Kakariko Well Exit']), - create_cave_region(player, 'Blinds Hideout', 'a bounty of five items', ["Blind's Hideout - Left", "Blind's Hideout - Right", - "Blind's Hideout - Far Left", "Blind's Hideout - Far Right"], ['Blinds Hideout N']), + create_cave_region(player, 'Blinds Hideout', 'a bounty of five items', [ "Blind's Hideout - Left", "Blind's Hideout - Right", + "Blind's Hideout - Far Left", "Blind's Hideout - Far Right"], ['Blinds Hideout N']), create_cave_region(player, 'Blinds Hideout (Top)', 'a bounty of five items', ["Blind's Hideout - Top"]), create_cave_region(player, 'Elder House', 'a connector', None, ['Elder House Exit (East)', 'Elder House Exit (West)']), - create_cave_region(player, 'Snitch Lady (West)', 'a boring house'), create_cave_region(player, 'Snitch Lady (East)', 'a boring house'), + create_cave_region(player, 'Snitch Lady (West)', 'a boring house'), create_cave_region(player, 'Chicken House', 'a house with a chest', ['Chicken House']), create_cave_region(player, 'Sick Kids House', 'the sick kid', ['Sick Kid']), create_cave_region(player, 'Bush Covered House', 'the grass man'), @@ -301,60 +302,60 @@ def create_regions(world, player): create_cave_region(player, 'Checkerboard Cave', 'a cave with an item', ['Checkerboard Cave']), create_cave_region(player, 'Aginahs Cave', 'a cave with a chest', ['Aginah\'s Cave']), create_cave_region(player, 'Cave 45', 'a cave with an item', ['Cave 45']), - create_cave_region(player, 'Swamp Healer Fairy', 'a fairy fountain'), + create_cave_region(player, 'Light Hype Fairy', 'a fairy fountain'), create_cave_region(player, 'Lake Hylia Fortune Teller', 'a fortune teller'), - create_cave_region(player, 'Cave Shop (Lake Hylia)', 'a common shop', ['Lake Hylia Shop - Left', 'Lake Hylia Shop - Middle', 'Lake Hylia Shop - Right']), + create_cave_region(player, 'Lake Hylia Shop', 'a common shop', ['Lake Hylia Shop - Left', 'Lake Hylia Shop - Middle', 'Lake Hylia Shop - Right']), create_cave_region(player, 'Capacity Upgrade', 'the queen of fairies', ['Capacity Upgrade - Left', 'Capacity Upgrade - Right']), + create_cave_region(player, 'Mini Moldorm Cave', 'a bounty of five items', ['Mini Moldorm Cave - Far Left', 'Mini Moldorm Cave - Left', + 'Mini Moldorm Cave - Right', 'Mini Moldorm Cave - Far Right', 'Mini Moldorm Cave - Generous Guy']), create_cave_region(player, 'Ice Rod Cave', 'a cave with a chest', ['Ice Rod Cave']), create_cave_region(player, 'Good Bee Cave', 'a cold bee'), create_cave_region(player, '20 Rupee Cave', 'a cave with some cash'), create_cave_region(player, 'Desert Healer Fairy', 'a fairy fountain'), create_cave_region(player, '50 Rupee Cave', 'a cave with some cash'), create_cave_region(player, 'Dam', 'the dam', ['Floodgate', 'Floodgate Chest']), - create_cave_region(player, 'Mini Moldorm Cave', 'a bounty of five items', ['Mini Moldorm Cave - Far Left', 'Mini Moldorm Cave - Left', 'Mini Moldorm Cave - Right', - 'Mini Moldorm Cave - Far Right', 'Mini Moldorm Cave - Generous Guy']), - - create_cave_region(player, 'Dark World Lumberjack Shop', 'a common shop', ['Dark Lumberjack Shop - Left', 'Dark Lumberjack Shop - Middle', 'Dark Lumberjack Shop - Right']), - create_cave_region(player, 'Spike Cave', 'Spike Cave', ['Spike Cave']), + + create_cave_region(player, 'Dark Lumberjack Shop', 'a common shop', ['Dark Lumberjack Shop - Left', 'Dark Lumberjack Shop - Middle', 'Dark Lumberjack Shop - Right']), create_cave_region(player, 'Dark Death Mountain Healer Fairy', 'a fairy fountain'), - create_cave_region(player, 'Hookshot Cave (Front)', 'a connector', None, - ['Hookshot Cave Front to Middle', 'Hookshot Cave Front Exit', 'Hookshot Cave Bonk Path', 'Hookshot Cave Hook Path']), + create_cave_region(player, 'Spike Cave', 'Spike Cave', ['Spike Cave']), + create_cave_region(player, 'Hookshot Cave (Front)', 'a connector', None, ['Hookshot Cave Front Exit', 'Hookshot Cave Front to Middle', + 'Hookshot Cave Bonk Path', 'Hookshot Cave Hook Path']), create_cave_region(player, 'Hookshot Cave (Bonk Islands)', 'a connector', ['Hookshot Cave - Bottom Right']), create_cave_region(player, 'Hookshot Cave (Hook Islands)', 'a connector', ['Hookshot Cave - Top Right', 'Hookshot Cave - Top Left', 'Hookshot Cave - Bottom Left']), - create_cave_region(player, 'Hookshot Cave (Back)', 'a connector', None, ['Hookshot Cave Back to Middle', 'Hookshot Cave Back Exit']), create_cave_region(player, 'Hookshot Cave (Middle)', 'a connector', None, ['Hookshot Cave Middle to Back', 'Hookshot Cave Middle to Front']), + create_cave_region(player, 'Hookshot Cave (Back)', 'a connector', None, ['Hookshot Cave Back to Middle', 'Hookshot Cave Back Exit']), create_cave_region(player, 'Superbunny Cave (Top)', 'a connector', ['Superbunny Cave - Top', 'Superbunny Cave - Bottom'], ['Superbunny Cave Exit (Top)']), create_cave_region(player, 'Superbunny Cave (Bottom)', 'a connector', None, ['Superbunny Cave Climb', 'Superbunny Cave Exit (Bottom)']), - create_cave_region(player, 'Cave Shop (Dark Death Mountain)', 'a common shop', ['Dark Death Mountain Shop - Left', 'Dark Death Mountain Shop - Middle', 'Dark Death Mountain Shop - Right']), + create_cave_region(player, 'Dark Death Mountain Shop', 'a common shop', ['Dark Death Mountain Shop - Left', 'Dark Death Mountain Shop - Middle', 'Dark Death Mountain Shop - Right']), create_cave_region(player, 'Bumper Cave (bottom)', 'a connector', None, ['Bumper Cave Exit (Bottom)', 'Bumper Cave Bottom to Top']), create_cave_region(player, 'Bumper Cave (top)', 'a connector', None, ['Bumper Cave Exit (Top)', 'Bumper Cave Top To Bottom']), create_cave_region(player, 'Fortune Teller (Dark)', 'a fortune teller'), create_cave_region(player, 'Dark Sanctuary Hint', 'a storyteller', None, ['Dark Sanctuary Hint Exit']), - create_cave_region(player, 'Dark World Potion Shop', 'a common shop', ['Dark Potion Shop - Left', 'Dark Potion Shop - Middle', 'Dark Potion Shop - Right']), - create_cave_region(player, 'Village of Outcasts Shop', 'a common shop', ['Village of Outcasts Shop - Left', 'Village of Outcasts Shop - Middle', 'Village of Outcasts Shop - Right']), + create_cave_region(player, 'Dark Potion Shop', 'a common shop', ['Dark Potion Shop - Left', 'Dark Potion Shop - Middle', 'Dark Potion Shop - Right']), create_cave_region(player, 'Chest Game', 'a game of 16 chests', ['Chest Game']), create_cave_region(player, 'C-Shaped House', 'a house with a chest', ['C-Shaped House']), create_cave_region(player, 'Brewery', 'a house with a chest', ['Brewery']), + create_cave_region(player, 'Village of Outcasts Shop', 'a common shop', ['Village of Outcasts Shop - Left', 'Village of Outcasts Shop - Middle', 'Village of Outcasts Shop - Right']), create_cave_region(player, 'Red Shield Shop', 'the rare shop', ['Red Shield Shop - Left', 'Red Shield Shop - Middle', 'Red Shield Shop - Right']), create_cave_region(player, 'Pyramid Fairy', 'a cave with two chests', ['Pyramid Fairy - Left', 'Pyramid Fairy - Right']), create_cave_region(player, 'Pyramid', 'a drop\'s exit', ['Ganon'], ['Ganon Drop']), create_cave_region(player, 'Bottom of Pyramid', 'a drop\'s exit', None, ['Pyramid Exit']), create_cave_region(player, 'Palace of Darkness Hint', 'a storyteller'), - create_cave_region(player, 'Dark World Hammer Peg Cave', 'a cave with an item', ['Peg Cave']), + create_cave_region(player, 'Hammer Peg Cave', 'a cave with an item', ['Peg Cave']), create_cave_region(player, 'Archery Game', 'a game of skill'), create_cave_region(player, 'Bonk Fairy (Dark)', 'a fairy fountain'), create_cave_region(player, 'Big Bomb Shop', 'the bomb shop', ['Big Bomb'], ['Big Bomb Shop Exit']), create_cave_region(player, 'Dark Lake Hylia Healer Fairy', 'a fairy fountain'), create_cave_region(player, 'East Dark World Hint', 'a storyteller'), + create_cave_region(player, 'Mire Shed', 'a cave with two chests', ['Mire Shed - Left', 'Mire Shed - Right']), + create_cave_region(player, 'Mire Healer Fairy', 'a fairy fountain'), + create_cave_region(player, 'Mire Hint', 'a storyteller'), create_cave_region(player, 'Hype Cave', 'a bounty of five items', ['Hype Cave - Top', 'Hype Cave - Middle Right', 'Hype Cave - Middle Left', - 'Hype Cave - Bottom', 'Hype Cave - Generous Guy']), + 'Hype Cave - Bottom', 'Hype Cave - Generous Guy']), create_cave_region(player, 'Dark Lake Hylia Shop', 'a common shop', ['Dark Lake Hylia Shop - Left', 'Dark Lake Hylia Shop - Middle', 'Dark Lake Hylia Shop - Right']), create_cave_region(player, 'Dark Lake Hylia Ledge Healer Fairy', 'a fairy fountain'), create_cave_region(player, 'Dark Lake Hylia Ledge Hint', 'a storyteller'), - create_cave_region(player, 'Dark Lake Hylia Ledge Spike Cave', 'a spiky hint'), - create_cave_region(player, 'Mire Shed', 'a cave with two chests', ['Mire Shed - Left', 'Mire Shed - Right']), - create_cave_region(player, 'Dark Desert Healer Fairy', 'a fairy fountain'), - create_cave_region(player, 'Dark Desert Hint', 'a storyteller') + create_cave_region(player, 'Dark Lake Hylia Ledge Spike Cave', 'a spiky hint') ] @@ -1137,7 +1138,7 @@ def create_shops(world, player): for region_name, (room_id, type, shopkeeper, custom, locked, inventory, sram) in shop_table.items(): if world.mode[player] == 'inverted': if (0x35 not in world.owswaps[player][0] and region_name == 'Dark Lake Hylia Shop') \ - or (0x35 in world.owswaps[player][0] and region_name == 'Cave Shop (Lake Hylia)'): + or (0x35 in world.owswaps[player][0] and region_name == 'Lake Hylia Shop'): locked = True inventory = [('Blue Potion', 160), ('Blue Shield', 50), ('Bombs (10)', 50)] custom = True @@ -1319,16 +1320,16 @@ bonk_table_by_location = {y: x for x, y in bonk_table_by_location_id.items()} _basic_shop_defaults = [('Red Potion', 150), ('Small Heart', 10), ('Bombs (10)', 50)] _dark_world_shop_defaults = [('Red Potion', 150), ('Blue Shield', 50), ('Bombs (10)', 50)] shop_table = { - 'Cave Shop (Dark Death Mountain)': (0x0112, ShopType.Shop, 0xC1, False, False, _basic_shop_defaults, 0), + 'Dark Death Mountain Shop': (0x0112, ShopType.Shop, 0xC1, False, False, _basic_shop_defaults, 0), 'Red Shield Shop': (0x0110, ShopType.Shop, 0xC1, False, False, [('Red Shield', 500), ('Bee', 10), ('Arrows (10)', 30)], 3), 'Dark Lake Hylia Shop': (0x010F, ShopType.Shop, 0xC1, False, False, _dark_world_shop_defaults, 6), - 'Dark World Lumberjack Shop': (0x010F, ShopType.Shop, 0xC1, False, False, _dark_world_shop_defaults, 9), + 'Dark Lumberjack Shop': (0x010F, ShopType.Shop, 0xC1, False, False, _dark_world_shop_defaults, 9), 'Village of Outcasts Shop': (0x010F, ShopType.Shop, 0xC1, False, False, _dark_world_shop_defaults, 12), - 'Dark World Potion Shop': (0x010F, ShopType.Shop, 0xC1, False, False, _dark_world_shop_defaults, 15), - 'Light World Death Mountain Shop': (0x00FF, ShopType.Shop, 0xA0, False, False, _basic_shop_defaults, 18), + 'Dark Potion Shop': (0x010F, ShopType.Shop, 0xC1, False, False, _dark_world_shop_defaults, 15), + 'Paradox Shop': (0x00FF, ShopType.Shop, 0xA0, False, False, _basic_shop_defaults, 18), 'Kakariko Shop': (0x011F, ShopType.Shop, 0xA0, False, False, _basic_shop_defaults, 21), - 'Cave Shop (Lake Hylia)': (0x0112, ShopType.Shop, 0xA0, False, False, _basic_shop_defaults, 24), + 'Lake Hylia Shop': (0x0112, ShopType.Shop, 0xA0, False, False, _basic_shop_defaults, 24), 'Potion Shop': (0x0109, ShopType.Shop, 0xFF, False, True, [('Red Potion', 120), ('Green Potion', 60), ('Blue Potion', 160)], 27), 'Capacity Upgrade': (0x0115, ShopType.UpgradeShop, 0x04, True, True, @@ -1337,15 +1338,15 @@ shop_table = { shop_to_location_table = { - 'Cave Shop (Dark Death Mountain)': ['Dark Death Mountain Shop - Left', 'Dark Death Mountain Shop - Middle', 'Dark Death Mountain Shop - Right'], + 'Dark Death Mountain Shop': ['Dark Death Mountain Shop - Left', 'Dark Death Mountain Shop - Middle', 'Dark Death Mountain Shop - Right'], 'Red Shield Shop': ['Red Shield Shop - Left', 'Red Shield Shop - Middle', 'Red Shield Shop - Right'], 'Dark Lake Hylia Shop': ['Dark Lake Hylia Shop - Left', 'Dark Lake Hylia Shop - Middle', 'Dark Lake Hylia Shop - Right'], - 'Dark World Lumberjack Shop': ['Dark Lumberjack Shop - Left', 'Dark Lumberjack Shop - Middle', 'Dark Lumberjack Shop - Right'], + 'Dark Lumberjack Shop': ['Dark Lumberjack Shop - Left', 'Dark Lumberjack Shop - Middle', 'Dark Lumberjack Shop - Right'], 'Village of Outcasts Shop': ['Village of Outcasts Shop - Left', 'Village of Outcasts Shop - Middle', 'Village of Outcasts Shop - Right'], - 'Dark World Potion Shop': ['Dark Potion Shop - Left', 'Dark Potion Shop - Middle', 'Dark Potion Shop - Right'], - 'Light World Death Mountain Shop': ['Paradox Shop - Left', 'Paradox Shop - Middle', 'Paradox Shop - Right'], + 'Dark Potion Shop': ['Dark Potion Shop - Left', 'Dark Potion Shop - Middle', 'Dark Potion Shop - Right'], + 'Paradox Shop': ['Paradox Shop - Left', 'Paradox Shop - Middle', 'Paradox Shop - Right'], 'Kakariko Shop': ['Kakariko Shop - Left', 'Kakariko Shop - Middle', 'Kakariko Shop - Right'], - 'Cave Shop (Lake Hylia)': ['Lake Hylia Shop - Left', 'Lake Hylia Shop - Middle', 'Lake Hylia Shop - Right'], + 'Lake Hylia Shop': ['Lake Hylia Shop - Left', 'Lake Hylia Shop - Middle', 'Lake Hylia Shop - Right'], 'Potion Shop': ['Potion Shop - Left', 'Potion Shop - Middle', 'Potion Shop - Right'], 'Capacity Upgrade': ['Capacity Upgrade - Left', 'Capacity Upgrade - Right'], } diff --git a/Rom.py b/Rom.py index bc94937e..69d46fda 100644 --- a/Rom.py +++ b/Rom.py @@ -2888,7 +2888,7 @@ InconvenientDungeonEntrances = {'Turtle Rock': 'Turtle Rock Main', InconvenientOtherEntrances = {'Death Mountain Return Cave (West)': 'The SW DM foothills cave', 'Mimic Cave': 'Mimic Ledge', - 'Dark World Hammer Peg Cave': 'The rows of pegs', + 'Hammer Peg Cave': 'The rows of pegs', 'Pyramid Fairy': 'The crack on the pyramid' } @@ -2957,15 +2957,15 @@ ItemEntrances = {'Blinds Hideout': 'Blind\'s old house', 'Chest Game': 'The westmost building in the Village of Outcasts' } -ShopEntrances = {'Cave Shop (Lake Hylia)': 'The cave NW Lake Hylia', +ShopEntrances = {'Lake Hylia Shop': 'The cave NW Lake Hylia', 'Kakariko Shop': 'The old Kakariko shop', 'Capacity Upgrade': 'The cave on the island', 'Dark Lake Hylia Shop': 'The building NW dark Lake Hylia', 'Dark World Shop': 'The hammer sealed building', 'Red Shield Shop': 'The fenced in building', - 'Cave Shop (Dark Death Mountain)': 'The base of east dark DM', - 'Dark World Potion Shop': 'The building near the catfish', - 'Dark World Lumberjack Shop': 'The northmost Dark World building' + 'Dark Death Mountain Shop': 'The base of east dark DM', + 'Dark Potion Shop': 'The building near the catfish', + 'Dark Lumberjack Shop': 'The northmost Dark World building' } OtherEntrances = {'Lake Hylia Fairy': 'A cave NE of Lake Hylia', @@ -2991,12 +2991,12 @@ OtherEntrances = {'Lake Hylia Fairy': 'A cave NE of Lake Hylia', 'Dark Lake Hylia Fairy': 'The cave NE dark Lake Hylia', 'Dark Death Mountain Fairy': 'The SW cave on dark DM', 'East Dark World Hint': 'The dark cave near the eastmost portal', - 'Dark Desert Hint': 'The cave east of the mire', + 'Mire Hint': 'The cave east of the mire', 'Palace of Darkness Hint': 'The building south of Kiki', 'Dark Lake Hylia Ledge Spike Cave': 'The rock SE dark Lake Hylia', 'Archery Game': 'The old archery game', 'Dark Lake Hylia Ledge Hint': 'The open cave SE dark Lake Hylia', - 'Dark Desert Fairy': 'The eastern hut in the mire', + 'Mire Fairy': 'The eastern hut in the mire', 'Dark Lake Hylia Ledge Fairy': 'The sealed cave SE dark Lake Hylia', 'Fortune Teller (Dark)': 'The building NE the Village of Outcasts' } diff --git a/Rules.py b/Rules.py index 99058d17..ad52dc0c 100644 --- a/Rules.py +++ b/Rules.py @@ -21,20 +21,19 @@ def set_rules(world, player): return global_rules(world, player) - default_rules(world, player) ow_inverted_rules(world, player) + if world.swords[player] == 'swordless': + swordless_rules(world, player) + ow_bunny_rules(world, player) - ow_terrain_rules(world, player) if world.mode[player] == 'standard': if not world.is_copied_world: standard_rules(world, player) - elif world.mode[player] == 'open' or world.mode[player] == 'inverted': - open_rules(world, player) else: - raise NotImplementedError('Not implemented yet') + misc_key_rules(world, player) bomb_rules(world, player) pot_rules(world, player) @@ -195,8 +194,11 @@ def global_rules(world, player): #for exit in world.get_region('Flute Sky', player).exits: # exit.hide_path = True + # s&q regions. link's house entrance is set to true so the filler knows the chest inside can always be reached set_rule(world.get_entrance('Old Man S&Q', player), lambda state: state.has('Return Old Man', player)) + set_rule(world.get_entrance('Other World S&Q', player), lambda state: state.has_Mirror(player) and state.has_beaten_aga(player)) + # flute rules set_rule(world.get_entrance('Flute Spot 1', player), lambda state: state.can_flute(player)) set_rule(world.get_entrance('Flute Spot 2', player), lambda state: state.can_flute(player)) set_rule(world.get_entrance('Flute Spot 3', player), lambda state: state.can_flute(player)) @@ -206,6 +208,7 @@ def global_rules(world, player): set_rule(world.get_entrance('Flute Spot 7', player), lambda state: state.can_flute(player)) set_rule(world.get_entrance('Flute Spot 8', player), lambda state: state.can_flute(player)) + # overworld location rules set_rule(world.get_location('Sunken Treasure', player), lambda state: state.has('Open Floodgate', player)) set_rule(world.get_location('Dark Blacksmith Ruins', player), lambda state: state.has('Return Smith', player)) set_rule(world.get_location('Old Man', player), lambda state: state.has('Return Old Man', player)) @@ -216,15 +219,36 @@ def global_rules(world, player): set_rule(world.get_location('Pyramid Crack', player), lambda state: state.has('Pick Up Big Bomb', player)) set_rule(world.get_entrance('Pyramid Crack', player), lambda state: state.has('Detonate Big Bomb', player)) set_rule(world.get_location('Master Sword Pedestal', player), lambda state: state.has('Red Pendant', player) and state.has('Blue Pendant', player) and state.has('Green Pendant', player)) + set_rule(world.get_location('Zora\'s Ledge', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_location('Sunken Treasure', player), lambda state: state.has('Open Floodgate', player)) + set_rule(world.get_location('Flute Spot', player), lambda state: state.has('Shovel', player)) + set_rule(world.get_location('Ether Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player)) + set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player)) + set_rule(world.get_location('Turtle Medallion Pad', player), lambda state: state.has_sword(player) and state.has_turtle_rock_medallion(player)) # sword required to cast magic (!) + # bonk items + if world.shuffle_bonk_drops[player]: + if not world.is_copied_world: + from Regions import bonk_prize_table + for location_name, (_, _, aga_required, _, _, _) in bonk_prize_table.items(): + loc = world.get_location(location_name, player) + if location_name == 'Cold Fairy Statue': + set_rule(loc, lambda state: state.can_use_bombs(player) and state.can_collect_bonkdrops(player)) + elif not aga_required: + set_rule(loc, lambda state: state.can_collect_bonkdrops(player)) + else: + set_rule(loc, lambda state: state.can_collect_bonkdrops(player) and state.has_beaten_aga(player)) + add_bunny_rule(loc, player) + + # underworld location rules + set_rule(world.get_location('Mimic Cave', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_location('Potion Shop', player), lambda state: state.has('Mushroom', player) and state.can_reach('Potion Shop Area', 'Region', player)) set_rule(world.get_location('Missing Smith', player), lambda state: state.has('Get Frog', player)) set_rule(world.get_location('Blacksmith', player), lambda state: state.has('Return Smith', player)) set_rule(world.get_location('Magic Bat', player), lambda state: state.has('Magic Powder', player)) set_rule(world.get_location('Sick Kid', player), lambda state: state.has_bottle(player)) set_rule(world.get_location('Library', player), lambda state: state.has_Boots(player)) - set_rule(world.get_location('Mimic Cave', player), lambda state: state.has('Hammer', player)) set_rule(world.get_location('Sahasrahla', player), lambda state: state.has('Green Pendant', player)) - set_rule(world.get_location('Spike Cave', player), lambda state: state.has('Hammer', player) and state.can_lift_rocks(player) and ((state.has('Cape', player) and state.can_extend_magic(player, 16, True)) or @@ -232,14 +256,101 @@ def global_rules(world, player): (state.can_extend_magic(player, 12, True) or (state.world.can_take_damage and (state.has_Boots(player) or state.has_hearts(player, 4)))))) ) - - set_rule(world.get_location('Hookshot Cave - Top Right', player), lambda state: state.has('Hookshot', player)) - set_rule(world.get_location('Hookshot Cave - Top Left', player), lambda state: state.has('Hookshot', player)) - set_rule(world.get_location('Hookshot Cave - Bottom Right', player), lambda state: state.has('Hookshot', player) or state.has('Pegasus Boots', player)) - set_rule(world.get_location('Hookshot Cave - Bottom Left', player), lambda state: state.has('Hookshot', player)) - + + # underworld rules + set_rule(world.get_entrance('Paradox Cave Push Block Reverse', player), lambda state: state.has_Mirror(player)) # can erase block - overridden in noglitches set_rule(world.get_entrance('Hookshot Cave Bonk Path', player), lambda state: state.has('Hookshot', player) or state.has('Pegasus Boots', player)) set_rule(world.get_entrance('Hookshot Cave Hook Path', player), lambda state: state.has('Hookshot', player)) + set_rule(world.get_entrance('Bumper Cave Bottom to Top', player), lambda state: state.has('Cape', player)) + set_rule(world.get_entrance('Bumper Cave Top To Bottom', player), lambda state: state.has('Cape', player) or state.has('Hookshot', player)) + + # terrain rules + set_rule(world.get_entrance('DM Hammer Bridge (West)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('DM Hammer Bridge (East)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('DM Broken Bridge (West)', player), lambda state: state.has('Hookshot', player)) + set_rule(world.get_entrance('DM Broken Bridge (East)', player), lambda state: state.has('Hookshot', player)) + set_rule(world.get_entrance('Fairy Ascension Rocks (North)', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Fairy Ascension Rocks (South)', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('TR Pegs Ledge Entry', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Mountain Entry Entrance Rock (West)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Mountain Entry Entrance Rock (East)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Lost Woods Pass Hammer (North)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Lost Woods Pass Hammer (South)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Lost Woods Pass Rock (North)', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Lost Woods Pass Rock (South)', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Kings Grave Outer Rocks', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Kings Grave Inner Rocks', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Potion Shop Rock (South)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Potion Shop Rock (North)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Zora Approach Rocks (West)', player), lambda state: state.can_lift_heavy_rocks(player) or state.has_Boots(player)) + set_rule(world.get_entrance('Zora Approach Rocks (East)', player), lambda state: state.can_lift_heavy_rocks(player) or state.has_Boots(player)) + set_rule(world.get_entrance('Hyrule Castle Inner East Rock', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Hyrule Castle Outer East Rock', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Bat Cave Ledge Peg', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Bat Cave Ledge Peg (East)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Desert Palace Statue Move', player), lambda state: state.has('Book of Mudora', player)) + set_rule(world.get_entrance('Desert Ledge Outer Rocks', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Desert Ledge Inner Rocks', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('C Whirlpool Rock (Bottom)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('C Whirlpool Rock (Top)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('C Whirlpool Pegs (Left)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('C Whirlpool Pegs (Right)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Desert Pass Rocks (North)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Desert Pass Rocks (South)', player), lambda state: state.can_lift_rocks(player)) + + set_rule(world.get_entrance('Skull Woods Bush Rock (West)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Skull Woods Bush Rock (East)', player), lambda state: state.can_lift_rocks(player)) + # this more like an ohko rule - dependent on bird being present too - so enemizer could turn this off? + set_rule(world.get_entrance('Bumper Cave Ledge Drop', player), lambda state: (state.has('Cape', player) or state.has('Cane of Byrna', player) or state.has_sword(player))) + set_rule(world.get_entrance('Bumper Cave Entrance Rock', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Skull Woods Pass Rock (North)', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Skull Woods Pass Rock (South)', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Dark Witch Rock (North)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Dark Witch Rock (South)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Catfish Approach Rocks (West)', player), lambda state: state.can_lift_heavy_rocks(player) or state.has_Boots(player)) + set_rule(world.get_entrance('Catfish Approach Rocks (East)', player), lambda state: state.can_lift_heavy_rocks(player) or state.has_Boots(player)) + set_rule(world.get_entrance('Village of Outcasts Pegs', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Grassy Lawn Pegs', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Broken Bridge Hammer Rock (South)', player), lambda state: state.can_lift_rocks(player) or state.has('Hammer', player)) + set_rule(world.get_entrance('Broken Bridge Hammer Rock (North)', player), lambda state: state.can_lift_rocks(player) or state.has('Hammer', player)) + set_rule(world.get_entrance('Broken Bridge Hookshot Gap', player), lambda state: state.has('Hookshot', player)) + set_rule(world.get_entrance('Peg Area Rocks (West)', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Peg Area Rocks (East)', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Dig Game To Ledge Drop', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Frog Rock (Inner)', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Frog Rock (Outer)', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Archery Game Rock (North)', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Archery Game Rock (South)', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Hammer Bridge Pegs (North)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Hammer Bridge Pegs (South)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Dark C Whirlpool Rock (Bottom)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Dark C Whirlpool Rock (Top)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Dark C Whirlpool Pegs (Left)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Dark C Whirlpool Pegs (Right)', player), lambda state: state.has('Hammer', player)) + + # entrance rules + # Caution: If king's grave is relaxed at all to account for reaching it via a two way cave's exit in insanity mode, then the bomb shop logic will need to be updated (that would involve create a small ledge-like Region for it) + # TODO: Not sure if this ^ is true anymore since Kings Grave is its own region now + set_rule(world.get_entrance('Lumberjack Tree Tree', player), lambda state: state.has_Boots(player) and state.has_beaten_aga(player)) + set_rule(world.get_entrance('Bonk Rock Cave', player), lambda state: state.has_Boots(player)) + set_rule(world.get_entrance('Sanctuary Grave', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Kings Grave', player), lambda state: state.has_Boots(player)) + set_rule(world.get_entrance('Bonk Fairy (Light)', player), lambda state: state.has_Boots(player)) + set_rule(world.get_entrance('Checkerboard Cave', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('20 Rupee Cave', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('50 Rupee Cave', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Hookshot Cave', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Hammer Peg Cave', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Bonk Fairy (Dark)', player), lambda state: state.has_Boots(player)) + set_rule(world.get_entrance('Dark Lake Hylia Ledge Spike Cave', player), lambda state: state.can_lift_rocks(player)) + + set_rule(world.get_entrance('Skull Woods Final Section', player), lambda state: state.has('Fire Rod', player)) + set_rule(world.get_entrance('Misery Mire', player), lambda state: state.has_sword(player) and state.has_misery_mire_medallion(player)) # sword required to cast magic (!) + set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has('Turtle Opened', player)) + + if not world.is_atgt_swapped(player): + set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has('Cape', player) or state.has_beam_sword(player)) + set_rule(world.get_entrance('Ganons Tower' if not world.is_atgt_swapped(player) else 'Agahnims Tower', player), lambda state: state.has_crystals(world.crystals_needed_for_gt[player], player)) # Start of door rando rules # TODO: Do these need to flag off when door rando is off? - some of them, yes @@ -682,7 +793,7 @@ def global_rules(world, player): def bomb_rules(world, player): # todo: kak well, pod hint (bonkable pots), hookshot pot, spike cave pots bonkable_doors = ['Two Brothers House Exit (West)', 'Two Brothers House Exit (East)'] # Technically this is incorrectly defined, but functionally the same as what is intended. - bombable_doors = ['Ice Rod Cave', 'Light World Bomb Hut', 'Light World Death Mountain Shop', 'Mini Moldorm Cave', + bombable_doors = ['Ice Rod Cave', 'Light World Bomb Hut', 'Paradox Shop', 'Mini Moldorm Cave', 'Hookshot Cave Back to Middle', 'Hookshot Cave Front to Middle', 'Hookshot Cave Middle to Front', 'Hookshot Cave Middle to Back', 'Dark Lake Hylia Ledge Fairy', 'Hype Cave', 'Brewery', 'Paradox Cave Chest Area NE', 'Blinds Hideout N', 'Kakariko Well (top to back)', @@ -815,7 +926,7 @@ def pot_rules(world, player): (state.has('Cane of Byrna', player) and (state.can_extend_magic(player, 12, True) or (state.world.can_take_damage and (state.has_Boots(player) or state.has_hearts(player, 4))))))) - for l in world.get_region('Dark Desert Hint', player).locations: + for l in world.get_region('Mire Hint', player).locations: if l.type == LocationType.Pot: add_rule(l, lambda state: state.can_use_bombs(player)) for l in world.get_region('Palace of Darkness Hint', player).locations: @@ -845,170 +956,11 @@ def pot_rules(world, player): add_rule(l, lambda state: state.can_hit_crystal(player)) -def default_rules(world, player): - set_rule(world.get_entrance('Other World S&Q', player), lambda state: state.has_Mirror(player) and state.has_beaten_aga(player)) - - # Underworld Logic - set_rule(world.get_entrance('Old Man Cave Exit (West)', player), lambda state: False) # drop cannot be climbed up - set_rule(world.get_entrance('Paradox Cave Push Block Reverse', player), lambda state: state.has_Mirror(player)) # can erase block, overwritten in noglitches - set_rule(world.get_entrance('Bumper Cave Bottom to Top', player), lambda state: state.has('Cape', player)) - set_rule(world.get_entrance('Bumper Cave Top To Bottom', player), lambda state: state.has('Cape', player) or state.has('Hookshot', player)) - set_rule(world.get_entrance('Superbunny Cave Exit (Bottom)', player), lambda state: False) # Cannot get to bottom exit from top. Just exists for shuffling - - # Item Access - set_rule(world.get_location('Zora\'s Ledge', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_location('Potion Shop', player), lambda state: state.has('Mushroom', player)) - set_rule(world.get_location('Flute Spot', player), lambda state: state.has('Shovel', player)) - set_rule(world.get_location('Ether Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player)) - set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player)) - set_rule(world.get_location('Turtle Medallion Pad', player), lambda state: state.has_sword(player) and state.has_turtle_rock_medallion(player)) # sword required to cast magic (!) - - # Bonk Item Access - if world.shuffle_bonk_drops[player]: - if not world.is_copied_world: - from Regions import bonk_prize_table - for location_name, (_, _, aga_required, _, _, _) in bonk_prize_table.items(): - loc = world.get_location(location_name, player) - if location_name == 'Cold Fairy Statue': - set_rule(loc, lambda state: state.can_use_bombs(player) and state.can_collect_bonkdrops(player)) - elif not aga_required: - set_rule(loc, lambda state: state.can_collect_bonkdrops(player)) - else: - set_rule(loc, lambda state: state.can_collect_bonkdrops(player) and state.has_beaten_aga(player)) - add_bunny_rule(loc, player) - - # Entrance Access - set_rule(world.get_entrance('Lumberjack Tree Tree', player), lambda state: state.has_Boots(player) and state.has_beaten_aga(player)) - set_rule(world.get_entrance('Bonk Rock Cave', player), lambda state: state.has_Boots(player)) - set_rule(world.get_entrance('Sanctuary Grave', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Kings Grave', player), lambda state: state.has_Boots(player)) - set_rule(world.get_entrance('Bonk Fairy (Light)', player), lambda state: state.has_Boots(player)) - set_rule(world.get_entrance('Checkerboard Cave', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('50 Rupee Cave', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('20 Rupee Cave', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Skull Woods Final Section', player), lambda state: state.has('Fire Rod', player)) - set_rule(world.get_entrance('Hookshot Cave', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has('Turtle Opened', player)) - set_rule(world.get_entrance('Dark World Hammer Peg Cave', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Bonk Fairy (Dark)', player), lambda state: state.has_Boots(player)) - set_rule(world.get_entrance('Misery Mire', player), lambda state: state.has_sword(player) and state.has_misery_mire_medallion(player)) # sword required to cast magic (!) - set_rule(world.get_entrance('Dark Lake Hylia Ledge Spike Cave', player), lambda state: state.can_lift_rocks(player)) - - # Region Access - set_rule(world.get_entrance('DM Hammer Bridge (West)', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('DM Hammer Bridge (East)', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('DM Broken Bridge (West)', player), lambda state: state.has('Hookshot', player)) - set_rule(world.get_entrance('DM Broken Bridge (East)', player), lambda state: state.has('Hookshot', player)) - set_rule(world.get_entrance('Fairy Ascension Rocks (North)', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Fairy Ascension Rocks (South)', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('TR Pegs Ledge Entry', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('TR Pegs Ledge Leave', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Mountain Entry Entrance Rock (West)', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Mountain Entry Entrance Rock (East)', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Lost Woods Pass Hammer (North)', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Lost Woods Pass Hammer (South)', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Lost Woods Pass Rock (North)', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Lost Woods Pass Rock (South)', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Kings Grave Outer Rocks', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Kings Grave Inner Rocks', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Potion Shop Rock (South)', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Potion Shop Rock (North)', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Zora Approach Rocks (West)', player), lambda state: state.can_lift_heavy_rocks(player) or state.has_Boots(player)) - set_rule(world.get_entrance('Zora Approach Rocks (East)', player), lambda state: state.can_lift_heavy_rocks(player) or state.has_Boots(player)) - set_rule(world.get_entrance('Hyrule Castle Inner East Rock', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Hyrule Castle Outer East Rock', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Bat Cave Ledge Peg', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Bat Cave Ledge Peg (East)', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Desert Palace Statue Move', player), lambda state: state.has('Book of Mudora', player)) - set_rule(world.get_entrance('Desert Ledge Outer Rocks', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Desert Ledge Inner Rocks', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('C Whirlpool Rock (Bottom)', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('C Whirlpool Rock (Top)', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('C Whirlpool Pegs (Left)', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('C Whirlpool Pegs (Right)', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Desert Pass Rocks (North)', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Desert Pass Rocks (South)', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Skull Woods Bush Rock (West)', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Skull Woods Bush Rock (East)', player), lambda state: state.can_lift_rocks(player)) - # this more like an ohko rule - dependent on bird being present too - so enemizer could turn this off? - set_rule(world.get_entrance('Bumper Cave Ledge Drop', player), lambda state: (state.has('Cape', player) or state.has('Cane of Byrna', player) or state.has_sword(player))) - set_rule(world.get_entrance('Bumper Cave Entrance Rock', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Skull Woods Pass Rock (North)', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Skull Woods Pass Rock (South)', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Dark Witch Rock (North)', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Dark Witch Rock (South)', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Catfish Approach Rocks (West)', player), lambda state: state.can_lift_heavy_rocks(player) or state.has_Boots(player)) - set_rule(world.get_entrance('Catfish Approach Rocks (East)', player), lambda state: state.can_lift_heavy_rocks(player) or state.has_Boots(player)) - set_rule(world.get_entrance('Village of Outcasts Pegs', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Grassy Lawn Pegs', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Broken Bridge Hammer Rock (South)', player), lambda state: state.can_lift_rocks(player) or state.has('Hammer', player)) - set_rule(world.get_entrance('Broken Bridge Hammer Rock (North)', player), lambda state: state.can_lift_rocks(player) or state.has('Hammer', player)) - set_rule(world.get_entrance('Broken Bridge Hookshot Gap', player), lambda state: state.has('Hookshot', player)) - set_rule(world.get_entrance('Peg Area Rocks (West)', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Peg Area Rocks (East)', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Dig Game To Ledge Drop', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Frog Rock (Inner)', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Frog Rock (Outer)', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Archery Game Rock (North)', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Archery Game Rock (South)', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Hammer Bridge Pegs (North)', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Hammer Bridge Pegs (South)', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Dark C Whirlpool Rock (Bottom)', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Dark C Whirlpool Rock (Top)', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Dark C Whirlpool Pegs (Left)', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Dark C Whirlpool Pegs (Right)', player), lambda state: state.has('Hammer', player)) - - set_rule(world.get_entrance('Zora Waterfall Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Zora Waterfall Water Entry', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Zora Waterfall Water Approach', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Kakariko Pond Whirlpool', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('River Bend Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('River Bend East Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Potion Shop Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Potion Shop Northeast Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Zora Approach Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Wooden Bridge Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Wooden Bridge Northeast Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('C Whirlpool Water Entry', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Statues Water Entry', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Lake Hylia Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Lake Hylia South Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Lake Hylia Northeast Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Lake Hylia Central Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Lake Hylia Island Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Lake Hylia Water D Leave', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Ice Cave SW', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Octoballoon Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Octoballoon Waterfall Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Qirn Jump Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Qirn Jump East Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Dark Witch Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Dark Witch Northeast Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Catfish Approach Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Broken Bridge Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Broken Bridge Northeast Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Broken Bridge West Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Hammer Bridge Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Dark C Whirlpool Water Entry', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Hype Cave Water Entry', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Ice Lake Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Ice Lake Northeast Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Ice Lake Southwest Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Ice Lake Southeast Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Ice Lake Moat Water Entry', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Shopping Mall SW', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Bomber Corner Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Bomber Corner Waterfall Water Drop', player), lambda state: state.has('Flippers', player)) - - if world.swords[player] == 'swordless': - swordless_rules(world, player) - - def ow_inverted_rules(world, player): if world.is_atgt_swapped(player): set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has_crystals(world.crystals_needed_for_gt[player], player)) else: - set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has('Cape', player) or state.has_beam_sword(player) or state.has_beaten_aga(player)) # barrier gets removed after killing agahnim, relevant for entrance shuffle + set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has('Cape', player) or state.has_beam_sword(player)) # barrier gets removed after killing agahnim, rule for that added later set_rule(world.get_entrance('GT Entry Approach', player), lambda state: state.has_crystals(world.crystals_needed_for_gt[player], player)) set_rule(world.get_entrance('GT Entry Leave', player), lambda state: state.has_crystals(world.crystals_needed_for_gt[player], player) or state.world.shuffle[player] in ('restricted', 'full', 'lite', 'lean', 'crossed', 'insanity')) @@ -1023,6 +975,7 @@ def ow_inverted_rules(world, player): if not world.is_tile_swapped(0x07, player): set_rule(world.get_entrance('TR Pegs Teleporter', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('TR Pegs Ledge Leave', player), lambda state: state.can_lift_heavy_rocks(player)) else: set_rule(world.get_entrance('Turtle Rock Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) set_rule(world.get_entrance('TR Pegs Ledge Drop', player), lambda state: False) @@ -1041,8 +994,8 @@ def ow_inverted_rules(world, player): set_rule(world.get_entrance('Hyrule Castle Main Gate (South)', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Hyrule Castle Main Gate (North)', player), lambda state: state.has_Mirror(player)) - set_rule(world.get_entrance('Top of Pyramid', player), lambda state: state.has_beaten_aga(player)) - set_rule(world.get_entrance('Top of Pyramid (Inner)', player), lambda state: state.has_beaten_aga(player)) + set_rule(world.get_entrance('Castle Gate Teleporter', player), lambda state: state.has_beaten_aga(player)) + set_rule(world.get_entrance('Castle Gate Teleporter (Inner)', player), lambda state: state.has_beaten_aga(player)) else: set_rule(world.get_entrance('Inverted Pyramid Hole', player), lambda state: world.is_pyramid_open(player) or state.has('Beat Agahnim 2', player)) set_rule(world.get_entrance('Pyramid Hole', player), lambda state: False) @@ -1084,6 +1037,7 @@ def ow_inverted_rules(world, player): def ow_bunny_rules(world, player): + # locations add_bunny_rule(world.get_location('Mushroom', player), player) add_bunny_rule(world.get_location('Zora\'s Ledge', player), player) add_bunny_rule(world.get_location('Maze Race', player), player) @@ -1091,6 +1045,7 @@ def ow_bunny_rules(world, player): add_bunny_rule(world.get_location('Turtle Medallion Pad', player), player) add_bunny_rule(world.get_location('Catfish', player), player) + # entrances add_bunny_rule(world.get_entrance('Lost Woods Hideout Drop', player), player) add_bunny_rule(world.get_entrance('Lumberjack Tree Tree', player), player) add_bunny_rule(world.get_entrance('Waterfall of Wishing', player), player) @@ -1101,30 +1056,29 @@ def ow_bunny_rules(world, player): add_bunny_rule(world.get_entrance('Hyrule Castle Secret Entrance Drop', player), player) add_bunny_rule(world.get_entrance('Bonk Fairy (Light)', player), player) add_bunny_rule(world.get_entrance('Checkerboard Cave', player), player) - add_bunny_rule(world.get_entrance('50 Rupee Cave', player), player) add_bunny_rule(world.get_entrance('20 Rupee Cave', player), player) + add_bunny_rule(world.get_entrance('50 Rupee Cave', player), player) + add_bunny_rule(world.get_entrance('Skull Woods First Section Hole (North)', player), player) # bunny cannot lift bush add_bunny_rule(world.get_entrance('Skull Woods Second Section Hole', player), player) # bunny cannot lift bush add_bunny_rule(world.get_entrance('Skull Woods Final Section', player), player) # bunny cannot use fire rod add_bunny_rule(world.get_entrance('Hookshot Cave', player), player) add_bunny_rule(world.get_entrance('Thieves Town', player), player) # bunny cannot pull - add_bunny_rule(world.get_entrance('Brewery', player), player) # bomb required add_bunny_rule(world.get_entrance('Palace of Darkness', player), player) # kiki needs pearl - add_bunny_rule(world.get_entrance('Dark World Hammer Peg Cave', player), player) + add_bunny_rule(world.get_entrance('Hammer Peg Cave', player), player) add_bunny_rule(world.get_entrance('Bonk Fairy (Dark)', player), player) add_bunny_rule(world.get_entrance('Misery Mire', player), player) - add_bunny_rule(world.get_entrance('Hype Cave', player), player) # bomb required - add_bunny_rule(world.get_entrance('Dark Lake Hylia Ledge Fairy', player), player) # bomb required add_bunny_rule(world.get_entrance('Dark Lake Hylia Ledge Spike Cave', player), player) + # terrain add_bunny_rule(world.get_entrance('Lost Woods Bush (West)', player), player) add_bunny_rule(world.get_entrance('Lost Woods Bush (East)', player), player) add_bunny_rule(world.get_entrance('DM Hammer Bridge (West)', player), player) add_bunny_rule(world.get_entrance('DM Hammer Bridge (East)', player), player) - add_bunny_rule(world.get_entrance('Fairy Ascension Rocks (North)', player), player) - add_bunny_rule(world.get_entrance('Fairy Ascension Rocks (South)', player), player) add_bunny_rule(world.get_entrance('DM Broken Bridge (West)', player), player) add_bunny_rule(world.get_entrance('DM Broken Bridge (East)', player), player) + add_bunny_rule(world.get_entrance('Fairy Ascension Rocks (North)', player), player) + add_bunny_rule(world.get_entrance('Fairy Ascension Rocks (South)', player), player) add_bunny_rule(world.get_entrance('TR Pegs Ledge Entry', player), player) add_bunny_rule(world.get_entrance('Mountain Entry Entrance Rock (West)', player), player) add_bunny_rule(world.get_entrance('Mountain Entry Entrance Rock (East)', player), player) @@ -1162,6 +1116,7 @@ def ow_bunny_rules(world, player): add_bunny_rule(world.get_entrance('C Whirlpool Pegs (Right)', player), player) add_bunny_rule(world.get_entrance('Desert Pass Rocks (North)', player), player) add_bunny_rule(world.get_entrance('Desert Pass Rocks (South)', player), player) + add_bunny_rule(world.get_entrance('Skull Woods Bush Rock (West)', player), player) add_bunny_rule(world.get_entrance('Skull Woods Bush Rock (East)', player), player) add_bunny_rule(world.get_entrance('Skull Woods Forgotten Bush (West)', player), player) @@ -1203,6 +1158,73 @@ def ow_bunny_rules(world, player): add_bunny_rule(world.get_entrance('Dark C Whirlpool Pegs (Left)', player), player) add_bunny_rule(world.get_entrance('Dark C Whirlpool Pegs (Right)', player), player) + if not world.is_atgt_swapped(player): + add_bunny_rule(world.get_entrance('Agahnims Tower', player), player) + + #TODO: This needs to get applied after bunny rules, move somewhere else tho + if not world.is_atgt_swapped(player): + add_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has_beaten_aga(player), 'or') # barrier gets removed after killing agahnim, relevant for entrance shuffle + + +def ow_terrain_rules(world, player): + for edge in world.owedges: + if edge.player == player and edge.dest and edge.dest.terrain == Terrain.Water: + ent = world.get_entrance(edge.name, player) + if edge.terrain == Terrain.Land: + set_rule(ent, lambda state: state.has('Flippers', player)) + if ent.parent_region.is_light_world == (world.mode[player] != 'inverted') and ent.connected_region.is_dark_world == (world.mode[player] != 'inverted'): + add_rule(ent, lambda state: state.has_Pearl(player)) + + for whirlpool_name in OWExitTypes['Whirlpool']: + ent = world.get_entrance(whirlpool_name, player) + if ent.parent_region.is_light_world == (world.mode[player] != 'inverted') and ent.connected_region.is_dark_world == (world.mode[player] != 'inverted'): + add_rule(ent, lambda state: state.has_Pearl(player)) + + +def no_glitches_rules(world, player): + set_rule(world.get_entrance('Zora Waterfall Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Zora Waterfall Water Entry', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Zora Waterfall Water Approach', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Kakariko Pond Whirlpool', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('River Bend Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('River Bend East Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Potion Shop Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Potion Shop Northeast Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Zora Approach Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Wooden Bridge Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Wooden Bridge Northeast Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('C Whirlpool Water Entry', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Statues Water Entry', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Lake Hylia Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Lake Hylia South Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Lake Hylia Northeast Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Lake Hylia Central Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Lake Hylia Island Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Lake Hylia Water D Leave', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Ice Cave SW', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Octoballoon Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Octoballoon Waterfall Water Drop', player), lambda state: state.has('Flippers', player)) + + set_rule(world.get_entrance('Qirn Jump Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Qirn Jump East Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Dark Witch Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Dark Witch Northeast Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Catfish Approach Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Broken Bridge Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Broken Bridge Northeast Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Broken Bridge West Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Hammer Bridge Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Dark C Whirlpool Water Entry', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Hype Cave Water Entry', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Ice Lake Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Ice Lake Northeast Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Ice Lake Southwest Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Ice Lake Southeast Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Ice Lake Moat Water Entry', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Shopping Mall SW', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Bomber Corner Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Bomber Corner Waterfall Water Drop', player), lambda state: state.has('Flippers', player)) + add_bunny_rule(world.get_entrance('Zora Waterfall Water Drop', player), player) add_bunny_rule(world.get_entrance('Zora Waterfall Water Entry', player), player) add_bunny_rule(world.get_entrance('Zora Waterfall Water Approach', player), player) @@ -1225,6 +1247,7 @@ def ow_bunny_rules(world, player): add_bunny_rule(world.get_entrance('Ice Cave SW', player), player) add_bunny_rule(world.get_entrance('Octoballoon Water Drop', player), player) add_bunny_rule(world.get_entrance('Octoballoon Waterfall Water Drop', player), player) + add_bunny_rule(world.get_entrance('Qirn Jump Water Drop', player), player) add_bunny_rule(world.get_entrance('Qirn Jump East Water Drop', player), player) add_bunny_rule(world.get_entrance('Dark Witch Water Drop', player), player) @@ -1246,23 +1269,7 @@ def ow_bunny_rules(world, player): add_bunny_rule(world.get_entrance('Bomber Corner Waterfall Water Drop', player), player) -def ow_terrain_rules(world, player): - for edge in world.owedges: - if edge.player == player and edge.dest and edge.dest.terrain == Terrain.Water: - ent = world.get_entrance(edge.name, player) - if edge.terrain == Terrain.Land: - set_rule(ent, lambda state: state.has('Flippers', player)) - if ent.parent_region.is_light_world == (world.mode[player] != 'inverted') and ent.connected_region.is_dark_world == (world.mode[player] != 'inverted'): - add_rule(ent, lambda state: state.has_Pearl(player)) - - for whirlpool_name in OWExitTypes['Whirlpool']: - ent = world.get_entrance(whirlpool_name, player) - if ent.parent_region.is_light_world == (world.mode[player] != 'inverted') and ent.connected_region.is_dark_world == (world.mode[player] != 'inverted'): - add_rule(ent, lambda state: state.has_Pearl(player)) - - -def no_glitches_rules(world, player): - # todo: move some dungeon rules to no glictes logic - see these for examples + # todo: move some dungeon rules to no glicthes logic - see these for examples # add_rule(world.get_entrance('Ganons Tower (Hookshot Room)', player), lambda state: state.has('Hookshot', player) or state.has_Boots(player)) # add_rule(world.get_entrance('Ganons Tower (Double Switch Room)', player), lambda state: state.has('Hookshot', player)) # DMs_room_chests = ['Ganons Tower - DMs Room - Top Left', 'Ganons Tower - DMs Room - Top Right', 'Ganons Tower - DMs Room - Bottom Left', 'Ganons Tower - DMs Room - Bottom Right'] @@ -1294,6 +1301,7 @@ def fake_flipper_rules(world, player): set_rule(world.get_entrance('Hype Cave Water Entry', player), lambda state: True) set_rule(world.get_entrance('Ice Lake Southeast Water Drop', player), lambda state: True) set_rule(world.get_entrance('Bomber Corner Water Drop', player), lambda state: True) + add_bunny_rule(world.get_entrance('Zora Waterfall Water Approach', player), player) add_bunny_rule(world.get_entrance('River Bend Water Drop', player), player) add_bunny_rule(world.get_entrance('River Bend East Water Drop', player), player) @@ -1320,6 +1328,7 @@ def forbid_bomb_jump_requirements(world, player): for location in DMs_room_chests: add_rule(world.get_location(location, player), lambda state: state.has('Hookshot', player)) set_rule(world.get_entrance('Paradox Cave Bomb Jump', player), lambda state: False) + set_rule(world.get_entrance('Ice Lake Northeast Pier Hop', player), lambda state: False) def add_conditional_lamps(world, player): def add_conditional_lamp(spot, spottype='Location'): @@ -1376,9 +1385,9 @@ def add_conditional_lamps(world, player): is_dark = False if not world.sewer_light_cone[player]: is_dark = True - elif world.doorShuffle[player] not in ['partitioned', 'crossed'] and not info['sewer']: + elif world.doorShuffle[player] not in ['crossed', 'partitioned'] and not info['sewer']: is_dark = True - elif world.doorShuffle[player] in ['partitioned', 'crossed']: + elif world.doorShuffle[player] in ['crossed', 'partitioned']: sewer_builder = world.dungeon_layouts[player]['Hyrule Castle'] is_dark = region not in sewer_builder.master_sector.region_set() if is_dark: @@ -1392,7 +1401,8 @@ def add_conditional_lamps(world, player): add_conditional_lamp('Old Man House Front to Back', 'Entrance') -def open_rules(world, player): + +def misc_key_rules(world, player): # softlock protection as you can reach the sewers small key door with a guard drop key set_rule(world.get_location('Hyrule Castle - Boomerang Chest', player), lambda state: state.has_sm_key('Small Key (Escape)', player)) set_rule(world.get_location('Hyrule Castle - Zelda\'s Chest', player), lambda state: state.has_sm_key('Small Key (Escape)', player)) @@ -1408,14 +1418,13 @@ def swordless_rules(world, player): set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has('Hammer', player)) set_rule(world.get_location('Ganon', player), lambda state: state.has('Hammer', player) and state.has_fire_source(player) and state.has('Silver Arrows', player) and state.can_shoot_arrows(player) and state.has_crystals(world.crystals_needed_for_ganon[player], player)) set_rule(world.get_entrance('Ganon Drop', player), lambda state: state.has('Hammer', player)) # need to damage ganon to get tiles to drop - - if not world.is_atgt_swapped(player): - set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has('Cape', player) or state.has('Hammer', player) or state.has_beaten_aga(player)) # barrier gets removed after killing agahnim, relevant for entrance shuffle set_rule(world.get_entrance('Misery Mire', player), lambda state: state.has_misery_mire_medallion(player)) # sword not required to use medallion for opening in swordless (!) set_rule(world.get_location('Turtle Medallion Pad', player), lambda state: state.has_turtle_rock_medallion(player)) # sword not required to use medallion for opening in swordless (!) - add_bunny_rule(world.get_entrance('Misery Mire', player), player) - add_bunny_rule(world.get_location('Turtle Medallion Pad', player), player) + + if not world.is_atgt_swapped(player): + set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has('Cape', player) or state.has('Hammer', player)) # barrier gets removed after killing agahnim, rule for that added later + std_kill_rooms = { 'Hyrule Dungeon Armory Main': ['Hyrule Dungeon Armory S', 'Hyrule Dungeon Armory ES'], # One green guard @@ -1563,11 +1572,11 @@ def set_bunny_rules(world, player, inverted): bunny_impassable_caves = ['Bumper Cave (top)', 'Bumper Cave (bottom)', 'Two Brothers House', 'Hookshot Cave (Middle)', 'Pyramid', 'Spiral Cave (Top)', 'Fairy Ascension Cave (Drop)'] bunny_accessible_locations = ['Link\'s Uncle', 'Sahasrahla', 'Sick Kid', 'Lost Woods Hideout', 'Lumberjack Tree', - 'Checkerboard Cave', 'Potion Shop', 'Spectacle Rock Cave', 'Pyramid', - 'Hype Cave - Generous Guy', 'Peg Cave', 'Bumper Cave Ledge', 'Old Man', - 'Frog', 'Missing Smith', 'Dark Blacksmith Ruins', 'Purple Chest', 'Pyramid Crack', 'Big Bomb', - 'Spectacle Rock', 'Bombos Tablet', 'Ether Tablet', 'Blacksmith', 'Stumpy', - 'Master Sword Pedestal', 'Bottle Merchant', 'Sunken Treasure', 'Desert Ledge', + 'Checkerboard Cave', 'Potion Shop', 'Spectacle Rock Cave', 'Pyramid', 'Old Man', + 'Hype Cave - Generous Guy', 'Peg Cave', 'Bumper Cave Ledge', 'Dark Blacksmith Ruins', + 'Spectacle Rock', 'Bombos Tablet', 'Ether Tablet', 'Purple Chest', 'Blacksmith', + 'Missing Smith', 'Master Sword Pedestal', 'Bottle Merchant', 'Sunken Treasure', 'Desert Ledge', + 'Pyramid Crack', 'Big Bomb', 'Stumpy', 'Lost Old Man', 'Old Man Drop Off', 'Kakariko Shop - Left', 'Kakariko Shop - Middle', 'Kakariko Shop - Right', 'Lake Hylia Shop - Left', 'Lake Hylia Shop - Middle', 'Lake Hylia Shop - Right', 'Potion Shop - Left', 'Potion Shop - Middle', 'Potion Shop - Right', @@ -1687,7 +1696,7 @@ def set_bunny_rules(world, player, inverted): for ext in region.exits: add_rule(ext, rule) - paradox_shop = world.get_region('Light World Death Mountain Shop', player) + paradox_shop = world.get_region('Paradox Shop', player) if is_bunny(paradox_shop): add_rule(paradox_shop.entrances[0], get_rule_to_add(paradox_shop)) diff --git a/resources/app/gui/lang/en.json b/resources/app/gui/lang/en.json index feadd457..0299c2f5 100644 --- a/resources/app/gui/lang/en.json +++ b/resources/app/gui/lang/en.json @@ -358,7 +358,6 @@ "randomizer.item.itempool.normal": "Normal", "randomizer.item.itempool.hard": "Hard", "randomizer.item.itempool.expert": "Expert", - "randomizer.item.flute_mode": "Flute Mode", "randomizer.item.flute_mode.normal": "Normal", "randomizer.item.flute_mode.active": "Pre-Activated", diff --git a/resources/app/gui/randomize/entrando/widgets.json b/resources/app/gui/randomize/entrando/widgets.json index adc16d18..a3104bf1 100644 --- a/resources/app/gui/randomize/entrando/widgets.json +++ b/resources/app/gui/randomize/entrando/widgets.json @@ -33,7 +33,7 @@ "padx": [20,0] } }, - "openpyramid": { + "openpyramid": { "type": "selectbox", "options": [ "auto", diff --git a/source/classes/constants.py b/source/classes/constants.py index 19b93027..999e17ed 100644 --- a/source/classes/constants.py +++ b/source/classes/constants.py @@ -80,7 +80,7 @@ SETTINGSTOPROCESS = { "dropshuffle": "dropshuffle", "keydropshuffle": "keydropshuffle", "take_any": "take_any", - + "itempool": "difficulty", "flute_mode": "flute_mode", "bow_mode": "bow_mode", @@ -118,7 +118,7 @@ SETTINGSTOPROCESS = { "experimental": "experimental", "dungeon_counters": "dungeon_counters", "mixed_travel": "mixed_travel", - "standardize_palettes": "standardize_palettes" + "standardize_palettes": "standardize_palettes", }, "enemizer": { "enemyshuffle": "shuffleenemies", diff --git a/source/item/District.py b/source/item/District.py index 3cd58a1f..113f2d18 100644 --- a/source/item/District.py +++ b/source/item/District.py @@ -119,7 +119,7 @@ def resolve_districts(world): if not location.item and location.real: district.locations.add(location.name) for ext in region.exits: - if ext.connected_region is not None and ext.connected_region not in visited: + if ext.connected_region and ext.connected_region not in visited: queue.appendleft(ext.connected_region) elif region.type == RegionType.Dungeon and region.dungeon: district.dungeons.add(region.dungeon.name) @@ -138,10 +138,10 @@ def find_reachable_locations(state, player): return check_set -inaccessible_regions_std = {'Desert Palace Stairs', 'Bumper Cave Ledge', 'Skull Woods Forest (West)', +inaccessible_regions_std = {'Desert Palace Mouth', 'Bumper Cave Ledge', 'Skull Woods Forest (West)', 'Dark Death Mountain Ledge', 'Dark Death Mountain Isolated Ledge', - 'Dark Death Mountain Floating Island'} + 'Death Mountain Floating Island'} -inaccessible_regions_inv = {'Desert Palace Stairs', 'Maze Race Ledge', 'Desert Ledge', +inaccessible_regions_inv = {'Desert Palace Mouth', 'Maze Race Ledge', 'Desert Ledge', 'Desert Palace Entrance (North) Spot', 'Hyrule Castle Ledge', 'Mountain Entry Ledge'} diff --git a/source/item/FillUtil.py b/source/item/FillUtil.py index 1ed455b3..fc2e063f 100644 --- a/source/item/FillUtil.py +++ b/source/item/FillUtil.py @@ -221,7 +221,7 @@ def district_item_pool_config(world): scale_factors = defaultdict(int) scale_total = 0 for p in range(1, world.players + 1): - ent = 'Agahnims Tower' if world.is_atgt_swapped(player) else 'Ganons Tower' + ent = 'Agahnims Tower' if world.is_atgt_swapped(p) else 'Ganons Tower' dungeon = world.get_entrance(ent, p).connected_region.dungeon if dungeon: scale = world.crystals_needed_for_gt[p] diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index d456f64e..ff0f4d87 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -499,9 +499,6 @@ def do_links_house(entrances, exits, avail, cross_world): if not avail.world.shufflelinks[avail.player]: links_house = 'Big Bomb Shop' if avail.world.is_bombshop_start(avail.player) else 'Links House' else: - # lobby shuffle means you ought to keep links house in the same world - sanc_spawn_can_be_dark = (not avail.inverted and avail.world.doorShuffle[avail.player] == 'crossed' - and avail.world.intensity[avail.player] >= 3) entrance_pool = entrances if avail.coupled else avail.decoupled_entrances forbidden = list(Isolated_LH_Doors) @@ -512,10 +509,10 @@ def do_links_house(entrances, exits, avail, cross_world): if avail.inverted: dark_sanc_region = avail.world.get_entrance('Dark Sanctuary Hint Exit', avail.player).connected_region.name forbidden.extend(get_nearby_entrances(avail, dark_sanc_region)) - - if avail.world.owShuffle[avail.player] == 'vanilla': + shuffle_mode = avail.world.shuffle[avail.player] + if shuffle_mode == 'vanilla': # simple shuffle - - if avail.world.shuffle[avail.player] == 'simple': + if shuffle_mode == 'simple': avail.links_on_mountain = True # taken care of by the logic below if avail.world.is_tile_swapped(0x03, avail.player): # in inverted, links house cannot be on the mountain forbidden.extend(['Spike Cave', 'Dark Death Mountain Fairy', 'Hookshot Fairy']) @@ -528,16 +525,21 @@ def do_links_house(entrances, exits, avail, cross_world): # can't have links house on eddm in restricted because Inverted Aga Tower isn't available # todo: inverted full may have the same problem if both links house and a mandatory connector is chosen # from the 3 inverted options - if avail.world.shuffle[avail.player] in ['restricted', 'lite', 'lean'] and avail.world.is_tile_swapped(0x03, avail.player): + if shuffle_mode == 'restricted' and avail.world.is_tile_swapped(0x03, avail.player): avail.links_on_mountain = True forbidden.extend(['Spike Cave', 'Dark Death Mountain Fairy']) - if avail.world.shuffle[avail.player] in ['lite', 'lean']: + if shuffle_mode in ['lite', 'lean']: + forbidden.extend(['Spike Cave', 'Mire Shed']) if avail.world.is_tile_swapped(0x05, avail.player): avail.links_on_mountain = True - forbidden.extend(['Cave Shop (Dark Death Mountain)']) + forbidden.extend(['Dark Death Mountain Shop']) else: avail.links_on_mountain = True + + # lobby shuffle means you ought to keep links house in the same world + sanc_spawn_can_be_dark = (not avail.inverted and avail.world.doorShuffle[avail.player] in ['partitioned', 'crossed'] + and avail.world.intensity[avail.player] >= 3) if cross_world and not sanc_spawn_can_be_dark: possible = [e for e in entrance_pool if e not in forbidden] @@ -1350,8 +1352,7 @@ inverted_sub_table = { 'Pyramid Entrance': 'Inverted Pyramid Entrance' } -inverted_exit_sub_table = { -} +inverted_exit_sub_table = { } def inverted_substitution(avail_pool, collection, is_entrance, is_set=False): @@ -1570,18 +1571,18 @@ modes = { 'fixed_non_items': { 'special': 'vanilla', 'condition': '', - 'entrances': ['Dark Desert Fairy', 'Archery Game', 'Fortune Teller (Dark)', 'Dark Sanctuary Hint', + 'entrances': ['Mire Fairy', 'Archery Game', 'Fortune Teller (Dark)', 'Dark Sanctuary Hint', 'Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Fairy', 'Dark Lake Hylia Shop', 'East Dark World Hint', 'Kakariko Gamble Game', 'Long Fairy Cave', 'Bush Covered House', 'Fortune Teller (Light)', 'Lost Woods Gamble', - 'Lake Hylia Fortune Teller', 'Lake Hylia Fairy', 'Bonk Fairy (Light)', 'Inverted Dark Sanctuary'], + 'Lake Hylia Fortune Teller', 'Lake Hylia Fairy', 'Bonk Fairy (Light)'], }, 'fixed_shops': { 'special': 'vanilla', 'condition': 'shopsanity', - 'entrances': ['Cave Shop (Dark Death Mountain)', 'Dark World Potion Shop', 'Dark World Lumberjack Shop', + 'entrances': ['Dark Death Mountain Shop', 'Dark Potion Shop', 'Dark Lumberjack Shop', 'Dark World Shop', 'Red Shield Shop', 'Kakariko Shop', 'Capacity Upgrade', - 'Cave Shop (Lake Hylia)'], + 'Lake Hylia Shop'], }, 'fixed_takeanys': { 'special': 'vanilla', @@ -1595,7 +1596,7 @@ modes = { 'entrances': ['Lumberjack House', 'Snitch Lady (West)', 'Snitch Lady (East)', 'Tavern (Front)', 'Light World Bomb Hut', '20 Rupee Cave', '50 Rupee Cave', 'Hookshot Fairy', 'Palace of Darkness Hint', 'Dark Lake Hylia Ledge Spike Cave', - 'Dark Desert Hint'] + 'Mire Hint'] }, 'fixed_bonk': { 'special': 'vanilla', @@ -1603,18 +1604,18 @@ modes = { 'entrances': ['Good Bee Cave'] }, 'item_caves': { # shuffles shops/pottery if they weren't fixed in the last steps - 'entrances': ['Mimic Cave', 'Spike Cave', 'Mire Shed', 'Dark World Hammer Peg Cave', 'Chest Game', + 'entrances': ['Mimic Cave', 'Spike Cave', 'Mire Shed', 'Hammer Peg Cave', 'Chest Game', 'C-Shaped House', 'Brewery', 'Hype Cave', 'Big Bomb Shop', 'Pyramid Fairy', 'Ice Rod Cave', 'Dam', 'Bonk Rock Cave', 'Library', 'Potion Shop', 'Mini Moldorm Cave', 'Checkerboard Cave', 'Graveyard Cave', 'Cave 45', 'Sick Kids House', 'Blacksmiths Hut', 'Sahasrahlas Hut', 'Aginahs Cave', 'Chicken House', 'Kings Grave', 'Blinds Hideout', - 'Waterfall of Wishing', 'Cave Shop (Dark Death Mountain)', 'Good Bee Cave', - 'Dark World Potion Shop', 'Dark World Lumberjack Shop', 'Dark World Shop', - 'Red Shield Shop', 'Kakariko Shop', 'Capacity Upgrade', 'Cave Shop (Lake Hylia)', + 'Waterfall of Wishing', 'Dark Death Mountain Shop', 'Good Bee Cave', + 'Dark Potion Shop', 'Dark Lumberjack Shop', 'Dark World Shop', + 'Red Shield Shop', 'Kakariko Shop', 'Capacity Upgrade', 'Lake Hylia Shop', 'Lumberjack House', 'Snitch Lady (West)', 'Snitch Lady (East)', 'Tavern (Front)', 'Light World Bomb Hut', '20 Rupee Cave', '50 Rupee Cave', 'Hookshot Fairy', 'Palace of Darkness Hint', 'Dark Lake Hylia Ledge Spike Cave', - 'Dark Desert Hint', 'Desert Fairy', 'Light Hype Fairy', 'Dark Death Mountain Fairy', + 'Mire Hint', 'Desert Fairy', 'Light Hype Fairy', 'Dark Death Mountain Fairy', 'Dark Lake Hylia Ledge Fairy', 'Bonk Fairy (Dark)', 'Links House', 'Tavern North'] }, @@ -1661,18 +1662,18 @@ modes = { 'fixed_non_items': { 'special': 'vanilla', 'condition': '', - 'entrances': ['Dark Desert Fairy', 'Archery Game', 'Fortune Teller (Dark)', 'Dark Sanctuary Hint', + 'entrances': ['Mire Fairy', 'Archery Game', 'Fortune Teller (Dark)', 'Dark Sanctuary Hint', 'Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Fairy', 'Dark Lake Hylia Shop', 'East Dark World Hint', 'Kakariko Gamble Game', 'Long Fairy Cave', 'Bush Covered House', 'Fortune Teller (Light)', 'Lost Woods Gamble', - 'Lake Hylia Fortune Teller', 'Lake Hylia Fairy', 'Bonk Fairy (Light)', 'Inverted Dark Sanctuary'], + 'Lake Hylia Fortune Teller', 'Lake Hylia Fairy', 'Bonk Fairy (Light)'], }, 'fixed_shops': { 'special': 'vanilla', 'condition': 'shopsanity', - 'entrances': ['Cave Shop (Dark Death Mountain)', 'Dark World Potion Shop', 'Dark World Lumberjack Shop', + 'entrances': ['Dark Death Mountain Shop', 'Dark Potion Shop', 'Dark Lumberjack Shop', 'Dark World Shop', 'Red Shield Shop', 'Kakariko Shop', 'Capacity Upgrade', - 'Cave Shop (Lake Hylia)'], + 'Lake Hylia Shop'], }, 'fixed_takeanys': { 'special': 'vanilla', @@ -1686,7 +1687,7 @@ modes = { 'entrances': ['Lumberjack House', 'Snitch Lady (West)', 'Snitch Lady (East)', 'Tavern (Front)', 'Light World Bomb Hut', '20 Rupee Cave', '50 Rupee Cave', 'Hookshot Fairy', 'Palace of Darkness Hint', 'Dark Lake Hylia Ledge Spike Cave', - 'Dark Desert Hint'] + 'Mire Hint'] }, 'fixed_bonk': { 'special': 'vanilla', @@ -1694,18 +1695,18 @@ modes = { 'entrances': ['Good Bee Cave'] }, 'item_caves': { # shuffles shops/pottery if they weren't fixed in the last steps - 'entrances': ['Mimic Cave', 'Spike Cave', 'Mire Shed', 'Dark World Hammer Peg Cave', 'Chest Game', + 'entrances': ['Mimic Cave', 'Spike Cave', 'Mire Shed', 'Hammer Peg Cave', 'Chest Game', 'C-Shaped House', 'Brewery', 'Hype Cave', 'Big Bomb Shop', 'Pyramid Fairy', 'Ice Rod Cave', 'Dam', 'Bonk Rock Cave', 'Library', 'Potion Shop', 'Mini Moldorm Cave', 'Checkerboard Cave', 'Graveyard Cave', 'Cave 45', 'Sick Kids House', 'Blacksmiths Hut', 'Sahasrahlas Hut', 'Aginahs Cave', 'Chicken House', 'Kings Grave', 'Blinds Hideout', - 'Waterfall of Wishing', 'Cave Shop (Dark Death Mountain)', 'Good Bee Cave', - 'Dark World Potion Shop', 'Dark World Lumberjack Shop', 'Dark World Shop', - 'Red Shield Shop', 'Kakariko Shop', 'Capacity Upgrade', 'Cave Shop (Lake Hylia)', + 'Waterfall of Wishing', 'Dark Death Mountain Shop', 'Good Bee Cave', + 'Dark Potion Shop', 'Dark Lumberjack Shop', 'Dark World Shop', + 'Red Shield Shop', 'Kakariko Shop', 'Capacity Upgrade', 'Lake Hylia Shop', 'Lumberjack House', 'Snitch Lady (West)', 'Snitch Lady (East)', 'Tavern (Front)', 'Light World Bomb Hut', '20 Rupee Cave', '50 Rupee Cave', 'Hookshot Fairy', 'Palace of Darkness Hint', 'Dark Lake Hylia Ledge Spike Cave', - 'Dark Desert Hint', 'Desert Fairy', 'Light Hype Fairy', 'Dark Death Mountain Fairy', + 'Mire Hint', 'Desert Fairy', 'Light Hype Fairy', 'Dark Death Mountain Fairy', 'Dark Lake Hylia Ledge Fairy', 'Bonk Fairy (Dark)', 'Links House', 'Tavern North'] # inverted links house gets substituted } @@ -1963,12 +1964,12 @@ entrance_map = { single_entrance_map = { 'Mimic Cave': 'Mimic Cave', 'Dark Death Mountain Fairy': 'Dark Death Mountain Healer Fairy', - 'Cave Shop (Dark Death Mountain)': 'Cave Shop (Dark Death Mountain)', 'Spike Cave': 'Spike Cave', - 'Dark Desert Fairy': 'Dark Desert Healer Fairy', 'Dark Desert Hint': 'Dark Desert Hint', 'Mire Shed': 'Mire Shed', - 'Archery Game': 'Archery Game', 'Dark World Potion Shop': 'Dark World Potion Shop', - 'Dark World Lumberjack Shop': 'Dark World Lumberjack Shop', 'Dark World Shop': 'Village of Outcasts Shop', + 'Dark Death Mountain Shop': 'Dark Death Mountain Shop', 'Spike Cave': 'Spike Cave', + 'Mire Fairy': 'Mire Healer Fairy', 'Mire Hint': 'Mire Hint', 'Mire Shed': 'Mire Shed', + 'Archery Game': 'Archery Game', 'Dark Potion Shop': 'Dark Potion Shop', + 'Dark Lumberjack Shop': 'Dark Lumberjack Shop', 'Dark World Shop': 'Village of Outcasts Shop', 'Fortune Teller (Dark)': 'Fortune Teller (Dark)', 'Dark Sanctuary Hint': 'Dark Sanctuary Hint', - 'Red Shield Shop': 'Red Shield Shop', 'Dark World Hammer Peg Cave': 'Dark World Hammer Peg Cave', + 'Red Shield Shop': 'Red Shield Shop', 'Hammer Peg Cave': 'Hammer Peg Cave', 'Chest Game': 'Chest Game', 'C-Shaped House': 'C-Shaped House', 'Brewery': 'Brewery', 'Bonk Fairy (Dark)': 'Bonk Fairy (Dark)', 'Hype Cave': 'Hype Cave', 'Dark Lake Hylia Ledge Hint': 'Dark Lake Hylia Ledge Hint', @@ -1987,9 +1988,9 @@ single_entrance_map = { 'Snitch Lady (West)': 'Snitch Lady (West)', 'Snitch Lady (East)': 'Snitch Lady (East)', 'Fortune Teller (Light)': 'Fortune Teller (Light)', 'Lost Woods Gamble': 'Lost Woods Gamble', 'Sick Kids House': 'Sick Kids House', 'Blacksmiths Hut': 'Blacksmiths Hut', 'Capacity Upgrade': 'Capacity Upgrade', - 'Cave Shop (Lake Hylia)': 'Cave Shop (Lake Hylia)', 'Sahasrahlas Hut': 'Sahasrahlas Hut', + 'Lake Hylia Shop': 'Lake Hylia Shop', 'Sahasrahlas Hut': 'Sahasrahlas Hut', 'Aginahs Cave': 'Aginahs Cave', 'Chicken House': 'Chicken House', 'Tavern North': 'Tavern', - 'Kings Grave': 'Kings Grave', 'Desert Fairy': 'Desert Healer Fairy', 'Light Hype Fairy': 'Swamp Healer Fairy', + 'Kings Grave': 'Kings Grave', 'Desert Fairy': 'Desert Healer Fairy', 'Light Hype Fairy': 'Light Hype Fairy', 'Lake Hylia Fortune Teller': 'Lake Hylia Fortune Teller', 'Lake Hylia Fairy': 'Lake Hylia Healer Fairy', 'Bonk Fairy (Light)': 'Bonk Fairy (Light)', 'Lumberjack House': 'Lumberjack House', 'Dam': 'Dam', 'Blinds Hideout': 'Blinds Hideout', 'Waterfall of Wishing': 'Waterfall of Wishing' @@ -2001,9 +2002,9 @@ DW_Entrances = [] Isolated_LH_Doors = ['Kings Grave', 'Waterfall of Wishing', 'Desert Palace Entrance (South)', 'Desert Palace Entrance (North)', 'Capacity Upgrade', 'Ice Palace', 'Skull Woods Final Section', 'Skull Woods Second Section Door (West)', - 'Dark World Hammer Peg Cave', 'Turtle Rock Isolated Ledge Entrance', + 'Hammer Peg Cave', 'Turtle Rock Isolated Ledge Entrance', 'Dark Death Mountain Ledge (West)', 'Dark Death Mountain Ledge (East)', - 'Dark World Shop', 'Dark World Potion Shop'] + 'Dark World Shop', 'Dark Potion Shop'] # inverted doesn't like really like - Paradox Top or Tower of Hera LH_DM_Connector_List = { @@ -2012,14 +2013,14 @@ LH_DM_Connector_List = { 'Tower of Hera', 'Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Bottom)', 'Spectacle Rock Cave', 'Paradox Cave (Bottom)', 'Paradox Cave (Middle)', 'Paradox Cave (Top)', 'Hookshot Fairy', 'Spike Cave', 'Dark Death Mountain Fairy', 'Ganons Tower', 'Superbunny Cave (Top)', 'Superbunny Cave (Bottom)', - 'Hookshot Cave', 'Cave Shop (Dark Death Mountain)', 'Turtle Rock'} + 'Hookshot Cave', 'Dark Death Mountain Shop', 'Turtle Rock'} LH_DM_Exit_Forbidden = { 'Turtle Rock Isolated Ledge Entrance', 'Mimic Cave', 'Hookshot Cave Back Entrance', 'Dark Death Mountain Ledge (West)', 'Dark Death Mountain Ledge (East)', 'Desert Palace Entrance (South)', - 'Ice Palace', 'Waterfall of Wishing', 'Kings Grave', 'Dark World Hammer Peg Cave', 'Capacity Upgrade', + 'Ice Palace', 'Waterfall of Wishing', 'Kings Grave', 'Hammer Peg Cave', 'Capacity Upgrade', 'Skull Woods Final Section', 'Skull Woods Second Section Door (West)' -} # omissions from Isolated Starts: 'Desert Palace Entrance (North)', 'Dark World Shop', 'Dark World Potion Shop' +} # omissions from Isolated Starts: 'Desert Palace Entrance (North)', 'Dark World Shop', 'Dark Potion Shop' Connector_List = [['Elder House Exit (East)', 'Elder House Exit (West)'], ['Two Brothers House Exit (East)', 'Two Brothers House Exit (West)'], @@ -2080,189 +2081,188 @@ Simple_DM_Non_Connectors = {'Old Man Cave Ledge', 'Spiral Cave (Top)', 'Superbun # They link together underworld regions mandatory_connections = [('Lost Woods Hideout (top to bottom)', 'Lost Woods Hideout (bottom)'), ('Lumberjack Tree (top to bottom)', 'Lumberjack Tree (bottom)'), - ('Kakariko Well (top to bottom)', 'Kakariko Well (bottom)'), - ('Kakariko Well (top to back)', 'Kakariko Well (back)'), - ('Blinds Hideout N', 'Blinds Hideout (Top)'), - ('Bat Cave Door', 'Bat Cave (left)'), - ('Sewer Drop', 'Sewers Rat Path'), - ('Old Man Cave Dropdown', 'Old Man Cave'), - ('Old Man House Front to Back', 'Old Man House Back'), - ('Old Man House Back to Front', 'Old Man House'), - ('Spectacle Rock Cave Drop', 'Spectacle Rock Cave (Bottom)'), - ('Spectacle Rock Cave Peak Drop', 'Spectacle Rock Cave (Bottom)'), ('Death Mountain Return Cave E', 'Death Mountain Return Cave (right)'), ('Death Mountain Return Cave W', 'Death Mountain Return Cave (left)'), + ('Old Man Cave Dropdown', 'Old Man Cave'), + ('Spectacle Rock Cave Drop', 'Spectacle Rock Cave (Bottom)'), + ('Spectacle Rock Cave Peak Drop', 'Spectacle Rock Cave (Bottom)'), + ('Old Man House Front to Back', 'Old Man House Back'), + ('Old Man House Back to Front', 'Old Man House'), ('Spiral Cave (top to bottom)', 'Spiral Cave (Bottom)'), - ('Light World Death Mountain Shop', 'Light World Death Mountain Shop'), ('Paradox Cave Push Block Reverse', 'Paradox Cave Chest Area'), ('Paradox Cave Push Block', 'Paradox Cave Front'), ('Paradox Cave Chest Area NE', 'Paradox Cave Bomb Area'), ('Paradox Cave Bomb Jump', 'Paradox Cave'), ('Paradox Cave Drop', 'Paradox Cave Chest Area'), + ('Paradox Shop', 'Paradox Shop'), ('Fairy Ascension Cave Climb', 'Fairy Ascension Cave (Top)'), ('Fairy Ascension Cave Pots', 'Fairy Ascension Cave (Bottom)'), ('Fairy Ascension Cave Drop', 'Fairy Ascension Cave (Drop)'), + ('Kakariko Well (top to bottom)', 'Kakariko Well (bottom)'), + ('Kakariko Well (top to back)', 'Kakariko Well (back)'), + ('Blinds Hideout N', 'Blinds Hideout (Top)'), + ('Sewer Drop', 'Sewers Rat Path'), ('Missing Smith', 'Missing Smith'), - ('Bumper Cave Bottom to Top', 'Bumper Cave (top)'), - ('Bumper Cave Top To Bottom', 'Bumper Cave (bottom)'), - ('Superbunny Cave Climb', 'Superbunny Cave (Top)'), + ('Bat Cave Door', 'Bat Cave (left)'), + ('Hookshot Cave Front to Middle', 'Hookshot Cave (Middle)'), ('Hookshot Cave Middle to Front', 'Hookshot Cave (Front)'), ('Hookshot Cave Middle to Back', 'Hookshot Cave (Back)'), ('Hookshot Cave Back to Middle', 'Hookshot Cave (Middle)'), ('Hookshot Cave Bonk Path', 'Hookshot Cave (Bonk Islands)'), ('Hookshot Cave Hook Path', 'Hookshot Cave (Hook Islands)'), + ('Superbunny Cave Climb', 'Superbunny Cave (Top)'), + ('Bumper Cave Bottom to Top', 'Bumper Cave (top)'), + ('Bumper Cave Top To Bottom', 'Bumper Cave (bottom)'), ('Ganon Drop', 'Bottom of Pyramid') ] # non-shuffled entrance links -default_connections = {'Links House': 'Links House', - 'Links House Exit': 'Links House Area', - 'Waterfall of Wishing': 'Waterfall of Wishing', - 'Blinds Hideout': 'Blinds Hideout', - 'Dam': 'Dam', - 'Lumberjack House': 'Lumberjack House', - 'Hyrule Castle Secret Entrance Drop': 'Hyrule Castle Secret Entrance', - 'Hyrule Castle Secret Entrance Stairs': 'Hyrule Castle Secret Entrance', - 'Hyrule Castle Secret Entrance Exit': 'Hyrule Castle Courtyard', - 'Bonk Fairy (Light)': 'Bonk Fairy (Light)', - 'Lake Hylia Fairy': 'Lake Hylia Healer Fairy', - 'Lake Hylia Fortune Teller': 'Lake Hylia Fortune Teller', - 'Light Hype Fairy': 'Swamp Healer Fairy', - 'Desert Fairy': 'Desert Healer Fairy', - 'Kings Grave': 'Kings Grave', - 'Tavern North': 'Tavern', - 'Chicken House': 'Chicken House', - 'Aginahs Cave': 'Aginahs Cave', - 'Sahasrahlas Hut': 'Sahasrahlas Hut', - 'Cave Shop (Lake Hylia)': 'Cave Shop (Lake Hylia)', - 'Capacity Upgrade': 'Capacity Upgrade', - 'Kakariko Well Drop': 'Kakariko Well (top)', - 'Kakariko Well Cave': 'Kakariko Well (bottom)', - 'Kakariko Well Exit': 'Kakariko Area', - 'Blacksmiths Hut': 'Blacksmiths Hut', - 'Bat Cave Drop': 'Bat Cave (right)', - 'Bat Cave Cave': 'Bat Cave (left)', - 'Bat Cave Exit': 'Blacksmith Area', - 'Sick Kids House': 'Sick Kids House', - 'Elder House (East)': 'Elder House', - 'Elder House (West)': 'Elder House', - 'Elder House Exit (East)': 'Kakariko Area', - 'Elder House Exit (West)': 'Kakariko Area', - 'North Fairy Cave Drop': 'North Fairy Cave', - 'North Fairy Cave': 'North Fairy Cave', - 'North Fairy Cave Exit': 'River Bend Area', - 'Lost Woods Gamble': 'Lost Woods Gamble', - 'Fortune Teller (Light)': 'Fortune Teller (Light)', - 'Snitch Lady (East)': 'Snitch Lady (East)', - 'Snitch Lady (West)': 'Snitch Lady (West)', - 'Bush Covered House': 'Bush Covered House', - 'Tavern (Front)': 'Tavern (Front)', - 'Light World Bomb Hut': 'Light World Bomb Hut', - 'Kakariko Shop': 'Kakariko Shop', +default_connections = {'Lost Woods Gamble': 'Lost Woods Gamble', 'Lost Woods Hideout Drop': 'Lost Woods Hideout (top)', 'Lost Woods Hideout Stump': 'Lost Woods Hideout (bottom)', 'Lost Woods Hideout Exit': 'Lost Woods East Area', + 'Lumberjack House': 'Lumberjack House', 'Lumberjack Tree Tree': 'Lumberjack Tree (top)', 'Lumberjack Tree Cave': 'Lumberjack Tree (bottom)', 'Lumberjack Tree Exit': 'Lumberjack Area', - 'Cave 45': 'Cave 45', - 'Graveyard Cave': 'Graveyard Cave', - 'Checkerboard Cave': 'Checkerboard Cave', - 'Mini Moldorm Cave': 'Mini Moldorm Cave', - 'Long Fairy Cave': 'Long Fairy Cave', # near East Light World Teleporter - 'Good Bee Cave': 'Good Bee Cave', - '20 Rupee Cave': '20 Rupee Cave', - '50 Rupee Cave': '50 Rupee Cave', - 'Ice Rod Cave': 'Ice Rod Cave', - 'Bonk Rock Cave': 'Bonk Rock Cave', - 'Library': 'Library', - 'Kakariko Gamble Game': 'Kakariko Gamble Game', - 'Potion Shop': 'Potion Shop', - 'Two Brothers House (East)': 'Two Brothers House', - 'Two Brothers House (West)': 'Two Brothers House', - 'Two Brothers House Exit (East)': 'Kakariko Suburb Area', - 'Two Brothers House Exit (West)': 'Maze Race Ledge', - - 'Sanctuary': 'Sanctuary Portal', - 'Sanctuary Grave': 'Sewer Drop', - 'Sanctuary Exit': 'Sanctuary Area', - - 'Old Man Cave (West)': 'Old Man Cave Ledge', + 'Death Mountain Return Cave (East)': 'Death Mountain Return Cave (right)', + 'Death Mountain Return Cave Exit (East)': 'West Death Mountain (Bottom)', 'Old Man Cave (East)': 'Old Man Cave', - 'Old Man Cave Exit (West)': 'Mountain Entry Entrance', 'Old Man Cave Exit (East)': 'West Death Mountain (Bottom)', + 'Spectacle Rock Cave': 'Spectacle Rock Cave (Top)', + 'Spectacle Rock Cave Exit (Top)': 'West Death Mountain (Bottom)', + 'Spectacle Rock Cave Peak': 'Spectacle Rock Cave (Peak)', + 'Spectacle Rock Cave Exit (Peak)': 'West Death Mountain (Bottom)', + 'Spectacle Rock Cave (Bottom)': 'Spectacle Rock Cave (Bottom)', + 'Spectacle Rock Cave Exit': 'West Death Mountain (Bottom)', 'Old Man House (Bottom)': 'Old Man House', 'Old Man House Exit (Bottom)': 'West Death Mountain (Bottom)', 'Old Man House (Top)': 'Old Man House Back', 'Old Man House Exit (Top)': 'West Death Mountain (Bottom)', - 'Death Mountain Return Cave (East)': 'Death Mountain Return Cave (right)', - 'Death Mountain Return Cave (West)': 'Death Mountain Return Cave (left)', - 'Death Mountain Return Cave Exit (West)': 'Mountain Entry Ledge', - 'Death Mountain Return Cave Exit (East)': 'West Death Mountain (Bottom)', - 'Spectacle Rock Cave Peak': 'Spectacle Rock Cave (Peak)', - 'Spectacle Rock Cave (Bottom)': 'Spectacle Rock Cave (Bottom)', - 'Spectacle Rock Cave': 'Spectacle Rock Cave (Top)', - 'Spectacle Rock Cave Exit': 'West Death Mountain (Bottom)', - 'Spectacle Rock Cave Exit (Top)': 'West Death Mountain (Bottom)', - 'Spectacle Rock Cave Exit (Peak)': 'West Death Mountain (Bottom)', - 'Paradox Cave (Bottom)': 'Paradox Cave Front', - 'Paradox Cave (Middle)': 'Paradox Cave', - 'Paradox Cave (Top)': 'Paradox Cave', - 'Paradox Cave Exit (Bottom)': 'East Death Mountain (Bottom)', - 'Paradox Cave Exit (Middle)': 'East Death Mountain (Bottom)', - 'Paradox Cave Exit (Top)': 'East Death Mountain (Top East)', - 'Hookshot Fairy': 'Hookshot Fairy', - 'Fairy Ascension Cave (Bottom)': 'Fairy Ascension Cave (Bottom)', - 'Fairy Ascension Cave (Top)': 'Fairy Ascension Cave (Top)', - 'Fairy Ascension Cave Exit (Bottom)': 'Fairy Ascension Plateau', - 'Fairy Ascension Cave Exit (Top)': 'Fairy Ascension Ledge', 'Spiral Cave': 'Spiral Cave (Top)', + 'Spiral Cave Exit (Top)': 'Spiral Cave Ledge', 'Spiral Cave (Bottom)': 'Spiral Cave (Bottom)', 'Spiral Cave Exit': 'East Death Mountain (Bottom)', - 'Spiral Cave Exit (Top)': 'Spiral Cave Ledge', + 'Mimic Cave': 'Mimic Cave', + 'Fairy Ascension Cave (Top)': 'Fairy Ascension Cave (Top)', + 'Fairy Ascension Cave Exit (Top)': 'Fairy Ascension Ledge', + 'Fairy Ascension Cave (Bottom)': 'Fairy Ascension Cave (Bottom)', + 'Fairy Ascension Cave Exit (Bottom)': 'Fairy Ascension Plateau', + 'Hookshot Fairy': 'Hookshot Fairy', + 'Paradox Cave (Top)': 'Paradox Cave', + 'Paradox Cave Exit (Top)': 'East Death Mountain (Top East)', + 'Paradox Cave (Middle)': 'Paradox Cave', + 'Paradox Cave Exit (Middle)': 'East Death Mountain (Bottom)', + 'Paradox Cave (Bottom)': 'Paradox Cave Front', + 'Paradox Cave Exit (Bottom)': 'East Death Mountain (Bottom)', + 'Death Mountain Return Cave (West)': 'Death Mountain Return Cave (left)', + 'Death Mountain Return Cave Exit (West)': 'Mountain Entry Ledge', + 'Old Man Cave (West)': 'Old Man Cave Ledge', + 'Old Man Cave Exit (West)': 'Mountain Entry Entrance', + 'Waterfall of Wishing': 'Waterfall of Wishing', + 'Fortune Teller (Light)': 'Fortune Teller (Light)', + 'Bonk Rock Cave': 'Bonk Rock Cave', + 'Sanctuary': 'Sanctuary Portal', + 'Sanctuary Grave': 'Sewer Drop', + 'Sanctuary Exit': 'Sanctuary Area', + 'Graveyard Cave': 'Graveyard Cave', + 'Kings Grave': 'Kings Grave', + 'North Fairy Cave Drop': 'North Fairy Cave', + 'North Fairy Cave': 'North Fairy Cave', + 'North Fairy Cave Exit': 'River Bend Area', + 'Potion Shop': 'Potion Shop', + 'Kakariko Well Drop': 'Kakariko Well (top)', + 'Kakariko Well Cave': 'Kakariko Well (bottom)', + 'Kakariko Well Exit': 'Kakariko Area', + 'Blinds Hideout': 'Blinds Hideout', + 'Elder House (West)': 'Elder House', + 'Elder House Exit (West)': 'Kakariko Area', + 'Elder House (East)': 'Elder House', + 'Elder House Exit (East)': 'Kakariko Area', + 'Snitch Lady (West)': 'Snitch Lady (West)', + 'Snitch Lady (East)': 'Snitch Lady (East)', + 'Chicken House': 'Chicken House', + 'Sick Kids House': 'Sick Kids House', + 'Bush Covered House': 'Bush Covered House', + 'Light World Bomb Hut': 'Light World Bomb Hut', + 'Kakariko Shop': 'Kakariko Shop', + 'Tavern North': 'Tavern', + 'Tavern (Front)': 'Tavern (Front)', + 'Hyrule Castle Secret Entrance Drop': 'Hyrule Castle Secret Entrance', + 'Hyrule Castle Secret Entrance Stairs': 'Hyrule Castle Secret Entrance', + 'Hyrule Castle Secret Entrance Exit': 'Hyrule Castle Courtyard', + 'Sahasrahlas Hut': 'Sahasrahlas Hut', + 'Blacksmiths Hut': 'Blacksmiths Hut', + 'Bat Cave Drop': 'Bat Cave (right)', + 'Bat Cave Cave': 'Bat Cave (left)', + 'Bat Cave Exit': 'Blacksmith Area', + 'Two Brothers House (West)': 'Two Brothers House', + 'Two Brothers House Exit (West)': 'Maze Race Ledge', + 'Two Brothers House (East)': 'Two Brothers House', + 'Two Brothers House Exit (East)': 'Kakariko Suburb Area', + 'Library': 'Library', + 'Kakariko Gamble Game': 'Kakariko Gamble Game', + 'Bonk Fairy (Light)': 'Bonk Fairy (Light)', + 'Links House': 'Links House', + 'Links House Exit': 'Links House Area', + 'Lake Hylia Fairy': 'Lake Hylia Healer Fairy', + 'Long Fairy Cave': 'Long Fairy Cave', + 'Checkerboard Cave': 'Checkerboard Cave', + 'Aginahs Cave': 'Aginahs Cave', + 'Cave 45': 'Cave 45', + 'Light Hype Fairy': 'Light Hype Fairy', + 'Lake Hylia Fortune Teller': 'Lake Hylia Fortune Teller', + 'Lake Hylia Shop': 'Lake Hylia Shop', + 'Capacity Upgrade': 'Capacity Upgrade', + 'Mini Moldorm Cave': 'Mini Moldorm Cave', + 'Ice Rod Cave': 'Ice Rod Cave', + 'Good Bee Cave': 'Good Bee Cave', + '20 Rupee Cave': '20 Rupee Cave', + 'Desert Fairy': 'Desert Healer Fairy', + '50 Rupee Cave': '50 Rupee Cave', + 'Dam': 'Dam', - 'Pyramid Fairy': 'Pyramid Fairy', - 'East Dark World Hint': 'East Dark World Hint', - 'Palace of Darkness Hint': 'Palace of Darkness Hint', - 'Big Bomb Shop': 'Big Bomb Shop', - 'Dark Lake Hylia Shop': 'Dark Lake Hylia Shop', - 'Dark Lake Hylia Fairy': 'Dark Lake Hylia Healer Fairy', - 'Dark Lake Hylia Ledge Fairy': 'Dark Lake Hylia Ledge Healer Fairy', - 'Dark Lake Hylia Ledge Spike Cave': 'Dark Lake Hylia Ledge Spike Cave', - 'Dark Lake Hylia Ledge Hint': 'Dark Lake Hylia Ledge Hint', - 'Hype Cave': 'Hype Cave', - 'Bonk Fairy (Dark)': 'Bonk Fairy (Dark)', - 'Brewery': 'Brewery', - 'C-Shaped House': 'C-Shaped House', - 'Chest Game': 'Chest Game', - 'Dark World Hammer Peg Cave': 'Dark World Hammer Peg Cave', - 'Bumper Cave (Bottom)': 'Bumper Cave (bottom)', - 'Bumper Cave (Top)': 'Bumper Cave (top)', - 'Red Shield Shop': 'Red Shield Shop', - 'Dark Sanctuary Hint': 'Dark Sanctuary Hint', - 'Fortune Teller (Dark)': 'Fortune Teller (Dark)', - 'Dark World Shop': 'Village of Outcasts Shop', - 'Dark World Lumberjack Shop': 'Dark World Lumberjack Shop', - 'Dark World Potion Shop': 'Dark World Potion Shop', - 'Archery Game': 'Archery Game', - 'Bumper Cave Exit (Top)': 'Bumper Cave Ledge', - 'Bumper Cave Exit (Bottom)': 'Bumper Cave Entrance', - 'Mire Shed': 'Mire Shed', - 'Dark Desert Hint': 'Dark Desert Hint', - 'Dark Desert Fairy': 'Dark Desert Healer Fairy', - 'Spike Cave': 'Spike Cave', - 'Hookshot Cave': 'Hookshot Cave (Front)', - 'Superbunny Cave (Top)': 'Superbunny Cave (Top)', - 'Cave Shop (Dark Death Mountain)': 'Cave Shop (Dark Death Mountain)', + 'Dark Lumberjack Shop': 'Dark Lumberjack Shop', 'Dark Death Mountain Fairy': 'Dark Death Mountain Healer Fairy', - 'Superbunny Cave (Bottom)': 'Superbunny Cave (Bottom)', - 'Superbunny Cave Exit (Top)': 'East Dark Death Mountain (Top)', - 'Superbunny Cave Exit (Bottom)': 'East Dark Death Mountain (Bottom)', - 'Hookshot Cave Front Exit': 'East Dark Death Mountain (Top)', - 'Hookshot Cave Back Exit': 'Dark Death Mountain Floating Island', + 'Spike Cave': 'Spike Cave', 'Hookshot Cave Back Entrance': 'Hookshot Cave (Back)', - 'Mimic Cave': 'Mimic Cave'} + 'Hookshot Cave Back Exit': 'Dark Death Mountain Floating Island', + 'Hookshot Cave': 'Hookshot Cave (Front)', + 'Hookshot Cave Front Exit': 'East Dark Death Mountain (Top)', + 'Superbunny Cave (Top)': 'Superbunny Cave (Top)', + 'Superbunny Cave Exit (Top)': 'East Dark Death Mountain (Top)', + 'Superbunny Cave (Bottom)': 'Superbunny Cave (Bottom)', + 'Superbunny Cave Exit (Bottom)': 'East Dark Death Mountain (Bottom)', + 'Dark Death Mountain Shop': 'Dark Death Mountain Shop', + 'Bumper Cave (Top)': 'Bumper Cave (top)', + 'Bumper Cave Exit (Top)': 'Bumper Cave Ledge', + 'Bumper Cave (Bottom)': 'Bumper Cave (bottom)', + 'Bumper Cave Exit (Bottom)': 'Bumper Cave Entrance', + 'Fortune Teller (Dark)': 'Fortune Teller (Dark)', + 'Dark Sanctuary Hint': 'Dark Sanctuary Hint', + 'Dark Potion Shop': 'Dark Potion Shop', + 'Chest Game': 'Chest Game', + 'C-Shaped House': 'C-Shaped House', + 'Dark World Shop': 'Village of Outcasts Shop', + 'Brewery': 'Brewery', + 'Red Shield Shop': 'Red Shield Shop', + 'Pyramid Fairy': 'Pyramid Fairy', + 'Palace of Darkness Hint': 'Palace of Darkness Hint', + 'Hammer Peg Cave': 'Hammer Peg Cave', + 'Archery Game': 'Archery Game', + 'Bonk Fairy (Dark)': 'Bonk Fairy (Dark)', + 'Big Bomb Shop': 'Big Bomb Shop', + 'Dark Lake Hylia Fairy': 'Dark Lake Hylia Healer Fairy', + 'East Dark World Hint': 'East Dark World Hint', + 'Mire Shed': 'Mire Shed', + 'Mire Hint': 'Mire Hint', + 'Mire Fairy': 'Mire Healer Fairy', + 'Hype Cave': 'Hype Cave', + 'Dark Lake Hylia Shop': 'Dark Lake Hylia Shop', + 'Dark Lake Hylia Ledge Fairy': 'Dark Lake Hylia Ledge Healer Fairy', + 'Dark Lake Hylia Ledge Hint': 'Dark Lake Hylia Ledge Hint', + 'Dark Lake Hylia Ledge Spike Cave': 'Dark Lake Hylia Ledge Spike Cave'} open_default_connections = {'Pyramid Hole': 'Pyramid', 'Pyramid Exit': 'Pyramid Ledge', @@ -2358,7 +2358,7 @@ door_addresses = {'Links House': (0x00, (0x0104, 0x2c 'Chicken House': (0x4A, (0x0108, 0x18, 0x1120, 0x0837, 0x0106, 0x0888, 0x0188, 0x08a4, 0x0193, 0x07, 0xf9, 0x1530, 0x0000), 0x00), 'Aginahs Cave': (0x70, (0x010a, 0x30, 0x0656, 0x0cc6, 0x02aa, 0x0d18, 0x0328, 0x0d33, 0x032f, 0x08, 0xf8, 0x0000, 0x0000), 0x00), 'Sahasrahlas Hut': (0x44, (0x0105, 0x1e, 0x0610, 0x06d4, 0x0c76, 0x0727, 0x0cf0, 0x0743, 0x0cfb, 0x0a, 0xf6, 0x0000, 0x0000), 0x00), - 'Cave Shop (Lake Hylia)': (0x57, (0x0112, 0x35, 0x0022, 0x0c00, 0x0b1a, 0x0c26, 0x0b98, 0x0c6d, 0x0b9f, 0x00, 0x00, 0x0000, 0x0000), 0x00), + 'Lake Hylia Shop': (0x57, (0x0112, 0x35, 0x0022, 0x0c00, 0x0b1a, 0x0c26, 0x0b98, 0x0c6d, 0x0b9f, 0x00, 0x00, 0x0000, 0x0000), 0x00), 'Capacity Upgrade': (0x5C, (0x0115, 0x35, 0x0a46, 0x0d36, 0x0c2a, 0x0d88, 0x0ca8, 0x0da3, 0x0caf, 0x0a, 0xf6, 0x0000, 0x0000), 0x00), 'Kakariko Well Drop': ([0xDB85C, 0xDB85D], None), 'Blacksmiths Hut': (0x63, (0x0121, 0x22, 0x010c, 0x081a, 0x0466, 0x0868, 0x04d8, 0x0887, 0x04e3, 0x06, 0xfa, 0x041A, 0x0000), 0x00), @@ -2401,19 +2401,19 @@ door_addresses = {'Links House': (0x00, (0x0104, 0x2c 'Brewery': (0x47, (0x0106, 0x58, 0x16a8, 0x08e4, 0x013e, 0x0938, 0x01b8, 0x0953, 0x01c3, 0x0a, 0xf6, 0x1AB6, 0x0000), 0x02), 'C-Shaped House': (0x53, (0x011c, 0x58, 0x09d8, 0x0744, 0x02ce, 0x0797, 0x0348, 0x07b3, 0x0353, 0x0a, 0xf6, 0x0DE8, 0x0000), 0x00), 'Chest Game': (0x46, (0x0106, 0x58, 0x078a, 0x0705, 0x004e, 0x0758, 0x00c8, 0x0774, 0x00d3, 0x09, 0xf7, 0x0B98, 0x0000), 0x00), - 'Dark World Hammer Peg Cave': (0x7E, (0x0127, 0x62, 0x0894, 0x091e, 0x0492, 0x09a6, 0x0508, 0x098b, 0x050f, 0x00, 0x00, 0x0000, 0x0000), 0x20), + 'Hammer Peg Cave': (0x7E, (0x0127, 0x62, 0x0894, 0x091e, 0x0492, 0x09a6, 0x0508, 0x098b, 0x050f, 0x00, 0x00, 0x0000, 0x0000), 0x20), 'Red Shield Shop': (0x74, (0x0110, 0x5a, 0x079a, 0x06e8, 0x04d6, 0x0738, 0x0548, 0x0755, 0x0553, 0x08, 0xf8, 0x0AA8, 0x0000), 0x00), 'Dark Sanctuary Hint': (0x59, (0x0112, 0x53, 0x001e, 0x0400, 0x06e2, 0x0446, 0x0758, 0x046d, 0x075f, 0x00, 0x00, 0x0000, 0x0000), 0x00), 'Fortune Teller (Dark)': (0x65, (0x0122, 0x51, 0x0610, 0x04b4, 0x027e, 0x0507, 0x02f8, 0x0523, 0x0303, 0x0a, 0xf6, 0x091E, 0x0000), 0x00), 'Dark World Shop': (0x5F, (0x010f, 0x58, 0x1058, 0x0814, 0x02be, 0x0868, 0x0338, 0x0883, 0x0343, 0x0a, 0xf6, 0x0000, 0x0000), 0x00), - 'Dark World Lumberjack Shop': (0x56, (0x010f, 0x42, 0x041c, 0x0074, 0x04e2, 0x00c7, 0x0558, 0x00e3, 0x055f, 0x0a, 0xf6, 0x0000, 0x0000), 0x00), - 'Dark World Potion Shop': (0x6E, (0x010f, 0x56, 0x080e, 0x04f4, 0x0c66, 0x0548, 0x0cd8, 0x0563, 0x0ce3, 0x0a, 0xf6, 0x0000, 0x0000), 0x00), + 'Dark Lumberjack Shop': (0x56, (0x010f, 0x42, 0x041c, 0x0074, 0x04e2, 0x00c7, 0x0558, 0x00e3, 0x055f, 0x0a, 0xf6, 0x0000, 0x0000), 0x00), + 'Dark Potion Shop': (0x6E, (0x010f, 0x56, 0x080e, 0x04f4, 0x0c66, 0x0548, 0x0cd8, 0x0563, 0x0ce3, 0x0a, 0xf6, 0x0000, 0x0000), 0x00), 'Archery Game': (0x58, (0x0111, 0x69, 0x069e, 0x0ac4, 0x02ea, 0x0b18, 0x0368, 0x0b33, 0x036f, 0x0a, 0xf6, 0x09AC, 0x0000), 0x00), 'Mire Shed': (0x5E, (0x010d, 0x70, 0x0384, 0x0c69, 0x001e, 0x0cb6, 0x0098, 0x0cd6, 0x00a3, 0x07, 0xf9, 0x0000, 0x0000), 0x00), - 'Dark Desert Hint': (0x61, (0x0114, 0x70, 0x0654, 0x0cc5, 0x02aa, 0x0d16, 0x0328, 0x0d32, 0x032f, 0x09, 0xf7, 0x0000, 0x0000), 0x00), - 'Dark Desert Fairy': (0x55, (0x0115, 0x70, 0x03a8, 0x0c6a, 0x013a, 0x0cb7, 0x01b8, 0x0cd7, 0x01bf, 0x06, 0xfa, 0x0000, 0x0000), 0x00), + 'Mire Hint': (0x61, (0x0114, 0x70, 0x0654, 0x0cc5, 0x02aa, 0x0d16, 0x0328, 0x0d32, 0x032f, 0x09, 0xf7, 0x0000, 0x0000), 0x00), + 'Mire Fairy': (0x55, (0x0115, 0x70, 0x03a8, 0x0c6a, 0x013a, 0x0cb7, 0x01b8, 0x0cd7, 0x01bf, 0x06, 0xfa, 0x0000, 0x0000), 0x00), 'Spike Cave': (0x40, (0x0117, 0x43, 0x0ed4, 0x01e4, 0x08aa, 0x0236, 0x0928, 0x0253, 0x092f, 0x0a, 0xf6, 0x0000, 0x0000), 0x00), - 'Cave Shop (Dark Death Mountain)': (0x6D, (0x0112, 0x45, 0x0ee0, 0x01e3, 0x0d00, 0x0236, 0x0daa, 0x0252, 0x0d7d, 0x0b, 0xf5, 0x0000, 0x0000), 0x00), + 'Dark Death Mountain Shop': (0x6D, (0x0112, 0x45, 0x0ee0, 0x01e3, 0x0d00, 0x0236, 0x0daa, 0x0252, 0x0d7d, 0x0b, 0xf5, 0x0000, 0x0000), 0x00), 'Dark Death Mountain Fairy': (0x6F, (0x0115, 0x43, 0x1400, 0x0294, 0x0600, 0x02e8, 0x0678, 0x0303, 0x0685, 0x0a, 0xf6, 0x0000, 0x0000), 0x00), 'Mimic Cave': (0x4E, (0x010c, 0x05, 0x07e0, 0x0103, 0x0d00, 0x0156, 0x0d78, 0x0172, 0x0d7d, 0x0b, 0xf5, 0x0000, 0x0000), 0x00), 'Big Bomb Shop': (0x52, (0x011c, 0x6c, 0x0506, 0x0a9a, 0x0832, 0x0ae7, 0x08b8, 0x0b07, 0x08bf, 0x06, 0xfa, 0x0816, 0x0000), 0x00), @@ -2493,11 +2493,11 @@ exit_ids = {'Links House Exit': (0x01, 0x00), 'Bonk Fairy (Light)': 0x71, 'Bonk Fairy (Dark)': 0x71, 'Lake Hylia Healer Fairy': 0x5E, - 'Swamp Healer Fairy': 0x5E, + 'Light Hype Fairy': 0x5E, 'Desert Healer Fairy': 0x5E, 'Dark Lake Hylia Healer Fairy': 0x5E, 'Dark Lake Hylia Ledge Healer Fairy': 0x5E, - 'Dark Desert Healer Fairy': 0x5E, + 'Mire Healer Fairy': 0x5E, 'Dark Death Mountain Healer Fairy': 0x5E, 'Fortune Teller (Light)': 0x65, 'Lake Hylia Fortune Teller': 0x65, @@ -2506,8 +2506,8 @@ exit_ids = {'Links House Exit': (0x01, 0x00), 'Chicken House': 0x4B, 'Aginahs Cave': 0x4D, 'Sahasrahlas Hut': 0x45, - 'Cave Shop (Lake Hylia)': 0x58, - 'Cave Shop (Dark Death Mountain)': 0x58, + 'Lake Hylia Shop': 0x58, + 'Dark Death Mountain Shop': 0x58, 'Capacity Upgrade': 0x5D, 'Blacksmiths Hut': 0x64, 'Sick Kids House': 0x40, @@ -2538,21 +2538,21 @@ exit_ids = {'Links House Exit': (0x01, 0x00), 'Big Bomb Shop': 0x53, 'Village of Outcasts Shop': 0x60, 'Dark Lake Hylia Shop': 0x60, - 'Dark World Lumberjack Shop': 0x60, - 'Dark World Potion Shop': 0x60, + 'Dark Lumberjack Shop': 0x60, + 'Dark Potion Shop': 0x60, 'Dark Lake Hylia Ledge Spike Cave': 0x70, 'Dark Lake Hylia Ledge Hint': 0x6A, 'Hype Cave': 0x3D, 'Brewery': 0x48, 'C-Shaped House': 0x54, 'Chest Game': 0x47, - 'Dark World Hammer Peg Cave': 0x83, + 'Hammer Peg Cave': 0x83, 'Red Shield Shop': 0x57, 'Dark Sanctuary Hint': 0x5A, 'Fortune Teller (Dark)': 0x66, 'Archery Game': 0x59, 'Mire Shed': 0x5F, - 'Dark Desert Hint': 0x62, + 'Mire Hint': 0x62, 'Spike Cave': 0x41, 'Mimic Cave': 0x4F, 'Kakariko Well (top)': 0x80, diff --git a/test/inverted/TestInverted.py b/test/inverted/TestInverted.py index 3097f4b7..f4f6e3d9 100644 --- a/test/inverted/TestInverted.py +++ b/test/inverted/TestInverted.py @@ -3,10 +3,10 @@ from DoorShuffle import link_doors from Doors import create_doors from Dungeons import create_dungeons, get_dungeon_item_pool from OverworldShuffle import link_overworld -from EntranceShuffle import link_inverted_entrances +from EntranceShuffle import link_entrances from ItemList import generate_itempool, difficulties from Items import ItemFactory -from Regions import create_regions, mark_light_world_regions, create_dungeon_regions, create_shops +from Regions import create_regions, mark_light_dark_world_regions, create_dungeon_regions, create_shops from RoomData import create_rooms from Rules import set_rules from test.TestBase import TestBase @@ -25,7 +25,7 @@ class TestInverted(TestBase): create_rooms(self.world, 1) create_dungeons(self.world, 1) link_overworld(self.world, 1) - link_inverted_entrances(self.world, 1) + link_entrances(self.world, 1) link_doors(self.world, 1) generate_itempool(self.world, 1) self.world.required_medallions[1] = ['Ether', 'Quake'] @@ -33,5 +33,5 @@ class TestInverted(TestBase): self.world.itempool.extend(ItemFactory(['Green Pendant', 'Red Pendant', 'Blue Pendant', 'Beat Agahnim 1', 'Beat Agahnim 2', 'Crystal 1', 'Crystal 2', 'Crystal 3', 'Crystal 4', 'Crystal 5', 'Crystal 6', 'Crystal 7'], 1)) self.world.get_location('Agahnim 1', 1).item = None self.world.get_location('Agahnim 2', 1).item = None - mark_light_world_regions(self.world, 1) + mark_light_dark_world_regions(self.world, 1) set_rules(self.world, 1) diff --git a/test/inverted/TestInvertedBombRules.py b/test/inverted/TestInvertedBombRules.py index acd32157..974ae797 100644 --- a/test/inverted/TestInvertedBombRules.py +++ b/test/inverted/TestInvertedBombRules.py @@ -4,6 +4,7 @@ from BaseClasses import World from Dungeons import create_dungeons from EntranceShuffle import connect_entrance, Inverted_LW_Entrances, Inverted_LW_Dungeon_Entrances, Inverted_LW_Single_Cave_Doors, Inverted_Old_Man_Entrances, Inverted_DW_Entrances, Inverted_DW_Dungeon_Entrances, Inverted_DW_Single_Cave_Doors, \ Inverted_LW_Entrances_Must_Exit, Inverted_LW_Dungeon_Entrances_Must_Exit, Inverted_Bomb_Shop_Multi_Cave_Doors, Inverted_Bomb_Shop_Single_Cave_Doors, Inverted_Blacksmith_Single_Cave_Doors, Inverted_Blacksmith_Multi_Cave_Doors +from Regions import create_regions from ItemList import difficulties from Rules import set_inverted_big_bomb_rules from test.inverted.TestInverted import TestInverted @@ -20,7 +21,7 @@ class TestInvertedBombRules(TestInverted): entrance = self.world.get_entrance(entrance_name, 1) entrance.connected_region = None self.world.get_region('Big Bomb Shop', 1).entrances = [] - connect_entrance(self.world, entrance, 'Links House', 1) + connect_entrance(self.world, entrance, 'Big Bomb Shop', 1) set_inverted_big_bomb_rules(self.world, 1) entrance.connected_region.entrances.remove(entrance) entrance.connected_region = None @@ -35,7 +36,7 @@ class TestInvertedBombRules(TestInverted): for entrance_name in ['Desert Palace Entrance (East)', 'Spectacle Rock Cave', 'Spectacle Rock Cave (Bottom)']: entrance = self.world.get_entrance(entrance_name, 1) self.world.get_region('Big Bomb Shop', 1).entrances = [] - connect_entrance(self.world, entrance, 'Links House', 1) + connect_entrance(self.world, entrance, 'Big Bomb Shop', 1) with self.assertRaises(Exception): set_inverted_big_bomb_rules(self.world, 1) entrance.connected_region.entrances.remove(entrance) diff --git a/test/inverted/TestInvertedEntrances.py b/test/inverted/TestInvertedEntrances.py index b0b20479..a4c2b1d7 100644 --- a/test/inverted/TestInvertedEntrances.py +++ b/test/inverted/TestInvertedEntrances.py @@ -49,16 +49,15 @@ class TestEntrances(TestInverted): ["Tower of Hera", True, ["Moon Pearl", "Hammer", "Hookshot", "Progressive Glove", "Ocarina"]], ["Tower of Hera", True, ["Moon Pearl", "Hammer", "Beat Agahnim 1", "Ocarina", "Hookshot"]], - # Agahnim's Tower (Inverted) - ["Ganons Tower", False, []], - ["Ganons Tower", False, [], ["Ocarina", "Lamp"]], - ["Ganons Tower", False, [], ["Ocarina", "Progressive Glove"]], - ["Ganons Tower", False, [], ["Moon Pearl", "Lamp"]], - ["Ganons Tower", False, [], ["Moon Pearl", "Progressive Glove"]], - ["Ganons Tower", True, ["Lamp", "Progressive Glove"]], - ["Ganons Tower", True, ["Ocarina", "Beat Agahnim 1", "Moon Pearl"]], - ["Ganons Tower", True, ["Ocarina", "Progressive Glove", "Progressive Glove", "Moon Pearl"]], - ["Ganons Tower", True, ["Ocarina", "Progressive Glove", "Hammer", "Moon Pearl"]], + ["Agahnims Tower", False, []], + ["Agahnims Tower", False, [], ["Ocarina", "Lamp"]], + ["Agahnims Tower", False, [], ["Ocarina", "Progressive Glove"]], + ["Agahnims Tower", False, [], ["Moon Pearl", "Lamp"]], + ["Agahnims Tower", False, [], ["Moon Pearl", "Progressive Glove"]], + ["Agahnims Tower", True, ["Lamp", "Progressive Glove"]], + ["Agahnims Tower", True, ["Ocarina", "Beat Agahnim 1", "Moon Pearl"]], + ["Agahnims Tower", True, ["Ocarina", "Progressive Glove", "Progressive Glove", "Moon Pearl"]], + ["Agahnims Tower", True, ["Ocarina", "Progressive Glove", "Hammer", "Moon Pearl"]], ["Palace of Darkness", False, []], ["Palace of Darkness", False, [], ["Hammer", "Flippers", "Magic Mirror", "Ocarina"]], @@ -105,16 +104,15 @@ class TestEntrances(TestInverted): ["Turtle Rock", True, ["Quake", "Progressive Sword", "Progressive Glove", "Hammer", "Moon Pearl", "Ocarina"]], ["Turtle Rock", True, ["Quake", "Progressive Sword", "Beat Agahnim 1", "Moon Pearl", "Ocarina"]], - # Ganon's Tower (Inverted) - ["Agahnims Tower", False, []], - ["Agahnims Tower", False, [], ["Crystal 1"]], - ["Agahnims Tower", False, [], ["Crystal 2"]], - ["Agahnims Tower", False, [], ["Crystal 3"]], - ["Agahnims Tower", False, [], ["Crystal 4"]], - ["Agahnims Tower", False, [], ["Crystal 5"]], - ["Agahnims Tower", False, [], ["Crystal 6"]], - ["Agahnims Tower", False, [], ["Crystal 7"]], - ["Agahnims Tower", True, ["Beat Agahnim 1", "Crystal 1", "Crystal 2", "Crystal 3", "Crystal 4", "Crystal 5", "Crystal 6", "Crystal 7"]], - ["Agahnims Tower", True, ["Moon Pearl", "Progressive Glove", "Progressive Glove", "Crystal 1", "Crystal 2", "Crystal 3", "Crystal 4", "Crystal 5", "Crystal 6", "Crystal 7"]], - ["Agahnims Tower", True, ["Moon Pearl", "Hammer", "Progressive Glove", "Progressive Glove", "Crystal 1", "Crystal 2", "Crystal 3", "Crystal 4", "Crystal 5", "Crystal 6", "Crystal 7"]], + ["Ganons Tower", False, []], + ["Ganons Tower", False, [], ["Crystal 1"]], + ["Ganons Tower", False, [], ["Crystal 2"]], + ["Ganons Tower", False, [], ["Crystal 3"]], + ["Ganons Tower", False, [], ["Crystal 4"]], + ["Ganons Tower", False, [], ["Crystal 5"]], + ["Ganons Tower", False, [], ["Crystal 6"]], + ["Ganons Tower", False, [], ["Crystal 7"]], + ["Ganons Tower", True, ["Beat Agahnim 1", "Crystal 1", "Crystal 2", "Crystal 3", "Crystal 4", "Crystal 5", "Crystal 6", "Crystal 7"]], + ["Ganons Tower", True, ["Moon Pearl", "Progressive Glove", "Progressive Glove", "Crystal 1", "Crystal 2", "Crystal 3", "Crystal 4", "Crystal 5", "Crystal 6", "Crystal 7"]], + ["Ganons Tower", True, ["Moon Pearl", "Hammer", "Progressive Glove", "Progressive Glove", "Crystal 1", "Crystal 2", "Crystal 3", "Crystal 4", "Crystal 5", "Crystal 6", "Crystal 7"]], ]) \ No newline at end of file diff --git a/test/inverted_owg/TestInvertedOWG.py b/test/inverted_owg/TestInvertedOWG.py index a82a092a..cfdf3a3d 100644 --- a/test/inverted_owg/TestInvertedOWG.py +++ b/test/inverted_owg/TestInvertedOWG.py @@ -3,11 +3,11 @@ from DoorShuffle import link_doors from Doors import create_doors from Dungeons import create_dungeons, get_dungeon_item_pool from OverworldShuffle import link_overworld -from EntranceShuffle import link_inverted_entrances +from EntranceShuffle import link_entrances from ItemList import generate_itempool, difficulties from Items import ItemFactory from OverworldGlitchRules import create_owg_connections -from Regions import create_regions, mark_light_world_regions, create_dungeon_regions, create_shops +from Regions import create_regions, mark_light_dark_world_regions, create_dungeon_regions, create_shops from RoomData import create_rooms from Rules import set_rules from test.TestBase import TestBase @@ -27,7 +27,7 @@ class TestInvertedOWG(TestBase): create_dungeons(self.world, 1) link_overworld(self.world, 1) create_owg_connections(self.world, 1) - link_inverted_entrances(self.world, 1) + link_entrances(self.world, 1) link_doors(self.world, 1) generate_itempool(self.world, 1) self.world.required_medallions[1] = ['Ether', 'Quake'] @@ -37,5 +37,5 @@ class TestInvertedOWG(TestBase): self.world.get_location('Agahnim 2', 1).item = None self.world.precollected_items.clear() self.world.itempool.append(ItemFactory('Pegasus Boots', 1)) - mark_light_world_regions(self.world, 1) + mark_light_dark_world_regions(self.world, 1) set_rules(self.world, 1) diff --git a/test/owg/TestVanillaOWG.py b/test/owg/TestVanillaOWG.py index 9b1ad9f1..c114f24b 100644 --- a/test/owg/TestVanillaOWG.py +++ b/test/owg/TestVanillaOWG.py @@ -7,7 +7,7 @@ from EntranceShuffle import link_entrances from ItemList import difficulties, generate_itempool from Items import ItemFactory from OverworldGlitchRules import create_owg_connections -from Regions import create_regions, create_dungeon_regions, create_shops, mark_dark_world_regions +from Regions import create_regions, create_dungeon_regions, create_shops, mark_light_dark_world_regions from RoomData import create_rooms from Rules import set_rules from test.TestBase import TestBase @@ -37,5 +37,5 @@ class TestVanillaOWG(TestBase): self.world.get_location('Agahnim 2', 1).item = None self.world.precollected_items.clear() self.world.itempool.append(ItemFactory('Pegasus Boots', 1)) - mark_dark_world_regions(self.world, 1) + mark_light_dark_world_regions(self.world, 1) set_rules(self.world, 1) \ No newline at end of file diff --git a/test/stats/EntranceShuffleStats.py b/test/stats/EntranceShuffleStats.py index 130cdb8b..9217a6ba 100644 --- a/test/stats/EntranceShuffleStats.py +++ b/test/stats/EntranceShuffleStats.py @@ -104,6 +104,7 @@ def test_loop(tests, entrance_set, exit_set, ctr, shuffle_mode, main_mode, links {}, {}, {}, {}, {}, True, {}, [], {}) world.customizer = False world.shufflelinks = {1: links} + world.shuffletavern = {1: False} create_regions(world, 1) create_dungeon_regions(world, 1) # print(f'Linking seed {seed}') diff --git a/test/vanilla/TestVanilla.py b/test/vanilla/TestVanilla.py index 56afbd53..6ed6e611 100644 --- a/test/vanilla/TestVanilla.py +++ b/test/vanilla/TestVanilla.py @@ -6,7 +6,7 @@ from OverworldShuffle import link_overworld from EntranceShuffle import link_entrances from ItemList import difficulties, generate_itempool from Items import ItemFactory -from Regions import create_regions, create_dungeon_regions, create_shops, mark_dark_world_regions +from Regions import create_regions, create_dungeon_regions, create_shops, mark_light_dark_world_regions from RoomData import create_rooms from Rules import set_rules from test.TestBase import TestBase @@ -33,5 +33,5 @@ class TestVanilla(TestBase): self.world.itempool.extend(ItemFactory(['Green Pendant', 'Red Pendant', 'Blue Pendant', 'Beat Agahnim 1', 'Beat Agahnim 2', 'Crystal 1', 'Crystal 2', 'Crystal 3', 'Crystal 4', 'Crystal 5', 'Crystal 6', 'Crystal 7'], 1)) self.world.get_location('Agahnim 1', 1).item = None self.world.get_location('Agahnim 2', 1).item = None - mark_dark_world_regions(self.world, 1) + mark_light_dark_world_regions(self.world, 1) set_rules(self.world, 1) From 2da8dc72ccb3a160dbe704ba9f7fd18c4e6ec422 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Fri, 7 Apr 2023 15:47:56 -0500 Subject: [PATCH 103/196] Better fix for Hera music silence This reverts commit c2b3d8ce6cf33ed735a6819e5d39c6e0b589ba23, reversing changes made to 1bf95fe2d77fe55906d0f16e9d78f9f5ede4c118. --- Rom.py | 9 +-------- data/base2current.bps | Bin 106126 -> 106120 bytes 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/Rom.py b/Rom.py index 69d46fda..56637ee3 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = 'b5e862bd5dee7ca32f8a80cfdf1cb8aa' +RANDOMIZERBASEHASH = 'e8fee7a4a2f70d9e24f3f2d583ae8aad' class JsonRom(object): @@ -989,13 +989,6 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): rom.write_byte(0x13f000+dungeon_id, opposite_door.roomIndex) elif not opposite_door: rom.write_byte(0x13f000+dungeon_id, 0) # no supertile preceeding boss - # fix for resuming Hera music after leaving boss room - boss_door = world.get_door('Hera Boss Down Stairs', player) - quadrant = boss_door.dest.quadrant if boss_door.dest.quadrant is not None else 0x7f - write_int16(rom, 0x13f0fe, quadrant << 9 | boss_door.dest.roomIndex) # room to resume music - boss_door = boss_door.entrance.parent_region.entrances[0].door - quadrant = boss_door.quadrant if boss_door.quadrant is not None else 0x7f - write_int16(rom, 0x13f0fc, quadrant << 9 | boss_door.roomIndex) # room to fade out if is_mystery: dr_flags |= DROptions.Hide_Total rom.write_byte(0x138004, dr_flags.value & 0xff) diff --git a/data/base2current.bps b/data/base2current.bps index d923d50f84a63b859add903f538d6f7c43a319bb..b5f54fd1665d907ce86fc6afb392c96a90a09438 100644 GIT binary patch delta 3078 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 Date: Fri, 7 Apr 2023 15:00:14 -0600 Subject: [PATCH 104/196] Fix for gui --- source/gui/bottom.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/source/gui/bottom.py b/source/gui/bottom.py index 93976c75..e2e0ffc4 100644 --- a/source/gui/bottom.py +++ b/source/gui/bottom.py @@ -215,7 +215,8 @@ def create_guiargs(parent): arg = options[mainpage][subpage][widget] if subpage != "" else options[mainpage][widget] page = parent.pages[mainpage].pages[subpage] if subpage != "" else parent.pages[mainpage] pagewidgets = page.content.customWidgets if mainpage == "custom" else page.content.startingWidgets if mainpage == "startinventory" else page.widgets - setattr(guiargs, arg, pagewidgets[widget].storageVar.get()) + if hasattr(pagewidgets[widget], 'storageVar'): + setattr(guiargs, arg, pagewidgets[widget].storageVar.get()) # Get EnemizerCLI setting guiargs.enemizercli = parent.pages["randomizer"].pages["enemizer"].widgets["enemizercli"].storageVar.get() @@ -287,10 +288,6 @@ def create_guiargs(parent): guiargs = update_deprecated_args(guiargs) # Key drop shuffle stuff - if guiargs.keydropshuffle: - guiargs.dropshuffle = 1 - guiargs.pottery = 'keys' if guiargs.pottery == 'none' else guiargs.pottery - if (hasattr(guiargs, 'retro') and guiargs.retro) or guiargs.mode == 'retro': if guiargs.bow_mode == 'progressive': guiargs.bow_mode = 'retro' From 4af94194614f734b51254de2c150d6d5810eb732 Mon Sep 17 00:00:00 2001 From: aerinon Date: Fri, 7 Apr 2023 16:01:08 -0600 Subject: [PATCH 105/196] GUI cleanup Fix Chest Game prize display --- source/gui/bottom.py | 9 --------- source/overworld/EntranceShuffle2.py | 2 +- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/source/gui/bottom.py b/source/gui/bottom.py index e2e0ffc4..beb77a1f 100644 --- a/source/gui/bottom.py +++ b/source/gui/bottom.py @@ -287,13 +287,4 @@ def create_guiargs(parent): guiargs = update_deprecated_args(guiargs) - # Key drop shuffle stuff - if (hasattr(guiargs, 'retro') and guiargs.retro) or guiargs.mode == 'retro': - if guiargs.bow_mode == 'progressive': - guiargs.bow_mode = 'retro' - elif guiargs.bow_mode == 'silvers': - guiargs.bow_mode = 'retro_silvers' - guiargs.take_any = 'random' if guiargs.take_any == 'none' else guiargs.take_any - guiargs.keyshuffle = 'universal' - return guiargs diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index 77790bda..572f3bb3 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -2744,7 +2744,7 @@ ow_prize_table = {'Links House': (0x8b1, 0xb2d), 'Dark Lake Hylia Ledge Hint': (0xec0, 0xc00), 'Hype Cave': (0x940, 0xc80), 'Bonk Fairy (Dark)': (0x740, 0xa80), - 'Brewery': (0x170, 0x980), 'C-Shaped House': (0x310, 0x7a0), 'Chest Game': (0x800, 0x7a0), + 'Brewery': (0x170, 0x980), 'C-Shaped House': (0x310, 0x7a0), 'Chest Game': (0x080, 0x7a0), 'Hammer Peg Cave': (0x4c0, 0x940), 'Red Shield Shop': (0x500, 0x680), 'Dark Sanctuary Hint': (0x720, 0x4a0), From 2e750c471f8325d755b0140c64d7be1122868221 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 9 Apr 2023 11:08:26 -0500 Subject: [PATCH 106/196] Fixed issue with bonk drops causing other duplicate spawns --- Rom.py | 2 +- asm/owrando.asm | 4 ++-- data/base2current.bps | Bin 106120 -> 106116 bytes 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Rom.py b/Rom.py index 56637ee3..542754ae 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = 'e8fee7a4a2f70d9e24f3f2d583ae8aad' +RANDOMIZERBASEHASH = 'ec28f4236a72f55c2a7bcf95cfccde8c' class JsonRom(object): diff --git a/asm/owrando.asm b/asm/owrando.asm index c4f512b0..6651be8d 100644 --- a/asm/owrando.asm +++ b/asm/owrando.asm @@ -520,7 +520,7 @@ OWBonkGoodBeeDrop: LDA.w $0D00,Y : SEC : SBC.l OWBonkPrizeTable[42].vert_offset : STA.w $0D00,Y LDA.w $0D20,Y : SBC #$00 : STA.w $0D20,Y - LDA.b #$01 : STA !REDRAW : STA !FORCE_HEART_SPAWN + LDA.b #$01 : STA !REDRAW .return PLY @@ -642,7 +642,7 @@ OWBonkDrops: LDA.w $0D00,Y : SEC : SBC.w OWBonkPrizeData,X : STA.w $0D00,Y LDA.w $0D20,Y : SBC #$00 : STA.w $0D20,Y - LDA.b #$01 : STA !REDRAW : STA !FORCE_HEART_SPAWN + LDA.b #$01 : STA !REDRAW PLB : RTL diff --git a/data/base2current.bps b/data/base2current.bps index b5f54fd1665d907ce86fc6afb392c96a90a09438..db7b60b98c75a8b399bd2227e50d854cdea337c6 100644 GIT binary patch delta 196 zcmV;#06YJPy#|E62C!uT1V!|^3$tkfbO!;egWd?Y-UtCIH33GK2|fWnA4ZL;XwVn0 zLGpeH0*^uRezQ10fsue)`tS#q1Dt_Tmu5ZzIRTxQq&@*X4L*sTfY|800K3{qmj{>b zJ^>vd)8Uq8AX_wwV0X6|(w-rDEYhDNxm;&TO;=53^|jbO!;igWd?Y-UtCIH33eS2|fWnA5M*`XwVn0 zLGpeH0*^uRezQ10fsue;`tS#q1Dt_Xmu5ZzIR&kcGf;n*pgsXT4MvHbfY|800K3{q zmk*cfJ^>vd=Zwl|o1%rpjH86b$c)J}&<3g57)->B$u-ahsoIk;mnS~~Hvu=7Uq1mW z3`&jq@RxCP0)UxJN|%;D0VV;{m%Tp$8UtgKahKXZ0X6|}w-G=AYhDPeX=(ssF3pQ# CnNigM From c2538d44cbcb4a5ee47f0cc174e57aa35143633e Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 13 Apr 2023 14:03:30 -0500 Subject: [PATCH 107/196] Minor GUI indentation --- resources/app/gui/randomize/dungeon/keysanity.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/resources/app/gui/randomize/dungeon/keysanity.json b/resources/app/gui/randomize/dungeon/keysanity.json index ec3ae380..5a2a8e60 100644 --- a/resources/app/gui/randomize/dungeon/keysanity.json +++ b/resources/app/gui/randomize/dungeon/keysanity.json @@ -6,7 +6,10 @@ "none", "wild", "universal" - ] + ], + "config": { + "padx": [20,0] + } }, "mapshuffle": { "type": "checkbox" }, "compassshuffle": { "type": "checkbox" }, From e1fe3e1639022aa670e03f60686fe445a8c0dd0f Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 13 Apr 2023 15:01:23 -0500 Subject: [PATCH 108/196] Changed bonk drops to not set flag if sprite is off screen --- Rom.py | 2 +- asm/owrando.asm | 1 + data/base2current.bps | Bin 106116 -> 106123 bytes 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Rom.py b/Rom.py index 542754ae..d6947401 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = 'ec28f4236a72f55c2a7bcf95cfccde8c' +RANDOMIZERBASEHASH = '544b8d7dd202c6e8a9e70b31af5bae3d' class JsonRom(object): diff --git a/asm/owrando.asm b/asm/owrando.asm index 6651be8d..55420da0 100644 --- a/asm/owrando.asm +++ b/asm/owrando.asm @@ -607,6 +607,7 @@ OWBonkDrops: .mark_collected ; S = Collected, FlagBitmask, X (row + 2) PLA : BNE + ; S = FlagBitmask, X (row + 2) + TYX : JSL Sprite_IsOnscreen : BCC + LDX.b $8A : LDA.l OverworldEventDataWRAM,X : ORA 1,S : STA.l OverworldEventDataWRAM,X REP #$20 diff --git a/data/base2current.bps b/data/base2current.bps index db7b60b98c75a8b399bd2227e50d854cdea337c6..e3891f5ac808b26d6254406cff156140150cf6a6 100644 GIT binary patch delta 118 zcmV-+0Ez#Ey#|ZD2C!uT1i0`=4})m|w`l~4>Hl~qGLXG`Dmm*77EHvwR` R7(fAQUI-MJ0^~#FypSGRDvSUC From 2abfc6ea80ed0bbf0fe27e9e1f36172ec44bf8fb Mon Sep 17 00:00:00 2001 From: aerinon Date: Thu, 13 Apr 2023 16:19:18 -0600 Subject: [PATCH 109/196] Swap E/W on Mire Torches/Mire Attic Hint --- DoorShuffle.py | 2 +- Doors.py | 4 ++-- Regions.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/DoorShuffle.py b/DoorShuffle.py index b236cd9e..a0add44b 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -4156,7 +4156,7 @@ interior_doors = [ ('Mire Neglected Room SE', 'Mire Chest View NE'), ('Mire BK Chest Ledge WS', 'Mire Warping Pool ES'), # technically one-way ('Mire Torches Top SW', 'Mire Torches Bottom NW'), - ('Mire Torches Bottom WS', 'Mire Attic Hint ES'), + ('Mire Torches Bottom ES', 'Mire Attic Hint WS'), ('Mire Dark Shooters SE', 'Mire Key Rupees NE'), ('Mire Dark Shooters SW', 'Mire Block X NW'), ('Mire Tall Dark and Roomy WS', 'Mire Crystal Right ES'), diff --git a/Doors.py b/Doors.py index e97505ee..4020caff 100644 --- a/Doors.py +++ b/Doors.py @@ -924,9 +924,9 @@ def create_doors(world, player): create_door(player, 'Mire Torches Top SW', Intr).dir(So, 0x97, Left, High).pos(1), create_door(player, 'Mire Torches Bottom Holes', Hole), create_door(player, 'Mire Torches Bottom NW', Intr).dir(No, 0x97, Left, High).pos(1), - create_door(player, 'Mire Torches Bottom WS', Intr).dir(We, 0x97, Bot, High).pos(0), + create_door(player, 'Mire Torches Bottom ES', Intr).dir(Ea, 0x97, Bot, High).pos(0), create_door(player, 'Mire Torches Top Holes', Hole), - create_door(player, 'Mire Attic Hint ES', Intr).dir(Ea, 0x97, Bot, High).pos(0), + create_door(player, 'Mire Attic Hint WS', Intr).dir(We, 0x97, Bot, High).pos(0), create_door(player, 'Mire Attic Hint Hole', Hole), create_door(player, 'Mire Dark Shooters Up Stairs', Sprl).dir(Up, 0x93, 0, LTH).ss(A, 0x32, 0xec), create_door(player, 'Mire Dark Shooters SW', Intr).dir(So, 0x93, Left, High).pos(0), diff --git a/Regions.py b/Regions.py index bcbb76d4..7b0e2535 100644 --- a/Regions.py +++ b/Regions.py @@ -691,8 +691,8 @@ def create_dungeon_regions(world, player): create_dungeon_region(player, 'Mire BK Chest Ledge', 'Misery Mire', ['Misery Mire - Big Key Chest'], ['Mire BK Chest Ledge WS']), create_dungeon_region(player, 'Mire Warping Pool', 'Misery Mire', None, ['Mire Warping Pool ES', 'Mire Warping Pool Warp']), create_dungeon_region(player, 'Mire Torches Top', 'Misery Mire', None, ['Mire Torches Top Down Stairs', 'Mire Torches Top SW', 'Mire Torches Top Holes']), - create_dungeon_region(player, 'Mire Torches Bottom', 'Misery Mire', None, ['Mire Torches Bottom NW', 'Mire Torches Bottom WS', 'Mire Torches Bottom Holes']), - create_dungeon_region(player, 'Mire Attic Hint', 'Misery Mire', None, ['Mire Attic Hint ES', 'Mire Attic Hint Hole']), + create_dungeon_region(player, 'Mire Torches Bottom', 'Misery Mire', None, ['Mire Torches Bottom NW', 'Mire Torches Bottom ES', 'Mire Torches Bottom Holes']), + create_dungeon_region(player, 'Mire Attic Hint', 'Misery Mire', None, ['Mire Attic Hint WS', 'Mire Attic Hint Hole']), create_dungeon_region(player, 'Mire Dark Shooters', 'Misery Mire', None, ['Mire Dark Shooters Up Stairs', 'Mire Dark Shooters SW', 'Mire Dark Shooters SE']), create_dungeon_region(player, 'Mire Key Rupees', 'Misery Mire', None, ['Mire Key Rupees NE']), create_dungeon_region(player, 'Mire Block X', 'Misery Mire', None, ['Mire Block X NW', 'Mire Block X WS']), From 072bbfac1fbba43c1dffbc836786e369e4dfe17b Mon Sep 17 00:00:00 2001 From: aerinon Date: Thu, 13 Apr 2023 16:20:54 -0600 Subject: [PATCH 110/196] Version bump and release note --- Main.py | 2 +- RELEASENOTES.md | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Main.py b/Main.py index 8f97ef46..62d519ed 100644 --- a/Main.py +++ b/Main.py @@ -34,7 +34,7 @@ from source.overworld.EntranceShuffle2 import link_entrances_new from source.tools.BPS import create_bps_from_data from source.classes.CustomSettings import CustomSettings -version_number = '1.2.0.15' +version_number = '1.2.0.16' version_branch = '-u' __version__ = f'{version_number}{version_branch}' diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 71b3ec75..4ae675a6 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -109,6 +109,9 @@ These are now independent of retro mode and have three options: None, Random, an # Bug Fixes and Notes +* 1.2.0.16u + * Fix for Mire Attic Hint door (direction was swapped) + * Dungeon at Chest Game displays correctly on OW map option * 1.2.0.15u * GUI reorganization * Logic fix for pots in GT conveyor cross From f5181adf36fd37dfbfbfb54214da18a4f4c58d19 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 13 Apr 2023 18:50:35 -0500 Subject: [PATCH 111/196] Version bump 0.3.0.6 --- CHANGELOG.md | 7 +++++++ OverworldShuffle.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35763257..135502b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 0.3.0.6 +- \~Merged in DR v1.2.0.15~ +- Fixed Tower of Hera music silence issue +- Improved GT crystal cutscene +- Fixed issue with bonk drop items causing duplicate sprite spawns +- Changed bonk prizes to not mark as collected unless it is visible on screen + ## 0.3.0.5 - Major reorganization to GUI Options - Corrected various fake world behavior in glitched modes diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 09128163..3e3cf192 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -7,7 +7,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType from OverworldGlitchRules import create_owg_connections from Utils import bidict -version_number = '0.3.0.5' +version_number = '0.3.0.6' # branch indicator is intentionally different across branches version_branch = '-u' From 1359514dea7ae1a2d893bf3467de4813b06b0b39 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 13 Apr 2023 19:21:11 -0500 Subject: [PATCH 112/196] Fixed default connections in Inverted to correctly swap AT/GT --- source/overworld/EntranceShuffle2.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index ff0f4d87..416ba226 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -62,6 +62,9 @@ def link_entrances_new(world, player): one_way_map = {} one_way_map.update(drop_map) one_way_map.update(single_entrance_map) + if avail_pool.world.is_atgt_swapped(avail_pool.player): + default_map['Ganons Tower'] = 'Agahnims Tower Exit' + default_map['Agahnims Tower'] = 'Ganons Tower Exit' avail_pool.default_map = default_map avail_pool.one_way_map = one_way_map From ea8bd117fcc9dcbe34c65f05adacd7ceff74cf08 Mon Sep 17 00:00:00 2001 From: aerinon Date: Fri, 14 Apr 2023 14:17:57 -0600 Subject: [PATCH 113/196] Fix for partial key logic for vanilla mire Fix for Kholdstare shell collision --- RELEASENOTES.md | 2 ++ Rom.py | 2 +- Rules.py | 38 +++++++++++++++++++++++++++++++++++++- data/base2current.bps | Bin 93979 -> 94044 bytes 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 4ae675a6..a84d0551 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -110,6 +110,8 @@ These are now independent of retro mode and have three options: None, Random, an # Bug Fixes and Notes * 1.2.0.16u + * Fix for partial key logic on vanilla Mire + * Fix for Kholdstare Shell collision when at Lanmo 2 * Fix for Mire Attic Hint door (direction was swapped) * Dungeon at Chest Game displays correctly on OW map option * 1.2.0.15u diff --git a/Rom.py b/Rom.py index b7285b2e..ea0b9c68 100644 --- a/Rom.py +++ b/Rom.py @@ -37,7 +37,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '29863ca305a8474c452cd13b3f921898' +RANDOMIZERBASEHASH = '9903cdfc3fc69112919ec49fb63e09ab' class JsonRom(object): diff --git a/Rules.py b/Rules.py index e8dc7aa5..fc608ec2 100644 --- a/Rules.py +++ b/Rules.py @@ -2000,7 +2000,9 @@ def add_key_logic_rules(world, player): key_logic = world.key_logic[player] eval_func = eval_small_key_door if world.key_logic_algorithm[player] == 'strict' and world.keyshuffle[player] == 'wild': - eval_func = eval_small_key_door_strict + eval_func = eval_small_key_door_strict + elif world.key_logic_algorithm[player] != 'default': + eval_func = eval_small_key_door_partial for d_name, d_logic in key_logic.items(): for door_name, rule in d_logic.door_rules.items(): door_entrance = world.get_entrance(door_name, player) @@ -2056,6 +2058,36 @@ def eval_small_key_door_main(state, door_name, dungeon, player): return door_openable +def eval_small_key_door_partial_main(state, door_name, dungeon, player): + if state.is_door_open(door_name, player): + return True + key_logic = state.world.key_logic[player][dungeon] + if door_name not in key_logic.door_rules: + return False + door_rule = key_logic.door_rules[door_name] + door_openable = False + for ruleType, number in door_rule.new_rules.items(): + if door_openable: + return True + if ruleType == KeyRuleType.WorstCase: + number = min(number, door_rule.small_key_num) + door_openable |= state.has_sm_key(key_logic.small_key_name, player, number) + elif ruleType == KeyRuleType.AllowSmall: + small_loc_item = door_rule.small_location.item + if small_loc_item and small_loc_item.name == key_logic.small_key_name and small_loc_item.player == player: + door_openable |= state.has_sm_key(key_logic.small_key_name, player, number) + elif isinstance(ruleType, tuple): + lock, lock_item = ruleType + # this doesn't track logical locks yet, i.e. hammer locks the item and hammer is there, but the item isn't + for loc in door_rule.alternate_big_key_loc: + spot = state.world.get_location(loc, player) + if spot.item and spot.item.name == lock_item: + number = min(number, door_rule.alternate_small_key) + door_openable |= state.has_sm_key(key_logic.small_key_name, player, number) + break + return door_openable + + def eval_small_key_door_strict_main(state, door_name, dungeon, player): if state.is_door_open(door_name, player): return True @@ -2070,6 +2102,10 @@ def eval_small_key_door(door_name, dungeon, player): return lambda state: eval_small_key_door_main(state, door_name, dungeon, player) +def eval_small_key_door_partial(door_name, dungeon, player): + return lambda state: eval_small_key_door_partial_main(state, door_name, dungeon, player) + + def eval_small_key_door_strict(door_name, dungeon, player): return lambda state: eval_small_key_door_strict_main(state, door_name, dungeon, player) diff --git a/data/base2current.bps b/data/base2current.bps index 832779a30453f400fad4258196d067eb09eafe59..e58c28ab1b469f73a96a04d2e5d5d50a2ca92b26 100644 GIT binary patch delta 2245 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 From d5e69b28f294ff148e7b197a8de617d6d364c524 Mon Sep 17 00:00:00 2001 From: aerinon Date: Fri, 14 Apr 2023 15:23:38 -0600 Subject: [PATCH 114/196] Fix for Non-ER Inverted Experimental (Aga and GT weren't logically swapped) Fix for customizer setting crystals to 0 for either GT/Ganon --- Main.py | 2 +- RELEASENOTES.md | 3 +++ source/classes/CustomSettings.py | 5 +++-- source/overworld/EntranceShuffle2.py | 4 ++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Main.py b/Main.py index 62d519ed..107b0694 100644 --- a/Main.py +++ b/Main.py @@ -34,7 +34,7 @@ from source.overworld.EntranceShuffle2 import link_entrances_new from source.tools.BPS import create_bps_from_data from source.classes.CustomSettings import CustomSettings -version_number = '1.2.0.16' +version_number = '1.2.0.17' version_branch = '-u' __version__ = f'{version_number}{version_branch}' diff --git a/RELEASENOTES.md b/RELEASENOTES.md index a84d0551..4f622e60 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -109,6 +109,9 @@ These are now independent of retro mode and have three options: None, Random, an # Bug Fixes and Notes +* 1.2.0.17u + * Fix for Non-ER Inverted Experimental (Aga and GT weren't logically swapped) + * Fix for customizer setting crystals to 0 for either GT/Ganon * 1.2.0.16u * Fix for partial key logic on vanilla Mire * Fix for Kholdstare Shell collision when at Lanmo 2 diff --git a/source/classes/CustomSettings.py b/source/classes/CustomSettings.py index ba5bd705..deb9f4d2 100644 --- a/source/classes/CustomSettings.py +++ b/source/classes/CustomSettings.py @@ -2,6 +2,7 @@ import os import urllib.request import urllib.parse import yaml +from typing import Any from yaml.representer import Representer from collections import defaultdict from pathlib import Path @@ -46,8 +47,8 @@ class CustomSettings(object): return meta['players'] def adjust_args(self, args): - def get_setting(value, default): - if value: + def get_setting(value: Any, default): + if value or value == 0: if isinstance(value, dict): return random.choices(list(value.keys()), list(value.values()), k=1)[0] else: diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index 572f3bb3..61f0a80d 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -56,6 +56,8 @@ def link_entrances_new(world, player): one_way_map.update(drop_map) one_way_map.update(single_entrance_map) if avail_pool.inverted: + default_map['Ganons Tower'] = 'Agahnims Tower Exit' + default_map['Agahnims Tower'] = 'Ganons Tower Exit' default_map['Old Man Cave (West)'] = 'Bumper Cave Exit (Bottom)' default_map['Death Mountain Return Cave (West)'] = 'Bumper Cave Exit (Top)' default_map['Bumper Cave (Bottom)'] = 'Old Man Cave Exit (West)' @@ -64,8 +66,6 @@ def link_entrances_new(world, player): default_map['Old Man Cave (East)'] = 'Death Mountain Return Cave Exit (West)' one_way_map['Bumper Cave (Top)'] = 'Dark Death Mountain Healer Fairy' del default_map['Bumper Cave (Top)'] - del one_way_map['Big Bomb Shop'] - one_way_map['Inverted Big Bomb Shop'] = 'Inverted Big Bomb Shop' avail_pool.default_map = default_map avail_pool.one_way_map = one_way_map From ee9fc3c6b13bb30cb360dcf62f3e6357efdcc307 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sat, 15 Apr 2023 05:18:40 -0500 Subject: [PATCH 115/196] Animate standing rupees for enemy drops --- Rom.py | 2 +- data/base2current.bps | Bin 106183 -> 106249 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Rom.py b/Rom.py index cb340f55..c6695728 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = 'c7dd0d311c13811cce9a2c384819744c' +RANDOMIZERBASEHASH = 'c24de4a717cea429d20d0e5510df2edd' class JsonRom(object): diff --git a/data/base2current.bps b/data/base2current.bps index 40f28c289d165dba1f53d85fc5c36c15a9ab9e43..d0b70bcdd8a3ab733d43950533b152e3e644c4e1 100644 GIT binary patch delta 8326 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 delta 8333 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 From 608e01c906f2dd14eb8ea4ae8098e22c6fe9de8b Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 16 Apr 2023 04:37:50 -0500 Subject: [PATCH 116/196] Fix pottery to retain gfx during map check --- Rom.py | 2 +- data/base2current.bps | Bin 106249 -> 106284 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Rom.py b/Rom.py index c6695728..cfa99828 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = 'c24de4a717cea429d20d0e5510df2edd' +RANDOMIZERBASEHASH = 'f5f779f1820204cd019ca5293594f955' class JsonRom(object): diff --git a/data/base2current.bps b/data/base2current.bps index d0b70bcdd8a3ab733d43950533b152e3e644c4e1..49650e2da50eb26d5f164437c9493f2468ba1965 100644 GIT binary patch delta 181 zcmV;m080Ofz6Pwm29SyYXOWAK3rL5RTnMtL>gsT(lNJA*0q_XP4)6$EZ0CSngy#UMP>mNMToQ=@m#{hkQvtA-1Umsj40W@B60?M{!XT*? jvzJmk0X70CE|-cs0Yd_7V7JdZ0WxC<>;2Ci_nUF2m70vvL8$#U3AlLoczZ%FwmqAY4)A z0OBy0U%Hieh{7 Date: Sun, 7 May 2023 20:19:18 -0500 Subject: [PATCH 117/196] Big ROM changes - New Item GFX code - Fixed Bonk Dupe issue - Fixed Bonk Despawn issue --- Rom.py | 2 +- asm/owrando.asm | 46 ++++++++++++++++++++++++++---------------- data/base2current.bps | Bin 106284 -> 106730 bytes 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/Rom.py b/Rom.py index cfa99828..aa09743e 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = 'f5f779f1820204cd019ca5293594f955' +RANDOMIZERBASEHASH = '3c651a38ea79504029c71b382c9c17da' class JsonRom(object): diff --git a/asm/owrando.asm b/asm/owrando.asm index 55420da0..166aa1e0 100644 --- a/asm/owrando.asm +++ b/asm/owrando.asm @@ -424,14 +424,16 @@ LoadMapDarkOrMixed: OWBonkGoodBeeDrop: { - LDA.l OWFlags+1 : AND.b #$02 : BNE .shuffled + LDA.l OWFlags+1 : AND.b #!FLAG_OW_BONKDROP : BNE .shuffled .vanilla ; what we wrote over STZ.w $0DD0,X LDA.l BottleContentsOne : ORA.l BottleContentsTwo ORA.l BottleContentsThree : ORA.l BottleContentsFour RTL .shuffled - PHY : TXY + LDA.w $0DD0,X : BNE + + JMP .return+1 + + PHY : TXY LDA.l RoomDataWRAM[$0120].high : AND.b #$02 : PHA : BNE + ; check if collected LDA.b #$1B : STA $12F ; JSL Sound_SetSfx3PanLong ; seems that when you bonk, there is a pending bonk sfx, so we clear that out and replace with reveal secret sfx + @@ -495,33 +497,37 @@ OWBonkGoodBeeDrop: ; spawn itemget item .spawn_item ; A = item id ; Y = bonk sprite slot ; S = Collected PLX : BEQ + : LDA.b #$00 : STA.w $0DD0,Y : BRA .return - + LDA.b #$01 : STA !REDRAW + + PHA + + LDA.b #$01 : STA !FORCE_HEART_SPAWN LDA.b #$EB : STA.l $7FFE00 JSL Sprite_SpawnDynamically+15 ; +15 to skip finding a new slot, use existing sprite - TYX : STZ.w $0F20,X ; layer the sprite is on - + LDA.b #$01 : STA.w !SPRITE_REDRAW,Y + + PLA : STA.w $0E80,Y + ; affects the rate the item moves in the Y/X direction - STZ.w $0D40,X + LDA.b #$00 : STA.w $0D40,Y LDA.b #$0A : STA.w $0D50,Y LDA.b #$1A : STA.w $0F80,Y ; amount of force (gives height to the arch) LDA.b #$FF : STA.w $0B58,Y ; stun timer LDA.b #$30 : STA.w $0F10,Y ; aux delay timer 4 ?? dunno what that means + LDA.b #$00 : STA.w $0F20,Y ; layer the sprite is on + ; sets the tile type that is underneath the sprite, water - LDA.b #$09 : STA.l $7FF9C2,X ; TODO: Figure out how to get the game to set this + TYX : LDA.b #$09 : STA.l $7FF9C2,X ; TODO: Figure out how to get the game to set this ; sets OW event bitmask flag, uses free RAM LDA.l OWBonkPrizeTable[42].flag : STA.w $0ED0,Y - + ; determines the initial spawn point of item LDA.w $0D00,Y : SEC : SBC.l OWBonkPrizeTable[42].vert_offset : STA.w $0D00,Y LDA.w $0D20,Y : SBC #$00 : STA.w $0D20,Y - LDA.b #$01 : STA !REDRAW - .return PLY LDA #$08 ; makes original good bee not spawn @@ -533,8 +539,10 @@ OWBonkDrops: { CMP.b #$D8 : BEQ + RTL - + LDA.l OWFlags+1 : AND.b #!FLAG_OW_CROSSED : BNE + + + LDA.l OWFlags+1 : AND.b #!FLAG_OW_BONKDROP : BNE + JSL.l Sprite_TransmuteToBomb : RTL + + LDA.w $0DD0,Y : BNE + + RTL + ; loop thru rando bonk table to find match @@ -618,13 +626,17 @@ OWBonkDrops: ; spawn itemget item .spawn_item ; A = item id ; Y = tree sprite slot ; S = Collected, FlagBitmask, X (row + 2) PLX : BEQ + : LDA.b #$00 : STA.w $0DD0,Y : JMP .return ; S = FlagBitmask, X (row + 2) - + LDA 2,S : TAX : INX + + PHA - LDA.b #$01 : STA !REDRAW + LDA.b #$01 : STA !FORCE_HEART_SPAWN LDA.b #$EB : STA.l $7FFE00 JSL Sprite_SpawnDynamically+15 ; +15 to skip finding a new slot, use existing sprite + LDA.b #$01 : STA.w !SPRITE_REDRAW,Y + + PLA : STA.w $0E80,Y + ; affects the rate the item moves in the Y/X direction LDA.b #$00 : STA.w $0D40,Y LDA.b #$0A : STA.w $0D50,Y @@ -637,14 +649,12 @@ OWBonkDrops: ; sets OW event bitmask flag, uses free RAM PLA : STA.w $0ED0,Y ; S = X (row + 2) - + ; determines the initial spawn point of item PLX : INX : INX : INX LDA.w $0D00,Y : SEC : SBC.w OWBonkPrizeData,X : STA.w $0D00,Y LDA.w $0D20,Y : SBC #$00 : STA.w $0D20,Y - LDA.b #$01 : STA !REDRAW - PLB : RTL .return @@ -958,7 +968,9 @@ OWNewDestination: OWLoadSpecialArea: { LDA.l Overworld_LoadSpecialOverworld_RoomId,X : STA.b $A0 - JSL Overworld_LoadSpecialOverworld ; sets M and X flags + CMP.w #$0182 : BNE + + JSL ZoraSplashGfxFix + + JSL Overworld_LoadSpecialOverworld ; sets M and X flags TYX LDY.b #$00 CPX.b #$01 : BNE + ; check if going to water transition diff --git a/data/base2current.bps b/data/base2current.bps index 49650e2da50eb26d5f164437c9493f2468ba1965..ab93a09e84c87d32990525473ea45acda28d3f49 100644 GIT binary patch delta 15397 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 TcFFN3AK~tM=Jm(lbiMw6_fO6& delta 14923 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 R-r^_t_1|0mkJoMR{(n{5-pl|1 From e1092b7def51af7d2640ce0e2c6aa1ccaaffe3c1 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 7 May 2023 20:29:16 -0500 Subject: [PATCH 118/196] Version bump 0.3.0.7 --- CHANGELOG.md | 12 ++++++++++-- OverworldShuffle.py | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 135502b5..23e4234e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,18 @@ # Changelog +## 0.3.0.7 +- \~Merged in DR v1.2.0.16~ +- Major overhaul of how item GFX are drawn on screen + - Bonk prize GFX can now all be displayed simultaneously + - Rupee items that are in-plain-sight are now animated + - Narrow items are now centered within their tile space + - Fixed issue with pottery items showing bad GFX after map check or medallion use +- Fixed issue with bonk drop items causing duplicate sprite spawns + ## 0.3.0.6 - \~Merged in DR v1.2.0.15~ - Fixed Tower of Hera music silence issue -- Improved GT crystal cutscene -- Fixed issue with bonk drop items causing duplicate sprite spawns +- Improved symmetrical GT crystal cutscene - Changed bonk prizes to not mark as collected unless it is visible on screen ## 0.3.0.5 diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 3e3cf192..301af8cb 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -7,7 +7,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType from OverworldGlitchRules import create_owg_connections from Utils import bidict -version_number = '0.3.0.6' +version_number = '0.3.0.7' # branch indicator is intentionally different across branches version_branch = '-u' From 393cbdd0abe160b7bdd77edac5c6a91ec7d2795d Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 8 May 2023 05:03:53 -0500 Subject: [PATCH 119/196] Apples/BeeTraps/Fairies now spawn automatically under pots --- Rom.py | 2 +- data/base2current.bps | Bin 106730 -> 106752 bytes source/item/FillUtil.py | 5 +++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Rom.py b/Rom.py index aa09743e..17c948ab 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '3c651a38ea79504029c71b382c9c17da' +RANDOMIZERBASEHASH = '08f762abe1d3687e07eb584ef962b9c0' class JsonRom(object): diff --git a/data/base2current.bps b/data/base2current.bps index ab93a09e84c87d32990525473ea45acda28d3f49..14b7becf7237325b18adac97c1ceee1e349a9a4f 100644 GIT binary patch delta 670 zcmWm4ZAcSw9KiAWopU=Un-*$w6I-`RQ?ab}ys2e@73w7Dg-DHhp^2c86*;v3teFp; z&JOzRN%Dqr-^WAoc5=_94|wk{}^(q&=^fd*`*At`gMd$bfLk5 z_n~Gqcv+;BZIH1Y;}S0!S~eqkG8vL;j&KEi4E<2dR&SmHf&JYOhiY-nwW&)c*50q8 zs%N;-OK4IMtGX8e1aa5%?v*k(%K4NdTkHB?_=5?W>aAWzuNa{f-wrFd=s`tq{0mPJ zl8K0?^LYd^NoP{pN1!sPI3*2%XsIHld;)2tSV~#~sU;yL9d0v27r60fGZ>%}r&-`C zX=ukS7AR5Dl?=19(5VQV!vPBvt8dre_vTOcF;QC48!+N^3tWNYxWWqip$9iwp&V{v zWQDU(j#sT<1U>#|1zR#^8(827?zDlf@cCUSPXIR$lEzQ+={}V{H!^%-dj4K)+N}@Z zuni`m5ZBqEOr;aoLjK$}LD&cyYFWj)q$O| delta 655 zcmWm4eMl2=9LMqdo_n~>HjUPtCb^xFHl!y^_lSfEqN1xPA_OIiw22Cd!Y1Rl#l$IR zlT&`8u_O@h61H8Zl)>;6{}Bq;1N~7NWQ4H5lq5_Da(}&FANZhUMQTYA9)!%1p-ISM zi=aWK`|z`b^?;My7uW?jfOc_?%mR>!D;fPVMTfwxgr2f4DhzMgZ`8Ei6ys8<@iB9p zLy&R|jL@Y57srKmKaW(jH_qkJ8{;!mV{~8or}Hy(&H9u}gGT7>D7&PxYK175>PDgb z_fw51R3lRA2cX&zxYR3#-WEh}CPPxyQ7%8g&=19I?bcjYWpm@};f7`&Btw|wT_3vOYy z*%-tL8%zU*TkKGxk&CNS;p40E_|cihGx&)e?kgIc5%$(ata89POWokmPEh?E7xj{8 zSFt!Ka!9r~Dsqh8WN0Ix`k8N7SIHA^Bm(#JkZ5cm`IjLpaSrZsfDTG=&;do~uX-bX zqxdJdY{VU&2ruW?=1?KuIgd_?y`IR--M$FlG>0 Date: Mon, 8 May 2023 07:49:38 -0500 Subject: [PATCH 120/196] Added better GFX for fairy and good bee --- Rom.py | 2 +- data/base2current.bps | Bin 106752 -> 106950 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Rom.py b/Rom.py index 17c948ab..5718b113 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '08f762abe1d3687e07eb584ef962b9c0' +RANDOMIZERBASEHASH = '939310f7bb9ea2553c431e3dcdbf1ba3' class JsonRom(object): diff --git a/data/base2current.bps b/data/base2current.bps index 14b7becf7237325b18adac97c1ceee1e349a9a4f..db98d6082954232e388b10100f797e7d08626d7c 100644 GIT binary patch delta 9492 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 F{{d~6Wsv{? delta 9611 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 V@|Mm5@Wxy8ulKgs Date: Tue, 9 May 2023 21:36:38 -0500 Subject: [PATCH 121/196] More GFX updates - Apples and Chickens now have GFX - Fixed issue with Menu not allowing DPad input with standing item on screen - Fixed issue with keys not drawing properly during tablet animation --- Rom.py | 2 +- data/base2current.bps | Bin 106950 -> 107092 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Rom.py b/Rom.py index 5718b113..47ea824a 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '939310f7bb9ea2553c431e3dcdbf1ba3' +RANDOMIZERBASEHASH = '333e288ccb654220c0b492f4bf030e0c' class JsonRom(object): diff --git a/data/base2current.bps b/data/base2current.bps index db98d6082954232e388b10100f797e7d08626d7c..e6fe5db2ed9421aaa85e2d587be04fdfc66f977c 100644 GIT binary patch delta 7380 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 From 66cec505def502b056c31e1be2c02757742a9de4 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Tue, 9 May 2023 21:49:11 -0500 Subject: [PATCH 122/196] Only apply powder patch if flag is set --- Rom.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Rom.py b/Rom.py index 47ea824a..dc955bda 100644 --- a/Rom.py +++ b/Rom.py @@ -1647,7 +1647,8 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): # powder patch: remove the need to leave the screen after powder, since it causes problems for potion shop at race game # temporarally we are just nopping out this check we will conver this to a rom fix soon. - rom.write_bytes(0x02F539, [0xEA, 0xEA, 0xEA, 0xEA, 0xEA] if world.powder_patch_required[player] else [0xAD, 0xBF, 0x0A, 0xF0, 0x4F]) + if world.powder_patch_required[player]: + rom.write_bytes(0x02F539, [0xEA, 0xEA, 0xEA, 0xEA, 0xEA]) # sprite patches rom.write_byte(snes_to_pc(0x0DB7D1), 0x03) # patch apple sprites to not permadeatch like enemies From 2dd0a64a4be6b4878516595438d4b6c1909b69d1 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Tue, 9 May 2023 21:53:06 -0500 Subject: [PATCH 123/196] Version bump 0.3.0.8 --- CHANGELOG.md | 5 +++++ OverworldShuffle.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23e4234e..44dc184d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 0.3.0.8 +- All Bonk prize GFX are no longer using the Power Star placeholder GFX +- Fixed issue with dislaying Key GFX during tablet animations +- Fixed issue with DPad input being disabled in Pause Menu if an item GFX is on screen + ## 0.3.0.7 - \~Merged in DR v1.2.0.16~ - Major overhaul of how item GFX are drawn on screen diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 301af8cb..bd8a05d2 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -7,7 +7,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType from OverworldGlitchRules import create_owg_connections from Utils import bidict -version_number = '0.3.0.7' +version_number = '0.3.0.8' # branch indicator is intentionally different across branches version_branch = '-u' From d606a84c35a5e5af6bd2c8e881c0afde2a20ad10 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Fri, 12 May 2023 21:31:24 -0500 Subject: [PATCH 124/196] ROM Updates - Fix Bonk count capping at 99 in credits - Fix Hera boss music still plays after boss defeated - Fixed Murahdahla in Rainstate --- ItemList.py | 15 ++++++++++++++- Rom.py | 2 +- Text.py | 2 +- asm/owrando.asm | 4 +--- data/base2current.bps | Bin 107092 -> 107085 bytes 5 files changed, 17 insertions(+), 6 deletions(-) diff --git a/ItemList.py b/ItemList.py index 437e422e..a2dd7552 100644 --- a/ItemList.py +++ b/ItemList.py @@ -1270,7 +1270,20 @@ def make_custom_item_pool(world, player, progressive, shuffle, difficulty, timer itemtotal = itemtotal + customitemarray["generickeys"] customitems = [ - "Bow", "Silver Arrows", "Blue Boomerang", "Red Boomerang", "Hookshot", "Mushroom", "Magic Powder", "Fire Rod", "Ice Rod", "Bombos", "Ether", "Quake", "Lamp", "Hammer", "Shovel", "Ocarina", "Bug Catching Net", "Book of Mudora", "Cane of Somaria", "Cane of Byrna", "Cape", "Pegasus Boots", "Power Glove", "Titans Mitts", "Progressive Glove", "Flippers", "Piece of Heart", "Boss Heart Container", "Sanctuary Heart Container", "Master Sword", "Tempered Sword", "Golden Sword", "Blue Shield", "Red Shield", "Mirror Shield", "Progressive Shield", "Blue Mail", "Red Mail", "Progressive Armor", "Magic Upgrade (1/2)", "Magic Upgrade (1/4)", "Bomb Upgrade (+5)", "Bomb Upgrade (+10)", "Arrow Upgrade (+5)", "Arrow Upgrade (+10)", "Single Arrow", "Arrows (10)", "Single Bomb", "Bombs (3)", "Rupee (1)", "Rupees (5)", "Rupees (20)", "Rupees (50)", "Rupees (100)", "Rupees (300)", "Rupoor", "Blue Clock", "Green Clock", "Red Clock", "Progressive Bow", "Bombs (10)", "Triforce Piece", "Triforce" + "Bow", "Silver Arrows", "Blue Boomerang", "Red Boomerang", "Hookshot", "Mushroom", "Magic Powder", + "Fire Rod", "Ice Rod", "Bombos", "Ether", "Quake", + "Lamp", "Hammer", "Shovel", "Ocarina", "Bug Catching Net", "Book of Mudora", + "Cane of Somaria", "Cane of Byrna", "Cape", + "Pegasus Boots", "Power Glove", "Titans Mitts", "Progressive Glove", "Flippers", + "Piece of Heart", "Boss Heart Container", "Sanctuary Heart Container", + "Master Sword", "Tempered Sword", "Golden Sword", + "Blue Shield", "Red Shield", "Mirror Shield", "Progressive Shield", + "Blue Mail", "Red Mail", "Progressive Armor", "Magic Upgrade (1/2)", "Magic Upgrade (1/4)", + "Bomb Upgrade (+5)", "Bomb Upgrade (+10)", "Arrow Upgrade (+5)", "Arrow Upgrade (+10)", + "Single Arrow", "Arrows (10)", "Single Bomb", "Bombs (3)", "Bombs (10)", + "Rupee (1)", "Rupees (5)", "Rupees (20)", "Rupees (50)", "Rupees (100)", "Rupees (300)", "Rupoor", + "Blue Clock", "Green Clock", "Red Clock", + "Progressive Bow", "Triforce Piece", "Triforce" ] for customitem in customitems: pool.extend([customitem] * customitemarray[get_custom_array_key(customitem)]) diff --git a/Rom.py b/Rom.py index dc955bda..29d0d0c1 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '333e288ccb654220c0b492f4bf030e0c' +RANDOMIZERBASEHASH = '31a41e7a988597917f12db7107886607' class JsonRom(object): diff --git a/Text.py b/Text.py index bf4f22cb..e3614056 100644 --- a/Text.py +++ b/Text.py @@ -2020,6 +2020,6 @@ class TextTable(object): text['ganon_phase_3_no_silvers_alt'] = CompressedTextMapper.convert("You can't best me without silver arrows!") text['ganon_phase_3_no_silvers'] = CompressedTextMapper.convert("You can't best me without silver arrows!") text['ganon_phase_3_silvers'] = CompressedTextMapper.convert("Oh no! Silver! My one true weakness!") - text['murahdahla'] = CompressedTextMapper.convert("Hello @. I\nam Murahdahla, brother of\nSahasrahla and Aginah. Behold the power of\ninvisibility.\n{PAUSE3}\n… … …\nWait! you can see me? I knew I should have\nhidden in a hollow tree.") + text['murahdahla'] = CompressedTextMapper.convert("Hello @. I\nam Murahdahla, brother of\nSahasrahla and Aginah. Behold the power of\ninvisibility.\n{PAUSE3}\n… … …\nWait! You can see me? I knew I should have\nhidden in a hollow tree.") text['end_pad_data'] = bytearray([0xfb]) text['terminator'] = bytearray([0xFF, 0xFF]) diff --git a/asm/owrando.asm b/asm/owrando.asm index 166aa1e0..d74718dd 100644 --- a/asm/owrando.asm +++ b/asm/owrando.asm @@ -968,9 +968,7 @@ OWNewDestination: OWLoadSpecialArea: { LDA.l Overworld_LoadSpecialOverworld_RoomId,X : STA.b $A0 - CMP.w #$0182 : BNE + - JSL ZoraSplashGfxFix - + JSL Overworld_LoadSpecialOverworld ; sets M and X flags + JSL Overworld_LoadSpecialOverworld ; sets M and X flags TYX LDY.b #$00 CPX.b #$01 : BNE + ; check if going to water transition diff --git a/data/base2current.bps b/data/base2current.bps index e6fe5db2ed9421aaa85e2d587be04fdfc66f977c..7c4263d9c2eef6aae47ffd0d16ddf328b0e5257d 100644 GIT binary patch delta 3805 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 From 2a008dfc3e3568a170e49ec904b9de1a17f3091c Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sat, 13 May 2023 02:16:36 -0500 Subject: [PATCH 125/196] Added a TF Cutscene when getting the TF item - Also fixed an issue with vanilla enemy key drops displaying incorrectly --- Rom.py | 6 +++--- data/base2current.bps | Bin 107085 -> 107444 bytes 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Rom.py b/Rom.py index 29d0d0c1..06ccb949 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '31a41e7a988597917f12db7107886607' +RANDOMIZERBASEHASH = '37055215524a94f346e892b7a716c2ef' class JsonRom(object): @@ -2489,7 +2489,7 @@ def write_strings(rom, world, player, team): tt['ganon_fall_in_alt'] = 'Why are you even here?\n You can\'t even hurt me! Get the Triforce Pieces.' tt['ganon_phase_3_alt'] = 'Seriously? Go Away, I will not Die.' tt['sign_ganon'] = 'Go find the Triforce pieces... Ganon is invincible!' - tt['murahdahla'] = "Hello @. I\nam Murahdahla, brother of\nSahasrahla and Aginah. Behold the power of\ninvisibility.\n\n\n\n… … …\n\nWait! you can see me? I knew I should have\nhidden in a hollow tree. If you bring\n%d triforce pieces, I can reassemble it." % int(world.treasure_hunt_count[player]) + tt['murahdahla'] = "Hello @. I\nam Murahdahla, brother of\nSahasrahla and Aginah. Behold the power of\ninvisibility.\n\n\n\n… … …\n\nWait! You can see me? I knew I should have\nhidden in a hollow tree. If you bring\n%d triforce pieces, I can reassemble it." % int(world.treasure_hunt_count[player]) elif world.goal[player] in ['pedestal']: tt['ganon_fall_in_alt'] = 'Why are you even here?\n You can\'t even hurt me! Your goal is at the pedestal.' tt['ganon_phase_3_alt'] = 'Seriously? Go Away, I will not Die.' @@ -2498,7 +2498,7 @@ def write_strings(rom, world, player, team): if world.goal[player] == 'trinity': trinity_crystal_text = ('%d crystal to beat Ganon.' if world.crystals_needed_for_ganon[player] == 1 else '%d crystals to beat Ganon.') % world.crystals_needed_for_ganon[player] tt['sign_ganon'] = 'Three ways to victory! %s Get to it!' % trinity_crystal_text - tt['murahdahla'] = "Hello @. I\nam Murahdahla, brother of\nSahasrahla and Aginah. Behold the power of\ninvisibility.\n\n\n\n… … …\n\nWait! you can see me? I knew I should have\nhidden in a hollow tree. If you bring\n%d triforce pieces, I can reassemble it." % int(world.treasure_hunt_count[player]) + tt['murahdahla'] = "Hello @. I\nam Murahdahla, brother of\nSahasrahla and Aginah. Behold the power of\ninvisibility.\n\n\n\n… … …\n\nWait! You can see me? I knew I should have\nhidden in a hollow tree. If you bring\n%d triforce pieces, I can reassemble it." % int(world.treasure_hunt_count[player]) elif world.goal[player] == 'ganonhunt': tt['sign_ganon'] = 'Go find the Triforce pieces to beat Ganon' elif world.goal[player] == 'completionist': diff --git a/data/base2current.bps b/data/base2current.bps index 7c4263d9c2eef6aae47ffd0d16ddf328b0e5257d..c4404bdc41bd150472e3a0742ff83513fae79525 100644 GIT binary patch delta 15521 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

2pV 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 delta 15119 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 P0z^Yi+1sMOqksE Date: Sat, 13 May 2023 02:23:15 -0500 Subject: [PATCH 126/196] Version bump 0.3.1.0 --- CHANGELOG.md | 7 +++++++ OverworldShuffle.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44dc184d..790cfaf6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 0.3.1.0 +- Added new Triforce Cutscene when getting Triforce item (turning in TF Pieces) +- Fixed issue with enemy key drops displaying the wrong GFX +- Fixed issue with boss music playing in Hera after boss is defeated +- Fixed issue that limited the Bonk count to cap at 99 +- Made Murahdahla interactable on Pyramid in Rainstate + ## 0.3.0.8 - All Bonk prize GFX are no longer using the Power Star placeholder GFX - Fixed issue with dislaying Key GFX during tablet animations diff --git a/OverworldShuffle.py b/OverworldShuffle.py index bd8a05d2..0c483b14 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -7,7 +7,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType from OverworldGlitchRules import create_owg_connections from Utils import bidict -version_number = '0.3.0.8' +version_number = '0.3.1.0' # branch indicator is intentionally different across branches version_branch = '-u' From f19b19ea0065a42c0d28200570f2c196e6f7b7de Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sat, 3 Jun 2023 16:23:04 -0500 Subject: [PATCH 127/196] Updated documentation for Good Bee addition to Bonk Drops --- README.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 33807afe..0bae614a 100644 --- a/README.md +++ b/README.md @@ -248,38 +248,37 @@ New flute spots are chosen at random with minimum bias. ## Bonk Drop Shuffle (--bonk_drops) -This adds 41 new item locations to the game. These bonk locations are limited to the ones that drop a static item in the vanilla game. +This adds 42 new item locations to the game. These bonk locations are limited to the ones that drop a static item in the vanilla game. - Bonk Locations consist of some trees, rocks, and statues - 33 Trees - 8 of the tree locations require Agahnim to be defeated to access the item - 6 Rocks - 1 of the rocks drops 2 items - - 1 Statue + - 2 Statues + - 1 of them is the Cold Fairy Statue next to Ice Rod Cave - Bonk locations can be collected by bonking into them with the Pegasus Boots or using the Quake Medallion - One of the bonk locations are guaranteed to have a full magic decanter - Some of the drops can be farmed repeatedly, but only increments the collection rate once - All of the bonk trees have been given an alternate color (and all non-bonk trees are reverted to normal tree color) - Some screens are coded to change the "alternate tree color", some of them are strange (just how the vanilla game does it) - Rocks and statues are unable to be made to have a different color -- Since Fairies and Apples are new items that can appear in plain sight, they don't have a proper graphic for them yet. For now, they show up as Power Stars -Here is a map that shows all the [Bonk Locations](https://media.discordapp.net/attachments/783989090017738753/1000880877548609607/unknown.png?width=1399&height=702). FYI, the 2-4 and 2-3-4 refer to the tree numbers that have the items. The 2 by Dark Fortune Teller indicate that there are 2 bonk items there. The stars with a green square are all Bonk Locations that are unlocked after you kill Aga 1. +Here is a map that shows all the [Bonk Locations](https://cdn.discordapp.com/attachments/1105770688649895968/1105770806769877072/bonkdrops.png?width=1399&height=702). FYI, the numbers indicate how many bonk items there. The stars with a green square are all Bonk Locations that are unlocked after you kill Aga 1. As far as map trackers, Bonk Locations are supported on `CodeTracker` when the Bonk Drops option is enabled. -Future Note: This does NOT include the Good Bee (Cold Bee) Cave Statue...yet. In the future, this could be an additional item location. - #### Items Added To Pool: - 15 Fairies - 8 Apples - 6 Bee Traps - 3 Red Rupees - 3 Blue Rupees -- 2 Single Bomb +- 2 Single Bombs - 2 Small Hearts - 1 Large Magic Decanter - 1 8x Bomb Pack +- 1 Good Bee ## New Goal Options (--goal) From 0ab54def8b9ac8908b3627df92c01a69d1dcfe09 Mon Sep 17 00:00:00 2001 From: aerinon Date: Thu, 8 Jun 2023 10:25:05 -0600 Subject: [PATCH 128/196] Removed backup locations for Dungeon Only and Major Only algorithms. If item cannot be placed in the appropriate location, the seed will fail to generate instead. --- Fill.py | 6 +++++- RELEASENOTES.md | 1 + source/item/FillUtil.py | 12 +----------- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/Fill.py b/Fill.py index 9acf7d45..f6582a16 100644 --- a/Fill.py +++ b/Fill.py @@ -279,6 +279,10 @@ def recovery_placement(item_to_place, locations, world, state, base_state, itemp if spot_to_fill: return spot_to_fill return None + # explicitly fail these cases + elif world.algorithm in ['dungeon_only', 'major_only']: + raise FillError(f'Rare placement for {world.algorithm} detected. {item_to_place} unable to be placed.' + f' Try a different seed') else: other_locations = [x for x in locations if x not in attempted] for location in other_locations: @@ -419,7 +423,7 @@ def distribute_items_restrictive(world, gftower_trash=False, fill_locations=None else: max_trash = gt_count scaled_trash = math.floor(max_trash * scale_factor) - if world.goal[player] in ['triforcehunt', 'trinity', 'ganonhunt']: + if world.goal[player] in ['triforcehunt', 'trinity', 'ganonhunt'] or world.algorithm == 'dungeon_only': gftower_trash_count = random.randint(scaled_trash, max_trash) else: gftower_trash_count = random.randint(0, scaled_trash) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 4f622e60..33b0a50e 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -110,6 +110,7 @@ These are now independent of retro mode and have three options: None, Random, an # Bug Fixes and Notes * 1.2.0.17u + * Removed backup locations for Dungeon Only and Major Only algorithms. If item cannot be placed in the appropriate location, the seed will fail to generate instead * Fix for Non-ER Inverted Experimental (Aga and GT weren't logically swapped) * Fix for customizer setting crystals to 0 for either GT/Ganon * 1.2.0.16u diff --git a/source/item/FillUtil.py b/source/item/FillUtil.py index 58558263..6a055584 100644 --- a/source/item/FillUtil.py +++ b/source/item/FillUtil.py @@ -151,9 +151,6 @@ def create_item_pool_config(world): config.item_pool[player] = determine_major_items(world, player) config.location_groups[0].locations = set(groups.locations) config.reserved_locations[player].update(groups.locations) - backup = (mode_grouping['Heart Pieces'] + mode_grouping['Dungeon Trash'] + mode_grouping['Shops'] - + mode_grouping['Overworld Trash'] + mode_grouping['GT Trash'] + mode_grouping['RetroShops']) - config.location_groups[1].locations = set(backup) elif world.algorithm == 'dungeon_only': config.location_groups = [ LocationGroup('Dungeons'), @@ -171,9 +168,6 @@ def create_item_pool_config(world): for player in range(1, world.players + 1): config.item_pool[player] = determine_major_items(world, player) config.location_groups[0].locations = set(dungeon_set) - backup = (mode_grouping['Heart Pieces'] + mode_grouping['Overworld Major'] - + mode_grouping['Overworld Trash'] + mode_grouping['Shops'] + mode_grouping['RetroShops']) - config.location_groups[1].locations = set(backup) def district_item_pool_config(world): @@ -419,11 +413,7 @@ def filter_locations(item_to_place, locations, world, vanilla_skip=False, potion if item_to_place.name in config.item_pool[item_to_place.player]: restricted = config.location_groups[0].locations filtered = [l for l in locations if l.name in restricted] - if len(filtered) == 0: - restricted = config.location_groups[1].locations - filtered = [l for l in locations if l.name in restricted] - # bias toward certain location in overflow? (thinking about this for major_bias) - return filtered if len(filtered) > 0 else locations + return filtered if world.algorithm == 'district': config = world.item_pool_config if ((isinstance(item_to_place,str) and item_to_place == 'Placeholder') From a842939e923a6f43a9ef2a80cd313305d9f72aa1 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Tue, 13 Jun 2023 18:36:16 -0500 Subject: [PATCH 129/196] Various region/rule reorganization to match DR --- CHANGELOG.md | 4 +- DoorShuffle.py | 4 +- DungeonGenerator.py | 4 +- EntranceShuffle.py | 6 +- ItemList.py | 16 +- Main.py | 2 +- OWEdges.py | 181 ++++----- OverworldGlitchRules.py | 74 ++-- OverworldShuffle.py | 575 ++++++++++++++------------- Regions.py | 303 +++++++------- Rules.py | 327 +++++++-------- source/item/District.py | 6 +- source/overworld/EntranceShuffle2.py | 16 +- 13 files changed, 753 insertions(+), 765 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 790cfaf6..1a8b1f70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -381,7 +381,7 @@ - Removed sortedcontainers dependency ### 0.1.6.7 -- Mountain Entry and West Death Mountain are now Swapped independently (Old Man rescue is always in your starting world) +- Mountain Pass and West Death Mountain are now Swapped independently (Old Man rescue is always in your starting world) - Fixed issue with AT/GT access logic - Improved spoiler log playthru accuracy - Fixed Boss Music when boss room is entered thru straight stairs @@ -407,7 +407,7 @@ ### 0.1.6.2 - Added Balanced option for Flute Shuffle -- Fixed issue with Flute Spot to Mountain Entry softlocking +- Fixed issue with Flute Spot to Mountain Pass softlocking - Fixed logic bug with Inverted Kakariko Portal ### 0.1.6.1 diff --git a/DoorShuffle.py b/DoorShuffle.py index eb9927ea..86410ed4 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -473,7 +473,7 @@ def choose_portals(world, player): if portal_region.type == RegionType.LightWorld: world.get_portal(portal, player).light_world = True if name in world.inaccessible_regions[player] or (hc_flag and portal != 'Hyrule Castle South'): - name_key = 'Desert Ledge' if name == 'Desert Palace Entrance (North) Spot' else name + name_key = 'Desert Ledge' if name == 'Desert Ledge Keep' else name region_map[name_key].append(portal) inaccessible_portals.append(portal) else: @@ -626,7 +626,7 @@ def analyze_portals(world, player): if portal_region.type == RegionType.LightWorld: world.get_portal(portal, player).light_world = True if name in world.inaccessible_regions[player]: - name_key = 'Desert Ledge' if name == 'Desert Palace Entrance (North) Spot' else name + name_key = 'Desert Ledge' if name == 'Desert Ledge Keep' else name region_map[name_key].append(portal) inaccessible_portals.append(portal) else: diff --git a/DungeonGenerator.py b/DungeonGenerator.py index f97f8ecf..2056fe4c 100644 --- a/DungeonGenerator.py +++ b/DungeonGenerator.py @@ -1538,8 +1538,8 @@ def calc_allowance_and_dead_ends(builder, connections_tuple, world, player): if entrance in connections.keys(): enabling_region = connections[entrance] check_list = list(potentials[enabling_region]) - if enabling_region.name in ['Desert Ledge', 'Desert Palace Entrance (North) Spot']: - alternate = 'Desert Palace Entrance (North) Spot' if enabling_region.name == 'Desert Ledge' else 'Desert Ledge' + if enabling_region.name in ['Desert Ledge', 'Desert Ledge Keep']: + alternate = 'Desert Ledge Keep' if enabling_region.name == 'Desert Ledge' else 'Desert Ledge' if world.get_region(alternate, player) in potentials: check_list.extend(potentials[world.get_region(alternate, player)]) connecting_entrances = [x for x in check_list if x != entrance and x not in dead_entrances and x not in drop_entrances_allowance] diff --git a/EntranceShuffle.py b/EntranceShuffle.py index ec99cd9f..ff875c59 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -1298,7 +1298,7 @@ def full_shuffle_dungeons(world, Dungeon_Exits, player): dw_must_exit.append(ledge.pop()) dw_related.extend(ledge) if not world.is_tile_swapped(0x30, player): - if 'Desert Palace Mouth' in world.inaccessible_regions[player]: + if 'Desert Mouth' in world.inaccessible_regions[player]: lw_entrances.remove('Desert Palace Entrance (East)') lw_must_exit.append('Desert Palace Entrance (East)') else: @@ -1501,8 +1501,8 @@ def connect_inaccessible_regions(world, lw_entrances, dw_entrances, caves, playe inaccessible_regions = list(world.inaccessible_regions[player]) # find OW regions that don't have a multi-entrance dungeon exit connected - glitch_regions = ['Central Cliffs', 'Eastern Cliff', 'Desert Northeast Cliffs', 'Hyrule Castle Water', - 'Dark Central Cliffs', 'Darkness Cliff', 'Mire Northeast Cliffs', 'Pyramid Water'] + glitch_regions = ['Central Cliffs', 'Eastern Cliff', 'Desert Northern Cliffs', 'Hyrule Castle Water', + 'Dark Central Cliffs', 'Darkness Cliff', 'Mire Northern Cliffs', 'Pyramid Water'] multi_dungeon_exits = { 'Hyrule Castle South Portal', 'Hyrule Castle West Portal', 'Hyrule Castle East Portal', 'Sanctuary Portal', 'Desert South Portal', 'Desert West Portal', diff --git a/ItemList.py b/ItemList.py index a2dd7552..01b95d68 100644 --- a/ItemList.py +++ b/ItemList.py @@ -213,7 +213,7 @@ def generate_itempool(world, player): loc.forced_item = loc.item if not world.is_tile_swapped(0x18, player): - region = world.get_region('Kakariko Area',player) + region = world.get_region('Kakariko Village',player) loc = Location(player, "Flute Activation", parent=region) region.locations.append(loc) @@ -589,10 +589,10 @@ def create_dynamic_shop_locations(world, player): def create_farm_locations(world, player): bush_bombs = ['Flute Boy Approach Area', - 'Kakariko Area', - 'Village of Outcasts Area', + 'Kakariko Village', + 'Village of Outcasts', 'Forgotten Forest Area', - 'Bat Cave Ledge', + 'Blacksmith Ledge', 'East Dark Death Mountain (Bottom)'] rock_bombs = ['Links House Area', 'Dark Chapel Area', @@ -606,7 +606,7 @@ def create_farm_locations(world, player): 'Dark Fortune Area', 'Qirn Jump Area', 'Shield Shop Area', - 'Palace of Darkness Nook Area', + 'Darkness Nook Area', 'Swamp Nook Area', 'Dark South Pass Area'] bonk_bombs = ['Kakariko Fortune Area', 'Dark Graveyard Area'] #TODO: Flute Boy Approach Area and Bonk Rock Ledge are available post-Aga @@ -622,10 +622,10 @@ def create_farm_locations(world, player): 'Hype Cave Area', 'Dark South Pass Area', 'Bumper Cave Area'] - pre_aga_tree_pulls = ['Hyrule Castle Courtyard', 'Mountain Entry Area'] + pre_aga_tree_pulls = ['Hyrule Castle Courtyard', 'Mountain Pass Area'] post_aga_tree_pulls = ['Statues Area', 'Eastern Palace Area'] - bush_crabs = ['Lost Woods East Area', 'Mountain Entry Area'] + bush_crabs = ['Lost Woods East Area', 'Mountain Pass Area'] pre_aga_bush_crabs = ['Lumberjack Area', 'South Pass Area'] rock_crabs = ['Desert Pass Area'] @@ -1118,8 +1118,6 @@ def get_pool_core(world, player, progressive, shuffle, difficulty, treasure_hunt pool.remove('Fighter Sword') pool.extend(['Rupees (50)']) - #TODO: Remove test placements - #place_item('Purple Chest', 'Magic Mirror') if timer in ['timed', 'timed-countdown']: pool.extend(diff.timedother) clock_mode = 'stopwatch' if timer == 'timed' else 'countdown' diff --git a/Main.py b/Main.py index 7492b516..66122931 100644 --- a/Main.py +++ b/Main.py @@ -786,7 +786,7 @@ def create_playthrough(world): prog_locations = [location for location in world.get_filled_locations() if location.item.advancement or world.goal[location.player] == 'completionist'] optional_locations = ['Trench 1 Switch', 'Trench 2 Switch', 'Ice Block Drop', 'Skull Star Tile', 'Flute Activation'] - optional_locations.extend(['Hyrule Castle Courtyard Tree Pull', 'Mountain Entry Area Tree Pull']) # adding pre-aga tree pulls + optional_locations.extend(['Hyrule Castle Courtyard Tree Pull', 'Mountain Pass Tree Pull']) # adding pre-aga tree pulls optional_locations.extend(['Lumberjack Area Crab Drop', 'South Pass Area Crab Drop']) # adding pre-aga bush crabs state_cache = [None] collection_spheres = [] diff --git a/OWEdges.py b/OWEdges.py index 813d36c2..6c9eb89c 100644 --- a/OWEdges.py +++ b/OWEdges.py @@ -51,8 +51,8 @@ def create_owedges(world, player): create_owedge(player, 'East Death Mountain WS', 0x05, We, Ld, 0x03, 0x0d).coordInfo(0x0340, 0x1660), create_owedge(player, 'East Death Mountain EN', 0x05, Ea, Ld, 0x02, 0x06).coordInfo(0x0078, 0x0180), create_owedge(player, 'Death Mountain TR Pegs WN', 0x07, We, Ld, 0x02) .coordInfo(0x0078, 0x00e0), - create_owedge(player, 'Mountain Entry NW', 0x0a, No, Ld, 0x01) .coordInfo(0x04cc, 0x180a), - create_owedge(player, 'Mountain Entry SE', 0x0a, So, Ld, 0x04) .coordInfo(0x0518, 0x1012), + create_owedge(player, 'Mountain Pass NW', 0x0a, No, Ld, 0x01) .coordInfo(0x04cc, 0x180a), + create_owedge(player, 'Mountain Pass SE', 0x0a, So, Ld, 0x04) .coordInfo(0x0518, 0x1012), create_owedge(player, 'Zora Waterfall NE', 0x0f, No, Ld, 0x02) .coordInfo(0x0f80, 0x009a).special_entrance(0x82), create_owedge(player, 'Zora Waterfall SE', 0x0f, So, Ld, 0x05) .coordInfo(0x0f80, 0x1020), create_owedge(player, 'Lost Woods Pass NW', 0x10, No, Ld, 0x03) .coordInfo(0x0058, 0x1800), @@ -402,7 +402,7 @@ OWEdgeGroups = { (Op, LW, Vt, Ld, PL, 1): ( [ ['Lumberjack SW'], - ['Mountain Entry SE'], + ['Mountain Pass SE'], ['Lost Woods SE'], ['Zora Waterfall SE'], ['Kakariko Fortune SC'], @@ -420,7 +420,7 @@ OWEdgeGroups = { ['Ice Cave SE'] ], [ - ['Mountain Entry NW'], + ['Mountain Pass NW'], ['Kakariko Pond NE'], ['Kakariko Fortune NE'], ['Zora Approach NE'], @@ -764,7 +764,7 @@ OWEdgeGroupsTerrain = { (Op, LW, Vt, None, PL, 1): ( [ ['Lumberjack SW'], - ['Mountain Entry SE'], + ['Mountain Pass SE'], ['Lost Woods SE'], ['Zora Waterfall SE'], ['Kakariko Fortune SC'], @@ -780,7 +780,7 @@ OWEdgeGroupsTerrain = { ['Statues SC'] ], [ - ['Mountain Entry NW'], + ['Mountain Pass NW'], ['Kakariko Pond NE'], ['Kakariko Fortune NE'], ['Zora Approach NE'], @@ -1037,12 +1037,12 @@ OWTileRegions = bidict({ 'East Death Mountain (Bottom)': 0x05, 'Death Mountain Floating Island': 0x05, - 'Death Mountain TR Pegs': 0x07, + 'Death Mountain TR Pegs Area': 0x07, 'Death Mountain TR Pegs Ledge': 0x07, - 'Mountain Entry Area': 0x0a, - 'Mountain Entry Entrance': 0x0a, - 'Mountain Entry Ledge': 0x0a, + 'Mountain Pass Area': 0x0a, + 'Mountain Pass Entry': 0x0a, + 'Mountain Pass Ledge': 0x0a, 'Zora Waterfall Area': 0x0f, 'Zora Waterfall Water': 0x0f, @@ -1076,9 +1076,9 @@ OWTileRegions = bidict({ 'Zora Approach Ledge': 0x17, 'Zora Approach Water': 0x17, - 'Kakariko Area': 0x18, + 'Kakariko Village': 0x18, 'Kakariko Southwest': 0x18, - 'Kakariko Grass Yard': 0x18, + 'Kakariko Bush Yard': 0x18, 'Forgotten Forest Area': 0x1a, @@ -1097,7 +1097,7 @@ OWTileRegions = bidict({ 'Eastern Palace Area': 0x1e, 'Blacksmith Area': 0x22, - 'Bat Cave Ledge': 0x22, + 'Blacksmith Ledge': 0x22, 'Sand Dunes Area': 0x25, @@ -1125,11 +1125,11 @@ OWTileRegions = bidict({ 'Desert Area': 0x30, 'Desert Ledge': 0x30, - 'Desert Palace Entrance (North) Spot': 0x30, + 'Desert Ledge Keep': 0x30, 'Desert Checkerboard Ledge': 0x30, - 'Desert Palace Stairs': 0x30, - 'Desert Palace Mouth': 0x30, - 'Desert Palace Teleporter Ledge': 0x30, + 'Desert Stairs': 0x30, + 'Desert Mouth': 0x30, + 'Desert Teleporter Ledge': 0x30, 'Bombos Tablet Ledge': 0x30, 'Flute Boy Approach Area': 0x32, @@ -1144,9 +1144,9 @@ OWTileRegions = bidict({ 'Statues Area': 0x34, 'Statues Water': 0x34, - 'Lake Hylia Area': 0x35, - 'Lake Hylia South Shore': 0x35, + 'Lake Hylia Northwest Bank': 0x35, 'Lake Hylia Northeast Bank': 0x35, + 'Lake Hylia South Shore': 0x35, 'Lake Hylia Central Island': 0x35, 'Lake Hylia Island': 0x35, 'Lake Hylia Water': 0x35, @@ -1176,7 +1176,7 @@ OWTileRegions = bidict({ 'Dark Lumberjack Area': 0x42, 'West Dark Death Mountain (Top)': 0x43, - 'GT Approach': 0x43, + 'GT Stairs': 0x43, 'West Dark Death Mountain (Bottom)': 0x43, 'East Dark Death Mountain (Top)': 0x45, @@ -1191,7 +1191,7 @@ OWTileRegions = bidict({ 'Turtle Rock Ledge': 0x47, 'Bumper Cave Area': 0x4a, - 'Bumper Cave Entrance': 0x4a, + 'Bumper Cave Entry': 0x4a, 'Bumper Cave Ledge': 0x4a, 'Catfish Area': 0x4f, @@ -1222,8 +1222,8 @@ OWTileRegions = bidict({ 'Catfish Approach Ledge': 0x57, 'Catfish Approach Water': 0x57, - 'Village of Outcasts Area': 0x58, - 'Dark Grassy Lawn': 0x58, + 'Village of Outcasts': 0x58, + 'Village of Outcasts Bush Yard': 0x58, 'Shield Shop Area': 0x5a, 'Shield Shop Fence': 0x5a, @@ -1267,10 +1267,10 @@ OWTileRegions = bidict({ 'Dark Tree Line Area': 0x6e, 'Dark Tree Line Water': 0x6e, - 'Palace of Darkness Nook Area': 0x6f, + 'Darkness Nook Area': 0x6f, - 'Misery Mire Area': 0x70, - 'Misery Mire Teleporter Ledge': 0x70, + 'Mire Area': 0x70, + 'Mire Teleporter Ledge': 0x70, 'Stumpy Approach Area': 0x72, 'Stumpy Approach Bush Entry': 0x72, @@ -1283,12 +1283,12 @@ OWTileRegions = bidict({ 'Hype Cave Area': 0x74, 'Hype Cave Water': 0x74, - 'Ice Lake Area': 0x75, + 'Ice Lake Northwest Bank': 0x75, 'Ice Lake Northeast Bank': 0x75, - 'Ice Lake Ledge (West)': 0x75, - 'Ice Lake Ledge (East)': 0x75, + 'Ice Lake Southwest Ledge': 0x75, + 'Ice Lake Southeast Ledge': 0x75, 'Ice Lake Water': 0x75, - 'Ice Lake Moat': 0x75, + 'Ice Lake Iceberg': 0x75, 'Ice Palace Area': 0x75, 'Shopping Mall Area': 0x77, @@ -1321,8 +1321,8 @@ parallel_links = bidict({'Lost Woods SW': 'Skull Woods SW', 'East Death Mountain WS': 'East Dark Death Mountain WS', 'East Death Mountain EN': 'East Dark Death Mountain EN', 'Death Mountain TR Pegs WN': 'Turtle Rock WN', - 'Mountain Entry NW': 'Bumper Cave NW', - 'Mountain Entry SE': 'Bumper Cave SE', + 'Mountain Pass NW': 'Bumper Cave NW', + 'Mountain Pass SE': 'Bumper Cave SE', 'Zora Waterfall SE': 'Catfish SE', 'Lost Woods Pass NW': 'Skull Woods Pass NW', 'Lost Woods Pass NE': 'Skull Woods Pass NE', @@ -1448,18 +1448,19 @@ parallel_links = bidict({'Lost Woods SW': 'Skull Woods SW', OWExitTypes = { 'OWEdge': [], 'Ledge': ['West Death Mountain Drop', - 'Spectacle Rock Drop', - 'East Death Mountain Spiral Ledge Drop', - 'East Death Mountain Fairy Ledge Drop', - 'East Death Mountain Mimic Ledge Drop', + 'Spectacle Rock Ledge Drop', + 'EDM To Spiral Ledge Drop', + 'EDM To Fairy Ledge Drop', + 'EDM To Mimic Ledge Drop', + 'EDM Ledge Drop', 'Spiral Ledge Drop', 'Mimic Ledge Drop', 'Spiral Mimic Ledge Drop', 'Fairy Ascension Ledge Drop', 'Fairy Ascension Plateau Ledge Drop', 'TR Pegs Ledge Drop', - 'Mountain Entry Entrance Ledge Drop', - 'Mountain Entry Ledge Drop', + 'Mountain Pass Entry Ledge Drop', + 'Mountain Pass Ledge Drop', 'Zora Waterfall Water Drop', 'Bonk Rock Ledge Drop', 'Graveyard Ledge Drop', @@ -1472,15 +1473,15 @@ OWExitTypes = { 'Hyrule Castle Ledge Courtyard Drop', 'Wooden Bridge Water Drop', 'Wooden Bridge Northeast Water Drop', - 'Sand Dunes Ledge Drop', - 'Stone Bridge East Ledge Drop', - 'Tree Line Ledge Drop', - 'Eastern Palace Ledge Drop', + 'Sand Dunes Cliff Ledge Drop', + 'Stone Bridge East Cliff Ledge Drop', + 'Tree Line Cliff Ledge Drop', + 'Eastern Palace Cliff Ledge Drop', 'Maze Race Ledge Drop', 'Central Bonk Rocks Cliff Ledge Drop', 'Links House Cliff Ledge Drop', 'Stone Bridge Cliff Ledge Drop', - 'Lake Hylia Area Cliff Ledge Drop', + 'Lake Hylia Northwest Cliff Ledge Drop', 'Lake Hylia Island FAWT Ledge Drop', 'Stone Bridge EC Cliff Water Drop', 'Tree Line WC Cliff Water Drop', @@ -1492,7 +1493,6 @@ OWExitTypes = { 'Checkerboard Ledge Drop', 'Desert Mouth Drop', 'Desert Teleporter Drop', - 'Desert Boss Cliff Ledge Drop', 'Checkerboard Cliff Ledge Drop', 'Suburb Cliff Ledge Drop', 'Cave 45 Cliff Ledge Drop', @@ -1505,29 +1505,29 @@ OWExitTypes = { 'Lake Hylia Island Water Drop', 'Desert Pass Ledge Drop', 'Octoballoon Waterfall Water Drop', - 'Dark Death Mountain Drop (West)', - 'Dark Death Mountain Drop (East)', + 'West Dark Death Mountain Drop', + 'East Dark Death Mountain Drop', 'Floating Island Drop', 'Turtle Rock Tail Ledge Drop', 'Turtle Rock Ledge Drop', 'Bumper Cave Ledge Drop', - 'Bumper Cave Entrance Drop', + 'Bumper Cave Entry Drop', 'Qirn Jump Water Drop', 'Dark Witch Water Drop', 'Dark Witch Northeast Water Drop', 'Catfish Approach Bottom Ledge Drop', 'Catfish Approach Water Drop', 'Catfish Approach Ledge Drop', - 'Shield Shop Fence (Outer) Ledge Drop', - 'Shield Shop Fence (Inner) Ledge Drop', + 'Shield Shop Fence Drop (Outer)', + 'Shield Shop Fence Drop (Inner)', 'Pyramid Exit Ledge Drop', 'Broken Bridge Water Drop', 'Broken Bridge Northeast Water Drop', 'Broken Bridge West Water Drop', - 'Dark Dunes Ledge Drop', - 'Hammer Bridge North Ledge Drop', - 'Dark Tree Line Ledge Drop', - 'Palace of Darkness Ledge Drop', + 'Dark Dunes Cliff Ledge Drop', + 'Hammer Bridge North Cliff Ledge Drop', + 'Dark Tree Line Cliff Ledge Drop', + 'Palace of Darkness Cliff Ledge Drop', 'Dig Game To Ledge Drop', 'Dig Game Ledge Drop', 'Frog Ledge Drop', @@ -1535,8 +1535,8 @@ OWExitTypes = { 'Dark Bonk Rocks Cliff Ledge Drop', 'Bomb Shop Cliff Ledge Drop', 'Hammer Bridge South Cliff Ledge Drop', - 'Ice Lake Moat Bomb Jump', - 'Ice Lake Area Cliff Ledge Drop', + 'Ice Lake Iceberg Bomb Jump', + 'Ice Lake Northwest Cliff Ledge Drop', 'Ice Palace Island FAWT Ledge Drop', 'Hammer Bridge EC Cliff Water Drop', 'Dark Tree Line WC Cliff Water Drop', @@ -1544,7 +1544,7 @@ OWExitTypes = { 'Dark C Whirlpool Cliff Ledge Drop', 'Dark C Whirlpool Portal Cliff Ledge Drop', 'Hype Cliff Ledge Drop', - 'Misery Mire Teleporter Ledge Drop', + 'Mire Teleporter Ledge Drop', 'Mire Cliff Ledge Drop', 'Dark Checkerboard Cliff Ledge Drop', 'Archery Game Cliff Ledge Drop', @@ -1565,30 +1565,30 @@ OWExitTypes = { 'DM Hammer Bridge (West)', 'DM Hammer Bridge (East)', 'Floating Island Bridge (East)', - 'Fairy Ascension Rocks (North)', + 'Fairy Ascension Rocks (Inner)', 'DM Broken Bridge (West)', 'DM Broken Bridge (East)', 'Spiral Mimic Bridge (West)', 'Spiral Mimic Bridge (East)', 'Spiral Ledge Approach', 'Mimic Ledge Approach', - 'Fairy Ascension Rocks (South)', + 'Fairy Ascension Rocks (Outer)', 'Floating Island Bridge (West)', 'TR Pegs Ledge Entry', 'TR Pegs Ledge Leave', - 'Mountain Entry Entrance Rock (West)', - 'Mountain Entry Entrance Rock (East)', + 'Mountain Pass Rock (Outer)', + 'Mountain Pass Rock (Inner)', 'Zora Waterfall Water Entry', - 'Zora Waterfall Water Approach', + 'Zora Waterfall Approach', 'Zora Waterfall Landing', 'Lost Woods Pass Hammer (North)', 'Lost Woods Pass Hammer (South)', 'Lost Woods Pass Rock (North)', 'Lost Woods Pass Rock (South)', - 'Kings Grave Outer Rocks', + 'Kings Grave Rocks (Outer)', 'Graveyard Ladder (Bottom)', 'Graveyard Ladder (Top)', - 'Kings Grave Inner Rocks', + 'Kings Grave Rocks (Inner)', 'River Bend Water Drop', 'River Bend West Pier', 'River Bend East Water Drop', @@ -1602,33 +1602,33 @@ OWExitTypes = { 'Kakariko Southwest Bush (South)', 'Kakariko Yard Bush (North)', 'Hyrule Castle Main Gate (South)', - 'Hyrule Castle Inner East Rock', + 'Hyrule Castle East Rock (Inner)', 'Hyrule Castle Southwest Bush (North)', 'Hyrule Castle Southwest Bush (South)', 'Hyrule Castle Courtyard Bush (South)', 'Hyrule Castle Main Gate (North)', 'Hyrule Castle Courtyard Bush (North)', - 'Hyrule Castle Outer East Rock', + 'Hyrule Castle East Rock (Outer)', 'Wooden Bridge Bush (South)', 'Wooden Bridge Bush (North)', - 'Bat Cave Ledge Peg', - 'Bat Cave Ledge Peg (East)', + 'Blacksmith Ledge Peg (West)', + 'Blacksmith Ledge Peg (East)', 'Maze Race Game', - 'Stone Bridge Northbound', - 'Stone Bridge Southbound', - 'Desert Palace Statue Move', + 'Stone Bridge (Northbound)', + 'Stone Bridge (Southbound)', + 'Desert Statue Move', 'Checkerboard Ledge Approach', - 'Desert Ledge Outer Rocks', - 'Desert Ledge Inner Rocks', + 'Desert Ledge Rocks (Outer)', + 'Desert Ledge Rocks (Inner)', 'Checkerboard Ledge Leave', 'Flute Boy Bush (South)', - 'Cave 45 Inverted Approach', + 'Cave 45 Approach', 'Flute Boy Bush (North)', - 'Cave 45 Inverted Leave', + 'Cave 45 Leave', 'C Whirlpool Rock (Bottom)', 'C Whirlpool Rock (Top)', - 'C Whirlpool Pegs (Right)', - 'C Whirlpool Pegs (Left)', + 'C Whirlpool Pegs (Outer)', + 'C Whirlpool Pegs (Inner)', 'C Whirlpool Water Entry', 'C Whirlpool Landing', 'Statues Water Entry', @@ -1649,14 +1649,15 @@ OWExitTypes = { 'Middle Aged Man', 'Octoballoon Water Drop', 'Octoballoon Pier', - 'Skull Woods Bush Rock (East)', - 'Skull Woods Bush Rock (West)', + 'Skull Woods Rock (East)', + 'Skull Woods Rock (West)', 'Skull Woods Forgotten Bush (West)', 'Skull Woods Forgotten Bush (East)', - 'GT Entry Approach', - 'GT Entry Leave', + 'GT Approach', + 'GT Leave', 'East Dark Death Mountain Bushes', - 'Bumper Cave Entrance Rock', + 'Bumper Cave Rock (Outer)', + 'Bumper Cave Rock (Inner)', 'Skull Woods Pass Bush Row (West)', 'Skull Woods Pass Bush Row (East)', 'Skull Woods Pass Bush (North)', @@ -1671,8 +1672,8 @@ OWExitTypes = { 'Dark Witch Rock (North)', 'Catfish Approach Rocks (West)', 'Catfish Approach Rocks (East)', - 'Village of Outcasts Pegs', - 'Grassy Lawn Pegs', + 'Bush Yard Pegs (Outer)', + 'Bush Yard Pegs (Inner)', 'Pyramid Crack', 'Broken Bridge Hammer Rock (South)', 'Broken Bridge Hammer Rock (North)', @@ -1690,8 +1691,8 @@ OWExitTypes = { 'Stumpy Approach Bush (North)', 'Dark C Whirlpool Rock (Bottom)', 'Dark C Whirlpool Rock (Top)', - 'Dark C Whirlpool Pegs (Right)', - 'Dark C Whirlpool Pegs (Left)', + 'Dark C Whirlpool Pegs (Outer)', + 'Dark C Whirlpool Pegs (Inner)', 'Dark C Whirlpool Water Entry', 'Dark C Whirlpool Landing', 'Hype Cave Water Entry', @@ -1699,7 +1700,7 @@ OWExitTypes = { 'Ice Lake Northeast Water Drop', 'Ice Lake Northeast Pier', 'Ice Lake Northeast Pier Hop', - 'Ice Lake Moat Water Entry', + 'Ice Lake Iceberg Water Entry', 'Bomber Corner Water Drop', 'Bomber Corner Pier' ], @@ -1714,14 +1715,14 @@ OWExitTypes = { 'South Hyrule Teleporter', 'Lake Hylia Teleporter', 'Dark Death Mountain Teleporter (West)', - 'Dark Death Mountain Teleporter (East)', + 'East Dark Death Mountain Teleporter', 'Turtle Rock Teleporter', 'West Dark World Teleporter', - 'Post Aga Inverted Teleporter', + 'Post Aga Teleporter', 'East Dark World Teleporter', - 'Misery Mire Teleporter', + 'Mire Teleporter', 'South Dark World Teleporter', - 'Ice Palace Teleporter' + 'Ice Lake Teleporter' ], 'Whirlpool': ['Zora Whirlpool', 'Kakariko Pond Whirlpool', diff --git a/OverworldGlitchRules.py b/OverworldGlitchRules.py index ec8e2fe7..715bbc41 100644 --- a/OverworldGlitchRules.py +++ b/OverworldGlitchRules.py @@ -347,14 +347,14 @@ def set_owg_rules(player, world, connections, default_rule): connection.access_rule = rule -glitch_regions = (['Central Cliffs', 'Eastern Cliff', 'Desert Northeast Cliffs'], - ['Dark Central Cliffs', 'Darkness Cliff', 'Mire Northeast Cliffs']) +glitch_regions = (['Central Cliffs', 'Eastern Cliff', 'Desert Northern Cliffs'], + ['Dark Central Cliffs', 'Darkness Cliff', 'Mire Northern Cliffs']) # same screen clips, no Tile Flip OWR implications boots_clips_local = [ # (name, from_region, to_region) ('Hera Ascent Clip', 'West Death Mountain (Bottom)', 'West Death Mountain (Top)'), #cannot guarantee camera correction, but a bomb clip exists ('WDDM Bomb Clip', 'West Dark Death Mountain (Bottom)', 'West Dark Death Mountain (Top)'), #cannot guarantee camera correction, but a bomb clip exists - ('Ganons Tower Screen Wrap Clip', 'West Dark Death Mountain (Bottom)', 'GT Approach'), # This only gets you to the GT entrance + ('Ganons Tower Screen Wrap Clip', 'West Dark Death Mountain (Bottom)', 'GT Stairs'), # This only gets you to the GT entrance ('Spectacle Rock Ledge Clip', 'West Death Mountain (Top)', 'Spectacle Rock Ledge'), ('Floating Island Clip', 'East Death Mountain (Top East)', 'Death Mountain Floating Island'), @@ -367,14 +367,14 @@ boots_clips_local = [ # (name, from_region, to_region) ('WDDM To EDDM Bottom Clip', 'East Dark Death Mountain (Bottom Left)', 'East Dark Death Mountain (Bottom)'), ('TR Bridge Clip', 'East Dark Death Mountain (Top)', 'Dark Death Mountain Ledge'), - ('TR Pegs Ledge Clip', 'Death Mountain TR Pegs', 'Death Mountain TR Pegs Ledge'), - ('TR Pegs Ledge Descent Clip', 'Death Mountain TR Pegs Ledge', 'Death Mountain TR Pegs'), # inverted only, but doesn't hurt to exist always + ('TR Pegs Ledge Clip', 'Death Mountain TR Pegs Area', 'Death Mountain TR Pegs Ledge'), + ('TR Pegs Ledge Descent Clip', 'Death Mountain TR Pegs Ledge', 'Death Mountain TR Pegs Area'), # inverted only, but doesn't hurt to exist always ('Turtle Rock Ledge Clip', 'Turtle Rock Area', 'Turtle Rock Ledge'), - ('Mountain Entry To Ledge Clip', 'Mountain Entry Area', 'Mountain Entry Ledge'), + ('Mountain Pass To Ledge Clip', 'Mountain Pass Area', 'Mountain Pass Ledge'), ('Bumper Cave Ledge Clip', 'Bumper Cave Area', 'Bumper Cave Ledge'), - ('Mountain Ledge Drop Clip', 'Mountain Entry Ledge', 'Mountain Entry Entrance'), - ('Bumper Cave Ledge Drop Clip', 'Bumper Cave Ledge', 'Bumper Cave Entrance'), + ('Mountain Ledge Drop Clip', 'Mountain Pass Ledge', 'Mountain Pass Entry'), + ('Bumper Cave Ledge Drop Clip', 'Bumper Cave Ledge', 'Bumper Cave Entry'), ('Potion Shop Northbound Rock Bypass Clip', 'Potion Shop Area', 'Potion Shop Northeast'), ('Potion Shop Southbound Rock Bypass Clip', 'Potion Shop Northeast', 'Potion Shop Area'), @@ -383,19 +383,19 @@ boots_clips_local = [ # (name, from_region, to_region) ('Hyrule Castle To Water Clip', 'Hyrule Castle Area', 'Hyrule Castle Water'), #fake flipper - #('Bat Cave River Clip Spot', 'Blacksmith Area', 'Bat Cave Ledge'), #cannot guarantee camera correction + ('Bat Cave River Clip Spot', 'Blacksmith Area', 'Blacksmith Ledge'), #cannot guarantee camera correction ('Maze Race Item Get Ledge Clip', 'Maze Race Area', 'Maze Race Prize'), ('Tree Line Water Clip', 'Tree Line Area', 'Tree Line Water'), #requires flippers ('Dark Tree Line Water Clip', 'Dark Tree Line Area', 'Dark Tree Line Water'), #requires flippers - ('Desert To Teleporter Clip', 'Desert Area', 'Desert Palace Teleporter Ledge'), - ('Mire To Teleporter Clip', 'Misery Mire Area', 'Misery Mire Teleporter Ledge'), + ('Desert To Teleporter Clip', 'Desert Area', 'Desert Teleporter Ledge'), + ('Mire To Teleporter Clip', 'Mire Area', 'Mire Teleporter Ledge'), ('Desert To Bombos Tablet Clip', 'Desert Area', 'Bombos Tablet Ledge'), - ('Lake Hylia To Shore Clip', 'Lake Hylia Area', 'Lake Hylia South Shore'), - ('Ice Lake To Shore Clip', 'Ice Lake Area', 'Ice Lake Ledge (West)') + ('Lake Hylia To Shore Clip', 'Lake Hylia Northwest Bank', 'Lake Hylia South Shore'), + ('Ice Lake To Shore Clip', 'Ice Lake Northwest Bank', 'Ice Lake Southwest Ledge') #('Desert Pass To Zora Clip', 'Desert Pass Area', 'Zoras Domain', ) #revisit when Zora is shuffled ] @@ -416,20 +416,20 @@ boots_clips = [ (['Kings Grave DMD Clip', 'Dark Kings Grave DMD Clip'], ['West Death Mountain (Bottom)', 'West Dark Death Mountain (Bottom)'], ['Kings Grave Area', None]), (['EDM to WDM Top Clip', 'EDDM To WDDM Clip'], ['East Death Mountain (Top West)', 'East Dark Death Mountain (Top)'], ['West Death Mountain (Top)', 'West Dark Death Mountain (Top)']), - (['EDM To TR Pegs Clip', 'EDDM To TR Clip'], ['East Death Mountain (Top East)', 'East Dark Death Mountain (Top)'], ['Death Mountain TR Pegs', None]), + (['EDM To TR Pegs Clip', 'EDDM To TR Clip'], ['East Death Mountain (Top East)', 'East Dark Death Mountain (Top)'], ['Death Mountain TR Pegs Area', None]), (['EDM DMD FAWT Clip', 'Dark Witch DMD FAWT Clip'], ['East Death Mountain (Bottom)', 'East Dark Death Mountain (Bottom)'], ['Potion Shop Area', 'Dark Witch Area']), (['WDM DMD To River Bend Clip', 'WDDM DMD To Qirn Jump Clip'], ['East Death Mountain (Bottom Left)', 'East Dark Death Mountain (Bottom Left)'], ['River Bend Area', 'Qirn Jump Area']), (['EDM DMD To River Bend Clip', 'EDDM DMD To Qirn Jump Clip'], ['East Death Mountain (Bottom)', 'East Dark Death Mountain (Bottom)'], ['River Bend Area', 'Qirn Jump Area']), - (['TR Pegs To EDM Clip', 'TR To EDDM Clip'], ['Death Mountain TR Pegs', 'Turtle Rock Area'], ['East Death Mountain (Top East)', 'East Dark Death Mountain (Top)']), - (['Zora DMD Clip', 'Catfish DMD Clip'], ['Death Mountain TR Pegs', 'Turtle Rock Area'], ['Zora Waterfall Area', 'Catfish Area']), + (['TR Pegs To EDM Clip', 'TR To EDDM Clip'], ['Death Mountain TR Pegs Area', 'Turtle Rock Area'], ['East Death Mountain (Top East)', 'East Dark Death Mountain (Top)']), + (['Zora DMD Clip', 'Catfish DMD Clip'], ['Death Mountain TR Pegs Area', 'Turtle Rock Area'], ['Zora Waterfall Area', 'Catfish Area']), - (['Mountain Entry To Pond Clip', 'Bumper Cave To Pond Clip'], ['Mountain Entry Area', 'Bumper Cave Area'], ['Kakariko Pond Area', 'Outcast Pond Area']), + (['Mountain Pass To Pond Clip', 'Bumper Cave To Pond Clip'], ['Mountain Pass Area', 'Bumper Cave Area'], ['Kakariko Pond Area', 'Outcast Pond Area']), (['Zora Waterfall Ledge Clip', 'Catfish Ledge Clip'], ['Zora Waterfall Area', 'Catfish Area'], ['Zora Approach Area', 'Catfish Approach Area']), #(['Pond DMA Clip', 'Dark Pond DMA Clip'], ['Kakariko Pond Area', 'Outcast Pond Area'], ['West Death Mountain (Bottom)', 'West Dark Death Mountain (Bottom)']), #cannot guarantee camera correction - (['Pond To Mountain Entry Clip', 'Pond To Bumper Cave Clip'], ['Kakariko Pond Area', 'Outcast Pond Area'], ['Mountain Entry Area', 'Bumper Cave Area']), + (['Pond To Mountain Pass Clip', 'Pond To Bumper Cave Clip'], ['Kakariko Pond Area', 'Outcast Pond Area'], ['Mountain Pass Area', 'Bumper Cave Area']), (['Pond To Bonk Rocks Clip', 'Pond To Chapel Clip'], ['Kakariko Pond Area', 'Outcast Pond Area'], ['Bonk Rock Ledge', 'Dark Chapel Area']), (['River Bend To Potion Shop Clip', 'Qirn Jump To Dark Witch Clip'], ['River Bend East Bank', 'Qirn Jump East Bank'], ['Potion Shop Area', 'Dark Witch Area']), @@ -443,8 +443,8 @@ boots_clips = [ (['Zora Approach To Potion Shop Clip', 'Catfish Approach To Dark Witch Clip'], ['Zora Approach Area', 'Catfish Approach Area'], ['Potion Shop Area', 'Dark Witch Area']), (['Zora Approach To PoD Clip', 'Catfish Approach To PoD Clip'], ['Zora Approach Area', 'Catfish Approach Area'], [None, 'Palace of Darkness Area']), - (['Kakariko Bomb Hut Clip', 'VoO To Dig Game Clip'], ['Kakariko Southwest', 'Village of Outcasts Area'], ['Maze Race Area', 'Dig Game Area']), - (['Kakariko To Dig Game Hook Clip', 'VoO To Dig Game Hook Clip'], ['Kakariko Southwest', 'Village of Outcasts Area'], [None, 'Dig Game Ledge']), #requires hookshot + (['Kakariko Bomb Hut Clip', 'VoO To Dig Game Clip'], ['Kakariko Southwest', 'Village of Outcasts'], ['Maze Race Area', 'Dig Game Area']), + (['Kakariko To Dig Game Hook Clip', 'VoO To Dig Game Hook Clip'], ['Kakariko Southwest', 'Village of Outcasts'], [None, 'Dig Game Ledge']), #requires hookshot (['Forgotten Forest To Blacksmith Clip', None], ['Forgotten Forest Area', None], ['Hyrule Castle Water', 'Pyramid Water']), #fake flipper @@ -452,30 +452,30 @@ boots_clips = [ (['Wooden Bridge To Water Clip', 'Broken Bridge To Water Clip'], ['Wooden Bridge Area', 'Broken Bridge West'], [None, 'Pyramid Water']), #fake flipper (['Eastern Palace To Zora Approach Clip', None], ['Eastern Palace Area', None], ['Zora Approach Area', 'Catfish Approach Area']), - (['Eastern Palace To Nook Clip', None], ['Eastern Palace Area', None], ['Eastern Nook Area', 'Palace of Darkness Nook Area']), + (['Eastern Palace To Nook Clip', None], ['Eastern Palace Area', None], ['Eastern Nook Area', 'Darkness Nook Area']), (['Eastern Palace To Cliff Clip', 'PoD To Cliff Clip'], ['Eastern Palace Area', 'Palace of Darkness Area'], ['Eastern Cliff', 'Darkness Cliff']), (['Sand Dunes To Cliff Clip', 'Dark Dunes To Cliff Clip'], ['Sand Dunes Area', 'Dark Dunes Area'], ['Eastern Cliff', 'Darkness Cliff']), (['Sand Dunes To Water Clip', 'Dark Dunes To Water Clip'], ['Sand Dunes Area', 'Dark Dunes Area'], [None, 'Pyramid Water']), #fake flipper - (['Maze Race To Desert Ledge Clip', 'Dig Game To Mire Clip'], ['Maze Race Area', 'Dig Game Area'], ['Desert Ledge', 'Misery Mire Area']), - (['Maze Race To Desert Boss Clip', 'Dig Game To Desert Boss Clip'], ['Maze Race Area', 'Dig Game Area'], ['Desert Palace Entrance (North) Spot', None]), - (['Suburb To Cliff Clip', 'Archery Game To Cliff Clip'], ['Kakariko Suburb Area', 'Archery Game Area'], ['Desert Northeast Cliffs', 'Mire Northeast Cliffs']), + (['Maze Race To Desert Ledge Clip', 'Dig Game To Mire Clip'], ['Maze Race Area', 'Dig Game Area'], ['Desert Ledge', 'Mire Area']), + (['Maze Race To Desert Boss Clip', 'Dig Game To Desert Boss Clip'], ['Maze Race Area', 'Dig Game Area'], ['Desert Ledge Keep', None]), + (['Suburb To Cliff Clip', 'Archery Game To Cliff Clip'], ['Kakariko Suburb Area', 'Archery Game Area'], ['Desert Northern Cliffs', 'Mire Northern Cliffs']), (['Central Bonk Rocks To Cliff Clip', 'Dark Bonk Rocks To Cliff Clip'], ['Central Bonk Rocks Area', 'Dark Bonk Rocks Area'], ['Central Cliffs', 'Dark Central Cliffs']), (['Links House To Cliff Clip', 'Bomb Shop To Cliff Clip'], ['Links House Area', 'Big Bomb Shop Area'], ['Central Cliffs', 'Dark Central Cliffs']), (['Stone Bridge To Cliff Clip', 'Hammer Bridge To Cliff Clip'], ['Stone Bridge South Area', 'Hammer Bridge South Area'], ['Central Cliffs', 'Dark Central Cliffs']), (['Eastern Nook To Eastern Clip', None], ['Eastern Nook Area', None], ['Eastern Palace Area', 'Palace of Darkness Area']), - (['Eastern Nook To Ice Cave FAWT Clip', 'PoD Nook To Shopping Mall FAWT Clip'], ['Eastern Nook Area', 'Palace of Darkness Nook Area'], ['Ice Cave Area', 'Shopping Mall Area']), + (['Eastern Nook To Ice Cave FAWT Clip', 'PoD Nook To Shopping Mall FAWT Clip'], ['Eastern Nook Area', 'Darkness Nook Area'], ['Ice Cave Area', 'Shopping Mall Area']), (['Links To Bridge FAWT Clip', 'Bomb Shop To Hammer Bridge FAWT Clip'], ['Links House Area', 'Big Bomb Shop Area'], ['Stone Bridge North Area', 'Hammer Bridge North Area']), #fake flipper (['Stone Bridge To Water Clip', 'Hammer Bridge To Water Clip'], ['Stone Bridge North Area', 'Hammer Bridge North Area'], [None, 'Pyramid Water']), #fake flipper (['Desert To Maze Race Clip', None], ['Desert Ledge', None], ['Maze Race Area', 'Dig Game Area']), - (['Desert To Cliff Clip', 'Mire To Cliff Clip'], ['Desert Area', 'Misery Mire Area'], ['Desert Northeast Cliffs', 'Mire Northeast Cliffs']), + (['Desert To Cliff Clip', 'Mire To Cliff Clip'], ['Desert Area', 'Mire Area'], ['Desert Northern Cliffs', 'Mire Northern Cliffs']), - (['Flute Boy To Cliff Clip', 'Stumpy To Cliff Clip'], ['Flute Boy Approach Area', 'Stumpy Approach Area'], ['Desert Northeast Cliffs', 'Mire Northeast Cliffs']), - (['Cave 45 To Cliff Clip', None], ['Cave 45 Ledge', None], ['Desert Northeast Cliffs', 'Mire Northeast Cliffs']), + (['Flute Boy To Cliff Clip', 'Stumpy To Cliff Clip'], ['Flute Boy Approach Area', 'Stumpy Approach Area'], ['Desert Northern Cliffs', 'Mire Northern Cliffs']), + (['Cave 45 To Cliff Clip', None], ['Cave 45 Ledge', None], ['Desert Northern Cliffs', 'Mire Northern Cliffs']), (['C Whirlpool To Cliff Clip', 'Dark C Whirlpool To Cliff Clip'], ['C Whirlpool Area', 'Dark C Whirlpool Area'], ['Central Cliffs', 'Dark Central Cliffs']), (['C Whirlpool Outer To Cliff Clip', 'Dark C Whirlpool Outer To Cliff Clip'], ['C Whirlpool Outer Area', 'Dark C Whirlpool Outer Area'], ['Central Cliffs', 'Dark Central Cliffs']), @@ -483,25 +483,25 @@ boots_clips = [ (['Statues To Cliff Clip', 'Hype To Cliff Clip'], ['Statues Area', 'Hype Cave Area'], ['Central Cliffs', 'Dark Central Cliffs']), - (['Lake Hylia To Statues Clip', 'Ice Lake To Hype Clip'], ['Lake Hylia Area', 'Ice Lake Area'], ['Statues Area', 'Hype Cave Area']), - (['Lake Hylia To South Pass Clip', 'Ice Lake To South Pass Clip'], ['Lake Hylia Area', 'Ice Lake Area'], ['South Pass Area', 'Dark South Pass Area']), + (['Lake Hylia To Statues Clip', 'Ice Lake To Hype Clip'], ['Lake Hylia Northwest Bank', 'Ice Lake Northwest Bank'], ['Statues Area', 'Hype Cave Area']), + (['Lake Hylia To South Pass Clip', 'Ice Lake To South Pass Clip'], ['Lake Hylia Northwest Bank', 'Ice Lake Northwest Bank'], ['South Pass Area', 'Dark South Pass Area']), - (['Desert Pass To Cliff Clip', 'Swamp Nook To Cliff Clip'], ['Desert Pass Area', 'Swamp Nook Area'], ['Desert Northeast Cliffs', 'Mire Northeast Cliffs']), - (['Desert Pass Southeast To Cliff Clip', None], ['Desert Pass Southeast', None], ['Desert Northeast Cliffs', 'Mire Northeast Cliffs']), + (['Desert Pass To Cliff Clip', 'Swamp Nook To Cliff Clip'], ['Desert Pass Area', 'Swamp Nook Area'], ['Desert Northern Cliffs', 'Mire Northern Cliffs']), + (['Desert Pass Southeast To Cliff Clip', None], ['Desert Pass Southeast', None], ['Desert Northern Cliffs', 'Mire Northern Cliffs']), - (['Dam To Cliff Clip', 'Swamp To Cliff Clip'], ['Dam Area', 'Swamp Area'], ['Desert Northeast Cliffs', 'Mire Northeast Cliffs']), + (['Dam To Cliff Clip', 'Swamp To Cliff Clip'], ['Dam Area', 'Swamp Area'], ['Desert Northern Cliffs', 'Mire Northern Cliffs']), (['Dam To Desert Pass Southeast Clip', 'Swamp To Desert Pass Southeast Clip'], ['Dam Area', 'Swamp Area'], ['Desert Pass Southeast', None]), - (['South Pass To Lake Hylia Clip', 'South Pass To Ice Lake Clip'], ['South Pass Area', 'Dark South Pass Area'], ['Lake Hylia Area', 'Ice Lake Area']), - (['South Pass To Shore Clip', 'South Pass To Dark Shore Clip'], ['South Pass Area', 'Dark South Pass Area'], ['Lake Hylia South Shore', 'Ice Lake Ledge (West)']), - #(['Octoballoon To Shore Clip', 'Bomber Corner To Shore Clip'], ['Octoballoon Area', 'Bomber Corner Area'], ['Lake Hylia South Shore', 'Ice Lake Ledge (East)']), #map wrap hardlock risk + (['South Pass To Lake Hylia Clip', 'South Pass To Ice Lake Clip'], ['South Pass Area', 'Dark South Pass Area'], ['Lake Hylia Northwest Bank', 'Ice Lake Northwest Bank']), + (['South Pass To Shore Clip', 'South Pass To Dark Shore Clip'], ['South Pass Area', 'Dark South Pass Area'], ['Lake Hylia South Shore', 'Ice Lake Southwest Ledge']), + #(['Octoballoon To Shore Clip', 'Bomber Corner To Shore Clip'], ['Octoballoon Area', 'Bomber Corner Area'], ['Lake Hylia South Shore', 'Ice Lake Southeast Ledge']), #map wrap hardlock risk (['HC Water To Blacksmith Clip', 'Pyramid Water To Hammerpegs Clip'], ['Hyrule Castle Water', 'Pyramid Water'], ['Blacksmith Area', 'Hammer Pegs Area']), #TODO: THIS IS NOT A BOOTS CLIP, this is a normal connection that needs to occur somewhere ([None, 'Pyramid Water To Bomb Shop Clip'], [None, 'Pyramid Water'], ['Links House Area', 'Big Bomb Shop Area']) #TODO: THIS IS NOT A BOOTS CLIP, this is a normal connection that needs to occur somewhere ] mirror_clips_local = [ - ('Desert East Mirror Clip', 'Misery Mire Area', 'Desert Palace Mouth'), + ('Desert East Mirror Clip', 'Mire Area', 'Desert Mouth'), ('EDDM Mirror Clip', 'East Dark Death Mountain (Bottom Left)', 'East Dark Death Mountain (Bottom)'), ('EDDM Mirror Clip', 'East Dark Death Mountain (Top)', 'Dark Death Mountain Ledge') ] diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 0c483b14..de997bfe 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -470,7 +470,7 @@ def link_overworld(world, player): target_spots = len(new_spots) + spots_to_place logging.getLogger('').debug(f'Sector of {sector[0]} regions gets {spots_to_place} spot(s)') - if 'Desert Palace Teleporter Ledge' in sector[1] or 'Misery Mire Teleporter Ledge' in sector[1]: + if 'Desert Teleporter Ledge' in sector[1] or 'Mire Teleporter Ledge' in sector[1]: addSpot(0x38, False) # guarantee desert/mire access random.shuffle(sector[1]) @@ -887,7 +887,6 @@ def create_flute_exits(world, player): exitname = 'Flute From ' + region.name exit = Entrance(region.player, exitname, region) exit.spot_type = 'Flute' - exit.access_rule = lambda state: state.can_flute(player) exit.connect(world.get_region('Flute Sky', player)) region.exits.append(exit) @@ -1128,17 +1127,17 @@ def validate_layout(world, player): 'East Death Mountain (Bottom)': ['East Death Mountain (Top East)'], 'Kakariko Suburb Area': ['Maze Race Ledge'], 'Maze Race Ledge': ['Kakariko Suburb Area'], - 'Desert Area': ['Desert Ledge', 'Desert Palace Mouth'], + 'Desert Area': ['Desert Ledge', 'Desert Mouth'], 'East Dark Death Mountain (Top)': ['Dark Death Mountain Floating Island'], 'East Dark Death Mountain (Bottom)': ['East Dark Death Mountain (Top)'], 'Turtle Rock Area': ['Dark Death Mountain Ledge', 'Dark Death Mountain Isolated Ledge'], 'Dark Death Mountain Ledge': ['Turtle Rock Area'], 'Dark Death Mountain Isolated Ledge': ['Turtle Rock Area'], - 'Mountain Entry Entrance': ['West Death Mountain (Bottom)'], - 'Mountain Entry Ledge': ['West Death Mountain (Bottom)'], - 'West Death Mountain (Bottom)': ['Mountain Entry Ledge'], - 'Bumper Cave Entrance': ['Bumper Cave Ledge'] + 'Mountain Pass Entry': ['West Death Mountain (Bottom)'], + 'Mountain Pass Ledge': ['West Death Mountain (Bottom)'], + 'West Death Mountain (Bottom)': ['Mountain Pass Ledge'], + 'Bumper Cave Entry': ['Bumper Cave Ledge'] } sane_connectors = { # guaranteed dungeon access @@ -1197,9 +1196,9 @@ def validate_layout(world, player): explore_region(start_region) if not world.is_tile_swapped(0x30, player): - start_region = 'Desert Palace Teleporter Ledge' + start_region = 'Desert Teleporter Ledge' else: - start_region = 'Misery Mire Teleporter Ledge' + start_region = 'Mire Teleporter Ledge' explore_region(start_region) if not world.is_tile_swapped(0x1b, player): @@ -1259,201 +1258,207 @@ test_connections = [ ] # 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 = [('Old Man S&Q', 'Old Man House'), +mandatory_connections = [ + ('Old Man S&Q', 'Old Man House'), - # Intra-tile OW Connections - ('Lost Woods Bush (West)', 'Lost Woods East Area'), #pearl - ('Lost Woods Bush (East)', 'Lost Woods West Area'), #pearl - ('West Death Mountain Drop', 'West Death Mountain (Bottom)'), - ('Spectacle Rock Drop', 'West Death Mountain (Top)'), - ('Old Man Drop Off', 'Old Man Drop Off'), - ('DM Hammer Bridge (West)', 'East Death Mountain (Top East)'), #hammer - ('DM Hammer Bridge (East)', 'East Death Mountain (Top West)'), #hammer - ('East Death Mountain Spiral Ledge Drop', 'Spiral Cave Ledge'), - ('Spiral Ledge Drop', 'East Death Mountain (Bottom)'), - ('East Death Mountain Fairy Ledge Drop', 'Fairy Ascension Ledge'), - ('Fairy Ascension Ledge Drop', 'Fairy Ascension Plateau'), - ('Fairy Ascension Plateau Ledge Drop', 'East Death Mountain (Bottom)'), - ('Fairy Ascension Rocks (North)', 'East Death Mountain (Bottom)'), #mitts - ('Fairy Ascension Rocks (South)', 'Fairy Ascension Plateau'), #mitts - ('DM Broken Bridge (West)', 'East Death Mountain (Bottom)'), #hookshot - ('DM Broken Bridge (East)', 'East Death Mountain (Bottom Left)'), #hookshot - ('TR Pegs Ledge Entry', 'Death Mountain TR Pegs Ledge'), #mitts - ('TR Pegs Ledge Leave', 'Death Mountain TR Pegs'), #mitts - ('TR Pegs Ledge Drop', 'Death Mountain TR Pegs'), - ('Mountain Entry Entrance Rock (West)', 'Mountain Entry Entrance'), #glove - ('Mountain Entry Entrance Rock (East)', 'Mountain Entry Area'), #glove - ('Mountain Entry Entrance Ledge Drop', 'Mountain Entry Area'), - ('Mountain Entry Ledge Drop', 'Mountain Entry Area'), - ('Zora Waterfall Landing', 'Zora Waterfall Area'), - ('Zora Waterfall Water Drop', 'Zora Waterfall Water'), #flippers - ('Zora Waterfall Water Entry', 'Zora Waterfall Water'), #flippers - ('Zora Waterfall Water Approach', 'Zora Waterfall Entryway'), #flippers - ('Lost Woods Pass Hammer (North)', 'Lost Woods Pass Portal Area'), #hammer - ('Lost Woods Pass Hammer (South)', 'Lost Woods Pass East Top Area'), #hammer - ('Lost Woods Pass Rock (North)', 'Lost Woods Pass East Bottom Area'), #mitts - ('Lost Woods Pass Rock (South)', 'Lost Woods Pass Portal Area'), #mitts - ('Bonk Rock Ledge Drop', 'Sanctuary Area'), - ('Graveyard Ledge Drop', 'Graveyard Area'), - ('Kings Grave Outer Rocks', 'Kings Grave Area'), #mitts - ('Kings Grave Inner Rocks', 'Graveyard Area'), #mitts - ('River Bend Water Drop', 'River Bend Water'), #flippers - ('River Bend East Water Drop', 'River Bend Water'), #flippers - ('River Bend West Pier', 'River Bend Area'), - ('River Bend East Pier', 'River Bend East Bank'), - ('Potion Shop Water Drop', 'Potion Shop Water'), #flippers - ('Potion Shop Northeast Water Drop', 'Potion Shop Water'), #flippers - ('Potion Shop Rock (South)', 'Potion Shop Northeast'), #glove - ('Potion Shop Rock (North)', 'Potion Shop Area'), #glove - ('Zora Approach Water Drop', 'Zora Approach Water'), #flippers - ('Zora Approach Rocks (West)', 'Zora Approach Ledge'), #mitts/boots - ('Zora Approach Rocks (East)', 'Zora Approach Area'), #mitts/boots - ('Zora Approach Bottom Ledge Drop', 'Zora Approach Ledge'), - ('Zora Approach Ledge Drop', 'Zora Approach Area'), - ('Kakariko Southwest Bush (North)', 'Kakariko Southwest'), #pearl - ('Kakariko Southwest Bush (South)', 'Kakariko Area'), #pearl - ('Kakariko Yard Bush (South)', 'Kakariko Grass Yard'), #pearl - ('Kakariko Yard Bush (North)', 'Kakariko Area'), #pearl - ('Hyrule Castle Southwest Bush (North)', 'Hyrule Castle Southwest'), #pearl - ('Hyrule Castle Southwest Bush (South)', 'Hyrule Castle Area'), #pearl - ('Hyrule Castle Courtyard Bush (North)', 'Hyrule Castle Courtyard'), #pearl - ('Hyrule Castle Courtyard Bush (South)', 'Hyrule Castle Courtyard Northeast'), #pearl - ('Hyrule Castle Main Gate (South)', 'Hyrule Castle Courtyard'), #aga+mirror - ('Hyrule Castle Main Gate (North)', 'Hyrule Castle Area'), #aga+mirror - ('Hyrule Castle Ledge Drop', 'Hyrule Castle Area'), - ('Hyrule Castle Ledge Courtyard Drop', 'Hyrule Castle Courtyard'), - ('Hyrule Castle Inner East Rock', 'Hyrule Castle East Entry'), #glove - ('Hyrule Castle Outer East Rock', 'Hyrule Castle Area'), #glove - ('Wooden Bridge Bush (South)', 'Wooden Bridge Northeast'), #pearl - ('Wooden Bridge Bush (North)', 'Wooden Bridge Area'), #pearl - ('Wooden Bridge Water Drop', 'Wooden Bridge Water'), #flippers - ('Wooden Bridge Northeast Water Drop', 'Wooden Bridge Water'), #flippers - ('Bat Cave Ledge Peg', 'Bat Cave Ledge'), #hammer - ('Bat Cave Ledge Peg (East)', 'Blacksmith Area'), #hammer - ('Maze Race Game', 'Maze Race Prize'), #pearl - ('Maze Race Ledge Drop', 'Maze Race Area'), - ('Stone Bridge Southbound', 'Stone Bridge South Area'), - ('Stone Bridge Northbound', 'Stone Bridge North Area'), - ('Desert Palace Statue Move', 'Desert Palace Stairs'), #book - ('Desert Ledge Drop', 'Desert Area'), - ('Desert Ledge Outer Rocks', 'Desert Palace Entrance (North) Spot'), #glove - ('Desert Ledge Inner Rocks', 'Desert Ledge'), #glove - ('Checkerboard Ledge Drop', 'Desert Area'), - ('Desert Mouth Drop', 'Desert Area'), - ('Desert Teleporter Drop', 'Desert Area'), - ('Bombos Tablet Drop', 'Desert Area'), - ('Flute Boy Bush (North)', 'Flute Boy Approach Area'), #pearl - ('Flute Boy Bush (South)', 'Flute Boy Bush Entry'), #pearl - ('C Whirlpool Water Entry', 'C Whirlpool Water'), #flippers - ('C Whirlpool Landing', 'C Whirlpool Area'), - ('C Whirlpool Rock (Bottom)', 'C Whirlpool Outer Area'), #glove - ('C Whirlpool Rock (Top)', 'C Whirlpool Area'), #glove - ('C Whirlpool Pegs (Right)', 'C Whirlpool Portal Area'), #hammer - ('C Whirlpool Pegs (Left)', 'C Whirlpool Area'), #hammer - ('Statues Water Entry', 'Statues Water'), #flippers - ('Statues Landing', 'Statues Area'), - ('Lake Hylia Water Drop', 'Lake Hylia Water'), #flippers - ('Lake Hylia South Water Drop', 'Lake Hylia Water'), #flippers - ('Lake Hylia Northeast Water Drop', 'Lake Hylia Water'), #flippers - ('Lake Hylia Central Water Drop', 'Lake Hylia Water'), #flippers - ('Lake Hylia Island Water Drop', 'Lake Hylia Water'), #flippers - ('Lake Hylia Central Island Pier', 'Lake Hylia Central Island'), - ('Lake Hylia West Pier', 'Lake Hylia Area'), - ('Lake Hylia East Pier', 'Lake Hylia Northeast Bank'), - ('Lake Hylia Water D Approach', 'Lake Hylia Water D'), - ('Lake Hylia Water D Leave', 'Lake Hylia Water'), #flippers - ('Desert Pass Ledge Drop', 'Desert Pass Area'), - ('Desert Pass Rocks (North)', 'Desert Pass Southeast'), #glove - ('Desert Pass Rocks (South)', 'Desert Pass Area'), #glove - ('Middle Aged Man', 'Middle Aged Man'), - ('Octoballoon Water Drop', 'Octoballoon Water'), #flippers - ('Octoballoon Waterfall Water Drop', 'Octoballoon Water'), #flippers - ('Octoballoon Pier', 'Octoballoon Area'), + # Intra-tile OW Connections + ('Lost Woods Bush (West)', 'Lost Woods East Area'), #pearl + ('Lost Woods Bush (East)', 'Lost Woods West Area'), #pearl + ('West Death Mountain Drop', 'West Death Mountain (Bottom)'), + ('Spectacle Rock Ledge Drop', 'West Death Mountain (Top)'), + ('Old Man Drop Off', 'Old Man Drop Off'), + ('DM Hammer Bridge (West)', 'East Death Mountain (Top East)'), #hammer + ('DM Hammer Bridge (East)', 'East Death Mountain (Top West)'), #hammer + ('EDM To Spiral Ledge Drop', 'Spiral Cave Ledge'), + ('EDM To Fairy Ledge Drop', 'Fairy Ascension Ledge'), + ('EDM Ledge Drop', 'East Death Mountain (Bottom)'), + ('Spiral Ledge Drop', 'East Death Mountain (Bottom)'), + ('Fairy Ascension Ledge Drop', 'Fairy Ascension Plateau'), + ('Fairy Ascension Plateau Ledge Drop', 'East Death Mountain (Bottom)'), + ('Fairy Ascension Rocks (Inner)', 'East Death Mountain (Bottom)'), #mitts + ('Fairy Ascension Rocks (Outer)', 'Fairy Ascension Plateau'), #mitts + ('DM Broken Bridge (West)', 'East Death Mountain (Bottom)'), #hookshot + ('DM Broken Bridge (East)', 'East Death Mountain (Bottom Left)'), #hookshot + ('TR Pegs Ledge Entry', 'Death Mountain TR Pegs Ledge'), #mitts + ('TR Pegs Ledge Leave', 'Death Mountain TR Pegs Area'), #mitts + ('Mountain Pass Rock (Outer)', 'Mountain Pass Entry'), #glove + ('Mountain Pass Rock (Inner)', 'Mountain Pass Area'), #glove + ('Mountain Pass Entry Ledge Drop', 'Mountain Pass Area'), + ('Mountain Pass Ledge Drop', 'Mountain Pass Area'), + ('Zora Waterfall Landing', 'Zora Waterfall Area'), + ('Zora Waterfall Water Drop', 'Zora Waterfall Water'), #flippers + ('Zora Waterfall Water Entry', 'Zora Waterfall Water'), #flippers + ('Zora Waterfall Approach', 'Zora Waterfall Entryway'), #flippers + ('Lost Woods Pass Hammer (North)', 'Lost Woods Pass Portal Area'), #hammer + ('Lost Woods Pass Hammer (South)', 'Lost Woods Pass East Top Area'), #hammer + ('Lost Woods Pass Rock (North)', 'Lost Woods Pass East Bottom Area'), #mitts + ('Lost Woods Pass Rock (South)', 'Lost Woods Pass Portal Area'), #mitts + ('Bonk Rock Ledge Drop', 'Sanctuary Area'), + ('Graveyard Ledge Drop', 'Graveyard Area'), + ('Kings Grave Rocks (Outer)', 'Kings Grave Area'), #mitts + ('Kings Grave Rocks (Inner)', 'Graveyard Area'), #mitts + ('River Bend Water Drop', 'River Bend Water'), #flippers + ('River Bend East Water Drop', 'River Bend Water'), #flippers + ('River Bend West Pier', 'River Bend Area'), + ('River Bend East Pier', 'River Bend East Bank'), + ('Potion Shop Water Drop', 'Potion Shop Water'), #flippers + ('Potion Shop Northeast Water Drop', 'Potion Shop Water'), #flippers + ('Potion Shop Rock (South)', 'Potion Shop Northeast'), #glove + ('Potion Shop Rock (North)', 'Potion Shop Area'), #glove + ('Zora Approach Water Drop', 'Zora Approach Water'), #flippers + ('Zora Approach Rocks (West)', 'Zora Approach Ledge'), #mitts/boots + ('Zora Approach Rocks (East)', 'Zora Approach Area'), #mitts/boots + ('Zora Approach Bottom Ledge Drop', 'Zora Approach Ledge'), + ('Zora Approach Ledge Drop', 'Zora Approach Area'), + ('Kakariko Southwest Bush (North)', 'Kakariko Southwest'), #pearl + ('Kakariko Southwest Bush (South)', 'Kakariko Village'), #pearl + ('Kakariko Yard Bush (South)', 'Kakariko Bush Yard'), #pearl + ('Kakariko Yard Bush (North)', 'Kakariko Village'), #pearl + ('Hyrule Castle Southwest Bush (North)', 'Hyrule Castle Southwest'), #pearl + ('Hyrule Castle Southwest Bush (South)', 'Hyrule Castle Area'), #pearl + ('Hyrule Castle Courtyard Bush (North)', 'Hyrule Castle Courtyard'), #pearl + ('Hyrule Castle Courtyard Bush (South)', 'Hyrule Castle Courtyard Northeast'), #pearl + ('Hyrule Castle Main Gate (South)', 'Hyrule Castle Courtyard'), #aga+mirror + ('Hyrule Castle Main Gate (North)', 'Hyrule Castle Area'), #aga+mirror + ('Hyrule Castle Ledge Drop', 'Hyrule Castle Area'), + ('Hyrule Castle Ledge Courtyard Drop', 'Hyrule Castle Courtyard'), + ('Hyrule Castle East Rock (Inner)', 'Hyrule Castle East Entry'), #glove + ('Hyrule Castle East Rock (Outer)', 'Hyrule Castle Area'), #glove + ('Wooden Bridge Bush (South)', 'Wooden Bridge Northeast'), #pearl + ('Wooden Bridge Bush (North)', 'Wooden Bridge Area'), #pearl + ('Wooden Bridge Water Drop', 'Wooden Bridge Water'), #flippers + ('Wooden Bridge Northeast Water Drop', 'Wooden Bridge Water'), #flippers + ('Blacksmith Ledge Peg (West)', 'Blacksmith Ledge'), #hammer + ('Blacksmith Ledge Peg (East)', 'Blacksmith Area'), #hammer + ('Maze Race Game', 'Maze Race Prize'), #pearl + ('Maze Race Ledge Drop', 'Maze Race Area'), + ('Stone Bridge (Southbound)', 'Stone Bridge South Area'), + ('Stone Bridge (Northbound)', 'Stone Bridge North Area'), + ('Desert Statue Move', 'Desert Stairs'), #book + ('Desert Ledge Drop', 'Desert Area'), + ('Desert Ledge Rocks (Outer)', 'Desert Ledge Keep'), #glove + ('Desert Ledge Rocks (Inner)', 'Desert Ledge'), #glove + ('Checkerboard Ledge Drop', 'Desert Area'), + ('Desert Mouth Drop', 'Desert Area'), + ('Desert Teleporter Drop', 'Desert Area'), + ('Bombos Tablet Drop', 'Desert Area'), + ('Flute Boy Bush (North)', 'Flute Boy Approach Area'), #pearl + ('Flute Boy Bush (South)', 'Flute Boy Bush Entry'), #pearl + ('C Whirlpool Water Entry', 'C Whirlpool Water'), #flippers + ('C Whirlpool Landing', 'C Whirlpool Area'), + ('C Whirlpool Rock (Bottom)', 'C Whirlpool Outer Area'), #glove + ('C Whirlpool Rock (Top)', 'C Whirlpool Area'), #glove + ('C Whirlpool Pegs (Outer)', 'C Whirlpool Portal Area'), #hammer + ('C Whirlpool Pegs (Inner)', 'C Whirlpool Area'), #hammer + ('Statues Water Entry', 'Statues Water'), #flippers + ('Statues Landing', 'Statues Area'), + ('Lake Hylia Water Drop', 'Lake Hylia Water'), #flippers + ('Lake Hylia South Water Drop', 'Lake Hylia Water'), #flippers + ('Lake Hylia Northeast Water Drop', 'Lake Hylia Water'), #flippers + ('Lake Hylia Central Water Drop', 'Lake Hylia Water'), #flippers + ('Lake Hylia Island Water Drop', 'Lake Hylia Water'), #flippers + ('Lake Hylia Central Island Pier', 'Lake Hylia Central Island'), + ('Lake Hylia West Pier', 'Lake Hylia Northwest Bank'), + ('Lake Hylia East Pier', 'Lake Hylia Northeast Bank'), + ('Lake Hylia Water D Approach', 'Lake Hylia Water D'), + ('Lake Hylia Water D Leave', 'Lake Hylia Water'), #flippers + ('Ice Cave Water Drop', 'Ice Cave Water'), #flippers + ('Ice Cave Pier', 'Ice Cave Area'), + ('Desert Pass Ledge Drop', 'Desert Pass Area'), + ('Desert Pass Rocks (North)', 'Desert Pass Southeast'), #glove + ('Desert Pass Rocks (South)', 'Desert Pass Area'), #glove + ('Middle Aged Man', 'Middle Aged Man'), + ('Octoballoon Water Drop', 'Octoballoon Water'), #flippers + ('Octoballoon Waterfall Water Drop', 'Octoballoon Water'), #flippers + ('Octoballoon Pier', 'Octoballoon Area'), - ('Skull Woods Bush Rock (West)', 'Skull Woods Forest'), #glove - ('Skull Woods Bush Rock (East)', 'Skull Woods Portal Entry'), #glove - ('Skull Woods Forgotten Bush (West)', 'Skull Woods Forgotten Path (Northeast)'), #pearl - ('Skull Woods Forgotten Bush (East)', 'Skull Woods Forgotten Path (Southwest)'), #pearl - ('Dark Death Mountain Drop (West)', 'West Dark Death Mountain (Bottom)'), - ('GT Entry Approach', 'GT Approach'), - ('GT Entry Leave', 'West Dark Death Mountain (Top)'), - ('Floating Island Drop', 'East Dark Death Mountain (Top)'), - ('Dark Death Mountain Drop (East)', 'East Dark Death Mountain (Bottom)'), - ('East Dark Death Mountain Bushes', 'East Dark Death Mountain (Bushes)'), - ('Turtle Rock Ledge Drop', 'Turtle Rock Area'), - ('Bumper Cave Entrance Rock', 'Bumper Cave Entrance'), #glove - ('Bumper Cave Ledge Drop', 'Bumper Cave Area'), - ('Bumper Cave Entrance Drop', 'Bumper Cave Area'), - ('Skull Woods Pass Bush Row (West)', 'Skull Woods Pass East Top Area'), #pearl - ('Skull Woods Pass Bush Row (East)', 'Skull Woods Pass West Area'), #pearl - ('Skull Woods Pass Bush (North)', 'Skull Woods Pass Portal Area'), #pearl - ('Skull Woods Pass Bush (South)', 'Skull Woods Pass East Top Area'), #pearl - ('Skull Woods Pass Rock (North)', 'Skull Woods Pass East Bottom Area'), #mitts - ('Skull Woods Pass Rock (South)', 'Skull Woods Pass Portal Area'), #mitts - ('Dark Graveyard Bush (South)', 'Dark Graveyard North'), #pearl - ('Dark Graveyard Bush (North)', 'Dark Graveyard Area'), #pearl - ('Qirn Jump Water Drop', 'Qirn Jump Water'), #flippers - ('Qirn Jump East Water Drop', 'Qirn Jump Water'), #flippers - ('Qirn Jump Pier', 'Qirn Jump East Bank'), - ('Dark Witch Water Drop', 'Dark Witch Water'), #flippers - ('Dark Witch Northeast Water Drop', 'Dark Witch Water'), #flippers - ('Dark Witch Rock (North)', 'Dark Witch Area'), #glove - ('Dark Witch Rock (South)', 'Dark Witch Northeast'), #glove - ('Catfish Approach Rocks (West)', 'Catfish Approach Ledge'), #mitts/boots - ('Catfish Approach Rocks (East)', 'Catfish Approach Area'), #mitts/boots - ('Catfish Approach Bottom Ledge Drop', 'Catfish Approach Ledge'), - ('Catfish Approach Ledge Drop', 'Catfish Approach Area'), - ('Catfish Approach Water Drop', 'Catfish Approach Water'), #flippers - ('Village of Outcasts Pegs', 'Dark Grassy Lawn'), #hammer - ('Grassy Lawn Pegs', 'Village of Outcasts Area'), #hammer - ('Shield Shop Fence (Outer) Ledge Drop', 'Shield Shop Fence'), - ('Shield Shop Fence (Inner) Ledge Drop', 'Shield Shop Area'), - ('Pyramid Exit Ledge Drop', 'Pyramid Area'), - ('Pyramid Crack', 'Pyramid Crack'), - ('Broken Bridge Hammer Rock (South)', 'Broken Bridge Northeast'), #hammer/glove - ('Broken Bridge Hammer Rock (North)', 'Broken Bridge Area'), #hammer/glove - ('Broken Bridge Hookshot Gap', 'Broken Bridge West'), #hookshot - ('Broken Bridge Water Drop', 'Broken Bridge Water'), #flippers - ('Broken Bridge Northeast Water Drop', 'Broken Bridge Water'), #flippers - ('Broken Bridge West Water Drop', 'Broken Bridge Water'), #flippers - ('Peg Area Rocks (West)', 'Hammer Pegs Area'), #mitts - ('Peg Area Rocks (East)', 'Hammer Pegs Entry'), #mitts - ('Dig Game To Ledge Drop', 'Dig Game Ledge'), #mitts - ('Dig Game Ledge Drop', 'Dig Game Area'), - ('Frog Ledge Drop', 'Archery Game Area'), - ('Frog Rock (Inner)', 'Frog Area'), #mitts - ('Frog Rock (Outer)', 'Frog Prison'), #mitts - ('Archery Game Rock (North)', 'Archery Game Area'), #mitts - ('Archery Game Rock (South)', 'Frog Area'), #mitts - ('Hammer Bridge Pegs (North)', 'Hammer Bridge South Area'), #hammer - ('Hammer Bridge Pegs (South)', 'Hammer Bridge North Area'), #hammer - ('Hammer Bridge Water Drop', 'Hammer Bridge Water'), #flippers - ('Hammer Bridge Pier', 'Hammer Bridge North Area'), - ('Misery Mire Teleporter Ledge Drop', 'Misery Mire Area'), - ('Stumpy Approach Bush (North)', 'Stumpy Approach Area'), #pearl - ('Stumpy Approach Bush (South)', 'Stumpy Approach Bush Entry'), #pearl - ('Dark C Whirlpool Water Entry', 'Dark C Whirlpool Water'), #flippers - ('Dark C Whirlpool Landing', 'Dark C Whirlpool Area'), - ('Dark C Whirlpool Rock (Bottom)', 'Dark C Whirlpool Outer Area'), #glove - ('Dark C Whirlpool Rock (Top)', 'Dark C Whirlpool Area'), #glove - ('Dark C Whirlpool Pegs (Right)', 'Dark C Whirlpool Portal Area'), #hammer - ('Dark C Whirlpool Pegs (Left)', 'Dark C Whirlpool Area'), #hammer - ('Hype Cave Water Entry', 'Hype Cave Water'), #flippers - ('Hype Cave Landing', 'Hype Cave Area'), - ('Ice Lake Water Drop', 'Ice Lake Water'), #flippers - ('Ice Lake Northeast Water Drop', 'Ice Lake Water'), #flippers - ('Ice Lake Southwest Water Drop', 'Ice Lake Water'), #flippers - ('Ice Lake Southeast Water Drop', 'Ice Lake Water'), #flippers - ('Ice Lake Moat Water Entry', 'Ice Lake Water'), #flippers - ('Ice Lake Northeast Pier', 'Ice Lake Northeast Bank'), - ('Bomber Corner Water Drop', 'Bomber Corner Water'), #flippers - ('Bomber Corner Waterfall Water Drop', 'Bomber Corner Water'), #flippers - ('Bomber Corner Pier', 'Bomber Corner Area'), + ('Skull Woods Rock (West)', 'Skull Woods Forest'), #glove + ('Skull Woods Rock (East)', 'Skull Woods Portal Entry'), #glove + ('Skull Woods Forgotten Bush (West)', 'Skull Woods Forgotten Path (Northeast)'), #pearl + ('Skull Woods Forgotten Bush (East)', 'Skull Woods Forgotten Path (Southwest)'), #pearl + ('West Dark Death Mountain Drop', 'West Dark Death Mountain (Bottom)'), + ('GT Approach', 'GT Stairs'), + ('GT Leave', 'West Dark Death Mountain (Top)'), + ('Floating Island Drop', 'East Dark Death Mountain (Top)'), + ('East Dark Death Mountain Drop', 'East Dark Death Mountain (Bottom)'), + ('East Dark Death Mountain Bushes', 'East Dark Death Mountain (Bushes)'), + ('Turtle Rock Ledge Drop', 'Turtle Rock Area'), + ('Bumper Cave Rock (Outer)', 'Bumper Cave Entry'), #glove + ('Bumper Cave Rock (Inner)', 'Bumper Cave Area'), #glove + ('Bumper Cave Ledge Drop', 'Bumper Cave Area'), + ('Bumper Cave Entry Drop', 'Bumper Cave Area'), + ('Skull Woods Pass Bush Row (West)', 'Skull Woods Pass East Top Area'), #pearl + ('Skull Woods Pass Bush Row (East)', 'Skull Woods Pass West Area'), #pearl + ('Skull Woods Pass Bush (North)', 'Skull Woods Pass Portal Area'), #pearl + ('Skull Woods Pass Bush (South)', 'Skull Woods Pass East Top Area'), #pearl + ('Skull Woods Pass Rock (North)', 'Skull Woods Pass East Bottom Area'), #mitts + ('Skull Woods Pass Rock (South)', 'Skull Woods Pass Portal Area'), #mitts + ('Dark Graveyard Bush (South)', 'Dark Graveyard North'), #pearl + ('Dark Graveyard Bush (North)', 'Dark Graveyard Area'), #pearl + ('Qirn Jump Water Drop', 'Qirn Jump Water'), #flippers + ('Qirn Jump East Water Drop', 'Qirn Jump Water'), #flippers + ('Qirn Jump Pier', 'Qirn Jump East Bank'), + ('Dark Witch Water Drop', 'Dark Witch Water'), #flippers + ('Dark Witch Northeast Water Drop', 'Dark Witch Water'), #flippers + ('Dark Witch Rock (North)', 'Dark Witch Area'), #glove + ('Dark Witch Rock (South)', 'Dark Witch Northeast'), #glove + ('Catfish Approach Water Drop', 'Catfish Approach Water'), #flippers + ('Catfish Approach Rocks (West)', 'Catfish Approach Ledge'), #mitts/boots + ('Catfish Approach Rocks (East)', 'Catfish Approach Area'), #mitts/boots + ('Catfish Approach Bottom Ledge Drop', 'Catfish Approach Ledge'), + ('Catfish Approach Ledge Drop', 'Catfish Approach Area'), + ('Bush Yard Pegs (Outer)', 'Village of Outcasts Bush Yard'), #hammer + ('Bush Yard Pegs (Inner)', 'Village of Outcasts'), #hammer + ('Shield Shop Fence Drop (Outer)', 'Shield Shop Fence'), + ('Shield Shop Fence Drop (Inner)', 'Shield Shop Area'), + ('Pyramid Exit Ledge Drop', 'Pyramid Area'), + ('Pyramid Crack', 'Pyramid Crack'), + ('Broken Bridge Hammer Rock (South)', 'Broken Bridge Northeast'), #hammer/glove + ('Broken Bridge Hammer Rock (North)', 'Broken Bridge Area'), #hammer/glove + ('Broken Bridge Hookshot Gap', 'Broken Bridge West'), #hookshot + ('Broken Bridge Water Drop', 'Broken Bridge Water'), #flippers + ('Broken Bridge Northeast Water Drop', 'Broken Bridge Water'), #flippers + ('Broken Bridge West Water Drop', 'Broken Bridge Water'), #flippers + ('Peg Area Rocks (West)', 'Hammer Pegs Area'), #mitts + ('Peg Area Rocks (East)', 'Hammer Pegs Entry'), #mitts + ('Dig Game To Ledge Drop', 'Dig Game Ledge'), #mitts + ('Dig Game Ledge Drop', 'Dig Game Area'), + ('Frog Ledge Drop', 'Archery Game Area'), + ('Frog Rock (Inner)', 'Frog Area'), #mitts + ('Frog Rock (Outer)', 'Frog Prison'), #mitts + ('Archery Game Rock (North)', 'Archery Game Area'), #mitts + ('Archery Game Rock (South)', 'Frog Area'), #mitts + ('Hammer Bridge Pegs (North)', 'Hammer Bridge South Area'), #hammer + ('Hammer Bridge Pegs (South)', 'Hammer Bridge North Area'), #hammer + ('Hammer Bridge Water Drop', 'Hammer Bridge Water'), #flippers + ('Hammer Bridge Pier', 'Hammer Bridge North Area'), + ('Mire Teleporter Ledge Drop', 'Mire Area'), + ('Stumpy Approach Bush (North)', 'Stumpy Approach Area'), #pearl + ('Stumpy Approach Bush (South)', 'Stumpy Approach Bush Entry'), #pearl + ('Dark C Whirlpool Water Entry', 'Dark C Whirlpool Water'), #flippers + ('Dark C Whirlpool Landing', 'Dark C Whirlpool Area'), + ('Dark C Whirlpool Rock (Bottom)', 'Dark C Whirlpool Outer Area'), #glove + ('Dark C Whirlpool Rock (Top)', 'Dark C Whirlpool Area'), #glove + ('Dark C Whirlpool Pegs (Outer)', 'Dark C Whirlpool Portal Area'), #hammer + ('Dark C Whirlpool Pegs (Inner)', 'Dark C Whirlpool Area'), #hammer + ('Hype Cave Water Entry', 'Hype Cave Water'), #flippers + ('Hype Cave Landing', 'Hype Cave Area'), + ('Ice Lake Water Drop', 'Ice Lake Water'), #flippers + ('Ice Lake Northeast Water Drop', 'Ice Lake Water'), #flippers + ('Ice Lake Southwest Water Drop', 'Ice Lake Water'), #flippers + ('Ice Lake Southeast Water Drop', 'Ice Lake Water'), #flippers + ('Ice Lake Iceberg Water Entry', 'Ice Lake Water'), #flippers + ('Ice Lake Northeast Pier', 'Ice Lake Northeast Bank'), + ('Shopping Mall Water Drop', 'Shopping Mall Water'), #flippers + ('Shopping Mall Pier', 'Shopping Mall Area'), + ('Bomber Corner Water Drop', 'Bomber Corner Water'), #flippers + ('Bomber Corner Waterfall Water Drop', 'Bomber Corner Water'), #flippers + ('Bomber Corner Pier', 'Bomber Corner Area'), - # OWG In-Bounds Connections - ('Ice Lake Northeast Pier Hop', 'Ice Lake Northeast Bank'), - ('Ice Lake Moat Bomb Jump', 'Ice Lake Moat') - ] + # OWG In-Bounds Connections + ('Ice Lake Northeast Pier Hop', 'Ice Lake Northeast Bank'), + ('Ice Lake Iceberg Bomb Jump', 'Ice Lake Iceberg') +] default_whirlpool_connections = [ ((0x33, 'C Whirlpool', 'C Whirlpool Water'), (0x15, 'River Bend Whirlpool', 'River Bend Water')), @@ -1479,17 +1484,18 @@ ow_connections = { ], [ ('Floating Island Bridge (West)', 'East Death Mountain (Top East)'), ('Floating Island Bridge (East)', 'Death Mountain Floating Island'), - ('East Death Mountain Mimic Ledge Drop', 'Mimic Cave Ledge'), + ('EDM To Mimic Ledge Drop', 'Mimic Cave Ledge'), ('Mimic Ledge Drop', 'East Death Mountain (Bottom)'), ('Spiral Mimic Bridge (West)', 'Spiral Mimic Ledge Extend'), ('Spiral Mimic Bridge (East)', 'Spiral Mimic Ledge Extend'), ('Spiral Ledge Approach', 'Spiral Cave Ledge'), ('Mimic Ledge Approach', 'Mimic Cave Ledge'), ('Spiral Mimic Ledge Drop', 'Fairy Ascension Ledge'), - ('Dark Death Mountain Teleporter (East)', 'East Death Mountain (Bottom)') + ('East Dark Death Mountain Teleporter', 'East Death Mountain (Bottom)') ]), 0x07: ([ - ('TR Pegs Teleporter', 'Turtle Rock Ledge') + ('TR Pegs Teleporter', 'Turtle Rock Ledge'), + ('TR Pegs Ledge Drop', 'Death Mountain TR Pegs Area') ], [ ('Turtle Rock Tail Ledge Drop', 'Turtle Rock Ledge'), ('Turtle Rock Teleporter', 'Death Mountain TR Pegs Ledge') @@ -1509,21 +1515,21 @@ ow_connections = { ('Castle Gate Teleporter', 'Pyramid Area'), ('Castle Gate Teleporter (Inner)', 'Pyramid Area') ], [ - ('Post Aga Inverted Teleporter', 'Hyrule Castle Area') + ('Post Aga Teleporter', 'Hyrule Castle Area') ]), 0x1e: ([ - ('Eastern Palace Ledge Drop', 'Eastern Palace Area'), # OWG - ('Palace of Darkness Ledge Drop', 'Palace of Darkness Area') # OWG + ('Eastern Palace Cliff Ledge Drop', 'Eastern Palace Area'), # OWG + ('Palace of Darkness Cliff Ledge Drop', 'Palace of Darkness Area') # OWG ], [ - ('Eastern Palace Ledge Drop', 'Palace of Darkness Area'), # OWG - ('Palace of Darkness Ledge Drop', 'Eastern Palace Area') # OWG + ('Eastern Palace Cliff Ledge Drop', 'Palace of Darkness Area'), # OWG + ('Palace of Darkness Cliff Ledge Drop', 'Eastern Palace Area') # OWG ]), 0x25: ([ - ('Sand Dunes Ledge Drop', 'Sand Dunes Area'), # OWG - ('Dark Dunes Ledge Drop', 'Dark Dunes Area') # OWG + ('Sand Dunes Cliff Ledge Drop', 'Sand Dunes Area'), # OWG + ('Dark Dunes Cliff Ledge Drop', 'Dark Dunes Area') # OWG ], [ - ('Sand Dunes Ledge Drop', 'Dark Dunes Area'), # OWG - ('Dark Dunes Ledge Drop', 'Sand Dunes Area') # OWG + ('Sand Dunes Cliff Ledge Drop', 'Dark Dunes Area'), # OWG + ('Dark Dunes Cliff Ledge Drop', 'Sand Dunes Area') # OWG ]), 0x29: ([ ('Suburb Cliff Ledge Drop', 'Kakariko Suburb Area'), # OWG @@ -1547,8 +1553,8 @@ ow_connections = { ('Bomb Shop Cliff Ledge Drop', 'Links House Area') # OWG ]), 0x2d: ([ - ('Stone Bridge East Ledge Drop', 'Stone Bridge North Area'), # OWG - ('Hammer Bridge North Ledge Drop', 'Hammer Bridge North Area'), # OWG + ('Stone Bridge East Cliff Ledge Drop', 'Stone Bridge North Area'), # OWG + ('Hammer Bridge North Cliff Ledge Drop', 'Hammer Bridge North Area'), # OWG ('Stone Bridge Cliff Ledge Drop', 'Stone Bridge South Area'), # OWG ('Hammer Bridge South Cliff Ledge Drop', 'Hammer Bridge South Area'), # OWG ('Stone Bridge EC Cliff Water Drop', 'Stone Bridge Water'), # fake flipper @@ -1556,8 +1562,8 @@ ow_connections = { ('Tree Line WC Cliff Water Drop', 'Tree Line Water'), # fake flipper ('Dark Tree Line WC Cliff Water Drop', 'Dark Tree Line Water') # fake flipper ], [ - ('Stone Bridge East Ledge Drop', 'Hammer Bridge North Area'), # OWG - ('Hammer Bridge North Ledge Drop', 'Stone Bridge North Area'), # OWG + ('Stone Bridge East Cliff Ledge Drop', 'Hammer Bridge North Area'), # OWG + ('Hammer Bridge North Cliff Ledge Drop', 'Stone Bridge North Area'), # OWG ('Stone Bridge Cliff Ledge Drop', 'Hammer Bridge South Area'), # OWG ('Hammer Bridge South Cliff Ledge Drop', 'Stone Bridge South Area'), # OWG ('Stone Bridge EC Cliff Water Drop', 'Hammer Bridge Water'), # fake flipper @@ -1566,29 +1572,27 @@ ow_connections = { ('Dark Tree Line WC Cliff Water Drop', 'Tree Line Water') # fake flipper ]), 0x2e: ([ - ('Tree Line Ledge Drop', 'Tree Line Area'), # OWG - ('Dark Tree Line Ledge Drop', 'Dark Tree Line Area') # OWG + ('Tree Line Cliff Ledge Drop', 'Tree Line Area'), # OWG + ('Dark Tree Line Cliff Ledge Drop', 'Dark Tree Line Area') # OWG ], [ - ('Tree Line Ledge Drop', 'Dark Tree Line Area'), # OWG - ('Dark Tree Line Ledge Drop', 'Tree Line Area') # OWG + ('Tree Line Cliff Ledge Drop', 'Dark Tree Line Area'), # OWG + ('Dark Tree Line Cliff Ledge Drop', 'Tree Line Area') # OWG ]), 0x2f: ([ - ('East Hyrule Teleporter', 'Palace of Darkness Nook Area') + ('East Hyrule Teleporter', 'Darkness Nook Area') ], [ ('East Dark World Teleporter', 'Eastern Nook Area') ]), 0x30: ([ ('Mirror To Bombos Tablet Ledge', 'Bombos Tablet Ledge'), # OWG - ('Desert Teleporter', 'Misery Mire Teleporter Ledge'), - ('Desert Boss Cliff Ledge Drop', 'Desert Palace Entrance (North) Spot'), # OWG - ('Mire Cliff Ledge Drop', 'Misery Mire Area'), # OWG + ('Desert Teleporter', 'Mire Teleporter Ledge'), + ('Mire Cliff Ledge Drop', 'Mire Area'), # OWG ('Checkerboard Cliff Ledge Drop', 'Desert Checkerboard Ledge') # OWG ], [ ('Checkerboard Ledge Approach', 'Desert Checkerboard Ledge'), ('Checkerboard Ledge Leave', 'Desert Area'), - ('Misery Mire Teleporter', 'Desert Palace Teleporter Ledge'), - ('Desert Boss Cliff Ledge Drop', 'Misery Mire Area'), # OWG - ('Mire Cliff Ledge Drop', 'Desert Palace Entrance (North) Spot'), # OWG + ('Mire Teleporter', 'Desert Teleporter Ledge'), + ('Mire Cliff Ledge Drop', 'Desert Ledge Keep'), # OWG ('Dark Checkerboard Cliff Ledge Drop', 'Desert Checkerboard Ledge') # OWG ]), 0x32: ([ @@ -1596,8 +1600,8 @@ ow_connections = { ('Cave 45 Cliff Ledge Drop', 'Cave 45 Ledge'), # OWG ('Stumpy Approach Cliff Ledge Drop', 'Stumpy Approach Area') # OWG ], [ - ('Cave 45 Inverted Leave', 'Flute Boy Approach Area'), - ('Cave 45 Inverted Approach', 'Cave 45 Ledge'), + ('Cave 45 Leave', 'Flute Boy Approach Area'), + ('Cave 45 Approach', 'Cave 45 Ledge'), ('Cave 45 Cliff Ledge Drop', 'Stumpy Approach Area'), # OWG ('Stumpy Approach Cliff Ledge Drop', 'Cave 45 Ledge') # OWG ]), @@ -1631,17 +1635,16 @@ ow_connections = { ]), 0x35: ([ ('Lake Hylia Teleporter', 'Ice Palace Area'), - #('Ice Palace Ledge Drop', 'Ice Lake Moat'), - ('Lake Hylia Area Cliff Ledge Drop', 'Lake Hylia Area'), # OWG - ('Ice Lake Area Cliff Ledge Drop', 'Ice Lake Area'), # OWG + ('Lake Hylia Northwest Cliff Ledge Drop', 'Lake Hylia Northwest Bank'), # OWG + ('Ice Lake Northwest Cliff Ledge Drop', 'Ice Lake Northwest Bank'), # OWG ('Lake Hylia Island FAWT Ledge Drop', 'Lake Hylia Island'), # OWG - ('Ice Palace Island FAWT Ledge Drop', 'Ice Lake Moat') # OWG + ('Ice Palace Island FAWT Ledge Drop', 'Ice Lake Iceberg') # OWG ], [ ('Lake Hylia Island Pier', 'Lake Hylia Island'), - ('Ice Palace Teleporter', 'Lake Hylia Water D'), - ('Lake Hylia Area Cliff Ledge Drop', 'Ice Lake Area'), # OWG - ('Ice Lake Area Cliff Ledge Drop', 'Lake Hylia Area'), # OWG - ('Lake Hylia Island FAWT Ledge Drop', 'Ice Lake Moat'), # OWG + ('Ice Lake Teleporter', 'Lake Hylia Water D'), + ('Lake Hylia Northwest Cliff Ledge Drop', 'Ice Lake Northwest Bank'), # OWG + ('Ice Lake Northwest Cliff Ledge Drop', 'Lake Hylia Northwest Bank'), # OWG + ('Lake Hylia Island FAWT Ledge Drop', 'Ice Lake Iceberg'), # OWG ('Ice Palace Island FAWT Ledge Drop', 'Lake Hylia Island') # OWG ]), 0x3a: ([ @@ -1681,11 +1684,11 @@ mirror_connections = { 'East Dark Death Mountain (Bushes)': ['Fairy Ascension Plateau'], 'East Dark Death Mountain (Bottom Left)': ['East Death Mountain (Bottom Left)'], - 'Turtle Rock Area': ['Death Mountain TR Pegs'], + 'Turtle Rock Area': ['Death Mountain TR Pegs Area'], - 'Bumper Cave Area': ['Mountain Entry Area'], - 'Bumper Cave Entrance': ['Mountain Entry Entrance'], - 'Bumper Cave Ledge': ['Mountain Entry Ledge'], + 'Bumper Cave Area': ['Mountain Pass Area'], + 'Bumper Cave Entry': ['Mountain Pass Entry'], + 'Bumper Cave Ledge': ['Mountain Pass Ledge'], 'Catfish Area': ['Zora Waterfall Area'], @@ -1712,8 +1715,8 @@ mirror_connections = { 'Catfish Approach Area': ['Zora Approach Area'], 'Catfish Approach Ledge': ['Zora Approach Ledge'], - 'Village of Outcasts Area': ['Kakariko Area'], - 'Dark Grassy Lawn': ['Kakariko Area'], + 'Village of Outcasts': ['Kakariko Village'], + 'Village of Outcasts Bush Yard': ['Kakariko Village'], 'Shield Shop Area': ['Forgotten Forest Area'], 'Shield Shop Fence': ['Forgotten Forest Area'], @@ -1728,7 +1731,7 @@ mirror_connections = { 'Palace of Darkness Area': ['Eastern Palace Area'], - 'Hammer Pegs Area': ['Blacksmith Area', 'Bat Cave Ledge'], + 'Hammer Pegs Area': ['Blacksmith Area', 'Blacksmith Ledge'], 'Hammer Pegs Entry': ['Blacksmith Area'], 'Dark Dunes Area': ['Sand Dunes Area'], @@ -1752,9 +1755,9 @@ mirror_connections = { 'Dark Tree Line Area': ['Tree Line Area'], - 'Palace of Darkness Nook Area': ['Eastern Nook Area'], + 'Darkness Nook Area': ['Eastern Nook Area'], - 'Misery Mire Area': ['Desert Area', 'Desert Ledge', 'Desert Checkerboard Ledge', 'Desert Palace Stairs', 'Desert Palace Entrance (North) Spot'], + 'Mire Area': ['Desert Area', 'Desert Ledge', 'Desert Checkerboard Ledge', 'Desert Stairs', 'Desert Ledge Keep'], 'Stumpy Approach Area': ['Cave 45 Ledge'], 'Stumpy Approach Bush Entry': ['Flute Boy Bush Entry'], @@ -1764,13 +1767,13 @@ mirror_connections = { 'Hype Cave Area': ['Statues Area'], - 'Ice Lake Area': ['Lake Hylia Area'], + 'Ice Lake Northwest Bank': ['Lake Hylia Northwest Bank'], 'Ice Lake Northeast Bank': ['Lake Hylia Northeast Bank'], - 'Ice Lake Ledge (West)': ['Lake Hylia South Shore'], - 'Ice Lake Ledge (East)': ['Lake Hylia South Shore'], + 'Ice Lake Southwest Ledge': ['Lake Hylia South Shore'], + 'Ice Lake Southeast Ledge': ['Lake Hylia South Shore'], 'Ice Lake Water': ['Lake Hylia Island'], 'Ice Palace Area': ['Lake Hylia Central Island'], - 'Ice Lake Moat': ['Lake Hylia Water', 'Lake Hylia Water D'], #needs flippers + 'Ice Lake Iceberg': ['Lake Hylia Water', 'Lake Hylia Water D'], #first one needs flippers 'Shopping Mall Area': ['Ice Cave Area'], @@ -1803,12 +1806,12 @@ mirror_connections = { 'East Death Mountain (Bottom)': ['East Dark Death Mountain (Bottom)'], 'Death Mountain Floating Island': ['Dark Death Mountain Floating Island'], - 'Death Mountain TR Pegs': ['Turtle Rock Area'], + 'Death Mountain TR Pegs Area': ['Turtle Rock Area'], 'Death Mountain TR Pegs Ledge': ['Turtle Rock Ledge'], - 'Mountain Entry Area': ['Bumper Cave Area'], - 'Mountain Entry Entrance': ['Bumper Cave Entrance'], - 'Mountain Entry Ledge': ['Bumper Cave Ledge'], + 'Mountain Pass Area': ['Bumper Cave Area'], + 'Mountain Pass Entry': ['Bumper Cave Entry'], + 'Mountain Pass Ledge': ['Bumper Cave Ledge'], 'Zora Waterfall Area': ['Catfish Area'], @@ -1837,9 +1840,9 @@ mirror_connections = { 'Zora Approach Area': ['Catfish Approach Area'], 'Zora Approach Ledge': ['Catfish Approach Ledge'], - 'Kakariko Area': ['Village of Outcasts Area'], - 'Kakariko Southwest': ['Village of Outcasts Area'], - 'Kakariko Grass Yard': ['Dark Grassy Lawn'], + 'Kakariko Village': ['Village of Outcasts'], + 'Kakariko Southwest': ['Village of Outcasts'], + 'Kakariko Bush Yard': ['Village of Outcasts Bush Yard'], 'Forgotten Forest Area': ['Shield Shop Area'], @@ -1877,13 +1880,13 @@ mirror_connections = { 'Tree Line Area': ['Dark Tree Line Area'], - 'Eastern Nook Area': ['Palace of Darkness Nook Area'], + 'Eastern Nook Area': ['Darkness Nook Area'], - 'Desert Area': ['Misery Mire Area'], - 'Desert Ledge': ['Misery Mire Area'], - 'Desert Palace Entrance (North) Spot': ['Misery Mire Area'], - 'Desert Checkerboard Ledge': ['Misery Mire Area'], - 'Desert Palace Stairs': ['Misery Mire Area'], + 'Desert Area': ['Mire Area'], + 'Desert Ledge': ['Mire Area'], + 'Desert Ledge Keep': ['Mire Area'], + 'Desert Checkerboard Ledge': ['Mire Area'], + 'Desert Stairs': ['Mire Area'], 'Flute Boy Approach Area': ['Stumpy Approach Area'], 'Cave 45 Ledge': ['Stumpy Approach Area'], @@ -1894,11 +1897,11 @@ mirror_connections = { 'Statues Area': ['Hype Cave Area'], - 'Lake Hylia Area': ['Ice Lake Area'], - 'Lake Hylia South Shore': ['Ice Lake Ledge (West)', 'Ice Lake Ledge (East)'], + 'Lake Hylia Northwest Bank': ['Ice Lake Northwest Bank'], + 'Lake Hylia South Shore': ['Ice Lake Southwest Ledge', 'Ice Lake Southeast Ledge'], 'Lake Hylia Northeast Bank': ['Ice Lake Northeast Bank'], 'Lake Hylia Central Island': ['Ice Palace Area'], - 'Lake Hylia Water D': ['Ice Lake Moat'], + 'Lake Hylia Water D': ['Ice Lake Iceberg'], 'Ice Cave Area': ['Shopping Mall Area'], @@ -1923,8 +1926,8 @@ default_connections = [('Lost Woods NW', 'Master Sword Meadow SC'), ('Lost Woods SC', 'Lost Woods Pass NE'), ('Lost Woods SE', 'Kakariko Fortune NE'), ('Lost Woods EN', 'Lumberjack WN'), - ('Lumberjack SW', 'Mountain Entry NW'), - ('Mountain Entry SE', 'Kakariko Pond NE'), + ('Lumberjack SW', 'Mountain Pass NW'), + ('Mountain Pass SE', 'Kakariko Pond NE'), ('Zora Waterfall NE', 'Zoras Domain SW'), ('Lost Woods Pass SW', 'Kakariko NW'), ('Lost Woods Pass SE', 'Kakariko NC'), @@ -2068,7 +2071,7 @@ one_way_ledges = { 'East Death Mountain (Bottom)': {'East Death Mountain (Top East)', 'Spiral Cave Ledge'}, 'Fairy Ascension Plateau': {'Fairy Ascension Ledge'}, - 'Mountain Entry Area': {'Mountain Entry Ledge'}, + 'Mountain Pass Area': {'Mountain Pass Ledge'}, 'Sanctuary Area': {'Bonk Rock Ledge'}, 'Graveyard Area': {'Graveyard Ledge'}, 'Potion Shop Water': {'Potion Shop Area', @@ -2083,9 +2086,9 @@ one_way_ledges = { 'Flute Boy Approach Area': {'Cave 45 Ledge'}, 'Desert Area': {'Desert Ledge', 'Desert Checkerboard Ledge', - 'Desert Palace Mouth', + 'Desert Mouth', 'Bombos Tablet Ledge', - 'Desert Palace Teleporter Ledge'}, + 'Desert Teleporter Ledge'}, 'Desert Pass Area': {'Desert Pass Ledge'}, 'Lake Hylia Water': {'Lake Hylia South Shore', 'Lake Hylia Island'}, @@ -2102,22 +2105,22 @@ one_way_ledges = { 'Broken Bridge Water': {'Broken Bridge West', 'Broken Bridge Area', 'Broken Bridge Northeast'}, - 'Misery Mire Area': {'Misery Mire Teleporter Ledge'}, - 'Ice Lake Water': {'Ice Lake Area', - 'Ice Lake Ledge (West)', - 'Ice Lake Ledge (East)'} + 'Mire Area': {'Mire Teleporter Ledge'}, + 'Ice Lake Water': {'Ice Lake Northwest Bank', + 'Ice Lake Southwest Ledge', + 'Ice Lake Southeast Ledge'} } isolated_regions = [ 'Death Mountain Floating Island', 'Mimic Cave Ledge', 'Spiral Mimic Ledge Extend', - 'Mountain Entry Ledge', + 'Mountain Pass Ledge', 'Maze Race Prize', 'Maze Race Ledge', 'Desert Ledge', - 'Desert Palace Entrance (North) Spot', - 'Desert Palace Mouth', + 'Desert Ledge Keep', + 'Desert Mouth', 'Dark Death Mountain Floating Island', 'Dark Death Mountain Ledge', 'Dark Death Mountain Isolated Ledge', @@ -2133,8 +2136,8 @@ flute_data = { 0x02: (['Lumberjack Area', 'Dark Lumberjack Area'], 0x02, 0x059c, 0x00d6, 0x04e6, 0x0138, 0x0558, 0x0143, 0x0563, 0xfffa, 0xfffa, 0x0138, 0x0550), 0x0b: (['West Death Mountain (Bottom)', 'West Dark Death Mountain (Top)'], 0x03, 0x1600, 0x02ca, 0x060e, 0x0328, 0x0678, 0x0337, 0x0683, 0xfff6, 0xfff2, 0x035b, 0x0680, 0x0118, 0x0860, 0x05c0, 0x00b8, 0x07ec, 0x0127, 0x086b, 0xfff8, 0x0004, 0x0148, 0x0850), 0x0e: (['East Death Mountain (Bottom)', 'East Dark Death Mountain (Bottom)'], 0x05, 0x1860, 0x031e, 0x0d00, 0x0388, 0x0da8, 0x038d, 0x0d7d, 0x0000, 0x0000, 0x0388, 0x0da8), - 0x07: (['Death Mountain TR Pegs', 'Turtle Rock Area'], 0x07, 0x0804, 0x0102, 0x0e1a, 0x0160, 0x0e90, 0x016f, 0x0e97, 0xfffe, 0x0006, 0x0160, 0x0f20), - 0x0a: (['Mountain Entry Area', 'Bumper Cave Area'], 0x0a, 0x0180, 0x0220, 0x0406, 0x0280, 0x0488, 0x028f, 0x0493, 0x0000, 0xfffa, 0x0280, 0x0488), + 0x07: (['Death Mountain TR Pegs Area', 'Turtle Rock Area'], 0x07, 0x0804, 0x0102, 0x0e1a, 0x0160, 0x0e90, 0x016f, 0x0e97, 0xfffe, 0x0006, 0x0160, 0x0f20), + 0x0a: (['Mountain Pass Area', 'Bumper Cave Area'], 0x0a, 0x0180, 0x0220, 0x0406, 0x0280, 0x0488, 0x028f, 0x0493, 0x0000, 0xfffa, 0x0280, 0x0488), 0x0f: (['Zora Waterfall Area', 'Catfish Area'], 0x0f, 0x0316, 0x025c, 0x0eb2, 0x02c0, 0x0f28, 0x02cb, 0x0f2f, 0x0002, 0xfffe, 0x02d0, 0x0f38), 0x10: (['Lost Woods Pass West Area', 'Skull Woods Pass West Area'], 0x10, 0x0080, 0x0400, 0x0000, 0x0448, 0x0058, 0x046f, 0x0085, 0x0000, 0x0000, 0x0448, 0x0058), 0x11: (['Kakariko Fortune Area', 'Dark Fortune Area'], 0x11, 0x0912, 0x051e, 0x0292, 0x0588, 0x0318, 0x058d, 0x031f, 0x0000, 0xfffe, 0x0588, 0x0318), @@ -2144,7 +2147,7 @@ flute_data = { 0x15: (['River Bend East Bank', 'Qirn Jump East Bank'], 0x15, 0x041a, 0x0486, 0x0ad2, 0x04e8, 0x0b48, 0x04f3, 0x0b4f, 0x0008, 0xfffe, 0x04f8, 0x0b60), 0x16: (['Potion Shop Area', 'Dark Witch Area'], 0x16, 0x0888, 0x0516, 0x0c4e, 0x0578, 0x0cc8, 0x0583, 0x0cd3, 0xfffa, 0xfff2, 0x0598, 0x0ccf), 0x17: (['Zora Approach Ledge', 'Catfish Approach Ledge'], 0x17, 0x039e, 0x047e, 0x0ef2, 0x04e0, 0x0f68, 0x04eb, 0x0f6f, 0x0000, 0xfffe, 0x04e0, 0x0f68), - 0x18: (['Kakariko Area', 'Village of Outcasts Area'], 0x18, 0x0b30, 0x0759, 0x017e, 0x07b7, 0x0200, 0x07c6, 0x020b, 0x0007, 0x0002, 0x07c0, 0x0210, 0x07c8, 0x01f8), + 0x18: (['Kakariko Village', 'Village of Outcasts'], 0x18, 0x0b30, 0x0759, 0x017e, 0x07b7, 0x0200, 0x07c6, 0x020b, 0x0007, 0x0002, 0x07c0, 0x0210, 0x07c8, 0x01f8), 0x1a: (['Forgotten Forest Area', 'Shield Shop Fence'], 0x1a, 0x081a, 0x070f, 0x04d2, 0x0770, 0x0548, 0x077c, 0x054f, 0xffff, 0xfffe, 0x0770, 0x0548), 0x1b: (['Hyrule Castle Courtyard', 'Pyramid Area'], 0x1b, 0x0c30, 0x077a, 0x0786, 0x07d8, 0x07f8, 0x07e7, 0x0803, 0x0006, 0xfffa, 0x07d8, 0x07f8), 0x1d: (['Wooden Bridge Area', 'Broken Bridge Northeast'], 0x1d, 0x0602, 0x06c2, 0x0a0e, 0x0720, 0x0a80, 0x072f, 0x0a8b, 0xfffe, 0x0002, 0x0720, 0x0a80), @@ -2158,13 +2161,13 @@ flute_data = { 0x2c: (['Links House Area', 'Big Bomb Shop Area'], 0x2c, 0x0588, 0x0ab9, 0x0840, 0x0b17, 0x08b8, 0x0b26, 0x08bf, 0xfff7, 0x0000, 0x0b20, 0x08b8), 0x2d: (['Stone Bridge South Area', 'Hammer Bridge South Area'], 0x2d, 0x0886, 0x0b1e, 0x0a2a, 0x0ba0, 0x0aa8, 0x0b8b, 0x0aaf, 0x0000, 0x0006, 0x0bc4, 0x0ad0), 0x2e: (['Tree Line Area', 'Dark Tree Line Area'], 0x2e, 0x0100, 0x0a1a, 0x0c00, 0x0a78, 0x0c30, 0x0a87, 0x0c7d, 0x0006, 0x0000, 0x0a78, 0x0c58), - 0x2f: (['Eastern Nook Area', 'Palace of Darkness Nook Area'], 0x2f, 0x0798, 0x0afa, 0x0eb2, 0x0b58, 0x0f30, 0x0b67, 0x0f37, 0xfff6, 0x000e, 0x0b50, 0x0f30), - 0x38: (['Desert Palace Teleporter Ledge', 'Misery Mire Teleporter Ledge'], 0x30, 0x1880, 0x0f1e, 0x0000, 0x0fa8, 0x0078, 0x0f8d, 0x008d, 0x0000, 0x0000, 0x0fb0, 0x0070), + 0x2f: (['Eastern Nook Area', 'Darkness Nook Area'], 0x2f, 0x0798, 0x0afa, 0x0eb2, 0x0b58, 0x0f30, 0x0b67, 0x0f37, 0xfff6, 0x000e, 0x0b50, 0x0f30), + 0x38: (['Desert Teleporter Ledge', 'Mire Teleporter Ledge'], 0x30, 0x1880, 0x0f1e, 0x0000, 0x0fa8, 0x0078, 0x0f8d, 0x008d, 0x0000, 0x0000, 0x0fb0, 0x0070), 0x32: (['Flute Boy Approach Area', 'Stumpy Approach Area'], 0x32, 0x03a0, 0x0c6c, 0x0500, 0x0cd0, 0x05a8, 0x0cdb, 0x0585, 0x0002, 0x0000, 0x0cd6, 0x0568), 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), + #0x35: (['Lake Hylia Northwest Bank', 'Ice Lake Northwest Bank'], 0x35, 0x0d00, 0x0da6, 0x0a06, 0x0e08, 0x0a80, 0x0e13, 0x0a8b, 0xfffa, 0xfffa, 0x0d88, 0x0a88), + 0x3e: (['Lake Hylia South Shore', 'Ice Lake Southeast Ledge'], 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), diff --git a/Regions.py b/Regions.py index c1b34d9e..461f6db6 100644 --- a/Regions.py +++ b/Regions.py @@ -7,154 +7,165 @@ from PotShuffle import key_drop_data, vanilla_pots, choose_pots, PotSecretTable def create_regions(world, player): world.regions += [ create_menu_region(player, 'Menu', None, ['Links House S&Q', 'Sanctuary S&Q', 'Old Man S&Q', 'Other World S&Q']), - create_menu_region(player, 'Flute Sky', None, ['Flute Spot 1', 'Flute Spot 2', 'Flute Spot 3', 'Flute Spot 4', 'Flute Spot 5', 'Flute Spot 6', 'Flute Spot 7', 'Flute Spot 8']), - + create_menu_region(player, 'Flute Sky', None, ['Flute Spot 1', 'Flute Spot 2', 'Flute Spot 3', 'Flute Spot 4', + 'Flute Spot 5', 'Flute Spot 6', 'Flute Spot 7', 'Flute Spot 8']), + create_lw_region(player, 'Master Sword Meadow', ['Master Sword Pedestal'], ['Master Sword Meadow SC']), create_lw_region(player, 'Lost Woods West Area', None, ['Lost Woods Bush (West)', 'Lost Woods NW', 'Lost Woods SW', 'Lost Woods SC']), - create_lw_region(player, 'Lost Woods East Area', ['Mushroom'], ['Lost Woods Bush (East)', 'Lost Woods Gamble', 'Lost Woods Hideout Drop', 'Lost Woods Hideout Stump', 'Lost Woods SE', 'Lost Woods EN']), + create_lw_region(player, 'Lost Woods East Area', ['Mushroom'], ['Lost Woods Gamble', 'Lost Woods Hideout Drop', 'Lost Woods Hideout Stump', 'Lost Woods Bush (East)', 'Lost Woods SE', 'Lost Woods EN']), create_lw_region(player, 'Lumberjack Area', None, ['Lumberjack Tree Tree', 'Lumberjack Tree Cave', 'Lumberjack House', 'Lumberjack WN', 'Lumberjack SW']), - create_lw_region(player, 'West Death Mountain (Top)', ['Ether Tablet'], ['Spectacle Rock Approach', 'West Death Mountain Drop', 'Tower of Hera', 'West Death Mountain EN']), - create_lw_region(player, 'Spectacle Rock Ledge', ['Spectacle Rock'], ['Spectacle Rock Leave', 'Spectacle Rock Drop']), - create_lw_region(player, 'West Death Mountain (Bottom)', ['Old Man Drop Off'], ['Old Man Drop Off', 'Old Man Cave (East)', 'Old Man House (Bottom)', 'Old Man House (Top)', 'Death Mountain Return Cave (East)', 'Spectacle Rock Cave', 'Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Bottom)', 'West Death Mountain Teleporter', 'West Death Mountain ES']), + create_lw_region(player, 'West Death Mountain (Top)', ['Ether Tablet'], ['Tower of Hera', 'Spectacle Rock Approach', 'West Death Mountain Drop', 'West Death Mountain EN']), + create_lw_region(player, 'Spectacle Rock Ledge', ['Spectacle Rock'], ['Spectacle Rock Leave', 'Spectacle Rock Ledge Drop']), + create_lw_region(player, 'West Death Mountain (Bottom)', ['Old Man Drop Off'], ['Old Man Cave (East)', 'Old Man House (Bottom)', 'Old Man House (Top)', + 'Death Mountain Return Cave (East)', 'Spectacle Rock Cave', 'Spectacle Rock Cave Peak', 'Spectacle Rock Cave (Bottom)', + 'Old Man Drop Off', 'West Death Mountain Teleporter', 'West Death Mountain ES']), create_lw_region(player, 'Old Man Drop Off', ['Old Man'], None), create_lw_region(player, 'East Death Mountain (Top West)', None, ['DM Hammer Bridge (West)', 'East Death Mountain WN']), - create_lw_region(player, 'East Death Mountain (Top East)', None, ['DM Hammer Bridge (East)', 'Floating Island Bridge (East)', 'East Death Mountain Spiral Ledge Drop', 'East Death Mountain Fairy Ledge Drop', 'East Death Mountain Mimic Ledge Drop', 'Paradox Cave (Top)', 'East Death Mountain EN']), - create_lw_region(player, 'Spiral Cave Ledge', None, ['Spiral Ledge Drop', 'Spiral Mimic Bridge (West)', 'Spiral Cave']), - create_lw_region(player, 'Mimic Cave Ledge', None, ['Mimic Ledge Drop', 'Spiral Mimic Bridge (East)', 'Mimic Cave']), - create_lw_region(player, 'Spiral Mimic Ledge Extend', None, ['Spiral Ledge Approach', 'Mimic Ledge Approach', 'Spiral Mimic Ledge Drop']), - create_lw_region(player, 'Fairy Ascension Ledge', None, ['Fairy Ascension Ledge Drop', 'Fairy Ascension Cave (Top)']), - create_lw_region(player, 'Fairy Ascension Plateau', None, ['Fairy Ascension Rocks (North)', 'Fairy Ascension Plateau Ledge Drop', 'Fairy Ascension Cave (Bottom)']), - create_lw_region(player, 'East Death Mountain (Bottom Left)', None, ['DM Broken Bridge (West)', 'East Death Mountain WS']), - create_lw_region(player, 'East Death Mountain (Bottom)', None, ['DM Broken Bridge (East)', 'Paradox Cave (Bottom)', 'Paradox Cave (Middle)', 'Hookshot Fairy', 'Spiral Cave (Bottom)', 'Fairy Ascension Rocks (South)', 'East Death Mountain Teleporter']), + create_lw_region(player, 'East Death Mountain (Top East)', None, ['Paradox Cave (Top)', 'DM Hammer Bridge (East)', 'Floating Island Bridge (East)', + 'EDM To Spiral Ledge Drop', 'EDM To Fairy Ledge Drop', 'EDM To Mimic Ledge Drop', 'EDM Ledge Drop', 'East Death Mountain EN']), create_lw_region(player, 'Death Mountain Floating Island', ['Floating Island'], ['Floating Island Bridge (West)']), - create_lw_region(player, 'Death Mountain TR Pegs', None, ['TR Pegs Ledge Entry', 'Death Mountain TR Pegs WN']), + create_lw_region(player, 'Spiral Cave Ledge', None, ['Spiral Cave', 'Spiral Ledge Drop', 'Spiral Mimic Bridge (West)']), + create_lw_region(player, 'Mimic Cave Ledge', None, ['Mimic Cave', 'Mimic Ledge Drop', 'Spiral Mimic Bridge (East)']), + create_lw_region(player, 'Spiral Mimic Ledge Extend', None, ['Spiral Ledge Approach', 'Mimic Ledge Approach', 'Spiral Mimic Ledge Drop']), + create_lw_region(player, 'Fairy Ascension Ledge', None, ['Fairy Ascension Cave (Top)', 'Fairy Ascension Ledge Drop']), + create_lw_region(player, 'Fairy Ascension Plateau', None, ['Fairy Ascension Cave (Bottom)', 'Fairy Ascension Rocks (Inner)', 'Fairy Ascension Plateau Ledge Drop']), + create_lw_region(player, 'East Death Mountain (Bottom Left)', None, ['DM Broken Bridge (West)', 'East Death Mountain WS']), + create_lw_region(player, 'East Death Mountain (Bottom)', None, ['Spiral Cave (Bottom)', 'Hookshot Fairy', 'Paradox Cave (Bottom)', 'Paradox Cave (Middle)', + 'DM Broken Bridge (East)', 'Fairy Ascension Rocks (Outer)', 'East Death Mountain Teleporter']), + create_lw_region(player, 'Death Mountain TR Pegs Area', None, ['TR Pegs Ledge Entry', 'Death Mountain TR Pegs WN']), create_lw_region(player, 'Death Mountain TR Pegs Ledge', None, ['TR Pegs Ledge Leave', 'TR Pegs Ledge Drop', 'TR Pegs Teleporter']), - create_lw_region(player, 'Mountain Entry Area', None, ['Mountain Entry Entrance Rock (West)', 'Mountain Entry NW', 'Mountain Entry SE']), - create_lw_region(player, 'Mountain Entry Entrance', None, ['Mountain Entry Entrance Rock (East)', 'Mountain Entry Entrance Ledge Drop', 'Old Man Cave (West)']), - create_lw_region(player, 'Mountain Entry Ledge', None, ['Mountain Entry Ledge Drop', 'Death Mountain Return Cave (West)'], 'a ledge in the foothills'), + create_lw_region(player, 'Mountain Pass Area', None, ['Mountain Pass Rock (Outer)', 'Mountain Pass NW', 'Mountain Pass SE']), + create_lw_region(player, 'Mountain Pass Ledge', None, ['Death Mountain Return Cave (West)', 'Mountain Pass Ledge Drop'], 'a ledge in the foothills'), + create_lw_region(player, 'Mountain Pass Entry', None, ['Old Man Cave (West)', 'Mountain Pass Rock (Inner)', 'Mountain Pass Entry Ledge Drop']), create_lw_region(player, 'Zora Waterfall Area', None, ['Zora Waterfall Water Entry', 'Zora Waterfall SE', 'Zora Waterfall NE']), - create_lw_region(player, 'Zora Waterfall Water', None, ['Zora Waterfall Water Approach', 'Zora Waterfall Landing', 'Zora Whirlpool'], 'Light World', Terrain.Water), - create_lw_region(player, 'Zora Waterfall Entryway', None, ['Zora Waterfall Water Drop', 'Waterfall of Wishing']), + create_lw_region(player, 'Zora Waterfall Water', None, ['Zora Waterfall Approach', 'Zora Waterfall Landing', 'Zora Whirlpool'], 'Light World', Terrain.Water), + create_lw_region(player, 'Zora Waterfall Entryway', None, ['Waterfall of Wishing', 'Zora Waterfall Water Drop']), create_lw_region(player, 'Zoras Domain', ['King Zora', 'Zora\'s Ledge'], ['Zoras Domain SW']), create_lw_region(player, 'Lost Woods Pass West Area', None, ['Lost Woods Pass NW', 'Lost Woods Pass SW']), create_lw_region(player, 'Lost Woods Pass East Top Area', None, ['Lost Woods Pass Hammer (North)', 'Lost Woods Pass NE']), - create_lw_region(player, 'Lost Woods Pass Portal Area', None, ['Kakariko Teleporter', 'Lost Woods Pass Hammer (South)', 'Lost Woods Pass Rock (North)']), + create_lw_region(player, 'Lost Woods Pass Portal Area', None, ['Lost Woods Pass Hammer (South)', 'Lost Woods Pass Rock (North)', 'Kakariko Teleporter']), create_lw_region(player, 'Lost Woods Pass East Bottom Area', None, ['Lost Woods Pass Rock (South)', 'Lost Woods Pass SE']), create_lw_region(player, 'Kakariko Fortune Area', None, ['Fortune Teller (Light)', 'Kakariko Fortune NE', 'Kakariko Fortune EN', 'Kakariko Fortune ES', 'Kakariko Fortune SC']), - create_lw_region(player, 'Kakariko Pond Area', None, ['Kakariko Pond NE', 'Kakariko Pond WN', 'Kakariko Pond WS', 'Kakariko Pond SW', 'Kakariko Pond SE', 'Kakariko Pond EN', 'Kakariko Pond ES', 'Kakariko Pond Whirlpool']), + create_lw_region(player, 'Kakariko Pond Area', None, ['Kakariko Pond Whirlpool', 'Kakariko Pond NE', 'Kakariko Pond WN', 'Kakariko Pond WS', + 'Kakariko Pond SW', 'Kakariko Pond SE', 'Kakariko Pond EN', 'Kakariko Pond ES']), create_lw_region(player, 'Sanctuary Area', None, ['Sanctuary', 'Sanctuary WS', 'Sanctuary EC']), create_lw_region(player, 'Bonk Rock Ledge', None, ['Bonk Rock Cave', 'Bonk Rock Ledge Drop', 'Sanctuary WN']), - create_lw_region(player, 'Graveyard Area', None, ['Sanctuary Grave', 'Kings Grave Outer Rocks', 'Graveyard Ladder (Bottom)', 'Graveyard WC', 'Graveyard EC']), - create_lw_region(player, 'Graveyard Ledge', None, ['Graveyard Ledge Drop', 'Graveyard Ladder (Top)', 'Graveyard Cave']), - create_lw_region(player, 'Kings Grave Area', None, ['Kings Grave Inner Rocks', 'Kings Grave']), - create_lw_region(player, 'River Bend Area', None, ['North Fairy Cave Drop', 'River Bend Water Drop', 'North Fairy Cave', 'River Bend WC', 'River Bend SW']), + create_lw_region(player, 'Graveyard Area', None, ['Sanctuary Grave', 'Kings Grave Rocks (Outer)', 'Graveyard Ladder (Bottom)', 'Graveyard WC', 'Graveyard EC']), + create_lw_region(player, 'Graveyard Ledge', None, ['Graveyard Cave', 'Graveyard Ledge Drop', 'Graveyard Ladder (Top)']), + create_lw_region(player, 'Kings Grave Area', None, ['Kings Grave', 'Kings Grave Rocks (Inner)']), + create_lw_region(player, 'River Bend Area', None, ['North Fairy Cave Drop', 'North Fairy Cave', 'River Bend Water Drop', 'River Bend WC', 'River Bend SW']), create_lw_region(player, 'River Bend East Bank', None, ['River Bend East Water Drop', 'River Bend SE', 'River Bend EC', 'River Bend ES']), - create_lw_region(player, 'River Bend Water', None, ['River Bend West Pier', 'River Bend East Pier', 'River Bend EN', 'River Bend SC', 'River Bend Whirlpool'], 'Light World', Terrain.Water), - create_lw_region(player, 'Potion Shop Area', None, ['Potion Shop Water Drop', 'Potion Shop Rock (South)', 'Potion Shop', 'Potion Shop WC', 'Potion Shop WS']), + create_lw_region(player, 'River Bend Water', None, ['River Bend West Pier', 'River Bend East Pier', 'River Bend Whirlpool', 'River Bend EN', 'River Bend SC'], 'Light World', Terrain.Water), + create_lw_region(player, 'Potion Shop Area', None, ['Potion Shop', 'Potion Shop Water Drop', 'Potion Shop Rock (South)', 'Potion Shop WC', 'Potion Shop WS']), create_lw_region(player, 'Potion Shop Northeast', None, ['Potion Shop Northeast Water Drop', 'Potion Shop Rock (North)', 'Potion Shop EC']), create_lw_region(player, 'Potion Shop Water', None, ['Potion Shop WN', 'Potion Shop EN'], 'Light World', Terrain.Water), create_lw_region(player, 'Zora Approach Area', None, ['Zora Approach Rocks (West)', 'Zora Approach Bottom Ledge Drop', 'Zora Approach Water Drop', 'Zora Approach WC']), create_lw_region(player, 'Zora Approach Ledge', None, ['Zora Approach Rocks (East)', 'Zora Approach Ledge Drop', 'Zora Approach NE']), create_lw_region(player, 'Zora Approach Water', None, ['Zora Approach WN'], 'Light World', Terrain.Water), - create_lw_region(player, 'Kakariko Area', ['Bottle Merchant'], ['Kakariko Southwest Bush (North)', 'Kakariko Yard Bush (South)', 'Kakariko Well Drop', 'Kakariko Well Cave', 'Blinds Hideout', - 'Elder House (West)', 'Elder House (East)', 'Snitch Lady (West)', 'Snitch Lady (East)', 'Chicken House', 'Sick Kids House', - 'Kakariko Shop', 'Tavern (Front)', 'Tavern North', 'Kakariko NW', 'Kakariko NC', 'Kakariko NE', 'Kakariko ES', 'Kakariko SE']), - create_lw_region(player, 'Kakariko Southwest', None, ['Kakariko Southwest Bush (South)', 'Light World Bomb Hut']), - create_lw_region(player, 'Kakariko Grass Yard', None, ['Kakariko Yard Bush (North)', 'Bush Covered House']), + create_lw_region(player, 'Kakariko Village', ['Bottle Merchant'], ['Kakariko Well Drop', 'Kakariko Well Cave', 'Blinds Hideout', 'Elder House (West)', 'Elder House (East)', + 'Snitch Lady (West)', 'Snitch Lady (East)', 'Chicken House', 'Sick Kids House', 'Kakariko Shop', 'Tavern (Front)', 'Tavern North', + 'Kakariko Southwest Bush (North)', 'Kakariko Yard Bush (South)', 'Kakariko NW', 'Kakariko NC', 'Kakariko NE', 'Kakariko ES', 'Kakariko SE']), + create_lw_region(player, 'Kakariko Southwest', None, ['Light World Bomb Hut', 'Kakariko Southwest Bush (South)']), + create_lw_region(player, 'Kakariko Bush Yard', None, ['Bush Covered House', 'Kakariko Yard Bush (North)']), create_lw_region(player, 'Forgotten Forest Area', None, ['Forgotten Forest NW', 'Forgotten Forest NE', 'Forgotten Forest ES']), - create_lw_region(player, 'Hyrule Castle Area', None, ['Hyrule Castle Secret Entrance Drop', 'Hyrule Castle Main Gate (South)', 'Hyrule Castle Inner East Rock', 'Hyrule Castle Southwest Bush (North)', 'Castle Gate Teleporter', 'Hyrule Castle WN', 'Hyrule Castle SE']), + create_lw_region(player, 'Hyrule Castle Area', None, ['Hyrule Castle Secret Entrance Drop', 'Hyrule Castle East Rock (Inner)', 'Hyrule Castle Southwest Bush (North)', + 'Hyrule Castle Main Gate (South)', 'Castle Gate Teleporter', 'Hyrule Castle WN', 'Hyrule Castle SE']), create_lw_region(player, 'Hyrule Castle Southwest', None, ['Hyrule Castle Southwest Bush (South)', 'Hyrule Castle SW']), - create_lw_region(player, 'Hyrule Castle Courtyard', None, ['Hyrule Castle Courtyard Bush (South)', 'Hyrule Castle Main Gate (North)', 'Hyrule Castle Entrance (South)', 'Castle Gate Teleporter (Inner)']), - create_lw_region(player, 'Hyrule Castle Courtyard Northeast', None, ['Hyrule Castle Courtyard Bush (North)', 'Hyrule Castle Secret Entrance Stairs']), - create_lw_region(player, 'Hyrule Castle Ledge', None, ['Hyrule Castle Ledge Drop', 'Hyrule Castle Ledge Courtyard Drop', 'Inverted Pyramid Entrance', 'Hyrule Castle Entrance (West)', 'Agahnims Tower', 'Hyrule Castle Entrance (East)', 'Inverted Pyramid Hole'], 'the castle rampart'), - create_lw_region(player, 'Hyrule Castle East Entry', None, ['Hyrule Castle Outer East Rock', 'Hyrule Castle ES']), + create_lw_region(player, 'Hyrule Castle Courtyard', None, ['Hyrule Castle Entrance (South)', 'Hyrule Castle Courtyard Bush (South)', 'Hyrule Castle Main Gate (North)', 'Castle Gate Teleporter (Inner)']), + create_lw_region(player, 'Hyrule Castle Courtyard Northeast', None, ['Hyrule Castle Secret Entrance Stairs', 'Hyrule Castle Courtyard Bush (North)']), + create_lw_region(player, 'Hyrule Castle Ledge', None, ['Hyrule Castle Entrance (West)', 'Agahnims Tower', 'Hyrule Castle Entrance (East)', 'Inverted Pyramid Entrance', 'Inverted Pyramid Hole', + 'Hyrule Castle Ledge Courtyard Drop', 'Hyrule Castle Ledge Drop'], 'the castle rampart'), + create_lw_region(player, 'Hyrule Castle East Entry', None, ['Hyrule Castle East Rock (Outer)', 'Hyrule Castle ES']), create_lw_region(player, 'Hyrule Castle Water', None, [], 'Light World', Terrain.Water), create_lw_region(player, 'Wooden Bridge Area', None, ['Wooden Bridge Bush (South)', 'Wooden Bridge Water Drop', 'Wooden Bridge NW', 'Wooden Bridge SW']), create_lw_region(player, 'Wooden Bridge Northeast', None, ['Wooden Bridge Bush (North)', 'Wooden Bridge Northeast Water Drop', 'Wooden Bridge NE']), create_lw_region(player, 'Wooden Bridge Water', None, ['Wooden Bridge NC'], 'Light World', Terrain.Water), create_lw_region(player, 'Eastern Palace Area', None, ['Sahasrahlas Hut', 'Eastern Palace', 'Eastern Palace SW', 'Eastern Palace SE']), - create_lw_region(player, 'Eastern Cliff', None, ['Sand Dunes Ledge Drop', 'Stone Bridge East Ledge Drop', 'Tree Line Ledge Drop', 'Eastern Palace Ledge Drop']), - create_lw_region(player, 'Blacksmith Area', None, ['Blacksmiths Hut', 'Bat Cave Cave', 'Bat Cave Ledge Peg', 'Blacksmith WS']), - create_lw_region(player, 'Bat Cave Ledge', None, ['Bat Cave Ledge Peg (East)', 'Bat Cave Drop']), + create_lw_region(player, 'Eastern Cliff', None, ['Sand Dunes Cliff Ledge Drop', 'Stone Bridge East Cliff Ledge Drop', 'Tree Line Cliff Ledge Drop', 'Eastern Palace Cliff Ledge Drop']), + create_lw_region(player, 'Blacksmith Area', None, ['Blacksmiths Hut', 'Bat Cave Cave', 'Blacksmith Ledge Peg (West)', 'Blacksmith WS']), + create_lw_region(player, 'Blacksmith Ledge', None, ['Bat Cave Drop', 'Blacksmith Ledge Peg (East)']), create_lw_region(player, 'Sand Dunes Area', None, ['Sand Dunes NW', 'Sand Dunes WN', 'Sand Dunes SC']), create_lw_region(player, 'Maze Race Area', None, ['Maze Race ES']), create_lw_region(player, 'Maze Race Ledge', None, ['Two Brothers House (West)', 'Maze Race Game'], 'a race against time'), - create_lw_region(player, 'Maze Race Prize', ['Maze Race'], ['Maze Race Ledge Drop']), #this is a separate region to make OWG item get possible without allowing the Entrance access + create_lw_region(player, 'Maze Race Prize', ['Maze Race'], ['Maze Race Ledge Drop']), # this is a separate region to make OWG item get possible without allowing the Entrance access create_lw_region(player, 'Kakariko Suburb Area', None, ['Library', 'Two Brothers House (East)', 'Kakariko Gamble Game', 'Kakariko Suburb NE', 'Kakariko Suburb WS', 'Kakariko Suburb ES']), create_lw_region(player, 'Flute Boy Area', ['Flute Spot'], ['Flute Boy SC']), create_lw_region(player, 'Flute Boy Pass', None, ['Flute Boy WS', 'Flute Boy SW']), - create_lw_region(player, 'Central Bonk Rocks Area', None, ['Bonk Fairy (Light)', 'Central Bonk Rocks NW', 'Central Bonk Rocks SW', 'Central Bonk Rocks EN', 'Central Bonk Rocks EC', 'Central Bonk Rocks ES']), + create_lw_region(player, 'Central Bonk Rocks Area', None, ['Bonk Fairy (Light)', 'Central Bonk Rocks NW', 'Central Bonk Rocks SW', + 'Central Bonk Rocks EN', 'Central Bonk Rocks EC', 'Central Bonk Rocks ES']), create_lw_region(player, 'Links House Area', None, ['Links House', 'Links House NE', 'Links House WN', 'Links House WC', 'Links House WS', 'Links House SC', 'Links House ES']), - create_lw_region(player, 'Stone Bridge North Area', None, ['Stone Bridge Southbound', 'Stone Bridge NC', 'Stone Bridge EN']), - create_lw_region(player, 'Stone Bridge South Area', None, ['Stone Bridge Northbound', 'Stone Bridge WS', 'Stone Bridge SC']), + create_lw_region(player, 'Stone Bridge North Area', None, ['Stone Bridge (Southbound)', 'Stone Bridge NC', 'Stone Bridge EN']), + create_lw_region(player, 'Stone Bridge South Area', None, ['Stone Bridge (Northbound)', 'Stone Bridge WS', 'Stone Bridge SC']), create_lw_region(player, 'Stone Bridge Water', None, ['Stone Bridge WC', 'Stone Bridge EC'], 'Light World', Terrain.Water), create_lw_region(player, 'Hobo Bridge', ['Hobo'], ['Hobo EC'], 'Light World', Terrain.Water), - create_lw_region(player, 'Central Cliffs', None, ['Central Bonk Rocks Cliff Ledge Drop', 'Links House Cliff Ledge Drop', 'Stone Bridge Cliff Ledge Drop', 'Lake Hylia Area Cliff Ledge Drop', 'Lake Hylia Island FAWT Ledge Drop', 'Stone Bridge EC Cliff Water Drop', 'Tree Line WC Cliff Water Drop', 'C Whirlpool Outer Cliff Ledge Drop', 'C Whirlpool Cliff Ledge Drop', 'C Whirlpool Portal Cliff Ledge Drop', 'Statues Cliff Ledge Drop']), + create_lw_region(player, 'Central Cliffs', None, ['Central Bonk Rocks Cliff Ledge Drop', 'Links House Cliff Ledge Drop', 'Stone Bridge Cliff Ledge Drop', 'Lake Hylia Northwest Cliff Ledge Drop', 'Lake Hylia Island FAWT Ledge Drop', 'Stone Bridge EC Cliff Water Drop', 'Tree Line WC Cliff Water Drop', 'C Whirlpool Outer Cliff Ledge Drop', 'C Whirlpool Cliff Ledge Drop', 'C Whirlpool Portal Cliff Ledge Drop', 'Statues Cliff Ledge Drop']), create_lw_region(player, 'Tree Line Area', None, ['Lake Hylia Fairy', 'Tree Line WN', 'Tree Line NW', 'Tree Line SE']), create_lw_region(player, 'Tree Line Water', None, ['Tree Line WC', 'Tree Line SC'], 'Light World', Terrain.Water), create_lw_region(player, 'Eastern Nook Area', None, ['Long Fairy Cave', 'East Hyrule Teleporter', 'Eastern Nook NE']), - create_lw_region(player, 'Desert Area', None, ['Desert Palace Statue Move', 'Checkerboard Ledge Approach', 'Aginahs Cave', 'Desert ES']), - create_lw_region(player, 'Desert Ledge', ['Desert Ledge'], ['Desert Ledge Outer Rocks', 'Desert Ledge Drop', 'Desert Palace Entrance (West)'], 'the desert ledge'), - create_lw_region(player, 'Desert Palace Entrance (North) Spot', None, ['Desert Ledge Inner Rocks', 'Desert Palace Entrance (North)'], 'the desert ledge'), - create_lw_region(player, 'Desert Checkerboard Ledge', None, ['Checkerboard Ledge Leave', 'Checkerboard Ledge Drop', 'Checkerboard Cave']), - create_lw_region(player, 'Desert Palace Stairs', None, ['Desert Palace Entrance (South)'], 'a sandy vista'), - create_lw_region(player, 'Desert Palace Mouth', None, ['Desert Mouth Drop', 'Desert Palace Entrance (East)']), - create_lw_region(player, 'Desert Palace Teleporter Ledge', None, ['Desert Teleporter Drop', 'Desert Teleporter']), - create_lw_region(player, 'Desert Northeast Cliffs', None, ['Desert Boss Cliff Ledge Drop', 'Checkerboard Cliff Ledge Drop', 'Suburb Cliff Ledge Drop', 'Cave 45 Cliff Ledge Drop', 'Desert C Whirlpool Cliff Ledge Drop', 'Desert Pass Cliff Ledge Drop', 'Dam Cliff Ledge Drop']), + create_lw_region(player, 'Desert Area', None, ['Aginahs Cave', 'Desert Statue Move', 'Checkerboard Ledge Approach', 'Desert ES']), + create_lw_region(player, 'Desert Ledge', ['Desert Ledge'], ['Desert Palace Entrance (West)', 'Desert Ledge Rocks (Outer)', 'Desert Ledge Drop'], 'the desert ledge'), + create_lw_region(player, 'Desert Ledge Keep', None, ['Desert Palace Entrance (North)', 'Desert Ledge Rocks (Inner)'], 'the desert ledge'), + create_lw_region(player, 'Desert Checkerboard Ledge', None, ['Checkerboard Cave', 'Checkerboard Ledge Drop', 'Checkerboard Ledge Leave']), + create_lw_region(player, 'Desert Stairs', None, ['Desert Palace Entrance (South)']), + create_lw_region(player, 'Desert Mouth', None, ['Desert Palace Entrance (East)', 'Desert Mouth Drop'], 'a sandy vista'), + create_lw_region(player, 'Desert Teleporter Ledge', None, ['Desert Teleporter Drop', 'Desert Teleporter']), + create_lw_region(player, 'Desert Northern Cliffs', None, ['Checkerboard Cliff Ledge Drop', 'Suburb Cliff Ledge Drop', 'Cave 45 Cliff Ledge Drop', 'Desert C Whirlpool Cliff Ledge Drop', 'Desert Pass Cliff Ledge Drop', 'Dam Cliff Ledge Drop']), create_lw_region(player, 'Bombos Tablet Ledge', ['Bombos Tablet'], ['Bombos Tablet Drop', 'Desert EC']), - create_lw_region(player, 'Flute Boy Approach Area', None, ['Flute Boy Bush (South)', 'Cave 45 Inverted Approach', 'Flute Boy Approach NW', 'Flute Boy Approach EC']), + create_lw_region(player, 'Flute Boy Approach Area', None, ['Flute Boy Bush (South)', 'Cave 45 Approach', 'Flute Boy Approach NW', 'Flute Boy Approach EC']), create_lw_region(player, 'Flute Boy Bush Entry', None, ['Flute Boy Bush (North)', 'Flute Boy Approach NC']), - create_lw_region(player, 'Cave 45 Ledge', None, ['Cave 45 Inverted Leave', 'Cave 45 Ledge Drop', 'Cave 45']), - create_lw_region(player, 'C Whirlpool Area', None, ['C Whirlpool Rock (Bottom)', 'C Whirlpool Pegs (Right)', 'C Whirlpool Water Entry', 'C Whirlpool EN', 'C Whirlpool ES', 'C Whirlpool SC']), - create_lw_region(player, 'C Whirlpool Portal Area', None, ['C Whirlpool Pegs (Left)', 'South Hyrule Teleporter']), + create_lw_region(player, 'Cave 45 Ledge', None, ['Cave 45', 'Cave 45 Ledge Drop', 'Cave 45 Leave']), + create_lw_region(player, 'C Whirlpool Area', None, ['C Whirlpool Rock (Bottom)', 'C Whirlpool Pegs (Outer)', 'C Whirlpool Water Entry', 'C Whirlpool EN', 'C Whirlpool ES', 'C Whirlpool SC']), + create_lw_region(player, 'C Whirlpool Portal Area', None, ['C Whirlpool Pegs (Inner)', 'South Hyrule Teleporter']), create_lw_region(player, 'C Whirlpool Water', None, ['C Whirlpool Landing', 'C Whirlpool', 'C Whirlpool EC'], 'Light World', Terrain.Water), create_lw_region(player, 'C Whirlpool Outer Area', None, ['C Whirlpool Rock (Top)', 'C Whirlpool WC', 'C Whirlpool NW']), - create_lw_region(player, 'Statues Area', None, ['Statues Water Entry', 'Light Hype Fairy', 'Statues NC', 'Statues WN', 'Statues WS', 'Statues SC']), + create_lw_region(player, 'Statues Area', None, ['Light Hype Fairy', 'Statues Water Entry', 'Statues NC', 'Statues WN', 'Statues WS', 'Statues SC']), create_lw_region(player, 'Statues Water', None, ['Statues Landing', 'Statues WC'], 'Light World', Terrain.Water), - create_lw_region(player, 'Lake Hylia Area', None, ['Lake Hylia Water Drop', 'Lake Hylia Fortune Teller', 'Lake Hylia Shop', 'Lake Hylia NW']), - create_lw_region(player, 'Lake Hylia South Shore', None, ['Lake Hylia South Water Drop', 'Mini Moldorm Cave', 'Lake Hylia WS', 'Lake Hylia ES']), + create_lw_region(player, 'Lake Hylia Northwest Bank', None, ['Lake Hylia Fortune Teller', 'Lake Hylia Shop', 'Lake Hylia Water Drop', 'Lake Hylia NW']), create_lw_region(player, 'Lake Hylia Northeast Bank', None, ['Lake Hylia Northeast Water Drop', 'Lake Hylia NE']), - create_lw_region(player, 'Lake Hylia Central Island', None, ['Lake Hylia Central Water Drop', 'Capacity Upgrade', 'Lake Hylia Teleporter']), + create_lw_region(player, 'Lake Hylia South Shore', None, ['Mini Moldorm Cave', 'Lake Hylia South Water Drop', 'Lake Hylia WS', 'Lake Hylia ES']), + create_lw_region(player, 'Lake Hylia Central Island', None, ['Capacity Upgrade', 'Lake Hylia Central Water Drop', 'Lake Hylia Teleporter']), create_lw_region(player, 'Lake Hylia Island', ['Lake Hylia Island'], ['Lake Hylia Island Water Drop']), - create_lw_region(player, 'Lake Hylia Water', None, ['Lake Hylia Central Island Pier', 'Lake Hylia Island Pier', 'Lake Hylia West Pier', 'Lake Hylia East Pier', 'Lake Hylia Water D Approach', 'Lake Hylia NC', 'Lake Hylia EC', 'Lake Hylia Whirlpool'], 'Light World', Terrain.Water), - create_lw_region(player, 'Lake Hylia Water D', None, ['Lake Hylia Water D Leave'], 'Light World', Terrain.Water), - create_lw_region(player, 'Ice Cave Area', None, ['Ice Rod Cave', 'Good Bee Cave', '20 Rupee Cave', 'Ice Cave SE', 'Ice Cave SW']), - create_lw_region(player, 'Desert Pass Area', ['Middle Aged Man'], ['Desert Pass Ladder (South)', 'Middle Aged Man', 'Desert Fairy', '50 Rupee Cave', 'Desert Pass WS', 'Desert Pass EC', 'Desert Pass Rocks (North)']), + create_lw_region(player, 'Lake Hylia Water', None, ['Lake Hylia Central Island Pier', 'Lake Hylia Island Pier', 'Lake Hylia West Pier', 'Lake Hylia East Pier', + 'Lake Hylia Water D Approach', 'Lake Hylia Whirlpool', 'Lake Hylia NC', 'Lake Hylia EC'], 'Light World', Terrain.Water), + create_lw_region(player, 'Lake Hylia Water D', None, ['Lake Hylia Water D Leave']), + create_lw_region(player, 'Ice Cave Area', None, ['Ice Rod Cave', 'Good Bee Cave', '20 Rupee Cave', 'Ice Cave Water Drop', 'Ice Cave SE']), + create_lw_region(player, 'Ice Cave Water', None, ['Ice Cave Pier', 'Ice Cave SW'], 'Light World', Terrain.Water), + create_lw_region(player, 'Desert Pass Area', ['Middle Aged Man'], ['Desert Fairy', '50 Rupee Cave', 'Middle Aged Man', 'Desert Pass Ladder (South)', 'Desert Pass Rocks (North)', 'Desert Pass WS', 'Desert Pass EC']), create_lw_region(player, 'Middle Aged Man', ['Purple Chest'], None), create_lw_region(player, 'Desert Pass Southeast', None, ['Desert Pass Rocks (South)', 'Desert Pass ES']), create_lw_region(player, 'Desert Pass Ledge', None, ['Desert Pass Ladder (North)', 'Desert Pass Ledge Drop', 'Desert Pass WC']), create_lw_region(player, 'Dam Area', ['Sunken Treasure'], ['Dam', 'Dam WC', 'Dam WS', 'Dam NC', 'Dam EC']), create_lw_region(player, 'South Pass Area', None, ['South Pass WC', 'South Pass NC', 'South Pass ES']), create_lw_region(player, 'Octoballoon Area', None, ['Octoballoon Water Drop', 'Octoballoon WS', 'Octoballoon NE']), - create_lw_region(player, 'Octoballoon Water', None, ['Octoballoon Pier', 'Octoballoon WC', 'Octoballoon Whirlpool'], 'Light World', Terrain.Water), + create_lw_region(player, 'Octoballoon Water', None, ['Octoballoon Pier', 'Octoballoon Whirlpool', 'Octoballoon WC'], 'Light World', Terrain.Water), create_lw_region(player, 'Octoballoon Water Ledge', None, ['Octoballoon Waterfall Water Drop', 'Octoballoon NW'], 'Light World', Terrain.Water), - - create_dw_region(player, 'Skull Woods Forest', None, ['Skull Woods Bush Rock (East)', 'Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', - 'Skull Woods First Section Door', 'Skull Woods Second Section Door (East)', 'Skull Woods SE']), - create_dw_region(player, 'Skull Woods Portal Entry', None, ['Skull Woods Bush Rock (West)', 'Skull Woods SC']), + + create_dw_region(player, 'Skull Woods Forest', None, ['Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', + 'Skull Woods First Section Door', 'Skull Woods Second Section Door (East)', 'Skull Woods Rock (East)', 'Skull Woods SE']), + create_dw_region(player, 'Skull Woods Portal Entry', None, ['Skull Woods Rock (West)', 'Skull Woods SC']), create_dw_region(player, 'Skull Woods Forest (West)', None, ['Skull Woods Second Section Hole', 'Skull Woods Second Section Door (West)', 'Skull Woods Final Section'], 'a deep, dark forest'), create_dw_region(player, 'Skull Woods Forgotten Path (Southwest)', None, ['Skull Woods Forgotten Bush (West)', 'Skull Woods SW']), create_dw_region(player, 'Skull Woods Forgotten Path (Northeast)', None, ['Skull Woods Forgotten Bush (East)', 'Skull Woods EN']), create_dw_region(player, 'Dark Lumberjack Area', None, ['Dark Lumberjack Shop', 'Dark Lumberjack WN', 'Dark Lumberjack SW']), - create_dw_region(player, 'West Dark Death Mountain (Top)', None, ['Dark Death Mountain Drop (West)', 'GT Entry Approach', 'West Dark Death Mountain EN']), - create_dw_region(player, 'GT Approach', None, ['GT Entry Leave', 'Ganons Tower']), + create_dw_region(player, 'West Dark Death Mountain (Top)', None, ['GT Approach', 'West Dark Death Mountain Drop', 'West Dark Death Mountain EN']), + create_dw_region(player, 'GT Stairs', None, ['Ganons Tower', 'GT Leave']), create_dw_region(player, 'West Dark Death Mountain (Bottom)', None, ['Spike Cave', 'Dark Death Mountain Fairy', 'Dark Death Mountain Teleporter (West)', 'West Dark Death Mountain ES']), - create_dw_region(player, 'East Dark Death Mountain (Top)', None, ['Dark Death Mountain Drop (East)', 'Superbunny Cave (Top)', 'Hookshot Cave', 'East Dark Death Mountain WN', 'East Dark Death Mountain EN']), - create_dw_region(player, 'East Dark Death Mountain (Bottom)', None, ['East Dark Death Mountain Bushes', 'Superbunny Cave (Bottom)', 'Dark Death Mountain Shop', 'Dark Death Mountain Teleporter (East)']), + create_dw_region(player, 'East Dark Death Mountain (Top)', None, ['Superbunny Cave (Top)', 'Hookshot Cave', 'East Dark Death Mountain Drop', 'East Dark Death Mountain WN', 'East Dark Death Mountain EN']), + create_dw_region(player, 'Dark Death Mountain Floating Island', None, ['Hookshot Cave Back Entrance', 'Floating Island Drop'], 'a dark floating island'), + create_dw_region(player, 'Dark Death Mountain Ledge', None, ['Dark Death Mountain Ledge (West)', 'Dark Death Mountain Ledge (East)'], 'a dark ledge'), + create_dw_region(player, 'Dark Death Mountain Isolated Ledge', None, ['Turtle Rock Isolated Ledge Entrance'], 'a dark vista'), + create_dw_region(player, 'East Dark Death Mountain (Bottom)', None, ['Superbunny Cave (Bottom)', 'Dark Death Mountain Shop', 'East Dark Death Mountain Bushes', 'East Dark Death Mountain Teleporter']), create_dw_region(player, 'East Dark Death Mountain (Bushes)', None, []), create_dw_region(player, 'East Dark Death Mountain (Bottom Left)', None, ['East Dark Death Mountain WS']), - create_dw_region(player, 'Dark Death Mountain Ledge', None, ['Dark Death Mountain Ledge (East)', 'Dark Death Mountain Ledge (West)'], 'a dark ledge'), - create_dw_region(player, 'Dark Death Mountain Isolated Ledge', None, ['Turtle Rock Isolated Ledge Entrance'], 'a dark vista'), - create_dw_region(player, 'Dark Death Mountain Floating Island', None, ['Floating Island Drop', 'Hookshot Cave Back Entrance'], 'a dark floating island'), - create_dw_region(player, 'Turtle Rock Area', None, ['Turtle Rock Tail Ledge Drop', 'Turtle Rock', 'Turtle Rock WN']), + create_dw_region(player, 'Turtle Rock Area', None, ['Turtle Rock', 'Turtle Rock Tail Ledge Drop', 'Turtle Rock WN']), create_dw_region(player, 'Turtle Rock Ledge', ['Turtle Medallion Pad'], ['Turtle Rock Ledge Drop', 'Turtle Rock Teleporter']), - create_dw_region(player, 'Bumper Cave Area', None, ['Bumper Cave Entrance Rock', 'Bumper Cave NW', 'Bumper Cave SE']), - create_dw_region(player, 'Bumper Cave Entrance', None, ['Bumper Cave Ledge Drop', 'Bumper Cave (Bottom)']), - create_dw_region(player, 'Bumper Cave Ledge', ['Bumper Cave Ledge'], ['Bumper Cave Entrance Drop', 'Bumper Cave (Top)'], 'a ledge with an item'), + create_dw_region(player, 'Bumper Cave Area', None, ['Bumper Cave Rock (Outer)', 'Bumper Cave NW', 'Bumper Cave SE']), + create_dw_region(player, 'Bumper Cave Ledge', ['Bumper Cave Ledge'], ['Bumper Cave (Top)', 'Bumper Cave Ledge Drop'], 'a ledge with an item'), + create_dw_region(player, 'Bumper Cave Entry', None, ['Bumper Cave (Bottom)', 'Bumper Cave Rock (Inner)', 'Bumper Cave Entry Drop']), create_dw_region(player, 'Catfish Area', ['Catfish'], ['Catfish SE']), create_dw_region(player, 'Skull Woods Pass West Area', None, ['Skull Woods Pass Bush Row (West)', 'Skull Woods Pass NW', 'Skull Woods Pass SW']), create_dw_region(player, 'Skull Woods Pass East Top Area', None, ['Skull Woods Pass Bush Row (East)', 'Skull Woods Pass Bush (North)', 'Skull Woods Pass NE']), - create_dw_region(player, 'Skull Woods Pass Portal Area', None, ['West Dark World Teleporter', 'Skull Woods Pass Bush (South)', 'Skull Woods Pass Rock (North)']), + create_dw_region(player, 'Skull Woods Pass Portal Area', None, ['Skull Woods Pass Bush (South)', 'Skull Woods Pass Rock (North)', 'West Dark World Teleporter']), create_dw_region(player, 'Skull Woods Pass East Bottom Area', None, ['Skull Woods Pass Rock (South)', 'Skull Woods Pass SE']), create_dw_region(player, 'Dark Fortune Area', None, ['Fortune Teller (Dark)', 'Dark Fortune NE', 'Dark Fortune EN', 'Dark Fortune ES', 'Dark Fortune SC']), create_dw_region(player, 'Outcast Pond Area', None, ['Outcast Pond NE', 'Outcast Pond WN', 'Outcast Pond WS', 'Outcast Pond SW', 'Outcast Pond SE', 'Outcast Pond EN', 'Outcast Pond ES']), @@ -164,35 +175,36 @@ def create_regions(world, player): create_dw_region(player, 'Qirn Jump Area', None, ['Qirn Jump Water Drop', 'Qirn Jump WC', 'Qirn Jump SW']), create_dw_region(player, 'Qirn Jump East Bank', None, ['Qirn Jump East Water Drop', 'Qirn Jump SE', 'Qirn Jump EC', 'Qirn Jump ES']), create_dw_region(player, 'Qirn Jump Water', None, ['Qirn Jump Pier', 'Qirn Jump Whirlpool', 'Qirn Jump EN', 'Qirn Jump SC'], 'Dark World', Terrain.Water), - create_dw_region(player, 'Dark Witch Area', None, ['Dark Witch Water Drop', 'Dark Witch Rock (South)', 'Dark Potion Shop', 'Dark Witch WC', 'Dark Witch WS']), + create_dw_region(player, 'Dark Witch Area', None, ['Dark Potion Shop', 'Dark Witch Water Drop', 'Dark Witch Rock (South)', 'Dark Witch WC', 'Dark Witch WS']), create_dw_region(player, 'Dark Witch Northeast', None, ['Dark Witch Northeast Water Drop', 'Dark Witch Rock (North)', 'Dark Witch EC']), create_dw_region(player, 'Dark Witch Water', None, ['Dark Witch WN', 'Dark Witch EN'], 'Dark World', Terrain.Water), create_dw_region(player, 'Catfish Approach Area', None, ['Catfish Approach Rocks (West)', 'Catfish Approach Bottom Ledge Drop', 'Catfish Approach Water Drop', 'Catfish Approach WC']), create_dw_region(player, 'Catfish Approach Ledge', None, ['Catfish Approach Rocks (East)', 'Catfish Approach Ledge Drop', 'Catfish Approach NE']), create_dw_region(player, 'Catfish Approach Water', None, ['Catfish Approach WN'], 'Dark World', Terrain.Water), - create_dw_region(player, 'Village of Outcasts Area', None, ['Village of Outcasts Pegs', 'Chest Game', 'Thieves Town', 'C-Shaped House', 'Brewery', 'Village of Outcasts NW', 'Village of Outcasts NC', 'Village of Outcasts NE', 'Village of Outcasts ES', 'Village of Outcasts SE']), - create_dw_region(player, 'Dark Grassy Lawn', None, ['Grassy Lawn Pegs', 'Dark World Shop']), - create_dw_region(player, 'Shield Shop Area', None, ['Shield Shop Fence (Outer) Ledge Drop', 'Shield Shop NW', 'Shield Shop NE']), - create_dw_region(player, 'Shield Shop Fence', None, ['Shield Shop Fence (Inner) Ledge Drop', 'Red Shield Shop']), - create_dw_region(player, 'Pyramid Area', ['Pyramid Crack', 'Pyramid'], ['Pyramid Crack', 'Pyramid Hole', 'Pyramid ES']), + create_dw_region(player, 'Village of Outcasts', None, ['Chest Game', 'Thieves Town', 'C-Shaped House', 'Brewery', 'Bush Yard Pegs (Outer)', + 'Village of Outcasts NW', 'Village of Outcasts NC', 'Village of Outcasts NE', 'Village of Outcasts ES', 'Village of Outcasts SE']), + create_dw_region(player, 'Village of Outcasts Bush Yard', None, ['Dark World Shop', 'Bush Yard Pegs (Inner)']), + create_dw_region(player, 'Shield Shop Area', None, ['Shield Shop Fence Drop (Outer)', 'Shield Shop NW', 'Shield Shop NE']), + create_dw_region(player, 'Shield Shop Fence', None, ['Red Shield Shop', 'Shield Shop Fence Drop (Inner)']), + create_dw_region(player, 'Pyramid Area', ['Pyramid Crack', 'Pyramid'], ['Pyramid Hole', 'Pyramid Crack', 'Pyramid ES']), create_dw_region(player, 'Pyramid Crack', None, ['Pyramid Fairy']), - create_dw_region(player, 'Pyramid Exit Ledge', None, ['Pyramid Exit Ledge Drop', 'Pyramid Entrance']), - create_dw_region(player, 'Pyramid Pass', None, ['Post Aga Inverted Teleporter', 'Pyramid SW', 'Pyramid SE']), + create_dw_region(player, 'Pyramid Exit Ledge', None, ['Pyramid Entrance', 'Pyramid Exit Ledge Drop']), + create_dw_region(player, 'Pyramid Pass', None, ['Post Aga Teleporter', 'Pyramid SW', 'Pyramid SE']), create_dw_region(player, 'Pyramid Water', None, [], 'Dark World', Terrain.Water), create_dw_region(player, 'Broken Bridge Area', None, ['Broken Bridge Hammer Rock (South)', 'Broken Bridge Water Drop', 'Broken Bridge SW']), create_dw_region(player, 'Broken Bridge Northeast', None, ['Broken Bridge Hammer Rock (North)', 'Broken Bridge Hookshot Gap', 'Broken Bridge Northeast Water Drop', 'Broken Bridge NE']), create_dw_region(player, 'Broken Bridge West', None, ['Broken Bridge West Water Drop', 'Broken Bridge NW']), create_dw_region(player, 'Broken Bridge Water', None, ['Broken Bridge NC'], 'Dark World', Terrain.Water), create_dw_region(player, 'Palace of Darkness Area', None, ['Palace of Darkness Hint', 'Palace of Darkness', 'Palace of Darkness SW', 'Palace of Darkness SE']), - create_dw_region(player, 'Darkness Cliff', None, ['Dark Dunes Ledge Drop', 'Hammer Bridge North Ledge Drop', 'Dark Tree Line Ledge Drop', 'Palace of Darkness Ledge Drop']), + create_dw_region(player, 'Darkness Cliff', None, ['Dark Dunes Cliff Ledge Drop', 'Hammer Bridge North Cliff Ledge Drop', 'Dark Tree Line Cliff Ledge Drop', 'Palace of Darkness Cliff Ledge Drop']), + create_dw_region(player, 'Hammer Pegs Area', ['Dark Blacksmith Ruins'], ['Hammer Peg Cave', 'Peg Area Rocks (East)']), create_dw_region(player, 'Hammer Pegs Entry', None, ['Peg Area Rocks (West)', 'Hammer Pegs WS']), - create_dw_region(player, 'Hammer Pegs Area', ['Dark Blacksmith Ruins'], ['Peg Area Rocks (East)', 'Hammer Peg Cave']), create_dw_region(player, 'Dark Dunes Area', None, ['Dark Dunes NW', 'Dark Dunes WN', 'Dark Dunes SC']), create_dw_region(player, 'Dig Game Area', ['Digging Game'], ['Dig Game To Ledge Drop', 'Dig Game ES']), create_dw_region(player, 'Dig Game Ledge', None, ['Dig Game Ledge Drop', 'Dig Game EC']), create_dw_region(player, 'Frog Area', None, ['Frog Ledge Drop', 'Frog Rock (Outer)', 'Archery Game Rock (North)', 'Frog NE']), create_dw_region(player, 'Frog Prison', ['Frog'], ['Frog Rock (Inner)']), - create_dw_region(player, 'Archery Game Area', None, ['Archery Game Rock (South)', 'Archery Game', 'Frog WC', 'Frog WS', 'Frog ES']), + create_dw_region(player, 'Archery Game Area', None, ['Archery Game', 'Archery Game Rock (South)', 'Frog WC', 'Frog WS', 'Frog ES']), create_dw_region(player, 'Stumpy Area', ['Stumpy'], ['Stumpy SC']), create_dw_region(player, 'Stumpy Pass', None, ['Stumpy WS', 'Stumpy SW']), create_dw_region(player, 'Dark Bonk Rocks Area', None, ['Bonk Fairy (Dark)', 'Dark Bonk Rocks NW', 'Dark Bonk Rocks SW', 'Dark Bonk Rocks EN', 'Dark Bonk Rocks EC', 'Dark Bonk Rocks ES']), @@ -200,30 +212,32 @@ def create_regions(world, player): create_dw_region(player, 'Hammer Bridge North Area', None, ['Hammer Bridge Pegs (North)', 'Hammer Bridge Water Drop', 'Hammer Bridge NC', 'Hammer Bridge EN']), create_dw_region(player, 'Hammer Bridge South Area', None, ['Hammer Bridge Pegs (South)', 'Hammer Bridge WS', 'Hammer Bridge SC']), create_dw_region(player, 'Hammer Bridge Water', None, ['Hammer Bridge Pier', 'Hammer Bridge EC'], 'Dark World', Terrain.Water), - create_dw_region(player, 'Dark Central Cliffs', None, ['Dark Bonk Rocks Cliff Ledge Drop', 'Bomb Shop Cliff Ledge Drop', 'Hammer Bridge South Cliff Ledge Drop', 'Ice Lake Area Cliff Ledge Drop', 'Ice Palace Island FAWT Ledge Drop', - 'Hammer Bridge EC Cliff Water Drop', 'Dark Tree Line WC Cliff Water Drop', 'Dark C Whirlpool Outer Cliff Ledge Drop', 'Dark C Whirlpool Cliff Ledge Drop', 'Dark C Whirlpool Portal Cliff Ledge Drop', 'Hype Cliff Ledge Drop']), + create_dw_region(player, 'Dark Central Cliffs', None, ['Dark Bonk Rocks Cliff Ledge Drop', 'Bomb Shop Cliff Ledge Drop', 'Hammer Bridge South Cliff Ledge Drop', 'Ice Lake Northwest Cliff Ledge Drop', 'Ice Palace Island FAWT Ledge Drop', + 'Hammer Bridge EC Cliff Water Drop', 'Dark Tree Line WC Cliff Water Drop', 'Dark C Whirlpool Outer Cliff Ledge Drop', 'Dark C Whirlpool Cliff Ledge Drop', 'Dark C Whirlpool Portal Cliff Ledge Drop', 'Hype Cliff Ledge Drop']), create_dw_region(player, 'Dark Tree Line Area', None, ['Dark Lake Hylia Fairy', 'Dark Tree Line WN', 'Dark Tree Line NW', 'Dark Tree Line SE']), create_dw_region(player, 'Dark Tree Line Water', None, ['Dark Tree Line WC', 'Dark Tree Line SC'], 'Dark World', Terrain.Water), - create_dw_region(player, 'Palace of Darkness Nook Area', None, ['East Dark World Hint', 'East Dark World Teleporter', 'Palace of Darkness Nook NE']), - create_dw_region(player, 'Misery Mire Area', None, ['Mire Shed', 'Misery Mire', 'Mire Fairy', 'Mire Hint']), - create_dw_region(player, 'Misery Mire Teleporter Ledge', None, ['Misery Mire Teleporter Ledge Drop', 'Misery Mire Teleporter']), - create_dw_region(player, 'Mire Northeast Cliffs', None, ['Mire Cliff Ledge Drop', 'Dark Checkerboard Cliff Ledge Drop', 'Archery Game Cliff Ledge Drop', 'Stumpy Approach Cliff Ledge Drop', 'Mire C Whirlpool Cliff Ledge Drop', 'Swamp Nook Cliff Ledge Drop', 'Swamp Cliff Ledge Drop', 'Mirror To Bombos Tablet Ledge']), + create_dw_region(player, 'Darkness Nook Area', None, ['East Dark World Hint', 'East Dark World Teleporter', 'Palace of Darkness Nook NE']), + create_dw_region(player, 'Mire Area', None, ['Mire Shed', 'Misery Mire', 'Mire Fairy', 'Mire Hint']), + create_dw_region(player, 'Mire Teleporter Ledge', None, ['Mire Teleporter Ledge Drop', 'Mire Teleporter']), + create_dw_region(player, 'Mire Northern Cliffs', None, ['Mire Cliff Ledge Drop', 'Dark Checkerboard Cliff Ledge Drop', 'Archery Game Cliff Ledge Drop', 'Stumpy Approach Cliff Ledge Drop', 'Mire C Whirlpool Cliff Ledge Drop', 'Swamp Nook Cliff Ledge Drop', 'Swamp Cliff Ledge Drop', 'Mirror To Bombos Tablet Ledge']), create_dw_region(player, 'Stumpy Approach Area', None, ['Stumpy Approach Bush (South)', 'Stumpy Approach NW', 'Stumpy Approach EC']), create_dw_region(player, 'Stumpy Approach Bush Entry', None, ['Stumpy Approach Bush (North)', 'Stumpy Approach NC']), - create_dw_region(player, 'Dark C Whirlpool Area', None, ['Dark C Whirlpool Rock (Bottom)', 'Dark C Whirlpool Pegs (Right)', 'Dark C Whirlpool Water Entry', 'Dark C Whirlpool EN', 'Dark C Whirlpool ES', 'Dark C Whirlpool SC']), - create_dw_region(player, 'Dark C Whirlpool Portal Area', None, ['Dark C Whirlpool Pegs (Left)', 'South Dark World Teleporter']), + create_dw_region(player, 'Dark C Whirlpool Area', None, ['Dark C Whirlpool Rock (Bottom)', 'Dark C Whirlpool Pegs (Outer)', 'Dark C Whirlpool Water Entry', + 'Dark C Whirlpool EN', 'Dark C Whirlpool ES', 'Dark C Whirlpool SC']), + create_dw_region(player, 'Dark C Whirlpool Portal Area', None, ['Dark C Whirlpool Pegs (Inner)', 'South Dark World Teleporter']), create_dw_region(player, 'Dark C Whirlpool Water', None, ['Dark C Whirlpool Landing', 'Dark C Whirlpool EC'], 'Dark World', Terrain.Water), create_dw_region(player, 'Dark C Whirlpool Outer Area', None, ['Dark C Whirlpool Rock (Top)', 'Dark C Whirlpool WC', 'Dark C Whirlpool NW']), - create_dw_region(player, 'Hype Cave Area', None, ['Hype Cave Water Entry', 'Hype Cave', 'Hype Cave NC', 'Hype Cave WN', 'Hype Cave WS', 'Hype Cave SC']), + create_dw_region(player, 'Hype Cave Area', None, ['Hype Cave', 'Hype Cave Water Entry', 'Hype Cave NC', 'Hype Cave WN', 'Hype Cave WS', 'Hype Cave SC']), create_dw_region(player, 'Hype Cave Water', None, ['Hype Cave Landing', 'Hype Cave WC'], 'Dark World', Terrain.Water), - create_dw_region(player, 'Ice Lake Area', None, ['Ice Lake Water Drop', 'Dark Lake Hylia Shop', 'Ice Lake NW']), - create_dw_region(player, 'Ice Lake Northeast Bank', None, ['Ice Lake Northeast Water Drop', 'Ice Lake NE']), - create_dw_region(player, 'Ice Lake Ledge (West)', None, ['Ice Lake Southwest Water Drop', 'Ice Lake WS']), - create_dw_region(player, 'Ice Lake Ledge (East)', None, ['Ice Lake Southeast Water Drop', 'Ice Lake ES']), - create_dw_region(player, 'Ice Lake Water', None, ['Ice Lake Northeast Pier', 'Ice Lake Moat Bomb Jump', 'Ice Lake NC', 'Ice Lake EC'], 'Dark World', Terrain.Water), - create_dw_region(player, 'Ice Lake Moat', None, ['Ice Palace Teleporter', 'Ice Lake Moat Water Entry', 'Ice Lake Northeast Pier Hop']), + create_dw_region(player, 'Ice Lake Northwest Bank', None, ['Dark Lake Hylia Shop', 'Ice Lake Water Drop', 'Ice Lake NW']), + create_dw_region(player, 'Ice Lake Northeast Bank', None, ['Ice Lake Northeast Water Drop', 'Ice Lake Iceberg Bomb Jump', 'Ice Lake NE']), + create_dw_region(player, 'Ice Lake Southwest Ledge', None, ['Ice Lake Southwest Water Drop', 'Ice Lake WS']), + create_dw_region(player, 'Ice Lake Southeast Ledge', None, ['Ice Lake Southeast Water Drop', 'Ice Lake ES']), + create_dw_region(player, 'Ice Lake Water', None, ['Ice Lake Northeast Pier', 'Ice Lake NC', 'Ice Lake EC'], 'Dark World', Terrain.Water), + create_dw_region(player, 'Ice Lake Iceberg', None, ['Ice Lake Iceberg Water Entry', 'Ice Lake Northeast Pier Hop', 'Ice Lake Teleporter']), create_dw_region(player, 'Ice Palace Area', None, ['Ice Palace']), - create_dw_region(player, 'Shopping Mall Area', None, ['Dark Lake Hylia Ledge Fairy', 'Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Ledge Spike Cave', 'Shopping Mall SW', 'Shopping Mall SE']), + create_dw_region(player, 'Shopping Mall Area', None, ['Dark Lake Hylia Ledge Fairy', 'Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Ledge Spike Cave', 'Shopping Mall Water Drop', 'Shopping Mall SE']), + create_dw_region(player, 'Shopping Mall Water', None, ['Shopping Mall Pier', 'Shopping Mall SW'], 'Dark World', Terrain.Water), create_dw_region(player, 'Swamp Nook Area', None, ['Swamp Nook EC', 'Swamp Nook ES']), create_dw_region(player, 'Swamp Area', None, ['Swamp Palace', 'Swamp WC', 'Swamp WS', 'Swamp NC', 'Swamp EC']), create_dw_region(player, 'Dark South Pass Area', None, ['Dark South Pass WC', 'Dark South Pass NC', 'Dark South Pass ES']), @@ -1096,42 +1110,31 @@ def _create_region(player, name, type, hint='Hyrule', locations=None, exits=None def mark_light_dark_world_regions(world, player): # cross world caves may have some sections marked as both in_light_world, and in_dark_work. # That is ok. the bunny logic will check for this case and incorporate special rules. - def mark_light(): - queue = collections.deque(region for region in world.get_regions(player) if region.type == RegionType.LightWorld) - seen = set(queue) - while queue: - current = queue.popleft() - current.is_light_world = True - for exit in current.exits: - if exit.connected_region is None or exit.connected_region.type == RegionType.DarkWorld: # todo: remove none check - # Don't venture into the dark world - continue - if exit.connected_region not in seen: - seen.add(exit.connected_region) - queue.append(exit.connected_region) + queue = collections.deque(region for region in world.get_regions(player) if region.type == RegionType.LightWorld) + seen = set(queue) + while queue: + current = queue.popleft() + current.is_light_world = True + for exit in current.exits: + if exit.connected_region is None or exit.connected_region.type == RegionType.DarkWorld: + # Don't venture into the dark world + continue + if exit.connected_region not in seen: + seen.add(exit.connected_region) + queue.append(exit.connected_region) - def mark_dark(): - queue = collections.deque(region for region in world.get_regions(player) if region.type == RegionType.DarkWorld) - seen = set(queue) - while queue: - current = queue.popleft() - current.is_dark_world = True - for exit in current.exits: - if exit.connected_region is not None: - if exit.connected_region.type == RegionType.LightWorld: - # Don't venture into the light world - continue - if exit.connected_region not in seen: - seen.add(exit.connected_region) - queue.append(exit.connected_region) - - # Note: I don't see why the order would matter, but the original Inverted code reversed the order - if world.mode[player] != 'inverted': - mark_light() - mark_dark() - else: - mark_dark() - mark_light() + queue = collections.deque(region for region in world.get_regions(player) if region.type == RegionType.DarkWorld) + seen = set(queue) + while queue: + current = queue.popleft() + current.is_dark_world = True + for exit in current.exits: + if exit.connected_region is None or exit.connected_region.type == RegionType.LightWorld: + # Don't venture into the light world + continue + if exit.connected_region not in seen: + seen.add(exit.connected_region) + queue.append(exit.connected_region) def create_shops(world, player): @@ -1269,8 +1272,8 @@ def pot_address(pot_index, super_tile): bonk_prize_table = { 'Lost Woods Hideout Tree': (0x00, 0x10, False, '', 'Lost Woods East Area', 'in a tree'), 'Death Mountain Bonk Rocks': (0x01, 0x10, False, '', 'East Death Mountain (Top East)', 'encased in stone'), - 'Mountain Entry Pull Tree': (0x02, 0x10, False, '', 'Mountain Entry Area', 'in a tree'), - 'Mountain Entry Southeast Tree': (0x03, 0x08, False, '', 'Mountain Entry Area', 'in a tree'), + 'Mountain Pass Pull Tree': (0x02, 0x10, False, '', 'Mountain Pass Area', 'in a tree'), + 'Mountain Pass Southeast Tree': (0x03, 0x08, False, '', 'Mountain Pass Area', 'in a tree'), 'Lost Woods Pass West Tree': (0x04, 0x10, False, '', 'Lost Woods Pass West Area', 'in a tree'), 'Kakariko Portal Tree': (0x05, 0x08, False, '', 'Lost Woods Pass East Top Area', 'in a tree'), 'Fortune Bonk Rocks': (0x06, 0x10, False, '', 'Kakariko Fortune Area', 'encased in stone'), @@ -1279,8 +1282,8 @@ bonk_prize_table = { 'Sanctuary Tree': (0x09, 0x08, False, '', 'Sanctuary Area', 'in a tree'), 'River Bend West Tree': (0x0a, 0x10, True, '', 'River Bend Area', 'in a tree'), 'River Bend East Tree': (0x0b, 0x08, False, '', 'River Bend East Bank', 'in a tree'), - 'Blinds Hideout Tree': (0x0c, 0x10, False, '', 'Kakariko Area', 'in a tree'), - 'Kakariko Welcome Tree': (0x0d, 0x08, False, '', 'Kakariko Area', 'in a tree'), + 'Blinds Hideout Tree': (0x0c, 0x10, False, '', 'Kakariko Village', 'in a tree'), + 'Kakariko Welcome Tree': (0x0d, 0x08, False, '', 'Kakariko Village', 'in a tree'), 'Forgotten Forest Southwest Tree': (0x0e, 0x10, False, '', 'Forgotten Forest Area', 'in a tree'), 'Forgotten Forest Central Tree': (0x0f, 0x08, False, '', 'Forgotten Forest Area', 'in a tree'), #'Forgotten Forest Southeast Tree': (0x10, 0x04, False, '', 'Forgotten Forest Area', 'in a tree'), @@ -1383,6 +1386,8 @@ flooded_keys_reverse = { 'Swamp Palace - Trench 1 Pot Key': 'Trench 1 Switch', 'Swamp Palace - Trench 2 Pot Key': 'Trench 2 Switch' } + + location_table = {'Mushroom': (0x180013, 0x186338, False, 'in the woods'), 'Bottle Merchant': (0x2eb18, 0x186339, False, 'with a merchant'), 'Flute Spot': (0x18014a, 0x18633d, False, 'underground'), diff --git a/Rules.py b/Rules.py index c09a0721..2cd92599 100644 --- a/Rules.py +++ b/Rules.py @@ -25,7 +25,7 @@ def set_rules(world, player): if world.swords[player] == 'swordless': swordless_rules(world, player) - + ow_bunny_rules(world, player) ow_terrain_rules(world, player) @@ -72,7 +72,7 @@ def set_rules(world, player): if not world.is_tile_swapped(0x18, player): if not world.is_copied_world: # Commented out below, this would be needed for rando implementations where Inverted requires flute activation in bunny territory - # kak_region = self.world.get_region('Kakariko Area', player) + # kak_region = self.world.get_region('Kakariko Village', player) # add_rule(world.get_location('Flute Activation', player), lambda state: state.has('Ocarina', player) and state.is_not_bunny(kak_region, player)) add_rule(world.get_location('Flute Activation', player), lambda state: state.has('Ocarina', player)) @@ -134,6 +134,7 @@ def set_defeat_dungeon_boss_rule(location): # Lambda required to defer evaluation of dungeon.boss since it will change later if boos shuffle is used set_rule(location, lambda state: location.parent_region.dungeon.boss.can_defeat(state)) + def set_always_allow(spot, rule): spot.always_allow = rule @@ -207,21 +208,21 @@ def global_rules(world, player): set_rule(world.get_entrance('Flute Spot 6', player), lambda state: state.can_flute(player)) set_rule(world.get_entrance('Flute Spot 7', player), lambda state: state.can_flute(player)) set_rule(world.get_entrance('Flute Spot 8', player), lambda state: state.can_flute(player)) - + # overworld location rules + set_rule(world.get_location('Master Sword Pedestal', player), lambda state: state.has('Red Pendant', player) and state.has('Blue Pendant', player) and state.has('Green Pendant', player)) set_rule(world.get_location('Ether Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player)) set_rule(world.get_location('Old Man', player), lambda state: state.has('Return Old Man', player)) set_rule(world.get_location('Old Man Drop Off', player), lambda state: state.has('Escort Old Man', player)) - set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player)) + set_rule(world.get_location('Turtle Medallion Pad', player), lambda state: state.has_sword(player) and state.has_turtle_rock_medallion(player)) # sword required to cast magic (!) + set_rule(world.get_location('Zora\'s Ledge', player), lambda state: state.has('Flippers', player)) set_rule(world.get_location('Flute Spot', player), lambda state: state.has('Shovel', player)) + set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player)) set_rule(world.get_location('Middle Aged Man', player), lambda state: state.has('Pick Up Purple Chest', player)) # Can S&Q with chest set_rule(world.get_location('Purple Chest', player), lambda state: state.has('Deliver Purple Chest', player)) # Can S&Q with chest set_rule(world.get_location('Sunken Treasure', player), lambda state: state.has('Open Floodgate', player)) - set_rule(world.get_location('Turtle Medallion Pad', player), lambda state: state.has_sword(player) and state.has_turtle_rock_medallion(player)) # sword required to cast magic (!) set_rule(world.get_location('Dark Blacksmith Ruins', player), lambda state: state.has('Return Smith', player)) set_rule(world.get_location('Big Bomb', player), lambda state: state.has('Crystal 5', player) and state.has('Crystal 6', player)) - set_rule(world.get_location('Master Sword Pedestal', player), lambda state: state.has('Red Pendant', player) and state.has('Blue Pendant', player) and state.has('Green Pendant', player)) - set_rule(world.get_location('Zora\'s Ledge', player), lambda state: state.has('Flippers', player)) # bonk items if world.shuffle_bonk_drops[player]: @@ -253,7 +254,7 @@ def global_rules(world, player): (state.can_extend_magic(player, 12, True) or (state.world.can_take_damage and (state.has_Boots(player) or state.has_hearts(player, 4)))))) ) - + # underworld rules set_rule(world.get_entrance('Paradox Cave Push Block Reverse', player), lambda state: state.has_Mirror(player)) # can erase block - overridden in noglitches set_rule(world.get_entrance('Hookshot Cave Bonk Path', player), lambda state: state.has('Hookshot', player) or state.has('Pegasus Boots', player)) @@ -266,51 +267,70 @@ def global_rules(world, player): set_rule(world.get_entrance('DM Hammer Bridge (East)', player), lambda state: state.has('Hammer', player)) set_rule(world.get_entrance('DM Broken Bridge (West)', player), lambda state: state.has('Hookshot', player)) set_rule(world.get_entrance('DM Broken Bridge (East)', player), lambda state: state.has('Hookshot', player)) - set_rule(world.get_entrance('Fairy Ascension Rocks (North)', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Fairy Ascension Rocks (South)', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Fairy Ascension Rocks (Inner)', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Fairy Ascension Rocks (Outer)', player), lambda state: state.can_lift_heavy_rocks(player)) set_rule(world.get_entrance('TR Pegs Ledge Entry', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Mountain Entry Entrance Rock (West)', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Mountain Entry Entrance Rock (East)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Mountain Pass Rock (Outer)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Mountain Pass Rock (Inner)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Zora Waterfall Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Zora Waterfall Water Entry', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Zora Waterfall Approach', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Lost Woods Pass Hammer (North)', player), lambda state: state.has('Hammer', player)) set_rule(world.get_entrance('Lost Woods Pass Hammer (South)', player), lambda state: state.has('Hammer', player)) set_rule(world.get_entrance('Lost Woods Pass Rock (North)', player), lambda state: state.can_lift_heavy_rocks(player)) set_rule(world.get_entrance('Lost Woods Pass Rock (South)', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Kings Grave Outer Rocks', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Kings Grave Inner Rocks', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('Potion Shop Rock (South)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Kakariko Pond Whirlpool', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Kings Grave Rocks (Outer)', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Kings Grave Rocks (Inner)', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('River Bend Water Drop', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Potion Shop Rock (North)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Potion Shop Rock (South)', player), lambda state: state.can_lift_rocks(player)) set_rule(world.get_entrance('Zora Approach Rocks (West)', player), lambda state: state.can_lift_heavy_rocks(player) or state.has_Boots(player)) set_rule(world.get_entrance('Zora Approach Rocks (East)', player), lambda state: state.can_lift_heavy_rocks(player) or state.has_Boots(player)) - set_rule(world.get_entrance('Hyrule Castle Inner East Rock', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Hyrule Castle Outer East Rock', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Bat Cave Ledge Peg', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Bat Cave Ledge Peg (East)', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Desert Palace Statue Move', player), lambda state: state.has('Book of Mudora', player)) - set_rule(world.get_entrance('Desert Ledge Outer Rocks', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Desert Ledge Inner Rocks', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Hyrule Castle East Rock (Inner)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Hyrule Castle East Rock (Outer)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Wooden Bridge Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Wooden Bridge Northeast Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Blacksmith Ledge Peg (West)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Blacksmith Ledge Peg (East)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Desert Statue Move', player), lambda state: state.has('Book of Mudora', player)) + set_rule(world.get_entrance('Desert Ledge Rocks (Outer)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Desert Ledge Rocks (Inner)', player), lambda state: state.can_lift_rocks(player)) set_rule(world.get_entrance('C Whirlpool Rock (Bottom)', player), lambda state: state.can_lift_rocks(player)) set_rule(world.get_entrance('C Whirlpool Rock (Top)', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('C Whirlpool Pegs (Left)', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('C Whirlpool Pegs (Right)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('C Whirlpool Pegs (Outer)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('C Whirlpool Pegs (Inner)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Lake Hylia Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Lake Hylia Northeast Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Lake Hylia Central Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Lake Hylia Island Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Lake Hylia Water D Leave', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Ice Cave Water Drop', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Desert Pass Rocks (North)', player), lambda state: state.can_lift_rocks(player)) set_rule(world.get_entrance('Desert Pass Rocks (South)', player), lambda state: state.can_lift_rocks(player)) - - set_rule(world.get_entrance('Skull Woods Bush Rock (West)', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Skull Woods Bush Rock (East)', player), lambda state: state.can_lift_rocks(player)) - # this more like an ohko rule - dependent on bird being present too - so enemizer could turn this off? + set_rule(world.get_entrance('Octoballoon Waterfall Water Drop', player), lambda state: state.has('Flippers', player)) + + set_rule(world.get_entrance('Skull Woods Rock (West)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Skull Woods Rock (East)', player), lambda state: state.can_lift_rocks(player)) + # this more like an ohko rule - dependent on bird being present too - so enemizer could turn this off? set_rule(world.get_entrance('Bumper Cave Ledge Drop', player), lambda state: (state.has('Cape', player) or state.has('Cane of Byrna', player) or state.has_sword(player))) - set_rule(world.get_entrance('Bumper Cave Entrance Rock', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Bumper Cave Rock (Outer)', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Bumper Cave Rock (Inner)', player), lambda state: state.can_lift_rocks(player)) set_rule(world.get_entrance('Skull Woods Pass Rock (North)', player), lambda state: state.can_lift_heavy_rocks(player)) set_rule(world.get_entrance('Skull Woods Pass Rock (South)', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Qirn Jump Water Drop', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Dark Witch Rock (North)', player), lambda state: state.can_lift_rocks(player)) set_rule(world.get_entrance('Dark Witch Rock (South)', player), lambda state: state.can_lift_rocks(player)) set_rule(world.get_entrance('Catfish Approach Rocks (West)', player), lambda state: state.can_lift_heavy_rocks(player) or state.has_Boots(player)) set_rule(world.get_entrance('Catfish Approach Rocks (East)', player), lambda state: state.can_lift_heavy_rocks(player) or state.has_Boots(player)) - set_rule(world.get_entrance('Village of Outcasts Pegs', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Grassy Lawn Pegs', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Bush Yard Pegs (Outer)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Bush Yard Pegs (Inner)', player), lambda state: state.has('Hammer', player)) set_rule(world.get_entrance('Broken Bridge Hammer Rock (South)', player), lambda state: state.can_lift_rocks(player) or state.has('Hammer', player)) set_rule(world.get_entrance('Broken Bridge Hammer Rock (North)', player), lambda state: state.can_lift_rocks(player) or state.has('Hammer', player)) set_rule(world.get_entrance('Broken Bridge Hookshot Gap', player), lambda state: state.has('Hookshot', player)) + set_rule(world.get_entrance('Broken Bridge Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Broken Bridge Northeast Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Broken Bridge West Water Drop', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Peg Area Rocks (West)', player), lambda state: state.can_lift_heavy_rocks(player)) set_rule(world.get_entrance('Peg Area Rocks (East)', player), lambda state: state.can_lift_heavy_rocks(player)) set_rule(world.get_entrance('Dig Game To Ledge Drop', player), lambda state: state.can_lift_heavy_rocks(player)) @@ -320,10 +340,18 @@ def global_rules(world, player): set_rule(world.get_entrance('Archery Game Rock (South)', player), lambda state: state.can_lift_heavy_rocks(player)) set_rule(world.get_entrance('Hammer Bridge Pegs (North)', player), lambda state: state.has('Hammer', player)) set_rule(world.get_entrance('Hammer Bridge Pegs (South)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Hammer Bridge Water Drop', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Dark C Whirlpool Rock (Bottom)', player), lambda state: state.can_lift_rocks(player)) set_rule(world.get_entrance('Dark C Whirlpool Rock (Top)', player), lambda state: state.can_lift_rocks(player)) - set_rule(world.get_entrance('Dark C Whirlpool Pegs (Left)', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('Dark C Whirlpool Pegs (Right)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Dark C Whirlpool Pegs (Outer)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Dark C Whirlpool Pegs (Inner)', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('Ice Lake Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Ice Lake Northeast Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Ice Lake Southwest Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Ice Lake Iceberg Water Entry', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Ice Lake Iceberg Bomb Jump', player), lambda state: state.can_use_bombs(player)) + set_rule(world.get_entrance('Shopping Mall Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Bomber Corner Waterfall Water Drop', player), lambda state: state.has('Flippers', player)) # entrance rules # Caution: If king's grave is relaxed at all to account for reaching it via a two way cave's exit in insanity mode, then the bomb shop logic will need to be updated (that would involve create a small ledge-like Region for it) @@ -808,10 +836,10 @@ def bomb_rules(world, player): bombable_items = ['Chicken House', 'Aginah\'s Cave', 'Graveyard Cave', 'Hype Cave - Top', 'Hype Cave - Middle Right', 'Hype Cave - Middle Left', 'Hype Cave - Bottom'] for location in bonkable_items: - add_rule(world.get_location(location, player), lambda state: state.can_use_bombs(player) or state.has_Boots(player)) + add_rule(world.get_location(location, player), lambda state: state.can_use_bombs(player) or state.has_Boots(player)) add_bunny_rule(world.get_location(location, player), player) for location in bombable_items: - add_rule(world.get_location(location, player), lambda state: state.can_use_bombs(player)) + add_rule(world.get_location(location, player), lambda state: state.can_use_bombs(player)) add_bunny_rule(world.get_location(location, player), player) cave_kill_locations = ['Mini Moldorm Cave - Far Left', 'Mini Moldorm Cave - Far Right', 'Mini Moldorm Cave - Left', 'Mini Moldorm Cave - Right', 'Mini Moldorm Cave - Generous Guy', 'Spiral Cave'] @@ -882,7 +910,7 @@ def bomb_rules(world, player): if world.doorShuffle[player] == 'vanilla': add_rule(world.get_entrance('TR Lazy Eyes SE', player), lambda state: state.can_use_bombs(player)) # ToDo: Add always true for inverted, cross-entrance, and door-variants and so on. add_rule(world.get_entrance('Turtle Rock Ledge Exit (West)', player), lambda state: state.can_use_bombs(player)) # Is this the same as above? - + dungeon_bonkable = ['Sewers Rat Path WS', 'Sewers Rat Path WN', 'PoD Warp Hint SE', 'PoD Jelly Hall NW', 'PoD Jelly Hall NE', 'PoD Mimics 1 SW', 'Thieves Ambush E', 'Thieves Rail Ledge W', @@ -960,8 +988,8 @@ def ow_inverted_rules(world, player): set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has_crystals(world.crystals_needed_for_gt[player], player)) else: set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has('Cape', player) or state.has_beam_sword(player)) # barrier gets removed after killing agahnim, rule for that added later - set_rule(world.get_entrance('GT Entry Approach', player), lambda state: state.has_crystals(world.crystals_needed_for_gt[player], player)) - set_rule(world.get_entrance('GT Entry Leave', player), lambda state: state.has_crystals(world.crystals_needed_for_gt[player], player) or state.world.shuffle[player] in ('restricted', 'full', 'lite', 'lean', 'crossed', 'insanity')) + set_rule(world.get_entrance('GT Approach', player), lambda state: state.has_crystals(world.crystals_needed_for_gt[player], player)) + set_rule(world.get_entrance('GT Leave', player), lambda state: state.has_crystals(world.crystals_needed_for_gt[player], player) or state.world.shuffle[player] in ('restricted', 'full', 'lite', 'lean', 'crossed', 'insanity')) if world.is_tile_swapped(0x03, player): set_rule(world.get_entrance('Spectacle Rock Approach', player), lambda state: world.logic[player] in ['noglitches', 'minorglitches'] and state.has_Pearl(player)) @@ -970,15 +998,14 @@ def ow_inverted_rules(world, player): if not world.is_tile_swapped(0x05, player): set_rule(world.get_entrance('East Death Mountain Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) else: - set_rule(world.get_entrance('Dark Death Mountain Teleporter (East)', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('East Dark Death Mountain Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) if not world.is_tile_swapped(0x07, player): set_rule(world.get_entrance('TR Pegs Teleporter', player), lambda state: state.has('Hammer', player)) set_rule(world.get_entrance('TR Pegs Ledge Leave', player), lambda state: state.can_lift_heavy_rocks(player)) else: set_rule(world.get_entrance('Turtle Rock Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) - set_rule(world.get_entrance('TR Pegs Ledge Drop', player), lambda state: False) - set_rule(world.get_entrance('TR Pegs Ledge Leave', player), lambda state: state.has('Hammer', player) and state.can_lift_heavy_rocks(player) and state.has_Pearl(player)) + set_rule(world.get_entrance('TR Pegs Ledge Leave', player), lambda state: state.has('Hammer', player) and state.can_lift_heavy_rocks(player)) set_rule(world.get_entrance('Turtle Rock Tail Ledge Drop', player), lambda state: world.logic[player] in ['noglitches', 'minorglitches']) if not world.is_tile_swapped(0x10, player): @@ -1000,7 +1027,7 @@ def ow_inverted_rules(world, player): set_rule(world.get_entrance('Pyramid Hole', player), lambda state: False) set_rule(world.get_entrance('Pyramid Entrance', player), lambda state: False) - set_rule(world.get_entrance('Post Aga Inverted Teleporter', player), lambda state: state.has_beaten_aga(player)) + set_rule(world.get_entrance('Post Aga Teleporter', player), lambda state: state.has_beaten_aga(player)) if not world.is_tile_swapped(0x2f, player): set_rule(world.get_entrance('East Hyrule Teleporter', player), lambda state: state.has('Hammer', player) and state.can_lift_rocks(player) and state.has_Pearl(player)) # bunny cannot use hammer @@ -1011,13 +1038,13 @@ def ow_inverted_rules(world, player): set_rule(world.get_entrance('Mirror To Bombos Tablet Ledge', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Desert Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) else: - set_rule(world.get_entrance('Misery Mire Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Mire Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) set_rule(world.get_entrance('Checkerboard Ledge Approach', player), lambda state: world.logic[player] in ['noglitches', 'minorglitches']) set_rule(world.get_entrance('Checkerboard Ledge Leave', player), lambda state: world.logic[player] in ['noglitches', 'minorglitches']) if world.is_tile_swapped(0x32, player): - set_rule(world.get_entrance('Cave 45 Inverted Approach', player), lambda state: world.logic[player] in ['noglitches', 'minorglitches']) - set_rule(world.get_entrance('Cave 45 Inverted Leave', player), lambda state: world.logic[player] in ['noglitches', 'minorglitches']) + set_rule(world.get_entrance('Cave 45 Approach', player), lambda state: world.logic[player] in ['noglitches', 'minorglitches']) + set_rule(world.get_entrance('Cave 45 Leave', player), lambda state: world.logic[player] in ['noglitches', 'minorglitches']) if not world.is_tile_swapped(0x33, player): set_rule(world.get_entrance('South Hyrule Teleporter', player), lambda state: state.can_lift_rocks(player)) @@ -1027,7 +1054,7 @@ def ow_inverted_rules(world, player): if not world.is_tile_swapped(0x35, player): set_rule(world.get_entrance('Lake Hylia Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) else: - set_rule(world.get_entrance('Ice Palace Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) + set_rule(world.get_entrance('Ice Lake Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) set_rule(world.get_entrance('Lake Hylia Island Pier', player), lambda state: world.logic[player] in ['noglitches', 'minorglitches']) if world.is_tile_swapped(0x3a, player): @@ -1038,10 +1065,10 @@ def ow_inverted_rules(world, player): def ow_bunny_rules(world, player): # locations add_bunny_rule(world.get_location('Mushroom', player), player) + add_bunny_rule(world.get_location('Turtle Medallion Pad', player), player) add_bunny_rule(world.get_location('Zora\'s Ledge', player), player) add_bunny_rule(world.get_location('Maze Race', player), player) add_bunny_rule(world.get_location('Flute Spot', player), player) - add_bunny_rule(world.get_location('Turtle Medallion Pad', player), player) add_bunny_rule(world.get_location('Catfish', player), player) # entrances @@ -1068,7 +1095,7 @@ def ow_bunny_rules(world, player): add_bunny_rule(world.get_entrance('Bonk Fairy (Dark)', player), player) add_bunny_rule(world.get_entrance('Misery Mire', player), player) add_bunny_rule(world.get_entrance('Dark Lake Hylia Ledge Spike Cave', player), player) - + # terrain add_bunny_rule(world.get_entrance('Lost Woods Bush (West)', player), player) add_bunny_rule(world.get_entrance('Lost Woods Bush (East)', player), player) @@ -1076,19 +1103,31 @@ def ow_bunny_rules(world, player): add_bunny_rule(world.get_entrance('DM Hammer Bridge (East)', player), player) add_bunny_rule(world.get_entrance('DM Broken Bridge (West)', player), player) add_bunny_rule(world.get_entrance('DM Broken Bridge (East)', player), player) - add_bunny_rule(world.get_entrance('Fairy Ascension Rocks (North)', player), player) - add_bunny_rule(world.get_entrance('Fairy Ascension Rocks (South)', player), player) + add_bunny_rule(world.get_entrance('Fairy Ascension Rocks (Inner)', player), player) + add_bunny_rule(world.get_entrance('Fairy Ascension Rocks (Outer)', player), player) add_bunny_rule(world.get_entrance('TR Pegs Ledge Entry', player), player) - add_bunny_rule(world.get_entrance('Mountain Entry Entrance Rock (West)', player), player) - add_bunny_rule(world.get_entrance('Mountain Entry Entrance Rock (East)', player), player) + add_bunny_rule(world.get_entrance('TR Pegs Ledge Leave', player), player) + add_bunny_rule(world.get_entrance('Mountain Pass Rock (Outer)', player), player) + add_bunny_rule(world.get_entrance('Mountain Pass Rock (Inner)', player), player) + add_bunny_rule(world.get_entrance('Zora Waterfall Water Drop', player), player) + add_bunny_rule(world.get_entrance('Zora Waterfall Water Entry', player), player) + add_bunny_rule(world.get_entrance('Zora Waterfall Approach', player), player) add_bunny_rule(world.get_entrance('Lost Woods Pass Hammer (North)', player), player) add_bunny_rule(world.get_entrance('Lost Woods Pass Hammer (South)', player), player) add_bunny_rule(world.get_entrance('Lost Woods Pass Rock (North)', player), player) add_bunny_rule(world.get_entrance('Lost Woods Pass Rock (South)', player), player) - add_bunny_rule(world.get_entrance('Kings Grave Outer Rocks', player), player) - add_bunny_rule(world.get_entrance('Kings Grave Inner Rocks', player), player) - add_bunny_rule(world.get_entrance('Potion Shop Rock (South)', player), player) + add_bunny_rule(world.get_entrance('Kakariko Pond Whirlpool', player), player) + add_bunny_rule(world.get_entrance('Kings Grave Rocks (Outer)', player), player) + add_bunny_rule(world.get_entrance('Kings Grave Rocks (Inner)', player), player) + add_bunny_rule(world.get_entrance('Graveyard Ladder (Top)', player), player) + add_bunny_rule(world.get_entrance('Graveyard Ladder (Bottom)', player), player) + add_bunny_rule(world.get_entrance('River Bend Water Drop', player), player) + add_bunny_rule(world.get_entrance('River Bend East Water Drop', player), player) + add_bunny_rule(world.get_entrance('Potion Shop Water Drop', player), player) + add_bunny_rule(world.get_entrance('Potion Shop Northeast Water Drop', player), player) add_bunny_rule(world.get_entrance('Potion Shop Rock (North)', player), player) + add_bunny_rule(world.get_entrance('Potion Shop Rock (South)', player), player) + add_bunny_rule(world.get_entrance('Zora Approach Water Drop', player), player) add_bunny_rule(world.get_entrance('Zora Approach Rocks (West)', player), player) add_bunny_rule(world.get_entrance('Zora Approach Rocks (East)', player), player) add_bunny_rule(world.get_entrance('Kakariko Southwest Bush (North)', player), player) @@ -1099,31 +1138,46 @@ def ow_bunny_rules(world, player): add_bunny_rule(world.get_entrance('Hyrule Castle Southwest Bush (South)', player), player) add_bunny_rule(world.get_entrance('Hyrule Castle Courtyard Bush (North)', player), player) add_bunny_rule(world.get_entrance('Hyrule Castle Courtyard Bush (South)', player), player) - add_bunny_rule(world.get_entrance('Hyrule Castle Inner East Rock', player), player) - add_bunny_rule(world.get_entrance('Hyrule Castle Outer East Rock', player), player) + add_bunny_rule(world.get_entrance('Hyrule Castle East Rock (Inner)', player), player) + add_bunny_rule(world.get_entrance('Hyrule Castle East Rock (Outer)', player), player) add_bunny_rule(world.get_entrance('Wooden Bridge Bush (North)', player), player) add_bunny_rule(world.get_entrance('Wooden Bridge Bush (South)', player), player) - add_bunny_rule(world.get_entrance('Bat Cave Ledge Peg', player), player) - add_bunny_rule(world.get_entrance('Bat Cave Ledge Peg (East)', player), player) - add_bunny_rule(world.get_entrance('Desert Ledge Outer Rocks', player), player) - add_bunny_rule(world.get_entrance('Desert Ledge Inner Rocks', player), player) + add_bunny_rule(world.get_entrance('Wooden Bridge Water Drop', player), player) + add_bunny_rule(world.get_entrance('Wooden Bridge Northeast Water Drop', player), player) + add_bunny_rule(world.get_entrance('Blacksmith Ledge Peg (West)', player), player) + add_bunny_rule(world.get_entrance('Blacksmith Ledge Peg (East)', player), player) + add_bunny_rule(world.get_entrance('Maze Race Game', player), player) + add_bunny_rule(world.get_entrance('Desert Ledge Rocks (Outer)', player), player) + add_bunny_rule(world.get_entrance('Desert Ledge Rocks (Inner)', player), player) add_bunny_rule(world.get_entrance('Flute Boy Bush (North)', player), player) add_bunny_rule(world.get_entrance('Flute Boy Bush (South)', player), player) + add_bunny_rule(world.get_entrance('C Whirlpool Water Entry', player), player) add_bunny_rule(world.get_entrance('C Whirlpool Rock (Bottom)', player), player) add_bunny_rule(world.get_entrance('C Whirlpool Rock (Top)', player), player) - add_bunny_rule(world.get_entrance('C Whirlpool Pegs (Left)', player), player) - add_bunny_rule(world.get_entrance('C Whirlpool Pegs (Right)', player), player) + add_bunny_rule(world.get_entrance('C Whirlpool Pegs (Outer)', player), player) + add_bunny_rule(world.get_entrance('C Whirlpool Pegs (Inner)', player), player) + add_bunny_rule(world.get_entrance('Statues Water Entry', player), player) + add_bunny_rule(world.get_entrance('Lake Hylia Water Drop', player), player) + add_bunny_rule(world.get_entrance('Lake Hylia South Water Drop', player), player) + add_bunny_rule(world.get_entrance('Lake Hylia Northeast Water Drop', player), player) + add_bunny_rule(world.get_entrance('Lake Hylia Central Water Drop', player), player) + add_bunny_rule(world.get_entrance('Lake Hylia Island Water Drop', player), player) + add_bunny_rule(world.get_entrance('Lake Hylia Water D Leave', player), player) + add_bunny_rule(world.get_entrance('Ice Cave Water Drop', player), player) add_bunny_rule(world.get_entrance('Desert Pass Rocks (North)', player), player) add_bunny_rule(world.get_entrance('Desert Pass Rocks (South)', player), player) + add_bunny_rule(world.get_entrance('Octoballoon Water Drop', player), player) + add_bunny_rule(world.get_entrance('Octoballoon Waterfall Water Drop', player), player) - add_bunny_rule(world.get_entrance('Skull Woods Bush Rock (West)', player), player) - add_bunny_rule(world.get_entrance('Skull Woods Bush Rock (East)', player), player) + add_bunny_rule(world.get_entrance('Skull Woods Rock (West)', player), player) + add_bunny_rule(world.get_entrance('Skull Woods Rock (East)', player), player) add_bunny_rule(world.get_entrance('Skull Woods Forgotten Bush (West)', player), player) add_bunny_rule(world.get_entrance('Skull Woods Forgotten Bush (East)', player), player) add_bunny_rule(world.get_entrance('Skull Woods Second Section Hole', player), player) add_bunny_rule(world.get_entrance('East Dark Death Mountain Bushes', player), player) add_bunny_rule(world.get_entrance('Bumper Cave Ledge Drop', player), player) - add_bunny_rule(world.get_entrance('Bumper Cave Entrance Rock', player), player) + add_bunny_rule(world.get_entrance('Bumper Cave Rock (Outer)', player), player) + add_bunny_rule(world.get_entrance('Bumper Cave Rock (Inner)', player), player) add_bunny_rule(world.get_entrance('Skull Woods Pass Bush Row (West)', player), player) add_bunny_rule(world.get_entrance('Skull Woods Pass Bush Row (East)', player), player) add_bunny_rule(world.get_entrance('Skull Woods Pass Bush (North)', player), player) @@ -1132,15 +1186,23 @@ def ow_bunny_rules(world, player): add_bunny_rule(world.get_entrance('Skull Woods Pass Rock (South)', player), player) add_bunny_rule(world.get_entrance('Dark Graveyard Bush (South)', player), player) add_bunny_rule(world.get_entrance('Dark Graveyard Bush (North)', player), player) + add_bunny_rule(world.get_entrance('Qirn Jump Water Drop', player), player) + add_bunny_rule(world.get_entrance('Qirn Jump East Water Drop', player), player) + add_bunny_rule(world.get_entrance('Dark Witch Water Drop', player), player) + add_bunny_rule(world.get_entrance('Dark Witch Northeast Water Drop', player), player) add_bunny_rule(world.get_entrance('Dark Witch Rock (North)', player), player) add_bunny_rule(world.get_entrance('Dark Witch Rock (South)', player), player) + add_bunny_rule(world.get_entrance('Catfish Approach Water Drop', player), player) add_bunny_rule(world.get_entrance('Catfish Approach Rocks (West)', player), player) add_bunny_rule(world.get_entrance('Catfish Approach Rocks (East)', player), player) - add_bunny_rule(world.get_entrance('Village of Outcasts Pegs', player), player) - add_bunny_rule(world.get_entrance('Grassy Lawn Pegs', player), player) + add_bunny_rule(world.get_entrance('Bush Yard Pegs (Outer)', player), player) + add_bunny_rule(world.get_entrance('Bush Yard Pegs (Inner)', player), player) add_bunny_rule(world.get_entrance('Broken Bridge Hammer Rock (South)', player), player) add_bunny_rule(world.get_entrance('Broken Bridge Hammer Rock (North)', player), player) add_bunny_rule(world.get_entrance('Broken Bridge Hookshot Gap', player), player) + add_bunny_rule(world.get_entrance('Broken Bridge Water Drop', player), player) + add_bunny_rule(world.get_entrance('Broken Bridge Northeast Water Drop', player), player) + add_bunny_rule(world.get_entrance('Broken Bridge West Water Drop', player), player) add_bunny_rule(world.get_entrance('Peg Area Rocks (West)', player), player) add_bunny_rule(world.get_entrance('Peg Area Rocks (East)', player), player) add_bunny_rule(world.get_entrance('Dig Game To Ledge Drop', player), player) @@ -1150,12 +1212,27 @@ def ow_bunny_rules(world, player): add_bunny_rule(world.get_entrance('Archery Game Rock (South)', player), player) add_bunny_rule(world.get_entrance('Hammer Bridge Pegs (North)', player), player) add_bunny_rule(world.get_entrance('Hammer Bridge Pegs (South)', player), player) + add_bunny_rule(world.get_entrance('Hammer Bridge Water Drop', player), player) add_bunny_rule(world.get_entrance('Stumpy Approach Bush (North)', player), player) add_bunny_rule(world.get_entrance('Stumpy Approach Bush (South)', player), player) + add_bunny_rule(world.get_entrance('Dark C Whirlpool Water Entry', player), player) add_bunny_rule(world.get_entrance('Dark C Whirlpool Rock (Bottom)', player), player) add_bunny_rule(world.get_entrance('Dark C Whirlpool Rock (Top)', player), player) - add_bunny_rule(world.get_entrance('Dark C Whirlpool Pegs (Left)', player), player) - add_bunny_rule(world.get_entrance('Dark C Whirlpool Pegs (Right)', player), player) + add_bunny_rule(world.get_entrance('Dark C Whirlpool Pegs (Outer)', player), player) + add_bunny_rule(world.get_entrance('Dark C Whirlpool Pegs (Inner)', player), player) + add_bunny_rule(world.get_entrance('Hype Cave Water Entry', player), player) + add_bunny_rule(world.get_entrance('Ice Lake Water Drop', player), player) + add_bunny_rule(world.get_entrance('Ice Lake Northeast Water Drop', player), player) + add_bunny_rule(world.get_entrance('Ice Lake Southwest Water Drop', player), player) + add_bunny_rule(world.get_entrance('Ice Lake Southeast Water Drop', player), player) + add_bunny_rule(world.get_entrance('Ice Lake Iceberg Water Entry', player), player) + add_bunny_rule(world.get_entrance('Shopping Mall Water Drop', player), player) + add_bunny_rule(world.get_entrance('Bomber Corner Water Drop', player), player) + add_bunny_rule(world.get_entrance('Bomber Corner Waterfall Water Drop', player), player) + + # OWG rules + add_bunny_rule(world.get_entrance('Stone Bridge EC Cliff Water Drop', player), player) + add_bunny_rule(world.get_entrance('Hammer Bridge EC Cliff Water Drop', player), player) if not world.is_atgt_swapped(player): add_bunny_rule(world.get_entrance('Agahnims Tower', player), player) @@ -1181,92 +1258,23 @@ def ow_terrain_rules(world, player): def no_glitches_rules(world, player): - set_rule(world.get_entrance('Zora Waterfall Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Zora Waterfall Water Entry', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Zora Waterfall Water Approach', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Kakariko Pond Whirlpool', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('River Bend Water Drop', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('River Bend East Water Drop', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Potion Shop Water Drop', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Potion Shop Northeast Water Drop', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Zora Approach Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Wooden Bridge Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Wooden Bridge Northeast Water Drop', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('C Whirlpool Water Entry', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Statues Water Entry', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Lake Hylia Water Drop', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Lake Hylia South Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Lake Hylia Northeast Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Lake Hylia Central Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Lake Hylia Island Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Lake Hylia Water D Leave', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Ice Cave SW', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Octoballoon Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Octoballoon Waterfall Water Drop', player), lambda state: state.has('Flippers', player)) - - set_rule(world.get_entrance('Qirn Jump Water Drop', player), lambda state: state.has('Flippers', player)) + set_rule(world.get_entrance('Qirn Jump East Water Drop', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Dark Witch Water Drop', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Dark Witch Northeast Water Drop', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Catfish Approach Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Broken Bridge Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Broken Bridge Northeast Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Broken Bridge West Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Hammer Bridge Water Drop', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Dark C Whirlpool Water Entry', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Hype Cave Water Entry', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Ice Lake Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Ice Lake Northeast Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Ice Lake Southwest Water Drop', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Ice Lake Southeast Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Ice Lake Moat Water Entry', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Shopping Mall SW', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Bomber Corner Water Drop', player), lambda state: state.has('Flippers', player)) - set_rule(world.get_entrance('Bomber Corner Waterfall Water Drop', player), lambda state: state.has('Flippers', player)) - - add_bunny_rule(world.get_entrance('Zora Waterfall Water Drop', player), player) - add_bunny_rule(world.get_entrance('Zora Waterfall Water Entry', player), player) - add_bunny_rule(world.get_entrance('Zora Waterfall Water Approach', player), player) - add_bunny_rule(world.get_entrance('Kakariko Pond Whirlpool', player), player) - add_bunny_rule(world.get_entrance('River Bend Water Drop', player), player) - add_bunny_rule(world.get_entrance('River Bend East Water Drop', player), player) - add_bunny_rule(world.get_entrance('Potion Shop Water Drop', player), player) - add_bunny_rule(world.get_entrance('Potion Shop Northeast Water Drop', player), player) - add_bunny_rule(world.get_entrance('Zora Approach Water Drop', player), player) - add_bunny_rule(world.get_entrance('Wooden Bridge Water Drop', player), player) - add_bunny_rule(world.get_entrance('Wooden Bridge Northeast Water Drop', player), player) - add_bunny_rule(world.get_entrance('C Whirlpool Water Entry', player), player) - add_bunny_rule(world.get_entrance('Statues Water Entry', player), player) - add_bunny_rule(world.get_entrance('Lake Hylia Water Drop', player), player) - add_bunny_rule(world.get_entrance('Lake Hylia South Water Drop', player), player) - add_bunny_rule(world.get_entrance('Lake Hylia Northeast Water Drop', player), player) - add_bunny_rule(world.get_entrance('Lake Hylia Central Water Drop', player), player) - add_bunny_rule(world.get_entrance('Lake Hylia Island Water Drop', player), player) - add_bunny_rule(world.get_entrance('Lake Hylia Water D Leave', player), player) - add_bunny_rule(world.get_entrance('Ice Cave SW', player), player) - add_bunny_rule(world.get_entrance('Octoballoon Water Drop', player), player) - add_bunny_rule(world.get_entrance('Octoballoon Waterfall Water Drop', player), player) - - add_bunny_rule(world.get_entrance('Qirn Jump Water Drop', player), player) - add_bunny_rule(world.get_entrance('Qirn Jump East Water Drop', player), player) - add_bunny_rule(world.get_entrance('Dark Witch Water Drop', player), player) - add_bunny_rule(world.get_entrance('Dark Witch Northeast Water Drop', player), player) - add_bunny_rule(world.get_entrance('Catfish Approach Water Drop', player), player) - add_bunny_rule(world.get_entrance('Broken Bridge Water Drop', player), player) - add_bunny_rule(world.get_entrance('Broken Bridge Northeast Water Drop', player), player) - add_bunny_rule(world.get_entrance('Broken Bridge West Water Drop', player), player) - add_bunny_rule(world.get_entrance('Hammer Bridge Water Drop', player), player) - add_bunny_rule(world.get_entrance('Dark C Whirlpool Water Entry', player), player) - add_bunny_rule(world.get_entrance('Hype Cave Water Entry', player), player) - add_bunny_rule(world.get_entrance('Ice Lake Water Drop', player), player) - add_bunny_rule(world.get_entrance('Ice Lake Northeast Water Drop', player), player) - add_bunny_rule(world.get_entrance('Ice Lake Southwest Water Drop', player), player) - add_bunny_rule(world.get_entrance('Ice Lake Southeast Water Drop', player), player) - add_bunny_rule(world.get_entrance('Ice Lake Moat Water Entry', player), player) - add_bunny_rule(world.get_entrance('Shopping Mall SW', player), player) - add_bunny_rule(world.get_entrance('Bomber Corner Water Drop', player), player) - add_bunny_rule(world.get_entrance('Bomber Corner Waterfall Water Drop', player), player) - # todo: move some dungeon rules to no glicthes logic - see these for examples # add_rule(world.get_entrance('Ganons Tower (Hookshot Room)', player), lambda state: state.has('Hookshot', player) or state.has_Boots(player)) @@ -1275,13 +1283,13 @@ def no_glitches_rules(world, player): # for location in DMs_room_chests: # add_rule(world.get_location(location, player), lambda state: state.has('Hookshot', player)) set_rule(world.get_entrance('Paradox Cave Push Block Reverse', player), lambda state: False) # no glitches does not require block override + set_rule(world.get_entrance('Ice Lake Northeast Pier Hop', player), lambda state: False) forbid_bomb_jump_requirements(world, player) if not world.is_copied_world: add_conditional_lamps(world, player) def fake_flipper_rules(world, player): - set_rule(world.get_entrance('Zora Waterfall Water Approach', player), lambda state: True) # warning, assumes FF possible on other end of whirlpool or local ancilla splash delete set_rule(world.get_entrance('River Bend Water Drop', player), lambda state: True) set_rule(world.get_entrance('River Bend East Water Drop', player), lambda state: True) set_rule(world.get_entrance('Potion Shop Water Drop', player), lambda state: True) @@ -1300,26 +1308,6 @@ def fake_flipper_rules(world, player): set_rule(world.get_entrance('Hype Cave Water Entry', player), lambda state: True) set_rule(world.get_entrance('Ice Lake Southeast Water Drop', player), lambda state: True) set_rule(world.get_entrance('Bomber Corner Water Drop', player), lambda state: True) - - add_bunny_rule(world.get_entrance('Zora Waterfall Water Approach', player), player) - add_bunny_rule(world.get_entrance('River Bend Water Drop', player), player) - add_bunny_rule(world.get_entrance('River Bend East Water Drop', player), player) - add_bunny_rule(world.get_entrance('Potion Shop Water Drop', player), player) - add_bunny_rule(world.get_entrance('Potion Shop Northeast Water Drop', player), player) - add_bunny_rule(world.get_entrance('Zora Approach Water Drop', player), player) - add_bunny_rule(world.get_entrance('C Whirlpool Water Entry', player), player) - add_bunny_rule(world.get_entrance('Statues Water Entry', player), player) - add_bunny_rule(world.get_entrance('Lake Hylia South Water Drop', player), player) - add_bunny_rule(world.get_entrance('Octoballoon Water Drop', player), player) - add_bunny_rule(world.get_entrance('Qirn Jump Water Drop', player), player) - add_bunny_rule(world.get_entrance('Qirn Jump East Water Drop', player), player) - add_bunny_rule(world.get_entrance('Dark Witch Water Drop', player), player) - add_bunny_rule(world.get_entrance('Dark Witch Northeast Water Drop', player), player) - add_bunny_rule(world.get_entrance('Catfish Approach Water Drop', player), player) - add_bunny_rule(world.get_entrance('Dark C Whirlpool Water Entry', player), player) - add_bunny_rule(world.get_entrance('Hype Cave Water Entry', player), player) - add_bunny_rule(world.get_entrance('Ice Lake Southeast Water Drop', player), player) - add_bunny_rule(world.get_entrance('Bomber Corner Water Drop', player), player) def forbid_bomb_jump_requirements(world, player): @@ -1327,7 +1315,7 @@ def forbid_bomb_jump_requirements(world, player): for location in DMs_room_chests: add_rule(world.get_location(location, player), lambda state: state.has('Hookshot', player)) set_rule(world.get_entrance('Paradox Cave Bomb Jump', player), lambda state: False) - set_rule(world.get_entrance('Ice Lake Northeast Pier Hop', player), lambda state: False) + set_rule(world.get_entrance('Ice Lake Iceberg Bomb Jump', player), lambda state: False) def add_conditional_lamps(world, player): def add_conditional_lamp(spot, spottype='Location'): @@ -1475,8 +1463,6 @@ def standard_rules(world, player): entrance = world.get_portal(portal_name, player).door.entrance set_rule(entrance, lambda state: state.has('Zelda Delivered', player)) set_rule(world.get_entrance('Sanctuary Exit', player), lambda state: state.has('Zelda Delivered', player)) - set_rule(world.get_entrance('Hyrule Castle Ledge Drop', player), lambda state: state.has('Zelda Delivered', player)) - set_rule(world.get_entrance('Hyrule Castle Main Gate (North)', player), lambda state: state.has('Zelda Delivered', player)) # zelda should be saved before agahnim is in play add_rule(world.get_location('Agahnim 1', player), lambda state: state.has('Zelda Delivered', player)) @@ -1519,15 +1505,9 @@ def standard_rules(world, player): rule_list, debug_path = find_rules_for_zelda_delivery(world, player) set_rule(world.get_location('Zelda Drop Off', player), lambda state: state.has('Zelda Herself', player) and check_rule_list(state, rule_list)) - add_rule(world.get_entrance('Links House SC', player), lambda state: state.has('Zelda Delivered', player)) - add_rule(world.get_entrance('Links House ES', player), lambda state: state.has('Zelda Delivered', player)) - add_rule(world.get_entrance('Central Bonk Rocks SW', player), lambda state: state.has('Zelda Delivered', player)) - add_rule(world.get_entrance('Hyrule Castle WN', player), lambda state: state.has('Zelda Delivered', player)) - add_rule(world.get_entrance('Hyrule Castle ES', player), lambda state: state.has('Zelda Delivered', player)) - add_rule(world.get_entrance('Hyrule Castle Main Gate (South)', player), lambda state: state.has('Zelda Delivered', player)) - add_rule(world.get_entrance('Hyrule Castle Main Gate (North)', player), lambda state: state.has('Zelda Delivered', player)) - add_rule(world.get_entrance('Hyrule Castle Ledge Drop', player), lambda state: state.has('Zelda Delivered', player)) - add_rule(world.get_entrance('Bonk Fairy (Light)', player), lambda state: state.has('Zelda Delivered', player)) + for entrance in ['Links House SC', 'Links House ES', 'Central Bonk Rocks SW', 'Hyrule Castle WN', 'Hyrule Castle ES', + 'Bonk Fairy (Light)', 'Hyrule Castle Main Gate (South)', 'Hyrule Castle Main Gate (North)', 'Hyrule Castle Ledge Drop']: + add_rule(world.get_entrance(entrance, player), lambda state: state.has('Zelda Delivered', player)) if world.shuffle_bonk_drops[player]: if not world.is_copied_world: @@ -1537,6 +1517,7 @@ def standard_rules(world, player): # don't allow bombs to get past here before zelda is rescued set_rule(world.get_entrance('GT Hookshot South Entry to Ranged Crystal', player), lambda state: (state.can_use_bombs(player) and state.has('Zelda Delivered', player)) or state.has('Blue Boomerang', player) or state.has('Red Boomerang', player)) # or state.has('Cane of Somaria', player)) + def find_rules_for_zelda_delivery(world, player): # path rules for backtracking start_region = world.get_region('Hyrule Dungeon Cellblock', player) diff --git a/source/item/District.py b/source/item/District.py index 113f2d18..baf46a82 100644 --- a/source/item/District.py +++ b/source/item/District.py @@ -138,10 +138,10 @@ def find_reachable_locations(state, player): return check_set -inaccessible_regions_std = {'Desert Palace Mouth', 'Bumper Cave Ledge', 'Skull Woods Forest (West)', +inaccessible_regions_std = {'Desert Mouth', 'Bumper Cave Ledge', 'Skull Woods Forest (West)', 'Dark Death Mountain Ledge', 'Dark Death Mountain Isolated Ledge', 'Death Mountain Floating Island'} -inaccessible_regions_inv = {'Desert Palace Mouth', 'Maze Race Ledge', 'Desert Ledge', - 'Desert Palace Entrance (North) Spot', 'Hyrule Castle Ledge', 'Mountain Entry Ledge'} +inaccessible_regions_inv = {'Desert Mouth', 'Maze Race Ledge', 'Desert Ledge', + 'Desert Ledge Keep', 'Hyrule Castle Ledge', 'Mountain Pass Ledge'} diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index 416ba226..89c6b0c0 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -751,8 +751,8 @@ def must_exits_helper(avail): inaccessible_regions = list(avail.world.inaccessible_regions[avail.player]) # find OW regions that don't have a multi-entrance dungeon exit connected - glitch_regions = ['Central Cliffs', 'Eastern Cliff', 'Desert Northeast Cliffs', 'Hyrule Castle Water', - 'Dark Central Cliffs', 'Darkness Cliff', 'Mire Northeast Cliffs', 'Pyramid Water'] + glitch_regions = ['Central Cliffs', 'Eastern Cliff', 'Desert Northern Cliffs', 'Hyrule Castle Water', + 'Dark Central Cliffs', 'Darkness Cliff', 'Mire Northern Cliffs', 'Pyramid Water'] multi_dungeon_exits = { 'Hyrule Castle South Portal', 'Hyrule Castle West Portal', 'Hyrule Castle East Portal', 'Sanctuary Portal', 'Desert South Portal', 'Desert West Portal', @@ -2160,9 +2160,9 @@ default_connections = {'Lost Woods Gamble': 'Lost Woods Gamble', 'Paradox Cave (Bottom)': 'Paradox Cave Front', 'Paradox Cave Exit (Bottom)': 'East Death Mountain (Bottom)', 'Death Mountain Return Cave (West)': 'Death Mountain Return Cave (left)', - 'Death Mountain Return Cave Exit (West)': 'Mountain Entry Ledge', + 'Death Mountain Return Cave Exit (West)': 'Mountain Pass Ledge', 'Old Man Cave (West)': 'Old Man Cave Ledge', - 'Old Man Cave Exit (West)': 'Mountain Entry Entrance', + 'Old Man Cave Exit (West)': 'Mountain Pass Entry', 'Waterfall of Wishing': 'Waterfall of Wishing', 'Fortune Teller (Light)': 'Fortune Teller (Light)', 'Bonk Rock Cave': 'Bonk Rock Cave', @@ -2177,12 +2177,12 @@ default_connections = {'Lost Woods Gamble': 'Lost Woods Gamble', 'Potion Shop': 'Potion Shop', 'Kakariko Well Drop': 'Kakariko Well (top)', 'Kakariko Well Cave': 'Kakariko Well (bottom)', - 'Kakariko Well Exit': 'Kakariko Area', + 'Kakariko Well Exit': 'Kakariko Village', 'Blinds Hideout': 'Blinds Hideout', 'Elder House (West)': 'Elder House', - 'Elder House Exit (West)': 'Kakariko Area', + 'Elder House Exit (West)': 'Kakariko Village', 'Elder House (East)': 'Elder House', - 'Elder House Exit (East)': 'Kakariko Area', + 'Elder House Exit (East)': 'Kakariko Village', 'Snitch Lady (West)': 'Snitch Lady (West)', 'Snitch Lady (East)': 'Snitch Lady (East)', 'Chicken House': 'Chicken House', @@ -2241,7 +2241,7 @@ default_connections = {'Lost Woods Gamble': 'Lost Woods Gamble', 'Bumper Cave (Top)': 'Bumper Cave (top)', 'Bumper Cave Exit (Top)': 'Bumper Cave Ledge', 'Bumper Cave (Bottom)': 'Bumper Cave (bottom)', - 'Bumper Cave Exit (Bottom)': 'Bumper Cave Entrance', + 'Bumper Cave Exit (Bottom)': 'Bumper Cave Entry', 'Fortune Teller (Dark)': 'Fortune Teller (Dark)', 'Dark Sanctuary Hint': 'Dark Sanctuary Hint', 'Dark Potion Shop': 'Dark Potion Shop', From 8955e8b26fce4ead88c8fa5da936bc83b82ea929 Mon Sep 17 00:00:00 2001 From: Cody Bailey Date: Wed, 14 Jun 2023 15:31:49 -0400 Subject: [PATCH 130/196] Fix JSON metadata --- BaseClasses.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BaseClasses.py b/BaseClasses.py index a7170779..af1436eb 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -2499,6 +2499,7 @@ class Spoiler(object): 'pseudoboots': self.world.pseudoboots, 'triforcegoal': self.world.treasure_hunt_count, 'triforcepool': self.world.treasure_hunt_total, + 'race': self.world.settings.world_rep['meta']['race'], 'code': {p: Settings.make_code(self.world, p) for p in range(1, self.world.players + 1)} } @@ -2601,6 +2602,7 @@ class Spoiler(object): self.set_lobby(portal.name, portal.door.name, player) def to_json(self): + self.parse_meta() self.parse_data() out = OrderedDict() out['Entrances'] = list(self.entrances.values()) From 1cbee3f1906537fff286797c37bced033cf038db Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 15 Jun 2023 12:42:33 -0500 Subject: [PATCH 131/196] Minor logic and terrain GFX changes to Spiral/Mimic Ledge in Inverted - Also updated GFX routine to handle and correct GFX issues when exceeding the max number of GFX --- OWEdges.py | 1 - OverworldShuffle.py | 3 +-- Regions.py | 2 +- Rom.py | 2 +- data/base2current.bps | Bin 107444 -> 107570 bytes 5 files changed, 3 insertions(+), 5 deletions(-) diff --git a/OWEdges.py b/OWEdges.py index 6c9eb89c..2657c682 100644 --- a/OWEdges.py +++ b/OWEdges.py @@ -1454,7 +1454,6 @@ OWExitTypes = { 'EDM To Mimic Ledge Drop', 'EDM Ledge Drop', 'Spiral Ledge Drop', - 'Mimic Ledge Drop', 'Spiral Mimic Ledge Drop', 'Fairy Ascension Ledge Drop', 'Fairy Ascension Plateau Ledge Drop', diff --git a/OverworldShuffle.py b/OverworldShuffle.py index de997bfe..a0b7a5e2 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -1270,7 +1270,6 @@ mandatory_connections = [ ('DM Hammer Bridge (West)', 'East Death Mountain (Top East)'), #hammer ('DM Hammer Bridge (East)', 'East Death Mountain (Top West)'), #hammer ('EDM To Spiral Ledge Drop', 'Spiral Cave Ledge'), - ('EDM To Fairy Ledge Drop', 'Fairy Ascension Ledge'), ('EDM Ledge Drop', 'East Death Mountain (Bottom)'), ('Spiral Ledge Drop', 'East Death Mountain (Bottom)'), ('Fairy Ascension Ledge Drop', 'Fairy Ascension Plateau'), @@ -1480,12 +1479,12 @@ ow_connections = { ('Dark Death Mountain Teleporter (West)', 'West Death Mountain (Bottom)') ]), 0x05: ([ + ('EDM To Fairy Ledge Drop', 'Fairy Ascension Ledge'), ('East Death Mountain Teleporter', 'East Dark Death Mountain (Bottom)') ], [ ('Floating Island Bridge (West)', 'East Death Mountain (Top East)'), ('Floating Island Bridge (East)', 'Death Mountain Floating Island'), ('EDM To Mimic Ledge Drop', 'Mimic Cave Ledge'), - ('Mimic Ledge Drop', 'East Death Mountain (Bottom)'), ('Spiral Mimic Bridge (West)', 'Spiral Mimic Ledge Extend'), ('Spiral Mimic Bridge (East)', 'Spiral Mimic Ledge Extend'), ('Spiral Ledge Approach', 'Spiral Cave Ledge'), diff --git a/Regions.py b/Regions.py index 461f6db6..7dd3617a 100644 --- a/Regions.py +++ b/Regions.py @@ -25,7 +25,7 @@ def create_regions(world, player): 'EDM To Spiral Ledge Drop', 'EDM To Fairy Ledge Drop', 'EDM To Mimic Ledge Drop', 'EDM Ledge Drop', 'East Death Mountain EN']), create_lw_region(player, 'Death Mountain Floating Island', ['Floating Island'], ['Floating Island Bridge (West)']), create_lw_region(player, 'Spiral Cave Ledge', None, ['Spiral Cave', 'Spiral Ledge Drop', 'Spiral Mimic Bridge (West)']), - create_lw_region(player, 'Mimic Cave Ledge', None, ['Mimic Cave', 'Mimic Ledge Drop', 'Spiral Mimic Bridge (East)']), + create_lw_region(player, 'Mimic Cave Ledge', None, ['Mimic Cave', 'Spiral Mimic Bridge (East)']), create_lw_region(player, 'Spiral Mimic Ledge Extend', None, ['Spiral Ledge Approach', 'Mimic Ledge Approach', 'Spiral Mimic Ledge Drop']), create_lw_region(player, 'Fairy Ascension Ledge', None, ['Fairy Ascension Cave (Top)', 'Fairy Ascension Ledge Drop']), create_lw_region(player, 'Fairy Ascension Plateau', None, ['Fairy Ascension Cave (Bottom)', 'Fairy Ascension Rocks (Inner)', 'Fairy Ascension Plateau Ledge Drop']), diff --git a/Rom.py b/Rom.py index 06ccb949..ac6eedba 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '37055215524a94f346e892b7a716c2ef' +RANDOMIZERBASEHASH = '5dc49b073decbc3b66635157ddedf05c' class JsonRom(object): diff --git a/data/base2current.bps b/data/base2current.bps index c4404bdc41bd150472e3a0742ff83513fae79525..759979e87036f3068494d6debb7ef9d57c6bb626 100644 GIT binary patch delta 11251 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%0D8>D|1pe{7{izb8J~bJT6}tE4F(6@+jx^|n zddp9tpZ@nx;kfQ)M;b8VH0TeU#X81*su1-;v<$Ibu|VSC-(rzeX|3n+=xP0QR6lga zgTYSspmC_}bu9363O&Hk;*O|(rc{Ni`_Jmq0@=Vg;2pFdXi@$njiXxiyy|&XHY-l6 zsh&HvQYqr4)^0e@?oGXivuT=~D0XKYkbn{PcpM0py{1ww$f@i2euD2`@%`fkEj5Jc z5ACtAdhWP0>@*5F?stdQFcqg^kkd%0(>v2B!vd)BrA})M=@h$hyAAA-!t~)mv!?{*W2|xzJW)Lb8pJ zeg!^nYu}c7kCi2W5dNa=kUfvx_db5-4u?7n$m9>I@eFU-R@OfF!Ds4*X(ar~Ig7CCrBNqZ+aFAWS5ZrdG7D Date: Fri, 16 Jun 2023 09:15:06 -0600 Subject: [PATCH 132/196] Fixed logic with mirror in west dark world --- EntranceShuffle.py | 2 ++ OverworldShuffle.py | 2 +- Regions.py | 3 ++- Rules.py | 2 ++ source/overworld/EntranceShuffle2.py | 2 ++ 5 files changed, 9 insertions(+), 2 deletions(-) diff --git a/EntranceShuffle.py b/EntranceShuffle.py index 2e5162e4..3a44b677 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -2169,6 +2169,8 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('West Dark World Gap', 'West Dark World'), ('Broken Bridge Pass (Top)', 'East Dark World'), ('Broken Bridge Pass (Bottom)', 'Northeast Dark World'), + ('Dark Graveyard Bush (South)', 'Dark Graveyard North'), + ('Dark Graveyard Bush (North)', 'West Dark World'), ('Peg Area Rocks (Left)', 'Hammer Peg Area'), ('Peg Area Rocks (Right)', 'West Dark World'), ('Village of Outcasts Heavy Rock', 'West Dark World'), diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 099d5a9c..3793f272 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -48,7 +48,7 @@ mirror_connections = { 'East Dark Death Mountain (Bushes)': ['Fairy Ascension Plateau'], 'East Dark Death Mountain (Bottom)': ['East Death Mountain (Bottom)'], - 'West Dark World': ['Graveyard Ledge', 'Kings Grave Area'], + 'Dark Graveyard North': ['Graveyard Ledge', 'Kings Grave Area'], 'Bumper Cave Ledge': ['Death Mountain Return Ledge'], 'Bumper Cave Entrance': ['Death Mountain Entrance'], diff --git a/Regions.py b/Regions.py index 7b0e2535..7546e012 100644 --- a/Regions.py +++ b/Regions.py @@ -85,7 +85,8 @@ def create_regions(world, player): create_dw_region(player, 'West Dark World', ['Frog'], ['Dark Lumberjack Shop', 'Fortune Teller (Dark)', 'Dark Sanctuary Hint', 'Chest Game', 'Thieves Town', 'C-Shaped House', 'Brewery', 'Red Shield Shop', 'Skull Woods Forest', 'Bumper Cave Entrance Rock', 'West Dark World Water Drop', 'Grassy Lawn Pegs (Bottom)', 'Peg Area Rocks (Left)', 'Village of Outcasts Drop', - 'West Dark World Teleporter', 'WDW Flute']), + 'West Dark World Teleporter', 'WDW Flute', 'Dark Graveyard Bush (South)']), + create_dw_region(player, 'Dark Graveyard North', None, ['Dark Graveyard Bush (North)']), create_dw_region(player, 'Skull Woods Forest', None, ['Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', 'Skull Woods First Section Door', 'Skull Woods Second Section Door (East)']), create_dw_region(player, 'Skull Woods Forest (West)', None, ['Skull Woods Second Section Hole', 'Skull Woods Second Section Door (West)', 'Skull Woods Final Section'], 'a deep, dark forest'), diff --git a/Rules.py b/Rules.py index fc608ec2..80392396 100644 --- a/Rules.py +++ b/Rules.py @@ -965,6 +965,8 @@ def ow_bunny_rules(world, player): add_bunny_rule(world.get_entrance('East Dark Death Mountain Bushes', player), player) add_bunny_rule(world.get_entrance('Bumper Cave Entrance Rock', player), player) + add_bunny_rule(world.get_entrance('Dark Graveyard Bush (South)', player), player) + add_bunny_rule(world.get_entrance('Dark Graveyard Bush (North)', player), player) add_bunny_rule(world.get_entrance('Dark Witch Rock (North)', player), player) add_bunny_rule(world.get_entrance('Dark Witch Rock (South)', player), player) add_bunny_rule(world.get_entrance('Grassy Lawn Pegs (Bottom)', player), player) diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index 61f0a80d..6afc7b9e 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -1962,6 +1962,8 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Grassy Lawn Pegs (Top)', 'West Dark World'), ('Grassy Lawn Pegs (Bottom)', 'Dark Grassy Lawn'), ('West Dark World Gap', 'West Dark World'), + ('Dark Graveyard Bush (South)', 'Dark Graveyard North'), + ('Dark Graveyard Bush (North)', 'West Dark World'), ('Broken Bridge Pass (Top)', 'East Dark World'), ('Broken Bridge Pass (Bottom)', 'Northeast Dark World'), ('Peg Area Rocks (Left)', 'Hammer Peg Area'), From 8afdbaca25724942f0d22d0ad9c886341bdce04c Mon Sep 17 00:00:00 2001 From: aerinon Date: Fri, 16 Jun 2023 09:22:08 -0600 Subject: [PATCH 133/196] Update release notes --- RELEASENOTES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 33b0a50e..e3d09589 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -110,6 +110,7 @@ These are now independent of retro mode and have three options: None, Random, an # Bug Fixes and Notes * 1.2.0.17u + * Fixed logic bug that allowed Pearl to be behind Graveyard Cave or King's Tomb entrances with only Mirror and West Dark World access (cross world shuffles only) * Removed backup locations for Dungeon Only and Major Only algorithms. If item cannot be placed in the appropriate location, the seed will fail to generate instead * Fix for Non-ER Inverted Experimental (Aga and GT weren't logically swapped) * Fix for customizer setting crystals to 0 for either GT/Ganon From 7512d73e99a6734323b86efcf2c694643c096762 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Fri, 16 Jun 2023 20:27:28 -0500 Subject: [PATCH 134/196] Version bump 0.3.1.1 --- CHANGELOG.md | 6 ++++++ OverworldShuffle.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a8b1f70..4d9a8e76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 0.3.1.1 +- \~Merged in DR v1.2.0.17~ +- Various renames/reorganizations of region/rule definition to match upcoming DR world remodel +- Minor improvements to item GFX draw routine +- Minor change to terrain/logic of Spiral/Mimic Ledge in Inverted 2.0 + ## 0.3.1.0 - Added new Triforce Cutscene when getting Triforce item (turning in TF Pieces) - Fixed issue with enemy key drops displaying the wrong GFX diff --git a/OverworldShuffle.py b/OverworldShuffle.py index a0b7a5e2..c5acb597 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -7,7 +7,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType from OverworldGlitchRules import create_owg_connections from Utils import bidict -version_number = '0.3.1.0' +version_number = '0.3.1.1' # branch indicator is intentionally different across branches version_branch = '-u' From 0314958201180a228c2aed93756b3d93b1a78a21 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Fri, 16 Jun 2023 20:40:34 -0500 Subject: [PATCH 135/196] Fixed issue where items spawning off screen might not redraw --- Rom.py | 2 +- data/base2current.bps | Bin 107570 -> 107581 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Rom.py b/Rom.py index ac6eedba..b2621829 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '5dc49b073decbc3b66635157ddedf05c' +RANDOMIZERBASEHASH = 'a5c37eecbe3e52b49639c0d0ad91a7c3' class JsonRom(object): diff --git a/data/base2current.bps b/data/base2current.bps index 759979e87036f3068494d6debb7ef9d57c6bb626..82728c51fce85028ec9f2b5452c58a3c2a6ddfba 100644 GIT binary patch delta 421 zcmV;W0b2gD$OgU029Syg|F@{>9EXh}CXtit1e^t9`m=%o5l;cTvy@Q7DgnE*SbM7h z0lTvVeNMmvNr9JCJpoe*mv%$yk8Oe_fS0U20UHt{w7nn>$-vM7yU9|}0lSxG+n3rs z0UH@0w8@~5BFV6@9;98s8IT6R8?XX^5~~IzmkvGw9s$RfEj|GyJ3YD34e&U*kO$B+ zxqt`Fa30VrmkS%8%?`=r@CwO0@CM1}@B)AqsREsl2d7{hpNqmJf%<5GV2BXAmxVq7 zL;?Xpm&-l@Mn0vqsDK2&v$Uv<79kjE00Bs%evTAFsQ}Et0GB9x0)Ul>(D{u5Lzf2- zjh1j)sk1Q!5`dX#jTRw{3qqG_mrp+dH7zLspM}C8mr8z~sRgNjwtyq4kGFsxvr~Sa zr%(W&so%AL1F0Xkg$TWXlNFVhu|ENI0brLWKmi^C0|S>wKmjEIJeO@i0e}Z#b{K#Q zfFPIjKmjBjKUCYN9#Y$r88!Qz4}b!xAB_t_2c|4X-A5OLT(>nr0i+5AGk1lbUANv# P0Zdp3Q6N=XYIQ;p@^`1k delta 434 zcmV;j0ZsnB$Of{=29Syg^0%n!9EXh}8IhCg1Y8ZH^0R^g5l;cGvy@Q7DgmyuSbM7h z0j{$IeNMmv1%sDVJpoe%B2l%Vke9GM0UHw*w7nn>$-vM7yU9|}0lSw39qX6fJpmgT z6ST>okRr*jupXpcz!{JRz#FgvfD)^GBbO0A0UiOmmoPp7B{Ma-&<*e~xsV6YE4hFN z&2S#jBbNaipREST>^TB)-!1rmUn zXpI&jj0-}SP?uUi0W~cT0H1}zAeS(Ho~Z??a<+gYse-qF9?%+1x Date: Thu, 29 Jun 2023 19:33:36 -0500 Subject: [PATCH 136/196] Fixed issue with Aga Door preventing TF Cutscene --- Rom.py | 2 +- data/base2current.bps | Bin 107581 -> 107658 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Rom.py b/Rom.py index b2621829..87d40d07 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = 'a5c37eecbe3e52b49639c0d0ad91a7c3' +RANDOMIZERBASEHASH = '32562fbd414b74de7ee7aa9b1063c487' class JsonRom(object): diff --git a/data/base2current.bps b/data/base2current.bps index 82728c51fce85028ec9f2b5452c58a3c2a6ddfba..71872ae5513c8e0450e40c04ff8153010d83874f 100644 GIT binary patch delta 2960 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 delta 2861 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 Date: Mon, 3 Jul 2023 15:55:35 -0500 Subject: [PATCH 137/196] Fixed issue with Kakariko music playing when killing Aggro Guards in enemizer --- Rom.py | 2 +- data/base2current.bps | Bin 107658 -> 107664 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Rom.py b/Rom.py index 87d40d07..216c8c9f 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '32562fbd414b74de7ee7aa9b1063c487' +RANDOMIZERBASEHASH = '497c4ca85d803687a8de846211824bd7' class JsonRom(object): diff --git a/data/base2current.bps b/data/base2current.bps index 71872ae5513c8e0450e40c04ff8153010d83874f..386d328769d8bd4a00008ef00f264b209e7d9c4f 100644 GIT binary patch delta 74 zcmV-Q0JZ;$$p(C;X|FM@}u6_m~$^ZZW delta 92 zcmV-i0Hgnq$p(ta2C#ks1HJn~vw;E92m(N=lUfQy18iG^v!M#jyepSaG3Mz4r5kI> yK=2I7LhuO5Q1ArFQP2pldh>qCfAE%LnTczn|Empimb042?%W8g2WJ~`UV!zYfGn&4 From 2bd6f6ec711755cd544105a352707562559d3a3a Mon Sep 17 00:00:00 2001 From: codemann8 Date: Tue, 4 Jul 2023 16:59:24 -0500 Subject: [PATCH 138/196] Fixed issue with Mixed OWR where Ice Cave/Shopping Mall water transitions were not flipping --- OWEdges.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OWEdges.py b/OWEdges.py index 2657c682..f4da280e 100644 --- a/OWEdges.py +++ b/OWEdges.py @@ -1153,6 +1153,7 @@ OWTileRegions = bidict({ 'Lake Hylia Water D': 0x35, 'Ice Cave Area': 0x37, + 'Ice Cave Water': 0x37, 'Desert Pass Area': 0x3a, 'Middle Aged Man': 0x3a, @@ -1292,6 +1293,7 @@ OWTileRegions = bidict({ 'Ice Palace Area': 0x75, 'Shopping Mall Area': 0x77, + 'Shopping Mall Water': 0x77, 'Swamp Nook Area': 0x7a, From 581597234cb871e3fa763e6f63f1a906b931a0f9 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Fri, 7 Jul 2023 01:33:39 -0500 Subject: [PATCH 139/196] Changing retro so bottle vendor fish prize gives a key instead of arrows --- Rom.py | 5 +++-- data/base2current.bps | Bin 107664 -> 107720 bytes 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Rom.py b/Rom.py index 216c8c9f..c21832e0 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '497c4ca85d803687a8de846211824bd7' +RANDOMIZERBASEHASH = '614fa2fcbb4644beddadcf356e121d5a' class JsonRom(object): @@ -1582,7 +1582,8 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): rom.write_byte(0x301FC, 0xDA if world.bow_mode[player].startswith('retro') else 0xE1) # rupees replace arrows under pots if enemized: rom.write_byte(0x1B152e, 0xDA if world.bow_mode[player].startswith('retro') else 0xE1) - rom.write_byte(0x30052, 0xDB if world.bow_mode[player].startswith('retro') else 0xE2) # replace arrows in fish prize from bottle merchant + if world.bow_mode[player].startswith('retro'): + rom.write_byte(0x30052, 0xE4 if world.keyshuffle[player] == 'universal' else 0xDB) # replace arrows in fish prize from bottle merchant rom.write_bytes(0xECB4E, [0xA9, 0x00, 0xEA, 0xEA] if world.bow_mode[player].startswith('retro') else [0xAF, 0x77, 0xF3, 0x7E]) # Thief steals rupees instead of arrows rom.write_bytes(0xF0D96, [0xA9, 0x00, 0xEA, 0xEA] if world.bow_mode[player].startswith('retro') else [0xAF, 0x77, 0xF3, 0x7E]) # Pikit steals rupees instead of arrows rom.write_bytes(0xEDA5, [0x35, 0x41] if world.bow_mode[player].startswith('retro') else [0x43, 0x44]) # Chest game gives rupees instead of arrows diff --git a/data/base2current.bps b/data/base2current.bps index 386d328769d8bd4a00008ef00f264b209e7d9c4f..99b8b7507ad96bcc7ec31a11eb97881f656b9117 100644 GIT binary patch delta 559 zcmV+~0?_@C$p*;D29SygHMpqi9EXh}N|BSB0g#g~0Z#;%-Do1Sf&mr>4QPd(B5bm# z>gww1XpXa*2n9$1&+Jpnc#xgZY7_tHNcHGze zAP$!q8jYdw9;KkkAOY|fmPZb+mtS2BfCYfimmNR>B3Vdf`;7{%H^7gIk&QRNz_q7L zDxRG|z&Pm;0F6Pjkbys!f~h~isWrfb2;v}Q2bXUHpObptn-P_f=91=;XqQM)nU;J) zz=;R|P?}%4mvd0si3k8vnOc$XhR0V5tORokZuQ`?gTHv63q xfC8x>jSE5trYuL@Zxw?`bGKkY0i+5CB2El|pGiZv3rqohSO^ov%%FgAXUP delta 495 zcmV0(6zLr3eK` z0l$;0P|^X1vwl%v907;3-))Nx2#2z$k5+)Czq4|Cs{sMOvmSjdkO7CcObr1pFab%I zdp!X*m(o1}LIER}6+Qth7$CICppYWTu&^GaUBDTT2EZGz0)P^$2A5er0UrU!mw7$` zIU5TbpUn=*M?a;ssDK2&wX~>> z79kjE00Bs%evTAFsQ}Et0GB9x0)Ul>(D{u5Lzia{jh1j)sk2c95`dX#jTRw{3qqG_ z7MG+y0X8f(0H1}zAeTyho~Z??gSLPpsgt*W9PP+fE&Fa4wo4kjUj;W5T&5WAOY}~RX_nE6AO2bjS8(d zz>kWNjW@u+wWnw)mx@3E9VrU~pObptn-P_f=91=;XqQM)nU+E`kckKYP?}%4mvd0s zi3k8vn?yO6&_Dry2x)d0fD3>qcb8W|0V5tqRNJQ}QrnXuHT#_pfC8x>jSE5trYuL@ lHy49sa<`a40i+5CK1~dOpJhU~LrejESP1z;hX1jbU#<|5!rA}; From d30642c0c76daea3777e6c26e7f5739ed58ed337 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Fri, 7 Jul 2023 03:41:33 -0500 Subject: [PATCH 140/196] Including OW Tile Flips in Printed Customizer File --- Main.py | 2 ++ OverworldShuffle.py | 16 ++++++++-------- source/classes/CustomSettings.py | 17 +++++++++++++++++ 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/Main.py b/Main.py index 6f0bad59..c426cef7 100644 --- a/Main.py +++ b/Main.py @@ -227,6 +227,8 @@ def main(args, seed=None, fish=None): update_world_regions(world, player) mark_light_dark_world_regions(world, player) create_dynamic_exits(world, player) + if args.print_custom_yaml: + world.settings.record_overworld(world) init_districts(world) diff --git a/OverworldShuffle.py b/OverworldShuffle.py index c5acb597..cf18f4c6 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -639,17 +639,17 @@ def shuffle_tiles(world, groups, result_list, do_grouped, player): if world.customizer: if not do_grouped: custom_flips = world.customizer.get_owtileflips() - if custom_flips: + if custom_flips and player in custom_flips: + custom_flips = custom_flips[player] nonflipped_groups = list() forced_flips = list() forced_nonflips = list() - player_key = player - if 'undefined_chance' in custom_flips[player_key]: - undefined_chance = custom_flips[player_key]['undefined_chance'] - if 'force_flip' in custom_flips[player_key]: - forced_flips = custom_flips[player_key]['force_flip'] - if 'force_no_flip' in custom_flips[player_key]: - forced_nonflips = custom_flips[player_key]['force_no_flip'] + if 'undefined_chance' in custom_flips: + undefined_chance = custom_flips['undefined_chance'] + if 'force_flip' in custom_flips: + forced_flips = custom_flips['force_flip'] + if 'force_no_flip' in custom_flips: + forced_nonflips = custom_flips['force_no_flip'] for group in groups: if any(owid in group[0] for owid in forced_nonflips): diff --git a/source/classes/CustomSettings.py b/source/classes/CustomSettings.py index c5ff7e78..3e90e5b3 100644 --- a/source/classes/CustomSettings.py +++ b/source/classes/CustomSettings.py @@ -232,6 +232,14 @@ class CustomSettings(object): self.world_rep['settings'] = settings_dict for p in self.player_range: settings_dict[p] = {} + settings_dict[p]['ow_shuffle'] = world.owShuffle[p] + settings_dict[p]['ow_terrain'] = world.owTerrain[p] + settings_dict[p]['ow_crossed'] = world.owCrossed[p] + settings_dict[p]['ow_keepsimilar'] = world.owKeepSimilar[p] + settings_dict[p]['ow_mixed'] = world.owMixed[p] + settings_dict[p]['ow_whirlpool'] = world.owWhirlpoolShuffle[p] + settings_dict[p]['ow_fluteshuffle'] = world.owFluteShuffle[p] + settings_dict[p]['bonk_drops'] = world.shuffle_bonk_drops[p] settings_dict[p]['shuffle'] = world.shuffle[p] settings_dict[p]['door_shuffle'] = world.doorShuffle[p] settings_dict[p]['intensity'] = world.intensity[p] @@ -329,6 +337,15 @@ class CustomSettings(object): else: placements[location.player][location.name] = location.item.name + def record_overworld(self, world): + self.world_rep['ow-tileflips'] = flips = {} + for p in self.player_range: + if p in world.owswaps and len(world.owswaps[p][0]) > 0: + flips[p] = {} + flips[p]['force_flip'] = list(f for f in world.owswaps[p][0] if f < 0x40 or f >= 0x80) + flips[p]['force_flip'].sort() + flips[p]['undefined_chance'] = 0 + def record_entrances(self, world): self.world_rep['entrances'] = entrances = {} world.custom_entrances = {} From 63c9b986f3feb7e26be000f30edab1bfacc58f3d Mon Sep 17 00:00:00 2001 From: codemann8 Date: Fri, 7 Jul 2023 03:42:23 -0500 Subject: [PATCH 141/196] Removing Bat Cave Screen Wrap from logic per v31 logic --- OverworldGlitchRules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OverworldGlitchRules.py b/OverworldGlitchRules.py index 715bbc41..0e05246d 100644 --- a/OverworldGlitchRules.py +++ b/OverworldGlitchRules.py @@ -383,7 +383,7 @@ boots_clips_local = [ # (name, from_region, to_region) ('Hyrule Castle To Water Clip', 'Hyrule Castle Area', 'Hyrule Castle Water'), #fake flipper - ('Bat Cave River Clip Spot', 'Blacksmith Area', 'Blacksmith Ledge'), #cannot guarantee camera correction + #('Bat Cave River Clip Spot', 'Blacksmith Area', 'Blacksmith Ledge'), #TODO: This should be added in MG (screenwrap transition) ('Maze Race Item Get Ledge Clip', 'Maze Race Area', 'Maze Race Prize'), From f3fd86e10e28fda9c4d73dab23a6b57322288823 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Fri, 7 Jul 2023 04:02:59 -0500 Subject: [PATCH 142/196] Add seed number to spoiler metadata --- BaseClasses.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/BaseClasses.py b/BaseClasses.py index 8b25f61c..57472ad9 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -2898,7 +2898,8 @@ class Spoiler(object): 'triforcegoal': self.world.treasure_hunt_count, 'triforcepool': self.world.treasure_hunt_total, 'race': self.world.settings.world_rep['meta']['race'], - 'code': {p: Settings.make_code(self.world, p) for p in range(1, self.world.players + 1)} + 'code': {p: Settings.make_code(self.world, p) for p in range(1, self.world.players + 1)}, + 'seed': self.world.seed } for p in range(1, self.world.players + 1): From 5ca25223866e14dd89b59a846ef314ad90453722 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Fri, 7 Jul 2023 04:15:05 -0500 Subject: [PATCH 143/196] Version bump 0.3.1.2 --- CHANGELOG.md | 6 ++++++ OverworldShuffle.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d9a8e76..25fa22be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 0.3.1.2 +- Retro now gives a universal key from bottle vendor fish prize +- Fixed issue with Aga Door preventing Murahduhla Cutscene +- Fixed issue with Ice Cave/Shopping Mall water transitions not flipping in Mixed OWR +- Minor improvements to item GFX draw routine + ## 0.3.1.1 - \~Merged in DR v1.2.0.17~ - Various renames/reorganizations of region/rule definition to match upcoming DR world remodel diff --git a/OverworldShuffle.py b/OverworldShuffle.py index cf18f4c6..4a1f38a4 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -7,7 +7,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType from OverworldGlitchRules import create_owg_connections from Utils import bidict -version_number = '0.3.1.1' +version_number = '0.3.1.2' # branch indicator is intentionally different across branches version_branch = '-u' From 0c640bf9dd252fa98a7723d8359a9066208c81ce Mon Sep 17 00:00:00 2001 From: aerinon Date: Mon, 10 Jul 2023 10:35:18 -0600 Subject: [PATCH 144/196] Fix for pyrmaid hole logic --- Main.py | 2 +- RELEASENOTES.md | 3 +++ Rules.py | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Main.py b/Main.py index 107b0694..e3f3df67 100644 --- a/Main.py +++ b/Main.py @@ -34,7 +34,7 @@ from source.overworld.EntranceShuffle2 import link_entrances_new from source.tools.BPS import create_bps_from_data from source.classes.CustomSettings import CustomSettings -version_number = '1.2.0.17' +version_number = '1.2.0.18' version_branch = '-u' __version__ = f'{version_number}{version_branch}' diff --git a/RELEASENOTES.md b/RELEASENOTES.md index e3d09589..a1013f6c 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -109,6 +109,9 @@ These are now independent of retro mode and have three options: None, Random, an # Bug Fixes and Notes +* 1.2.0.18u + * Fixed an issue with pyramid hole being in logic when it is not opened. + * * 1.2.0.17u * Fixed logic bug that allowed Pearl to be behind Graveyard Cave or King's Tomb entrances with only Mirror and West Dark World access (cross world shuffles only) * Removed backup locations for Dungeon Only and Major Only algorithms. If item cannot be placed in the appropriate location, the seed will fail to generate instead diff --git a/Rules.py b/Rules.py index 80392396..26e70f5f 100644 --- a/Rules.py +++ b/Rules.py @@ -887,7 +887,7 @@ def ow_inverted_rules(world, player): set_rule(world.get_entrance('Hyrule Castle Main Gate', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Hyrule Castle Main Gate (North)', player), lambda state: state.has_Mirror(player)) set_rule(world.get_location('Frog', player), lambda state: state.can_lift_heavy_rocks(player) and state.has_Pearl(player)) - set_rule(world.get_entrance('Pyramid Hole', player), lambda state: world.open_pyramid[player] or world.goal[player] == 'trinity' or state.has('Beat Agahnim 2', player)) + set_rule(world.get_entrance('Pyramid Hole', player), lambda state: world.is_pyramid_open(player) or state.has('Beat Agahnim 2', player)) else: set_rule(world.get_entrance('East Dark Death Mountain Teleporter (Top)', player), lambda state: state.can_lift_heavy_rocks(player) and state.has('Hammer', player) and state.has_Pearl(player)) # bunny cannot use hammer set_rule(world.get_entrance('East Dark Death Mountain Teleporter (Bottom)', player), lambda state: state.can_lift_heavy_rocks(player)) From 5d2ceaf75c22522a9cb15b45760e907d4df582cf Mon Sep 17 00:00:00 2001 From: aerinon Date: Mon, 10 Jul 2023 13:56:05 -0600 Subject: [PATCH 145/196] Updated baserom for crystal custscene and hera music fix Updated a couple of error messages and when they are displayed Updated Ganonhunt goal text to be more consistent across randomizers --- ItemList.py | 3 ++- Main.py | 4 +++- README.md | 2 +- RELEASENOTES.md | 7 +++++-- Rom.py | 2 +- data/base2current.bps | Bin 94044 -> 94169 bytes resources/app/gui/lang/en.json | 2 +- 7 files changed, 13 insertions(+), 7 deletions(-) diff --git a/ItemList.py b/ItemList.py index b9e3f4c8..a44a3f6e 100644 --- a/ItemList.py +++ b/ItemList.py @@ -1287,7 +1287,8 @@ def make_customizer_pool(world, player): bow_found = next((i for i in pool if i in {'Bow', 'Progressive Bow'}), None) if not bow_found: missing_items.append('Progressive Bow') - logging.getLogger('').warning(f'The following items are not in the custom item pool {", ".join(missing_items)}') + if missing_items: + logging.getLogger('').warning(f'The following items are not in the custom item pool {", ".join(missing_items)}') g, t = set_default_triforce(world.goal[player], world.treasure_hunt_count[player], world.treasure_hunt_total[player]) diff --git a/Main.py b/Main.py index e3f3df67..2edf2c03 100644 --- a/Main.py +++ b/Main.py @@ -628,7 +628,9 @@ def create_playthrough(world): logging.getLogger('').debug(world.fish.translate("cli", "cli", "building.calculating.spheres"), len(collection_spheres), len(sphere), len(prog_locations)) if not sphere: - logging.getLogger('').error(world.fish.translate("cli", "cli", "cannot.reach.items"), [world.fish.translate("cli","cli","cannot.reach.item") % (location.item.name, location.item.player, location.name, location.player) for location in sphere_candidates]) + if world.accessibility[location.item.player] != 'none': + logging.getLogger('').error(world.fish.translate("cli", "cli", "cannot.reach.items"), + [world.fish.translate("cli","cli","cannot.reach.item") % (location.item.name, location.item.player, location.name, location.player) for location in sphere_candidates]) if any([location.name not in optional_locations and world.accessibility[location.item.player] != 'none' for location in sphere_candidates]): raise RuntimeError(world.fish.translate("cli", "cli", "cannot.reach.progression")) else: diff --git a/README.md b/README.md index fbe9eed5..21a444cc 100644 --- a/README.md +++ b/README.md @@ -404,7 +404,7 @@ CLI: `--logic owglitches` New supported goals: * Trinity: Find one of 3 triforces to win. One is at pedestal. One is with Ganon. One is with Murahdahla who wants you to find 8 of 10 triforce pieces to complete. -* Triforce Hunt + Ganon: Collect the requisite triforce pieces, then defeat Ganon. (Aga2 not required). Use `ganonhunt` on CLI +* Ganonhunt: Collect the requisite triforce pieces, then defeat Ganon. (Aga2 not required). Use `ganonhunt` on CLI * Completionist: All dungeons not enough for you? You have to obtain every item in the game too. This option turns on the collection rate counter and forces accessibility to be 100% locations. Finish by defeating Ganon. diff --git a/RELEASENOTES.md b/RELEASENOTES.md index a1013f6c..5dc0ee0a 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -57,7 +57,7 @@ Please see [Customizer documentation](docs/Customizer.md) on how to create custo ## New Goals -### Triforce Hunt + Ganon +### Ganonhunt Collect the requisite triforce pieces, then defeat Ganon. (Aga2 not required). Use `ganonhunt` on CLI ### Completionist @@ -111,7 +111,10 @@ These are now independent of retro mode and have three options: None, Random, an * 1.2.0.18u * Fixed an issue with pyramid hole being in logic when it is not opened. - * + * Crystal cutscene at GT use new symmetrical layouts (thanks Codemann) + * Fix for Hera Boss music (thanks Codemann) + * Fixed accessibility: none using a spoiling message + * Fixed warning message about custom item pool when it is fine * 1.2.0.17u * Fixed logic bug that allowed Pearl to be behind Graveyard Cave or King's Tomb entrances with only Mirror and West Dark World access (cross world shuffles only) * Removed backup locations for Dungeon Only and Major Only algorithms. If item cannot be placed in the appropriate location, the seed will fail to generate instead diff --git a/Rom.py b/Rom.py index ea0b9c68..482080b2 100644 --- a/Rom.py +++ b/Rom.py @@ -37,7 +37,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '9903cdfc3fc69112919ec49fb63e09ab' +RANDOMIZERBASEHASH = '467681d6160233f7af2761c631e26985' class JsonRom(object): diff --git a/data/base2current.bps b/data/base2current.bps index e58c28ab1b469f73a96a04d2e5d5d50a2ca92b26..9b3d673a51005eba1d3d336d10206d582cb1852b 100644 GIT binary patch delta 8191 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 delta 8271 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°`X4)5(K{T}vV8Q!2ldJX#&(odD~x(*$f+FJ%jrb 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 WZ`*gx12YFmOGf(@j^A=;)c*lzQAw!) diff --git a/resources/app/gui/lang/en.json b/resources/app/gui/lang/en.json index eb53f640..9d56137c 100644 --- a/resources/app/gui/lang/en.json +++ b/resources/app/gui/lang/en.json @@ -241,7 +241,7 @@ "randomizer.item.goal.triforcehunt": "Triforce Hunt", "randomizer.item.goal.trinity": "Trinity", "randomizer.item.goal.crystals": "Crystals", - "randomizer.item.goal.ganonhunt": "Triforce Hunt + Ganon", + "randomizer.item.goal.ganonhunt": "Ganonhunt", "randomizer.item.goal.completionist": "Completionist", "randomizer.item.crystals_gt": "Crystals to open GT", From ccbbe93d63a264f333fb45ba2d402ee04c163967 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Tue, 11 Jul 2023 13:05:20 -0500 Subject: [PATCH 146/196] Changing retro so bottle vendor fish prize gives a key instead of arrows Fixed issue where all other narrow OW items drew 4 pixels to the left --- Rom.py | 2 +- data/base2current.bps | Bin 107720 -> 107724 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Rom.py b/Rom.py index c21832e0..712fb0d4 100644 --- a/Rom.py +++ b/Rom.py @@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '614fa2fcbb4644beddadcf356e121d5a' +RANDOMIZERBASEHASH = '32f6a9f479f6ccb7e66e9906ff0d0e4c' class JsonRom(object): diff --git a/data/base2current.bps b/data/base2current.bps index 99b8b7507ad96bcc7ec31a11eb97881f656b9117..e6c9ca6b873b6a541a4d4ea1ae46662dbaf01546 100644 GIT binary patch delta 237 zcmVPP+fGxcs4wo4kjiK-&rJ%_m0nh}OOFs#K zmmwX36@btLr5o^=8|ZaNKu)VLNkzw2mnx; zU%8iaP}+$I08*PUm(M@}fCp7~7=R0a6qi;(0VEwWRokZ$Q`?gbHv63qfC8x>jSE5t nrYuL@UloH;x0gWyr3wZrP7HvbQMW=&0e)Br0M$?5kX-?Pcm`Z2 delta 233 zcmV1F2P)|33jJE;*$JN{|bw0050Oz>PP+fGNEo4wo4kjiK-!rJ%_m0q_@=M-H!- zUtJ7<1%S|(SwI0Z0Zf;TKmi^oZv&r`dfuB6m67I>=8|ZaNKu)Vd_us92mnx;U%8ia zP}+$I08*PMm(xH2fCo)?7=R0a43}C#0VEwORokZuQ`?gTHv63qfC8x>jSE5trYuL@ jZxw?`x0^u$r3wZjP7HvbNw-E!0e)Br6UEG+fN^KZOv_v- From d135405ed3bb76bd68d16e20ac1235eb65294129 Mon Sep 17 00:00:00 2001 From: aerinon Date: Wed, 12 Jul 2023 09:16:00 -0600 Subject: [PATCH 147/196] Customizer: Exception raised for placements of items that are not in pool --- ItemList.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ItemList.py b/ItemList.py index a44a3f6e..5ffb5152 100644 --- a/ItemList.py +++ b/ItemList.py @@ -1397,6 +1397,8 @@ def fill_specific_items(world): track_dungeon_items(item_to_place, loc, world) loc.event = (event_flag or item_to_place.advancement or item_to_place.bigkey or item_to_place.smallkey) + else: + raise Exception(f'Did not find "{item}" in item pool to place at "{location}"') advanced_placements = world.customizer.get_advanced_placements() if advanced_placements: for player, placement_list in advanced_placements.items(): @@ -1406,7 +1408,7 @@ def fill_specific_items(world): item_to_place, event_flag = get_item_and_event_flag(item, world, player, dungeon_pool, prize_set, prize_pool) if not item_to_place: - continue + raise Exception(f'Did not find "{item}" in item pool to place for a LocationGroup"') locations = placement['locations'] handled = False while not handled: From 1b81151941eca3fb963e010b1bb023ead6ed262d Mon Sep 17 00:00:00 2001 From: aerinon Date: Wed, 12 Jul 2023 09:50:53 -0600 Subject: [PATCH 148/196] Customizer: Fixed issue with Assured sword and start inventory --- ItemList.py | 31 +++++++++++++++++-------------- RELEASENOTES.md | 4 +++- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/ItemList.py b/ItemList.py index 5ffb5152..168d841d 100644 --- a/ItemList.py +++ b/ItemList.py @@ -1297,20 +1297,23 @@ def make_customizer_pool(world, player): if pieces < t: pool.extend(['Triforce Piece'] * (t - pieces)) - if not world.customizer.get_start_inventory(): - if world.logic[player] in ['owglitches', 'nologic']: - precollected_items.append('Pegasus Boots') - if 'Pegasus Boots' in pool: - pool.remove('Pegasus Boots') - pool.append('Rupees (20)') - if world.swords[player] == 'assured': - precollected_items.append('Progressive Sword') - if 'Progressive Sword' in pool: - pool.remove('Progressive Sword') - pool.append('Rupees (50)') - elif 'Fighter Sword' in pool: - pool.remove('Fighter Sword') - pool.append('Rupees (50)') + sphere_0 = world.customizer.get_start_inventory() + no_start_inventory = not sphere_0 or not sphere_0[player] + init_equip = [] if no_start_inventory else sphere_0[player] + if (world.logic[player] in ['owglitches', 'nologic'] + and (no_start_inventory or all(x != 'Pegasus Boots' for x in init_equip))): + precollected_items.append('Pegasus Boots') + if 'Pegasus Boots' in pool: + pool.remove('Pegasus Boots') + pool.append('Rupees (20)') + if world.swords[player] == 'assured' and (no_start_inventory or all(' Sword' not in x for x in init_equip)): + precollected_items.append('Progressive Sword') + if 'Progressive Sword' in pool: + pool.remove('Progressive Sword') + pool.append('Rupees (50)') + elif 'Fighter Sword' in pool: + pool.remove('Fighter Sword') + pool.append('Rupees (50)') return pool, placed_items, precollected_items, clock_mode, 1 diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 5dc0ee0a..5f11c963 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -113,7 +113,9 @@ These are now independent of retro mode and have three options: None, Random, an * Fixed an issue with pyramid hole being in logic when it is not opened. * Crystal cutscene at GT use new symmetrical layouts (thanks Codemann) * Fix for Hera Boss music (thanks Codemann) - * Fixed accessibility: none using a spoiling message + * Customizer: fixed an issue with assured sword and start_inventory + * Customizer: warns when trying to specifically place an item that's not in the item pool + * Fixed "accessibility: none" displaying a spoiling message * Fixed warning message about custom item pool when it is fine * 1.2.0.17u * Fixed logic bug that allowed Pearl to be behind Graveyard Cave or King's Tomb entrances with only Mirror and West Dark World access (cross world shuffles only) From e0bf8227fb327922524f98cbd3046169fcda23c6 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 12 Jul 2023 20:05:47 -0500 Subject: [PATCH 149/196] Fixed issue with flipper rules not getting pearl rules added --- Rules.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Rules.py b/Rules.py index 2cd92599..16ba3eb8 100644 --- a/Rules.py +++ b/Rules.py @@ -26,18 +26,6 @@ def set_rules(world, player): if world.swords[player] == 'swordless': swordless_rules(world, player) - ow_bunny_rules(world, player) - ow_terrain_rules(world, player) - - if world.mode[player] == 'standard': - if not world.is_copied_world: - standard_rules(world, player) - else: - misc_key_rules(world, player) - - bomb_rules(world, player) - pot_rules(world, player) - if world.logic[player] == 'noglitches': no_glitches_rules(world, player) elif world.logic[player] == 'minorglitches': @@ -54,6 +42,18 @@ def set_rules(world, player): else: raise NotImplementedError('Not implemented yet') + ow_bunny_rules(world, player) + ow_terrain_rules(world, player) + + if world.mode[player] == 'standard': + if not world.is_copied_world: + standard_rules(world, player) + else: + misc_key_rules(world, player) + + bomb_rules(world, player) + pot_rules(world, player) + if world.goal[player] == 'dungeons': # require all dungeons to beat ganon add_rule(world.get_location('Ganon', player), lambda state: state.can_reach('Master Sword Pedestal', 'Location', player) and state.has_beaten_aga(player) and state.has('Beat Agahnim 2', player) and state.has_crystals(7, player)) From 119e2895125b8136c4f4104405a8df5521c8a830 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 13 Jul 2023 16:53:15 -0500 Subject: [PATCH 150/196] Fixed issue with non crossworld ER modes not clearing out entrances from previous attempts --- source/overworld/EntranceShuffle2.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index 89c6b0c0..ccf94a4f 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -69,6 +69,8 @@ def link_entrances_new(world, player): avail_pool.one_way_map = one_way_map global LW_Entrances, DW_Entrances + LW_Entrances = [] + DW_Entrances = [] for e in [e for e in avail_pool.entrances if e not in drop_map]: region = world.get_entrance(e, player).parent_region if region.type == RegionType.LightWorld: From c2ec7c7491aae00d7297bec7cf2e54890163060d Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 13 Jul 2023 23:26:57 -0500 Subject: [PATCH 151/196] Fixed a bad merge causing LH on mountain to not place a connector --- source/overworld/EntranceShuffle2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index ccf94a4f..800eab80 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -515,7 +515,7 @@ def do_links_house(entrances, exits, avail, cross_world): dark_sanc_region = avail.world.get_entrance('Dark Sanctuary Hint Exit', avail.player).connected_region.name forbidden.extend(get_nearby_entrances(avail, dark_sanc_region)) shuffle_mode = avail.world.shuffle[avail.player] - if shuffle_mode == 'vanilla': + if avail.world.owShuffle[avail.player] == 'vanilla': # simple shuffle - if shuffle_mode == 'simple': avail.links_on_mountain = True # taken care of by the logic below From 84ecf22142646a820dc5532096a1050af523e70d Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 16 Jul 2023 00:26:12 -0500 Subject: [PATCH 152/196] Disabling "LH on mountain" connector Due to bug found/fixed in previous commit, it was found this was effectively disabled anyways for many months, seemingly without issue --- source/overworld/EntranceShuffle2.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index 800eab80..6dd111d7 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -570,6 +570,8 @@ def do_links_house(entrances, exits, avail, cross_world): if links_house in dm_spots and avail.world.owShuffle[avail.player] == 'vanilla': if avail.links_on_mountain: return # connector is fine + logging.getLogger('').warning(f'Links House is placed in tight area and is now unhandled. Report any errors that occur from here.') + return if avail.world.shuffle[avail.player] in ['lite', 'lean']: rem_exits = [e for e in avail.exits if e in Connector_Exit_Set and e not in Dungeon_Exit_Set] multi_exit_caves = figure_out_connectors(rem_exits) From 4f1bad25105ba24b98b4a3a98af4a7026786c597 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 16 Jul 2023 00:51:16 -0500 Subject: [PATCH 153/196] Adding missing code that allows Sanc spawn to be placed in DW in Lean ER --- Doors.py | 2 +- DungeonGenerator.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doors.py b/Doors.py index 4020caff..751b2d4c 100644 --- a/Doors.py +++ b/Doors.py @@ -1499,7 +1499,7 @@ def create_doors(world, player): # static portal flags world.get_door('Sanctuary S', player).dead_end(allowPassage=True) - if world.mode[player] == 'open' and world.shuffle[player] not in ['crossed', 'insanity']: + if world.mode[player] == 'open' and world.shuffle[player] not in ['lean', 'crossed', 'insanity']: world.get_door('Sanctuary S', player).lw_restricted = True world.get_door('Eastern Hint Tile Blocked Path SE', player).passage = False world.get_door('TR Big Chest Entrance SE', player).passage = False diff --git a/DungeonGenerator.py b/DungeonGenerator.py index 2056fe4c..b3602680 100644 --- a/DungeonGenerator.py +++ b/DungeonGenerator.py @@ -1360,7 +1360,7 @@ def create_dungeon_builders(all_sectors, connections_tuple, world, player, dunge for name, builder in dungeon_map.items(): calc_allowance_and_dead_ends(builder, connections_tuple, world, player) - if world.mode[player] == 'open' and world.shuffle[player] not in ['crossed', 'insanity']: + if world.mode[player] == 'open' and world.shuffle[player] not in ['lean', 'crossed', 'insanity']: sanc = find_sector('Sanctuary', candidate_sectors) if sanc: # only run if sanc if a candidate lw_builders = [] From 4f5d268401ec3e3cb96f5f9abd4da89bc709614e Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 16 Jul 2023 01:04:34 -0500 Subject: [PATCH 154/196] Adding new Swapped ER mode option --- BaseClasses.py | 4 +- Doors.py | 2 +- DungeonGenerator.py | 2 +- ItemList.py | 2 +- OverworldShuffle.py | 2 +- Rom.py | 2 +- Rules.py | 2 +- TestSuite.py | 3 + TestSuiteStat.py | 4 +- mystery_example.yml | 1 + mystery_testsuite.yml | 3 + resources/app/cli/args.json | 1 + resources/app/cli/lang/en.json | 1 + resources/app/gui/lang/en.json | 1 + .../app/gui/randomize/entrando/widgets.json | 1 + source/overworld/EntranceShuffle2.py | 239 ++++++++++++++++-- 16 files changed, 238 insertions(+), 32 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index 57472ad9..099d4d53 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -132,7 +132,7 @@ class World(object): set_player_attr('can_access_trock_big_chest', None) set_player_attr('can_access_trock_middle', None) set_player_attr('fix_fake_world', logic[player] not in ['owglitches', 'nologic'] - or shuffle[player] in ['lean', 'crossed', 'insanity']) + or shuffle[player] in ['lean', 'swapped', 'crossed', 'insanity']) set_player_attr('mapshuffle', False) set_player_attr('compassshuffle', False) set_player_attr('keyshuffle', 'none') @@ -3395,7 +3395,7 @@ class Pot(object): # byte 0: DDDE EEEE (DR, ER) dr_mode = {"basic": 1, "crossed": 2, "vanilla": 0, "partitioned": 3} er_mode = {"vanilla": 0, "simple": 1, "restricted": 2, "full": 3, "crossed": 4, "insanity": 5, 'lite': 8, - 'lean': 9, "dungeonsfull": 7, "dungeonssimple": 6} + 'lean': 9, "dungeonsfull": 7, "dungeonssimple": 6, "swapped": 10} # byte 1: LLLW WSS? (logic, mode, sword) logic_mode = {"noglitches": 0, "minorglitches": 1, "nologic": 2, "owglitches": 3, "majorglitches": 4} diff --git a/Doors.py b/Doors.py index 751b2d4c..8ba20e40 100644 --- a/Doors.py +++ b/Doors.py @@ -1499,7 +1499,7 @@ def create_doors(world, player): # static portal flags world.get_door('Sanctuary S', player).dead_end(allowPassage=True) - if world.mode[player] == 'open' and world.shuffle[player] not in ['lean', 'crossed', 'insanity']: + if world.mode[player] == 'open' and world.shuffle[player] not in ['lean', 'swapped', 'crossed', 'insanity']: world.get_door('Sanctuary S', player).lw_restricted = True world.get_door('Eastern Hint Tile Blocked Path SE', player).passage = False world.get_door('TR Big Chest Entrance SE', player).passage = False diff --git a/DungeonGenerator.py b/DungeonGenerator.py index b3602680..3e67fa67 100644 --- a/DungeonGenerator.py +++ b/DungeonGenerator.py @@ -1360,7 +1360,7 @@ def create_dungeon_builders(all_sectors, connections_tuple, world, player, dunge for name, builder in dungeon_map.items(): calc_allowance_and_dead_ends(builder, connections_tuple, world, player) - if world.mode[player] == 'open' and world.shuffle[player] not in ['lean', 'crossed', 'insanity']: + if world.mode[player] == 'open' and world.shuffle[player] not in ['lean', 'swapped', 'crossed', 'insanity']: sanc = find_sector('Sanctuary', candidate_sectors) if sanc: # only run if sanc if a candidate lw_builders = [] diff --git a/ItemList.py b/ItemList.py index 01b95d68..bb23ecec 100644 --- a/ItemList.py +++ b/ItemList.py @@ -964,7 +964,7 @@ def balance_prices(world, player): def check_hints(world, player): - if world.shuffle[player] in ['simple', 'restricted', 'full', 'lite', 'lean', 'crossed', 'insanity']: + if world.shuffle[player] in ['simple', 'restricted', 'full', 'lite', 'lean', 'swapped', 'crossed', 'insanity']: for shop, location_list in shop_to_location_table.items(): if shop in ['Capacity Upgrade', 'Paradox Shop', 'Potion Shop']: continue # near the queen, near potions, and near 7 chests are fine diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 4a1f38a4..d95b2cb8 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -705,7 +705,7 @@ def shuffle_tiles(world, groups, result_list, do_grouped, player): attempts -= 1 continue # ensure sanc can be placed in LW in certain modes - if not do_grouped and world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull', 'lean', 'crossed', 'insanity'] and world.mode[player] != 'inverted' and (world.doorShuffle[player] != 'crossed' or world.intensity[player] < 3 or world.mode[player] == 'standard'): + if not do_grouped and world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull', 'lean', 'swapped', 'crossed', 'insanity'] and world.mode[player] != 'inverted' and (world.doorShuffle[player] != 'crossed' or world.intensity[player] < 3 or world.mode[player] == 'standard'): free_dw_drops = parity[5] + (1 if world.shuffle_ganon else 0) free_drops = 6 + (1 if world.mode[player] != 'standard' else 0) + (1 if world.shuffle_ganon else 0) if free_dw_drops == free_drops: diff --git a/Rom.py b/Rom.py index 712fb0d4..a19ff73c 100644 --- a/Rom.py +++ b/Rom.py @@ -1661,7 +1661,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): # rom.write_byte(snes_to_pc(0x0DB730), 0x08) # allows chickens to travel across water # allow smith into multi-entrance caves in appropriate shuffles - if world.shuffle[player] in ['restricted', 'full', 'lite', 'lean', 'crossed', 'insanity'] or (world.shuffle[player] == 'simple' and world.mode[player] == 'inverted'): + if world.shuffle[player] in ['restricted', 'full', 'lite', 'lean', 'swapped', 'crossed', 'insanity'] or (world.shuffle[player] == 'simple' and world.mode[player] == 'inverted'): rom.write_byte(0x18004C, 0x01) # set correct flag for hera basement item diff --git a/Rules.py b/Rules.py index 16ba3eb8..f1383ee6 100644 --- a/Rules.py +++ b/Rules.py @@ -989,7 +989,7 @@ def ow_inverted_rules(world, player): else: set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has('Cape', player) or state.has_beam_sword(player)) # barrier gets removed after killing agahnim, rule for that added later set_rule(world.get_entrance('GT Approach', player), lambda state: state.has_crystals(world.crystals_needed_for_gt[player], player)) - set_rule(world.get_entrance('GT Leave', player), lambda state: state.has_crystals(world.crystals_needed_for_gt[player], player) or state.world.shuffle[player] in ('restricted', 'full', 'lite', 'lean', 'crossed', 'insanity')) + set_rule(world.get_entrance('GT Leave', player), lambda state: state.has_crystals(world.crystals_needed_for_gt[player], player) or state.world.shuffle[player] in ('restricted', 'full', 'lite', 'lean', 'swapped', 'crossed', 'insanity')) if world.is_tile_swapped(0x03, player): set_rule(world.get_entrance('Spectacle Rock Approach', player), lambda state: world.logic[player] in ['noglitches', 'minorglitches'] and state.has_Pearl(player)) diff --git a/TestSuite.py b/TestSuite.py index 355c1883..9c2f29d0 100644 --- a/TestSuite.py +++ b/TestSuite.py @@ -49,6 +49,9 @@ def main(args=None): test("Shopsanity", "--shuffle vanilla --shopsanity") test("Simple ", "--shuffle simple") test("Full ", "--shuffle full") + test("Lite ", "--shuffle lite") + test("Lean ", "--shuffle lean") + test("Swapped ", "--shuffle swapped") test("Crossed ", "--shuffle crossed") test("Insanity ", "--shuffle insanity") test("OWG ", "--logic owglitches") diff --git a/TestSuiteStat.py b/TestSuiteStat.py index 92d066c6..ecde323d 100644 --- a/TestSuiteStat.py +++ b/TestSuiteStat.py @@ -14,7 +14,7 @@ ALL_SETTINGS = { 'mode': ['open', 'standard', 'inverted'], 'goal': ['ganon', 'pedestal', 'triforcehunt', 'trinity', 'crystals', 'dungeons'], 'swords': ['random', 'swordless', 'assured'], - 'shuffle': ['vanilla','simple','restricted','full','dungeonssimple','dungeonsfull','lite','lean','crossed','insanity'], + 'shuffle': ['vanilla','simple','restricted','full','dungeonssimple','dungeonsfull','lite','lean','swapped','crossed','insanity'], 'shufflelinks': [True, False], 'shuffleganon': [True, False], 'door_shuffle': ['vanilla', 'basic', 'crossed'], @@ -39,7 +39,7 @@ SETTINGS = { 'goal': ['ganon'], 'swords': ['random'], 'shuffle': ['vanilla', - 'dungeonssimple', 'dungeonsfull', 'simple', 'restricted', 'full', 'lite', 'lean', 'crossed', 'insanity' + 'dungeonssimple', 'dungeonsfull', 'simple', 'restricted', 'full', 'lite', 'lean', 'swapped', 'crossed', 'insanity' ], 'shufflelinks': [True, False], 'shuffleganon': [True, False], diff --git a/mystery_example.yml b/mystery_example.yml index a74a8914..50ced9ab 100644 --- a/mystery_example.yml +++ b/mystery_example.yml @@ -91,6 +91,7 @@ full: 2 lite: 2 lean: 2 + swapped: 2 crossed: 3 insanity: 1 open_pyramid: diff --git a/mystery_testsuite.yml b/mystery_testsuite.yml index f919b7cc..7210fca6 100644 --- a/mystery_testsuite.yml +++ b/mystery_testsuite.yml @@ -56,6 +56,9 @@ entrance_shuffle: simple: 1 restricted: 1 full: 1 + lite: 1 + lean: 1 + swapped: 1 crossed: 1 insanity: 1 shufflelinks: diff --git a/resources/app/cli/args.json b/resources/app/cli/args.json index 9f0d2d77..8dca326f 100644 --- a/resources/app/cli/args.json +++ b/resources/app/cli/args.json @@ -209,6 +209,7 @@ "full", "lite", "lean", + "swapped", "crossed", "insanity", "dungeonsfull", diff --git a/resources/app/cli/lang/en.json b/resources/app/cli/lang/en.json index f76bf61b..26190a46 100644 --- a/resources/app/cli/lang/en.json +++ b/resources/app/cli/lang/en.json @@ -211,6 +211,7 @@ "Lean: Same as Lite, except connectors can travel cross worlds.", "Crossed: Mix cave and dungeon entrances freely while allowing", " caves to cross between worlds.", + "Swapped: Same as Crossed, but entrances switch places in pairs.", "Insanity: Decouple entrances and exits from each other and", " shuffle them freely. Caves that used to be single", " entrance will still exit to the same location from", diff --git a/resources/app/gui/lang/en.json b/resources/app/gui/lang/en.json index 284da304..8dd28803 100644 --- a/resources/app/gui/lang/en.json +++ b/resources/app/gui/lang/en.json @@ -179,6 +179,7 @@ "randomizer.entrance.entranceshuffle.restricted": "Restricted", "randomizer.entrance.entranceshuffle.full": "Full", "randomizer.entrance.entranceshuffle.lean": "Lean", + "randomizer.entrance.entranceshuffle.swapped": "Swapped", "randomizer.entrance.entranceshuffle.crossed": "Crossed", "randomizer.entrance.entranceshuffle.insanity": "Insanity", "randomizer.entrance.entranceshuffle.dungeonsfull": "Dungeons + Full", diff --git a/resources/app/gui/randomize/entrando/widgets.json b/resources/app/gui/randomize/entrando/widgets.json index a3104bf1..c325ea26 100644 --- a/resources/app/gui/randomize/entrando/widgets.json +++ b/resources/app/gui/randomize/entrando/widgets.json @@ -9,6 +9,7 @@ "full", "lite", "lean", + "swapped", "crossed", "insanity", "dungeonsfull", diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index 6dd111d7..b5de938d 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -12,6 +12,7 @@ class EntrancePool(object): self.exits = set() self.inverted = False self.coupled = True + self.swapped = False self.default_map = {} self.one_way_map = {} self.skull_handled = False @@ -91,6 +92,7 @@ def link_entrances_new(world, player): if mode not in modes: raise RuntimeError(f'Shuffle mode {mode} is not yet supported') mode_cfg = copy.deepcopy(modes[mode]) + avail_pool.swapped = mode_cfg['undefined'] == 'swap' if avail_pool.is_standard(): do_standard_connections(avail_pool) pool_list = mode_cfg['pools'] if 'pools' in mode_cfg else {} @@ -98,7 +100,10 @@ def link_entrances_new(world, player): special_shuffle = pool['special'] if 'special' in pool else None if special_shuffle == 'drops': holes, targets = find_entrances_and_targets_drops(avail_pool, pool['entrances']) - connect_random(holes, targets, avail_pool) + if avail_pool.swapped: + connect_swapped(holes, targets, avail_pool) + else: + connect_random(holes, targets, avail_pool) elif special_shuffle == 'normal_drops': cross_world = mode_cfg['cross_world'] == 'on' if 'cross_world' in mode_cfg else False keep_together = mode_cfg['keep_drops_together'] == 'on' if 'keep_drops_together' in mode_cfg else True @@ -131,7 +136,10 @@ def link_entrances_new(world, player): exits.remove('Skull Woods First Section Exit') connect_random(entrances, exits, avail_pool, True) entrances, exits = [rem_ent], ['Skull Woods First Section Exit'] - connect_random(entrances, exits, avail_pool, True) + if avail_pool.swapped: + connect_swapped(entrances, exits, avail_pool, True) + else: + connect_random(entrances, exits, avail_pool, True) avail_pool.skull_handled = True else: entrances, exits = find_entrances_and_exits(avail_pool, pool['entrances']) @@ -139,7 +147,7 @@ def link_entrances_new(world, player): undefined_behavior = mode_cfg['undefined'] if undefined_behavior == 'vanilla': do_vanilla_connections(avail_pool) - elif undefined_behavior == 'shuffle': + elif undefined_behavior in ['shuffle', 'swap']: do_main_shuffle(set(avail_pool.entrances), set(avail_pool.exits), avail_pool, mode_cfg) # afterward @@ -259,6 +267,8 @@ def do_main_shuffle(entrances, exits, avail, mode_def): rem_exits.update([x for item in multi_exit_caves for x in item if x in avail.exits]) rem_exits.update(exits) + if avail.swapped: + rem_exits = [x for x in rem_exits if x in avail.exits] # old man cave do_old_man_cave_exit(rem_entrances, rem_exits, avail, cross_world) @@ -273,9 +283,15 @@ def do_main_shuffle(entrances, exits, avail, mode_def): bomb_shop_options = [x for x in rem_entrances] if avail.world.is_tile_swapped(0x03, avail.player): bomb_shop_options = [x for x in bomb_shop_options if x not in ['Spectacle Rock Cave', 'Spectacle Rock Cave (Bottom)']] + if avail.swapped and len(bomb_shop_options) > 1: + bomb_shop_options = [x for x in bomb_shop_options if x != 'Big Bomb Shop'] bomb_shop_choice = random.choice(bomb_shop_options) connect_entrance(bomb_shop_choice, bomb_shop, avail) rem_entrances.remove(bomb_shop_choice) + if avail.swapped and bomb_shop_choice != 'Big Bomb Shop': + swap_ent, swap_ext = connect_swap(bomb_shop_choice, bomb_shop, avail) + rem_exits.remove(swap_ext) + rem_entrances.remove(swap_ent) if not avail.coupled: avail.decoupled_exits.remove(bomb_shop) rem_exits.remove(bomb_shop) @@ -283,6 +299,7 @@ def do_main_shuffle(entrances, exits, avail, mode_def): def bonk_fairy_exception(x): # (Bonk Fairy not eligible in standard) return not avail.is_standard() or x != 'Bonk Fairy (Light)' if not cross_world: + #TODO: Add Swapped ER support for this # OM Cave entrance in lw/dw if cross_world off if 'Old Man Cave Exit (West)' in rem_exits: world_limiter = DW_Entrances if avail.inverted else LW_Entrances @@ -333,12 +350,17 @@ def do_main_shuffle(entrances, exits, avail, mode_def): rem_entrances = list(unused_entrances) rem_entrances.sort() rem_exits = list(rem_exits if avail.coupled else avail.decoupled_exits) + if avail.swapped: + rem_exits = [x for x in rem_exits if x in avail.exits] rem_exits.sort() random.shuffle(rem_entrances) random.shuffle(rem_exits) placing = min(len(rem_entrances), len(rem_exits)) - for door, target in zip(rem_entrances, rem_exits): - connect_entrance(door, target, avail) + if avail.swapped: + connect_swapped(rem_entrances, rem_exits, avail) + else: + for door, target in zip(rem_entrances, rem_exits): + connect_entrance(door, target, avail) rem_entrances[:] = rem_entrances[placing:] rem_exits[:] = rem_exits[placing:] if rem_entrances or rem_exits: @@ -354,6 +376,8 @@ def do_old_man_cave_exit(entrances, exits, avail, cross_world): region_name = 'West Dark Death Mountain (Top)' om_cave_options = list(get_accessible_entrances(region_name, avail, [], cross_world, True, True, True)) om_cave_options = [e for e in om_cave_options if e in entrances and e != 'Old Man House (Bottom)'] + if avail.swapped: + om_cave_options = [e for e in om_cave_options if e not in Forbidden_Swap_Entrances] assert len(om_cave_options), 'No available entrances left to place Old Man Cave' random.shuffle(om_cave_options) om_cave_choice = None @@ -368,6 +392,10 @@ def do_old_man_cave_exit(entrances, exits, avail, cross_world): else: connect_two_way(om_cave_choice, 'Old Man Cave Exit (East)', avail) entrances.remove(om_cave_choice) + if avail.swapped and om_cave_choice != 'Old Man Cave (East)': + swap_ent, swap_ext = connect_swap(om_cave_choice, 'Old Man Cave Exit (East)', avail) + entrances.remove(swap_ent) + exits.remove(swap_ext) exits.remove('Old Man Cave Exit (East)') @@ -392,10 +420,17 @@ def do_blacksmith(entrances, exits, avail): blacksmith_options = list(OrderedDict.fromkeys(blacksmith_options + list(get_accessible_entrances(sanc_region.name, avail, assumed_inventory, False, True, True)))) else: logging.getLogger('').warning('Blacksmith is unable to use Sanctuary S&Q as initial accessibility because Sanctuary Exit has not been placed yet') + + if avail.swapped: + blacksmith_options = [e for e in blacksmith_options if e not in Forbidden_Swap_Entrances] blacksmith_options = [x for x in blacksmith_options if x in entrances] blacksmith_choice = random.choice(blacksmith_options) connect_entrance(blacksmith_choice, 'Blacksmiths Hut', avail) entrances.remove(blacksmith_choice) + if avail.swapped and blacksmith_choice != 'Blacksmiths Hut': + swap_ent, swap_ext = connect_swap(blacksmith_choice, 'Blacksmiths Hut', avail) + entrances.remove(swap_ent) + exits.remove(swap_ext) if not avail.coupled: avail.decoupled_exits.remove('Blacksmiths Hut') exits.remove('Blacksmiths Hut') @@ -452,11 +487,20 @@ def do_holes_and_linked_drops(entrances, exits, avail, cross_world, keep_togethe random.shuffle(hole_entrances) if not cross_world and 'Sanctuary Grave' in holes_to_shuffle: hc = avail.world.get_entrance('Hyrule Castle Exit (South)', avail.player) + is_hc_in_dw = avail.world.mode[avail.player] == 'inverted' + if hc.connected_region: + is_hc_in_dw = hc.connected_region.type == RegionType.DarkWorld chosen_entrance = None - if hc.connected_region and hc.connected_region.type == RegionType.DarkWorld: - chosen_entrance = next(entrance for entrance in hole_entrances if entrance[0] in DW_Entrances) + if is_hc_in_dw: + if avail.swapped: + chosen_entrance = next(e for e in hole_entrances if e[0] in DW_Entrances and e[0] != 'Sanctuary') + if not chosen_entrance: + chosen_entrance = next(e for e in hole_entrances if e[0] in DW_Entrances) if not chosen_entrance: - chosen_entrance = next(entrance for entrance in hole_entrances if entrance[0] in LW_Entrances) + if avail.swapped: + chosen_entrance = next(e for e in hole_entrances if e[0] in LW_Entrances and e[0] != 'Sanctuary') + if not chosen_entrance: + chosen_entrance = next(e for e in hole_entrances if e[0] in LW_Entrances) if chosen_entrance: hole_entrances.remove(chosen_entrance) sanc_interior = next(target for target in hole_targets if target[0] == 'Sanctuary Exit') @@ -465,14 +509,33 @@ def do_holes_and_linked_drops(entrances, exits, avail, cross_world, keep_togethe connect_entrance(chosen_entrance[1], sanc_interior[1], avail) # hole remove_from_list(entrances, [chosen_entrance[0], chosen_entrance[1]]) remove_from_list(exits, [sanc_interior[0], sanc_interior[1]]) + if avail.swapped and drop_map[chosen_entrance[1]] != sanc_interior[1]: + swap_ent, swap_ext = connect_swap(chosen_entrance[0], sanc_interior[0], avail) + swap_drop, swap_tgt = connect_swap(chosen_entrance[1], sanc_interior[1], avail) + hole_entrances.remove((swap_ent, swap_drop)) + hole_targets.remove((swap_ext, swap_tgt)) + remove_from_list(entrances, [swap_ent, swap_drop]) + remove_from_list(exits, [swap_ext, swap_tgt]) random.shuffle(hole_targets) - for entrance, drop in hole_entrances: - ext, target = hole_targets.pop() + while len(hole_entrances): + entrance, drop = hole_entrances.pop() + if avail.swapped and len(hole_targets) > 1: + ext, target = next((x, t) for x, t in hole_targets if x != entrance_map[entrance]) + hole_targets.remove((ext, target)) + else: + ext, target = hole_targets.pop() connect_two_way(entrance, ext, avail) connect_entrance(drop, target, avail) remove_from_list(entrances, [entrance, drop]) remove_from_list(exits, [ext, target]) + if avail.swapped and drop_map[drop] != target: + swap_ent, swap_ext = connect_swap(entrance, ext, avail) + swap_drop, swap_tgt = connect_swap(drop, target, avail) + hole_entrances.remove((swap_ent, swap_drop)) + hole_targets.remove((swap_ext, swap_tgt)) + remove_from_list(entrances, [swap_ent, swap_drop]) + remove_from_list(exits, [swap_ext, swap_tgt]) def do_dark_sanc(entrances, exits, avail): @@ -482,6 +545,11 @@ def do_dark_sanc(entrances, exits, avail): forbidden = list(Isolated_LH_Doors) if not avail.world.is_tile_swapped(0x05, avail.player): forbidden.append('Mimic Cave') + if avail.swapped: + forbidden.append('Dark Sanctuary Hint') + forbidden.extend(Forbidden_Swap_Entrances) + if not avail.world.is_bombshop_start(avail.player): + forbidden.append('Links House') if avail.world.owShuffle[avail.player] == 'vanilla': choices = [e for e in avail.world.districts[avail.player]['Northwest Dark World'].entrances if e not in forbidden and e in entrances] else: @@ -493,6 +561,10 @@ def do_dark_sanc(entrances, exits, avail): ext.connect(avail.world.get_entrance(choice, avail.player).parent_region) if not avail.coupled: avail.decoupled_entrances.remove(choice) + if avail.swapped and choice != 'Dark Sanctuary Hint': + swap_ent, swap_ext = connect_swap(choice, 'Dark Sanctuary Hint', avail) + entrances.remove(swap_ent) + exits.remove(swap_ext) elif not ext.connected_region: # default to output to vanilla area, assume vanilla connection ext.connect(avail.world.get_region('Dark Chapel Area', avail.player)) @@ -501,8 +573,9 @@ def do_dark_sanc(entrances, exits, avail): def do_links_house(entrances, exits, avail, cross_world): lh_exit = 'Big Bomb Shop' if avail.world.is_bombshop_start(avail.player) else 'Links House Exit' if lh_exit in exits: + links_house_vanilla = 'Big Bomb Shop' if avail.world.is_bombshop_start(avail.player) else 'Links House' if not avail.world.shufflelinks[avail.player]: - links_house = 'Big Bomb Shop' if avail.world.is_bombshop_start(avail.player) else 'Links House' + links_house = links_house_vanilla else: entrance_pool = entrances if avail.coupled else avail.decoupled_entrances @@ -514,6 +587,9 @@ def do_links_house(entrances, exits, avail, cross_world): if avail.inverted: dark_sanc_region = avail.world.get_entrance('Dark Sanctuary Hint Exit', avail.player).connected_region.name forbidden.extend(get_nearby_entrances(avail, dark_sanc_region)) + if avail.swapped: + forbidden.append(links_house_vanilla) + forbidden.extend(Forbidden_Swap_Entrances) shuffle_mode = avail.world.shuffle[avail.player] if avail.world.owShuffle[avail.player] == 'vanilla': # simple shuffle - @@ -564,6 +640,10 @@ def do_links_house(entrances, exits, avail, cross_world): if not avail.coupled: avail.decoupled_entrances.remove(links_house) avail.decoupled_exits.remove(lh_exit) + if avail.swapped and links_house != links_house_vanilla: + swap_ent, swap_ext = connect_swap(links_house, lh_exit, avail) + entrances.remove(swap_ent) + exits.remove(swap_ext) # links on dm dm_spots = LH_DM_Connector_List.union(LH_DM_Exit_Forbidden) @@ -598,14 +678,16 @@ def do_links_house(entrances, exits, avail, cross_world): possible_exits.sort() chosen_dm_escape = random.choice(possible_dm_exits) chosen_landing = random.choice(possible_exits) + chosen_exit_start = chosen_cave.pop(0) + chosen_exit_end = chosen_cave.pop() if avail.coupled: - connect_two_way(chosen_dm_escape, chosen_cave.pop(0), avail) - connect_two_way(chosen_landing, chosen_cave.pop(), avail) + connect_two_way(chosen_dm_escape, chosen_exit_start, avail) + connect_two_way(chosen_landing, chosen_exit_end, avail) entrances.remove(chosen_dm_escape) entrances.remove(chosen_landing) else: - connect_entrance(chosen_dm_escape, chosen_cave.pop(0), avail) - connect_exit(chosen_cave.pop(), chosen_landing, avail) + connect_entrance(chosen_dm_escape, chosen_exit_start, avail) + connect_exit(chosen_exit_end, chosen_landing, avail) entrances.remove(chosen_dm_escape) avail.decoupled_entrances.remove(chosen_landing) if len(chosen_cave): @@ -966,21 +1048,41 @@ def do_cross_world_connectors(entrances, caves, avail): cave_candidate = (None, 0) for i, cave in enumerate(caves): if isinstance(cave, str): - cave = (cave,) + cave = [cave] if len(cave) > cave_candidate[1]: cave_candidate = (i, len(cave)) cave = caves.pop(cave_candidate[0]) if isinstance(cave, str): - cave = (cave,) + cave = [cave] - for ext in cave: + while len(cave): + ext = cave.pop() if not avail.coupled: choice = random.choice(avail.decoupled_entrances) connect_exit(ext, choice, avail) avail.decoupled_entrances.remove(choice) else: - connect_two_way(entrances.pop(), ext, avail) + if avail.swapped and len(entrances) > 1: + chosen_entrance = next(e for e in entrances if combine_map[e] != ext) + entrances.remove(chosen_entrance) + else: + chosen_entrance = entrances.pop() + connect_two_way(chosen_entrance, ext, avail) + if avail.swapped: + swap_ent, swap_ext = connect_swap(chosen_entrance, ext, avail) + if swap_ent: + entrances.remove(swap_ent) + if chosen_entrance not in single_entrance_map: + for c in caves: + if swap_ext == c: + caves.remove(swap_ext) + break + if swap_ext in c: + c.remove(swap_ext) + if len(c) == 0: + caves.remove(c) + break def do_fixed_shuffle(avail, entrance_list): @@ -1008,7 +1110,7 @@ def do_fixed_shuffle(avail, entrance_list): choice = choices[i] elif rules.must_exit_to_lw: lw_exits = set() - for e, x in {**entrance_map, **single_entrance_map, **drop_map}.items(): + for e, x in combine_map.items(): if x in avail.exits: region = avail.world.get_entrance(e, avail.player).parent_region if region.type == RegionType.LightWorld: @@ -1194,6 +1296,10 @@ def do_mandatory_connections(avail, entrances, cave_options, must_exit): if entrance in must_exit: must_exit.remove(entrance) entrances.append(entrance) + if avail.swapped: + swap_forbidden = [e for e in entrances if combine_map[e] in must_exit] + for e in swap_forbidden: + entrances.remove(e) entrances.sort() # sort these for consistency random.shuffle(entrances) random.shuffle(cave_options) @@ -1206,6 +1312,19 @@ def do_mandatory_connections(avail, entrances, cave_options, must_exit): invalid_connections[ext] = invalid_connections[ext].union({'Agahnims Tower', 'Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)'}) break + def connect_cave_swap(entrance, exit, current_cave): + swap_entrance, swap_exit = connect_swap(entrance, exit, avail) + if swap_entrance and entrance not in single_entrance_map: + for option in cave_options: + if swap_exit in option and option == current_cave: + x=0 + if swap_exit in option and option != current_cave: + option.remove(swap_exit) + if len(option) == 0: + cave_options.remove(option) + break + return swap_entrance, swap_exit + used_caves = [] required_entrances = 0 # Number of entrances reserved for used_caves while must_exit: @@ -1213,9 +1332,10 @@ def do_mandatory_connections(avail, entrances, cave_options, must_exit): # find multi exit cave candidates = [] for candidate in cave_options: - if not isinstance(candidate, str) and (candidate in used_caves + if not isinstance(candidate, str) and len(candidate) > 1 and (candidate in used_caves or len(candidate) < len(entrances) - required_entrances): - candidates.append(candidate) + if not avail.swapped or (combine_map[exit] not in candidate and not any(e for e in must_exit if combine_map[e] in candidate)): #maybe someday allow these, but we need to disallow mutual locks in Swapped + candidates.append(candidate) cave = random.choice(candidates) if cave is None: raise RuntimeError('No more caves left. Should not happen!') @@ -1225,11 +1345,17 @@ def do_mandatory_connections(avail, entrances, cave_options, must_exit): shuffle_connector_exits(rnd_cave) # should be the same as unbiasing some entrances... entrances.remove(exit) connect_two_way(exit, rnd_cave[-1], avail) + if avail.swapped: + swap_ent, _ = connect_cave_swap(exit, rnd_cave[-1], cave) + entrances.remove(swap_ent) if len(cave) == 2: entrance = next(e for e in entrances[::-1] if e not in invalid_connections[exit] and e not in invalid_cave_connections[tuple(cave)] and e not in must_exit) entrances.remove(entrance) connect_two_way(entrance, rnd_cave[0], avail) + if avail.swapped and combine_map[entrance] != rnd_cave[0]: + swap_ent, _ = connect_cave_swap(entrance, rnd_cave[0], cave) + entrances.remove(swap_ent) if cave in used_caves: required_entrances -= 2 used_caves.remove(cave) @@ -1243,6 +1369,9 @@ def do_mandatory_connections(avail, entrances, cave_options, must_exit): cave_entrances.append(entrance) entrances.remove(entrance) connect_two_way(entrance, cave_exit, avail) + if avail.swapped and combine_map[entrance] != cave_exit: + swap_ent, _ = connect_cave_swap(entrance, cave_exit, cave) + entrances.remove(swap_ent) if entrance not in invalid_connections: invalid_connections[exit] = set() if all(entrance in invalid_connections for entrance in cave_entrances): @@ -1267,7 +1396,12 @@ def do_mandatory_connections(avail, entrances, cave_options, must_exit): invalid_cave_connections[tuple(cave)] = set() entrances.remove(entrance) connect_two_way(entrance, cave_exit, avail) + if avail.swapped and combine_map[entrance] != cave_exit: + swap_ent, _ = connect_cave_swap(entrance, cave_exit, cave) + entrances.remove(swap_ent) cave_options.remove(cave) + if avail.swapped: + entrances.extend(swap_forbidden) def do_mandatory_connections_decoupled(avail, cave_options, must_exit): @@ -1378,6 +1512,46 @@ def inverted_substitution(avail_pool, collection, is_entrance, is_set=False): pass +def connect_swapped(entrancelist, targetlist, avail, two_way=False): + random.shuffle(entrancelist) + sorted_targets = list() + for ent in entrancelist: + if ent in combine_map: + if combine_map[ent] not in targetlist: + logging.getLogger('').error(f'{combine_map[ent]} not in target list, cannot swap entrance') + raise Exception(f'{combine_map[ent]} not in target list, cannot swap entrance') + sorted_targets.append(combine_map[ent]) + if len(sorted_targets): + targetlist = list(sorted_targets) + else: + targetlist = list(targetlist) + indexlist = list(range(len(targetlist))) + random.shuffle(indexlist) + + while len(indexlist) > 1: + index1 = indexlist.pop() + index2 = indexlist.pop() + targetlist[index1], targetlist[index2] = targetlist[index2], targetlist[index1] + + for exit, target in zip(entrancelist, targetlist): + if two_way: + connect_two_way(exit, target, avail) + else: + connect_entrance(exit, target, avail) + + +def connect_swap(entrance, exit, avail): + swap_exit = combine_map[entrance] + if swap_exit != exit: + swap_entrance = next(e for e, x in combine_map.items() if x == exit) + if entrance in entrance_map: + connect_two_way(swap_entrance, swap_exit, avail) + else: + connect_entrance(swap_entrance, swap_exit, avail) + return swap_entrance, swap_exit + return None, None + + def connect_random(exitlist, targetlist, avail, two_way=False): targetlist = list(targetlist) random.shuffle(targetlist) @@ -1841,6 +2015,23 @@ modes = { }, } }, + 'swapped': { + 'undefined': 'swap', + 'keep_drops_together': 'on', + 'cross_world': 'on', + 'pools': { + 'skull_drops': { + 'special': 'drops', + 'entrances': ['Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', + 'Skull Woods First Section Hole (North)', 'Skull Woods Second Section Hole'] + }, + 'skull_doors': { + 'special': 'skull', + 'entrances': ['Skull Woods First Section Door', 'Skull Woods Second Section Door (East)', + 'Skull Woods Second Section Door (West)'] + }, + } + }, 'crossed': { 'undefined': 'shuffle', 'keep_drops_together': 'on', @@ -2003,6 +2194,8 @@ single_entrance_map = { 'Blinds Hideout': 'Blinds Hideout', 'Waterfall of Wishing': 'Waterfall of Wishing' } +combine_map = {**entrance_map, **single_entrance_map, **drop_map} + LW_Entrances = [] DW_Entrances = [] @@ -2083,6 +2276,8 @@ Must_Exit_Invalid_Connections = defaultdict(set) Simple_DM_Non_Connectors = {'Old Man Cave Ledge', 'Spiral Cave (Top)', 'Superbunny Cave (Bottom)', 'Spectacle Rock Cave (Peak)', 'Spectacle Rock Cave (Top)'} +Forbidden_Swap_Entrances = {'Old Man Cave (East)', 'Blacksmiths Hut', 'Big Bomb Shop'} + # these are connections that cannot be shuffled and always exist. # They link together underworld regions From 138bd2b41f5ab9848fb6fd4b52cc128a7587089e Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 16 Jul 2023 01:12:12 -0500 Subject: [PATCH 155/196] Minor formatting --- source/overworld/EntranceShuffle2.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index b5de938d..eb277bc8 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -190,10 +190,10 @@ def do_vanilla_connections(avail_pool): def do_main_shuffle(entrances, exits, avail, mode_def): - # drops and holes cross_world = mode_def['cross_world'] == 'on' if 'cross_world' in mode_def else False - keep_together = mode_def['keep_drops_together'] == 'on' if 'keep_drops_together' in mode_def else True avail.coupled = mode_def['decoupled'] != 'on' if 'decoupled' in mode_def else True + # drops and holes + keep_together = mode_def['keep_drops_together'] == 'on' if 'keep_drops_together' in mode_def else True do_holes_and_linked_drops(entrances, exits, avail, cross_world, keep_together) if not avail.coupled: @@ -298,6 +298,8 @@ def do_main_shuffle(entrances, exits, avail, mode_def): def bonk_fairy_exception(x): # (Bonk Fairy not eligible in standard) return not avail.is_standard() or x != 'Bonk Fairy (Light)' + + # old man S&Q cave if not cross_world: #TODO: Add Swapped ER support for this # OM Cave entrance in lw/dw if cross_world off From d4f33f50eb7b16651653b6a024fc3f52fa0c68fa Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 16 Jul 2023 12:59:43 -0500 Subject: [PATCH 156/196] More code for Swapped ER implementation --- source/overworld/EntranceShuffle2.py | 40 +++++++++++++++++++--------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index eb277bc8..f11d0081 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -209,6 +209,10 @@ def do_main_shuffle(entrances, exits, avail, mode_def): if not avail.coupled: avail.decoupled_entrances.remove('Agahnims Tower') avail.decoupled_exits.remove('Ganons Tower Exit') + if avail.swapped: + connect_swap('Agahnims Tower', 'Ganons Tower Exit', avail) + entrances.remove('Ganons Tower') + exits.remove('Agahnims Tower Exit') elif 'Ganons Tower' in entrances: connect_two_way('Ganons Tower', 'Ganons Tower Exit', avail) entrances.remove('Ganons Tower') @@ -384,7 +388,10 @@ def do_old_man_cave_exit(entrances, exits, avail, cross_world): random.shuffle(om_cave_options) om_cave_choice = None while not om_cave_choice: - om_cave_choice = om_cave_options.pop() + if not len(om_cave_options) and 'Old Man Cave (East)' in entrances: + om_cave_choice = 'Old Man Cave (East)' + else: + om_cave_choice = om_cave_options.pop() choice_region = avail.world.get_entrance(om_cave_choice, avail.player).parent_region.name if 'West Death Mountain (Bottom)' not in build_accessible_region_list(avail.world, choice_region, avail.player, True, True): om_cave_choice = None @@ -1076,15 +1083,18 @@ def do_cross_world_connectors(entrances, caves, avail): if swap_ent: entrances.remove(swap_ent) if chosen_entrance not in single_entrance_map: - for c in caves: - if swap_ext == c: - caves.remove(swap_ext) - break - if swap_ext in c: - c.remove(swap_ext) - if len(c) == 0: - caves.remove(c) - break + if swap_ext in cave: + cave.remove(swap_ext) + else: + for c in caves: + if swap_ext == c: + caves.remove(swap_ext) + break + if not isinstance(c, str) and swap_ext in c: + c.remove(swap_ext) + if len(c) == 0: + caves.remove(c) + break def do_fixed_shuffle(avail, entrance_list): @@ -1297,7 +1307,8 @@ def do_mandatory_connections(avail, entrances, cave_options, must_exit): invalid_connections[entrance] = set() if entrance in must_exit: must_exit.remove(entrance) - entrances.append(entrance) + if entrance not in entrances: + entrances.append(entrance) if avail.swapped: swap_forbidden = [e for e in entrances if combine_map[e] in must_exit] for e in swap_forbidden: @@ -1345,7 +1356,10 @@ def do_mandatory_connections(avail, entrances, cave_options, must_exit): # all caves are sorted so that the last exit is always reachable rnd_cave = list(cave) shuffle_connector_exits(rnd_cave) # should be the same as unbiasing some entrances... - entrances.remove(exit) + if avail.swapped and exit in swap_forbidden: + swap_forbidden.remove(exit) + else: + entrances.remove(exit) connect_two_way(exit, rnd_cave[-1], avail) if avail.swapped: swap_ent, _ = connect_cave_swap(exit, rnd_cave[-1], cave) @@ -1546,6 +1560,8 @@ def connect_swap(entrance, exit, avail): swap_exit = combine_map[entrance] if swap_exit != exit: swap_entrance = next(e for e, x in combine_map.items() if x == exit) + if swap_entrance in ['Pyramid Entrance', 'Pyramid Hole'] and avail.world.is_tile_swapped(0x1b, avail.player): + swap_entrance = 'Inverted ' + swap_entrance if entrance in entrance_map: connect_two_way(swap_entrance, swap_exit, avail) else: From fce629b95f1b1c355c6523fdfeba200f6d9e5635 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 16 Jul 2023 13:17:20 -0500 Subject: [PATCH 157/196] Version bump 0.3.2.0 --- CHANGELOG.md | 5 +++++ OverworldShuffle.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25fa22be..b156a0dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 0.3.2.0 +- New Swapped ER mode option +- Fixed issue with flipper rules not properly getting pearl requirement added +- Fixed minor issues in generating non-crossed ER on subsequent attempts + ## 0.3.1.2 - Retro now gives a universal key from bottle vendor fish prize - Fixed issue with Aga Door preventing Murahduhla Cutscene diff --git a/OverworldShuffle.py b/OverworldShuffle.py index d95b2cb8..c34b6d62 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -7,7 +7,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType from OverworldGlitchRules import create_owg_connections from Utils import bidict -version_number = '0.3.1.2' +version_number = '0.3.2.0' # branch indicator is intentionally different across branches version_branch = '-u' From a987e58fc9079ef2d0358c2438dda1ac59df81c7 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 17 Jul 2023 01:37:55 -0500 Subject: [PATCH 158/196] Adding Flute Activation only if an activated flute cannot be found elsewhere --- ItemList.py | 3 ++- Rules.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ItemList.py b/ItemList.py index bb23ecec..7fe75e3b 100644 --- a/ItemList.py +++ b/ItemList.py @@ -212,7 +212,8 @@ def generate_itempool(world, player): loc.locked = True loc.forced_item = loc.item - if not world.is_tile_swapped(0x18, player): + if (world.flute_mode[player] != 'active' and not world.is_tile_swapped(0x18, player) + and 'Ocarina (Activated)' not in list(map(str, [i for i in world.precollected_items if i.player == player]))): region = world.get_region('Kakariko Village',player) loc = Location(player, "Flute Activation", parent=region) diff --git a/Rules.py b/Rules.py index f1383ee6..024c1436 100644 --- a/Rules.py +++ b/Rules.py @@ -69,7 +69,8 @@ def set_rules(world, player): elif world.goal[player] == 'completionist': add_rule(world.get_location('Ganon', player), lambda state: state.everything(player)) - if not world.is_tile_swapped(0x18, player): + if (world.flute_mode[player] != 'active' and not world.is_tile_swapped(0x18, player) + and 'Ocarina (Activated)' not in list(map(str, [i for i in world.precollected_items if i.player == player]))): if not world.is_copied_world: # Commented out below, this would be needed for rando implementations where Inverted requires flute activation in bunny territory # kak_region = self.world.get_region('Kakariko Village', player) From 213d3d3aa0798722225e9c3707c2945b96c1d3b9 Mon Sep 17 00:00:00 2001 From: aerinon Date: Wed, 19 Jul 2023 12:31:50 -0600 Subject: [PATCH 159/196] Fixed an issue where certain vanilla door types would not allow other types to be placed. Customizer: fixed an issue where last ditch placements would move customized items. Those are now locked and the generation will fail instead if no alternatives are found. --- DoorShuffle.py | 28 +++++++++++++++------------- ItemList.py | 2 ++ RELEASENOTES.md | 2 ++ 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/DoorShuffle.py b/DoorShuffle.py index a0add44b..35cc7624 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -1962,7 +1962,7 @@ def shuffle_big_key_doors(door_type_pools, used_doors, start_regions_map, all_cu if flex_map[dungeon] > 0: queue.append(dungeon) # time to re-assign - reassign_big_key_doors(bk_map, world, player) + reassign_big_key_doors(bk_map, used_doors, world, player) for name, big_list in bk_map.items(): used_doors.update(flatten_pair_list(big_list)) return used_doors @@ -2047,7 +2047,7 @@ def shuffle_small_key_doors(door_type_pools, used_doors, start_regions_map, all_ else: builder.key_doors_num -= 1 # time to re-assign - reassign_key_doors(small_map, world, player) + reassign_key_doors(small_map, used_doors, world, player) for dungeon_name in pool: if world.keyshuffle[player] != 'universal': builder = world.dungeon_layouts[player][dungeon_name] @@ -2129,7 +2129,7 @@ def shuffle_bomb_dash_doors(door_type_pools, used_doors, start_regions_map, all_ suggestion_map[dungeon] = pair queue.append(dungeon) # time to re-assign - reassign_bd_doors(bd_map, world, player) + reassign_bd_doors(bd_map, used_doors, world, player) for name, pair in bd_map.items(): used_doors.update(flatten_pair_list(pair[0])) used_doors.update(flatten_pair_list(pair[1])) @@ -2539,7 +2539,7 @@ def find_current_bk_doors(builder): return current_doors -def reassign_big_key_doors(bk_map, world, player): +def reassign_big_key_doors(bk_map, used_doors, world, player): logger = logging.getLogger('') for name, big_doors in bk_map.items(): flat_proposal = flatten_pair_list(big_doors) @@ -2547,11 +2547,12 @@ def reassign_big_key_doors(bk_map, world, player): queue = deque(find_current_bk_doors(builder)) while len(queue) > 0: d = queue.pop() - if d.type is DoorType.Interior and d not in flat_proposal and d.dest not in flat_proposal: + if (d.type is DoorType.Interior and d not in flat_proposal and d.dest not in flat_proposal + and d not in used_doors and d.dest not in used_doors): if not d.entranceFlag: world.get_room(d.roomIndex, player).change(d.doorListPos, DoorKind.Normal) d.bigKey = False - elif d.type is DoorType.Normal and d not in flat_proposal: + elif d.type is DoorType.Normal and d not in flat_proposal and d not in used_doors: if not d.entranceFlag: world.get_room(d.roomIndex, player).change(d.doorListPos, DoorKind.Normal) d.bigKey = False @@ -2795,7 +2796,7 @@ def find_valid_bd_combination(builder, suggested, world, player): return bomb_proposal, dash_proposal, ttl_needed -def reassign_bd_doors(bd_map, world, player): +def reassign_bd_doors(bd_map, used_doors, world, player): for name, pair in bd_map.items(): flat_bomb_proposal = flatten_pair_list(pair[0]) flat_dash_proposal = flatten_pair_list(pair[1]) @@ -2808,10 +2809,10 @@ def reassign_bd_doors(bd_map, world, player): queue = deque(find_current_bd_doors(builder, world)) while len(queue) > 0: d = queue.pop() - if d.type is DoorType.Interior and not_in_proposal(d): + if d.type is DoorType.Interior and not_in_proposal(d) and d not in used_doors and d.dest not in used_doors: if not d.entranceFlag: world.get_room(d.roomIndex, player).change(d.doorListPos, DoorKind.Normal) - elif d.type is DoorType.Normal and not_in_proposal(d): + elif d.type is DoorType.Normal and not_in_proposal(d) and d not in used_doors: if not d.entranceFlag: world.get_room(d.roomIndex, player).change(d.doorListPos, DoorKind.Normal) do_bombable_dashable(pair[0], DoorKind.Bombable, world, player) @@ -3003,7 +3004,7 @@ def valid_key_door_pair(door1, door2): return len(door1.entrance.parent_region.exits) <= 1 or len(door2.entrance.parent_region.exits) <= 1 -def reassign_key_doors(small_map, world, player): +def reassign_key_doors(small_map, used_doors, world, player): logger = logging.getLogger('') for name, small_doors in small_map.items(): logger.debug(f'Key doors for {name}') @@ -3013,7 +3014,7 @@ def reassign_key_doors(small_map, world, player): queue = deque(find_current_key_doors(builder)) while len(queue) > 0: d = queue.pop() - if d.type is DoorType.SpiralStairs and d not in proposal: + if d.type is DoorType.SpiralStairs and d not in proposal and d not in used_doors: room = world.get_room(d.roomIndex, player) if room.doorList[d.doorListPos][1] == DoorKind.StairKeyLow: room.delete(d.doorListPos) @@ -3023,13 +3024,14 @@ def reassign_key_doors(small_map, world, player): else: room.delete(d.doorListPos) d.smallKey = False - elif d.type is DoorType.Interior and d not in flat_proposal and d.dest not in flat_proposal: + elif (d.type is DoorType.Interior and d not in flat_proposal and d.dest not in flat_proposal + and d not in used_doors and d.dest not in used_doors): if not d.entranceFlag: world.get_room(d.roomIndex, player).change(d.doorListPos, DoorKind.Normal) d.smallKey = False d.dest.smallKey = False queue.remove(d.dest) - elif d.type is DoorType.Normal and d not in flat_proposal: + elif d.type is DoorType.Normal and d not in flat_proposal and d not in used_doors: if not d.entranceFlag: world.get_room(d.roomIndex, player).change(d.doorListPos, DoorKind.Normal) d.smallKey = False diff --git a/ItemList.py b/ItemList.py index 168d841d..9ca15555 100644 --- a/ItemList.py +++ b/ItemList.py @@ -1396,6 +1396,7 @@ def fill_specific_items(world): dungeon_pool, prize_set, prize_pool) if item_to_place: world.push_item(loc, item_to_place, False) + loc.locked = True track_outside_keys(item_to_place, loc, world) track_dungeon_items(item_to_place, loc, world) loc.event = (event_flag or item_to_place.advancement @@ -1431,6 +1432,7 @@ def fill_specific_items(world): if loc.item: continue world.push_item(loc, item_to_place, False) + loc.locked = True track_outside_keys(item_to_place, loc, world) track_dungeon_items(item_to_place, loc, world) loc.event = (event_flag or item_to_place.advancement diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 5f11c963..7010ecb6 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -113,6 +113,8 @@ These are now independent of retro mode and have three options: None, Random, an * Fixed an issue with pyramid hole being in logic when it is not opened. * Crystal cutscene at GT use new symmetrical layouts (thanks Codemann) * Fix for Hera Boss music (thanks Codemann) + * Fixed an issue where certain vanilla door types would not allow other types to be placed. + * Customizer: fixed an issue where last ditch placements would move customized items. Those are now locked and the generation will fail instead is no alternative are found. * Customizer: fixed an issue with assured sword and start_inventory * Customizer: warns when trying to specifically place an item that's not in the item pool * Fixed "accessibility: none" displaying a spoiling message From b6275d0688f7ab92cb5811f7aac8243c956ddabd Mon Sep 17 00:00:00 2001 From: aerinon Date: Wed, 19 Jul 2023 12:57:07 -0600 Subject: [PATCH 160/196] Typo --- RELEASENOTES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 7010ecb6..45577d04 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -114,7 +114,7 @@ These are now independent of retro mode and have three options: None, Random, an * Crystal cutscene at GT use new symmetrical layouts (thanks Codemann) * Fix for Hera Boss music (thanks Codemann) * Fixed an issue where certain vanilla door types would not allow other types to be placed. - * Customizer: fixed an issue where last ditch placements would move customized items. Those are now locked and the generation will fail instead is no alternative are found. + * Customizer: fixed an issue where last ditch placements would move customized items. Those are now locked and the generation will fail instead if no alternatives are found. * Customizer: fixed an issue with assured sword and start_inventory * Customizer: warns when trying to specifically place an item that's not in the item pool * Fixed "accessibility: none" displaying a spoiling message From 2c6af4e44cc438b5eaeb9dc26c6a9e3835e13d27 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 17 Jul 2023 04:28:12 -0500 Subject: [PATCH 161/196] More Swapped ER fixes --- source/overworld/EntranceShuffle2.py | 43 +++++++++++++++++++--------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index f11d0081..16ce2dfc 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -289,6 +289,7 @@ def do_main_shuffle(entrances, exits, avail, mode_def): bomb_shop_options = [x for x in bomb_shop_options if x not in ['Spectacle Rock Cave', 'Spectacle Rock Cave (Bottom)']] if avail.swapped and len(bomb_shop_options) > 1: bomb_shop_options = [x for x in bomb_shop_options if x != 'Big Bomb Shop'] + bomb_shop_choice = random.choice(bomb_shop_options) connect_entrance(bomb_shop_choice, bomb_shop, avail) rem_entrances.remove(bomb_shop_choice) @@ -433,6 +434,8 @@ def do_blacksmith(entrances, exits, avail): if avail.swapped: blacksmith_options = [e for e in blacksmith_options if e not in Forbidden_Swap_Entrances] blacksmith_options = [x for x in blacksmith_options if x in entrances] + + assert len(blacksmith_options), 'No available entrances left to place Blacksmith' blacksmith_choice = random.choice(blacksmith_options) connect_entrance(blacksmith_choice, 'Blacksmiths Hut', avail) entrances.remove(blacksmith_choice) @@ -563,6 +566,7 @@ def do_dark_sanc(entrances, exits, avail): choices = [e for e in avail.world.districts[avail.player]['Northwest Dark World'].entrances if e not in forbidden and e in entrances] else: choices = [e for e in get_starting_entrances(avail) if e not in forbidden and e in entrances] + choice = random.choice(choices) entrances.remove(choice) exits.remove('Dark Sanctuary Hint') @@ -596,6 +600,10 @@ def do_links_house(entrances, exits, avail, cross_world): if avail.inverted: dark_sanc_region = avail.world.get_entrance('Dark Sanctuary Hint Exit', avail.player).connected_region.name forbidden.extend(get_nearby_entrances(avail, dark_sanc_region)) + else: + if (avail.world.doorShuffle[avail.player] != 'vanilla' and avail.world.intensity[avail.player] > 2 + and not avail.world.is_tile_swapped(0x1b, avail.player)): + forbidden.append('Hyrule Castle Entrance (South)') if avail.swapped: forbidden.append(links_house_vanilla) forbidden.extend(Forbidden_Swap_Entrances) @@ -1381,13 +1389,17 @@ def do_mandatory_connections(avail, entrances, cave_options, must_exit): elif cave[-1] == 'Spectacle Rock Cave Exit': # Spectacle rock only has one exit cave_entrances = [] for cave_exit in rnd_cave[:-1]: - entrance = next(e for e in entrances[::-1] if e not in invalid_connections[exit] and e not in must_exit) - cave_entrances.append(entrance) - entrances.remove(entrance) - connect_two_way(entrance, cave_exit, avail) - if avail.swapped and combine_map[entrance] != cave_exit: - swap_ent, _ = connect_cave_swap(entrance, cave_exit, cave) - entrances.remove(swap_ent) + if avail.swapped and cave_exit not in avail.exits: + entrance = avail.world.get_entrance(cave_exit, avail.player).parent_region.entrances[0].name + cave_entrances.append(entrance) + else: + entrance = next(e for e in entrances[::-1] if e not in invalid_connections[exit] and e not in must_exit) + cave_entrances.append(entrance) + entrances.remove(entrance) + connect_two_way(entrance, cave_exit, avail) + if avail.swapped and combine_map[entrance] != cave_exit: + swap_ent, _ = connect_cave_swap(entrance, cave_exit, cave) + entrances.remove(swap_ent) if entrance not in invalid_connections: invalid_connections[exit] = set() if all(entrance in invalid_connections for entrance in cave_entrances): @@ -1408,13 +1420,16 @@ def do_mandatory_connections(avail, entrances, cave_options, must_exit): for cave in used_caves: if cave in cave_options: # check if we placed multiple entrances from this 3 or 4 exit for cave_exit in cave: - entrance = next(e for e in entrances[::-1] if e not in invalid_cave_connections[tuple(cave)]) - invalid_cave_connections[tuple(cave)] = set() - entrances.remove(entrance) - connect_two_way(entrance, cave_exit, avail) - if avail.swapped and combine_map[entrance] != cave_exit: - swap_ent, _ = connect_cave_swap(entrance, cave_exit, cave) - entrances.remove(swap_ent) + if avail.swapped and cave_exit not in avail.exits: + continue + else: + entrance = next(e for e in entrances[::-1] if e not in invalid_cave_connections[tuple(cave)]) + invalid_cave_connections[tuple(cave)] = set() + entrances.remove(entrance) + connect_two_way(entrance, cave_exit, avail) + if avail.swapped and combine_map[entrance] != cave_exit: + swap_ent, _ = connect_cave_swap(entrance, cave_exit, cave) + entrances.remove(swap_ent) cave_options.remove(cave) if avail.swapped: entrances.extend(swap_forbidden) From 6d03c5c5325bf7cf9579b8d52b003c61c6865b6e Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 19 Jul 2023 14:14:01 -0500 Subject: [PATCH 162/196] Merge branch 'OverworldShuffleDev' of https://github.com/codemann8/ALttPDoorRandomizer into OverworldShuffleDev Adding console output when generation fails to reach required items --- Main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Main.py b/Main.py index c426cef7..cb2d4983 100644 --- a/Main.py +++ b/Main.py @@ -877,6 +877,7 @@ def create_playthrough(world): if world.has_beaten_game(state): required_locations.clear() else: + logging.getLogger('').error(world.fish.translate("cli", "cli", "cannot.reach.items"), [world.fish.translate("cli","cli","cannot.reach.item") % (loc.item.name, loc.item.player, loc.name, loc.player) for loc in required_locations]) raise RuntimeError(world.fish.translate("cli","cli","cannot.reach.required")) # store the required locations for statistical analysis From ea70d7cb5add7a6c952103ace2fdb3ade4405794 Mon Sep 17 00:00:00 2001 From: Catobat <69204835+Catobat@users.noreply.github.com> Date: Wed, 26 Jul 2023 02:40:40 +0200 Subject: [PATCH 163/196] Move Triforce Pieces Min and Max handling to Main --- CLI.py | 2 +- Main.py | 22 ++++++++++++++++++++-- source/tools/MysteryUtils.py | 16 +++++++--------- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/CLI.py b/CLI.py index 312c1d80..85283053 100644 --- a/CLI.py +++ b/CLI.py @@ -229,7 +229,7 @@ def parse_settings(): "triforce_pool_max": 0, "triforce_goal_min": 0, "triforce_goal_max": 0, - "triforce_min_difference": 10, + "triforce_min_difference": 0, "code": "", "multi": 1, diff --git a/Main.py b/Main.py index 2edf2c03..049f5932 100644 --- a/Main.py +++ b/Main.py @@ -124,8 +124,6 @@ def main(args, seed=None, fish=None): world.potshuffle = args.shufflepots.copy() world.mixed_travel = args.mixed_travel.copy() world.standardize_palettes = args.standardize_palettes.copy() - world.treasure_hunt_count = {k: int(v) for k, v in args.triforce_goal.items()} - world.treasure_hunt_total = {k: int(v) for k, v in args.triforce_pool.items()} world.shufflelinks = args.shufflelinks.copy() world.shuffletavern = args.shuffletavern.copy() world.pseudoboots = args.pseudoboots.copy() @@ -135,6 +133,26 @@ def main(args, seed=None, fish=None): world.collection_rate = args.collection_rate.copy() world.colorizepots = args.colorizepots.copy() + world.treasure_hunt_count = {} + world.treasure_hunt_total = {} + for p in args.triforce_goal: + if int(args.triforce_goal[p]) != 0 or int(args.triforce_pool[p]) != 0 or int(args.triforce_goal_min[p]) != 0 or int(args.triforce_goal_max[p]) != 0 or int(args.triforce_pool_min[p]) != 0 or int(args.triforce_pool_max[p]) != 0: + if int(args.triforce_goal[p]) != 0: + world.treasure_hunt_count[p] = int(args.triforce_goal[p]) + elif int(args.triforce_goal_min[p]) != 0 and int(args.triforce_goal_max[p]) != 0: + world.treasure_hunt_count[p] = random.randint(int(args.triforce_goal_min[p]), int(args.triforce_goal_max[p])) + else: + world.treasure_hunt_count[p] = 8 if world.goal[p] == 'trinity' else 20 + if int(args.triforce_pool[p]) != 0: + world.treasure_hunt_total[p] = int(args.triforce_pool[p]) + elif int(args.triforce_pool_min[p]) != 0 and int(args.triforce_pool_max[p]) != 0: + world.treasure_hunt_total[p] = random.randint(max(int(args.triforce_pool_min[p]), world.treasure_hunt_count[p] + int(args.triforce_min_difference[p])), int(args.triforce_pool_max[p])) + else: + world.treasure_hunt_total[p] = 10 if world.goal[p] == 'trinity' else 30 + else: + # this will be handled in ItemList.py and custom item pool is used to determine the numbers + world.treasure_hunt_count[p], world.treasure_hunt_total[p] = 0, 0 + world.rom_seeds = {player: random.randint(0, 999999999) for player in range(1, world.players + 1)} world.finish_init() diff --git a/source/tools/MysteryUtils.py b/source/tools/MysteryUtils.py index 8f371b6c..32ee9d5f 100644 --- a/source/tools/MysteryUtils.py +++ b/source/tools/MysteryUtils.py @@ -125,15 +125,13 @@ def roll_settings(weights): ret.crystals_ganon = get_choice('ganon_open') - from ItemList import set_default_triforce - default_tf_goal, default_tf_pool = set_default_triforce(ret.goal, 0, 0) - goal_min = get_choice_default('triforce_goal_min', default=default_tf_goal) - goal_max = get_choice_default('triforce_goal_max', default=default_tf_goal) - pool_min = get_choice_default('triforce_pool_min', default=default_tf_pool) - pool_max = get_choice_default('triforce_pool_max', default=default_tf_pool) - ret.triforce_goal = random.randint(int(goal_min), int(goal_max)) - min_diff = get_choice_default('triforce_min_difference', default=default_tf_pool-default_tf_goal) - ret.triforce_pool = random.randint(max(int(pool_min), ret.triforce_goal + int(min_diff)), int(pool_max)) + ret.triforce_pool = get_choice_default('triforce_pool', default=0) + ret.triforce_goal = get_choice_default('triforce_goal', default=0) + ret.triforce_pool_min = get_choice_default('triforce_pool_min', default=0) + ret.triforce_pool_max = get_choice_default('triforce_pool_max', default=0) + ret.triforce_goal_min = get_choice_default('triforce_goal_min', default=0) + ret.triforce_goal_max = get_choice_default('triforce_goal_max', default=0) + ret.triforce_min_difference = get_choice_default('triforce_min_difference', default=0) ret.mode = get_choice('world_state') if ret.mode == 'retro': From 66bd8960a1738d3b91b63f920ce05a9c9a91e078 Mon Sep 17 00:00:00 2001 From: Catobat <69204835+Catobat@users.noreply.github.com> Date: Wed, 26 Jul 2023 15:03:45 +0200 Subject: [PATCH 164/196] Support Triforce Piece settings in Customizer YAML --- source/classes/CustomSettings.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/classes/CustomSettings.py b/source/classes/CustomSettings.py index deb9f4d2..ca0f2062 100644 --- a/source/classes/CustomSettings.py +++ b/source/classes/CustomSettings.py @@ -144,6 +144,11 @@ class CustomSettings(object): args.pseudoboots[p] = get_setting(settings['pseudoboots'], args.pseudoboots[p]) args.triforce_goal[p] = get_setting(settings['triforce_goal'], args.triforce_goal[p]) args.triforce_pool[p] = get_setting(settings['triforce_pool'], args.triforce_pool[p]) + args.triforce_goal_min[p] = get_setting(settings['triforce_goal_min'], args.triforce_goal_min[p]) + args.triforce_goal_max[p] = get_setting(settings['triforce_goal_max'], args.triforce_goal_max[p]) + args.triforce_pool_min[p] = get_setting(settings['triforce_pool_min'], args.triforce_pool_min[p]) + args.triforce_pool_max[p] = get_setting(settings['triforce_pool_max'], args.triforce_pool_max[p]) + args.triforce_min_difference[p] = get_setting(settings['triforce_min_difference'], args.triforce_min_difference[p]) args.beemizer[p] = get_setting(settings['beemizer'], args.beemizer[p]) # mystery usage From bf9ad536fe3aa34f7130815c8ec41fa6671c622f Mon Sep 17 00:00:00 2001 From: Catobat <69204835+Catobat@users.noreply.github.com> Date: Wed, 26 Jul 2023 15:27:47 +0200 Subject: [PATCH 165/196] Implement triforce_max_difference --- CLI.py | 3 ++- Main.py | 2 +- README.md | 3 ++- mystery_example.yml | 1 + mystery_testsuite.yml | 1 + resources/app/cli/args.json | 1 + source/classes/CustomSettings.py | 1 + source/tools/MysteryUtils.py | 1 + 8 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CLI.py b/CLI.py index 85283053..2c925c6c 100644 --- a/CLI.py +++ b/CLI.py @@ -132,7 +132,7 @@ def parse_cli(argv, no_defaults=False): 'flute_mode', 'bow_mode', 'take_any', 'boots_hint', 'shuffle', 'door_shuffle', 'intensity', 'crystals_ganon', 'crystals_gt', 'openpyramid', 'mapshuffle', 'compassshuffle', 'keyshuffle', 'bigkeyshuffle', 'startinventory', - 'usestartinventory', 'bombbag', 'overworld_map', 'restrict_boss_items', + 'usestartinventory', 'bombbag', 'overworld_map', 'restrict_boss_items', 'triforce_max_difference', 'triforce_pool_min', 'triforce_pool_max', 'triforce_goal_min', 'triforce_goal_max', 'triforce_min_difference', 'triforce_goal', 'triforce_pool', 'shufflelinks', 'shuffletavern', 'pseudoboots', 'retro', 'accessibility', 'hints', 'beemizer', 'experimental', 'dungeon_counters', @@ -230,6 +230,7 @@ def parse_settings(): "triforce_goal_min": 0, "triforce_goal_max": 0, "triforce_min_difference": 0, + "triforce_max_difference": 10000, "code": "", "multi": 1, diff --git a/Main.py b/Main.py index 049f5932..17444ce7 100644 --- a/Main.py +++ b/Main.py @@ -146,7 +146,7 @@ def main(args, seed=None, fish=None): if int(args.triforce_pool[p]) != 0: world.treasure_hunt_total[p] = int(args.triforce_pool[p]) elif int(args.triforce_pool_min[p]) != 0 and int(args.triforce_pool_max[p]) != 0: - world.treasure_hunt_total[p] = random.randint(max(int(args.triforce_pool_min[p]), world.treasure_hunt_count[p] + int(args.triforce_min_difference[p])), int(args.triforce_pool_max[p])) + world.treasure_hunt_total[p] = random.randint(max(int(args.triforce_pool_min[p]), world.treasure_hunt_count[p] + int(args.triforce_min_difference[p])), min(int(args.triforce_pool_max[p]), world.treasure_hunt_count[p] + int(args.triforce_max_difference[p]))) else: world.treasure_hunt_total[p] = 10 if world.goal[p] == 'trinity' else 30 else: diff --git a/README.md b/README.md index 21a444cc..df21ad17 100644 --- a/README.md +++ b/README.md @@ -573,13 +573,14 @@ Create bps patch(es) instead of generating rom(s) for distribution. `--bps` ### Triforce Hunt Settings -A collection of settings to control the triforce piece pool for the CLI/Mystery +A collection of settings to control the triforce piece pool if not specified through --triforce_goal and --triforce_pool * --triforce_goal_min: Minimum number of pieces to collect to win * --triforce_goal_max: Maximum number of pieces to collect to win * --triforce_pool_min: Minimum number of pieces in item pool * --triforce_pool_max: Maximum number of pieces in item pool * --triforce_min_difference: Minimum difference between pool and goal to win +* --triforce_max_difference: Maximum difference between pool and goal to win ### Seed diff --git a/mystery_example.yml b/mystery_example.yml index 344875f4..92abd726 100644 --- a/mystery_example.yml +++ b/mystery_example.yml @@ -107,6 +107,7 @@ triforce_pool_min: 20 triforce_pool_max: 40 triforce_min_difference: 10 + triforce_max_difference: 15 dungeon_items: standard: 10 mc: 3 diff --git a/mystery_testsuite.yml b/mystery_testsuite.yml index f919b7cc..d6e46832 100644 --- a/mystery_testsuite.yml +++ b/mystery_testsuite.yml @@ -83,6 +83,7 @@ triforce_goal_max: 30 triforce_pool_min: 30 triforce_pool_max: 40 triforce_min_difference: 10 +triforce_max_difference: 12 map_shuffle: on: 1 off: 1 diff --git a/resources/app/cli/args.json b/resources/app/cli/args.json index 5254a1c4..2eaf847e 100644 --- a/resources/app/cli/args.json +++ b/resources/app/cli/args.json @@ -339,6 +339,7 @@ "triforce_goal_min": {}, "triforce_goal_max": {}, "triforce_min_difference": {}, + "triforce_max_difference": {}, "custom": { "type": "bool", "help": "suppress" diff --git a/source/classes/CustomSettings.py b/source/classes/CustomSettings.py index ca0f2062..a0cea069 100644 --- a/source/classes/CustomSettings.py +++ b/source/classes/CustomSettings.py @@ -149,6 +149,7 @@ class CustomSettings(object): args.triforce_pool_min[p] = get_setting(settings['triforce_pool_min'], args.triforce_pool_min[p]) args.triforce_pool_max[p] = get_setting(settings['triforce_pool_max'], args.triforce_pool_max[p]) args.triforce_min_difference[p] = get_setting(settings['triforce_min_difference'], args.triforce_min_difference[p]) + args.triforce_max_difference[p] = get_setting(settings['triforce_max_difference'], args.triforce_max_difference[p]) args.beemizer[p] = get_setting(settings['beemizer'], args.beemizer[p]) # mystery usage diff --git a/source/tools/MysteryUtils.py b/source/tools/MysteryUtils.py index 32ee9d5f..0405efff 100644 --- a/source/tools/MysteryUtils.py +++ b/source/tools/MysteryUtils.py @@ -132,6 +132,7 @@ def roll_settings(weights): ret.triforce_goal_min = get_choice_default('triforce_goal_min', default=0) ret.triforce_goal_max = get_choice_default('triforce_goal_max', default=0) ret.triforce_min_difference = get_choice_default('triforce_min_difference', default=0) + ret.triforce_max_difference = get_choice_default('triforce_max_difference', default=10000) ret.mode = get_choice('world_state') if ret.mode == 'retro': From 8d17d9564075fefaa275a40044bb123367c1cce1 Mon Sep 17 00:00:00 2001 From: aerinon Date: Thu, 27 Jul 2023 13:45:44 -0600 Subject: [PATCH 166/196] Fixed a generation bug Add ganonhunt to pyramid open --- BaseClasses.py | 2 +- DoorShuffle.py | 20 +++++++++----------- RELEASENOTES.md | 3 +++ 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index af1436eb..c9d4be13 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -283,7 +283,7 @@ class World(object): else: if self.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull']: return False - elif self.goal[player] in ['crystals', 'trinity']: + elif self.goal[player] in ['crystals', 'trinity', 'ganonhunt']: return True else: return False diff --git a/DoorShuffle.py b/DoorShuffle.py index 35cc7624..462eb406 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -2547,13 +2547,12 @@ def reassign_big_key_doors(bk_map, used_doors, world, player): queue = deque(find_current_bk_doors(builder)) while len(queue) > 0: d = queue.pop() - if (d.type is DoorType.Interior and d not in flat_proposal and d.dest not in flat_proposal - and d not in used_doors and d.dest not in used_doors): - if not d.entranceFlag: + if d.type is DoorType.Interior and d not in flat_proposal and d.dest not in flat_proposal: + if not d.entranceFlag and d not in used_doors and d.dest not in used_doors: world.get_room(d.roomIndex, player).change(d.doorListPos, DoorKind.Normal) d.bigKey = False - elif d.type is DoorType.Normal and d not in flat_proposal and d not in used_doors: - if not d.entranceFlag: + elif d.type is DoorType.Normal and d not in flat_proposal : + if not d.entranceFlag and d not in used_doors: world.get_room(d.roomIndex, player).change(d.doorListPos, DoorKind.Normal) d.bigKey = False for obj in big_doors: @@ -3014,7 +3013,7 @@ def reassign_key_doors(small_map, used_doors, world, player): queue = deque(find_current_key_doors(builder)) while len(queue) > 0: d = queue.pop() - if d.type is DoorType.SpiralStairs and d not in proposal and d not in used_doors: + if d.type is DoorType.SpiralStairs and d not in proposal: room = world.get_room(d.roomIndex, player) if room.doorList[d.doorListPos][1] == DoorKind.StairKeyLow: room.delete(d.doorListPos) @@ -3024,15 +3023,14 @@ def reassign_key_doors(small_map, used_doors, world, player): else: room.delete(d.doorListPos) d.smallKey = False - elif (d.type is DoorType.Interior and d not in flat_proposal and d.dest not in flat_proposal - and d not in used_doors and d.dest not in used_doors): - if not d.entranceFlag: + elif d.type is DoorType.Interior and d not in flat_proposal and d.dest not in flat_proposal: + if not d.entranceFlag and d not in used_doors and d.dest not in used_doors: world.get_room(d.roomIndex, player).change(d.doorListPos, DoorKind.Normal) d.smallKey = False d.dest.smallKey = False queue.remove(d.dest) - elif d.type is DoorType.Normal and d not in flat_proposal and d not in used_doors: - if not d.entranceFlag: + elif d.type is DoorType.Normal and d not in flat_proposal: + if not d.entranceFlag and d not in used_doors: world.get_room(d.roomIndex, player).change(d.doorListPos, DoorKind.Normal) d.smallKey = False for dp in world.paired_doors[player]: diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 45577d04..0b8d2151 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -109,6 +109,9 @@ These are now independent of retro mode and have three options: None, Random, an # Bug Fixes and Notes +* 1.2.0.19u + * Fixed a bug with dungeon generation + * Changed the "Ganonhunt" goal to use open pyramid on the Auto setting * 1.2.0.18u * Fixed an issue with pyramid hole being in logic when it is not opened. * Crystal cutscene at GT use new symmetrical layouts (thanks Codemann) From 75fc1f7cc3b06fb451564ef161275aff54883039 Mon Sep 17 00:00:00 2001 From: aerinon Date: Fri, 28 Jul 2023 12:29:47 -0600 Subject: [PATCH 167/196] Fixed customizer example Fixed /missing command in multiworld for non-pottery lottery settings --- Main.py | 2 +- MultiClient.py | 15 ++++++++++++--- RELEASENOTES.md | 5 ++++- docs/customizer_example.yaml | 5 ++++- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/Main.py b/Main.py index 17444ce7..dd5ebc3e 100644 --- a/Main.py +++ b/Main.py @@ -34,7 +34,7 @@ from source.overworld.EntranceShuffle2 import link_entrances_new from source.tools.BPS import create_bps_from_data from source.classes.CustomSettings import CustomSettings -version_number = '1.2.0.18' +version_number = '1.2.0.19' version_branch = '-u' __version__ = f'{version_number}{version_branch}' diff --git a/MultiClient.py b/MultiClient.py index fbde673d..646c60cf 100644 --- a/MultiClient.py +++ b/MultiClient.py @@ -66,6 +66,8 @@ class Context: self.lookup_name_to_id = {} self.lookup_id_to_name = {} + self.pottery_locations_enabled = None + def color_code(*args): codes = {'reset': 0, 'bold': 1, 'underline': 4, 'black': 30, 'red': 31, 'green': 32, 'yellow': 33, 'blue': 34, 'magenta': 35, 'cyan': 36, 'white': 37 , 'black_bg': 40, 'red_bg': 41, 'green_bg': 42, 'yellow_bg': 43, @@ -96,6 +98,8 @@ SHOP_SRAM_START = WRAM_START + 0x0164B8 # 2 bytes? ITEM_SRAM_SIZE = 0x250 SHOP_SRAM_LEN = 0x29 # 41 tracked items +POT_LOCATION_TABLE = 0x142A60 + RECV_PROGRESS_ADDR = SAVEDATA_START + 0x4D0 # 2 bytes RECV_ITEM_ADDR = SAVEDATA_START + 0x4D2 # 1 byte RECV_ITEM_PLAYER_ADDR = SAVEDATA_START + 0x4D3 # 1 byte @@ -826,12 +830,14 @@ def get_location_name_from_address(ctx, address): def filter_location(ctx, location): + if location in location_table_pot_items: + tile_idx, mask = location_table_pot_items[location] + tracking_data = ctx.pottery_locations_enabled + tile_pots = tracking_data[tile_idx] | (tracking_data[tile_idx+1] << 8) + return (mask & tile_pots) == 0 if (not ctx.key_drop_mode and location in PotShuffle.key_drop_data and PotShuffle.key_drop_data[location][0] == 'Drop'): return True - if (not ctx.pottery_mode and location in PotShuffle.key_drop_data - and PotShuffle.key_drop_data[location][0] == 'Pot'): - return True if not ctx.shop_mode and location in Regions.flat_normal_shops: return True if not ctx.retro_mode and location in Regions.flat_retro_shops: @@ -996,6 +1002,9 @@ async def game_watcher(ctx : Context): logging.warning("ROM change detected, please reconnect to the multiworld server") await disconnect(ctx) + if ctx.pottery_locations_enabled is None: + ctx.pottery_locations_enabled = await snes_read(ctx, POT_LOCATION_TABLE, 0x250) + gamemode = await snes_read(ctx, WRAM_START + 0x10, 1) if gamemode is None or gamemode[0] not in INGAME_MODES: continue diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 0b8d2151..7416496f 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -110,8 +110,11 @@ These are now independent of retro mode and have three options: None, Random, an # Bug Fixes and Notes * 1.2.0.19u - * Fixed a bug with dungeon generation + * Added min/max for triforce pool, goal, and differnce for CLI and Customizer. (Thanks Catobat) + * Fixed a bug with dungeon generation + * Multiworld: Fixed /missing command to not list all the pots * Changed the "Ganonhunt" goal to use open pyramid on the Auto setting + * Customizer: Fixed the example yaml for shopsanity * 1.2.0.18u * Fixed an issue with pyramid hole being in logic when it is not opened. * Crystal cutscene at GT use new symmetrical layouts (thanks Codemann) diff --git a/docs/customizer_example.yaml b/docs/customizer_example.yaml index 3d0c7624..76514990 100644 --- a/docs/customizer_example.yaml +++ b/docs/customizer_example.yaml @@ -1,7 +1,7 @@ meta: algorithm: balanced players: 1 - seed: 42 + seed: 41 # note to self: seed 42 had an interesting Swamp Palace problem names: Lonk settings: 1: @@ -56,6 +56,9 @@ item_pool: Sanctuary Heart Container: 3 Shovel: 3 Single Arrow: 1 + Green Potion: 1 + Blue Potion: 1 + Red Potion: 1 placements: 1: Palace of Darkness - Big Chest: Hammer From 1592fac79293265aba0e564d9c11e4db602467d7 Mon Sep 17 00:00:00 2001 From: aerinon Date: Fri, 28 Jul 2023 12:32:28 -0600 Subject: [PATCH 168/196] Typo --- RELEASENOTES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 7416496f..3231157f 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -110,7 +110,7 @@ These are now independent of retro mode and have three options: None, Random, an # Bug Fixes and Notes * 1.2.0.19u - * Added min/max for triforce pool, goal, and differnce for CLI and Customizer. (Thanks Catobat) + * Added min/max for triforce pool, goal, and difference for CLI and Customizer. (Thanks Catobat) * Fixed a bug with dungeon generation * Multiworld: Fixed /missing command to not list all the pots * Changed the "Ganonhunt" goal to use open pyramid on the Auto setting From 982032e156bcaee7a3b643089d47f714b2dd15c5 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sat, 29 Jul 2023 05:04:46 -0500 Subject: [PATCH 169/196] Supporting old keyshuffle keywords --- BaseClasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BaseClasses.py b/BaseClasses.py index 263bd223..d6ac2c28 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -3450,7 +3450,7 @@ flutespot_mode = {"vanilla": 0, "balanced": 1, "random": 2} # byte 13: FBBB TTSS (flute_mode, bow_mode, take_any, small_key_mode) flute_mode = {'normal': 0, 'active': 1} -keyshuffle_mode = {'none': 0, 'wild': 1, 'universal': 2} # reserved 8 modes? +keyshuffle_mode = {'none': 0, 'off': 0, 'wild': 1, 'on': 1, 'universal': 2} # reserved 8 modes? take_any_mode = {'none': 0, 'random': 1, 'fixed': 2} bow_mode = {'progressive': 0, 'silvers': 1, 'retro': 2, 'retro_silvers': 3} From 35f3abc1c1041d69aee2ebe8e9bf23430923f422 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sat, 29 Jul 2023 05:10:47 -0500 Subject: [PATCH 170/196] Creating user notes field to be supplied by the seed roller --- BaseClasses.py | 3 +++ CLI.py | 3 ++- Main.py | 2 +- docs/customizer_example.yaml | 1 + resources/app/cli/args.json | 1 + source/classes/CustomSettings.py | 6 ++++-- 6 files changed, 12 insertions(+), 4 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index d6ac2c28..c79eb691 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -2898,6 +2898,7 @@ class Spoiler(object): 'triforcegoal': self.world.treasure_hunt_count, 'triforcepool': self.world.treasure_hunt_total, 'race': self.world.settings.world_rep['meta']['race'], + 'user_notes': self.world.settings.world_rep['meta']['user_notes'], 'code': {p: Settings.make_code(self.world, p) for p in range(1, self.world.players + 1)}, 'seed': self.world.seed } @@ -3047,6 +3048,8 @@ class Spoiler(object): outfile.write('ALttP Overworld Randomizer - Seed: %s\n\n' % (self.world.seed)) for k,v in self.metadata["versions"].items(): outfile.write((k + ' Version:').ljust(line_width) + '%s\n' % v) + if self.metadata['user_notes']: + outfile.write('User Notes:'.ljust(line_width) + '%s\n' % self.metadata['user_notes']) outfile.write('Filling Algorithm:'.ljust(line_width) + '%s\n' % self.world.algorithm) outfile.write('Players:'.ljust(line_width) + '%d\n' % self.world.players) outfile.write('Teams:'.ljust(line_width) + '%d\n' % self.world.teams) diff --git a/CLI.py b/CLI.py index b554d20f..1249f89b 100644 --- a/CLI.py +++ b/CLI.py @@ -355,7 +355,8 @@ def parse_settings(): "outputpath": os.path.join("."), "saveonexit": "ask", "outputname": "", - "startinventoryarray": {} + "startinventoryarray": {}, + "notes": "" } if sys.platform.lower().find("windows"): diff --git a/Main.py b/Main.py index 3d8d46e3..449d7977 100644 --- a/Main.py +++ b/Main.py @@ -183,7 +183,7 @@ def main(args, seed=None, fish=None): world.player_names[player].append(name) logger.info('') world.settings = CustomSettings() - world.settings.create_from_world(world, args.race) + world.settings.create_from_world(world, args) outfilebase = f'OR_{args.outputname if args.outputname else world.seed}' diff --git a/docs/customizer_example.yaml b/docs/customizer_example.yaml index 82505821..4c31cb7e 100644 --- a/docs/customizer_example.yaml +++ b/docs/customizer_example.yaml @@ -3,6 +3,7 @@ meta: players: 1 seed: 41 # note to self: seed 42 had an interesting Swamp Palace problem names: Lonk + notes: "Some notes specified by the user" settings: 1: door_shuffle: basic diff --git a/resources/app/cli/args.json b/resources/app/cli/args.json index 08ccec98..75456d19 100644 --- a/resources/app/cli/args.json +++ b/resources/app/cli/args.json @@ -576,5 +576,6 @@ ] }, "outputname": {}, + "notes": {}, "code": {} } \ No newline at end of file diff --git a/source/classes/CustomSettings.py b/source/classes/CustomSettings.py index 5d02ca14..99972d7f 100644 --- a/source/classes/CustomSettings.py +++ b/source/classes/CustomSettings.py @@ -63,6 +63,7 @@ class CustomSettings(object): args.suppress_rom = get_setting(meta['suppress_rom'], args.suppress_rom) args.names = get_setting(meta['names'], args.names) args.race = get_setting(meta['race'], args.race) + args.notes = get_setting(meta['user_notes'], args.notes) self.player_range = range(1, args.multi + 1) if 'settings' in self.file_source: for p in self.player_range: @@ -227,14 +228,15 @@ class CustomSettings(object): return self.file_source['drops'] return None - def create_from_world(self, world, race): + def create_from_world(self, world, settings): self.player_range = range(1, world.players + 1) settings_dict, meta_dict = {}, {} self.world_rep['meta'] = meta_dict meta_dict['players'] = world.players meta_dict['algorithm'] = world.algorithm meta_dict['seed'] = world.seed - meta_dict['race'] = race + meta_dict['race'] = settings.race + meta_dict['user_notes'] = settings.notes self.world_rep['settings'] = settings_dict for p in self.player_range: settings_dict[p] = {} From 0ee88618a72cf720862d8db0f77b563db0438366 Mon Sep 17 00:00:00 2001 From: aerinon Date: Tue, 1 Aug 2023 11:31:59 -0600 Subject: [PATCH 171/196] Paired dungeon shuffle --- BaseClasses.py | 3 +- DoorShuffle.py | 57 +++++++++++++--------------------- resources/app/cli/args.json | 1 + resources/app/cli/lang/en.json | 1 + resources/app/gui/lang/en.json | 1 + 5 files changed, 26 insertions(+), 37 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index c9d4be13..3663a962 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -80,6 +80,7 @@ class World(object): self.rooms = [] self._room_cache = {} self.dungeon_layouts = {} + self.dungeon_pool = {} self.inaccessible_regions = {} self.enabled_entrances = {} self.key_logic = {} @@ -2922,7 +2923,7 @@ class Pot(object): # byte 0: DDDE EEEE (DR, ER) -dr_mode = {"basic": 1, "crossed": 2, "vanilla": 0, "partitioned": 3} +dr_mode = {"basic": 1, "crossed": 2, "vanilla": 0, "partitioned": 3, 'paired': 4} er_mode = {"vanilla": 0, "simple": 1, "restricted": 2, "full": 3, "crossed": 4, "insanity": 5, 'lite': 8, 'lean': 9, "dungeonsfull": 7, "dungeonssimple": 6} diff --git a/DoorShuffle.py b/DoorShuffle.py index 462eb406..abf1def8 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -88,7 +88,9 @@ def link_doors_prep(world, player): find_inaccessible_regions(world, player) - if world.intensity[player] >= 3 and world.doorShuffle[player] != 'vanilla': + if world.doorShuffle[player] != 'vanilla': + create_dungeon_pool(world, player) + if world.intensity[player] >= 3 and world.doorShuffle[player] != 'vanilla': choose_portals(world, player) else: if world.shuffle[player] == 'vanilla': @@ -132,6 +134,20 @@ def create_dungeon_pool(world, player): pool = None if world.doorShuffle[player] == 'basic': pool = [([name], regions) for name, regions in dungeon_regions.items()] + elif world.doorShuffle[player] == 'paired': + dungeon_pool = list(dungeon_regions.keys()) + groups = [] + while dungeon_pool: + if len(dungeon_pool) == 3: + groups.append(list(dungeon_pool)) + dungeon_pool.clear() + else: + choice_a = random.choice(dungeon_pool) + dungeon_pool.remove(choice_a) + choice_b = random.choice(dungeon_pool) + dungeon_pool.remove(choice_b) + groups.append([choice_a, choice_b]) + pool = [(group, list(chain.from_iterable([dungeon_regions[d] for d in group]))) for group in groups] elif world.doorShuffle[player] == 'partitioned': groups = [['Hyrule Castle', 'Eastern Palace', 'Desert Palace', 'Tower of Hera', 'Agahnims Tower'], ['Palace of Darkness', 'Swamp Palace', 'Skull Woods', 'Thieves Town'], @@ -142,38 +158,17 @@ def create_dungeon_pool(world, player): elif world.doorShuffle[player] != 'vanilla': logging.getLogger('').error('Invalid door shuffle setting: %s' % world.doorShuffle[player]) raise Exception('Invalid door shuffle setting: %s' % world.doorShuffle[player]) - return pool + world.dungeon_pool[player] = pool def link_doors_main(world, player): - pool = create_dungeon_pool(world, player) + pool = world.dungeon_pool[player] if pool: main_dungeon_pool(pool, world, player) if world.doorShuffle[player] != 'vanilla': create_door_spoiler(world, player) -# todo: I think this function is not necessary -def mark_regions(world, player): - # traverse dungeons and make sure dungeon property is assigned - player_dungeons = [dungeon for dungeon in world.dungeons if dungeon.player == player] - for dungeon in player_dungeons: - queue = deque(dungeon.regions) - while len(queue) > 0: - region = world.get_region(queue.popleft(), player) - if region.name not in dungeon.regions: - dungeon.regions.append(region.name) - region.dungeon = dungeon - for ext in region.exits: - d = world.check_for_door(ext.name, player) - connected = ext.connected_region - if d is not None and connected is not None: - if d.dest is not None and connected.name not in dungeon.regions and connected.type == RegionType.Dungeon and connected.name not in queue: - queue.append(connected) # needs to be added - elif connected is not None and connected.name not in dungeon.regions and connected.type == RegionType.Dungeon and connected.name not in queue: - queue.append(connected) # needs to be added - - def create_door_spoiler(world, player): logger = logging.getLogger('') shuffled_door_types = [DoorType.Normal, DoorType.SpiralStairs] @@ -437,17 +432,7 @@ def pair_existing_key_doors(world, player, door_a, door_b): def choose_portals(world, player): if world.doorShuffle[player] != ['vanilla']: shuffle_flag = world.doorShuffle[player] != 'basic' - allowed = {} - if world.doorShuffle[player] == 'basic': - allowed = {name: {name} for name in dungeon_regions} - elif world.doorShuffle[player] == 'partitioned': - groups = [['Hyrule Castle', 'Eastern Palace', 'Desert Palace', 'Tower of Hera', 'Agahnims Tower'], - ['Palace of Darkness', 'Swamp Palace', 'Skull Woods', 'Thieves Town'], - ['Ice Palace', 'Misery Mire', 'Turtle Rock', 'Ganons Tower']] - allowed = {name: set(group) for group in groups for name in group} - elif world.doorShuffle[player] == 'crossed': - all_dungeons = set(dungeon_regions.keys()) - allowed = {name: all_dungeons for name in dungeon_regions} + allowed = {name: set(group[0]) for group in world.dungeon_pool[player] for name in group[0]} # key drops allow the big key in the right place in Desert Tiles 2 bk_shuffle = world.bigkeyshuffle[player] or world.pottery[player] not in ['none', 'cave'] @@ -592,7 +577,7 @@ def customizer_portals(master_door_list, world, player): assigned_doors.add(door) # restricts connected doors to the customized portals if assigned_doors: - pool = create_dungeon_pool(world, player) + pool = world.dungeon_pool[player] if pool: pool_map = {} for pool, region_list in pool: diff --git a/resources/app/cli/args.json b/resources/app/cli/args.json index 2eaf847e..9aff422a 100644 --- a/resources/app/cli/args.json +++ b/resources/app/cli/args.json @@ -175,6 +175,7 @@ "door_shuffle": { "choices": [ "basic", + "paired", "partitioned", "crossed", "vanilla" diff --git a/resources/app/cli/lang/en.json b/resources/app/cli/lang/en.json index 4d5fb151..49bd891a 100644 --- a/resources/app/cli/lang/en.json +++ b/resources/app/cli/lang/en.json @@ -220,6 +220,7 @@ "door_shuffle": [ "Select Door Shuffling Algorithm. (default: %(default)s)", "Basic: Doors are mixed within a single dungeon.", + "Paired Dungeon are paired (with one trio) and only mixed in those groups", "Partitioned Doors are mixed in 3 partitions: L1-3+HC+AT, D1-4, D5-8", "Crossed: Doors are mixed between all dungeons.", "Vanilla: All doors are connected the same way they were in the", diff --git a/resources/app/gui/lang/en.json b/resources/app/gui/lang/en.json index 9d56137c..fb81c391 100644 --- a/resources/app/gui/lang/en.json +++ b/resources/app/gui/lang/en.json @@ -62,6 +62,7 @@ "randomizer.dungeon.dungeondoorshuffle": "Dungeon Door Shuffle", "randomizer.dungeon.dungeondoorshuffle.vanilla": "Vanilla", "randomizer.dungeon.dungeondoorshuffle.basic": "Basic", + "randomizer.dungeon.dungeondoorshuffle.paired": "Paired", "randomizer.dungeon.dungeondoorshuffle.partitioned": "Partitioned", "randomizer.dungeon.dungeondoorshuffle.crossed": "Crossed", From 1817cf38242e6ba14a05bab682b5461fa3970edb Mon Sep 17 00:00:00 2001 From: Catobat <69204835+Catobat@users.noreply.github.com> Date: Tue, 1 Aug 2023 22:00:58 +0200 Subject: [PATCH 172/196] Fix byte 12 in settings code --- BaseClasses.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index c9d4be13..122d6de4 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -3028,8 +3028,8 @@ class Settings(object): (flute_mode[w.flute_mode[p]] << 7 | bow_mode[w.bow_mode[p]] << 4 | take_any_mode[w.take_any[p]] << 2 | keyshuffle_mode[w.keyshuffle[p]]), - ((0x80 if w.pseudoboots[p] else 0) | overworld_map_mode[w.overworld_map[p]] << 6 - | trap_door_mode[w.trap_door_mode[p]] << 4 | key_logic_algo[w.key_logic_algorithm[p]]), + ((0x80 if w.pseudoboots[p] else 0) | overworld_map_mode[w.overworld_map[p]] << 5 + | trap_door_mode[w.trap_door_mode[p]] << 3 | key_logic_algo[w.key_logic_algorithm[p]]), ]) return base64.b64encode(code, "+-".encode()).decode() @@ -3099,8 +3099,8 @@ class Settings(object): args.keyshuffle[p] = r(keyshuffle_mode)[settings[11] & 0x3] if len(settings) > 12: args.pseudoboots[p] = True if settings[12] & 0x80 else False - args.overworld_map[p] = r(overworld_map_mode)[(settings[12] & 0x60) >> 6] - args.trap_door_mode[p] = r(trap_door_mode)[(settings[12] & 0x14) >> 4] + args.overworld_map[p] = r(overworld_map_mode)[(settings[12] & 0x60) >> 5] + args.trap_door_mode[p] = r(trap_door_mode)[(settings[12] & 0x18) >> 3] args.key_logic_algorithm[p] = r(key_logic_algo)[settings[12] & 0x07] From 7197a23b4520a67c9005d60b2859de060c585c51 Mon Sep 17 00:00:00 2001 From: Catobat <69204835+Catobat@users.noreply.github.com> Date: Wed, 2 Aug 2023 02:23:19 +0200 Subject: [PATCH 173/196] Add setting for self-looping doors --- BaseClasses.py | 15 ++++++++++----- CLI.py | 3 ++- Main.py | 2 ++ README.md | 8 +++++++- mystery_example.yml | 3 +++ mystery_testsuite.yml | 3 +++ resources/app/cli/args.json | 4 ++++ resources/app/cli/lang/en.json | 1 + resources/app/gui/lang/en.json | 1 + resources/app/gui/randomize/dungeon/widgets.json | 6 ++++++ source/classes/CustomSettings.py | 2 ++ source/classes/constants.py | 1 + source/dungeon/DungeonStitcher.py | 14 +++++++++++--- source/tools/MysteryUtils.py | 1 + 14 files changed, 54 insertions(+), 10 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index 122d6de4..89b39a43 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -145,6 +145,7 @@ class World(object): set_player_attr('colorizepots', True) set_player_attr('pot_pool', {}) set_player_attr('decoupledoors', False) + set_player_attr('door_self_loops', False) set_player_attr('door_type_mode', 'original') set_player_attr('trap_door_mode', 'optional') set_player_attr('key_logic_algorithm', 'default') @@ -2472,6 +2473,7 @@ class Spoiler(object): 'trap_door_mode': self.world.trap_door_mode, 'key_logic': self.world.key_logic_algorithm, 'decoupledoors': self.world.decoupledoors, + 'door_self_loops': self.world.door_self_loops, 'dungeon_counters': self.world.dungeon_counters, 'item_pool': self.world.difficulty, 'item_functionality': self.world.difficulty_adjustments, @@ -2682,6 +2684,7 @@ class Spoiler(object): outfile.write(f"Trap Door Mode: {self.metadata['trap_door_mode'][player]}\n") outfile.write(f"Key Logic Algorithm: {self.metadata['key_logic'][player]}\n") outfile.write(f"Decouple Doors: {yn(self.metadata['decoupledoors'][player])}\n") + outfile.write(f"Spiral Stairs can self-loop: {yn(self.metadata['door_self_loops'][player])}\n") outfile.write(f"Experimental: {yn(self.metadata['experimental'][player])}\n") outfile.write(f"Dungeon Counters: {self.metadata['dungeon_counters'][player]}\n") outfile.write(f"Drop Shuffle: {yn(self.metadata['dropshuffle'][player])}\n") @@ -2947,10 +2950,10 @@ mixed_travel_mode = {"prevent": 0, "allow": 1, "force": 2} pottery_mode = {'none': 0, 'keys': 2, 'lottery': 3, 'dungeon': 4, 'cave': 5, 'cavekeys': 6, 'reduced': 7, 'clustered': 8, 'nonempty': 9} -# byte 5: CCCC CTTX (crystals gt, ctr2, experimental) +# byte 5: SCCC CTTX (self-loop doors, crystals gt, ctr2, experimental) counter_mode = {"default": 0, "off": 1, "on": 2, "pickup": 3} -# byte 6: CCCC CPAA (crystals ganon, pyramid, access +# byte 6: ?CCC CPAA (crystals ganon, pyramid, access access_mode = {"items": 0, "locations": 1, "none": 2} # byte 7: B?MC DDEE (big, ?, maps, compass, door_type, enemies) @@ -3008,7 +3011,8 @@ class Settings(object): (0x80 if w.shuffletavern[p] else 0) | (0x10 if w.dropshuffle[p] else 0) | (pottery_mode[w.pottery[p]]), - ((8 if w.crystals_gt_orig[p] == "random" else int(w.crystals_gt_orig[p])) << 3) + (0x80 if w.door_self_loops[p] else 0) + | ((8 if w.crystals_gt_orig[p] == "random" else int(w.crystals_gt_orig[p])) << 3) | (counter_mode[w.dungeon_counters[p]] << 1) | (1 if w.experimental[p] else 0), ((8 if w.crystals_ganon_orig[p] == "random" else int(w.crystals_ganon_orig[p])) << 3) @@ -3067,12 +3071,13 @@ class Settings(object): args.dropshuffle[p] = True if settings[4] & 0x10 else False args.pottery[p] = r(pottery_mode)[settings[4] & 0x0F] + args.door_self_loops[p] = True if settings[5] & 0x80 else False args.dungeon_counters[p] = r(counter_mode)[(settings[5] & 0x6) >> 1] - cgt = (settings[5] & 0xf8) >> 3 + cgt = (settings[5] & 0x78) >> 3 args.crystals_gt[p] = "random" if cgt == 8 else cgt args.experimental[p] = True if settings[5] & 0x1 else False - cgan = (settings[6] & 0xf8) >> 3 + cgan = (settings[6] & 0x78) >> 3 args.crystals_ganon[p] = "random" if cgan == 8 else cgan args.openpyramid[p] = True if settings[6] & 0x4 else False diff --git a/CLI.py b/CLI.py index 2c925c6c..ec7ce8c9 100644 --- a/CLI.py +++ b/CLI.py @@ -141,7 +141,7 @@ def parse_cli(argv, no_defaults=False): 'heartbeep', 'remote_items', 'shopsanity', 'dropshuffle', 'pottery', 'keydropshuffle', 'mixed_travel', 'standardize_palettes', 'code', 'reduce_flashing', 'shuffle_sfx', 'msu_resume', 'collection_rate', 'colorizepots', 'decoupledoors', 'door_type_mode', - 'trap_door_mode', 'key_logic_algorithm']: + 'trap_door_mode', 'key_logic_algorithm', 'door_self_loops']: value = getattr(defaults, name) if getattr(playerargs, name) is None else getattr(playerargs, name) if player == 1: setattr(ret, name, {1: value}) @@ -218,6 +218,7 @@ def parse_settings(): 'trap_door_mode': 'optional', 'key_logic_algorithm': 'default', 'decoupledoors': False, + 'door_self_loops': False, 'experimental': False, 'dungeon_counters': 'default', 'mixed_travel': 'prevent', diff --git a/Main.py b/Main.py index dd5ebc3e..d1dca6af 100644 --- a/Main.py +++ b/Main.py @@ -115,6 +115,7 @@ def main(args, seed=None, fish=None): world.trap_door_mode = args.trap_door_mode.copy() world.key_logic_algorithm = args.key_logic_algorithm.copy() world.decoupledoors = args.decoupledoors.copy() + world.door_self_loops = args.door_self_loops.copy() world.experimental = args.experimental.copy() world.dungeon_counters = args.dungeon_counters.copy() world.fish = fish @@ -487,6 +488,7 @@ def copy_world(world): ret.beemizer = world.beemizer.copy() ret.intensity = world.intensity.copy() ret.decoupledoors = world.decoupledoors.copy() + ret.door_self_loops = world.door_self_loops.copy() ret.experimental = world.experimental.copy() ret.shopsanity = world.shopsanity.copy() ret.dropshuffle = world.dropshuffle.copy() diff --git a/README.md b/README.md index df21ad17..24e79807 100644 --- a/README.md +++ b/README.md @@ -174,7 +174,13 @@ CLI: `--key_logic [default|partial|strict]` This is similar to insanity mode in ER where door entrances and exits are not paired anymore. Tends to remove more logic from dungeons as many rooms will not be required to traverse to explore. Hope you like transitions. -CLI `--decoupledoors` +CLI: `--decoupledoors` + +### Self-Looping Spiral Stairs + +If enabled, spiral stairs are allowed to lead to themselves. + +CLI: `--door_self_loops` ### Pottery diff --git a/mystery_example.yml b/mystery_example.yml index 92abd726..bd8cbbe2 100644 --- a/mystery_example.yml +++ b/mystery_example.yml @@ -31,6 +31,9 @@ partial: 0 strict: 0 decoupledoors: off + door_self_loops: + on: 1 + off: 1 dropshuffle: on: 1 off: 1 diff --git a/mystery_testsuite.yml b/mystery_testsuite.yml index d6e46832..c7250d2b 100644 --- a/mystery_testsuite.yml +++ b/mystery_testsuite.yml @@ -31,6 +31,9 @@ key_logic_algorithm: decoupledoors: off: 9 # more strict on: 1 +door_self_loops: + on: 1 + off: 1 dropshuffle: on: 1 off: 1 diff --git a/resources/app/cli/args.json b/resources/app/cli/args.json index 2eaf847e..626a3b72 100644 --- a/resources/app/cli/args.json +++ b/resources/app/cli/args.json @@ -212,6 +212,10 @@ "action": "store_true", "type": "bool" }, + "door_self_loops": { + "action": "store_true", + "type": "bool" + }, "experimental": { "action": "store_true", "type": "bool" diff --git a/resources/app/cli/lang/en.json b/resources/app/cli/lang/en.json index 4d5fb151..031a1061 100644 --- a/resources/app/cli/lang/en.json +++ b/resources/app/cli/lang/en.json @@ -253,6 +253,7 @@ "strict: Ensure small keys are available" ], "decoupledoors" : [ "Door entrances and exits are decoupled" ], + "door_self_loops" : [ "Spiral stairs are allowed to self-loop" ], "experimental": [ "Enable experimental features. (default: %(default)s)" ], "dungeon_counters": [ "Enable dungeon chest counters. (default: %(default)s)" ], "crystals_ganon": [ diff --git a/resources/app/gui/lang/en.json b/resources/app/gui/lang/en.json index 9d56137c..87bf4e03 100644 --- a/resources/app/gui/lang/en.json +++ b/resources/app/gui/lang/en.json @@ -58,6 +58,7 @@ "randomizer.dungeon.smallkeyshuffle.universal": "Universal", "randomizer.dungeon.bigkeyshuffle": "Big Keys", "randomizer.dungeon.decoupledoors": "Decouple Doors", + "randomizer.dungeon.door_self_loops": "Allow Self-Looping Spiral Stairs", "randomizer.dungeon.dungeondoorshuffle": "Dungeon Door Shuffle", "randomizer.dungeon.dungeondoorshuffle.vanilla": "Vanilla", diff --git a/resources/app/gui/randomize/dungeon/widgets.json b/resources/app/gui/randomize/dungeon/widgets.json index bcf7232a..4be6a385 100644 --- a/resources/app/gui/randomize/dungeon/widgets.json +++ b/resources/app/gui/randomize/dungeon/widgets.json @@ -66,6 +66,12 @@ } }, "decoupledoors": { + "type": "checkbox", + "config": { + "padx": [20,0] + } + }, + "door_self_loops": { "type": "checkbox", "config": { "padx": [20,0], diff --git a/source/classes/CustomSettings.py b/source/classes/CustomSettings.py index a0cea069..2ddc1747 100644 --- a/source/classes/CustomSettings.py +++ b/source/classes/CustomSettings.py @@ -113,6 +113,7 @@ class CustomSettings(object): args.trap_door_mode[p] = get_setting(settings['trap_door_mode'], args.trap_door_mode[p]) args.key_logic_algorithm[p] = get_setting(settings['key_logic_algorithm'], args.key_logic_algorithm[p]) args.decoupledoors[p] = get_setting(settings['decoupledoors'], args.decoupledoors[p]) + args.door_self_loops[p] = get_setting(settings['door_self_loops'], args.door_self_loops[p]) args.dungeon_counters[p] = get_setting(settings['dungeon_counters'], args.dungeon_counters[p]) args.crystals_gt[p] = get_setting(settings['crystals_gt'], args.crystals_gt[p]) args.crystals_ganon[p] = get_setting(settings['crystals_ganon'], args.crystals_ganon[p]) @@ -232,6 +233,7 @@ class CustomSettings(object): settings_dict[p]['trap_door_mode'] = world.trap_door_mode[p] settings_dict[p]['key_logic_algorithm'] = world.key_logic_algorithm[p] settings_dict[p]['decoupledoors'] = world.decoupledoors[p] + settings_dict[p]['door_self_loops'] = world.door_self_loops[p] settings_dict[p]['logic'] = world.logic[p] settings_dict[p]['mode'] = world.mode[p] settings_dict[p]['swords'] = world.swords[p] diff --git a/source/classes/constants.py b/source/classes/constants.py index 812042b8..1ca3c08e 100644 --- a/source/classes/constants.py +++ b/source/classes/constants.py @@ -106,6 +106,7 @@ SETTINGSTOPROCESS = { "door_type_mode": "door_type_mode", "trap_door_mode": "trap_door_mode", "decoupledoors": "decoupledoors", + "door_self_loops": "door_self_loops", "experimental": "experimental", "dungeon_counters": "dungeon_counters", "mixed_travel": "mixed_travel", diff --git a/source/dungeon/DungeonStitcher.py b/source/dungeon/DungeonStitcher.py index 1eac3fb1..ec61b829 100644 --- a/source/dungeon/DungeonStitcher.py +++ b/source/dungeon/DungeonStitcher.py @@ -22,7 +22,7 @@ def generate_dungeon(builder, entrance_region_names, split_dungeon, world, playe queue = collections.deque(proposed_map.items()) while len(queue) > 0: a, b = queue.popleft() - if world.decoupledoors[player]: + if a == b or world.decoupledoors[player]: connect_doors_one_way(a, b) else: connect_doors(a, b) @@ -128,14 +128,14 @@ def create_random_proposal(doors_to_connect, world, player): next_hook = random.choice(hooks_left) primary_door = random.choice(primary_bucket[next_hook]) opp_hook, secondary_door = type_map[next_hook], None - while (secondary_door is None or secondary_door == primary_door + while (secondary_door is None or (secondary_door == primary_door and not world.door_self_loops[player]) or decouple_check(primary_bucket[next_hook], secondary_bucket[opp_hook], primary_door, secondary_door, world, player)): secondary_door = random.choice(secondary_bucket[opp_hook]) proposal[primary_door] = secondary_door primary_bucket[next_hook].remove(primary_door) secondary_bucket[opp_hook].remove(secondary_door) - if not world.decoupledoors[player]: + if primary_door != secondary_door and not world.decoupledoors[player]: proposal[secondary_door] = primary_door primary_bucket[opp_hook].remove(secondary_door) secondary_bucket[next_hook].remove(primary_door) @@ -205,6 +205,14 @@ def modify_proposal(proposed_map, explored_state, doors_to_connect, hash_code_se old_attempt = proposed_map[new_door] else: old_attempt = next(x for x in proposed_map if proposed_map[x] == new_door) + # ensure nothing gets messed up when something loops with itself + if attempt == old_target and old_attempt == new_door: + old_attempt = new_door + old_target = attempt + elif attempt == old_target: + old_target = old_attempt + elif old_attempt == new_door: + old_attempt = old_target proposed_map[old_attempt] = old_target if not world.decoupledoors[player]: proposed_map[old_target] = old_attempt diff --git a/source/tools/MysteryUtils.py b/source/tools/MysteryUtils.py index 0405efff..5000f670 100644 --- a/source/tools/MysteryUtils.py +++ b/source/tools/MysteryUtils.py @@ -87,6 +87,7 @@ def roll_settings(weights): ret.trap_door_mode = get_choice('trap_door_mode') ret.key_logic_algorithm = get_choice('key_logic_algorithm') ret.decoupledoors = get_choice('decoupledoors') == 'on' + ret.door_self_loops = get_choice('door_self_loops') == 'on' ret.experimental = get_choice('experimental') == 'on' ret.collection_rate = get_choice('collection_rate') == 'on' From 9497ef36ad17867ab6a3d435719c49ef26e1698b Mon Sep 17 00:00:00 2001 From: aerinon Date: Wed, 2 Aug 2023 08:05:54 -0600 Subject: [PATCH 174/196] Paired needs a bunch of generation work apparently. Disabling it. Minor generation improvements. --- DungeonGenerator.py | 32 ++++++++++++++++++++++---------- resources/app/cli/args.json | 1 - 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/DungeonGenerator.py b/DungeonGenerator.py index f97f8ecf..d96b654a 100644 --- a/DungeonGenerator.py +++ b/DungeonGenerator.py @@ -1677,10 +1677,24 @@ def assign_location_sectors_minimal(dungeon_map, free_location_sectors, global_p random.shuffle(sector_list) orig_location_set = build_orig_location_set(dungeon_map) num_dungeon_items = requested_dungeon_items(world, player) + locations_to_distribute = sum(sector.chest_locations for sector in free_location_sectors.keys()) + reserved_per_dungeon = {d_name: count_reserved_locations(world, player, orig_location_set[d_name]) + for d_name in dungeon_map.keys()} + base_free, found_enough = 2, False + while not found_enough: + needed = sum(max(0, max(base_free, reserved_per_dungeon[d]) + num_dungeon_items - len(orig_location_set[d])) + for d in dungeon_map.keys()) + if needed > locations_to_distribute: + if base_free == 0: + raise Exception('Unable to meet minimum requirements, check for customizer problems') + base_free -= 1 + else: + found_enough = True d_idx = {builder.name: i for i, builder in enumerate(dungeon_map.values())} next_sector = sector_list.pop() while not valid: - choice, totals, location_set = weighted_random_location(dungeon_map, choices, orig_location_set, world, player) + choice, totals, location_set = weighted_random_location(dungeon_map, choices, orig_location_set, + base_free, world, player) if not choice: break choices[choice].append(next_sector) @@ -1691,7 +1705,7 @@ def assign_location_sectors_minimal(dungeon_map, free_location_sectors, global_p valid = True for d_name, idx in d_idx.items(): free_items = count_reserved_locations(world, player, location_set[d_name]) - target = max(free_items, 2) + num_dungeon_items + target = max(free_items, base_free) + num_dungeon_items if totals[idx] < target: valid = False break @@ -1699,8 +1713,7 @@ def assign_location_sectors_minimal(dungeon_map, free_location_sectors, global_p if len(sector_list) == 0: choices = defaultdict(list) sector_list = list(free_location_sectors) - else: - next_sector = sector_list.pop() + next_sector = sector_list.pop() else: choices[choice].remove(next_sector) for builder, choice_list in choices.items(): @@ -1709,7 +1722,7 @@ def assign_location_sectors_minimal(dungeon_map, free_location_sectors, global_p return free_location_sectors -def weighted_random_location(dungeon_map, choices, orig_location_set, world, player): +def weighted_random_location(dungeon_map, choices, orig_location_set, base_free, world, player): population = [] totals = [] location_set = {x: set(y) for x, y in orig_location_set.items()} @@ -1720,7 +1733,7 @@ def weighted_random_location(dungeon_map, choices, orig_location_set, world, pla builder_set = location_set[dungeon_builder.name] builder_set.update(set().union(*(s.chest_location_set for s in choices[dungeon_builder]))) free_items = count_reserved_locations(world, player, builder_set) - target = max(free_items, 2) + num_dungeon_items + target = max(free_items, base_free) + num_dungeon_items if ttl < target: population.append(dungeon_builder) choice = random.choice(population) if len(population) > 0 else None @@ -1775,7 +1788,7 @@ def count_reserved_locations(world, player, proposed_set): return 2 -def assign_crystal_switch_sectors(dungeon_map, crystal_switches, crystal_barriers, global_pole, assign_one=False): +def assign_crystal_switch_sectors(dungeon_map, crystal_switches, crystal_barriers, global_pole): population = [] some_c_switches_present = False for name, builder in dungeon_map.items(): @@ -1784,7 +1797,7 @@ def assign_crystal_switch_sectors(dungeon_map, crystal_switches, crystal_barrier if builder.c_switch_present and not builder.c_locked: some_c_switches_present = True if len(population) == 0: # nothing needs a switch - if assign_one and not some_c_switches_present: # something should have one + if len(crystal_barriers) > 0 and not some_c_switches_present: # something should have one if len(crystal_switches) == 0: raise GenerationException('No crystal switches to assign. Ref %s' % next(iter(dungeon_map.keys()))) valid, builder_choice, switch_choice = False, None, None @@ -3139,8 +3152,7 @@ def balance_split(candidate_sectors, dungeon_map, global_pole, builder_info): check_for_forced_assignments(dungeon_map, candidate_sectors, global_pole) check_for_forced_crystal(dungeon_map, candidate_sectors, global_pole) crystal_switches, crystal_barriers, neutral_sectors, polarized_sectors = categorize_sectors(candidate_sectors) - leftover = assign_crystal_switch_sectors(dungeon_map, crystal_switches, crystal_barriers, - global_pole, len(crystal_barriers) > 0) + leftover = assign_crystal_switch_sectors(dungeon_map, crystal_switches, crystal_barriers, global_pole) ensure_crystal_switches_reachable(dungeon_map, leftover, polarized_sectors, crystal_barriers, global_pole) for sector in leftover: if sector.polarity().is_neutral(): diff --git a/resources/app/cli/args.json b/resources/app/cli/args.json index 9aff422a..2eaf847e 100644 --- a/resources/app/cli/args.json +++ b/resources/app/cli/args.json @@ -175,7 +175,6 @@ "door_shuffle": { "choices": [ "basic", - "paired", "partitioned", "crossed", "vanilla" From f2b8c840a25a5c433534d9fdde1345e7f1f6babb Mon Sep 17 00:00:00 2001 From: Catobat <69204835+Catobat@users.noreply.github.com> Date: Wed, 2 Aug 2023 17:02:15 +0200 Subject: [PATCH 175/196] Fix potential bug with re-linking decoupled doors --- source/dungeon/DungeonStitcher.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/dungeon/DungeonStitcher.py b/source/dungeon/DungeonStitcher.py index ec61b829..504fc03b 100644 --- a/source/dungeon/DungeonStitcher.py +++ b/source/dungeon/DungeonStitcher.py @@ -200,7 +200,6 @@ def modify_proposal(proposed_map, explored_state, doors_to_connect, hash_code_se unvisted_bucket[opp_hook].sort(key=lambda d: d.name) new_door = random.choice(unvisted_bucket[opp_hook]) old_target = proposed_map[attempt] - proposed_map[attempt] = new_door if not world.decoupledoors[player]: old_attempt = proposed_map[new_door] else: @@ -213,6 +212,7 @@ def modify_proposal(proposed_map, explored_state, doors_to_connect, hash_code_se old_target = old_attempt elif old_attempt == new_door: old_attempt = old_target + proposed_map[attempt] = new_door proposed_map[old_attempt] = old_target if not world.decoupledoors[player]: proposed_map[old_target] = old_attempt From c0c3204fd50953f6f580b998d5fdbb026af5d205 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sat, 29 Jul 2023 05:10:47 -0500 Subject: [PATCH 176/196] Notes field --- BaseClasses.py | 6 +++++- CLI.py | 3 ++- Main.py | 2 +- docs/customizer_example.yaml | 1 + resources/app/cli/args.json | 1 + source/classes/CustomSettings.py | 6 ++++-- 6 files changed, 14 insertions(+), 5 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index 3663a962..3d97414b 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -2501,7 +2501,9 @@ class Spoiler(object): 'triforcegoal': self.world.treasure_hunt_count, 'triforcepool': self.world.treasure_hunt_total, 'race': self.world.settings.world_rep['meta']['race'], - 'code': {p: Settings.make_code(self.world, p) for p in range(1, self.world.players + 1)} + 'user_notes': self.world.settings.world_rep['meta']['user_notes'], + 'code': {p: Settings.make_code(self.world, p) for p in range(1, self.world.players + 1)}, + 'seed': self.world.seed } for p in range(1, self.world.players + 1): @@ -2642,6 +2644,8 @@ class Spoiler(object): self.parse_meta() with open(filename, 'w') as outfile: outfile.write('ALttP Dungeon Randomizer Version %s - Seed: %s\n\n' % (self.metadata['version'], self.world.seed)) + if self.metadata['user_notes']: + outfile.write('User Notes: %s\n' % self.metadata['user_notes']) outfile.write('Filling Algorithm: %s\n' % self.world.algorithm) outfile.write('Players: %d\n' % self.world.players) outfile.write('Teams: %d\n' % self.world.teams) diff --git a/CLI.py b/CLI.py index 2c925c6c..8f790ed8 100644 --- a/CLI.py +++ b/CLI.py @@ -346,7 +346,8 @@ def parse_settings(): "outputpath": os.path.join("."), "saveonexit": "ask", "outputname": "", - "startinventoryarray": {} + "startinventoryarray": {}, + "notes": "" } if sys.platform.lower().find("windows"): diff --git a/Main.py b/Main.py index dd5ebc3e..7c124808 100644 --- a/Main.py +++ b/Main.py @@ -172,7 +172,7 @@ def main(args, seed=None, fish=None): world.player_names[player].append(name) logger.info('') world.settings = CustomSettings() - world.settings.create_from_world(world, args.race) + world.settings.create_from_world(world, args) outfilebase = f'DR_{args.outputname if args.outputname else world.seed}' diff --git a/docs/customizer_example.yaml b/docs/customizer_example.yaml index 76514990..acdf5188 100644 --- a/docs/customizer_example.yaml +++ b/docs/customizer_example.yaml @@ -3,6 +3,7 @@ meta: players: 1 seed: 41 # note to self: seed 42 had an interesting Swamp Palace problem names: Lonk + notes: "Some notes specified by the user" settings: 1: door_shuffle: basic diff --git a/resources/app/cli/args.json b/resources/app/cli/args.json index 2eaf847e..bdc6b4db 100644 --- a/resources/app/cli/args.json +++ b/resources/app/cli/args.json @@ -513,5 +513,6 @@ ] }, "outputname": {}, + "notes": {}, "code": {} } diff --git a/source/classes/CustomSettings.py b/source/classes/CustomSettings.py index a0cea069..c0e82eed 100644 --- a/source/classes/CustomSettings.py +++ b/source/classes/CustomSettings.py @@ -63,6 +63,7 @@ class CustomSettings(object): args.suppress_rom = get_setting(meta['suppress_rom'], args.suppress_rom) args.names = get_setting(meta['names'], args.names) args.race = get_setting(meta['race'], args.race) + args.notes = get_setting(meta['user_notes'], args.notes) self.player_range = range(1, args.multi + 1) if 'settings' in self.file_source: for p in self.player_range: @@ -214,14 +215,15 @@ class CustomSettings(object): return self.file_source['drops'] return None - def create_from_world(self, world, race): + def create_from_world(self, world, settings): self.player_range = range(1, world.players + 1) settings_dict, meta_dict = {}, {} self.world_rep['meta'] = meta_dict meta_dict['players'] = world.players meta_dict['algorithm'] = world.algorithm meta_dict['seed'] = world.seed - meta_dict['race'] = race + meta_dict['race'] = settings.race + meta_dict['user_notes'] = settings.notes self.world_rep['settings'] = settings_dict for p in self.player_range: settings_dict[p] = {} From 1566813f81a51743df987b762c4bcc6352d0ccb2 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 2 Aug 2023 15:01:37 -0500 Subject: [PATCH 177/196] Changing yaml output to show hex numbers as hex and not as decimal --- Utils.py | 7 +++++++ source/classes/CustomSettings.py | 4 +++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Utils.py b/Utils.py index a208efe1..1a2a1c1c 100644 --- a/Utils.py +++ b/Utils.py @@ -737,6 +737,13 @@ class bidict(dict): super(bidict, self).__delitem__(key) +class HexInt(int): pass + +def hex_representer(dumper, data): + import yaml + return yaml.ScalarNode('tag:yaml.org,2002:int', f"{data:#0{4}x}") + + if __name__ == '__main__': # make_new_base2current() # read_entrance_data(old_rom=sys.argv[1]) diff --git a/source/classes/CustomSettings.py b/source/classes/CustomSettings.py index 99972d7f..7dc86366 100644 --- a/source/classes/CustomSettings.py +++ b/source/classes/CustomSettings.py @@ -4,6 +4,7 @@ import urllib.parse import yaml from typing import Any from yaml.representer import Representer +from Utils import HexInt, hex_representer from collections import defaultdict from pathlib import Path @@ -350,7 +351,7 @@ class CustomSettings(object): for p in self.player_range: if p in world.owswaps and len(world.owswaps[p][0]) > 0: flips[p] = {} - flips[p]['force_flip'] = list(f for f in world.owswaps[p][0] if f < 0x40 or f >= 0x80) + flips[p]['force_flip'] = list(HexInt(f) for f in world.owswaps[p][0] if f < 0x40 or f >= 0x80) flips[p]['force_flip'].sort() flips[p]['undefined_chance'] = 0 @@ -416,6 +417,7 @@ class CustomSettings(object): def write_to_file(self, destination): yaml.add_representer(defaultdict, Representer.represent_dict) + yaml.add_representer(HexInt, hex_representer) with open(destination, 'w') as file: yaml.dump(self.world_rep, file) From f442cff06119c12b18cbac68f9c18529ded2da09 Mon Sep 17 00:00:00 2001 From: aerinon Date: Thu, 3 Aug 2023 15:06:54 -0600 Subject: [PATCH 178/196] Logic added for openable trap doors --- BaseClasses.py | 3 +- DoorShuffle.py | 52 ++++++++++++--- Main.py | 2 +- RELEASENOTES.md | 3 + Rules.py | 101 +++++++++++++++++++++++++++- test/dungeons/trap_test.yaml | 125 +++++++++++++++++++++++++++++++++++ 6 files changed, 271 insertions(+), 15 deletions(-) create mode 100644 test/dungeons/trap_test.yaml diff --git a/BaseClasses.py b/BaseClasses.py index 3d97414b..a62ca101 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -1760,6 +1760,7 @@ class Door(object): self.dest = None self.blocked = False # Indicates if the door is normally blocked off as an exit. (Sanc door or always closed) self.blocked_orig = False + self.trapped = False self.stonewall = False # Indicate that the door cannot be enter until exited (Desert Torches, PoD Eye Statue) self.smallKey = False # There's a small key door on this side self.bigKey = False # There's a big key door on this side @@ -1870,7 +1871,7 @@ class Door(object): return self def no_exit(self): - self.blocked = self.blocked_orig = True + self.blocked = self.blocked_orig = self.trapped = True return self def no_entrance(self): diff --git a/DoorShuffle.py b/DoorShuffle.py index abf1def8..7a78246b 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -88,8 +88,7 @@ def link_doors_prep(world, player): find_inaccessible_regions(world, player) - if world.doorShuffle[player] != 'vanilla': - create_dungeon_pool(world, player) + create_dungeon_pool(world, player) if world.intensity[player] >= 3 and world.doorShuffle[player] != 'vanilla': choose_portals(world, player) else: @@ -1844,12 +1843,12 @@ def shuffle_trap_doors(door_type_pools, paths, start_regions_map, all_custom, wo builder.candidates.trap = filter_key_door_pool(builder.candidates.trap, all_custom[dungeon]) remaining -= len(custom_trap_doors[dungeon]) ttl += len(builder.candidates.trap) - if ttl == 0: + if ttl == 0 and all(len(custom_trap_doors[dungeon]) == 0 for dungeon in pool): continue for dungeon in pool: builder = world.dungeon_layouts[player][dungeon] proportion = len(builder.candidates.trap) - calc = int(round(proportion * door_type_pool.traps/ttl)) + calc = 0 if ttl == 0 else int(round(proportion * door_type_pool.traps/ttl)) suggested = min(proportion, calc) remaining -= suggested suggestion_map[dungeon] = suggested @@ -1981,7 +1980,10 @@ def shuffle_small_key_doors(door_type_pools, used_doors, start_regions_map, all_ remaining = max(0, remaining) for dungeon in pool: builder = world.dungeon_layouts[player][dungeon] - calculated = int(round(builder.key_doors_num*total_keys/ttl)) + if ttl == 0: + calculated = 0 + else: + calculated = int(round(builder.key_doors_num*total_keys/ttl)) max_keys = max(0, builder.location_cnt - calc_used_dungeon_items(builder, world, player)) cand_len = max(0, len(builder.candidates.small) - builder.key_drop_cnt) limit = min(max_keys, cand_len, max_computation) @@ -2211,9 +2213,10 @@ def find_valid_trap_combination(builder, suggested, start_regions, paths, world, sample_list = build_sample_list(combinations, 1000) proposal = kth_combination(sample_list[itr], trap_door_pool, trap_doors_needed) proposal.extend(custom_trap_doors) + filtered_proposal = [x for x in proposal if x.name not in trap_door_exceptions] start_regions, event_starts = filter_start_regions(builder, start_regions, world, player) - while not validate_trap_layout(proposal, builder, start_regions, paths, world, player): + while not validate_trap_layout(filtered_proposal, builder, start_regions, paths, world, player): itr += 1 if itr >= len(sample_list): if not drop: @@ -2248,6 +2251,12 @@ def filter_start_regions(builder, start_regions, world, player): portal_entrance_region = portal.door.entrance.parent_region.name if portal_entrance_region not in builder.path_entrances: excluded[region] = None + if not portal: + drop_region = next((x.parent_region for x in region.entrances + if x.parent_region.type in [RegionType.LightWorld, RegionType.DarkWorld] + or x.parent_region.name == 'Sewer Drop'), None) + if drop_region and drop_region.name in world.inaccessible_regions[player]: + excluded[region] = None if std_flag and (not portal or portal.find_portal_entrance().parent_region.name != 'Hyrule Castle Courtyard'): excluded[region] = None if portal is None: @@ -2343,10 +2352,12 @@ def reassign_trap_doors(trap_map, world, player): elif kind in [DoorKind.Trap2, DoorKind.TrapTriggerable]: room.change(d.doorListPos, DoorKind.Normal) d.blocked = False + d.trapped = False # connect_one_way(world, d.name, d.dest.name, player) elif d.type is DoorType.Normal and d not in traps: world.get_room(d.roomIndex, player).change(d.doorListPos, DoorKind.Normal) d.blocked = False + d.trapped = False for d in traps: change_door_to_trap(d, world, player) world.spoiler.set_door_type(f'{d.name} ({d.dungeon_name()})', 'Trap Door', player) @@ -2384,24 +2395,45 @@ def change_door_to_trap(d, world, player): elif d.direction in [Direction.North, Direction.West]: new_kind = DoorKind.TrapTriggerable if new_kind: - d.blocked = True + d.blocked = is_trap_door_blocked(d) + d.trapped = True pos = 3 if d.type == DoorType.Normal else 4 verify_door_list_pos(d, room, world, player, pos) d.trapFlag = {0: 0x4, 1: 0x2, 2: 0x1, 3: 0x8}[d.doorListPos] room.change(d.doorListPos, new_kind) - if d.entrance.connected_region is not None: + if d.entrance.connected_region is not None and d.blocked: d.entrance.connected_region.entrances.remove(d.entrance) d.entrance.connected_region = None elif d.type is DoorType.Normal: - d.blocked = True + d.blocked = is_trap_door_blocked(d) + d.trapped = True verify_door_list_pos(d, room, world, player, pos=3) d.trapFlag = {0: 0x4, 1: 0x2, 2: 0x1}[d.doorListPos] room.change(d.doorListPos, DoorKind.Trap) - if d.entrance.connected_region is not None: + if d.entrance.connected_region is not None and d.blocked: d.entrance.connected_region.entrances.remove(d.entrance) d.entrance.connected_region = None +trap_door_exceptions = { + 'PoD Mimics 2 SW', 'TR Twin Pokeys NW', 'Thieves Blocked Entry SW', 'Hyrule Dungeon Armory Interior Key Door N', + 'Desert Compass Key Door WN', 'TR Tile Room SE', 'Mire Cross SW', 'Tower Circle of Pots ES', + 'Eastern Single Eyegore ES', 'Eastern Duo Eyegores SE', 'Swamp Push Statue S', + 'Skull 2 East Lobby WS', 'GT Hope Room WN', 'Eastern Courtyard Ledge S', 'Ice Lobby SE', 'GT Speed Torch WN', + 'Ice Switch Room ES', 'Ice Switch Room NE', 'Skull Torch Room WS', 'GT Speed Torch NE', 'GT Speed Torch WS', + 'GT Torch Cross WN', 'Mire Tile Room SW', 'Mire Tile Room ES', 'TR Torches WN', 'PoD Lobby N', 'PoD Middle Cage S', + 'Ice Bomb Jump NW', 'GT Hidden Spikes SE', 'Ice Tall Hint EN', 'GT Conveyor Cross EN', 'Eastern Pot Switch WN', + 'Thieves Conveyor Maze WN', 'Thieves Conveyor Maze SW', 'Eastern Dark Square Key Door WN', 'Eastern Lobby NW', + 'Eastern Lobby NE', 'Ice Cross Bottom SE', 'Desert Back Lobby S', 'Desert West S', + 'Desert West Lobby ES', 'Mire Hidden Shooters SE', 'Mire Hidden Shooters ES', 'Mire Hidden Shooters WS', + 'Tower Dark Pits EN', 'Tower Dark Maze ES', 'TR Tongue Pull WS', +} + + +def is_trap_door_blocked(door): + return door.name not in trap_door_exceptions + + def find_big_key_candidates(builder, start_regions, used, world, player): if world.door_type_mode[player] != 'original': # big, all, chaos # traverse dungeon and find candidates diff --git a/Main.py b/Main.py index 7c124808..be6266e2 100644 --- a/Main.py +++ b/Main.py @@ -34,7 +34,7 @@ from source.overworld.EntranceShuffle2 import link_entrances_new from source.tools.BPS import create_bps_from_data from source.classes.CustomSettings import CustomSettings -version_number = '1.2.0.19' +version_number = '1.2.0.20' version_branch = '-u' __version__ = f'{version_number}{version_branch}' diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 3231157f..59f1e778 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -109,6 +109,9 @@ These are now independent of retro mode and have three options: None, Random, an # Bug Fixes and Notes +* 1.2.0.20u + * Added logic for trap doors that could be opened using existing room triggers + * Added a notes field for user added notes either via CLI or Customizer * 1.2.0.19u * Added min/max for triforce pool, goal, and difference for CLI and Customizer. (Thanks Catobat) * Fixed a bug with dungeon generation diff --git a/Rules.py b/Rules.py index 26e70f5f..0b390f3d 100644 --- a/Rules.py +++ b/Rules.py @@ -276,11 +276,18 @@ def global_rules(world, player): # Start of door rando rules # TODO: Do these need to flag off when door rando is off? - some of them, yes + def is_trapped(entrance): + return world.get_entrance(entrance, player).door.trapped + # Eastern Palace # Eyegore room needs a bow set_rule(world.get_entrance('Eastern Duo Eyegores NE', player), lambda state: state.can_shoot_arrows(player)) set_rule(world.get_entrance('Eastern Single Eyegore NE', player), lambda state: state.can_shoot_arrows(player)) set_rule(world.get_entrance('Eastern Map Balcony Hook Path', player), lambda state: state.has('Hookshot', player)) + if is_trapped('Eastern Single Eyegore ES'): + set_rule(world.get_entrance('Eastern Single Eyegore ES', player), lambda state: state.can_shoot_arrows(player)) + if is_trapped('Eastern Duo Eyegores SE'): + set_rule(world.get_entrance('Eastern Duo Eyegores SE', player), lambda state: state.can_shoot_arrows(player)) # Boss rules. Same as below but no BK or arrow requirement. set_defeat_dungeon_boss_rule(world.get_location('Eastern Palace - Prize', player)) @@ -305,13 +312,18 @@ def global_rules(world, player): set_rule(world.get_entrance('Tower Red Spears WN', player), lambda state: state.can_kill_most_things(player)) set_rule(world.get_entrance('Tower Red Guards EN', player), lambda state: state.can_kill_most_things(player)) set_rule(world.get_entrance('Tower Red Guards SW', player), lambda state: state.can_kill_most_things(player)) + set_rule(world.get_entrance('Tower Circle of Pots NW', player), lambda state: state.can_kill_most_things(player)) + if is_trapped('Tower Circle of Pots ES'): + set_rule(world.get_entrance('Tower Circle of Pots ES', player), + lambda state: state.can_kill_most_things(player)) set_rule(world.get_entrance('Tower Altar NW', player), lambda state: state.has_sword(player)) set_defeat_dungeon_boss_rule(world.get_location('Agahnim 1', player)) - set_rule(world.get_entrance('PoD Arena Landing Bonk Path', player), lambda state: state.has_Boots(player)) set_rule(world.get_entrance('PoD Mimics 1 NW', player), lambda state: state.can_shoot_arrows(player)) set_rule(world.get_entrance('PoD Mimics 2 NW', player), lambda state: state.can_shoot_arrows(player)) + if is_trapped('PoD Mimics 2 SW'): + set_rule(world.get_entrance('PoD Mimics 2 SW', player), lambda state: state.can_shoot_arrows(player)) set_rule(world.get_entrance('PoD Bow Statue Down Ladder', player), lambda state: state.can_shoot_arrows(player)) set_rule(world.get_entrance('PoD Map Balcony Drop Down', player), lambda state: state.has('Hammer', player)) set_rule(world.get_entrance('PoD Dark Pegs Landing to Right', player), lambda state: state.has('Hammer', player)) @@ -360,6 +372,8 @@ def global_rules(world, player): set_rule(world.get_entrance('Skull Big Chest Hookpath', player), lambda state: state.has('Hookshot', player)) set_rule(world.get_entrance('Skull Torch Room WN', player), lambda state: state.has('Fire Rod', player)) + if is_trapped('Skull Torch Room WS'): + set_rule(world.get_entrance('Skull Torch Room WS', player), lambda state: state.has('Fire Rod', player)) set_rule(world.get_entrance('Skull Vines NW', player), lambda state: state.has_sword(player)) hidden_pits_door = world.get_door('Skull Small Hall WS', player) @@ -397,6 +411,8 @@ def global_rules(world, player): set_rule(world.get_location('Thieves\' Town - Prize', player), lambda state: state.has('Maiden Unmasked', player) and world.get_location('Thieves\' Town - Prize', player).parent_region.dungeon.boss.can_defeat(state)) set_rule(world.get_entrance('Ice Lobby WS', player), lambda state: state.can_melt_things(player)) + if is_trapped('Ice Lobby SE'): + set_rule(world.get_entrance('Ice Lobby SE', player), lambda state: state.can_melt_things(player)) set_rule(world.get_entrance('Ice Hammer Block ES', player), lambda state: state.can_lift_rocks(player) and state.has('Hammer', player)) set_rule(world.get_location('Ice Palace - Hammer Block Key Drop', player), lambda state: state.can_lift_rocks(player) and state.has('Hammer', player)) set_rule(world.get_location('Ice Palace - Map Chest', player), lambda state: state.can_lift_rocks(player) and state.has('Hammer', player)) @@ -411,6 +427,12 @@ def global_rules(world, player): set_rule(world.get_entrance('Ice Hookshot Balcony Path', player), lambda state: state.has('Hookshot', player)) if not world.get_door('Ice Switch Room SE', player).entranceFlag: set_rule(world.get_entrance('Ice Switch Room SE', player), lambda state: state.has('Cane of Somaria', player) or state.has('Convenient Block', player)) + if is_trapped('Ice Switch Room ES'): + set_rule(world.get_entrance('Ice Switch Room ES', player), + lambda state: state.has('Cane of Somaria', player) or state.has('Convenient Block', player)) + if is_trapped('Ice Switch Room NE'): + set_rule(world.get_entrance('Ice Switch Room NE', player), + lambda state: state.has('Cane of Somaria', player) or state.has('Convenient Block', player)) set_defeat_dungeon_boss_rule(world.get_location('Ice Palace - Boss', player)) set_defeat_dungeon_boss_rule(world.get_location('Ice Palace - Prize', player)) @@ -431,8 +453,15 @@ def global_rules(world, player): or state.has('Cane of Byrna', player) or state.has('Cape', player)) set_rule(world.get_entrance('Mire Left Bridge Hook Path', player), lambda state: state.has('Hookshot', player)) set_rule(world.get_entrance('Mire Tile Room NW', player), lambda state: state.has_fire_source(player)) + if is_trapped('Mire Tile Room SW'): + set_rule(world.get_entrance('Mire Tile Room SW', player), lambda state: state.has_fire_source(player)) + if is_trapped('Mire Tile Room ES'): + set_rule(world.get_entrance('Mire Tile Room ES', player), lambda state: state.has_fire_source(player)) set_rule(world.get_entrance('Mire Attic Hint Hole', player), lambda state: state.has_fire_source(player)) set_rule(world.get_entrance('Mire Dark Shooters SW', player), lambda state: state.has('Cane of Somaria', player)) + if is_trapped('Mire Dark Shooters SE'): + set_rule(world.get_entrance('Mire Dark Shooters SE', player), + lambda state: state.has('Cane of Somaria', player)) set_defeat_dungeon_boss_rule(world.get_location('Misery Mire - Boss', player)) set_defeat_dungeon_boss_rule(world.get_location('Misery Mire - Prize', player)) @@ -448,6 +477,9 @@ def global_rules(world, player): set_rule(world.get_entrance('TR Hub Path', player), lambda state: state.has('Cane of Somaria', player)) set_rule(world.get_entrance('TR Hub Ledges Path', player), lambda state: state.has('Cane of Somaria', player)) set_rule(world.get_entrance('TR Torches NW', player), lambda state: state.has('Cane of Somaria', player) and state.has('Fire Rod', player)) + if is_trapped('TR Torches WN'): + set_rule(world.get_entrance('TR Torches WN', player), + lambda state: state.has('Cane of Somaria', player) and state.has('Fire Rod', player)) set_rule(world.get_entrance('TR Big Chest Entrance Gap', player), lambda state: state.has('Cane of Somaria', player) or state.has('Hookshot', player)) set_rule(world.get_entrance('TR Big Chest Gap', player), lambda state: state.has('Cane of Somaria', player) or state.has_Boots(player)) set_rule(world.get_entrance('TR Dark Ride Up Stairs', player), lambda state: state.has('Cane of Somaria', player)) @@ -467,10 +499,20 @@ def global_rules(world, player): set_rule(world.get_location('Ganons Tower - Bob\'s Torch', player), lambda state: state.has_Boots(player)) set_rule(world.get_entrance('GT Hope Room EN', player), lambda state: state.has('Cane of Somaria', player)) + if is_trapped('GT Hope Room WN'): + set_rule(world.get_entrance('GT Hope Room WN', player), lambda state: state.has('Cane of Somaria', player)) set_rule(world.get_entrance('GT Conveyor Cross Hammer Path', player), lambda state: state.has('Hammer', player)) set_rule(world.get_entrance('GT Conveyor Cross Hookshot Path', player), lambda state: state.has('Hookshot', player)) + if is_trapped('GT Conveyor Cross EN'): + set_rule(world.get_entrance('GT Conveyor Cross EN', player), lambda state: state.has('Hammer', player)) if not world.get_door('GT Speed Torch SE', player).entranceFlag: set_rule(world.get_entrance('GT Speed Torch SE', player), lambda state: state.has('Fire Rod', player)) + if is_trapped('GT Speed Torch NE'): + set_rule(world.get_entrance('GT Speed Torch NE', player), lambda state: state.has('Fire Rod', player)) + if is_trapped('GT Speed Torch WS'): + set_rule(world.get_entrance('GT Speed Torch WS', player), lambda state: state.has('Fire Rod', player)) + if is_trapped('GT Speed Torch WN'): + set_rule(world.get_entrance('GT Speed Torch WN', player), lambda state: state.has('Fire Rod', player)) set_rule(world.get_entrance('GT Hookshot South-Mid Path', player), lambda state: state.has('Hookshot', player)) set_rule(world.get_entrance('GT Hookshot Mid-North Path', player), lambda state: state.has('Hookshot', player)) set_rule(world.get_entrance('GT Hookshot East-Mid Path', player), lambda state: state.has('Hookshot', player) or state.has_Boots(player)) @@ -505,6 +547,8 @@ def global_rules(world, player): set_rule(world.get_entrance('GT Lanmolas 2 ES', player), lambda state: world.get_region('GT Lanmolas 2', player).dungeon.bosses['middle'].can_defeat(state)) set_rule(world.get_entrance('GT Lanmolas 2 NW', player), lambda state: world.get_region('GT Lanmolas 2', player).dungeon.bosses['middle'].can_defeat(state)) set_rule(world.get_entrance('GT Torch Cross ES', player), lambda state: state.has_fire_source(player)) + if is_trapped('GT Torch Cross WN'): + set_rule(world.get_entrance('GT Torch Cross WN', player), lambda state: state.has_fire_source(player)) set_rule(world.get_entrance('GT Falling Torches NE', player), lambda state: state.has_fire_source(player)) # todo: the following only applies to crystal state propagation from this supertile # you can also reset the supertile, but I'm not sure how to model that @@ -760,13 +804,29 @@ def bomb_rules(world, player): ('GT Petting Zoo SE', False), # Dont make anyone do this room with bombs and/or pots. ('GT DMs Room SW', False) # Four red stalfos ] + conditional_kill_traps = [ + ('Hyrule Dungeon Armory Interior Key Door N', True), + ('Desert Compass Key Door WN', True), + ('Thieves Blocked Entry SW', True), + ('TR Tongue Pull WS', True), + ('TR Twin Pokeys NW', False), + ] for killdoor,bombable in easy_kill_rooms: if bombable: add_rule(world.get_entrance(killdoor, player), lambda state: (state.can_use_bombs(player) or state.can_kill_most_things(player))) else: add_rule(world.get_entrance(killdoor, player), lambda state: state.can_kill_most_things(player)) + for kill_door, bombable in conditional_kill_traps: + if world.get_entrance(kill_door, player).door.trapped: + if bombable: + add_rule(world.get_entrance(kill_door, player), + lambda state: (state.can_use_bombs(player) or state.can_kill_most_things(player))) + else: + add_rule(world.get_entrance(kill_door, player), lambda state: state.can_kill_most_things(player)) add_rule(world.get_entrance('Ice Stalfos Hint SE', player), lambda state: state.can_use_bombs(player)) # Need bombs for big stalfos knights - add_rule(world.get_entrance('Mire Cross ES', player), lambda state: state.can_kill_most_things(player)) # 4 Sluggulas. Bombs don't work // or (state.can_use_bombs(player) and state.has('Magic Powder'), player) + add_rule(world.get_entrance('Mire Cross ES', player), lambda state: state.can_kill_most_things(player)) # 4 Sluggulas. Bombs don't work // or (state.can_use_bombs(player) and state.has('Magic Powder'), player) + if world.get_entrance('Mire Cross SW', player).door.trapped: + add_rule(world.get_entrance('Mire Cross SW', player), lambda state: state.can_kill_most_things(player)) enemy_kill_drops = [ # Location, bool-bombable ('Hyrule Castle - Map Guard Key Drop', True), @@ -1143,6 +1203,9 @@ def swordless_rules(world, player): set_rule(world.get_entrance('Tower Altar NW', player), lambda state: True) set_rule(world.get_entrance('Skull Vines NW', player), lambda state: True) set_rule(world.get_entrance('Ice Lobby WS', player), lambda state: state.has('Fire Rod', player) or state.has('Bombos', player)) + if world.get_entrance('Ice Lobby SE', player).door.trapped: + set_rule(world.get_entrance('Ice Lobby SE', player), + lambda state: state.has('Fire Rod', player) or state.has('Bombos', player)) set_rule(world.get_location('Ice Palace - Freezor Chest', player), lambda state: state.has('Fire Rod', player) or state.has('Bombos', player)) set_rule(world.get_location('Ether Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has('Hammer', player)) @@ -1156,7 +1219,7 @@ def swordless_rules(world, player): if world.mode[player] != 'inverted': set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has('Cape', player) or state.has('Hammer', player)) - +# todo: new traps std_kill_rooms = { 'Hyrule Dungeon Armory Main': ['Hyrule Dungeon Armory S', 'Hyrule Dungeon Armory ES'], # One green guard 'Hyrule Dungeon Armory Boomerang': ['Hyrule Dungeon Armory Boomerang WS'], # One blue guard @@ -1187,6 +1250,18 @@ std_kill_rooms = { 'GT Wizzrobes 2': ['GT Wizzrobes 2 SE', 'GT Wizzrobes 2 NE'] # Wizzrobes. Bombs don't work } # all trap rooms? +std_kill_doors_if_trapped = { + 'Hyrule Dungeon Armory Main': 'Hyrule Dungeon Armory Interior Key Door N', + # 'Eastern Single Eyegore ES', # arrow rule is sufficient + # 'Eastern Duo Eyegores S', # arrow rule is sufficient + 'TR Twin Pokeys': 'TR Twin Pokeys NW', + 'Thieves Basement Block': 'Thieves Blocked Entry SW', + 'Desert Compass Room': 'Desert Compass Key Door WN', + 'Mire Cross': 'Mire Cross SW', + 'Tower Circle of Pots': 'Tower Circle of Pots ES', + # 'Ice Lobby S' # can melt rule is sufficient +} + def add_connection(parent_name, target_name, entrance_name, world, player): parent = world.get_region(parent_name, player) target = world.get_region(target_name, player) @@ -1241,6 +1316,10 @@ def standard_rules(world, player): if region.name in std_kill_rooms: for ent in std_kill_rooms[region.name]: add_rule(world.get_entrance(ent, player), lambda state: standard_escape_rule(state)) + if region.name in std_kill_doors_if_trapped: + ent = world.get_entrance(std_kill_doors_if_trapped[region.name], player) + if ent.door.trapped: + add_rule(ent, lambda state: standard_escape_rule(state)) set_rule(world.get_location('Zelda Pickup', player), lambda state: state.has('Big Key (Escape)', player)) set_rule(world.get_entrance('Hyrule Castle Throne Room Tapestry', player), lambda state: state.has('Zelda Herself', player)) @@ -1866,6 +1945,11 @@ def set_bunny_rules(world, player, inverted): if is_bunny(bunny_exit.parent_region): add_rule(bunny_exit, get_rule_to_add(bunny_exit.parent_region)) + for ent_name in bunny_impassible_if_trapped: + bunny_exit = world.get_entrance(ent_name, player) + if bunny_exit.door.trapped and is_bunny(bunny_exit.parent_region): + add_rule(bunny_exit, get_rule_to_add(bunny_exit.parent_region)) + doors_to_check = [x for x in world.doors if x.player == player and x not in bunny_impassible_doors] doors_to_check = [x for x in doors_to_check if x.type in [DoorType.Normal, DoorType.Interior] and not x.blocked] for door in doors_to_check: @@ -1997,6 +2081,17 @@ bunny_impassible_doors = { 'GT Validation Block Path' } +bunny_impassible_if_trapped = { + 'Hyrule Dungeon Armory Interior Key Door N', 'Eastern Pot Switch WN', 'Eastern Lobby NW', + 'Eastern Lobby NE', 'Desert Compass Key Door WN', 'Tower Circle of Pots ES', 'PoD Mimics 2 SW', + 'PoD Middle Cage S', 'Swamp Push Statue S', 'Skull 2 East Lobby WS', 'Skull Torch Room WS', + 'Thieves Conveyor Maze WN', 'Thieves Conveyor Maze SW', 'Thieves Blocked Entry SW', 'Ice Bomb Jump NW', + 'Ice Tall Hint EN', 'Ice Switch Room ES', 'Ice Switch Room NE', 'Mire Cross SW', + 'Mire Tile Room SW', 'Mire Tile Room ES', 'TR Twin Pokeys NW', 'TR Torches WN', 'GT Hope Room WN', + 'GT Speed Torch NE', 'GT Speed Torch WS', 'GT Torch Cross WN', 'GT Hidden Spikes SE', 'GT Conveyor Cross EN', + 'GT Speed Torch WN', 'Ice Lobby SE' +} + def add_key_logic_rules(world, player): key_logic = world.key_logic[player] diff --git a/test/dungeons/trap_test.yaml b/test/dungeons/trap_test.yaml new file mode 100644 index 00000000..d82a8ade --- /dev/null +++ b/test/dungeons/trap_test.yaml @@ -0,0 +1,125 @@ +meta: + players: 1 +settings: + 1: + door_shuffle: basic + intensity: 3 + door_type_mode: all +doors: + 1: + doors: + PoD Mimics 2 SW: + type: Trap Door +# TR Twin Pokeys NW: # not possible due to trap flags +# type: Trap Door + Thieves Blocked Entry SW: + type: Trap Door + Hyrule Dungeon Armory Interior Key Door N: + type: Trap Door + Desert Compass Key Door WN: + type: Trap Door + TR Tile Room SE: + type: Trap Door +# Mire Cross SW: # not possible due to trap flags +# type: Trap Door + Tower Circle of Pots ES: + type: Trap Door + Eastern Single Eyegore ES: + type: Trap Door + Eastern Duo Eyegores SE: + type: Trap Door + Swamp Push Statue S: + type: Trap Door +# Skull 2 East Lobby WS: # currently not possible due to trap flags +# type: Trap Door + GT Hope Room WN : + type: Trap Door + +# Eastern Courtyard Ledge S: # currently not possible due to trap flags +# type: Trap Door + Ice Switch Room ES : + type: Trap Door + Ice Switch Room NE : + type: Trap Door + Skull Torch Room WS : + type: Trap Door + GT Speed Torch NE : + type: Trap Door + GT Speed Torch WS : + type: Trap Door + GT Torch Cross WN : + type: Trap Door + Mire Tile Room SW : + type: Trap Door + Mire Tile Room ES : + type: Trap Door + TR Torches WN : + type: Trap Door + PoD Lobby N: + type: Trap Door + PoD Middle Cage S: + type: Trap Door + Ice Bomb Jump NW: + type: Trap Door + GT Hidden Spikes SE: + type: Trap Door + Ice Tall Hint EN: + type: Trap Door + GT Conveyor Cross EN: + type: Trap Door + Eastern Pot Switch WN: + type: Trap Door + Thieves Conveyor Maze WN: + type: Trap Door +# Thieves Conveyor Maze SW: #not possible due to 4 door limit +# type: Trap Door + Eastern Dark Square Key Door WN: + type: Trap Door + Eastern Lobby NW: + type: Trap Door + Eastern Lobby NE: + type: Trap Door +# Ice Cross Bottom SE: # not possible due to trap flags +# type: Trap Door + Desert Back Lobby S: + type: Trap Door +# Desert West S: need enough lobbies for basic, should otherwise work +# type: Trap Door + Desert West Lobby ES: + type: Trap Door +# Mire Hidden Shooters SE: # not possible due to trap flags +# type: Trap Door +# Mire Hidden Shooters ES: # not possible due to trap flags +# type: Trap Door + Mire Hidden Shooters WS: + type: Trap Door + Tower Dark Pits EN: + type: Trap Door + Tower Dark Maze ES: + type: Trap Door + TR Tongue Pull WS: + type: Trap Door + +# Lower layer: not valid + # Sewers Pull Switch N: + # type: Trap Door + # PoD Sexy Statue W: # not possible due to trap flags and low layer too, so likely not an exception + # type: Trap Door + +# Not valid due to disappearing somaria block +# Mire Dark Shooters SE: +# type: Trap Door + + # These triggers don't open doors +# Ice Compass Room NE: +# type: Trap Door +# Hera Torches NE: +# type: Trap Door +# Mire Spikes WS: +# type: Trap Door +# Mire Spikes SW: +# type: Trap Door +# Mire Spikes NW: +# type: Trap Door +# Tower Room 03 WN: +# type: Trap Door From e6597a7ab9c43c8ab88da11a83f4f6838bf06d17 Mon Sep 17 00:00:00 2001 From: aerinon Date: Mon, 7 Aug 2023 09:36:50 -0600 Subject: [PATCH 179/196] Fixed inverted problem with experimental (logically assumed link's house was in the light world) Fixed hint typo --- PotShuffle.py | 2 +- RELEASENOTES.md | 4 +++- source/overworld/EntranceShuffle2.py | 4 ++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/PotShuffle.py b/PotShuffle.py index 6a4df35e..b90d7863 100644 --- a/PotShuffle.py +++ b/PotShuffle.py @@ -1022,7 +1022,7 @@ key_drop_data = { 'Ice Palace - Jelly Key Drop': ['Drop', (0x09DA21, 0xE, 3), 'dropped in Ice Palace', 'Small Key (Ice Palace)'], 'Ice Palace - Conveyor Key Drop': ['Drop', (0x09DE08, 0x3E, 8), 'dropped in Ice Palace', 'Small Key (Ice Palace)'], 'Ice Palace - Hammer Block Key Drop': ['Pot', 0x3F, 'under a block in Ice Palace', 'Small Key (Ice Palace)'], - 'Ice Palace - Many Pots Pot Key': ['Pot', 0x9F, 'int a pot in Ice Palace', 'Small Key (Ice Palace)'], + 'Ice Palace - Many Pots Pot Key': ['Pot', 0x9F, 'in a pot in Ice Palace', 'Small Key (Ice Palace)'], 'Misery Mire - Spikes Pot Key': ['Pot', 0xB3, 'in a pot in Misery Mire', 'Small Key (Misery Mire)'], 'Misery Mire - Fishbone Pot Key': ['Pot', 0xA1, 'in a pot in forgotten Mire', 'Small Key (Misery Mire)'], 'Misery Mire - Conveyor Crystal Key Drop': ['Drop', (0x09E7FB, 0xC1, 9), 'dropped in Misery Mire', 'Small Key (Misery Mire)'], diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 59f1e778..9dfc8bbd 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -111,7 +111,9 @@ These are now independent of retro mode and have three options: None, Random, an * 1.2.0.20u * Added logic for trap doors that could be opened using existing room triggers - * Added a notes field for user added notes either via CLI or Customizer + * Fixed a problem with inverted generation and the experimental flag + * Added a notes field for user added notes either via CLI or Customizer (thanks Hiimcody and Codemann) + * Fixed a typo for a specific pot hint * 1.2.0.19u * Added min/max for triforce pool, goal, and difference for CLI and Customizer. (Thanks Catobat) * Fixed a bug with dungeon generation diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index 6afc7b9e..da71c661 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -66,6 +66,10 @@ def link_entrances_new(world, player): default_map['Old Man Cave (East)'] = 'Death Mountain Return Cave Exit (West)' one_way_map['Bumper Cave (Top)'] = 'Dark Death Mountain Healer Fairy' del default_map['Bumper Cave (Top)'] + del one_way_map['Big Bomb Shop'] + one_way_map['Links House'] = 'Big Bomb Shop' + del default_map['Links House'] + default_map['Big Bomb Shop'] = 'Links House Exit' avail_pool.default_map = default_map avail_pool.one_way_map = one_way_map From 9e26c9c42cb9c726f1208183306e063e6d8f1ec4 Mon Sep 17 00:00:00 2001 From: aerinon Date: Mon, 7 Aug 2023 10:44:55 -0600 Subject: [PATCH 180/196] Fixed minor issue with dungeon counter interfering with timer --- Main.py | 2 +- RELEASENOTES.md | 2 ++ Rom.py | 2 +- data/base2current.bps | Bin 93219 -> 93217 bytes 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Main.py b/Main.py index 7d3ae0eb..4f49cc48 100644 --- a/Main.py +++ b/Main.py @@ -31,7 +31,7 @@ from Utils import output_path, parse_player_names from source.item.FillUtil import create_item_pool_config, massage_item_pool, district_item_pool_config from source.tools.BPS import create_bps_from_data -__version__ = '1.1.5-dev' +__version__ = '1.1.6-dev' from source.classes.BabelFish import BabelFish diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 4c65204f..b3734893 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -181,6 +181,8 @@ Same as above but both small keys and bigs keys of the dungeon are not allowed o # Bug Fixes and Notes +* 1.1.6 + * Minor issue with dungeon counter hud interfering with timer * 1.1.5 * MultiServer can not disable forfeits if desired * 1.1.4 diff --git a/Rom.py b/Rom.py index b76cfef8..b09b7107 100644 --- a/Rom.py +++ b/Rom.py @@ -37,7 +37,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = 'fc4d4a01f8c4e00280ea5640297f8e9c' +RANDOMIZERBASEHASH = 'e30a2490da811232e0a438da8fa662ee' class JsonRom(object): diff --git a/data/base2current.bps b/data/base2current.bps index 25cc58b2c300e723aaa269298be9cd15e9323ea3..c616e5516f89d5176466cff4f5bd8336b754f234 100644 GIT binary patch delta 63 zcmV-F0KosF*ae~31+ZEH15<&lvt0qw Date: Mon, 7 Aug 2023 10:49:55 -0600 Subject: [PATCH 181/196] Fixed minor issue with dungeon counter interfering with timer (rom re-build) --- RELEASENOTES.md | 2 ++ Rom.py | 2 +- data/base2current.bps | Bin 94169 -> 94167 bytes 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 61ab6abb..35155c50 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -201,6 +201,8 @@ These are now independent of retro mode and have three options: None, Random, an * Fix for unintentional decoupled door in standard * Fix a problem with BK doors being one-sided * Change to how wilds keys are placed in standard, better randomization + * Removed a Triforce text + * Fix for Desert Tiles 1 key door * 1.2.0.7-u * Fix for some misery mire key logic * Minor standard generation fix diff --git a/Rom.py b/Rom.py index 482080b2..5b65c852 100644 --- a/Rom.py +++ b/Rom.py @@ -37,7 +37,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '467681d6160233f7af2761c631e26985' +RANDOMIZERBASEHASH = '168574b64461acded5f2e8394a05577e' class JsonRom(object): diff --git a/data/base2current.bps b/data/base2current.bps index 9b3d673a51005eba1d3d336d10206d582cb1852b..80dff6bf7a424495c72c7b12a3e5ab3083e2fc14 100644 GIT binary patch delta 79 zcmV-V0I>hr-v!s-1+ZQL1RRdzakF9pSLQ9vILCf~52=43k21%8k2J@Ak2c4CpAQm{ lxdbBjyQJbEuW$2y$^Y;opC}TLv*_pPhX{CIs4;^=YVPr8Cu0Br delta 81 zcmV-X0IvVn-v!y<1+ZQL1ni9ya Date: Mon, 7 Aug 2023 12:19:35 -0600 Subject: [PATCH 182/196] Fix for hera boss music (the last?) --- RELEASENOTES.md | 2 ++ Rom.py | 2 +- data/base2current.bps | Bin 94167 -> 94175 bytes 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 35155c50..336c604e 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -110,10 +110,12 @@ These are now independent of retro mode and have three options: None, Random, an # Bug Fixes and Notes * 1.2.0.20u + * New generation feature that allows Spiral Stair to link to themselves (thank Catobat) * Added logic for trap doors that could be opened using existing room triggers * Fixed a problem with inverted generation and the experimental flag * Added a notes field for user added notes either via CLI or Customizer (thanks Hiimcody and Codemann) * Fixed a typo for a specific pot hint + * Fix for Hera Boss music (thanks Codemann) * 1.1.6 (from Stable) * Minor issue with dungeon counter hud interfering with timer * 1.2.0.19u diff --git a/Rom.py b/Rom.py index 5b65c852..5dc3652a 100644 --- a/Rom.py +++ b/Rom.py @@ -37,7 +37,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '168574b64461acded5f2e8394a05577e' +RANDOMIZERBASEHASH = '61662913cc0cb12fb870d794937d88d9' class JsonRom(object): diff --git a/data/base2current.bps b/data/base2current.bps index 80dff6bf7a424495c72c7b12a3e5ab3083e2fc14..23872f82d3be21e2fabd52ac809761a819691b9f 100644 GIT binary patch delta 5805 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 delta 5761 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 From fd3bdc6b712ca9c9b8413682d65dfc1359228254 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 7 Aug 2023 16:04:58 -0500 Subject: [PATCH 183/196] Version bump 0.3.2.1 --- CHANGELOG.md | 5 +++++ OverworldShuffle.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b156a0dd..1f235164 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 0.3.2.1 +- \~Merged in DR v1.2.0.20~ +- Some minor Swapped ER improvements +- Fixed generation error with Flute Activation + ## 0.3.2.0 - New Swapped ER mode option - Fixed issue with flipper rules not properly getting pearl requirement added diff --git a/OverworldShuffle.py b/OverworldShuffle.py index c34b6d62..76773b77 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -7,7 +7,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType from OverworldGlitchRules import create_owg_connections from Utils import bidict -version_number = '0.3.2.0' +version_number = '0.3.2.1' # branch indicator is intentionally different across branches version_branch = '-u' From a4d5dec8ad1d2106ed332a22bfff43cc2b5e65d0 Mon Sep 17 00:00:00 2001 From: aerinon Date: Mon, 7 Aug 2023 16:49:34 -0600 Subject: [PATCH 184/196] Fixed an error Small performance increase --- DoorShuffle.py | 1 + KeyDoorShuffle.py | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/DoorShuffle.py b/DoorShuffle.py index 7a78246b..aa988351 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -2229,6 +2229,7 @@ def find_valid_trap_combination(builder, suggested, start_regions, paths, world, itr = 0 proposal = kth_combination(sample_list[itr], trap_door_pool, trap_doors_needed) proposal.extend(custom_trap_doors) + filtered_proposal = [x for x in proposal if x.name not in trap_door_exceptions] builder.trap_door_proposal = proposal return proposal, trap_doors_needed diff --git a/KeyDoorShuffle.py b/KeyDoorShuffle.py index 87eea7ea..7284c0cf 100644 --- a/KeyDoorShuffle.py +++ b/KeyDoorShuffle.py @@ -459,7 +459,7 @@ def refine_placement_rules(key_layout, max_ctr): changed = True while changed: changed = False - rules_to_remove = [] + rules_to_remove = {} for rule in key_logic.placement_rules: if rule.check_locations_w_bk: rule.check_locations_w_bk.difference_update(key_logic.sm_restricted) @@ -468,7 +468,7 @@ def refine_placement_rules(key_layout, max_ctr): rule.check_locations_w_bk.difference_update(key_onlys) rule.needed_keys_w_bk -= len(key_onlys) if rule.needed_keys_w_bk == 0: - rules_to_remove.append(rule) + rules_to_remove[rule] = None # todo: evaluate this usage # if rule.bk_relevant and len(rule.check_locations_w_bk) == rule.needed_keys_w_bk + 1: # new_restricted = set(max_ctr.free_locations) - rule.check_locations_w_bk @@ -481,13 +481,13 @@ def refine_placement_rules(key_layout, max_ctr): # changed = True if rule.needed_keys_w_bk > key_layout.max_chests or len(rule.check_locations_w_bk) < rule.needed_keys_w_bk: logging.getLogger('').warning('Invalid rule - what went wrong here??') - rules_to_remove.append(rule) + rules_to_remove[rule] = None changed = True if rule.bk_conditional_set is not None: rule.bk_conditional_set.difference_update(key_logic.bk_restricted) rule.bk_conditional_set.difference_update(max_ctr.key_only_locations) if len(rule.bk_conditional_set) == 0: - rules_to_remove.append(rule) + rules_to_remove[rule] = None if rule.check_locations_wo_bk: rule.check_locations_wo_bk.difference_update(key_logic.sm_restricted) key_onlys = rule.check_locations_wo_bk.intersection(max_ctr.key_only_locations) @@ -495,11 +495,11 @@ def refine_placement_rules(key_layout, max_ctr): rule.check_locations_wo_bk.difference_update(key_onlys) rule.needed_keys_wo_bk -= len(key_onlys) if rule.needed_keys_wo_bk == 0: - rules_to_remove.append(rule) + rules_to_remove[rule] = None if len(rule.check_locations_wo_bk) < rule.needed_keys_wo_bk or rule.needed_keys_wo_bk > key_layout.max_chests: if not rule.prize_relevance and len(rule.bk_conditional_set) > 0: key_logic.bk_restricted.update(rule.bk_conditional_set) - rules_to_remove.append(rule) + rules_to_remove[rule] = None changed = True # impossible for bk to be here, I think for rule_a, rule_b in itertools.combinations([x for x in key_logic.placement_rules if x not in rules_to_remove], 2): if rule_b.bk_conditional_set and rule_a.check_locations_w_bk: @@ -511,25 +511,25 @@ def refine_placement_rules(key_layout, max_ctr): common_locs = len(rule_b.check_locations_w_bk & rule_a.check_locations_wo_bk) if (common_needed - common_locs) * 2 > key_layout.max_chests: key_logic.bk_restricted.update(rule_a.bk_conditional_set) - rules_to_remove.append(rule_a) + rules_to_remove[rule_a] = None changed = True break equivalent_rules = [] for rule in key_logic.placement_rules: for rule2 in key_logic.placement_rules: - if rule != rule2: + if rule != rule2 and rule not in rules_to_remove and rule2 not in rules_to_remove: if rule.check_locations_w_bk and rule2.check_locations_w_bk: if rule2.check_locations_w_bk == rule.check_locations_w_bk and rule2.needed_keys_w_bk > rule.needed_keys_w_bk: - rules_to_remove.append(rule) + rules_to_remove[rule] = None elif rule2.needed_keys_w_bk == rule.needed_keys_w_bk and rule2.check_locations_w_bk < rule.check_locations_w_bk: - rules_to_remove.append(rule) + rules_to_remove[rule] = None elif rule2.check_locations_w_bk == rule.check_locations_w_bk and rule2.needed_keys_w_bk == rule.needed_keys_w_bk: equivalent_rules.append((rule, rule2)) if rule.check_locations_wo_bk and rule2.check_locations_wo_bk and rule.bk_conditional_set == rule2.bk_conditional_set: if rule2.check_locations_wo_bk == rule.check_locations_wo_bk and rule2.needed_keys_wo_bk > rule.needed_keys_wo_bk: - rules_to_remove.append(rule) + rules_to_remove[rule] = None elif rule2.needed_keys_wo_bk == rule.needed_keys_wo_bk and rule2.check_locations_wo_bk < rule.check_locations_wo_bk: - rules_to_remove.append(rule) + rules_to_remove[rule] = None elif rule2.check_locations_wo_bk == rule.check_locations_wo_bk and rule2.needed_keys_wo_bk == rule.needed_keys_wo_bk: equivalent_rules.append((rule, rule2)) if len(rules_to_remove) > 0: From ed9585eef60eaf60476be088218fe698ce132f58 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 17 Aug 2023 07:04:06 -0500 Subject: [PATCH 185/196] Fixed Swapped ER to prevent Old Man from being unretunable --- source/overworld/EntranceShuffle2.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index 16ce2dfc..6ab63f0c 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -265,9 +265,14 @@ def do_main_shuffle(entrances, exits, avail, mode_def): else: # cross world mandantory entrance_list = list(entrances) + if avail.swapped: + forbidden = [e for e in Forbidden_Swap_Entrances if e in entrance_list] + entrance_list = [e for e in entrance_list if e not in forbidden] must_exit, multi_exit_caves = figure_out_must_exits_cross_world(entrances, exits, avail) do_mandatory_connections(avail, entrance_list, multi_exit_caves, must_exit) rem_entrances.update(entrance_list) + if avail.swapped: + rem_entrances.update(forbidden) rem_exits.update([x for item in multi_exit_caves for x in item if x in avail.exits]) rem_exits.update(exits) From 70e1e7a28be3e02f026249d9cdfca1b01bd0c23d Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 17 Aug 2023 07:05:38 -0500 Subject: [PATCH 186/196] Fixed Swapped ER so that remaining cave placements in mandatory exits cannot choose vanilla --- docs/presets/Swapkeys.yaml | 22 ++++++++++++++++++++++ docs/presets/swapkeys.yml | 17 +++++++++++++++++ docs/vanilla_multi_lobbies.yaml | 28 ++++++++++++++++++++++++++++ source/overworld/EntranceShuffle2.py | 9 ++++++--- 4 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 docs/presets/Swapkeys.yaml create mode 100644 docs/presets/swapkeys.yml create mode 100644 docs/vanilla_multi_lobbies.yaml diff --git a/docs/presets/Swapkeys.yaml b/docs/presets/Swapkeys.yaml new file mode 100644 index 00000000..20b7e88b --- /dev/null +++ b/docs/presets/Swapkeys.yaml @@ -0,0 +1,22 @@ +meta: + branch: OWR + seed_name: Swapkeys + seed_notes: Crosskeys but Swapped ER +settings: + 1: + mode: open + logic: noglitches + goal: crystals + crystals_gt: "7" + crystals_ganon: "7" + accessibility: locations + mapshuffle: 1 + compassshuffle: 1 + keyshuffle: wild + bigkeyshuffle: 1 + shuffle: swapped + shuffleganon: 1 + shufflelinks: 0 + shuffletavern: 1 + experimental: 0 + hints: 0 diff --git a/docs/presets/swapkeys.yml b/docs/presets/swapkeys.yml new file mode 100644 index 00000000..e71e4521 --- /dev/null +++ b/docs/presets/swapkeys.yml @@ -0,0 +1,17 @@ +settings: + 1: + description: Swapkeys + glitches_required: none + mode: open + goal: crystals + crystals_gt: "7" + crystals_ganon: "7" + weapons: randomized + accessibility: locations + entrance_shuffle: swapped + shufflelinks: off + shuffletavern: on + mapshuffle: on + compassshuffle: on + keyshuffle: wild + bigkeyshuffle: on diff --git a/docs/vanilla_multi_lobbies.yaml b/docs/vanilla_multi_lobbies.yaml new file mode 100644 index 00000000..06eaf835 --- /dev/null +++ b/docs/vanilla_multi_lobbies.yaml @@ -0,0 +1,28 @@ +doors: + 1: + lobbies: + #Agahnims Tower: Tower Lobby S + Desert Back: Desert Back Lobby S + Desert East: Desert East Lobby S + Desert South: Desert Main Lobby S + Desert West: Desert West S + #Eastern: Eastern Lobby S + #Ganons Tower: GT Lobby S + #Hera: Hera Lobby S + Hyrule Castle East: Hyrule Castle East Lobby S + Hyrule Castle South: Hyrule Castle Lobby S + Hyrule Castle West: Hyrule Castle West Lobby S + #Ice: Ice Lobby SE + #Mire: Mire Lobby S + #Palace of Darkness: PoD Lobby S + #Sanctuary: Sanctuary S + #Skull 1: Skull 1 Lobby S + #Skull 2 East: Skull 2 East Lobby SW + #Skull 2 West: Skull 2 West Lobby S + #Skull 3: Skull 3 Lobby SW + #Swamp: Swamp Lobby S + #Thieves Town: Thieves Lobby S + Turtle Rock Chest: TR Big Chest Entrance SE + Turtle Rock Eye Bridge: TR Eye Bridge SW + Turtle Rock Lazy Eyes: TR Lazy Eyes SE + Turtle Rock Main: TR Main Lobby SE diff --git a/source/overworld/EntranceShuffle2.py b/source/overworld/EntranceShuffle2.py index 6ab63f0c..87bcdf1d 100644 --- a/source/overworld/EntranceShuffle2.py +++ b/source/overworld/EntranceShuffle2.py @@ -1379,7 +1379,8 @@ def do_mandatory_connections(avail, entrances, cave_options, must_exit): entrances.remove(swap_ent) if len(cave) == 2: entrance = next(e for e in entrances[::-1] if e not in invalid_connections[exit] - and e not in invalid_cave_connections[tuple(cave)] and e not in must_exit) + and e not in invalid_cave_connections[tuple(cave)] and e not in must_exit + and (not avail.swapped or rnd_cave[0] != combine_map[e])) entrances.remove(entrance) connect_two_way(entrance, rnd_cave[0], avail) if avail.swapped and combine_map[entrance] != rnd_cave[0]: @@ -1398,7 +1399,8 @@ def do_mandatory_connections(avail, entrances, cave_options, must_exit): entrance = avail.world.get_entrance(cave_exit, avail.player).parent_region.entrances[0].name cave_entrances.append(entrance) else: - entrance = next(e for e in entrances[::-1] if e not in invalid_connections[exit] and e not in must_exit) + entrance = next(e for e in entrances[::-1] if e not in invalid_connections[exit] and e not in must_exit + and (not avail.swapped or cave_exit != combine_map[e])) cave_entrances.append(entrance) entrances.remove(entrance) connect_two_way(entrance, cave_exit, avail) @@ -1428,7 +1430,8 @@ def do_mandatory_connections(avail, entrances, cave_options, must_exit): if avail.swapped and cave_exit not in avail.exits: continue else: - entrance = next(e for e in entrances[::-1] if e not in invalid_cave_connections[tuple(cave)]) + entrance = next(e for e in entrances[::-1] if e not in invalid_cave_connections[tuple(cave)] + and (not avail.swapped or cave_exit != combine_map[e])) invalid_cave_connections[tuple(cave)] = set() entrances.remove(entrance) connect_two_way(entrance, cave_exit, avail) From 6ef8abd2ed595e665cd5faf782e8beb4affea195 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 17 Aug 2023 07:31:42 -0500 Subject: [PATCH 187/196] Changing hints in Swapped ER to not hint entrance locations --- Rom.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Rom.py b/Rom.py index b57b1564..0a5a4197 100644 --- a/Rom.py +++ b/Rom.py @@ -2185,7 +2185,7 @@ def write_strings(rom, world, player, team): # Now we write inconvenient locations for most shuffles and finish taking care of the less chaotic ones. if world.shuffle[player] not in ['lite', 'lean']: entrances_to_hint.update(InconvenientOtherEntrances) - if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull', 'lite', 'lean']: + if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull', 'lite', 'lean', 'swapped']: hint_count = 0 elif world.shuffle[player] in ['simple', 'restricted']: hint_count = 2 @@ -2236,7 +2236,7 @@ def write_strings(rom, world, player, team): entrances_to_hint.update({'Inverted Pyramid Entrance': 'The extra castle passage'}) else: entrances_to_hint.update({'Pyramid Entrance': 'The pyramid ledge'}) - hint_count = 4 if world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull'] else 0 + hint_count = 4 if world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull', 'swapped'] else 0 hint_count -= 2 if world.shuffle[player] not in ['simple', 'restricted'] else 0 for entrance in all_entrances: if entrance.name in entrances_to_hint: @@ -2255,7 +2255,7 @@ def write_strings(rom, world, player, team): if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull']: locations_to_hint.extend(InconvenientVanillaLocations) random.shuffle(locations_to_hint) - hint_count = 3 if world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull'] else 5 + hint_count = 3 if world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull', 'swapped'] else 5 hint_count -= 2 if world.doorShuffle[player] not in ['vanilla', 'basic'] else 0 del locations_to_hint[hint_count:] for location in locations_to_hint: @@ -2330,7 +2330,7 @@ def write_strings(rom, world, player, team): if world.bigkeyshuffle[player]: items_to_hint.extend(BigKeys) random.shuffle(items_to_hint) - hint_count = 5 if world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull'] else 8 + hint_count = 5 if world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull', 'swapped'] else 8 hint_count += 2 if world.doorShuffle[player] not in ['vanilla', 'basic'] else 0 hint_count += 1 if world.owShuffle[player] != 'vanilla' or world.owCrossed[player] != 'none' or world.owMixed[player] else 0 while hint_count > 0 and len(items_to_hint) > 0: From 7bc9a43ef4db6ea714c563c24f311172d018fc72 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 17 Aug 2023 07:33:17 -0500 Subject: [PATCH 188/196] Fixed false negative reachability error in playthru calc --- Main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Main.py b/Main.py index d7542d88..1223b79e 100644 --- a/Main.py +++ b/Main.py @@ -808,7 +808,7 @@ def create_playthrough(world): prog_locations = [location for location in world.get_filled_locations() if location.item.advancement or world.goal[location.player] == 'completionist'] optional_locations = ['Trench 1 Switch', 'Trench 2 Switch', 'Ice Block Drop', 'Skull Star Tile', 'Flute Activation'] - optional_locations.extend(['Hyrule Castle Courtyard Tree Pull', 'Mountain Pass Tree Pull']) # adding pre-aga tree pulls + optional_locations.extend(['Hyrule Castle Courtyard Tree Pull', 'Mountain Pass Area Tree Pull']) # adding pre-aga tree pulls optional_locations.extend(['Lumberjack Area Crab Drop', 'South Pass Area Crab Drop']) # adding pre-aga bush crabs state_cache = [None] collection_spheres = [] From 24372c3868728358a4dba198ae665c7039748b5a Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 17 Aug 2023 11:50:06 -0500 Subject: [PATCH 189/196] Converting flute data to owid-based rather than by owslot --- OverworldShuffle.py | 31 +++++++++++++++---------------- Rom.py | 4 ++-- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 76773b77..08eaca4f 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -407,9 +407,9 @@ def link_overworld(world, player): logging.getLogger('').debug('Shuffling flute spots') def connect_flutes(flute_destinations): for o in range(0, len(flute_destinations)): - owslot = flute_destinations[o] - regions = flute_data[owslot][0] - if not world.is_tile_swapped(flute_data[owslot][1], player): + owid = flute_destinations[o] + regions = flute_data[owid][0] + if not world.is_tile_swapped(owid, player): connect_simple(world, 'Flute Spot ' + str(o + 1), regions[0], player) else: connect_simple(world, 'Flute Spot ' + str(o + 1), regions[1], player) @@ -431,7 +431,7 @@ def link_overworld(world, player): new_ignored.add(exit.connected_region.name) getIgnored(exit.connected_region.name, base_owid, OWTileRegions[exit.connected_region.name]) - if not world.is_tile_swapped(flute_data[owid][1], player): + if not world.is_tile_swapped(owid, player): new_region = flute_data[owid][0][0] else: new_region = flute_data[owid][0][1] @@ -456,7 +456,7 @@ def link_overworld(world, player): return True # determine sectors (isolated groups of regions) to place flute spots - flute_regions = {(f[0][0] if (f[1] not in world.owswaps[player][0]) != (world.mode[player] == 'inverted') else f[0][1]) : o for o, f in flute_data.items()} + flute_regions = {(f[0][0] if (o not in world.owswaps[player][0]) != (world.mode[player] == 'inverted') else f[0][1]) : o for o, f in flute_data.items()} flute_sectors = [(len([r for l in s for r in l]), [r for l in s for r in l if r in flute_regions]) for s in world.owsectors[player]] flute_sectors = [s for s in flute_sectors if len(s[1]) > 0] region_total = sum([c for c,_ in flute_sectors]) @@ -471,7 +471,7 @@ def link_overworld(world, player): logging.getLogger('').debug(f'Sector of {sector[0]} regions gets {spots_to_place} spot(s)') if 'Desert Teleporter Ledge' in sector[1] or 'Mire Teleporter Ledge' in sector[1]: - addSpot(0x38, False) # guarantee desert/mire access + addSpot(0x30, False) # guarantee desert/mire access random.shuffle(sector[1]) f = 0 @@ -495,7 +495,6 @@ def link_overworld(world, player): connect_flutes(new_spots) # update spoiler - new_spots = list(map(lambda o: flute_data[o][1], new_spots)) s = list(map(lambda x: ' ' if x not in new_spots else 'F', [i for i in range(0x40)])) text_output = flute_spoiler_table.replace('s', '%s') % ( s[0x02], s[0x07], s[0x00], s[0x03], s[0x05], @@ -1223,8 +1222,8 @@ def validate_layout(world, player): # check if can be accessed flute if unreachable_regions[region_name].type == RegionType.LightWorld: owid = OWTileRegions[region_name] - if owid < 0x80 and any(f[1] == owid and region_name in f[0] for f in flute_data.values()): - if world.owFluteShuffle[player] != 'vanilla' or owid % 0x40 in [0x03, 0x16, 0x18, 0x2c, 0x2f, 0x3b, 0x3f]: + if owid < 0x80 and owid % 40 in flute_data and region_name in flute_data[owid][0]: + if world.owFluteShuffle[player] != 'vanilla' or owid % 0x40 in default_flute_connections: unreachable_regions.pop(region_name) explore_region(region_name) break @@ -1467,7 +1466,7 @@ default_whirlpool_connections = [ ] default_flute_connections = [ - 0x0b, 0x16, 0x18, 0x2c, 0x2f, 0x38, 0x3b, 0x3f + 0x03, 0x16, 0x18, 0x2c, 0x2f, 0x30, 0x3b, 0x3f ] ow_connections = { @@ -2131,10 +2130,10 @@ isolated_regions = [ flute_data = { #Slot LW Region DW Region OWID VRAM BG Y BG X Link Y Link X Cam Y Cam X Unk1 Unk2 IconY IconX AltY AltX AltVRAM AltBGY AltBGX AltCamY AltCamX AltUnk1 AltUnk2 AltIconY AltIconX - 0x09: (['Lost Woods East Area', 'Skull Woods Forest'], 0x00, 0x1042, 0x022e, 0x0202, 0x0290, 0x0288, 0x029b, 0x028f, 0xfff2, 0x000e, 0x0290, 0x0288, 0x0290, 0x0290), + 0x00: (['Lost Woods East Area', 'Skull Woods Forest'], 0x09, 0x1042, 0x022e, 0x0202, 0x0290, 0x0288, 0x029b, 0x028f, 0xfff2, 0x000e, 0x0290, 0x0288, 0x0290, 0x0290), 0x02: (['Lumberjack Area', 'Dark Lumberjack Area'], 0x02, 0x059c, 0x00d6, 0x04e6, 0x0138, 0x0558, 0x0143, 0x0563, 0xfffa, 0xfffa, 0x0138, 0x0550), - 0x0b: (['West Death Mountain (Bottom)', 'West Dark Death Mountain (Top)'], 0x03, 0x1600, 0x02ca, 0x060e, 0x0328, 0x0678, 0x0337, 0x0683, 0xfff6, 0xfff2, 0x035b, 0x0680, 0x0118, 0x0860, 0x05c0, 0x00b8, 0x07ec, 0x0127, 0x086b, 0xfff8, 0x0004, 0x0148, 0x0850), - 0x0e: (['East Death Mountain (Bottom)', 'East Dark Death Mountain (Bottom)'], 0x05, 0x1860, 0x031e, 0x0d00, 0x0388, 0x0da8, 0x038d, 0x0d7d, 0x0000, 0x0000, 0x0388, 0x0da8), + 0x03: (['West Death Mountain (Bottom)', 'West Dark Death Mountain (Top)'], 0x0b, 0x1600, 0x02ca, 0x060e, 0x0328, 0x0678, 0x0337, 0x0683, 0xfff6, 0xfff2, 0x035b, 0x0680, 0x0118, 0x0860, 0x05c0, 0x00b8, 0x07ec, 0x0127, 0x086b, 0xfff8, 0x0004, 0x0148, 0x0850), + 0x05: (['East Death Mountain (Bottom)', 'East Dark Death Mountain (Bottom)'], 0x0e, 0x1860, 0x031e, 0x0d00, 0x0388, 0x0da8, 0x038d, 0x0d7d, 0x0000, 0x0000, 0x0388, 0x0da8), 0x07: (['Death Mountain TR Pegs Area', 'Turtle Rock Area'], 0x07, 0x0804, 0x0102, 0x0e1a, 0x0160, 0x0e90, 0x016f, 0x0e97, 0xfffe, 0x0006, 0x0160, 0x0f20), 0x0a: (['Mountain Pass Area', 'Bumper Cave Area'], 0x0a, 0x0180, 0x0220, 0x0406, 0x0280, 0x0488, 0x028f, 0x0493, 0x0000, 0xfffa, 0x0280, 0x0488), 0x0f: (['Zora Waterfall Area', 'Catfish Area'], 0x0f, 0x0316, 0x025c, 0x0eb2, 0x02c0, 0x0f28, 0x02cb, 0x0f2f, 0x0002, 0xfffe, 0x02d0, 0x0f38), @@ -2150,7 +2149,7 @@ flute_data = { 0x1a: (['Forgotten Forest Area', 'Shield Shop Fence'], 0x1a, 0x081a, 0x070f, 0x04d2, 0x0770, 0x0548, 0x077c, 0x054f, 0xffff, 0xfffe, 0x0770, 0x0548), 0x1b: (['Hyrule Castle Courtyard', 'Pyramid Area'], 0x1b, 0x0c30, 0x077a, 0x0786, 0x07d8, 0x07f8, 0x07e7, 0x0803, 0x0006, 0xfffa, 0x07d8, 0x07f8), 0x1d: (['Wooden Bridge Area', 'Broken Bridge Northeast'], 0x1d, 0x0602, 0x06c2, 0x0a0e, 0x0720, 0x0a80, 0x072f, 0x0a8b, 0xfffe, 0x0002, 0x0720, 0x0a80), - 0x26: (['Eastern Palace Area', 'Palace of Darkness Area'], 0x1e, 0x1802, 0x091e, 0x0c0e, 0x09c0, 0x0c80, 0x098b, 0x0c8b, 0x0000, 0x0002, 0x09c0, 0x0c80), + 0x1e: (['Eastern Palace Area', 'Palace of Darkness Area'], 0x26, 0x1802, 0x091e, 0x0c0e, 0x09c0, 0x0c80, 0x098b, 0x0c8b, 0x0000, 0x0002, 0x09c0, 0x0c80), 0x22: (['Blacksmith Area', 'Hammer Pegs Area'], 0x22, 0x058c, 0x08aa, 0x0462, 0x0908, 0x04d8, 0x0917, 0x04df, 0x0006, 0xfffe, 0x0908, 0x04d8), 0x25: (['Sand Dunes Area', 'Dark Dunes Area'], 0x25, 0x030e, 0x085a, 0x0a76, 0x08b8, 0x0ae8, 0x08c7, 0x0af3, 0x0006, 0xfffa, 0x08b8, 0x0b08), 0x28: (['Maze Race Area', 'Dig Game Area'], 0x28, 0x0908, 0x0b1e, 0x003a, 0x0b88, 0x00b8, 0x0b8d, 0x00bf, 0x0000, 0x0006, 0x0b88, 0x00b8), @@ -2161,12 +2160,12 @@ flute_data = { 0x2d: (['Stone Bridge South Area', 'Hammer Bridge South Area'], 0x2d, 0x0886, 0x0b1e, 0x0a2a, 0x0ba0, 0x0aa8, 0x0b8b, 0x0aaf, 0x0000, 0x0006, 0x0bc4, 0x0ad0), 0x2e: (['Tree Line Area', 'Dark Tree Line Area'], 0x2e, 0x0100, 0x0a1a, 0x0c00, 0x0a78, 0x0c30, 0x0a87, 0x0c7d, 0x0006, 0x0000, 0x0a78, 0x0c58), 0x2f: (['Eastern Nook Area', 'Darkness Nook Area'], 0x2f, 0x0798, 0x0afa, 0x0eb2, 0x0b58, 0x0f30, 0x0b67, 0x0f37, 0xfff6, 0x000e, 0x0b50, 0x0f30), - 0x38: (['Desert Teleporter Ledge', 'Mire Teleporter Ledge'], 0x30, 0x1880, 0x0f1e, 0x0000, 0x0fa8, 0x0078, 0x0f8d, 0x008d, 0x0000, 0x0000, 0x0fb0, 0x0070), + 0x30: (['Desert Teleporter Ledge', 'Mire Teleporter Ledge'], 0x38, 0x1880, 0x0f1e, 0x0000, 0x0fa8, 0x0078, 0x0f8d, 0x008d, 0x0000, 0x0000, 0x0fb0, 0x0070), 0x32: (['Flute Boy Approach Area', 'Stumpy Approach Area'], 0x32, 0x03a0, 0x0c6c, 0x0500, 0x0cd0, 0x05a8, 0x0cdb, 0x0585, 0x0002, 0x0000, 0x0cd6, 0x0568), 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 Northwest Bank', 'Ice Lake Northwest Bank'], 0x35, 0x0d00, 0x0da6, 0x0a06, 0x0e08, 0x0a80, 0x0e13, 0x0a8b, 0xfffa, 0xfffa, 0x0d88, 0x0a88), - 0x3e: (['Lake Hylia South Shore', 'Ice Lake Southeast Ledge'], 0x35, 0x1860, 0x0f1e, 0x0d00, 0x0f98, 0x0da8, 0x0f8b, 0x0d85, 0x0000, 0x0000, 0x0f90, 0x0da4), + 0x35: (['Lake Hylia South Shore', 'Ice Lake Southeast Ledge'], 0x3e, 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), diff --git a/Rom.py b/Rom.py index 0a5a4197..5c1752cf 100644 --- a/Rom.py +++ b/Rom.py @@ -689,9 +689,9 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): owFlags |= 0x0100 for o in range(0, len(flute_spots)): - owslot = flute_spots[o] + owid = flute_spots[o] offset = 0 - data = flute_data[owslot] + data = flute_data[owid] if world.is_tile_swapped(data[1], player): offset = 0x40 From 4151e16893c1f0440d7351fd144a1ac860ed1e10 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 17 Aug 2023 12:07:15 -0500 Subject: [PATCH 190/196] Fix some bugs in OWR layout validation --- OverworldShuffle.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 08eaca4f..34284432 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -705,8 +705,8 @@ def shuffle_tiles(world, groups, result_list, do_grouped, player): continue # ensure sanc can be placed in LW in certain modes if not do_grouped and world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull', 'lean', 'swapped', 'crossed', 'insanity'] and world.mode[player] != 'inverted' and (world.doorShuffle[player] != 'crossed' or world.intensity[player] < 3 or world.mode[player] == 'standard'): - free_dw_drops = parity[5] + (1 if world.shuffle_ganon else 0) - free_drops = 6 + (1 if world.mode[player] != 'standard' else 0) + (1 if world.shuffle_ganon else 0) + free_dw_drops = parity[5] + (1 if world.shuffle_ganon[player] else 0) + free_drops = 6 + (1 if world.mode[player] != 'standard' else 0) + (1 if world.shuffle_ganon[player] else 0) if free_dw_drops == free_drops: attempts -= 1 continue @@ -1190,7 +1190,7 @@ def validate_layout(world, player): start_region = 'Big Bomb Shop Area' explore_region(start_region) - if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull', 'lite', 'lean'] and world.mode == 'inverted': + if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull', 'lite', 'lean'] and world.mode[player] == 'inverted': start_region = 'Dark Chapel Area' explore_region(start_region) @@ -1220,7 +1220,7 @@ def validate_layout(world, player): unreachable_count = len(unreachable_regions) for region_name in reversed(unreachable_regions): # check if can be accessed flute - if unreachable_regions[region_name].type == RegionType.LightWorld: + if unreachable_regions[region_name].type == (RegionType.LightWorld if world.mode[player] != 'inverted' else RegionType.DarkWorld): owid = OWTileRegions[region_name] if owid < 0x80 and owid % 40 in flute_data and region_name in flute_data[owid][0]: if world.owFluteShuffle[player] != 'vanilla' or owid % 0x40 in default_flute_connections: @@ -1230,9 +1230,9 @@ def validate_layout(world, player): # check if entrances in region could be used to access region if world.shuffle[player] != 'vanilla': for entrance in [e for e in unreachable_regions[region_name].exits if e.spot_type == 'Entrance']: - if (entrance.name == 'Links House' and (world.mode == 'inverted' or not world.shufflelinks[player] or world.shuffle[player] in ['dungeonssimple', 'dungeonsfull', 'lite', 'lean'])) \ - or (entrance.name == 'Big Bomb Shop' and (world.mode != 'inverted' or not world.shufflelinks[player] or world.shuffle[player] in ['dungeonssimple', 'dungeonsfull', 'lite', 'lean'])) \ - or (entrance.name == 'Ganons Tower' and (world.mode != 'inverted' and not world.shuffle_ganon[player])) \ + if (entrance.name == 'Links House' and (world.mode[player] == 'inverted' or not world.shufflelinks[player] or world.shuffle[player] in ['dungeonssimple', 'dungeonsfull', 'lite', 'lean'])) \ + or (entrance.name == 'Big Bomb Shop' and (world.mode[player] != 'inverted' or not world.shufflelinks[player] or world.shuffle[player] in ['dungeonssimple', 'dungeonsfull', 'lite', 'lean'])) \ + or (entrance.name == 'Ganons Tower' and (world.mode[player] != 'inverted' and not world.shuffle_ganon[player])) \ or (entrance.name in ['Skull Woods First Section Door', 'Skull Woods Second Section Door (East)', 'Skull Woods Second Section Door (West)'] and world.shuffle[player] not in ['insanity']) \ or entrance.name == 'Tavern North': continue # these are fixed entrances and cannot be used for gaining access to region From bbd3187cb1d3658a054342fb7685fdc3269d6785 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Fri, 18 Aug 2023 05:24:26 -0500 Subject: [PATCH 191/196] Converting flute data to owid-based rather than by owslot --- Rom.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rom.py b/Rom.py index 5c1752cf..c2677ec3 100644 --- a/Rom.py +++ b/Rom.py @@ -696,7 +696,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): if world.is_tile_swapped(data[1], player): offset = 0x40 - write_int16(rom, snes_to_pc(0x02E849 + (o * 2)), data[1] + offset) # owid + write_int16(rom, snes_to_pc(0x02E849 + (o * 2)), owid + offset) # owid write_int16(rom, snes_to_pc(0x02E8D1 + (o * 2)), data[13] if offset > 0 and len(data) > 13 else data[5]) # link Y write_int16(rom, snes_to_pc(0x02E8F3 + (o * 2)), data[14] if offset > 0 and len(data) > 13 else data[6]) # link X From 8b077cb3799611ef4ee48b6307bb615901fff94a Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sat, 19 Aug 2023 12:55:55 -0500 Subject: [PATCH 192/196] Adding Customizer support for flute shuffle --- OverworldShuffle.py | 76 +++++++++++++++++++++++++++----- docs/Customizer.md | 10 ++++- docs/customizer_example.yaml | 13 ++++++ source/classes/CustomSettings.py | 14 ++++++ 4 files changed, 100 insertions(+), 13 deletions(-) diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 34284432..27501a7e 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -417,11 +417,15 @@ def link_overworld(world, player): if world.owFluteShuffle[player] == 'vanilla': connect_flutes(default_flute_connections) else: + flute_spots = 8 flute_pool = list(flute_data.keys()) new_spots = list() ignored_regions = set() + used_flute_regions = [] + forbidden_spots = [] + forbidden_regions = [] - def addSpot(owid, ignore_proximity): + def addSpot(owid, ignore_proximity, forced): if world.owFluteShuffle[player] == 'balanced': def getIgnored(regionname, base_owid, owid): region = world.get_region(regionname, player) @@ -430,23 +434,28 @@ def link_overworld(world, player): if exit.connected_region.name in OWTileRegions and (OWTileRegions[exit.connected_region.name] in [base_owid, owid] or OWTileRegions[regionname] == base_owid): new_ignored.add(exit.connected_region.name) getIgnored(exit.connected_region.name, base_owid, OWTileRegions[exit.connected_region.name]) + if regionname in one_way_ledges: + for ledge_region in one_way_ledges[regionname]: + if ledge_region not in new_ignored: + new_ignored.add(ledge_region) + getIgnored(ledge_region, base_owid, OWTileRegions[ledge_region]) if not world.is_tile_swapped(owid, player): new_region = flute_data[owid][0][0] else: new_region = flute_data[owid][0][1] - if new_region in ignored_regions: + if new_region in ignored_regions and not forced: return False new_ignored = {new_region} getIgnored(new_region, OWTileRegions[new_region], OWTileRegions[new_region]) - if not ignore_proximity and random.randint(0, 31) != 0 and new_ignored.intersection(ignored_regions): + if not ignore_proximity and not forced and random.randint(0, 31) != 0 and new_ignored.intersection(ignored_regions): return False ignored_regions.update(new_ignored) if owid in flute_pool: flute_pool.remove(owid) - if ignore_proximity: + if ignore_proximity and not forced: logging.getLogger('').warning(f'Warning: Adding flute spot within proximity: {hex(owid)}') logging.getLogger('').debug(f'Placing flute at: {hex(owid)}') new_spots.append(owid) @@ -455,23 +464,65 @@ def link_overworld(world, player): logging.getLogger('').warning(f'Warning: Attempted to place flute spot not in pool: {hex(owid)}') return True + if world.customizer: + custom_spots = world.customizer.get_owflutespots() + if custom_spots and player in custom_spots: + if 'force' in custom_spots[player]: + for id in custom_spots[player]['force']: + owid = id & 0xBF + addSpot(owid, True, True) + flute_spots -= 1 + if not world.is_tile_swapped(owid, player): + used_flute_regions.append(flute_data[owid][0][0]) + else: + used_flute_regions.append(flute_data[owid][0][1]) + if 'forbid' in custom_spots[player]: + for id in custom_spots[player]['forbid']: + owid = id & 0xBF + if owid not in new_spots: + forbidden_spots.append(owid) + if not world.is_tile_swapped(owid, player): + forbidden_regions.append(flute_data[owid][0][0]) + else: + forbidden_regions.append(flute_data[owid][0][1]) + # determine sectors (isolated groups of regions) to place flute spots - flute_regions = {(f[0][0] if (o not in world.owswaps[player][0]) != (world.mode[player] == 'inverted') else f[0][1]) : o for o, f in flute_data.items()} + flute_regions = {(f[0][0] if (o not in world.owswaps[player][0]) != (world.mode[player] == 'inverted') else f[0][1]) : o for o, f in flute_data.items() if o not in new_spots and o not in forbidden_spots} flute_sectors = [(len([r for l in s for r in l]), [r for l in s for r in l if r in flute_regions]) for s in world.owsectors[player]] flute_sectors = [s for s in flute_sectors if len(s[1]) > 0] region_total = sum([c for c,_ in flute_sectors]) sector_total = len(flute_sectors) + empty_sector_total = 0 + sector_has_spot = [] - # reserve a number of flute spots for each sector - flute_spots = 8 + # determine which sectors still need a flute spot for sector in flute_sectors: + already_has_spot = any(region in sector for region in used_flute_regions) + sector_has_spot.append(already_has_spot) + if not already_has_spot: + empty_sector_total += 1 + if flute_spots < empty_sector_total: + logging.getLogger('').warning(f'Warning: Not every sector can have a flute spot, generation might fail') + # pretend like some of the empty sectors already have a flute spot, don't know if they will be reachable + for i in range(len(flute_sectors)): + if not sector_has_spot[i]: + sector_has_spot[i] = True + empty_sector_total -= 1 + if flute_spots == empty_sector_total: + break + + # distribute flute spots for each sector + for i in range(len(flute_sectors)): + sector = flute_sectors[i] sector_total -= 1 - spots_to_place = min(flute_spots - sector_total, max(1, round((sector[0] * (flute_spots - sector_total) / region_total) + 0.5))) + if not sector_has_spot[i]: + empty_sector_total -= 1 + spots_to_place = min(flute_spots - empty_sector_total, max(0 if sector_has_spot[i] else 1, round((sector[0] * (flute_spots - sector_total) / region_total) + 0.5))) target_spots = len(new_spots) + spots_to_place logging.getLogger('').debug(f'Sector of {sector[0]} regions gets {spots_to_place} spot(s)') - if 'Desert Teleporter Ledge' in sector[1] or 'Mire Teleporter Ledge' in sector[1]: - addSpot(0x30, False) # guarantee desert/mire access + if 0x30 in flute_pool and 0x30 not in forbidden_spots and len(new_spots) < target_spots and ('Desert Teleporter Ledge' in sector[1] or 'Mire Teleporter Ledge' in sector[1]): + addSpot(0x30, True, True) # guarantee desert/mire access random.shuffle(sector[1]) f = 0 @@ -482,8 +533,9 @@ def link_overworld(world, player): t += 1 if t > 5: raise GenerationException('Infinite loop detected in flute shuffle') - if sector[1][f] not in new_spots: - addSpot(flute_regions[sector[1][f]], t > 0) + owid = flute_regions[sector[1][f]] + if owid not in new_spots and owid not in forbidden_spots: + addSpot(owid, t > 0, False) f += 1 region_total -= sector[0] diff --git a/docs/Customizer.md b/docs/Customizer.md index 9e45635a..68687c23 100644 --- a/docs/Customizer.md +++ b/docs/Customizer.md @@ -89,7 +89,7 @@ You may define an item and a list of locations that an item should not be placed ### ow-tileflips -This must be defined by player. Each player number should be listed with the appropriate sections and each of these players MUST have `ow_mixed: true` in the `settings` section in order for any values here to take effect. This section has three primary subsections: `force_flip`, `force_no_flip`, and `undefined`. +This must be defined by player. Each player number should be listed with the appropriate sections and each of these players MUST have `ow_mixed: true` in the `settings` section in order for any values here to take effect. This section has three primary subsections: `force_flip`, `force_no_flip`, and `undefined_chance`. #### force_flip / force_no_flip @@ -110,6 +110,14 @@ force_no_flip: `undefined_chance` should be used to determine how to handle all the remaining tiles that aren't explicitly defined in the earlier step. This represents the percent chance a tile will flip. This value can be set from 0 to 100 (default is 50). A value of 0 means there is a 0% chance it will be flipped. +### ow-flutespots + +This must be defined by player. Each player number should be listed with the appropriate sections and each of these players MUST have some form of Flute Shuffle in order for any values here to take effect. This section has two subsections: `force` and `forbid`. Both are lists of OW Screen IDs, please refer to ow-tileflips above for more information. + +Everything listed in `force` means that this screen must contain a flute spot. + +Everything listed in `forbid` means that this screen must not contain a flute spot. + ### entrances This must be defined by player. Each player number should be listed with the appropriate sections. This section has three primary subsections: `entrances`, `exits`, and `two-way`. diff --git a/docs/customizer_example.yaml b/docs/customizer_example.yaml index 4c31cb7e..ecf209b1 100644 --- a/docs/customizer_example.yaml +++ b/docs/customizer_example.yaml @@ -77,6 +77,19 @@ ow-tileflips: - 0x2c - 0x18 undefined_chance: 50 +ow-flutespots: + 1: + force: + - 0x00 + - 0x12 + - 0x18 + - 0x1a + - 0x2f + - 0x30 + - 0x35 + forbid: + - 0x03 + - 0x05 entrances: 1: entrances: diff --git a/source/classes/CustomSettings.py b/source/classes/CustomSettings.py index a9d84948..7eb8a31c 100644 --- a/source/classes/CustomSettings.py +++ b/source/classes/CustomSettings.py @@ -10,6 +10,7 @@ from pathlib import Path import RaceRandom as random from BaseClasses import LocationType, DoorType +from OverworldShuffle import default_flute_connections, flute_data from source.tools.MysteryUtils import roll_settings, get_weights @@ -200,6 +201,11 @@ class CustomSettings(object): return self.file_source['ow-tileflips'] return None + def get_owflutespots(self): + if 'ow-flutespots' in self.file_source: + return self.file_source['ow-flutespots'] + return None + def get_entrances(self): if 'entrances' in self.file_source: return self.file_source['entrances'] @@ -356,6 +362,14 @@ class CustomSettings(object): flips[p]['force_flip'] = list(HexInt(f) for f in world.owswaps[p][0] if f < 0x40 or f >= 0x80) flips[p]['force_flip'].sort() flips[p]['undefined_chance'] = 0 + self.world_rep['ow-flutespots'] = flute = {} + for p in self.player_range: + flute[p] = {} + if p in world.owflutespots: + flute[p]['force'] = list(HexInt(id) for id in sorted(world.owflutespots[p])) + else: + flute[p]['force'] = list(HexInt(id) for id in sorted(default_flute_connections)) + flute[p]['forbid'] = [] def record_entrances(self, world): self.world_rep['entrances'] = entrances = {} From 256b59b4b84f1683ac5a78f2fa884627f85ec268 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sat, 19 Aug 2023 13:20:27 -0500 Subject: [PATCH 193/196] Temporarily fix issue with Customizer+Grouped OWR --- OverworldShuffle.py | 48 ++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 27501a7e..20d81e0c 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -690,33 +690,33 @@ def shuffle_tiles(world, groups, result_list, do_grouped, player): if world.customizer: if not do_grouped: custom_flips = world.customizer.get_owtileflips() - if custom_flips and player in custom_flips: - custom_flips = custom_flips[player] - nonflipped_groups = list() - forced_flips = list() - forced_nonflips = list() - if 'undefined_chance' in custom_flips: - undefined_chance = custom_flips['undefined_chance'] - if 'force_flip' in custom_flips: - forced_flips = custom_flips['force_flip'] - if 'force_no_flip' in custom_flips: - forced_nonflips = custom_flips['force_no_flip'] + if custom_flips and player in custom_flips: + custom_flips = custom_flips[player] + nonflipped_groups = list() + forced_flips = list() + forced_nonflips = list() + if 'undefined_chance' in custom_flips: + undefined_chance = custom_flips['undefined_chance'] + if 'force_flip' in custom_flips: + forced_flips = custom_flips['force_flip'] + if 'force_no_flip' in custom_flips: + forced_nonflips = custom_flips['force_no_flip'] - for group in groups: - if any(owid in group[0] for owid in forced_nonflips): - nonflipped_groups.append(group) - if any(owid in group[0] for owid in forced_flips): - flipped_groups.append(group) + for group in groups: + if any(owid in group[0] for owid in forced_nonflips): + nonflipped_groups.append(group) + if any(owid in group[0] for owid in forced_flips): + flipped_groups.append(group) - # Check if there are any groups that appear in both sets - if any(group in flipped_groups for group in nonflipped_groups): - raise GenerationException('Conflict found when flipping tiles') - - for g in nonflipped_groups: - always_removed.append(g) - if undefined_chance == 0: - for g in [g for g in groups if g not in flipped_groups + always_removed]: + # Check if there are any groups that appear in both sets + if any(group in flipped_groups for group in nonflipped_groups): + raise GenerationException('Conflict found when flipping tiles') + + for g in nonflipped_groups: always_removed.append(g) + if undefined_chance == 0: + for g in [g for g in groups if g not in flipped_groups + always_removed]: + always_removed.append(g) attempts = 1 if 0 < undefined_chance < 100: From b0d8ea074c0bac1423f01a63cef66856e2d885d2 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sat, 19 Aug 2023 13:27:38 -0500 Subject: [PATCH 194/196] Fixed issue with Major Item + TF goals --- source/item/FillUtil.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/item/FillUtil.py b/source/item/FillUtil.py index 87d6381d..1bdd8950 100644 --- a/source/item/FillUtil.py +++ b/source/item/FillUtil.py @@ -357,7 +357,7 @@ def determine_major_items(world, player): major_item_set.add('Single Arrow') if world.keyshuffle[player] == 'universal': major_item_set.add('Small Key (Universal)') - if world.goal in ['triforcehunt', 'trinity']: + if world.goal[player] in ['triforcehunt', 'trinity', 'ganonhunt']: major_item_set.add('Triforce Piece') if world.bombbag[player]: major_item_set.add('Bomb Upgrade (+10)') From 911dd4d702485f7d518e53b676a326a3d15f984c Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sat, 19 Aug 2023 19:24:16 -0500 Subject: [PATCH 195/196] Sorting flute spots by OW Slot --- Rom.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Rom.py b/Rom.py index c2677ec3..559ef2b8 100644 --- a/Rom.py +++ b/Rom.py @@ -688,8 +688,9 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): flute_spots = world.owflutespots[player] owFlags |= 0x0100 - for o in range(0, len(flute_spots)): - owid = flute_spots[o] + flute_writes = sorted([(f, flute_data[f][1]) for f in flute_spots], key = lambda f: f[1]) + for o in range(0, len(flute_writes)): + owid = flute_writes[o][0] offset = 0 data = flute_data[owid] From eb1888334eacdfcdadf0259987dae42eb00e99c5 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sat, 19 Aug 2023 19:43:11 -0500 Subject: [PATCH 196/196] Version bump 0.3.2.2 --- CHANGELOG.md | 7 +++++++ OverworldShuffle.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f235164..5f1c8fbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 0.3.2.2 +- Added Customizer support for Flute Shuffle (thanks Catobat) +- Fixed bad Old Man rescue possibility in Swapped ER +- Fixed vanilla placement issue in Swapped ER +- Removed entrance hints in Swapped ER +- Fixed various generation/validation errors + ## 0.3.2.1 - \~Merged in DR v1.2.0.20~ - Some minor Swapped ER improvements diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 20d81e0c..f1752dbd 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -7,7 +7,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType from OverworldGlitchRules import create_owg_connections from Utils import bidict -version_number = '0.3.2.1' +version_number = '0.3.2.2' # branch indicator is intentionally different across branches version_branch = '-u'