Merge branch 'pull/23'

# Conflicts:
#	BaseClasses.py
#	EntranceShuffle.py
#	ItemList.py
#	Mystery.py
#	Rules.py
This commit is contained in:
Fabian Dill
2020-04-08 15:07:19 +02:00
12 changed files with 534 additions and 96 deletions

239
Rules.py
View File

@@ -1,6 +1,7 @@
import collections
import logging
from BaseClasses import CollectionState
import OWGSets
from BaseClasses import CollectionState, RegionType
def set_rules(world, player):
@@ -38,6 +39,12 @@ def set_rules(world, player):
if world.logic[player] == 'noglitches':
no_glitches_rules(world, player)
elif world.logic[player] == 'owglitches':
logging.getLogger('').info('There is a chance OWG has bugged edge case rulesets, especially in inverted. Definitely file a report on GitHub if you see anything strange.')
# Initially setting no_glitches_rules to set the baseline rules for some
# entrances. The overworld_glitches_rules set is primarily additive.
no_glitches_rules(world, player)
overworld_glitches_rules(world, player)
elif world.logic[player] == 'minorglitches':
logging.getLogger('').info('Minor Glitches may be buggy still. No guarantee for proper logic checks.')
else:
@@ -293,8 +300,7 @@ def global_rules(world, player):
set_rule(world.get_location('Ganons Tower - Bob\'s Torch', player), lambda state: state.has_Boots(player))
set_rule(world.get_entrance('Ganons Tower (Tile Room)', player), lambda state: state.has('Cane of Somaria', player))
set_rule(world.get_entrance('Ganons Tower (Hookshot Room)', player), lambda state: state.has('Hammer', player))
set_rule(world.get_entrance('Ganons Tower (Hookshot Room)', player), lambda state: state.has('Hammer', player) and (state.has('Hookshot', player) or state.has_Boots(player)))
set_rule(world.get_entrance('Ganons Tower (Map Room)', player), lambda state: state.has_key('Small Key (Ganons Tower)', player, 4) or (item_name(state, 'Ganons Tower - Map Chest', player) in [('Big Key (Ganons Tower)', player), ('Small Key (Ganons Tower)', player)] and state.has_key('Small Key (Ganons Tower)', player, 3)))
if world.accessibility[player] != 'locations':
set_always_allow(world.get_location('Ganons Tower - Map Chest', player), lambda state, item: item.name == 'Small Key (Ganons Tower)' and item.player == player and state.has_key('Small Key (Ganons Tower)', player, 3))
@@ -356,7 +362,6 @@ def default_rules(world, player):
set_rule(world.get_entrance('Kings Grave Mirror Spot', player), lambda state: state.has_Pearl(player) and state.has_Mirror(player))
# Caution: If king's grave is releaxed at all to account for reaching it via a two way cave's exit in insanity mode, then the bomb shop logic will need to be updated (that would involve create a small ledge-like Region for it)
set_rule(world.get_entrance('Bonk Fairy (Light)', player), lambda state: state.has_Boots(player))
set_rule(world.get_entrance('Bat Cave Drop Ledge', player), lambda state: state.has('Hammer', player))
set_rule(world.get_entrance('Lumberjack Tree Tree', player), lambda state: state.has_Boots(player) and state.has('Beat Agahnim 1', player))
set_rule(world.get_entrance('Bonk Rock Cave', player), lambda state: state.has_Boots(player))
set_rule(world.get_entrance('Desert Palace Stairs', player), lambda state: state.has('Book of Mudora', player))
@@ -392,7 +397,8 @@ def default_rules(world, player):
set_rule(world.get_entrance('Turtle Rock Teleporter', player), lambda state: state.can_lift_heavy_rocks(player) and state.has('Hammer', player))
set_rule(world.get_entrance('East Death Mountain (Top)', player), lambda state: state.has('Hammer', player))
set_rule(world.get_location('Catfish', player), lambda state: state.can_lift_rocks(player))
set_rule(world.get_entrance('Catfish Exit Rock', player), lambda state: state.can_lift_rocks(player))
set_rule(world.get_entrance('Catfish Entrance Rock', player), lambda state: state.can_lift_rocks(player))
set_rule(world.get_entrance('Northeast Dark World Broken Bridge Pass', player), lambda state: state.has_Pearl(player) and (state.can_lift_rocks(player) or state.has('Hammer', player) or state.has('Flippers', player)))
set_rule(world.get_entrance('East Dark World Broken Bridge Pass', player), lambda state: state.has_Pearl(player) and (state.can_lift_rocks(player) or state.has('Hammer', player)))
set_rule(world.get_entrance('South Dark World Bridge', player), lambda state: state.has('Hammer', player) and state.has_Pearl(player))
@@ -402,7 +408,7 @@ def default_rules(world, player):
set_rule(world.get_entrance('Hyrule Castle Ledge Mirror Spot', player), lambda state: state.has_Mirror(player))
set_rule(world.get_entrance('Hyrule Castle Main Gate', player), lambda state: state.has_Mirror(player))
set_rule(world.get_entrance('Dark Lake Hylia Drop (East)', player), lambda state: (state.has_Pearl(player) and state.has('Flippers', player) or state.has_Mirror(player))) # Overworld Bunny Revival
set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player) and state.has_Mirror(player))
set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player))
set_rule(world.get_entrance('Dark Lake Hylia Drop (South)', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player)) # ToDo any fake flipper set up?
set_rule(world.get_entrance('Dark Lake Hylia Ledge Fairy', player), lambda state: state.has_Pearl(player)) # bomb required
set_rule(world.get_entrance('Dark Lake Hylia Ledge Spike Cave', player), lambda state: state.can_lift_rocks(player) and state.has_Pearl(player))
@@ -415,6 +421,7 @@ def default_rules(world, player):
set_rule(world.get_entrance('Skull Woods Second Section Hole', player), lambda state: state.has_Pearl(player)) # bunny cannot lift bush
set_rule(world.get_entrance('Maze Race Mirror Spot', player), lambda state: state.has_Mirror(player))
set_rule(world.get_entrance('Cave 45 Mirror Spot', player), lambda state: state.has_Mirror(player))
set_rule(world.get_entrance('Bombos Tablet Mirror Spot', player), lambda state: state.has_Mirror(player))
set_rule(world.get_entrance('East Dark World Bridge', player), lambda state: state.has_Pearl(player) and state.has('Hammer', player))
set_rule(world.get_entrance('Lake Hylia Island Mirror Spot', player), lambda state: state.has_Pearl(player) and state.has_Mirror(player) and state.has('Flippers', player))
set_rule(world.get_entrance('Lake Hylia Central Island Mirror Spot', player), lambda state: state.has_Mirror(player))
@@ -460,6 +467,19 @@ def default_rules(world, player):
set_rule(world.get_entrance('Ganons Tower', player), lambda state: state.has_crystals(world.crystals_needed_for_gt[player], player))
def forbid_overworld_glitches(world, player):
for exit in OWGSets.get_boots_clip_exits_lw(world.mode[player] == 'inverted'):
set_rule(world.get_entrance(exit, player), lambda state: False)
for exit in OWGSets.get_boots_clip_exits_dw(world.mode[player] == 'inverted'):
set_rule(world.get_entrance(exit, player), lambda state: False)
for exit in OWGSets.get_glitched_speed_drops_dw():
set_rule(world.get_entrance(exit, player), lambda state: False)
if world.mode[player] != 'inverted':
for exit in OWGSets.get_mirror_clip_spots_dw():
set_rule(world.get_entrance(exit, player), lambda state: False)
def inverted_rules(world, player):
# s&q regions. link's house entrance is set to true so the filler knows the chest inside can always be reached
world.get_region('Inverted Links House', player).can_reach_private = lambda state: True
@@ -631,6 +651,7 @@ def no_glitches_rules(world, player):
set_rule(world.get_entrance('Dark Lake Hylia Teleporter', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player) and (state.has('Hammer', player) or state.can_lift_rocks(player)))
set_rule(world.get_entrance('Dark Lake Hylia Ledge Drop', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player))
else:
set_rule(world.get_entrance('Bat Cave Drop Ledge', player), lambda state: state.has('Hammer', player))
set_rule(world.get_entrance('Zoras River', player), lambda state: state.has_Pearl(player) and (state.has('Flippers', player) or state.can_lift_rocks(player)))
set_rule(world.get_entrance('Lake Hylia Central Island Pier', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player)) # can be fake flippered to
set_rule(world.get_entrance('Lake Hylia Island Pier', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player)) # can be fake flippered to
@@ -642,25 +663,48 @@ def no_glitches_rules(world, player):
set_rule(world.get_entrance('Dark Lake Hylia Ledge Drop', player), lambda state: state.has('Flippers', player))
set_rule(world.get_entrance('East Dark World Pier', player), lambda state: state.has('Flippers', player))
add_rule(world.get_entrance('Ganons Tower (Hookshot Room)', player), lambda state: state.has('Hookshot', player) or state.has_Boots(player))
add_rule(world.get_entrance('Ganons Tower (Double Switch Room)', player), lambda state: state.has('Hookshot', player))
set_rule(world.get_entrance('Paradox Cave Push Block Reverse', player), lambda state: False) # no glitches does not require block override
forbid_bomb_jump_requirements(world, player)
forbid_overworld_glitches(world, player)
add_conditional_lamps(world, player)
def forbid_bomb_jump_requirements(world, player):
DMs_room_chests = ['Ganons Tower - DMs Room - Top Left', 'Ganons Tower - DMs Room - Top Right', 'Ganons Tower - DMs Room - Bottom Left', 'Ganons Tower - DMs Room - Bottom Right']
for location in DMs_room_chests:
add_rule(world.get_location(location, player), lambda state: state.has('Hookshot', player))
set_rule(world.get_entrance('Paradox Cave Push Block Reverse', player), lambda state: False) # no glitches does not require block override
set_rule(world.get_entrance('Paradox Cave Bomb Jump', player), lambda state: False)
set_rule(world.get_entrance('Skull Woods First Section Bomb Jump', player), lambda state: False)
DW_Entrances = ['Bumper Cave (Bottom)',
'Superbunny Cave (Top)',
'Superbunny Cave (Bottom)',
'Hookshot Cave',
'Bumper Cave (Top)',
'Hookshot Cave Back Entrance',
'Dark Death Mountain Ledge (East)',
'Turtle Rock Isolated Ledge Entrance',
'Thieves Town',
'Skull Woods Final Section',
'Ice Palace',
'Misery Mire',
'Palace of Darkness',
'Swamp Palace',
'Turtle Rock',
'Dark Death Mountain Ledge (West)']
def check_is_dark_world(region):
for entrance in region.entrances:
if entrance.name in DW_Entrances:
return True
return False
def add_conditional_lamps(world, player):
# Light cones in standard depend on which world we actually are in, not which one the location would normally be
# We add Lamp requirements only to those locations which lie in the dark world (or everything if open
DW_Entrances = ['Bumper Cave (Bottom)', 'Superbunny Cave (Top)', 'Superbunny Cave (Bottom)', 'Hookshot Cave', 'Bumper Cave (Top)', 'Hookshot Cave Back Entrance', 'Dark Death Mountain Ledge (East)',
'Turtle Rock Isolated Ledge Entrance', 'Thieves Town', 'Skull Woods Final Section', 'Ice Palace', 'Misery Mire', 'Palace of Darkness', 'Swamp Palace', 'Turtle Rock', 'Dark Death Mountain Ledge (West)']
def check_is_dark_world(region):
for entrance in region.entrances:
if entrance.name in DW_Entrances:
return True
return False
def add_conditional_lamp(spot, region, spottype='Location'):
if spottype == 'Location':
@@ -699,6 +743,54 @@ def no_glitches_rules(world, player):
add_lamp_requirement(world.get_entrance('Throne Room', player), player)
def overworld_glitches_rules(world, player):
# Spots that are immediately accessible.
for entrance in OWGSets.get_immediately_accessible_entrances(world, player):
set_rule(world.get_entrance(entrance, player), lambda state: True)
# Boots-accessible locations.
for entrance in OWGSets.get_boots_clip_exits_lw(world.mode[player] == 'inverted'):
set_rule(world.get_entrance(entrance, player), lambda state: state.can_boots_clip_lw(player))
for entrance in OWGSets.get_boots_clip_exits_dw(world.mode[player] == 'inverted'):
set_rule(world.get_entrance(entrance, player), lambda state: state.can_boots_clip_dw(player))
# Glitched speed drops.
for drop in OWGSets.get_glitched_speed_drops_dw():
set_rule(world.get_entrance(drop, player), lambda state: state.can_get_glitched_speed_dw(player))
# Dark Death Mountain Ledge Clip Spot also accessible with mirror.
if world.mode[player] != 'inverted':
add_rule(world.get_entrance('Dark Death Mountain Ledge Clip Spot', player), lambda state: state.has_Mirror(player), 'or')
# Mirror clip spots.
if world.mode[player] != 'inverted':
for clip_spot in OWGSets.get_mirror_clip_spots_dw():
set_rule(world.get_entrance(clip_spot, player), lambda state: state.has_Mirror(player))
else:
for clip_spot in OWGSets.get_mirror_clip_spots_lw():
set_rule(world.get_entrance(clip_spot, player), lambda state: state.has_Mirror(player))
# Locations that you can superbunny mirror into, but need a sword to clear.
mini_moldorm_cave = world.get_region('Mini Moldorm Cave', player)
for superbunny_mirror_weapon_region in OWGSets.get_sword_required_superbunny_mirror_regions():
region = world.get_region(superbunny_mirror_weapon_region, player)
if check_is_dark_world(region):
for spot in region.locations:
add_rule(world.get_location(spot, player), lambda state: state.can_superbunny_mirror_with_sword(player), 'or')
# Regions that require the boots and some other stuff.
if world.mode[player] != 'inverted':
set_rule(world.get_entrance('Dark Desert Teleporter', player), lambda state: state.has('Ocarina', player) or (state.can_boots_clip_dw(player) and state.can_lift_heavy_rocks(player)))
set_rule(world.get_entrance('Turtle Rock Teleporter', player), lambda state: (state.can_boots_clip_dw(player) or state.can_lift_heavy_rocks(player)) and state.has('Hammer', player))
add_rule(world.get_entrance('Catfish Exit Rock', player), lambda state: state.can_boots_clip_dw(player), 'or')
add_rule(world.get_entrance('East Dark World Broken Bridge Pass', player), lambda state: state.can_boots_clip_dw(player), 'or')
add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: state.can_reach('Dark Death Mountain (West Bottom)', 'Region', player) and state.has_Mirror(player))
else:
add_rule(world.get_entrance('South Dark World Teleporter', player), lambda state: state.has_Boots(player) and state.can_lift_rocks(player), 'or')
# Zora's Ledge via waterwalk setup.
add_rule(world.get_location('Zora\'s Ledge', player), lambda state: state.has_Boots(player), 'or')
def open_rules(world, player):
# softlock protection as you can reach the sewers small key door with a guard drop key
set_rule(world.get_location('Hyrule Castle - Boomerang Chest', player), lambda state: state.has_key('Small Key (Escape)', player))
@@ -1260,7 +1352,6 @@ def set_inverted_big_bomb_rules(world, player):
def set_bunny_rules(world, player):
# regions for the exits of multi-entrace caves/drops that bunny cannot pass
# Note spiral cave may be technically passible, but it would be too absurd to require since OHKO mode is a thing.
bunny_impassable_caves = ['Bumper Cave', 'Two Brothers House', 'Hookshot Cave', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Left)', 'Skull Woods First Section (Top)', 'Turtle Rock (Entrance)', 'Turtle Rock (Second Section)', 'Turtle Rock (Big Chest)', 'Skull Woods Second Section (Drop)',
@@ -1275,9 +1366,20 @@ def set_bunny_rules(world, player):
def options_to_access_rule(options):
return lambda state: any(rule(state) for rule in options)
def get_rule_to_add(region):
if not region.is_light_world:
return lambda state: state.has_Pearl(player)
def get_rule_to_add(region, location = None, connecting_entrance = None):
# In OWG, a location can potentially be superbunny-mirror accessible or
# bunny revival accessible.
if world.logic[player] == 'owglitches':
if region.name in OWGSets.get_invalid_bunny_revival_dungeons():
return lambda state: state.has_Mirror(player) or state.has_Pearl(player)
if not any([
None not in [location, connecting_entrance] and location.name in OWGSets.get_superbunny_accessible_locations() and connecting_entrance.name not in OWGSets.get_invalid_mirror_bunny_entrances_dw(),
not region.is_light_world]):
return lambda state: state.has_Pearl(player)
else:
if not region.is_light_world:
return lambda state: state.has_Pearl(player)
# in this case we are mixed region.
# we collect possible options.
@@ -1300,11 +1402,18 @@ def set_bunny_rules(world, player):
new_path = path + [entrance.access_rule]
seen.add(new_region)
if not new_region.is_light_world:
continue # we don't care about pure dark world entrances
# For OWG, establish superbunny and revival rules.
if world.logic[player] == 'owglitches' and entrance.name not in OWGSets.get_invalid_mirror_bunny_entrances_dw():
for location in entrance.connected_region.locations:
if location.name in OWGSets.get_superbunny_accessible_locations():
possible_options.append(lambda state: path_to_access_rule(new_path, entrance) and state.has_Mirror(player))
continue
else:
continue
if new_region.is_dark_world:
queue.append((new_region, new_path))
else:
# we have reached pure light world, so we have a new possible option
# we have reached pure light world or a dungeon, so we have a new possible option
possible_options.append(path_to_access_rule(new_path, entrance))
return options_to_access_rule(possible_options)
@@ -1321,24 +1430,32 @@ def set_bunny_rules(world, player):
if paradox_shop.is_dark_world:
add_rule(paradox_shop.entrances[0], get_rule_to_add(paradox_shop))
# Add requirements for all locations that are actually in the dark world, except those available to the bunny
for location in world.get_locations():
if location.player == player and location.parent_region.is_dark_world:
if location.name in bunny_accessible_locations:
continue
add_rule(location, get_rule_to_add(location.parent_region))
# Add requirements for all locations that are actually in the dark world, except those available to the bunny, including dungeon revival
for entrance in world.get_entrances():
if entrance.player == player and entrance.parent_region.is_dark_world:
if world.logic[player] == 'owglitches':
if entrance.connected_region.type == RegionType.Dungeon:
if entrance.connected_region.name in OWGSets.get_invalid_bunny_revival_dungeons():
add_rule(entrance, get_rule_to_add(entrance.connected_region, None, entrance))
continue
if entrance.connected_region.name == 'Turtle Rock (Entrance)':
add_rule(world.get_entrance('Turtle Rock Entrance Gap', player), get_rule_to_add(entrance.connected_region, None, entrance))
if entrance.name in OWGSets.get_invalid_mirror_bunny_entrances_dw():
continue
for location in entrance.connected_region.locations:
if world.logic[player] == 'owglitches' and entrance.name in OWGSets.get_invalid_mirror_bunny_entrances_dw():
add_rule(location, get_rule_to_add(entrance.connected_region, location, entrance))
continue
if location.name in bunny_accessible_locations:
continue
add_rule(location, get_rule_to_add(entrance.connected_region, location))
def set_inverted_bunny_rules(world, player):
# regions for the exits of multi-entrace caves/drops that bunny cannot pass
# Note spiral cave may be technically passible, but it would be too absurd to require since OHKO mode is a thing.
bunny_impassable_caves = ['Bumper Cave', 'Two Brothers House', 'Hookshot Cave', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Left)', 'Skull Woods First Section (Top)', 'Turtle Rock (Entrance)', 'Turtle Rock (Second Section)', 'Turtle Rock (Big Chest)', 'Skull Woods Second Section (Drop)',
'Turtle Rock (Eye Bridge)', 'Sewers', 'Pyramid', 'Spiral Cave (Top)', 'Desert Palace Main (Inner)', 'Fairy Ascension Cave (Drop)', 'The Sky']
bunny_accessible_locations = ['Link\'s Uncle', 'Sahasrahla', 'Sick Kid', 'Lost Woods Hideout', 'Lumberjack Tree', 'Checkerboard Cave', 'Potion Shop', 'Spectacle Rock Cave', 'Pyramid', 'Hype Cave - Generous Guy', 'Peg Cave', 'Bumper Cave Ledge', 'Dark Blacksmith Ruins', 'Bombos Tablet', 'Ether Tablet', 'Purple Chest']
bunny_accessible_locations = ['Link\'s Uncle', 'Sahasrahla', 'Sick Kid', 'Lost Woods Hideout', 'Lumberjack Tree', 'Checkerboard Cave', 'Potion Shop', 'Spectacle Rock Cave', 'Pyramid', 'Hype Cave - Generous Guy', 'Peg Cave', 'Bumper Cave Ledge', 'Dark Blacksmith Ruins', 'Bombos Tablet Ledge', 'Ether Tablet', 'Purple Chest']
def path_to_access_rule(path, entrance):
return lambda state: state.can_reach(entrance) and all(rule(state) for rule in path)
@@ -1346,9 +1463,19 @@ def set_inverted_bunny_rules(world, player):
def options_to_access_rule(options):
return lambda state: any(rule(state) for rule in options)
def get_rule_to_add(region):
if not region.is_dark_world:
return lambda state: state.has_Pearl(player)
def get_rule_to_add(region, location = None, connecting_entrance = None):
# In OWG, a location can potentially be superbunny-mirror accessible or
# bunny revival accessible.
if world.logic[player] == 'owglitches':
if region.name in OWGSets.get_invalid_bunny_revival_dungeons():
return lambda state: state.has_Mirror(player) or state.has_Pearl(player)
if not any([
None not in [location, connecting_entrance] and location.name in OWGSets.get_superbunny_accessible_locations() and connecting_entrance.name not in OWGSets.get_invalid_mirror_bunny_entrances_lw(),
not region.is_dark_world]):
return lambda state: state.has_Pearl(player)
else:
if not region.is_dark_world:
return lambda state: state.has_Pearl(player)
# in this case we are mixed region.
# we collect possible options.
@@ -1371,7 +1498,14 @@ def set_inverted_bunny_rules(world, player):
new_path = path + [entrance.access_rule]
seen.add(new_region)
if not new_region.is_dark_world:
continue # we don't care about pure light world entrances
# For OWG, establish superbunny and revival rules.
if world.logic[player] == 'owglitches' and entrance.name not in OWGSets.get_invalid_mirror_bunny_entrances_lw():
for location in entrance.connected_region.locations:
if location.name in OWGSets.get_superbunny_accessible_locations():
possible_options.append(lambda state: path_to_access_rule(new_path, entrance) and state.has_Mirror(player))
continue
else:
continue
if new_region.is_light_world:
queue.append((new_region, new_path))
else:
@@ -1392,13 +1526,22 @@ def set_inverted_bunny_rules(world, player):
if paradox_shop.is_light_world:
add_rule(paradox_shop.entrances[0], get_rule_to_add(paradox_shop))
# Add requirements for all locations that are actually in the light world, except those available to the bunny
for location in world.get_locations():
if location.player == player and location.parent_region.is_light_world:
if location.name in bunny_accessible_locations:
continue
add_rule(location, get_rule_to_add(location.parent_region))
# Add requirements for all locations that are actually in the light world, except those available to the bunny, including dungeon revival
for entrance in world.get_entrances():
if entrance.player == player and entrance.parent_region.is_light_world:
if world.logic[player] == 'owglitches':
if entrance.connected_region.type == RegionType.Dungeon:
if entrance.connected_region.name in OWGSets.get_invalid_bunny_revival_dungeons():
add_rule(entrance, get_rule_to_add(entrance.connected_region, None, entrance))
continue
if entrance.connected_region.name == 'Turtle Rock (Entrance)':
add_rule(world.get_entrance('Turtle Rock Entrance Gap', player), get_rule_to_add(entrance.connected_region, None, entrance))
if entrance.name in OWGSets.get_invalid_mirror_bunny_entrances_lw():
continue
for location in entrance.connected_region.locations:
if world.logic[player] == 'owglitches' and entrance.name in OWGSets.get_invalid_mirror_bunny_entrances_lw():
add_rule(location, get_rule_to_add(entrance.connected_region, location, entrance))
continue
if location.name in bunny_accessible_locations:
continue
add_rule(location, get_rule_to_add(entrance.connected_region, location))