From 3adf4fadd11414c92103136071ea27b9bef70703 Mon Sep 17 00:00:00 2001 From: Kevin Cathcart Date: Tue, 2 Jan 2018 00:39:53 -0500 Subject: [PATCH] Partial vt28 logic update --- BaseClasses.py | 21 +++++++++++--- Fill.py | 19 +++++++------ ItemList.py | 3 ++ Main.py | 1 + Rules.py | 76 ++++++++++++++++++++++++++++++-------------------- 5 files changed, 76 insertions(+), 44 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index ec9c4b54..d05b5519 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -52,6 +52,7 @@ class World(object): self.fastmenu = fastmenu self.disable_music = disable_music self.keysanity = keysanity + self.can_take_damage = True self.spoiler = Spoiler(self) def intialize_regions(self): @@ -151,7 +152,7 @@ class World(object): if not isinstance(location, Location): location = self.get_location(location) - if location.can_fill(item): + if location.can_fill(self.state, item, False): location.item = item item.location = location if collect: @@ -351,6 +352,17 @@ class CollectionState(object): def can_lift_heavy_rocks(self): return self.has('Titans Mitts') + def can_extend_magic(self): + return self.has('Half Magic') or self.has('Quarter Magic') or self.has_bottle() # FIXME bottle should really also have a requirement that we can reach some shop that sells green or blue potions + + def can_kill_most_things(self, enemies=5): + return (self.has_blunt_weapon() + or self.has('Cane of Somaria') + or (self.has('Cane of Byrna') and (enemies < 6 or self.can_extend_Magic())) + or self.has('Bow') + or self.has('Fire Rod') + ) + def has_sword(self): return self.has('Fighter Sword') or self.has('Master Sword') or self.has('Tempered Sword') or self.has('Golden Sword') @@ -580,11 +592,12 @@ class Location(object): self.recursion_count = 0 self.staleness_count = 0 self.event = False + self.always_allow = lambda item, state: False self.access_rule = lambda state: True - self.item_rule = lambda state: True + self.item_rule = lambda item: True - def can_fill(self, item): - return self.parent_region.can_fill(item) and self.item_rule(item) + def can_fill(self, state, item, check_access=True): + return self.always_allow(item, self) or (self.parent_region.can_fill(item) and self.item_rule(item) and (not check_access or self.can_reach(state))) def can_reach(self, state): if self.access_rule(state) and state.can_reach(self.parent_region): diff --git a/Fill.py b/Fill.py index f9e64378..2ac444de 100644 --- a/Fill.py +++ b/Fill.py @@ -57,7 +57,7 @@ def distribute_items_cutoff(world, cutoffrate=0.33): spot_to_fill = None for location in fill_locations if placed_advancement_items / total_advancement_items < cutoffrate else reversed(fill_locations): - if world.state.can_reach(location) and location.can_fill(item_to_place): + if location.can_fill(world.state, item_to_place): spot_to_fill = location break @@ -129,7 +129,7 @@ def distribute_items_staleness(world): if not progress_done and random.randint(0, location.staleness_count) > 2: continue - if world.state.can_reach(location) and location.can_fill(item_to_place): + if location.can_fill(world.state, item_to_place): spot_to_fill = location break else: @@ -138,7 +138,7 @@ def distribute_items_staleness(world): # might have skipped too many locations due to potential staleness. Do not check for staleness now to find a candidate if spot_to_fill is None: for location in fill_locations: - if world.state.can_reach(location) and location.can_fill(item_to_place): + if location.can_fill(world.state, item_to_place): spot_to_fill = location break @@ -168,15 +168,16 @@ def fill_restrictive(world, base_state, locations, itempool): item_to_place = itempool.pop() maximum_exploration_state = sweep_from_pool() + perform_access_check = True if world.check_beatable_only: - can_beat_without = world.has_beaten_game(maximum_exploration_state) + perform_access_check = not world.has_beaten_game(maximum_exploration_state) + spot_to_fill = None for location in locations: - if location.can_fill(item_to_place): - if (world.check_beatable_only and can_beat_without) or maximum_exploration_state.can_reach(location): - spot_to_fill = location - break + if location.can_fill(maximum_exploration_state, item_to_place, perform_access_check): + spot_to_fill = location + break if spot_to_fill is None: # we filled all reachable spots. Maybe the game can be beaten anyway? @@ -251,7 +252,7 @@ def flood_items(world): random.shuffle(location_list) spot_to_fill = None for location in location_list: - if world.state.can_reach(location) and location.can_fill(itempool[0]): + if location.can_fill(world.state, itempool[0]): spot_to_fill = location break diff --git a/ItemList.py b/ItemList.py index 1faaa514..784a51e0 100644 --- a/ItemList.py +++ b/ItemList.py @@ -180,6 +180,9 @@ def generate_itempool(world): or world.mode not in ['open', 'standard', 'swordless'] 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') + if world.timer in ['ohko', 'timed-ohko']: + world.can_take_damage = False + world.push_item('Ganon', ItemFactory('Triforce'), False) world.get_location('Ganon').event = True world.push_item('Agahnim 1', ItemFactory('Beat Agahnim 1'), False) diff --git a/Main.py b/Main.py index ab3ac04f..03e172ac 100644 --- a/Main.py +++ b/Main.py @@ -133,6 +133,7 @@ def copy_world(world): ret.dark_world_light_cone = world.dark_world_light_cone ret.seed = world.seed ret.can_access_trock_eyebridge = world.can_access_trock_eyebridge + ret.can_take_damage = world.can_take_damage create_regions(ret) create_dungeons(ret) diff --git a/Rules.py b/Rules.py index e46a3445..77effcb7 100644 --- a/Rules.py +++ b/Rules.py @@ -39,6 +39,9 @@ def set_rules(world): def set_rule(spot, rule): spot.access_rule = rule +def set_always_allow(spot, rule): + spot.always_allow = rule + def add_rule(spot, rule, combine='and'): old_rule = spot.access_rule @@ -60,10 +63,15 @@ def forbid_item(location, item): def item_in_locations(state, item, locations): for location in locations: loc = state.world.get_location(location) - if loc.item is not None and loc.item.name == item: + if item_name(loc) == item: return True return False +def item_name(location): + if location.item is None: + return None + return location.item.name + def global_rules(world): # ganon can only carry triforce @@ -111,6 +119,7 @@ def global_rules(world): set_rule(world.get_location('Master Sword Pedestal'), 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.has('Beat Agahnim 1')) # barrier gets removed after killing agahnim, relevant for entrance shuffle + # FIXME: VT has a can_kill_most_things(8) call on Aga Tower's entrance. I suspect this needs to be added to first two chests inside the tower instead? set_rule(world.get_entrance('Agahnim 1'), lambda state: state.has_sword() and state.has('Small Key (Agahnims Tower)', 2)) set_rule(world.get_location('Castle Tower - Dark Maze'), lambda state: state.has('Small Key (Agahnims Tower)')) set_rule(world.get_entrance('Top of Pyramid'), lambda state: state.has('Beat Agahnim 1')) @@ -175,7 +184,9 @@ def global_rules(world): set_rule(world.get_entrance('Fairy Ascension Mirror Spot'), lambda state: state.has_Mirror() and state.has_Pearl()) # need to lift flowers set_rule(world.get_entrance('Isolated Ledge Mirror Spot'), lambda state: state.has_Mirror()) set_rule(world.get_entrance('Superbunny Cave Exit (Bottom)'), lambda state: False) # Cannot get to bottom exit from top. Just exists for shuffling - set_rule(world.get_location('Spike Cave'), lambda state: state.has('Hammer') and state.can_lift_rocks() and (state.has('Cane of Byrna') or state.has('Cape')) and (state.has_bottle() or state.has('Half Magic') or state.has('Quarter Magic'))) + set_rule(world.get_location('Spike Cave'), lambda state: state.has('Hammer') and state.can_lift_rocks() and (state.has('Cane of Byrna') or state.has('Cape')) and state.can_extend_magic()) + # TODO: Current-VT logic is: hammer and lift_rocks and ((cape and extend) or (byrna and (can-take-damage OR canextend))) + # Is that really good enough? Can you really get through with byrna, single magic w/o refills and only 3 hearts? set_rule(world.get_location('Hookshot Cave - Top Right'), lambda state: state.has('Hookshot')) set_rule(world.get_location('Hookshot Cave - Top Left'), lambda state: state.has('Hookshot')) set_rule(world.get_location('Hookshot Cave - Bottom Right'), lambda state: state.has('Hookshot') or state.has('Pegasus Boots')) @@ -230,6 +241,7 @@ def global_rules(world): 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') or state.has('Cane of Byrna'))) set_rule(world.get_location('Thieves\' Town - Big Chest'), lambda state: state.has('Small Key (Thieves Town)') and state.has('Hammer')) + # TODO: add key-for-key logic to above w always_allow, etc. set_rule(world.get_location('Thieves\' Town - Attic'), lambda state: state.has('Small Key (Thieves Town)')) for location in ['Thieves\' Town - Attic', 'Thieves\' Town - Big Chest', 'Thieves\' Town - Blind\'s Cell', 'Thieves Town - Blind']: forbid_item(world.get_location(location), 'Big Key (Thieves Town)') @@ -250,14 +262,14 @@ def global_rules(world): 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('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 (item_in_locations(state, 'Big Key (Ice Palace)', ['Ice Palace - Spike Room', 'Ice Palace - Big Key Chest', 'Ice Palace - Map Chest']) and state.has('Small Key (Ice Palace)')) or state.has('Small Key (Ice Palace)', 2)) and (state.has('Hookshot') or state.has('Cape') or state.has('Cane of Byrna'))) + set_rule(world.get_entrance('Ice Palace (East)'), lambda state: (state.has('Hookshot') or (item_in_locations(state, 'Big Key (Ice Palace)', ['Ice Palace - Spike Room', 'Ice Palace - Big Key Chest', 'Ice Palace - Map Chest']) and state.has('Small Key (Ice Palace)')) or state.has('Small Key (Ice Palace)', 2)) and (world.can_take_damage or state.has('Hookshot') or state.has('Cape') or state.has('Cane of Byrna'))) set_rule(world.get_entrance('Ice Palace (East Top)'), lambda state: state.can_lift_rocks() and state.has('Hammer')) for location in ['Ice Palace - Big Chest', 'Ice Palace - Kholdstare']: 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('Misery Mire - Big Chest'), lambda state: state.has('Big Key (Misery Mire)')) - set_rule(world.get_location('Misery Mire - Spike Chest'), lambda state: state.has('Cane of Byrna') or state.has('Cape')) + set_rule(world.get_location('Misery Mire - Spike Chest'), lambda state: world.can_take_damage or state.has('Cane of Byrna') or state.has('Cape')) 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 ... # big key gives backdoor access to that from the teleporter in the north west @@ -265,8 +277,8 @@ def global_rules(world): # in addition, you can open the door to the map room before getting access to a color switch, so this is locked behing 2 small keys or the big key... set_rule(world.get_location('Misery Mire - Main Lobby'), lambda state: state.has('Small Key (Misery Mire)', 2) 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.has('Small Key (Misery Mire)', 2) if ((state.world.get_location('Misery Mire - Compass Chest').item is not None and state.world.get_location('Misery Mire - Compass Chest').item.name in ['Big Key (Misery Mire)']) or - (state.world.get_location('Misery Mire - Big Key Chest').item is not None and state.world.get_location('Misery Mire - Big Key Chest').item.name in ['Big Key (Misery Mire)'])) else state.has('Small Key (Misery Mire)', 3)) + set_rule(world.get_entrance('Misery Mire (West)'), lambda state: state.has('Small Key (Misery Mire)', 2) if ((item_name(state.world.get_location('Misery Mire - Compass Chest')) in ['Big Key (Misery Mire)']) or + (item_name(state.world.get_location('Misery Mire - Big Key Chest')) in ['Big Key (Misery Mire)'])) else state.has('Small Key (Misery Mire)', 3)) set_rule(world.get_location('Misery Mire - Compass Chest'), lambda state: state.has_fire_source()) set_rule(world.get_location('Misery Mire - Big Key Chest'), 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())) @@ -284,29 +296,31 @@ def global_rules(world): 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')) + # FIXME: should shield overflow count check to the progrssive logic stuff, so we don't get false mirror shields which would cause problems here set_rule(world.get_location('Turtle Rock - Eye Bridge - Bottom Left'), lambda state: state.has('Cane of Byrna') or state.has('Cape') or state.has('Mirror Shield')) set_rule(world.get_location('Turtle Rock - Eye Bridge - Bottom Right'), lambda state: state.has('Cane of Byrna') or state.has('Cape') or state.has('Mirror Shield')) set_rule(world.get_location('Turtle Rock - Eye Bridge - Top Left'), lambda state: state.has('Cane of Byrna') or state.has('Cape') or state.has('Mirror Shield')) set_rule(world.get_location('Turtle Rock - Eye Bridge - Top Right'), lambda state: state.has('Cane of Byrna') or state.has('Cape') or state.has('Mirror Shield')) 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'))) + (state.has('Hammer') or state.has_beam_sword() or state.can_extend_magic())) + # TODO: Per VT, possibly allow a regular sword with 4x extended magic (ie. quater magic, or half magic+bottle or 3 bottles) set_trock_key_rules(world) set_rule(world.get_entrance('Palace of Darkness Bonk Wall'), lambda state: state.has('Bow')) set_rule(world.get_entrance('Palace of Darkness Hammer Peg Drop'), lambda state: state.has('Hammer')) set_rule(world.get_entrance('Palace of Darkness 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('Palace of Darkness 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('Palace of Darkness Big Key Chest Staircase'), lambda state: state.has('Small Key (Palace of Darkness)', 5) or (state.world.get_location('Palace of Darkness - Big Key Chest').item is not None and (state.world.get_location('Palace of Darkness - Big Key Chest').item.name in ['Small Key (Palace of Darkness)']))) + set_rule(world.get_entrance('Palace of Darkness Big Key Chest Staircase'), lambda state: state.has('Small Key (Palace of Darkness)', 5) or (item_name(state.world.get_location('Palace of Darkness - Big Key Chest')) in ['Small Key (Palace of Darkness)'])) set_rule(world.get_entrance('Palace of Darkness (North)'), lambda state: state.has('Small Key (Palace of Darkness)', 4)) set_rule(world.get_location('Palace of Darkness - Big Chest'), lambda state: state.has('Big Key (Palace of Darkness)')) if world.keysanity: - set_rule(world.get_entrance('Palace of Darkness Spike Statue Room Door'), lambda state: state.has('Small Key (Palace of Darkness)', 6) or (state.world.get_location('Palace of Darkness - Harmless Hellway').item is not None and (state.world.get_location('Palace of Darkness - Harmless Hellway').item.name in ['Small Key (Palace of Darkness)']))) - set_rule(world.get_entrance('Palace of Darkness Big Key Chest Staircase'), lambda state: state.has('Small Key (Palace of Darkness)', 6) or (state.world.get_location('Palace of Darkness - Big Key Chest').item is not None and (state.world.get_location('Palace of Darkness - Big Key Chest').item.name in ['Small Key (Palace of Darkness)']))) + set_rule(world.get_entrance('Palace of Darkness Spike Statue Room Door'), lambda state: state.has('Small Key (Palace of Darkness)', 6) or (item_name(state.world.get_location('Palace of Darkness - Harmless Hellway')) in ['Small Key (Palace of Darkness)'])) + set_rule(world.get_entrance('Palace of Darkness Big Key Chest Staircase'), lambda state: state.has('Small Key (Palace of Darkness)', 6) or (item_name(state.world.get_location('Palace of Darkness - Big Key Chest')) in ['Small Key (Palace of Darkness)'])) set_rule(world.get_entrance('Palace of Darkness Maze Door'), lambda state: state.has('Small Key (Palace of Darkness)', 6)) else: - set_rule(world.get_entrance('Palace of Darkness Spike Statue Room Door'), lambda state: state.has('Small Key (Palace of Darkness)', 5) or (state.world.get_location('Palace of Darkness - Harmless Hellway').item is not None and (state.world.get_location('Palace of Darkness - Harmless Hellway').item.name in ['Small Key (Palace of Darkness)']))) - set_rule(world.get_entrance('Palace of Darkness Big Key Chest Staircase'), lambda state: state.has('Small Key (Palace of Darkness)', 5) or (state.world.get_location('Palace of Darkness - Big Key Chest').item is not None and (state.world.get_location('Palace of Darkness - Big Key Chest').item.name in ['Small Key (Palace of Darkness)']))) + set_rule(world.get_entrance('Palace of Darkness Spike Statue Room Door'), lambda state: state.has('Small Key (Palace of Darkness)', 5) or (item_name(state.world.get_location('Palace of Darkness - Harmless Hellway')) in ['Small Key (Palace of Darkness)'])) + set_rule(world.get_entrance('Palace of Darkness Big Key Chest Staircase'), lambda state: state.has('Small Key (Palace of Darkness)', 5) or (item_name(state.world.get_location('Palace of Darkness - Big Key Chest')) in ['Small Key (Palace of Darkness)'])) set_rule(world.get_entrance('Palace of Darkness Maze Door'), lambda state: state.has('Small Key (Palace of Darkness)', 5)) for location in ['Palace of Darkness - Big Chest', 'Palace of Darkness - Helmasaur']: @@ -322,13 +336,12 @@ def global_rules(world): set_rule(world.get_location('Ganons Tower - Bob\'s 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')) - if world.keysanity: - set_rule(world.get_entrance('Ganons Tower (Map Room)'), lambda state: state.has('Small Key (Ganons Tower)', 4) or (state.world.get_location('Ganons Tower - Map Chest').item is not None and state.world.get_location('Ganons Tower - Map Chest').item.name == 'Big Key (Ganons Tower)' and state.has('Small Key (Ganons Tower)', 3)) or (state.world.get_location('Ganons Tower - Map Chest').item is not None and state.world.get_location('Ganons Tower - Map Chest').item.name == 'Small Key (Ganons Tower)')) - else: - set_rule(world.get_entrance('Ganons Tower (Map Room)'), lambda state: state.has('Small Key (Ganons Tower)', 3) or (state.world.get_location('Ganons Tower - Map Chest').item is not None and state.world.get_location('Ganons Tower - Map Chest').item.name == 'Small Key (Ganons Tower)')) - # It is possible to need more than 2 keys to get through this entance if you spend keys elsewhere We reflect this in the chest requirements. - # However we need to leave these at the lower values derive that with 3 keys it is always possible to reach Bob and Ice Armos. + set_rule(world.get_entrance('Ganons Tower (Map Room)'), lambda state: state.has('Small Key (Ganons Tower)', 4) or (item_name(state.world.get_location('Ganons Tower - Map Chest')) in ['Big Key (Ganons Tower)', 'Small Key (Ganons Tower)'] and state.has('Small Key (Ganons Tower)', 3))) + set_always_allow(world.get_entrance('Ganons Tower (Map Room)'), lambda state, item: item.name == 'Small Key (Ganons Tower)' and state.has('Small Key (Ganons Tower)', 3)) + + # It is possible to need more than 2 keys to get through this entance if you spend keys elsewhere. We reflect this in the chest requirements. + # However we need to leave these at the lower values to derive that with 3 keys it is always possible to reach Bob and Ice Armos. set_rule(world.get_entrance('Ganons Tower (Double Switch Room)'), lambda state: state.has('Small Key (Ganons Tower)', 2)) # It is possible to need more than 3 keys .... set_rule(world.get_entrance('Ganons Tower (Firesnake Room)'), lambda state: state.has('Small Key (Ganons Tower)', 3)) @@ -361,7 +374,7 @@ def global_rules(world): set_rule(world.get_location('Ganon'), lambda state: state.has_beam_sword() and state.has_fire_source() and 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') - and (state.has('Tempered Sword') or state.has('Golden Sword') or (state.has('Silver Arrows') and state.has('Bow')) or state.has('Lamp') or state.has_bottle() or state.has('Half Magic') or state.has('Quarter Magic'))) # need to light torch a sufficient amount of times + and (state.has('Tempered Sword') or state.has('Golden Sword') or (state.has('Silver Arrows') and state.has('Bow')) or state.has('Lamp') or state.can_extend_magic())) # need to light torch a sufficient amount of times set_rule(world.get_entrance('Ganon Drop'), lambda state: state.has_beam_sword()) # need to damage ganon to get tiles to drop @@ -426,11 +439,8 @@ def open_rules(world): forbid_item(world.get_location('Hyrule Castle - Boomerang Chest'), 'Small Key (Escape)') forbid_item(world.get_location('Hyrule Castle - Zelda\'s Chest'), 'Small Key (Escape)') - # to prevent key-lock in keysanity we need to prevent these chests from having an item that - # blocks the small key - if world.keysanity: - set_rule(world.get_location('Hyrule Castle - Boomerang Chest'), lambda state: state.has('Small Key (Escape)')) - set_rule(world.get_location('Hyrule Castle - Zelda\'s Chest'), lambda state: state.has('Small Key (Escape)')) + set_rule(world.get_location('Hyrule Castle - Boomerang Chest'), lambda state: state.has('Small Key (Escape)')) + set_rule(world.get_location('Hyrule Castle - Zelda\'s Chest'), lambda state: state.has('Small Key (Escape)')) def swordless_rules(world): @@ -455,10 +465,13 @@ def swordless_rules(world): def standard_rules(world): # easiest way to enforce key placement not relevant for open - forbid_item(world.get_location('Sewers - Secret Room - Left'), 'Small Key (Escape)') - forbid_item(world.get_location('Sewers - Secret Room - Middle'), 'Small Key (Escape)') - forbid_item(world.get_location('Sewers - Secret Room - Right'), 'Small Key (Escape)') - forbid_item(world.get_location('Sanctuary'), 'Small Key (Escape)') + set_rule(world.get_location('Sewers - Dark Cross'), lambda state: state.can_kill_most_things()) + add_rule(world.get_entrance('Sewers Door'), lambda state: state.can_kill_most_things()) + + set_rule(world.get_location('Hyrule Castle - Boomerang Chest'), lambda state: state.can_kill_most_things()) + set_rule(world.get_location('Hyrule Castle - Zelda\'s Chest'), lambda state: state.can_kill_most_things()) + + def set_trock_key_rules(world): @@ -495,11 +508,12 @@ def set_trock_key_rules(world): # however in keysanity being able to reach all other chests while only having three keys does not imply this contains # a key, so we again need all four keys unless it contains the big key if can_reach_back: - set_rule(world.get_location('Turtle Rock - Big Key Chest'), lambda state: state.has('Small Key (Turtle Rock)', 4) or (state.world.get_location('Turtle Rock - Big Key Chest').item is not None and (state.world.get_location('Turtle Rock - Big Key Chest').item.name in ['Small Key (Turtle Rock)']))) + set_rule(world.get_location('Turtle Rock - Big Key Chest'), lambda state: state.has('Small Key (Turtle Rock)', 4) or (item_name(state.world.get_location('Turtle Rock - Big Key Chest')) in ['Small Key (Turtle Rock)'])) elif world.keysanity: - set_rule(world.get_location('Turtle Rock - Big Key Chest'), lambda state: state.has('Small Key (Turtle Rock)', 2) if (state.world.get_location('Turtle Rock - Big Key Chest').item is not None and (state.world.get_location('Turtle Rock - Big Key Chest').item.name in ['Big Key (Turtle Rock)'])) else state.has('Small Key (Turtle Rock)', 4) or (state.world.get_location('Turtle Rock - Big Key Chest').item is not None and (state.world.get_location('Turtle Rock - Big Key Chest').item.name in ['Small Key (Turtle Rock)']))) + set_rule(world.get_location('Turtle Rock - Big Key Chest'), lambda state: state.has('Small Key (Turtle Rock)', 2) if (item_name(state.world.get_location('Turtle Rock - Big Key Chest')) in ['Big Key (Turtle Rock)']) else state.has('Small Key (Turtle Rock)', 4) or (item_name(state.world.get_location('Turtle Rock - Big Key Chest')) in ['Small Key (Turtle Rock)'])) else: - set_rule(world.get_location('Turtle Rock - Big Key Chest'), lambda state: state.has('Small Key (Turtle Rock)', 2) if (state.world.get_location('Turtle Rock - Big Key Chest').item is not None and (state.world.get_location('Turtle Rock - Big Key Chest').item.name in ['Big Key (Turtle Rock)'])) else state.has('Small Key (Turtle Rock)', 3) or (state.world.get_location('Turtle Rock - Big Key Chest').item is not None and (state.world.get_location('Turtle Rock - Big Key Chest').item.name in ['Small Key (Turtle Rock)']))) + set_rule(world.get_location('Turtle Rock - Big Key Chest'), lambda state: state.has('Small Key (Turtle Rock)', 2) if (item_name(state.world.get_location('Turtle Rock - Big Key Chest')) in ['Big Key (Turtle Rock)']) else state.has('Small Key (Turtle Rock)', 3) or (item_name(state.world.get_location('Turtle Rock - Big Key Chest')) in ['Small Key (Turtle Rock)'])) + # FIXME add key-for-key logic to the above mess via always_allow rules. Ugh! # set big key restrictions non_big_key_locations = ['Turtle Rock - Big Chest', 'Turtle Rock - Trinexx']