Make keys, pendants, crystals and agahnim fights "events", which we sweep for everytime we have new unlock potential. Simplifies searching for items significantly.
This commit is contained in:
		
							parent
							
								
									1fe6774ba0
								
							
						
					
					
						commit
						a73dba985f
					
				
							
								
								
									
										112
									
								
								BaseClasses.py
								
								
								
								
							
							
						
						
									
										112
									
								
								BaseClasses.py
								
								
								
								
							|  | @ -76,6 +76,39 @@ class World(object): | |||
|                         return r_location | ||||
|         raise RuntimeError('No such location %s' % location) | ||||
| 
 | ||||
|     def get_all_state(self): | ||||
|         ret = CollectionState(self) | ||||
|          | ||||
|         def soft_collect(item): | ||||
|             if item.name.startswith('Progressive '): | ||||
|                 if 'Sword' in item.name: | ||||
|                     if ret.has('Golden Sword'): | ||||
|                         pass | ||||
|                     elif ret.has('Tempered Sword'): | ||||
|                         ret.prog_items.append('Golden Sword') | ||||
|                     elif ret.has('Master Sword'): | ||||
|                         ret.prog_items.append('Tempered Sword') | ||||
|                     elif ret.has('Fighter Sword'): | ||||
|                         ret.prog_items.append('Master Sword') | ||||
|                     else: | ||||
|                         ret.prog_items.append('Fighter Sword') | ||||
|                 elif 'Glove' in item.name: | ||||
|                     if ret.has('Titans Mitts'): | ||||
|                         pass | ||||
|                     elif ret.has('Power Glove'): | ||||
|                         ret.prog_items.append('Titans Mitts') | ||||
|                     else: | ||||
|                         ret.prog_items.append('Power Glove') | ||||
| 
 | ||||
|             elif item.advancement: | ||||
|                 ret.prog_items.append(item.name) | ||||
| 
 | ||||
|         for location in self.get_filled_locations(): | ||||
|             soft_collect(location.item) | ||||
|         for item in self.itempool: | ||||
|             soft_collect(item) | ||||
|         return ret | ||||
| 
 | ||||
|     def find_items(self, item): | ||||
|         return [location for location in self.get_locations() if location.item is not None and location.item.name == item] | ||||
| 
 | ||||
|  | @ -87,7 +120,7 @@ class World(object): | |||
|             location.item = item | ||||
|             item.location = location | ||||
|             if collect: | ||||
|                 self.state.collect(item) | ||||
|                 self.state.collect(item, location.event) | ||||
| 
 | ||||
|             logging.getLogger('').debug('Placed %s at %s' % (item, location)) | ||||
|         else: | ||||
|  | @ -103,6 +136,9 @@ class World(object): | |||
|     def get_unfilled_locations(self): | ||||
|         return [location for location in self.get_locations() if location.item is None] | ||||
| 
 | ||||
|     def get_filled_locations(self): | ||||
|         return [location for location in self.get_locations() if location.item is not None] | ||||
| 
 | ||||
|     def get_reachable_locations(self, state=None): | ||||
|         if state is None: | ||||
|             state = self.state | ||||
|  | @ -116,7 +152,7 @@ class World(object): | |||
|     def unlocks_new_location(self, item): | ||||
|         temp_state = self.state.copy() | ||||
|         temp_state._clear_cache() | ||||
|         temp_state.collect(item) | ||||
|         temp_state.collect(item, True) | ||||
| 
 | ||||
|         for location in self.get_unfilled_locations(): | ||||
|             if temp_state.can_reach(location) and not self.state.can_reach(location): | ||||
|  | @ -125,7 +161,7 @@ class World(object): | |||
|         return False | ||||
| 
 | ||||
|     def can_beat_game(self): | ||||
|         prog_locations = [location for location in self.get_locations() if location.item is not None and location.item.advancement] | ||||
|         prog_locations = [location for location in self.get_locations() if location.item is not None and (location.item.advancement or location.event)] | ||||
| 
 | ||||
|         state = CollectionState(self) | ||||
|         treasure_pieces_collected = 0 | ||||
|  | @ -148,7 +184,7 @@ class World(object): | |||
| 
 | ||||
|             for location in sphere: | ||||
|                 prog_locations.remove(location) | ||||
|                 state.collect(location.item) | ||||
|                 state.collect(location.item, True) | ||||
| 
 | ||||
|         return False | ||||
| 
 | ||||
|  | @ -166,14 +202,14 @@ class World(object): | |||
| 
 | ||||
| class CollectionState(object): | ||||
| 
 | ||||
|     def __init__(self, parent, has_everything=False): | ||||
|     def __init__(self, parent): | ||||
|         self.prog_items = [] | ||||
|         self.world = parent | ||||
|         self.has_everything = has_everything | ||||
|         self.region_cache = {} | ||||
|         self.location_cache = {} | ||||
|         self.entrance_cache = {} | ||||
|         self.recursion_count = 0 | ||||
|         self.events = [] | ||||
| 
 | ||||
|     def _clear_cache(self): | ||||
|         # we only need to invalidate results which were False, places we could reach before we can still reach after adding more items | ||||
|  | @ -182,11 +218,12 @@ class CollectionState(object): | |||
|         self.entrance_cache = {k: v for k, v in self.entrance_cache.items() if v} | ||||
| 
 | ||||
|     def copy(self): | ||||
|         ret = CollectionState(self.world, self.has_everything) | ||||
|         ret = CollectionState(self.world) | ||||
|         ret.prog_items = copy.copy(self.prog_items) | ||||
|         ret.region_cache = copy.copy(self.region_cache) | ||||
|         ret.location_cache = copy.copy(self.location_cache) | ||||
|         ret.entrance_cache = copy.copy(self.entrance_cache) | ||||
|         ret.events = copy.copy(self.events) | ||||
|         return ret | ||||
| 
 | ||||
|     def can_reach(self, spot, resolution_hint=None): | ||||
|  | @ -233,45 +270,24 @@ class CollectionState(object): | |||
|             return can_reach | ||||
|         return correct_cache[spot] | ||||
| 
 | ||||
|     def can_collect(self, item, count=None): | ||||
|         if isinstance(item, Item): | ||||
|             item = item.name | ||||
|         if count is None: | ||||
|             cached = self.world._item_cache.get(item, None) | ||||
|             if cached is None: | ||||
|                 candidates = self.world.find_items(item) | ||||
|                 if not candidates: | ||||
|                     return False | ||||
|                 elif len(candidates) == 1: | ||||
|                     cached = candidates[0] | ||||
|                     self.world._item_cache[item] = cached | ||||
|                 else: | ||||
|                     # this should probably not happen, wonky item distribution? | ||||
|                     return self._can_reach_n(self.world.find_items(item), 1) | ||||
|             return self.can_reach(cached) | ||||
|     def sweep_for_events(self, key_only=False): | ||||
|         # this may need improvement | ||||
|         new_locations = True | ||||
|         checked_locations = 0 | ||||
|         while new_locations: | ||||
|             reachable_events = [location for location in self.world.get_filled_locations() if location.event and (not key_only or location.item.key) and self.can_reach(location)] | ||||
|             for event in reachable_events: | ||||
|                 if event.name not in self.events: | ||||
|                     self.events.append(event.name) | ||||
|                     self.collect(event.item, True) | ||||
|             new_locations = len(reachable_events) > checked_locations | ||||
|             checked_locations = len(reachable_events) | ||||
| 
 | ||||
|         return self._can_reach_n(self.world.find_items(item), count) | ||||
| 
 | ||||
