diff --git a/BaseClasses.py b/BaseClasses.py index 1d9bb095..81b47e79 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -301,6 +301,9 @@ class World(object): return edge return None + def is_tile_swapped(self, owid, player): + return (self.mode[player] == 'inverted') != (owid in self.owswaps[player][0] and self.owMixed[player]) + def check_for_door(self, doorname, player): if isinstance(doorname, Door): return doorname @@ -3038,12 +3041,12 @@ class Spoiler(object): 'triforcepool': self.world.treasure_hunt_total, 'code': {p: Settings.make_code(self.world, p) for p in range(1, self.world.players + 1)} } - if self.world.custom: - for p in range(1, self.world.players + 1): - if self.world.customitemarray[p]["triforcepiecesgoal"] > 0: - self.metadata['triforcegoal'][p] = max(min(self.world.customitemarray[p]["triforcepiecesgoal"], 99), 1) - if self.world.customitemarray[p]["triforcepieces"] > 0: - self.metadata['triforcepool'][p] = max(min(self.world.customitemarray[p]["triforcepieces"], 168), self.metadata['triforcegoal'][p]) + for p in range(1, self.world.players + 1): + from ItemList import set_default_triforce + if self.world.custom and p in self.world.customitemarray: + self.metadata['triforcegoal'][p], self.metadata['triforcepool'][p] = set_default_triforce(self.metadata['goal'][p], self.world.customitemarray[p]["triforcepiecesgoal"], self.world.customitemarray[p]["triforcepieces"]) + else: + self.metadata['triforcegoal'][p], self.metadata['triforcepool'][p] = set_default_triforce(self.metadata['goal'][p], self.world.treasure_hunt_count[p], self.world.treasure_hunt_total[p]) def parse_data(self): self.medallions = OrderedDict() @@ -3200,7 +3203,8 @@ class Spoiler(object): if self.metadata['shuffle'][player] != 'vanilla': outfile.write('Shuffle GT/Ganon:'.ljust(line_width) + '%s\n' % ('Yes' if self.metadata['shuffleganon'][player] else 'No')) outfile.write('Shuffle Links:'.ljust(line_width) + '%s\n' % ('Yes' if self.metadata['shufflelinks'][player] else 'No')) - outfile.write('Pyramid Hole Pre-opened:'.ljust(line_width) + '%s\n' % ('Yes' if self.metadata['open_pyramid'][player] else 'No')) + if self.metadata['goal'][player] != 'trinity': + outfile.write('Pyramid Hole Pre-opened:'.ljust(line_width) + '%s\n' % ('Yes' if self.metadata['open_pyramid'][player] else 'No')) 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]) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2990d4f..6bb81edf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +### 0.2.3.6 +- Added Trinity goal (8/10 default TF pieces) +- Many improvements to TFH pool allocation +- Fixed some issues with Multiworld generation with Custom Item Pools + ### 0.2.3.5 - Fixed issue with multiworld generation - Added infinite loop detection diff --git a/CLI.py b/CLI.py index 5bbcf572..a1e53a3c 100644 --- a/CLI.py +++ b/CLI.py @@ -177,13 +177,13 @@ def parse_settings(): "mixed_travel": "prevent", "standardize_palettes": "standardize", - "triforce_pool": 30, - "triforce_goal": 20, + "triforce_pool": 0, + "triforce_goal": 0, "triforce_pool_min": 0, "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/DoorShuffle.py b/DoorShuffle.py index 7964755e..fcd312cd 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -89,11 +89,11 @@ def link_doors_main(world, player): if world.mode[player] == 'standard': world.get_portal('Sanctuary', player).destination = True world.get_portal('Desert East', player).destination = True - if (world.mode[player] == 'inverted') != (0x30 in world.owswaps[player][0] and world.owMixed[player]): + if world.is_tile_swapped(0x30, player): world.get_portal('Desert West', player).destination = True - if (world.mode[player] == 'inverted') == (0x00 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x00, player): world.get_portal('Skull 2 West', player).destination = True - if (world.mode[player] == 'inverted') == (0x05 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x05, player): world.get_portal('Turtle Rock Lazy Eyes', player).destination = True world.get_portal('Turtle Rock Eye Bridge', player).destination = True else: @@ -1837,7 +1837,7 @@ def find_inaccessible_regions(world, player): if connect.type is not RegionType.Dungeon or connect.name.endswith(' Portal'): queue.append(connect) world.inaccessible_regions[player].extend([r.name for r in all_regions if r not in visited_regions and valid_inaccessible_region(r)]) - if (world.mode[player] == 'inverted') != (0x1b in world.owswaps[player][0] and world.owMixed[player]): + if world.is_tile_swapped(0x1b, player): ledge = world.get_region('Hyrule Castle Ledge', player) if any(x for x in ledge.exits if x.connected_region and x.connected_region.name == 'Agahnims Tower Portal'): world.inaccessible_regions[player].append('Hyrule Castle Ledge') @@ -1857,7 +1857,7 @@ def find_accessible_entrances(world, player, builder): start_regions = ['Links House', 'Sanctuary'] else: start_regions = ['Links House', 'Dark Sanctuary Hint'] - if (world.mode[player] == 'inverted') != (0x1b in world.owswaps[player][0] and world.owMixed[player]): + if world.is_tile_swapped(0x1b, player): start_regions.append('Hyrule Castle Ledge') regs = convert_regions(start_regions, world, player) visited_regions = set() @@ -1873,7 +1873,7 @@ def find_accessible_entrances(world, player, builder): while len(queue) > 0: next_region = queue.popleft() visited_regions.add(next_region) - if (world.mode[player] == 'inverted') != (0x1b in world.owswaps[player][0] and world.owMixed[player]) and next_region.name == 'Tower Agahnim 1': + if world.is_tile_swapped(0x1b, player) and next_region.name == 'Tower Agahnim 1': connect = world.get_region('Hyrule Castle Ledge', player) if connect not in queue and connect not in visited_regions: queue.append(connect) diff --git a/EntranceShuffle.py b/EntranceShuffle.py index 337eb453..5e6c772f 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -34,7 +34,7 @@ def link_entrances(world, player): world.owsectors[player] = build_sectors(world, player) # modifications to lists - if invFlag == (0x1b in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x1b, player): drop_connections.append(tuple(('Pyramid Hole', 'Pyramid'))) dropexit_connections.append(tuple(('Pyramid Entrance', 'Pyramid Exit'))) connect_simple(world, 'Other World S&Q', 'Pyramid Area', player) @@ -47,7 +47,7 @@ def link_entrances(world, player): dropexit_connections.append(tuple(('Inverted Pyramid Entrance', 'Pyramid Exit'))) connect_simple(world, 'Other World S&Q', 'Hyrule Castle Ledge', player) - if invFlag == (0x03 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x03, player): connect_simple(world, 'Old Man S&Q', 'Old Man House', player) else: connect_simple(world, 'Old Man S&Q', 'West Dark Death Mountain (Bottom)', player) @@ -89,18 +89,16 @@ def link_entrances(world, player): # inverted entrance mods ignore_pool = True for owid in swapped_connections.keys(): - if invFlag != (owid in world.owswaps[player][0] and world.owMixed[player]): + if world.is_tile_swapped(owid, player): for (entrancename, exitname) in swapped_connections[owid]: try: connect_two_way(world, entrancename, exitname, player) except RuntimeError: connect_entrance(world, entrancename, exitname, player) - if invFlag != (0x03 in world.owswaps[player][0] and world.owMixed[player]) and \ - invFlag == (0x0a in world.owswaps[player][0] and world.owMixed[player]): + if world.is_tile_swapped(0x03, player) and not world.is_tile_swapped(0x0a, player): connect_entrance(world, 'Death Mountain Return Cave (West)', 'Dark Death Mountain Healer Fairy', player) - elif invFlag != (0x0a in world.owswaps[player][0] and world.owMixed[player]) and \ - invFlag == (0x03 in world.owswaps[player][0] and world.owMixed[player]): + elif world.is_tile_swapped(0x0a, player) and not world.is_tile_swapped(0x03, player): connect_two_way(world, 'Bumper Cave (Top)', 'Death Mountain Return Cave Exit (West)', player) ignore_pool = False @@ -144,15 +142,15 @@ def link_entrances(world, player): Two_Door_Caves_Directional = list() Two_Door_Caves = [('Elder House (East)', 'Elder House (West)'), ('Superbunny Cave (Bottom)', 'Superbunny Cave (Top)')] - if invFlag == (0x0a in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x0a, player): Two_Door_Caves_Directional.append(tuple({'Bumper Cave (Bottom)', 'Bumper Cave (Top)'})) else: Two_Door_Caves_Directional.append(tuple({'Old Man Cave (West)', 'Death Mountain Return Cave (West)'})) - if invFlag == (0x05 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x05, player): Two_Door_Caves_Directional.append(tuple({'Hookshot Cave', 'Hookshot Cave Back Entrance'})) else: Two_Door_Caves.append(tuple({'Hookshot Cave', 'Hookshot Cave Back Entrance'})) - if invFlag == (0x28 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x28, player): Two_Door_Caves.append(tuple({'Two Brothers House (East)', 'Two Brothers House (West)'})) else: Two_Door_Caves_Directional.append(tuple({'Two Brothers House (East)', 'Two Brothers House (West)'})) @@ -181,14 +179,14 @@ def link_entrances(world, player): caves.extend(list(Old_Man_House)) caves.extend(list(three_exit_caves)) - if invFlag == (0x18 in world.owswaps[player][0] and world.owMixed[player]) or invFlag == (0x03 in world.owswaps[player][0] and world.owMixed[player]): # ability to activate flute in LW + if (not world.is_tile_swapped(0x18, player)) or (not world.is_tile_swapped(0x03, player)): # ability to activate flute in LW candidates = [e for e in lw_wdm_entrances if e != 'Old Man House (Bottom)'] random.shuffle(candidates) old_man_exit = candidates.pop() lw_wdm_entrances.remove(old_man_exit) connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player) - if invFlag == (0x0a in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x0a, player): lw_wdm_entrances.extend(['Old Man Cave (West)', 'Death Mountain Return Cave (West)']) else: lw_wdm_entrances.extend(['Bumper Cave (Bottom)', 'Bumper Cave (Top)']) @@ -213,7 +211,7 @@ def link_entrances(world, player): connect_two_way(world, old_man_exit, 'Old Man Cave Exit (East)', player) # place old man, bumper cave bottom to DDM entrances not in east bottom - if invFlag == (0x0a in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x0a, player): connect_two_way(world, 'Old Man Cave (West)', 'Old Man Cave Exit (West)', player) else: connect_two_way(world, 'Bumper Cave (Bottom)', 'Old Man Cave Exit (West)', player) @@ -223,7 +221,7 @@ def link_entrances(world, player): connect_caves(world, lw_wdm_entrances + lw_edm_entrances, [], caves, player) else: # place Old Man House in WDM if not swapped - if invFlag == (0x03 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x03, player): connect_caves(world, lw_wdm_entrances, [], list(Old_Man_House), player) else: connect_caves(world, lw_edm_entrances, [], list(Old_Man_House), player) @@ -258,7 +256,7 @@ def link_entrances(world, player): # place bomb shop, has limited options bomb_shop_doors = list(entrance_pool) - if world.logic[player] in ['noglitches', 'minorglitches'] or (invFlag != (0x1b in world.owswaps[player][0] and world.owMixed[player])): + if world.logic[player] in ['noglitches', 'minorglitches'] or world.is_tile_swapped(0x1b, player): bomb_shop_doors = [e for e in entrance_pool if e not in ['Pyramid Fairy']] bomb_shop = random.choice(bomb_shop_doors) connect_entrance(world, bomb_shop, 'Big Bomb Shop', player) @@ -303,7 +301,7 @@ def link_entrances(world, player): # place bomb shop, has limited options bomb_shop_doors = list(entrance_pool) - if world.logic[player] in ['noglitches', 'minorglitches'] or (invFlag != (0x1b in world.owswaps[player][0] and world.owMixed[player])): + if world.logic[player] in ['noglitches', 'minorglitches'] or world.is_tile_swapped(0x1b, player): bomb_shop_doors = [e for e in entrance_pool if e not in ['Pyramid Fairy']] bomb_shop = random.choice(bomb_shop_doors) connect_entrance(world, bomb_shop, 'Big Bomb Shop', player) @@ -360,7 +358,7 @@ def link_entrances(world, player): # place bomb shop, has limited options bomb_shop_doors = [e for e in entrance_pool if e not in list(zip(*drop_connections + dropexit_connections))[0]] - if world.logic[player] in ['noglitches', 'minorglitches'] or (invFlag != (0x1b in world.owswaps[player][0] and world.owMixed[player])): + if world.logic[player] in ['noglitches', 'minorglitches'] or world.is_tile_swapped(0x1b, player): bomb_shop_doors = [e for e in bomb_shop_doors if e not in ['Pyramid Fairy']] bomb_shop = random.choice(bomb_shop_doors) connect_entrance(world, bomb_shop, 'Big Bomb Shop', player) @@ -462,7 +460,7 @@ def link_entrances(world, player): # place bomb shop, has limited options bomb_shop_doors = list(entrance_pool) - if world.logic[player] in ['noglitches', 'minorglitches'] or (invFlag != (0x1b in world.owswaps[player][0] and world.owMixed[player])): + if world.logic[player] in ['noglitches', 'minorglitches'] or world.is_tile_swapped(0x1b, player): bomb_shop_doors = [e for e in entrance_pool if e not in ['Pyramid Fairy']] bomb_shop = random.choice(bomb_shop_doors) connect_entrance(world, bomb_shop, 'Big Bomb Shop', player) @@ -516,7 +514,7 @@ def link_entrances(world, player): # place bomb shop, has limited options bomb_shop_doors = list(entrance_pool) - if world.logic[player] in ['noglitches', 'minorglitches'] or (invFlag != (0x1b in world.owswaps[player][0] and world.owMixed[player])): + if world.logic[player] in ['noglitches', 'minorglitches'] or world.is_tile_swapped(0x1b, player): bomb_shop_doors = [e for e in entrance_pool if e not in ['Pyramid Fairy']] bomb_shop = random.choice(bomb_shop_doors) connect_entrance(world, bomb_shop, 'Big Bomb Shop', player) @@ -565,7 +563,7 @@ def link_entrances(world, player): # place bomb shop, has limited options bomb_shop_doors = list(entrance_pool) - if world.logic[player] in ['noglitches', 'minorglitches'] or (invFlag != (0x1b in world.owswaps[player][0] and world.owMixed[player])): + if world.logic[player] in ['noglitches', 'minorglitches'] or world.is_tile_swapped(0x1b, player): bomb_shop_doors = [e for e in entrance_pool if e not in ['Pyramid Fairy']] bomb_shop = random.choice(bomb_shop_doors) connect_entrance(world, bomb_shop, 'Big Bomb Shop', player) @@ -604,11 +602,11 @@ def link_entrances(world, player): if not world.shuffle_ganon: connect_two_way(world, 'Ganons Tower' if not invFlag else 'Agahnims Tower', 'Ganons Tower Exit', player) - connect_two_way(world, 'Pyramid Entrance' if invFlag == (0x1b in world.owswaps[player][0] and world.owMixed[player]) else 'Inverted Pyramid Entrance', 'Pyramid Exit', player) - connect_entrance(world, 'Pyramid Hole' if invFlag == (0x1b in world.owswaps[player][0] and world.owMixed[player]) else 'Inverted Pyramid Hole', 'Pyramid', player) + connect_two_way(world, 'Pyramid Entrance' if not world.is_tile_swapped(0x1b, player) else 'Inverted Pyramid Entrance', 'Pyramid Exit', player) + connect_entrance(world, 'Pyramid Hole' if not world.is_tile_swapped(0x1b, player) else 'Inverted Pyramid Hole', 'Pyramid', player) else: caves.extend(['Ganons Tower Exit', 'Pyramid Exit']) - hole_entrances.append('Pyramid Hole' if invFlag == (0x1b in world.owswaps[player][0] and world.owMixed[player]) else 'Inverted Pyramid Hole') + hole_entrances.append('Pyramid Hole' if not world.is_tile_swapped(0x1b, player) else 'Inverted Pyramid Hole') hole_targets.append('Pyramid') # shuffle holes @@ -648,7 +646,7 @@ def link_entrances(world, player): # place bomb shop, has limited options bomb_shop_doors = list(entrance_pool) - if world.logic[player] in ['noglitches', 'minorglitches'] or (invFlag != (0x1b in world.owswaps[player][0] and world.owMixed[player])): + if world.logic[player] in ['noglitches', 'minorglitches'] or world.is_tile_swapped(0x1b, player): bomb_shop_doors = [e for e in entrance_pool if e not in ['Pyramid Fairy']] random.shuffle(bomb_shop_doors) bomb_shop = bomb_shop_doors.pop() @@ -693,7 +691,7 @@ def link_entrances(world, player): world.powder_patch_required[player] = True # check for ganon location - if world.get_entrance('Pyramid Hole' if invFlag == (0x1b in world.owswaps[player][0] and world.owMixed[player]) else 'Inverted Pyramid Hole', player).connected_region.name != 'Pyramid': + if world.get_entrance('Pyramid Hole' if not world.is_tile_swapped(0x1b, player) else 'Inverted Pyramid Hole', player).connected_region.name != 'Pyramid': world.ganon_at_pyramid[player] = False # check for Ganon's Tower location @@ -1074,7 +1072,7 @@ def scramble_holes(world, player): hole_targets.append(('Hyrule Castle Secret Entrance Exit', 'Hyrule Castle Secret Entrance')) if world.shuffle_ganon: - hole_entrances.append(('Pyramid Entrance', 'Pyramid Hole') if invFlag == (0x1b in world.owswaps[player][0] and world.owMixed[player]) else ('Inverted Pyramid Entrance', 'Inverted Pyramid Hole')) + hole_entrances.append(('Pyramid Entrance', 'Pyramid Hole') if not world.is_tile_swapped(0x1b, player) else ('Inverted Pyramid Entrance', 'Inverted Pyramid Hole')) hole_targets.append(('Pyramid Exit', 'Pyramid')) # shuffle sanctuary hole in same world as other HC entrances @@ -1099,11 +1097,11 @@ def scramble_holes(world, player): else: # checks if drop candidates exist in LW drop_owids = [ 0x00, 0x02, 0x13, 0x15, 0x18, 0x1b, 0x22 ] - hc_in_lw = any([invFlag == (owid in world.owswaps[player][0] and world.owMixed[player]) for owid in drop_owids]) + hc_in_lw = any([not world.is_tile_swapped(owid, player) for owid in drop_owids]) candidate_drops = list() for door, drop in hole_entrances: - if hc_in_lw == (drop_owid_map[door][1] == (invFlag == (drop_owid_map[door][0] in world.owswaps[player][0] and world.owMixed[player]))): + if hc_in_lw == (drop_owid_map[door][1] == (not world.is_tile_swapped(drop_owid_map[door][0], player))): candidate_drops.append(tuple((door, drop))) random.shuffle(candidate_drops) @@ -1117,7 +1115,7 @@ def scramble_holes(world, player): # place pyramid hole if not world.shuffle_ganon: exit, target = ('Pyramid Exit', 'Pyramid') - if invFlag == (0x1b in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x1b, player): connect_two_way(world, 'Pyramid Entrance', exit, player) connect_entrance(world, 'Pyramid Hole', target, player) else: @@ -1183,16 +1181,16 @@ def simple_shuffle_dungeons(world, player): # checks if drop candidates exist in LW drop_owids = [ 0x00, 0x02, 0x13, 0x15, 0x18, 0x1b, 0x22 ] - drops_in_light_world = any([invFlag == (owid in world.owswaps[player][0] and world.owMixed[player]) for owid in drop_owids]) + drops_in_light_world = any([not world.is_tile_swapped(owid, player) for owid in drop_owids]) # placing HC in guaranteed same-world as available dropdowns if not drops_in_light_world or not invFlag: candidate_dungeons = list() for d in multi_dungeons: - if not drops_in_light_world and dungeon_owid_map[d][1] == (invFlag != (dungeon_owid_map[d][0] in world.owswaps[player][0] and world.owMixed[player])): + if not drops_in_light_world and dungeon_owid_map[d][1] == world.is_tile_swapped(dungeon_owid_map[d][0], player): # only adding DW candidates candidate_dungeons.append(d) - elif not invFlag and dungeon_owid_map[d][1] == (invFlag == (dungeon_owid_map[d][0] in world.owswaps[player][0] and world.owMixed[player])): + elif not invFlag and dungeon_owid_map[d][1] == (not world.is_tile_swapped(dungeon_owid_map[d][0], player)): # only adding LW candidates candidate_dungeons.append(d) random.shuffle(candidate_dungeons) @@ -1218,7 +1216,7 @@ def simple_shuffle_dungeons(world, player): elif hc_target == 'Turtle Rock': connect_two_way(world, 'Turtle Rock', 'Hyrule Castle Exit (South)', player) connect_two_way(world, 'Dark Death Mountain Ledge (West)', 'Hyrule Castle Exit (West)', player) - if invFlag == (0x45 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x45, player): connect_two_way(world, 'Turtle Rock Isolated Ledge Entrance', 'Hyrule Castle Exit (East)', player) connect_two_way(world, 'Dark Death Mountain Ledge (East)', at_door, player) else: @@ -1302,7 +1300,7 @@ def full_shuffle_dungeons(world, Dungeon_Exits, player): lw_entrances = list() dw_entrances = list() for owid in dungeon_owid_map.keys(): - if dungeon_owid_map[owid][1] == (invFlag == (owid in world.owswaps[player][0] and world.owMixed[player])): + if dungeon_owid_map[owid][1] == (not world.is_tile_swapped(owid, player)): lw_entrances.extend([e for e in dungeon_owid_map[owid][0] if e in entrance_pool]) else: dw_entrances.extend([e for e in dungeon_owid_map[owid][0] if e in entrance_pool]) @@ -1315,7 +1313,7 @@ def full_shuffle_dungeons(world, Dungeon_Exits, player): dw_must_exit = list() lw_related = list() dw_related = list() - if invFlag == (0x45 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x45, player): dw_entrances.remove('Turtle Rock Isolated Ledge Entrance') dw_must_exit.append('Turtle Rock Isolated Ledge Entrance') if 'Dark Death Mountain Ledge' in world.inaccessible_regions[player]: @@ -1324,7 +1322,7 @@ def full_shuffle_dungeons(world, Dungeon_Exits, player): random.shuffle(ledge) dw_must_exit.append(ledge.pop()) dw_related.extend(ledge) - if invFlag == (0x30 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x30, player): if 'Desert Palace Mouth' in world.inaccessible_regions[player]: lw_entrances.remove('Desert Palace Entrance (East)') lw_must_exit.append('Desert Palace Entrance (East)') @@ -1337,7 +1335,7 @@ def full_shuffle_dungeons(world, Dungeon_Exits, player): random.shuffle(ledge) dw_must_exit.append(ledge.pop()) dw_related.extend(ledge) - if invFlag == (0x1b in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x1b, player): if 'Hyrule Castle Ledge' in world.inaccessible_regions[player]: ledge = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)', 'Agahnims Tower'] lw_entrances = [e for e in lw_entrances if e not in ledge] @@ -1352,7 +1350,7 @@ def full_shuffle_dungeons(world, Dungeon_Exits, player): hyrule_castle_exits = list([tuple(e for e in hyrule_castle_exits if e in exit_pool)]) hyrule_castle_exits.extend([e for e in dungeon_exits if isinstance(e, str)]) dungeon_exits = [e for e in dungeon_exits if not isinstance(e, str)] - if invFlag == (0x13 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x13, player): connect_mandatory_exits(world, lw_entrances, hyrule_castle_exits, lw_must_exit, player, False) dungeon_exits.extend([e for e in hyrule_castle_exits if isinstance(e, str)]) hyrule_castle_exits = [e for e in hyrule_castle_exits if not isinstance(e, str)] @@ -1444,7 +1442,7 @@ def place_blacksmith(world, links_house, player): def place_old_man(world, pool, player, ignore_list=[]): # exit has to come from specific set of doors, the entrance is free to move about - if (world.mode[player] == 'inverted') == (0x03 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x03, player): region_name = 'West Death Mountain (Top)' else: region_name = 'West Dark Death Mountain (Top)' @@ -1537,7 +1535,7 @@ def connect_inaccessible_regions(world, lw_entrances, dw_entrances, caves, playe for region_name in inaccessible_regions.copy(): region = world.get_region(region_name, player) if region.type not in [RegionType.LightWorld, RegionType.DarkWorld] or not any((not exit.connected_region and exit.spot_type == 'Entrance') for exit in region.exits) \ - or (region_name == 'Pyramid Exit Ledge' and world.shuffle[player] != 'insanity' or invFlag != (0x1b in world.owswaps[player][0] and world.owMixed[player])): + or (region_name == 'Pyramid Exit Ledge' and world.shuffle[player] != 'insanity' or world.is_tile_swapped(0x1b, player)): inaccessible_regions.remove(region_name) elif region.type == (RegionType.LightWorld if not invFlag else RegionType.DarkWorld): must_exit_regions.append(region_name) diff --git a/Fill.py b/Fill.py index 4288a62c..46128ffd 100644 --- a/Fill.py +++ b/Fill.py @@ -701,7 +701,7 @@ def balance_money_progression(world): sphere_locations = get_sphere_locations(state, unchecked_locations) checked_locations = [] for player in range(1, world.players+1): - kiki_payable = state.prog_items[('Moon Pearl', player)] > 0 or (world.mode[player] == 'inverted') != (0x1e in world.owswaps[player][0] and world.owMixed[player]) + kiki_payable = state.prog_items[('Moon Pearl', player)] > 0 or world.is_tile_swapped(0x1e, player) if kiki_payable and world.get_region('Palace of Darkness Area', player) in state.reachable_regions[player]: if not kiki_paid[player]: kiki_check[player] = True diff --git a/ItemList.py b/ItemList.py index 9cf13c2d..b1856f63 100644 --- a/ItemList.py +++ b/ItemList.py @@ -184,7 +184,7 @@ def get_custom_array_key(item): def generate_itempool(world, player): - if (world.difficulty[player] not in ['normal', 'hard', 'expert'] or world.goal[player] not in ['ganon', 'pedestal', 'dungeons', 'triforcehunt', 'crystals', 'trinity'] + if (world.difficulty[player] not in ['normal', 'hard', 'expert'] or world.goal[player] not in ['ganon', 'pedestal', 'dungeons', 'triforcehunt', 'trinity', 'crystals'] or world.mode[player] not in ['open', 'standard', 'inverted'] or world.timer not in ['none', 'display', 'timed', 'timed-ohko', 'ohko', 'timed-countdown'] or world.progressive not in ['on', 'off', 'random']): raise NotImplementedError('Not supported yet') @@ -268,8 +268,8 @@ def generate_itempool(world, player): world.get_location('Zelda Drop Off', player).locked = True # set up item pool - if world.custom: - (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_total, treasure_hunt_icon, lamps_needed_for_dark_rooms) = make_custom_item_pool(world.progressive, world.shuffle[player], world.difficulty[player], world.timer, world.goal[player], world.mode[player], world.swords[player], world.retro[player], world.bombbag[player], world.customitemarray) + if world.custom and player in world.customitemarray: + (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_total, treasure_hunt_icon, lamps_needed_for_dark_rooms) = make_custom_item_pool(world.progressive, world.shuffle[player], world.difficulty[player], world.timer, world.goal[player], world.mode[player], world.swords[player], world.retro[player], world.bombbag[player], world.customitemarray[player]) world.rupoor_cost = min(world.customitemarray[player]["rupoorcost"], 9999) else: (pool, placed_items, precollected_items, clock_mode, lamps_needed_for_dark_rooms) = get_pool_core(world.progressive, world.shuffle[player], world.difficulty[player], world.treasure_hunt_total[player], world.timer, world.goal[player], world.mode[player], world.swords[player], world.retro[player], world.bombbag[player], world.doorShuffle[player], world.logic[player]) @@ -370,14 +370,8 @@ def generate_itempool(world, player): world.clock_mode = clock_mode if world.goal[player] in ['triforcehunt', 'trinity']: - if world.treasure_hunt_count[player] == 0: - world.treasure_hunt_count[player] = 20 - if world.treasure_hunt_total[player] == 0: - world.treasure_hunt_total[player] = 30 + world.treasure_hunt_count[player], world.treasure_hunt_total[player] = set_default_triforce(world.goal[player], world.treasure_hunt_count[player], world.treasure_hunt_total[player]) world.treasure_hunt_icon[player] = 'Triforce Piece' - if world.custom: - world.treasure_hunt_count[player] = treasure_hunt_count - world.treasure_hunt_total[player] = treasure_hunt_total world.itempool.extend([item for item in get_dungeon_item_pool(world) if item.player == player and ((item.smallkey and world.keyshuffle[player]) @@ -388,9 +382,9 @@ def generate_itempool(world, player): # logic has some branches where having 4 hearts is one possible requirement (of several alternatives) # rather than making all hearts/heart pieces progression items (which slows down generation considerably) # We mark one random heart container as an advancement item (or 4 heart pieces in expert mode) - if world.difficulty[player] in ['normal', 'hard'] and not (world.custom and world.customitemarray[player]["heartcontainer"] == 0): + if world.difficulty[player] in ['normal', 'hard'] and not (world.custom and player in world.customitemarray and world.customitemarray[player]["heartcontainer"] == 0): next(item for item in items if item.name == 'Boss Heart Container').advancement = True - elif world.difficulty[player] in ['expert'] and not (world.custom and world.customitemarray[player]["heartpiece"] < 4): + elif world.difficulty[player] in ['expert'] and not (world.custom and player in world.customitemarray and world.customitemarray[player]["heartpiece"] < 4): adv_heart_pieces = (item for item in items if item.name == 'Piece of Heart') for i in range(4): next(adv_heart_pieces).advancement = True @@ -447,7 +441,7 @@ def set_up_take_anys(world, player): if world.mode[player] == 'inverted': if 'Dark Sanctuary Hint' in take_any_locations: take_any_locations.remove('Dark Sanctuary Hint') - if (world.mode[player] == 'inverted') != (0x29 in world.owswaps[player][0] and world.owMixed[player]): + if world.is_tile_swapped(0x29, player): if 'Archery Game' in take_any_locations: take_any_locations.remove('Archery Game') @@ -966,13 +960,12 @@ def get_pool_core(progressive, shuffle, difficulty, treasure_hunt_total, timer, return (pool, placed_items, precollected_items, clock_mode, lamps_needed_for_dark_rooms) def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, swords, retro, bombbag, customitemarray): - if isinstance(customitemarray,dict) and 1 in customitemarray: - customitemarray = customitemarray[1] pool = [] placed_items = {} precollected_items = [] clock_mode = None treasure_hunt_count = None + treasure_hunt_total = None treasure_hunt_icon = None def place_item(loc, item): @@ -981,7 +974,7 @@ def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, s # Correct for insanely oversized item counts and take initial steps to handle undersized pools. # Bow to Silver Arrows Upgrade, including Generic Keys & Rupoors - for x in [*range(0, 66 + 1), 68, 69]: + for x in [*range(0, 69)]: key = CONST.CUSTOMITEMS[x] if customitemarray[key] > total_items_to_place: customitemarray[key] = total_items_to_place @@ -990,6 +983,10 @@ def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, s if customitemarray["triforce"] > total_items_to_place: customitemarray["triforce"] = total_items_to_place + # Triforce Pieces + if goal in ['triforcehunt', 'trinity']: + customitemarray["triforcepiecesgoal"], customitemarray["triforcepieces"] = set_default_triforce(goal, customitemarray["triforcepiecesgoal"], customitemarray["triforcepieces"]) + itemtotal = 0 # Bow to Silver Arrows Upgrade, including Generic Keys & Rupoors for x in [*range(0, 66 + 1), 68, 69]: @@ -1020,18 +1017,7 @@ def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, s pool.append(thisbottle) if customitemarray["triforcepieces"] > 0 or customitemarray["triforcepiecesgoal"] > 0: - treasure_hunt_count = 20 - treasure_hunt_total = 30 - if customitemarray["triforcepiecesgoal"] > 0: - treasure_hunt_count = max(min(customitemarray["triforcepiecesgoal"], 99), 1) #To display, count must be between 1 and 99. - if customitemarray["triforcepieces"] > 0: - treasure_hunt_total = max(min(customitemarray["triforcepieces"], 168), treasure_hunt_count) #168 max to ensure other progression can fit. treasure_hunt_icon = 'Triforce Piece' - # Ensure game is always possible to complete here, force sufficient pieces if the player is unwilling. - if (customitemarray["triforcepieces"] < treasure_hunt_count) and (goal in ['triforcehunt', 'trinity']) and (customitemarray["triforce"] == 0): - extrapieces = treasure_hunt_count - customitemarray["triforcepieces"] - pool.extend(['Triforce Piece'] * extrapieces) - itemtotal = itemtotal + extrapieces if timer in ['display', 'timed', 'timed-countdown']: clock_mode = 'countdown' if timer == 'timed-countdown' else 'stopwatch' @@ -1075,6 +1061,18 @@ def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, s return (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_total, treasure_hunt_icon, lamps_needed_for_dark_rooms) +def set_default_triforce(goal, custom_goal, custom_total): + triforce_goal, triforce_total = 0, 0 + if goal == 'triforcehunt': + triforce_goal, triforce_total = 20, 30 + elif goal == 'trinity': + triforce_goal, triforce_total = 8, 10 + if custom_goal > 0: + triforce_goal = max(min(custom_goal, 128), 1) + if custom_total > 0 or custom_goal > 0: + triforce_total = max(min(custom_total, 128), triforce_goal) #128 max to ensure other progression can fit. + return (triforce_goal, triforce_total) + # A quick test to ensure all combinations generate the correct amount of items. def test(): for difficulty in ['normal', 'hard', 'expert']: diff --git a/KeyDoorShuffle.py b/KeyDoorShuffle.py index 748c1549..83bcba43 100644 --- a/KeyDoorShuffle.py +++ b/KeyDoorShuffle.py @@ -1970,7 +1970,7 @@ def val_mire(key_logic, world, player): def val_turtle(key_logic, world, player): # todo: check vanilla key logic when TR back doors are accessible - if world.shuffle[player] == 'vanilla' and (world.mode[player] == 'inverted') == (0x05 in world.owswaps[player][0] and world.owMixed[player]) and world.logic[player] in ('noglitches', 'minorglitches'): + if world.shuffle[player] == 'vanilla' and (not world.is_tile_swapped(0x05, player)) and world.logic[player] in ('noglitches', 'minorglitches'): val_rule(key_logic.door_rules['TR Hub NW'], 1) val_rule(key_logic.door_rules['TR Pokey 1 NW'], 2) val_rule(key_logic.door_rules['TR Chain Chomps Down Stairs'], 3) diff --git a/Main.py b/Main.py index b9db1ee8..624f8107 100644 --- a/Main.py +++ b/Main.py @@ -131,8 +131,8 @@ def main(args, seed=None, fish=None): world.keydropshuffle = args.keydropshuffle.copy() world.mixed_travel = args.mixed_travel.copy() world.standardize_palettes = args.standardize_palettes.copy() - world.treasure_hunt_count = args.triforce_goal.copy() - world.treasure_hunt_total = args.triforce_pool.copy() + world.treasure_hunt_count = {player: int(args.triforce_goal[player]) for player in range(1, world.players + 1)} + world.treasure_hunt_total = {player: int(args.triforce_pool[player]) for player in range(1, world.players + 1)} world.shufflelinks = args.shufflelinks.copy() world.pseudoboots = args.pseudoboots.copy() diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 3f753b85..0dd9223a 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -1,10 +1,11 @@ import RaceRandom as random, logging, copy from collections import OrderedDict +from DungeonGenerator import GenerationException from BaseClasses import OWEdge, WorldType, RegionType, Direction, Terrain, PolSlot, Entrance from Regions import mark_dark_world_regions, mark_light_world_regions from OWEdges import OWTileRegions, OWTileGroups, OWEdgeGroups, OWExitTypes, OpenStd, parallel_links, IsParallel -__version__ = '0.2.3.5-u' +__version__ = '0.2.3.6-u' def link_overworld(world, player): # setup mandatory connections @@ -159,7 +160,7 @@ def link_overworld(world, player): # apply tile logical connections for owid in ow_connections.keys(): - if (world.mode[player] == 'inverted') == (owid in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(owid, player): for (exitname, regionname) in ow_connections[owid][0]: connect_simple(world, exitname, regionname, player) else: @@ -342,7 +343,7 @@ def link_overworld(world, player): for o in range(0, len(flute_destinations)): owslot = flute_destinations[o] regions = flute_data[owslot][0] - if (world.mode[player] == 'inverted') == (flute_data[owslot][1] in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(flute_data[owslot][1], player): connect_simple(world, 'Flute Spot ' + str(o + 1), regions[0], player) else: connect_simple(world, 'Flute Spot ' + str(o + 1), regions[1], player) @@ -364,7 +365,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 (world.mode[player] == 'inverted') == (flute_data[owid][1] in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(flute_data[owid][1], player): new_region = flute_data[owid][0][0] else: new_region = flute_data[owid][0][1] diff --git a/README.md b/README.md index 55bfdb98..e56bdfe3 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,12 @@ New flute spots are chosen at random, with restrictions that limit the promixity New flute spots are chosen at random with minimum bias. +## New Goal Options (--goal) + +### Trinity + +This goal gives you the choice between 3 goals, only one of which the player needs to complete: Defeat Ganon (no Aga2), Pulling Pedestal, or turn in TF pieces to Murahdulah. By default, you need to find 8 of 10 total TF pieces but this can be changed with a Custom Item Pool. It is recommended to set GT Entry to 7 crystals and Ganon to 5 crystals or Random crystals, although the player can flexibly change these settings as they seem fit. + ## New Entrance Shuffle Options (--shuffle) ### Lite diff --git a/Rom.py b/Rom.py index f5232ddc..3aeb31d1 100644 --- a/Rom.py +++ b/Rom.py @@ -639,7 +639,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): offset = 0 data = flute_data[owslot] - if (world.mode[player] == 'inverted') != (data[1] in world.owswaps[player][0] and world.owMixed[player]): + if world.is_tile_swapped(data[1], player): offset = 0x40 write_int16(rom, snes_to_pc(0x02E849 + (o * 2)), data[1] + offset) # owid @@ -2355,7 +2355,7 @@ def write_strings(rom, world, player, team): elif world.shopsanity[player]: entrances_to_hint.update(ShopEntrances) if world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull']: - if world.mode[player] == 'inverted' != (0x2c in world.owswaps[player][0] and world.owMixed[player]): + if world.is_tile_swapped(0x2c, player): entrances_to_hint.update({'Links House': 'The hero\'s old residence'}) if world.shufflelinks[player]: entrances_to_hint.update({'Big Bomb Shop': 'The old bomb shop'}) @@ -2367,7 +2367,7 @@ def write_strings(rom, world, player, team): if world.shuffle[player] in ['insanity', 'madness_legacy', 'insanity_legacy']: entrances_to_hint.update(InsanityEntrances) if world.shuffle_ganon: - if world.mode[player] == 'inverted' != (0x1b in world.owswaps[player][0] and world.owMixed[player]): + if world.is_tile_swapped(0x1b, player): entrances_to_hint.update({'Inverted Pyramid Entrance': 'The extra castle passage'}) else: entrances_to_hint.update({'Pyramid Entrance': 'The pyramid ledge'}) @@ -2705,9 +2705,9 @@ def set_inverted_mode(world, player, rom, inverted_buffer): write_int16(rom, 0x15AEE + 2*0x38, 0x00E0) write_int16(rom, 0x15AEE + 2*0x25, 0x000C) - if (world.mode[player] == 'inverted') != (0x03 in world.owswaps[player][0] and world.owMixed[player]): + if world.is_tile_swapped(0x03, player): if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull'] \ - or (world.shuffle[player] == 'simple' and (world.mode[player] == 'inverted' != (0x05 in world.owswaps[player][0] and world.owMixed[player]))): + or (world.shuffle[player] == 'simple' and world.is_tile_swapped(0x05, player)): rom.write_bytes(snes_to_pc(0x308350), [0x00, 0x00, 0x01]) # mountain cave starts on OW write_int16(rom, snes_to_pc(0x02D8DE), 0x00F1) # change mountain cave spawn point to just outside old man cave @@ -2729,20 +2729,20 @@ def set_inverted_mode(world, player, rom, inverted_buffer): rom.write_byte(snes_to_pc(0x02D9B8), 0x12) rom.write_bytes(0x180247, [0x00, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00]) # indicates the overworld door being used for the single entrance spawn point - if (world.mode[player] == 'inverted') != (0x05 in world.owswaps[player][0] and world.owMixed[player]): + if world.is_tile_swapped(0x05, player): rom.write_bytes(snes_to_pc(0x1BC655), [0x4A, 0x1D, 0x82]) # add warp under rock rom.write_byte(snes_to_pc(0x1BC428), 0x00) # remove secret portal - if (world.mode[player] == 'inverted') != (0x07 in world.owswaps[player][0] and world.owMixed[player]): + if world.is_tile_swapped(0x07, player): rom.write_bytes(snes_to_pc(0x1BC387), [0xDD, 0xD1]) # add warps under rocks rom.write_bytes(snes_to_pc(0x1BD1DD), [0xA4, 0x06, 0x82, 0x9E, 0x06, 0x82, 0xFF, 0xFF]) # add warps under rocks rom.write_byte(0x180089, 0x01) # open TR after exit rom.write_bytes(0x0086E, [0x5C, 0x00, 0xA0, 0xA1]) # TR tail if world.shuffle[player] in ['vanilla']: world.fix_trock_doors[player] = True - if (world.mode[player] == 'inverted') != (0x10 in world.owswaps[player][0] and world.owMixed[player]): + if world.is_tile_swapped(0x10, player): rom.write_bytes(snes_to_pc(0x1BC67A), [0x2E, 0x0B, 0x82]) # add warp under rock rom.write_byte(snes_to_pc(0x1BC43A), 0x00) # remove secret portal - if (world.mode[player] == 'inverted') != (0x1B in world.owswaps[player][0] and world.owMixed[player]): + if world.is_tile_swapped(0x1b, player): write_int16(rom, 0x15AEE + 2 * 0x06, 0x0020) # post aga hyrule castle spawn rom.write_byte(0x15B8C + 0x06, 0x1B) write_int16(rom, 0x15BDB + 2 * 0x06, 0x00AE) @@ -2847,24 +2847,24 @@ def set_inverted_mode(world, player, rom, inverted_buffer): rom.write_byte(0x1607C + 0x37, 0x0A) write_int16(rom, 0x160CB + 2 * 0x37, 0x0000) write_int16(rom, 0x16169 + 2 * 0x37, 0x811C) - if (world.mode[player] == 'inverted') != (0x29 in world.owswaps[player][0] and world.owMixed[player]): + if world.is_tile_swapped(0x29, player): rom.write_bytes(snes_to_pc(0x06B2AB), [0xF0, 0xE1, 0x05]) # frog pickup on contact - if (world.mode[player] == 'inverted') != (0x2C in world.owswaps[player][0] and world.owMixed[player]): + if world.is_tile_swapped(0x2c, player): if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull']: rom.write_byte(0x15B8C, 0x6C) # exit links at bomb shop area rom.write_byte(0xDBB73 + 0x00, 0x53) # switch bomb shop and links house rom.write_byte(0xDBB73 + 0x52, 0x01) - if (world.mode[player] == 'inverted') != (0x2F in world.owswaps[player][0] and world.owMixed[player]): + if world.is_tile_swapped(0x2f, player): rom.write_bytes(snes_to_pc(0x1BC80D), [0xB2, 0x0B, 0x82]) # add warp under rock rom.write_byte(snes_to_pc(0x1BC590), 0x00) # remove secret portal - if (world.mode[player] == 'inverted') != (0x30 in world.owswaps[player][0] and world.owMixed[player]): + if world.is_tile_swapped(0x30, player): rom.write_bytes(snes_to_pc(0x1BC81E), [0x94, 0x1D, 0x82]) # add warp under rock rom.write_byte(snes_to_pc(0x1BC5A1), 0x00) # remove secret portal - if (world.mode[player] == 'inverted') != (0x33 in world.owswaps[player][0] and world.owMixed[player]): + if world.is_tile_swapped(0x33, player): rom.write_bytes(snes_to_pc(0x1BC3DF), [0xD8, 0xD1]) # add warp under rock rom.write_bytes(snes_to_pc(0x1BD1D8), [0xA8, 0x02, 0x82, 0xFF, 0xFF]) # add warp under rock rom.write_byte(snes_to_pc(0x1BC5B1), 0x00) # remove secret portal - if (world.mode[player] == 'inverted') != (0x35 in world.owswaps[player][0] and world.owMixed[player]): + if world.is_tile_swapped(0x35, player): rom.write_bytes(snes_to_pc(0x1BC85A), [0x50, 0x0F, 0x82]) # add warp under rock rom.write_byte(snes_to_pc(0x1BC5C7), 0x00) # remove secret portal diff --git a/Rules.py b/Rules.py index 8a79b5f1..afecc0fc 100644 --- a/Rules.py +++ b/Rules.py @@ -55,7 +55,7 @@ def set_rules(world, player): elif world.goal[player] == 'ganon': # require aga2 to beat ganon add_rule(world.get_location('Ganon', player), lambda state: state.has('Beat Agahnim 2', player)) - elif world.goal[player] in ['triforcehunt', 'trinity']: + if world.goal[player] in ['triforcehunt', 'trinity']: if ('Murahdahla', player) in world._location_cache: add_rule(world.get_location('Murahdahla', player), lambda state: state.item_count('Triforce Piece', player) + state.item_count('Power Star', player) >= int(state.world.treasure_hunt_count[player])) @@ -879,7 +879,7 @@ def ow_rules(world, player): else: set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has_crystals(world.crystals_needed_for_gt[player], player)) - if (world.mode[player] == 'inverted') == (0x00 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x00, player): set_rule(world.get_entrance('Lost Woods East Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Lost Woods Entry Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Lost Woods Pedestal Mirror Spot', player), lambda state: state.has_Mirror(player)) @@ -894,12 +894,12 @@ def ow_rules(world, player): set_rule(world.get_entrance('Skull Woods Forgotten (Middle) Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Skull Woods Front Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x02 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x02, player): set_rule(world.get_entrance('Lumberjack Mirror Spot', player), lambda state: state.has_Mirror(player)) else: set_rule(world.get_entrance('Dark Lumberjack Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x03 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x03, player): set_rule(world.get_entrance('West Death Mountain (Top) 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)) else: @@ -907,7 +907,7 @@ def ow_rules(world, player): set_rule(world.get_entrance('Bubble Boy Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('West Dark Death Mountain (Bottom) Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x05 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x05, player): set_rule(world.get_entrance('East Death Mountain (Top West) Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('East Death Mountain (Top East) 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)) @@ -929,7 +929,7 @@ def ow_rules(world, player): set_rule(world.get_entrance('Dark Floating Island Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Dark Death Mountain Teleporter (East)', player), lambda state: state.can_lift_heavy_rocks(player)) - if (world.mode[player] == 'inverted') == (0x07 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x07, player): set_rule(world.get_entrance('TR Pegs Area Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('TR Pegs Teleporter', player), lambda state: state.has('Hammer', player)) else: @@ -937,7 +937,7 @@ def ow_rules(world, player): set_rule(world.get_entrance('Turtle Rock Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Turtle Rock Teleporter', player), lambda state: state.has('Hammer', player) and state.can_lift_heavy_rocks(player) and state.has_Pearl(player)) - if (world.mode[player] == 'inverted') == (0x0a in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x0a, player): set_rule(world.get_entrance('Mountain Entry Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Mountain Entry Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Mountain Entry Entrance Mirror Spot', player), lambda state: state.has_Mirror(player)) @@ -946,12 +946,12 @@ def ow_rules(world, player): set_rule(world.get_entrance('Bumper Cave Entry 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)) - if (world.mode[player] == 'inverted') == (0x0f in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x0f, player): set_rule(world.get_entrance('Zora Waterfall Mirror Spot', player), lambda state: state.has_Mirror(player)) else: set_rule(world.get_entrance('Catfish Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x10 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x10, player): set_rule(world.get_entrance('Lost Woods Pass West Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Lost Woods Pass East Top Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Lost Woods Pass Portal Mirror Spot', player), lambda state: state.has_Mirror(player)) @@ -963,24 +963,24 @@ def ow_rules(world, player): set_rule(world.get_entrance('Skull Woods Pass Portal Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Skull Woods Pass East Bottom Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x11 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x11, player): set_rule(world.get_entrance('Kakariko Fortune Mirror Spot', player), lambda state: state.has_Mirror(player)) else: set_rule(world.get_entrance('Outcast Fortune Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x12 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x12, player): set_rule(world.get_entrance('Kakariko Pond Mirror Spot', player), lambda state: state.has_Mirror(player)) else: set_rule(world.get_entrance('Outcast Pond Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x13 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x13, player): set_rule(world.get_entrance('Sanctuary Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Bonk Rock Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) else: set_rule(world.get_entrance('Dark Chapel Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Dark Chapel Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x14 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x14, 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('Kings Grave Mirror Spot', player), lambda state: state.has_Pearl(player) and state.has_Mirror(player)) else: @@ -990,28 +990,28 @@ def ow_rules(world, player): set_rule(world.get_entrance('Dark Graveyard Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Dark Graveyard Grave Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x15 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x15, player): set_rule(world.get_entrance('River Bend Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('River Bend East Mirror Spot', player), lambda state: state.has_Mirror(player)) else: set_rule(world.get_entrance('Qirn Jump Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Qirn Jump East Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x16 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x16, player): set_rule(world.get_entrance('Potion Shop Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Potion Shop Northeast Mirror Spot', player), lambda state: state.has_Mirror(player)) else: set_rule(world.get_entrance('Dark Witch Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Dark Witch Northeast Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x17 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x17, player): set_rule(world.get_entrance('Zora Approach Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Zora Approach Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) else: set_rule(world.get_entrance('Catfish Approach Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Catfish Approach Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x18 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x18, player): set_rule(world.get_entrance('Kakariko Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Kakariko Grass Mirror Spot', player), lambda state: state.has_Mirror(player)) else: @@ -1019,13 +1019,13 @@ def ow_rules(world, player): set_rule(world.get_entrance('Village of Outcasts Southwest Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Hammer House Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x1a in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x1a, player): set_rule(world.get_entrance('Forgotton Forest Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Forgotton Forest Fence Mirror Spot', player), lambda state: state.has_Mirror(player)) else: set_rule(world.get_entrance('Shield Shop Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x1b in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x1b, player): set_rule(world.get_entrance('Inverted Pyramid Hole', player), lambda state: False) set_rule(world.get_entrance('Inverted Pyramid Entrance', player), lambda state: False) 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)) @@ -1040,7 +1040,7 @@ def ow_rules(world, player): set_rule(world.get_entrance('Top of Pyramid (Inner)', player), lambda state: state.has('Beat Agahnim 1', player)) else: 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)) - add_rule(world.get_entrance('Pyramid Hole', player), lambda state: False) + 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('Agahnims Tower', player), lambda state: state.has_crystals(world.crystals_needed_for_gt[player], player)) @@ -1053,7 +1053,7 @@ def ow_rules(world, player): set_rule(world.get_entrance('Pyramid Entry Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Post Aga Inverted Teleporter', player), lambda state: state.has('Beat Agahnim 1', player)) - if (world.mode[player] == 'inverted') == (0x1d in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x1d, player): set_rule(world.get_entrance('Wooden Bridge Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Wooden Bridge Northeast Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Wooden Bridge West Mirror Spot', player), lambda state: state.has_Mirror(player)) @@ -1062,12 +1062,12 @@ def ow_rules(world, player): set_rule(world.get_entrance('Broken Bridge East Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Broken Bridge Northeast Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x1e in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x1e, player): set_rule(world.get_entrance('Eastern Palace Mirror Spot', player), lambda state: state.has_Mirror(player)) else: set_rule(world.get_entrance('Palace of Darkness Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x22 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x22, player): set_rule(world.get_entrance('Blacksmith Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Blacksmith Entry Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Bat Cave Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) @@ -1075,19 +1075,19 @@ def ow_rules(world, player): set_rule(world.get_entrance('Hammer Pegs Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Hammer Pegs Entry Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x25 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x25, player): set_rule(world.get_entrance('Sand Dunes Mirror Spot', player), lambda state: state.has_Mirror(player)) else: set_rule(world.get_entrance('Dark Dunes Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x28 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x28, player): set_rule(world.get_entrance('Maze Race Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Maze Race Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) else: set_rule(world.get_entrance('Dig Game Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Dig Game Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x29 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x29, player): set_rule(world.get_entrance('Kakariko Suburb Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Kakariko Suburb South Mirror Spot', player), lambda state: state.has_Mirror(player)) else: @@ -1095,24 +1095,24 @@ def ow_rules(world, player): set_rule(world.get_entrance('Frog Prison Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Archery Game Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x2a in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x2a, player): set_rule(world.get_entrance('Flute Boy Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Flute Boy Pass Mirror Spot', player), lambda state: state.has_Mirror(player)) else: set_rule(world.get_entrance('Stumpy Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Stumpy Pass Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x2b in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x2b, player): set_rule(world.get_entrance('Central Bonk Rocks Mirror Spot', player), lambda state: state.has_Mirror(player)) else: set_rule(world.get_entrance('Dark Bonk Rocks Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x2c in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x2c, player): set_rule(world.get_entrance('Links House Mirror Spot', player), lambda state: state.has_Mirror(player)) else: set_rule(world.get_entrance('Big Bomb Shop Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x2d in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x2d, player): set_rule(world.get_entrance('Stone Bridge Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Stone Bridge South Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Hobo Mirror Spot', player), lambda state: state.has_Mirror(player) and state.has_Pearl(player) and state.has('Flippers', player)) @@ -1121,19 +1121,19 @@ def ow_rules(world, player): set_rule(world.get_entrance('Hammer Bridge South Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Dark Hobo Mirror Spot', player), lambda state: state.has_Mirror(player) and state.has_Pearl(player) and state.has('Flippers', player)) - if (world.mode[player] == 'inverted') == (0x2e in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x2e, player): set_rule(world.get_entrance('Tree Line Mirror Spot', player), lambda state: state.has_Mirror(player)) else: set_rule(world.get_entrance('Dark Tree Line Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x2f in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x2f, player): set_rule(world.get_entrance('Eastern Nook Mirror Spot', player), lambda state: state.has_Mirror(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 else: set_rule(world.get_entrance('Darkness Nook Mirror Spot', player), lambda state: state.has_Mirror(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)) - if (world.mode[player] == 'inverted') == (0x30 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x30, player): set_rule(world.get_entrance('Checkerboard Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Desert 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)) @@ -1148,14 +1148,14 @@ def ow_rules(world, player): set_rule(world.get_entrance('Misery Mire Main Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Misery Mire Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) - if (world.mode[player] == 'inverted') == (0x32 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x32, player): set_rule(world.get_entrance('Cave 45 Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Flute Boy Entry Mirror Spot', player), lambda state: state.has_Mirror(player)) else: set_rule(world.get_entrance('Stumpy Approach Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Stumpy Bush Entry Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x33 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x33, player): set_rule(world.get_entrance('C Whirlpool Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('C Whirlpool Outer Mirror Spot', player), lambda state: state.has_Mirror(player)) 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 @@ -1166,12 +1166,12 @@ def ow_rules(world, player): 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)) set_rule(world.get_entrance('South Teleporter Cliff Ledge Drop', player), lambda state: state.can_lift_rocks(player) and state.has_Pearl(player)) - if (world.mode[player] == 'inverted') == (0x34 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x34, player): set_rule(world.get_entrance('Statues Mirror Spot', player), lambda state: state.has_Mirror(player)) else: set_rule(world.get_entrance('Hype Cave Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x35 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x35, player): set_rule(world.get_entrance('Lake Hylia Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Lake Hylia Northeast Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Lake Hylia Island Mirror Spot', player), lambda state: state.has_Mirror(player) and state.has_Pearl(player) and state.has('Flippers', player)) @@ -1188,12 +1188,12 @@ def ow_rules(world, player): set_rule(world.get_entrance('Ice Palace Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Ice Palace Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) - if (world.mode[player] == 'inverted') == (0x37 in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x37, player): set_rule(world.get_entrance('Ice Cave Mirror Spot', player), lambda state: state.has_Mirror(player)) else: set_rule(world.get_entrance('Shopping Mall Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x3a in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x3a, player): set_rule(world.get_entrance('Desert Pass Ledge Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Desert Pass Mirror Spot', player), lambda state: state.has_Mirror(player)) else: @@ -1201,17 +1201,17 @@ def ow_rules(world, player): set_rule(world.get_entrance('Swamp Nook Southeast Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Swamp Nook Pegs Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x3b in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x3b, player): set_rule(world.get_entrance('Dam Mirror Spot', player), lambda state: state.has_Mirror(player)) else: set_rule(world.get_entrance('Swamp Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x3c in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x3c, player): set_rule(world.get_entrance('South Pass Mirror Spot', player), lambda state: state.has_Mirror(player)) else: set_rule(world.get_entrance('Dark South Pass Mirror Spot', player), lambda state: state.has_Mirror(player)) - if (world.mode[player] == 'inverted') == (0x3f in world.owswaps[player][0] and world.owMixed[player]): + if not world.is_tile_swapped(0x3f, player): set_rule(world.get_entrance('Octoballoon Mirror Spot', player), lambda state: state.has_Mirror(player)) else: set_rule(world.get_entrance('Bomber Corner Mirror Spot', player), lambda state: state.has_Mirror(player)) diff --git a/resources/app/gui/lang/en.json b/resources/app/gui/lang/en.json index aaab4a5d..f0ffc621 100644 --- a/resources/app/gui/lang/en.json +++ b/resources/app/gui/lang/en.json @@ -237,6 +237,7 @@ "randomizer.item.goal.pedestal": "Master Sword Pedestal", "randomizer.item.goal.dungeons": "All Dungeons", "randomizer.item.goal.triforcehunt": "Triforce Hunt", + "randomizer.item.goal.trinity": "Trinity", "randomizer.item.goal.crystals": "Crystals", "randomizer.item.crystals_gt": "Crystals to open GT", diff --git a/resources/app/gui/randomize/item/widgets.json b/resources/app/gui/randomize/item/widgets.json index bed86116..9cb664ae 100644 --- a/resources/app/gui/randomize/item/widgets.json +++ b/resources/app/gui/randomize/item/widgets.json @@ -35,6 +35,7 @@ "pedestal", "dungeons", "triforcehunt", + "trinity", "crystals" ] },