|     def _can_reach_n(self, candidates, count): | ||||
|         maxfail = len(candidates) - count | ||||
|         fail = 0 | ||||
|         success = 0 | ||||
|         for candidate in candidates: | ||||
|             if self.can_reach(candidate): | ||||
|                 success += 1 | ||||
|             else: | ||||
|                 fail += 1 | ||||
|             if fail > maxfail: | ||||
|                 return False | ||||
|             if success >= count: | ||||
|                 return True | ||||
|         return False | ||||
| 
 | ||||
|     def has(self, item): | ||||
|         if self.has_everything: | ||||
|             return True | ||||
|         else: | ||||
|     def has(self, item, count=1): | ||||
|         if count == 1: | ||||
|             return item in self.prog_items | ||||
|         else: | ||||
|             return len([pritem for pritem in self.prog_items if pritem == item]) >= count | ||||
| 
 | ||||
|     def can_lift_rocks(self): | ||||
|         return self.has('Power Glove') or self.has('Titans Mitts') | ||||
|  | @ -306,7 +322,7 @@ class CollectionState(object): | |||
|     def has_turtle_rock_medallion(self): | ||||
|         return self.has(self.world.required_medallions[1]) | ||||
| 
 | ||||
|     def collect(self, item): | ||||
|     def collect(self, item, event=False): | ||||
|         changed = False | ||||
|         if item.name.startswith('Progressive '): | ||||
|             if 'Sword' in item.name: | ||||
|  | @ -334,12 +350,15 @@ class CollectionState(object): | |||
|                     self.prog_items.append('Power Glove') | ||||
|                     changed = True | ||||
| 
 | ||||
|         elif item.advancement: | ||||
|         elif event or item.advancement: | ||||
|             self.prog_items.append(item.name) | ||||
|             changed = True | ||||
| 
 | ||||
|         if changed: | ||||
|             self._clear_cache() | ||||
|             if not event: | ||||
|                 self.sweep_for_events() | ||||
|                 self._clear_cache() | ||||
| 
 | ||||
|     def remove(self, item): | ||||
|         if item.advancement: | ||||
|  | @ -456,6 +475,7 @@ class Location(object): | |||
|         self.hint_text = hint_text if hint_text is not None else 'Hyrule' | ||||
|         self.recursion_count = 0 | ||||
|         self.staleness_count = 0 | ||||
|         self.event = False | ||||
| 
 | ||||
|     def access_rule(self, state): | ||||
|         return True | ||||
|  |  | |||
|  | @ -20,15 +20,18 @@ def fill_dungeons(world): | |||
| 
 | ||||
|     freebes = ['[dungeon-A2-1F] Ganons Tower - Map Room', '[dungeon-D1-1F] Dark Palace - Spike Statue Room', '[dungeon-D1-1F] Dark Palace - Big Key Room'] | ||||
| 
 | ||||
|     all_state_base = world.get_all_state() | ||||
| 
 | ||||
|     # this key is in a fixed location (for now) | ||||
|     world.push_item(world.get_location('[dungeon-D3-B1] Skull Woods - South of Big Chest'), ItemFactory('Small Key (Skull Woods)'), False) | ||||
|     world.get_location('[dungeon-D3-B1] Skull Woods - South of Big Chest').event = True | ||||
| 
 | ||||
|     for dungeon_regions, big_key, small_keys, dungeon_items in [TR, ES, EP, DP, ToH, AT, PoD, TT, SW, SP, IP, MM, GT]: | ||||
|         # this is what we need to fill | ||||
|         dungeon_locations = [location for location in world.get_unfilled_locations() if location.parent_region.name in dungeon_regions] | ||||
|         random.shuffle(dungeon_locations) | ||||
| 
 | ||||
|         all_state = CollectionState(world, True) | ||||
|         all_state = all_state_base.copy() | ||||
| 
 | ||||
|         # first place big key | ||||
|         if big_key is not None: | ||||
|  | @ -42,11 +45,13 @@ def fill_dungeons(world): | |||
|                 raise RuntimeError('No suitable location for %s' % big_key) | ||||
| 
 | ||||
|             world.push_item(bk_location, big_key, False) | ||||
|             bk_location.event = True | ||||
|             dungeon_locations.remove(bk_location) | ||||
|             all_state._clear_cache() | ||||
| 
 | ||||
|         # next place small keys | ||||
|         for small_key in small_keys: | ||||
|             all_state.sweep_for_events() | ||||
|             sk_location = None | ||||
|             for location in dungeon_locations: | ||||
|                 if location.name in freebes or location.can_reach(all_state): | ||||
|  | @ -57,6 +62,7 @@ def fill_dungeons(world): | |||
|                 raise RuntimeError('No suitable location for %s' % small_key) | ||||
| 
 | ||||
|             world.push_item(sk_location, small_key, False) | ||||
|             sk_location.event = True | ||||
|             dungeon_locations.remove(sk_location) | ||||
|             all_state._clear_cache() | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										4
									
								
								Items.py
								
								
								
								
							
							
						
						
									
										4
									
								
								Items.py
								
								
								
								
							|  | @ -155,4 +155,6 @@ item_table = {'Bow': (True, False, False, False, 0x0B, 'You have\nchosen the\nar | |||
|               'Big Key (Ganons Tower)': (False, False, True, False, 0x32, None, None, None, None, None, None), | ||||
|               'Compass (Ganons Tower)': (False, True, False, False, 0x25, None, None, None, None, None, None), | ||||
|               'Map (Ganons Tower)': (False, True, False, False, 0x33, None, None, None, None, None, None), | ||||
|               'Nothing': (False, False, False, False, 0x5A, 'Some Hot Air', None, None, None, None, None)} | ||||
|               'Nothing': (False, False, False, False, 0x5A, 'Some Hot Air', None, None, None, None, None), | ||||
|               'Beat Agahnim 1': (True, False, False, False, None, None, None, None, None, None, None), | ||||
|               'Beat Agahnim 2': (True, False, False, False, None, None, None, None, None, None, None)} | ||||
|  |  | |||
							
								
								
									
										11
									
								
								Main.py
								
								
								
								
							
							
						
						
									
										11
									
								
								Main.py
								
								
								
								
							|  | @ -309,6 +309,10 @@ def generate_itempool(world): | |||
|         raise NotImplementedError('Not supported yet') | ||||
| 
 | ||||
|     world.push_item('Ganon', ItemFactory('Triforce'), False) | ||||
|     world.push_item('Agahnim 1', ItemFactory('Beat Agahnim 1'), False) | ||||
|     world.get_location('Agahnim 1').event = True | ||||
|     world.push_item('Agahnim 2', ItemFactory('Beat Agahnim 2'), False) | ||||
|     world.get_location('Agahnim 2').event = True | ||||
| 
 | ||||
|     # set up item pool | ||||
|     if world.difficulty in ['timed', 'timed-countdown']: | ||||
|  | @ -380,6 +384,7 @@ def generate_itempool(world): | |||
|     random.shuffle(crystals) | ||||
|     for location, crystal in zip(crystal_locations, crystals): | ||||
|         world.push_item(location, crystal, False) | ||||
|         location.event = True | ||||
| 
 | ||||
|     # shuffle medallions | ||||
|     mm_medallion = ['Ether', 'Quake', 'Bombos'][random.randint(0, 2)] | ||||
|  | @ -418,6 +423,8 @@ def copy_world(world): | |||
|             item = Item(location.item.name, location.item.advancement, location.item.priority, location.item.key) | ||||
|             ret.get_location(location.name).item = item | ||||
|             item.location = ret.get_location(location.name) | ||||
|         if location.event: | ||||
|             ret.get_location(location.name).event = True | ||||
| 
 | ||||
|     # copy remaining itempool. No item in itempool should have an assigned location | ||||
|     for item in world.itempool: | ||||
|  | @ -454,7 +461,9 @@ def create_playthrough(world): | |||
| 
 | ||||
|         for location in sphere: | ||||
|             sphere_candidates.remove(location) | ||||
|             state.collect(location.item) | ||||
|             state.collect(location.item, True) | ||||
| 
 | ||||
|         state.sweep_for_events(key_only=True) | ||||
| 
 | ||||
|         collection_spheres.append(sphere) | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										10
									
								
								Regions.py
								
								
								
								
							
							
						
						
									
										10
									
								
								Regions.py
								
								
								
								
							|  | @ -13,7 +13,7 @@ def create_regions(world): | |||
|                        'Sanctuary', 'Sanctuary Grave', 'Old Man Cave (West)', 'Flute Spot 1', 'Dark Desert Teleporter', '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)', 'Waterfall of Wishing', | ||||
|                        'Bonk Fairy (Light)', '50 Rupee Cave', 'Fortune Teller (Light)', 'Lake Hylia Fairy', 'Swamp Fairy', 'Desert Fairy', 'Lumberjack House', 'Lake Hylia Fortune Teller', 'Kakariko Gamble Game']), | ||||
|                        'Bonk Fairy (Light)', '50 Rupee Cave', 'Fortune Teller (Light)', 'Lake Hylia Fairy', 'Swamp Fairy', 'Desert Fairy', 'Lumberjack House', 'Lake Hylia Fortune Teller', 'Kakariko Gamble Game', 'Top of Pyramid']), | ||||
|         create_region('Lake Hylia Central Island', None, ['Capacity Upgrade', 'Lake Hylia Central Island Teleporter']), | ||||
|         create_region('Thiefs Hut', ["[cave-022-B1] Thiefs hut [top chest]", | ||||
|                                      "[cave-022-B1] Thiefs hut [top left chest]", | ||||
|  | @ -96,7 +96,7 @@ def create_regions(world): | |||
|                                  '[dungeon-C-B1] Escape - Final Basement Room [right chest]'], ['Sanctuary Push Door', 'Sewers Back Door']), | ||||
|         create_region('Sanctuary', ['[dungeon-C-1F] Sanctuary'], ['Sanctuary Exit']), | ||||
|         create_region('Agahnims Tower', ['[dungeon-A1-2F] Hyrule Castle Tower - 2 Knife Guys Room', '[dungeon-A1-3F] Hyrule Castle Tower - Maze Room'], ['Agahnim 1', 'Agahnims Tower Exit']), | ||||
|         create_region('Agahnim 1', None, ['Top of Pyramid']), | ||||
|         create_region('Agahnim 1', ['Agahnim 1'], None), | ||||
|         create_region('Old Man Cave', ['Old Mountain Man'], ['Old Man Cave Exit (East)', 'Old Man Cave Exit (West)']), | ||||
|         create_region('Old Man House', None, ['Old Man House Exit (Bottom)', 'Old Man House Front to Back']), | ||||
|         create_region('Old Man House Back', None, ['Old Man House Exit (Top)', 'Old Man House Back to Front']), | ||||
|  | @ -132,7 +132,7 @@ def create_regions(world): | |||
|         create_region('Tower of Hera (Top)', ['[dungeon-L3-1F] Tower of Hera - 4F [small chest]', '[dungeon-L3-1F] Tower of Hera - Big Chest', 'Moldorm - Heart Container', 'Moldorm - Pendant']), | ||||
| 
 | ||||
|         create_region('East Dark World', ['Piece of Heart (Pyramid)', 'Catfish'], ['Pyramid Fairy', 'South Dark World Bridge', 'West Dark World Gap', 'Palace of Darkness Pay Kiki', 'Dark Lake Hylia Drop (East)', 'Dark Lake Hylia Teleporter', | ||||
|                                                                                    'Hyrule Castle Ledge Mirror Spot', 'Dark Lake Hylia Fairy', 'Palace of Darkness Hint', 'East Dark World Hint', 'Dark World Potion Shop']), | ||||
|                                                                                    'Hyrule Castle Ledge Mirror Spot', 'Dark Lake Hylia Fairy', 'Palace of Darkness Hint', 'East Dark World Hint', 'Dark World Potion Shop', 'Pyramid Hole']), | ||||
|         create_region('Palace of Darkness Kiki Door', None, ['Palace of Darkness', 'Palace of Darkness Kiki Door Reverse']), | ||||
|         create_region('Palace of Darkness Hint'), | ||||
|         create_region('East Dark World Hint'), | ||||
|  | @ -262,7 +262,7 @@ def create_regions(world): | |||
|         create_region('Ganons Tower (Before Moldorm)', ['[dungeon-A2-6F] Ganons Tower - Mini Helmasaur Room [left chest]', '[dungeon-A2-6F] Ganons Tower - Mini Helmasaur Room [right chest]', | ||||
|                                                         '[dungeon-A2-6F] Ganons Tower - Room before Moldorm'], ['Ganons Tower Moldorm Door']), | ||||
|         create_region('Ganons Tower (Moldorm)', None, ['Ganons Tower Moldorm Gap']), | ||||
|         create_region('Agahnim 2', ['[dungeon-A2-6F] Ganons Tower - Moldorm Room'], ['Pyramid Hole']), | ||||
|         create_region('Agahnim 2', ['[dungeon-A2-6F] Ganons Tower - Moldorm Room', 'Agahnim 2'], None), | ||||
|         create_region('Pyramid', ['Ganon'], ['Ganon Drop']), | ||||
|         create_region('Bottom of Pyramid', None, ['Pyramid Exit']), | ||||
|         create_region('Pyramid Ledge', None, ['Pyramid Entrance', 'Pyramid Drop']) | ||||
|  | @ -499,6 +499,8 @@ location_table = {'Mushroom': (0x180013, False, 'in the woods'), | |||
|                   '[dungeon-A2-6F] Ganons Tower - Room before Moldorm': (0xEB03, False, 'atop My Tower'), | ||||
|                   '[dungeon-A2-6F] Ganons Tower - Moldorm Room': (0xEB06, False, 'atop My Tower'), | ||||
|                   'Ganon': (None, False, 'from me'), | ||||
|                   'Agahnim 1': (None, False, 'from my wizardry from'), | ||||
|                   'Agahnim 2': (None, False, 'from my wizardry from'), | ||||
|                   'Armos - Pendant': ([0x1209D, 0x53EF8, 0x53EF9, 0x180052, 0x18007C, 0xC6FE], True, 'Eastern Palace'), | ||||
|                   'Lanmolas - Pendant': ([0x1209E, 0x53F1C, 0x53F1D, 0x180053, 0x180078, 0xC6FF], True, 'Desert Palace'), | ||||
|                   'Moldorm - Pendant': ([0x120A5, 0x53F0A, 0x53F0B, 0x18005A, 0x18007A, 0xC706], True, 'Tower of Hera'), | ||||
|  |  | |||
							
								
								
									
										7
									
								
								Rom.py
								
								
								
								
							
							
						
						
									
										7
									
								
								Rom.py
								
								
								
								
							|  | @ -14,12 +14,11 @@ RANDOMIZERBASEHASH = 'd5b61947feef1972e0f546ba43180e62' | |||
| def patch_rom(world, rom, hashtable, quickswap=False, beep='normal', sprite=None): | ||||
|     # patch items | ||||
|     for location in world.get_locations(): | ||||
|         if location.name == 'Ganon': | ||||
|             # cannot shuffle this yet | ||||
|             continue | ||||
| 
 | ||||
|         itemid = location.item.code if location.item is not None else 0x5A | ||||
| 
 | ||||
|         if itemid is None or location.address is None: | ||||
|             continue | ||||
| 
 | ||||
|         locationaddress = location.address | ||||
|         if not location.crystal: | ||||
|             # regular items | ||||
|  |  | |||
							
								
								
									
										112
									
								
								Rules.py
								
								
								
								
							
							
						
						
									
										112
									
								
								Rules.py
								
								
								
								
							|  | @ -69,7 +69,7 @@ def global_rules(world): | |||
|     set_rule(world.get_entrance('Bonk Fairy (Light)'), lambda state: state.has_Boots()) | ||||
|     set_rule(world.get_location('Piece of Heart (Dam)'), lambda state: state.can_reach('Dam')) | ||||
|     set_rule(world.get_entrance('Bat Cave Drop Ledge'), lambda state: state.has('Hammer')) | ||||
|     set_rule(world.get_entrance('Lumberjack Tree Tree'), lambda state: state.has_Boots() and state.can_reach('Top of Pyramid', 'Entrance')) | ||||
|     set_rule(world.get_entrance('Lumberjack Tree Tree'), lambda state: state.has_Boots() and state.has('Beat Agahnim 1')) | ||||
|     set_rule(world.get_entrance('Bonk Rock Cave'), lambda state: state.has_Boots()) | ||||
|     set_rule(world.get_entrance('Desert Palace Stairs'), lambda state: state.has('Book of Mudora')) | ||||
|     set_rule(world.get_entrance('Sanctuary Grave'), lambda state: state.can_lift_rocks()) | ||||
|  | @ -95,10 +95,11 @@ def global_rules(world): | |||
|     set_rule(world.get_entrance('Desert Palace Entrance (North) Rocks'), lambda state: state.can_lift_rocks()) | ||||
|     set_rule(world.get_entrance('Desert Ledge Return Rocks'), lambda state: state.can_lift_rocks())  # should we decide to place something that is not a dungeon end up there at some point | ||||
|     set_rule(world.get_entrance('Checkerboard Cave'), lambda state: state.can_lift_rocks()) | ||||
|     set_rule(world.get_location('Altar'), lambda state: state.can_collect('Red Pendant') and state.can_collect('Blue Pendant') and state.can_collect('Green Pendant')) | ||||
|     set_rule(world.get_location('Sahasrahla'), lambda state: state.can_collect('Green Pendant')) | ||||
|     set_rule(world.get_location('Altar'), lambda state: state.has('Red Pendant') and state.has('Blue Pendant') and state.has('Green Pendant')) | ||||
|     set_rule(world.get_location('Sahasrahla'), lambda state: state.has('Green Pendant')) | ||||
|     set_rule(world.get_entrance('Agahnims Tower'), lambda state: state.has('Cape') or state.has_beam_sword() or state.can_reach('Agahnim 1'))  # barrier gets removed after killing agahnim, relevant for entrance shuffle | ||||
|     set_rule(world.get_entrance('Agahnim 1'), lambda state: state.has_sword()) | ||||
|     set_rule(world.get_entrance('Top of Pyramid'), lambda state: state.has('Beat Agahnim 1')) | ||||
|     set_rule(world.get_entrance('Old Man Cave Exit (West)'), lambda state: False)  # drop cannott be climbed up | ||||
|     set_rule(world.get_entrance('Broken Bridge (West)'), lambda state: state.has('Hookshot')) | ||||
|     set_rule(world.get_entrance('Broken Bridge (East)'), lambda state: state.has('Hookshot')) | ||||
|  | @ -160,7 +161,7 @@ def global_rules(world): | |||
|     set_rule(world.get_entrance('Spike Cave'), lambda state: state.has_Pearl()) | ||||
|     set_rule(world.get_entrance('Dark Death Mountain Fairy'), lambda state: state.has_Pearl()) | ||||
|     set_rule(world.get_entrance('Spectacle Rock Mirror Spot'), lambda state: state.has_Mirror()) | ||||
|     set_rule(world.get_entrance('Ganons Tower'), lambda state: state.can_collect('Crystal 1') and state.can_collect('Crystal 2') and state.can_collect('Crystal 3') and state.can_collect('Crystal 4') and state.can_collect('Crystal 5') and state.can_collect('Crystal 6') and state.can_collect('Crystal 7')) | ||||
|     set_rule(world.get_entrance('Ganons Tower'), lambda state: state.has('Crystal 1') and state.has('Crystal 2') and state.has('Crystal 3') and state.has('Crystal 4') and state.has('Crystal 5') and state.has('Crystal 6') and state.has('Crystal 7')) | ||||
|     set_rule(world.get_entrance('Hookshot Cave'), lambda state: state.can_lift_rocks() and state.has_Pearl()) | ||||
|     set_rule(world.get_entrance('East Death Mountain (Top) Mirror Spot'), lambda state: state.has_Mirror()) | ||||
|     set_rule(world.get_entrance('Mimic Cave Mirror Spot'), lambda state: state.has_Mirror()) | ||||
|  | @ -180,28 +181,28 @@ def global_rules(world): | |||
|     set_rule(world.get_entrance('Turtle Rock'), lambda state: state.has_Pearl() and state.has_sword() and state.has_turtle_rock_medallion())  # sword required to cast magic (!) | ||||
|     set_rule(world.get_location('[cave-013] Mimic Cave'), lambda state: state.has('Hammer')) | ||||
| 
 | ||||
|     set_rule(world.get_entrance('Sewers Door'), lambda state: state.can_collect('Small Key (Escape)')) | ||||
|     set_rule(world.get_entrance('Sewers Back Door'), lambda state: state.can_collect('Small Key (Escape)')) | ||||
|     set_rule(world.get_entrance('Sewers Door'), lambda state: state.has('Small Key (Escape)')) | ||||
|     set_rule(world.get_entrance('Sewers Back Door'), lambda state: state.has('Small Key (Escape)')) | ||||
| 
 | ||||
|     set_rule(world.get_location('[dungeon-L1-1F] Eastern Palace - Big Chest'), lambda state: state.can_collect('Big Key (Eastern Palace)')) | ||||
|     set_rule(world.get_location('Armos - Heart Container'), lambda state: state.has('Bow') and state.can_collect('Big Key (Eastern Palace)')) | ||||
|     set_rule(world.get_location('Armos - Pendant'), lambda state: state.has('Bow') and state.can_collect('Big Key (Eastern Palace)')) | ||||
|     set_rule(world.get_location('[dungeon-L1-1F] Eastern Palace - Big Chest'), lambda state: state.has('Big Key (Eastern Palace)')) | ||||
|     set_rule(world.get_location('Armos - Heart Container'), lambda state: state.has('Bow') and state.has('Big Key (Eastern Palace)')) | ||||
|     set_rule(world.get_location('Armos - Pendant'), lambda state: state.has('Bow') and state.has('Big Key (Eastern Palace)')) | ||||
|     for location in ['Armos - Heart Container', '[dungeon-L1-1F] Eastern Palace - Big Chest']: | ||||
|         forbid_item(world.get_location(location), 'Big Key (Eastern Palace)') | ||||
| 
 | ||||
|     set_rule(world.get_location('[dungeon-L2-B1] Desert Palace - Big Chest'), lambda state: state.can_collect('Big Key (Desert Palace)')) | ||||
|     set_rule(world.get_location('[dungeon-L2-B1] Desert Palace - Big Chest'), lambda state: state.has('Big Key (Desert Palace)')) | ||||
|     set_rule(world.get_location('[dungeon-L2-B1] Desert Palace - Torch'), lambda state: state.has_Boots()) | ||||
|     set_rule(world.get_entrance('Desert Palace East Wing'), lambda state: state.can_collect('Small Key (Desert Palace)')) | ||||
|     set_rule(world.get_location('Lanmolas - Pendant'), lambda state: state.can_collect('Small Key (Desert Palace)') and state.can_collect('Big Key (Desert Palace)') and state.has_fire_source() and | ||||
|     set_rule(world.get_entrance('Desert Palace East Wing'), lambda state: state.has('Small Key (Desert Palace)')) | ||||
|     set_rule(world.get_location('Lanmolas - Pendant'), lambda state: state.has('Small Key (Desert Palace)') and state.has('Big Key (Desert Palace)') and state.has_fire_source() and | ||||
|                                                                      (state.has_blunt_weapon() or state.has('Fire Rod') or state.has('Ice Rod') or state.has('Bow'))) | ||||
|     set_rule(world.get_location('Lanmolas - Heart Container'), lambda state: state.can_collect('Small Key (Desert Palace)') and state.can_collect('Big Key (Desert Palace)') and state.has_fire_source() and | ||||
|     set_rule(world.get_location('Lanmolas - Heart Container'), lambda state: state.has('Small Key (Desert Palace)') and state.has('Big Key (Desert Palace)') and state.has_fire_source() and | ||||
|                                                                      (state.has_blunt_weapon() or state.has('Fire Rod') or state.has('Ice Rod') or state.has('Bow'))) | ||||
|     for location in ['Lanmolas - Heart Container', '[dungeon-L2-B1] Desert Palace - Big Chest']: | ||||
|         forbid_item(world.get_location(location), 'Big Key (Desert Palace)') | ||||
| 
 | ||||
|     set_rule(world.get_entrance('Tower of Hera Small Key Door'), lambda state: state.can_collect('Small Key (Tower of Hera)')) | ||||
|     set_rule(world.get_entrance('Tower of Hera Big Key Door'), lambda state: state.can_collect('Big Key (Tower of Hera)')) | ||||
|     set_rule(world.get_location('[dungeon-L3-1F] Tower of Hera - Big Chest'), lambda state: state.can_collect('Big Key (Tower of Hera)')) | ||||
|     set_rule(world.get_entrance('Tower of Hera Small Key Door'), lambda state: state.has('Small Key (Tower of Hera)')) | ||||
|     set_rule(world.get_entrance('Tower of Hera Big Key Door'), lambda state: state.has('Big Key (Tower of Hera)')) | ||||
|     set_rule(world.get_location('[dungeon-L3-1F] Tower of Hera - Big Chest'), lambda state: state.has('Big Key (Tower of Hera)')) | ||||
|     set_rule(world.get_location('[dungeon-L3-1F] Tower of Hera - Basement'), lambda state: state.has_fire_source()) | ||||
|     set_rule(world.get_location('Moldorm - Heart Container'), lambda state: state.has_blunt_weapon()) | ||||
|     set_rule(world.get_location('Moldorm - Pendant'), lambda state: state.has_blunt_weapon()) | ||||
|  | @ -209,31 +210,31 @@ def global_rules(world): | |||
|         forbid_item(world.get_location(location), 'Big Key (Tower of Hera)') | ||||
| 
 | ||||
|     set_rule(world.get_entrance('Swamp Palace Moat'), lambda state: state.has('Flippers') and state.can_reach('Dam')) | ||||
|     set_rule(world.get_entrance('Swamp Palace Small Key Door'), lambda state: state.can_collect('Small Key (Swamp Palace)')) | ||||
|     set_rule(world.get_entrance('Swamp Palace Small Key Door'), lambda state: state.has('Small Key (Swamp Palace)')) | ||||
|     set_rule(world.get_entrance('Swamp Palace (Center)'), lambda state: state.has('Hammer')) | ||||
|     set_rule(world.get_location('[dungeon-D2-B1] Swamp Palace - Big Chest'), lambda state: state.can_collect('Big Key (Swamp Palace)')) | ||||
|     set_rule(world.get_location('[dungeon-D2-B1] Swamp Palace - Big Chest'), lambda state: state.has('Big Key (Swamp Palace)')) | ||||
|     set_rule(world.get_entrance('Swamp Palace (North)'), lambda state: state.has('Hookshot')) | ||||
|     set_rule(world.get_location('Arrghus - Heart Container'), lambda state: state.has_blunt_weapon()) | ||||
|     set_rule(world.get_location('Arrghus - Crystal'), lambda state: state.has_blunt_weapon()) | ||||
|     for location in ['[dungeon-D2-B1] Swamp Palace - Big Chest', '[dungeon-D2-1F] Swamp Palace - First Room']: | ||||
|         forbid_item(world.get_location(location), 'Big Key (Swamp Palace)') | ||||
| 
 | ||||
|     set_rule(world.get_entrance('Thieves Town Big Key Door'), lambda state: state.can_collect('Big Key (Thieves Town)')) | ||||
|     set_rule(world.get_entrance('Blind Fight'), lambda state: state.can_collect('Small Key (Thieves Town)') and (state.has_blunt_weapon() or state.has('Cane of Somaria'))) | ||||
|     set_rule(world.get_location('[dungeon-D4-B2] Thieves Town - Big Chest'), lambda state: state.can_collect('Small Key (Thieves Town)') and state.has('Hammer')) | ||||
|     set_rule(world.get_location('[dungeon-D4-1F] Thieves Town - Room above Boss'), lambda state: state.can_collect('Small Key (Thieves Town)')) | ||||
|     set_rule(world.get_entrance('Thieves Town Big Key Door'), lambda state: state.has('Big Key (Thieves Town)')) | ||||
|     set_rule(world.get_entrance('Blind Fight'), lambda state: state.has('Small Key (Thieves Town)') and (state.has_blunt_weapon() or state.has('Cane of Somaria'))) | ||||
|     set_rule(world.get_location('[dungeon-D4-B2] Thieves Town - Big Chest'), lambda state: state.has('Small Key (Thieves Town)') and state.has('Hammer')) | ||||
|     set_rule(world.get_location('[dungeon-D4-1F] Thieves Town - Room above Boss'), lambda state: state.has('Small Key (Thieves Town)')) | ||||
|     for location in ['[dungeon-D4-1F] Thieves Town - Room above Boss', '[dungeon-D4-B2] Thieves Town - Big Chest', '[dungeon-D4-B2] Thieves Town - Chest next to Blind', 'Blind - Heart Container']: | ||||
|         forbid_item(world.get_location(location), 'Big Key (Thieves Town)') | ||||
| 
 | ||||
|     set_rule(world.get_location('[dungeon-D3-B1] Skull Woods - Big Chest'), lambda state: state.can_collect('Big Key (Skull Woods)')) | ||||
|     set_rule(world.get_entrance('Skull Woods Torch Room'), lambda state: state.can_collect('Small Key (Skull Woods)', 3) and state.has('Fire Rod') and state.has_sword())  # sword required for curtain | ||||
|     set_rule(world.get_location('[dungeon-D3-B1] Skull Woods - Big Chest'), lambda state: state.has('Big Key (Skull Woods)')) | ||||
|     set_rule(world.get_entrance('Skull Woods Torch Room'), lambda state: state.has('Small Key (Skull Woods)', 3) and state.has('Fire Rod') and state.has_sword())  # sword required for curtain | ||||
|     for location in ['[dungeon-D3-B1] Skull Woods - Big Chest']: | ||||
|         forbid_item(world.get_location(location), 'Big Key (Skull Woods)') | ||||
| 
 | ||||
|     set_rule(world.get_entrance('Ice Palace Entrance Room'), lambda state: state.has('Fire Rod') or (state.has('Bombos') and state.has_sword())) | ||||
|     set_rule(world.get_location('[dungeon-D5-B5] Ice Palace - Big Chest'), lambda state: state.can_collect('Big Key (Ice Palace)')) | ||||
|     set_rule(world.get_entrance('Ice Palace (Kholdstare)'), lambda state: state.can_lift_rocks() and state.has('Hammer') and state.can_collect('Big Key (Ice Palace)') and (state.can_collect('Small Key (Ice Palace)', 2) or (state.has('Cane of Somaria') and state.can_collect('Small Key (Ice Palace)', 1)))) | ||||
|     set_rule(world.get_entrance('Ice Palace (East)'), lambda state: state.has('Hookshot') or (state.can_collect('Small Key (Ice Palace)', 1) and ((state.world.get_location('[dungeon-D5-B3] Ice Palace - Spike Room').item is not None and state.world.get_location('[dungeon-D5-B3] Ice Palace - Spike Room').item.name in ['Big Key (Ice Palace)']) or | ||||
|     set_rule(world.get_location('[dungeon-D5-B5] Ice Palace - Big Chest'), lambda state: state.has('Big Key (Ice Palace)')) | ||||
|     set_rule(world.get_entrance('Ice Palace (Kholdstare)'), lambda state: state.can_lift_rocks() and state.has('Hammer') and state.has('Big Key (Ice Palace)') and (state.has('Small Key (Ice Palace)', 2) or (state.has('Cane of Somaria') and state.has('Small Key (Ice Palace)', 1)))) | ||||
|     set_rule(world.get_entrance('Ice Palace (East)'), lambda state: state.has('Hookshot') or (state.has('Small Key (Ice Palace)', 1) and ((state.world.get_location('[dungeon-D5-B3] Ice Palace - Spike Room').item is not None and state.world.get_location('[dungeon-D5-B3] Ice Palace - Spike Room').item.name in ['Big Key (Ice Palace)']) or | ||||
|                                                                                                                                                   (state.world.get_location('[dungeon-D5-B1] Ice Palace - Big Key Room').item is not None and state.world.get_location('[dungeon-D5-B1] Ice Palace - Big Key Room').item.name in ['Big Key (Ice Palace)']) or | ||||
|                                                                                                                                                   (state.world.get_location('[dungeon-D5-B2] Ice Palace - Map Room').item is not None and state.world.get_location('[dungeon-D5-B2] Ice Palace - Map Room').item.name in ['Big Key (Ice Palace)']))))  # if you do ipbj and waste SKs in the basement, you have to BJ over the hookshot room to fix your mess potentially. This seems fair | ||||
|     set_rule(world.get_entrance('Ice Palace (East Top)'), lambda state: state.can_lift_rocks() and state.has('Hammer')) | ||||
|  | @ -241,13 +242,13 @@ def global_rules(world): | |||
|         forbid_item(world.get_location(location), 'Big Key (Ice Palace)') | ||||
| 
 | ||||
|     set_rule(world.get_entrance('Misery Mire Entrance Gap'), lambda state: (state.has_Boots() or state.has('Hookshot')) and (state.has_sword() or state.has('Fire Rod') or state.has('Ice Rod') or state.has('Hammer') or state.has('Cane of Somaria') or state.has('Bow')))  # need to defeat wizzrobes, bombs don't work ... | ||||
|     set_rule(world.get_location('[dungeon-D6-B1] Misery Mire - Big Chest'), lambda state: state.can_collect('Big Key (Misery Mire)')) | ||||
|     set_rule(world.get_entrance('Misery Mire Big Key Door'), lambda state: state.can_collect('Big Key (Misery Mire)')) | ||||
|     set_rule(world.get_location('[dungeon-D6-B1] Misery Mire - Big Chest'), lambda state: state.has('Big Key (Misery Mire)')) | ||||
|     set_rule(world.get_entrance('Misery Mire Big Key Door'), lambda state: state.has('Big Key (Misery Mire)')) | ||||
|     # you can squander the free small key from the pot by opening the south door to the north west switch room, locking you out of accessing a color switch ... | ||||
|     set_rule(world.get_location('[dungeon-D6-B1] Misery Mire - Hub Room'), lambda state: state.can_collect('Small Key (Misery Mire)', 1) or state.can_collect('Big Key (Misery Mire)')) | ||||
|     set_rule(world.get_location('[dungeon-D6-B1] Misery Mire - Map Room'), lambda state: state.can_collect('Small Key (Misery Mire)', 1) or state.can_collect('Big Key (Misery Mire)')) | ||||
|     set_rule(world.get_location('[dungeon-D6-B1] Misery Mire - Hub Room'), lambda state: state.has('Small Key (Misery Mire)', 1) or state.has('Big Key (Misery Mire)')) | ||||
|     set_rule(world.get_location('[dungeon-D6-B1] Misery Mire - Map Room'), lambda state: state.has('Small Key (Misery Mire)', 1) or state.has('Big Key (Misery Mire)')) | ||||
|     # we can place a small key in the West wing iff it also contains/blocks the Big Key, as we cannot reach and softlock with the basement key door yet | ||||
|     set_rule(world.get_entrance('Misery Mire (West)'), lambda state: state.can_collect('Small Key (Misery Mire)', 3) if state.can_reach('Misery Mire (Final Area)') else state.can_collect('Small Key (Misery Mire)', 2)) | ||||
|     set_rule(world.get_entrance('Misery Mire (West)'), lambda state: state.has('Small Key (Misery Mire)', 3) if state.can_reach('Misery Mire (Final Area)') else state.has('Small Key (Misery Mire)', 2)) | ||||
|     set_rule(world.get_location('[dungeon-D6-B1] Misery Mire - Compass Room'), lambda state: state.has_fire_source()) | ||||
|     set_rule(world.get_location('[dungeon-D6-B1] Misery Mire - Big Key Room'), lambda state: state.has_fire_source()) | ||||
|     set_rule(world.get_entrance('Misery Mire (Vitreous)'), lambda state: state.has('Cane of Somaria') and (state.has('Bow') or state.has_blunt_weapon())) | ||||
|  | @ -260,16 +261,16 @@ def global_rules(world): | |||
|     set_rule(world.get_location('[dungeon-D7-1F] Turtle Rock - Compass Room'), lambda state: state.has('Cane of Somaria'))  # We could get here from the middle section without Cane as we don't cross the entrance gap! | ||||
|     set_rule(world.get_location('[dungeon-D7-1F] Turtle Rock - Map Room [left chest]'), lambda state: state.has('Cane of Somaria') and state.has('Fire Rod')) | ||||
|     set_rule(world.get_location('[dungeon-D7-1F] Turtle Rock - Map Room [right chest]'), lambda state: state.has('Cane of Somaria') and state.has('Fire Rod')) | ||||
|     set_rule(world.get_entrance('Turtle Rock Pokey Room'), lambda state: state.can_collect('Small Key (Turtle Rock)', 3) if state.can_reach('Turtle Rock (Dark Room) (North)', 'Entrance') else state.can_collect('Small Key (Turtle Rock)', 2) if state.can_reach('Turtle Rock (Eye Bridge)') else state.can_collect('Small Key (Turtle Rock)', 1))  # May waste keys from back entrance if accessible | ||||
|     set_rule(world.get_entrance('Turtle Rock (Chain Chomp Room) (South)'), lambda state: state.can_collect('Small Key (Turtle Rock)', 4))  # Just to be save | ||||
|     set_rule(world.get_entrance('Turtle Rock (Chain Chomp Room) (North)'), lambda state: state.can_collect('Small Key (Turtle Rock)', 4) if state.can_reach('Turtle Rock (Dark Room) (North)', 'Entrance') else state.can_collect('Small Key (Turtle Rock)', 3) if state.can_reach('Turtle Rock (Eye Bridge)') else state.can_collect('Small Key (Turtle Rock)', 2))  # May waste keys from back entrance if accessible | ||||
|     set_rule(world.get_location('[dungeon-D7-B1] Turtle Rock - Big Chest'), lambda state: state.can_collect('Big Key (Turtle Rock)') and (state.has('Cane of Somaria') or state.has('Hookshot'))) | ||||
|     set_rule(world.get_entrance('Turtle Rock Pokey Room'), lambda state: state.has('Small Key (Turtle Rock)', 3) if state.can_reach('Turtle Rock (Dark Room) (North)', 'Entrance') else state.has('Small Key (Turtle Rock)', 2) if state.can_reach('Turtle Rock (Eye Bridge)') else state.has('Small Key (Turtle Rock)', 1))  # May waste keys from back entrance if accessible | ||||
|     set_rule(world.get_entrance('Turtle Rock (Chain Chomp Room) (South)'), lambda state: state.has('Small Key (Turtle Rock)', 4))  # Just to be save | ||||
|     set_rule(world.get_entrance('Turtle Rock (Chain Chomp Room) (North)'), lambda state: state.has('Small Key (Turtle Rock)', 4) if state.can_reach('Turtle Rock (Dark Room) (North)', 'Entrance') else state.has('Small Key (Turtle Rock)', 3) if state.can_reach('Turtle Rock (Eye Bridge)') else state.has('Small Key (Turtle Rock)', 2))  # May waste keys from back entrance if accessible | ||||
|     set_rule(world.get_location('[dungeon-D7-B1] Turtle Rock - Big Chest'), lambda state: state.has('Big Key (Turtle Rock)') and (state.has('Cane of Somaria') or state.has('Hookshot'))) | ||||
|     set_rule(world.get_entrance('Turtle Rock (Big Chest) (North)'), lambda state: state.has('Cane of Somaria') or state.has('Hookshot')) | ||||
|     set_rule(world.get_entrance('Turtle Rock Big Key Door'), lambda state: state.can_collect('Big Key (Turtle Rock)')) | ||||
|     set_rule(world.get_entrance('Turtle Rock Dark Room Staircase'), lambda state: state.can_collect('Small Key (Turtle Rock)', 3)) | ||||
|     set_rule(world.get_entrance('Turtle Rock Big Key Door'), lambda state: state.has('Big Key (Turtle Rock)')) | ||||
|     set_rule(world.get_entrance('Turtle Rock Dark Room Staircase'), lambda state: state.has('Small Key (Turtle Rock)', 3)) | ||||
|     set_rule(world.get_entrance('Turtle Rock (Dark Room) (North)'), lambda state: state.has('Cane of Somaria')) | ||||
|     set_rule(world.get_entrance('Turtle Rock (Dark Room) (South)'), lambda state: state.has('Cane of Somaria')) | ||||
|     set_rule(world.get_entrance('Turtle Rock (Trinexx)'), lambda state: state.can_collect('Small Key (Turtle Rock)', 4) and state.can_collect('Big Key (Turtle Rock)') and | ||||
|     set_rule(world.get_entrance('Turtle Rock (Trinexx)'), lambda state: state.has('Small Key (Turtle Rock)', 4) and state.has('Big Key (Turtle Rock)') and | ||||
|                                                                         state.has('Cane of Somaria') and state.has('Fire Rod') and state.has('Ice Rod') and | ||||
|                                                                         (state.has('Hammer') or state.has_beam_sword() or state.has('Bottle') or state.has('Half Magic') or state.has('Quarter Magic'))) | ||||
|     for location in ['[dungeon-D7-B1] Turtle Rock - Big Chest', 'Trinexx - Heart Container', '[dungeon-D7-B1] Turtle Rock - Roller Switch Room', '[dungeon-D7-B2] Turtle Rock - Eye Bridge Room [bottom left chest]', | ||||
|  | @ -278,13 +279,13 @@ def global_rules(world): | |||
| 
 | ||||
|     set_rule(world.get_entrance('Dark Palace Bonk Wall'), lambda state: state.has('Bow')) | ||||
|     set_rule(world.get_entrance('Dark Palace Hammer Peg Drop'), lambda state: state.has('Hammer')) | ||||
|     set_rule(world.get_entrance('Dark Palace Bridge Room'), lambda state: state.can_collect('Small Key (Palace of Darkness)', 1))  # If we can reach any other small key door, we already have back door access to this area | ||||
|     set_rule(world.get_entrance('Dark Palace Big Key Door'), lambda state: state.can_collect('Small Key (Palace of Darkness)', 6) and state.can_collect('Big Key (Palace of Darkness)') and state.has('Bow') and state.has('Hammer')) | ||||
|     set_rule(world.get_entrance('Dark Palace Big Key Chest Staircase'), lambda state: state.can_collect('Small Key (Palace of Darkness)', 6) or (state.world.get_location('[dungeon-D1-1F] Dark Palace - Big Key Room').item is not None and (state.world.get_location('[dungeon-D1-1F] Dark Palace - Big Key Room').item.name in ['Small Key (Palace of Darkness)']))) | ||||
|     set_rule(world.get_entrance('Dark Palace Spike Statue Room Door'), lambda state: state.can_collect('Small Key (Palace of Darkness)', 6) or (state.world.get_location('[dungeon-D1-1F] Dark Palace - Spike Statue Room').item is not None and (state.world.get_location('[dungeon-D1-1F] Dark Palace - Spike Statue Room').item.name in ['Small Key (Palace of Darkness)']))) | ||||
|     set_rule(world.get_entrance('Dark Palace (North)'), lambda state: state.can_collect('Small Key (Palace of Darkness)', 4)) | ||||
|     set_rule(world.get_entrance('Dark Palace Maze Door'), lambda state: state.can_collect('Small Key (Palace of Darkness)', 6)) | ||||
|     set_rule(world.get_location('[dungeon-D1-1F] Dark Palace - Big Chest'), lambda state: state.can_collect('Big Key (Palace of Darkness)')) | ||||
|     set_rule(world.get_entrance('Dark Palace Bridge Room'), lambda state: state.has('Small Key (Palace of Darkness)', 1))  # If we can reach any other small key door, we already have back door access to this area | ||||
|     set_rule(world.get_entrance('Dark Palace Big Key Door'), lambda state: state.has('Small Key (Palace of Darkness)', 6) and state.has('Big Key (Palace of Darkness)') and state.has('Bow') and state.has('Hammer')) | ||||
|     set_rule(world.get_entrance('Dark Palace Big Key Chest Staircase'), lambda state: state.has('Small Key (Palace of Darkness)', 6) or (state.world.get_location('[dungeon-D1-1F] Dark Palace - Big Key Room').item is not None and (state.world.get_location('[dungeon-D1-1F] Dark Palace - Big Key Room').item.name in ['Small Key (Palace of Darkness)']))) | ||||
|     set_rule(world.get_entrance('Dark Palace Spike Statue Room Door'), lambda state: state.has('Small Key (Palace of Darkness)', 6) or (state.world.get_location('[dungeon-D1-1F] Dark Palace - Spike Statue Room').item is not None and (state.world.get_location('[dungeon-D1-1F] Dark Palace - Spike Statue Room').item.name in ['Small Key (Palace of Darkness)']))) | ||||
|     set_rule(world.get_entrance('Dark Palace (North)'), lambda state: state.has('Small Key (Palace of Darkness)', 4)) | ||||
|     set_rule(world.get_entrance('Dark Palace Maze Door'), lambda state: state.has('Small Key (Palace of Darkness)', 6)) | ||||
|     set_rule(world.get_location('[dungeon-D1-1F] Dark Palace - Big Chest'), lambda state: state.has('Big Key (Palace of Darkness)')) | ||||
|     for location in ['[dungeon-D1-1F] Dark Palace - Big Chest', 'Helmasaur - Heart Container']: | ||||
|         forbid_item(world.get_location(location), 'Big Key (Palace of Darkness)') | ||||
| 
 | ||||
|  | @ -292,19 +293,20 @@ def global_rules(world): | |||
|     set_rule(world.get_location('[dungeon-A2-1F] Ganons Tower - Torch'), lambda state: state.has_Boots()) | ||||
|     set_rule(world.get_entrance('Ganons Tower (Tile Room)'), lambda state: state.has('Cane of Somaria')) | ||||
|     set_rule(world.get_entrance('Ganons Tower (Hookshot Room)'), lambda state: state.has('Hammer')) | ||||
|     set_rule(world.get_entrance('Ganons Tower (Map Room)'), lambda state: state.can_collect('Small Key (Ganons Tower)', 3) or (state.world.get_location('[dungeon-A2-1F] Ganons Tower - Map Room').item is not None and state.world.get_location('[dungeon-A2-1F] Ganons Tower - Map Room').item.name == 'Small Key (Ganons Tower)')) | ||||
|     set_rule(world.get_entrance('Ganons Tower (Double Switch Room)'), lambda state: state.can_collect('Small Key (Ganons Tower)', 2)) | ||||
|     set_rule(world.get_entrance('Ganons Tower (Firesnake Room)'), lambda state: state.can_collect('Small Key (Ganons Tower)', 3)) | ||||
|     set_rule(world.get_entrance('Ganons Tower (Tile Room) Key Door'), lambda state: state.can_collect('Small Key (Ganons Tower)', 3))  # possibly too pessimistic | ||||
|     set_rule(world.get_location('[dungeon-A2-1F] Ganons Tower - Big Chest'), lambda state: state.can_collect('Big Key (Ganons Tower)')) | ||||
|     set_rule(world.get_entrance('Ganons Tower (Map Room)'), lambda state: state.has('Small Key (Ganons Tower)', 3) or (state.world.get_location('[dungeon-A2-1F] Ganons Tower - Map Room').item is not None and state.world.get_location('[dungeon-A2-1F] Ganons Tower - Map Room').item.name == 'Small Key (Ganons Tower)')) | ||||
|     set_rule(world.get_entrance('Ganons Tower (Double Switch Room)'), lambda state: state.has('Small Key (Ganons Tower)', 2)) | ||||
|     set_rule(world.get_entrance('Ganons Tower (Firesnake Room)'), lambda state: state.has('Small Key (Ganons Tower)', 3)) | ||||
|     set_rule(world.get_entrance('Ganons Tower (Tile Room) Key Door'), lambda state: state.has('Small Key (Ganons Tower)', 3))  # possibly too pessimistic | ||||
|     set_rule(world.get_location('[dungeon-A2-1F] Ganons Tower - Big Chest'), lambda state: state.has('Big Key (Ganons Tower)')) | ||||
|     set_rule(world.get_location('[dungeon-A2-B1] Ganons Tower - Armos Room [left chest]'), lambda state: state.has('Bow') or state.has_blunt_weapon()) | ||||
|     set_rule(world.get_location('[dungeon-A2-B1] Ganons Tower - Armos Room [bottom chest]'), lambda state: state.has('Bow') or state.has_blunt_weapon()) | ||||
|     set_rule(world.get_location('[dungeon-A2-B1] Ganons Tower - Armos Room [right chest]'), lambda state: state.has('Bow') or state.has_blunt_weapon()) | ||||
|     set_rule(world.get_entrance('Ganons Tower Big Key Door'), lambda state: state.can_collect('Big Key (Ganons Tower)') and state.has('Bow')) | ||||
|     set_rule(world.get_entrance('Ganons Tower Big Key Door'), lambda state: state.has('Big Key (Ganons Tower)') and state.has('Bow')) | ||||
|     set_rule(world.get_entrance('Ganons Tower Torch Rooms'), lambda state: state.has_fire_source()) | ||||
|     set_rule(world.get_entrance('Ganons Tower Moldorm Door'), lambda state: state.can_collect('Small Key (Ganons Tower)', 4)) | ||||
|     set_rule(world.get_entrance('Ganons Tower Moldorm Door'), lambda state: state.has('Small Key (Ganons Tower)', 4)) | ||||
|     set_rule(world.get_entrance('Ganons Tower Moldorm Gap'), lambda state: state.has('Hookshot')) | ||||
|     set_rule(world.get_entrance('Pyramid Hole'), lambda state: state.can_reach('East Dark World') and (state.has_sword() or state.has('Bottle') or state.has('Bug Catching Net')))  # some obscure hammer on pyramid soft lock potential scenarios | ||||
|     set_rule(world.get_location('Agahnim 2'), lambda state: state.has_sword() or state.has('Hammer') or state.has('Bug Catching Net')) | ||||
|     set_rule(world.get_entrance('Pyramid Hole'), lambda state: state.has('Beat Agahnim 2')) | ||||
|     for location in ['[dungeon-A2-1F] Ganons Tower - Big Chest', '[dungeon-A2-6F] Ganons Tower - Mini Helmasaur Room [left chest]', '[dungeon-A2-6F] Ganons Tower - Mini Helmasaur Room [right chest]', | ||||
|                      '[dungeon-A2-6F] Ganons Tower - Room before Moldorm', '[dungeon-A2-6F] Ganons Tower - Moldorm Room']: | ||||
|         forbid_item(world.get_location(location), 'Big Key (Ganons Tower)') | ||||
|  | @ -453,7 +455,7 @@ def set_big_bomb_rules(world): | |||
|                              'Mimic Cave Mirror Spot'] | ||||
|     Isolated_LW_entrances =['Capacity Upgrade', | ||||
|                             'Hookshot Fairy'] | ||||
|     set_rule(world.get_entrance('Pyramid Fairy'), lambda state: state.has_Pearl() and state.can_reach('Big Bomb Shop', 'Region') and state.can_collect('Crystal 5') and state.can_collect('Crystal 6')) | ||||
|     set_rule(world.get_entrance('Pyramid Fairy'), lambda state: state.has_Pearl() and state.can_reach('Big Bomb Shop', 'Region') and state.has('Crystal 5') and state.has('Crystal 6')) | ||||
|     if bombshop_entrance.name in Normal_LW_entrances: | ||||
|         add_rule(world.get_entrance('Pyramid Fairy'), lambda state: state.can_reach('Top of Pyramid', 'Entrance') or (state.has('Hammer') and state.can_lift_rocks()) or state.has_Mirror()) | ||||
|     elif bombshop_entrance.name in LW_walkable_entrances: | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue