Merge branch 'DoorDev' into DoorExtension

# Conflicts:
#	DoorShuffle.py
#	Doors.py
#	Regions.py
This commit is contained in:
randall.rupper
2019-09-16 14:02:32 -06:00
5 changed files with 222 additions and 78 deletions

View File

@@ -809,6 +809,8 @@ class DoorType(Enum):
Open = 5 Open = 5
Hole = 6 Hole = 6
Warp = 7 Warp = 7
Interior = 8
Logical = 9
@unique @unique
@@ -864,6 +866,7 @@ class Door(object):
self.landing = False # Indicates a door only for matching Holes/Warp # Todo: add to those self.landing = False # Indicates a door only for matching Holes/Warp # Todo: add to those
self.smallKey = False # There's a small key door on this side self.smallKey = False # There's a small key door on this side
self.bigKey = False # There's a big key door on this side self.bigKey = False # There's a big key door on this side
self.ugly = False # Indicates that it can't be seen from the front (e.g. back of a big key door)
def getAddress(self): def getAddress(self):
if self.type == DoorType.Normal: if self.type == DoorType.Normal:
@@ -933,17 +936,24 @@ class Boss(object):
return self.defeat_rule(state, self.player) return self.defeat_rule(state, self.player)
class Location(object): class Location(object):
def __init__(self, player, name='', address=None, crystal=False, hint_text=None, parent=None): def __init__(self, player, name='', address=None, crystal=False, hint_text=None, parent=None, forced_item=None):
self.name = name self.name = name
self.parent_region = parent self.parent_region = parent
self.item = None if forced_item is not None:
from Items import ItemFactory
self.forced_item = ItemFactory([forced_item], player)[0]
self.item = self.forced_item
self.event = True
else:
self.forced_item = None
self.item = None
self.event = False
self.crystal = crystal self.crystal = crystal
self.address = address self.address = address
self.spot_type = 'Location' self.spot_type = 'Location'
self.hint_text = hint_text if hint_text is not None else 'Hyrule' self.hint_text = hint_text if hint_text is not None else 'Hyrule'
self.recursion_count = 0 self.recursion_count = 0
self.staleness_count = 0 self.staleness_count = 0
self.event = False
self.locked = True self.locked = True
self.always_allow = lambda item, state: False self.always_allow = lambda item, state: False
self.access_rule = lambda state: True self.access_rule = lambda state: True

View File

@@ -153,7 +153,7 @@ def connect_one_way(world, entrancename, exitname, player):
# if these were already connected somewhere, remove the backreference # if these were already connected somewhere, remove the backreference
if entrance.connected_region is not None: if entrance.connected_region is not None:
entrance.connected_region.entrances.remove(entrance, player) entrance.connected_region.entrances.remove(entrance)
if ext.connected_region is not None: if ext.connected_region is not None:
ext.connected_region.entrances.remove(ext) ext.connected_region.entrances.remove(ext)
@@ -169,39 +169,69 @@ def connect_one_way(world, entrancename, exitname, player):
def within_dungeon(world, player): def within_dungeon(world, player):
dungeon_region_lists = [hyrule_castle_regions, eastern_regions, desert_regions] # TODO: The "starts" regions need access logic
for region_list in dungeon_region_lists: # Aerinon's note: I think this is handled already by ER Rules
shuffle_dungeon(world, player, region_list) dungeon_region_starts_es = ['Hyrule Castle Lobby', 'Hyrule Castle West Lobby', 'Hyrule Castle East Lobby', 'Sewers Secret Room']
dungeon_region_starts_ep = ['Eastern Lobby']
dungeon_region_lists = [(dungeon_region_starts_es, hyrule_castle_regions), (dungeon_region_starts_ep, eastern_regions)]
for start_list, region_list in dungeon_region_lists:
shuffle_dungeon(world, player, start_list, region_list)
def shuffle_dungeon(world, player, start_region_names, dungeon_region_names):
def shuffle_dungeon(world, player, dungeon_region_names):
logger = logging.getLogger('') logger = logging.getLogger('')
# Part one - generate a random layout
available_regions = [] available_regions = []
for name in dungeon_region_names: for name in [r for r in dungeon_region_names if r not in start_region_names]:
available_regions.append(world.get_region(name, player)) available_regions.append(world.get_region(name, player))
random.shuffle(available_regions) random.shuffle(available_regions)
# Pick a random region and make its doors the open set # "Ugly" doors are doors that we don't want to see from the front, because of some
# TODO: It would make sense to start with the entrance but I'm not sure it's needed. # sort of unsupported key door. To handle them, make a map of "ugly regions" and
# never link across them.
ugly_regions = {}
next_ugly_region = 1
# Add all start regions to the open set.
available_doors = [] available_doors = []
region = available_regions.pop() for name in start_region_names:
print("Starting in " + region.name) logger.info("Starting in %s", name)
available_doors.extend(get_doors(world, region, player)) for door in get_doors(world, world.get_region(name, player), player):
ugly_regions[door.name] = 0
available_doors.append(door)
# Loop until all available doors are used # Loop until all available doors are used
while len(available_doors) > 0: while len(available_doors) > 0:
# Pick a random available door to connect # Pick a random available door to connect, prioritizing ones that aren't blocked.
# TODO: Is there an existing "remove random from list" in this codebase? # This makes them either get picked up through another door (so they head deeper
# into the dungeon), or puts them late in the dungeon (so they probably are part
# of a loop). Panic if neither of these happens.
random.shuffle(available_doors) random.shuffle(available_doors)
available_doors.sort(key=lambda door: 1 if door.blocked else 2 if door.ugly else 0)
door = available_doors.pop() door = available_doors.pop()
logger.info('Linking %s', door.name) logger.info('Linking %s', door.name)
# Find an available region that has a compatible door # Find an available region that has a compatible door
connect_region, connect_door = find_compatible_door_in_regions(world, door, available_regions, player) connect_region, connect_door = find_compatible_door_in_regions(world, door, available_regions, player)
if connect_region is not None: # Also ignore compatible doors if they're blocked; these should only be used to
# create loops.
if connect_region is not None and not door.blocked:
logger.info(' Found new region %s via %s', connect_region.name, connect_door.name) logger.info(' Found new region %s via %s', connect_region.name, connect_door.name)
# Apply connection and add the new region's doors to the available list # Apply connection and add the new region's doors to the available list
maybe_connect_two_way(world, door, connect_door, player) maybe_connect_two_way(world, door, connect_door, player)
available_doors.extend(get_doors(world, connect_region, player)) # Figure out the new room's ugliness region
new_room_ugly_region = ugly_regions[door.name]
if connect_door.ugly:
next_ugly_region += 1
new_room_ugly_region = next_ugly_region
# Add the doors
for door in get_doors(world, connect_region, player):
ugly_regions[door.name] = new_room_ugly_region
available_doors.append(door)
# If an ugly door is anything but the connect door, panic and die
if door != connect_door and door.ugly:
logger.info('Failed because of ugly door, trying again.')
shuffle_dungeon(world, player, start_region_names, dungeon_region_names)
return
# We've used this region and door, so don't use them again # We've used this region and door, so don't use them again
available_regions.remove(connect_region) available_regions.remove(connect_region)
available_doors.remove(connect_door) available_doors.remove(connect_door)
@@ -214,15 +244,29 @@ def shuffle_dungeon(world, player, dungeon_region_names):
available_doors.remove(connect_door) available_doors.remove(connect_door)
# Check that we used everything, and retry if we failed # Check that we used everything, and retry if we failed
if len(available_regions) > 0 or len(available_doors) > 0: if len(available_regions) > 0 or len(available_doors) > 0:
logger.info('Failed to add all regions to dungeon, trying again.') logger.info('Failed to add all regions to dungeon, trying again.')
shuffle_dungeon(world, player, dungeon_region_names) shuffle_dungeon(world, player, start_region_names, dungeon_region_names)
return
# Connects a and b. Or don't if they're an unsupported connection type. # Connects a and b. Or don't if they're an unsupported connection type.
# TODO: This is gross, don't do it this way # TODO: This is gross, don't do it this way
def maybe_connect_two_way(world, a, b, player): def maybe_connect_two_way(world, a, b, player):
if a.type in [DoorType.Open, DoorType.StraightStairs, DoorType.Hole, DoorType.Warp]: # Return on unsupported types.
if a.type in [DoorType.Open, DoorType.StraightStairs, DoorType.Hole, DoorType.Warp, DoorType.Interior, DoorType.Logical]:
return return
connect_two_way(world, a.name, b.name, player) # Connect supported types
if a.type == DoorType.Normal or a.type == DoorType.SpiralStairs:
if a.blocked:
connect_one_way(world, b.name, a.name, player)
elif b.blocked:
connect_one_way(world, a.name, b.name, player)
else:
connect_two_way(world, a.name, b.name, player)
return
# If we failed to account for a type, panic
raise RuntimeError('Unknown door type ' + a.type.name)
# Finds a compatible door in regions, returns the region and door # Finds a compatible door in regions, returns the region and door
def find_compatible_door_in_regions(world, door, regions, player): def find_compatible_door_in_regions(world, door, regions, player):
@@ -232,9 +276,10 @@ def find_compatible_door_in_regions(world, door, regions, player):
return region, proposed_door return region, proposed_door
return None, None return None, None
def find_compatible_door_in_list(ugly_regions, world, door, doors, player):
def find_compatible_door_in_list(world, door, doors, player):
for proposed_door in doors: for proposed_door in doors:
if ugly_regions[door.name] != ugly_regions[proposed_door.name]:
continue
if doors_compatible(door, proposed_door): if doors_compatible(door, proposed_door):
return proposed_door return proposed_door
@@ -259,6 +304,10 @@ def doors_compatible(a, b):
return doors_fit_mandatory_pair(falldown_pits_as_doors, a, b) return doors_fit_mandatory_pair(falldown_pits_as_doors, a, b)
if a.type == DoorType.Warp: if a.type == DoorType.Warp:
return doors_fit_mandatory_pair(dungeon_warps_as_doors, a, b) return doors_fit_mandatory_pair(dungeon_warps_as_doors, a, b)
if a.type == DoorType.Interior:
return doors_fit_mandatory_pair(interior_doors, a, b)
if a.type == DoorType.Normal and (a.smallKey or b.smallKey or a.bigKey or b.bigKey):
return doors_fit_mandatory_pair(key_doors, a, b)
return a.direction == switch_dir(b.direction) return a.direction == switch_dir(b.direction)
@@ -936,28 +985,10 @@ def get_doors_ex(world, region, player):
mandatory_connections = [ mandatory_connections = [
('Hyrule Dungeon North Abyss Catwalk Dropdown', 'Hyrule Dungeon North Abyss'), ('Hyrule Dungeon North Abyss Catwalk Dropdown', 'Hyrule Dungeon North Abyss'),
# ('Hyrule Dungeon Key Door S', 'Hyrule Dungeon North Abyss'),
# ('Hyrule Dungeon Key Door N', 'Hyrule Dungeon Map Room'),
('Sewers Secret Room Push Block', 'Sewers Secret Room Blocked Path'), ('Sewers Secret Room Push Block', 'Sewers Secret Room Blocked Path'),
('Eastern Hint Tile Push Block', 'Eastern Compass Area') ('Eastern Hint Tile Push Block', 'Eastern Compass Area')
] ]
intratile_doors = [
('Hyrule Dungeon Key Door S', 'Hyrule Dungeon Key Door N'),
('Desert East Lobby WS', 'Desert East Wing ES'),
('Desert East Wing Key Door EN', 'Desert Compass Key Door WN'),
('Desert North Hall NW', 'Desert Map SW'),
('Desert North Hall NE', 'Desert Map SE'),
('Desert Sandworm Corner NE', 'Desert Bonk Torch SE'),
('Desert Sandworm Corner WS', 'Desert Circle of Pots ES'),
('Desert Circle of Pots NW', 'Desert Big Chest SW'),
('Desert West Wing WS', 'Desert West Lobby ES',),
('Desert Back Lobby NW', 'Desert Tiles 1 SW'),
('Desert Bridge SW', 'Desert Four Statues NW'),
('Desert Four Statues ES', 'Desert Beamos Hall WS',),
('Desert Tiles 2 NE', 'Desert Wall Slide SE'),
]
# todo: these path rules are more complicated I think... # todo: these path rules are more complicated I think...
# there may be a better way to do them if we randomize dungeon entrances # there may be a better way to do them if we randomize dungeon entrances
dungeon_paths = { dungeon_paths = {
@@ -981,16 +1012,20 @@ dungeon_paths = {
'Ganons Tower': [] 'Ganons Tower': []
} }
spiral_staircases = [('Hyrule Castle Back Hall Down Stairs', 'Hyrule Dungeon Map Room Up Stairs'), spiral_staircases = [
('Hyrule Dungeon Armory Down Stairs', 'Hyrule Dungeon Staircase Up Stairs'), ('Hyrule Castle Back Hall Down Stairs', 'Hyrule Dungeon Map Room Up Stairs'),
('Hyrule Dungeon Staircase Down Stairs', 'Hyrule Dungeon Cellblock Up Stairs'), ('Hyrule Dungeon Armory Down Stairs', 'Hyrule Dungeon Staircase Up Stairs'),
('Sewers Behind Tapestry Down Stairs', 'Sewers Rope Room Up Stairs'), ('Hyrule Dungeon Staircase Down Stairs', 'Hyrule Dungeon Cellblock Up Stairs'),
('Sewers Secret Room Up Stairs', 'Sewers Pull Switch Down Stairs'), ('Sewers Behind Tapestry Down Stairs', 'Sewers Rope Room Up Stairs'),
('Eastern Darkness Up Stairs', 'Eastern Attic Start Down Stairs'), ('Sewers Secret Room Up Stairs', 'Sewers Pull Switch Down Stairs'),
('Desert Tiles 1 Up Stairs', 'Desert Bridge Down Stairs')] ('Eastern Darkness Up Stairs', 'Eastern Attic Start Down Stairs'),
('Desert Tiles 1 Up Stairs', 'Desert Bridge Down Stairs')
]
straight_staircases = [('Hyrule Castle Lobby North Stairs', 'Hyrule Castle Throne Room South Stairs'), straight_staircases = [
('Sewers Rope Room North Stairs', 'Sewers Dark Cross South Stairs')] ('Hyrule Castle Lobby North Stairs', 'Hyrule Castle Throne Room South Stairs'),
('Sewers Rope Room North Stairs', 'Sewers Dark Cross South Stairs')
]
open_edges = [ open_edges = [
('Hyrule Dungeon North Abyss South Edge', 'Hyrule Dungeon South Abyss North Edge'), ('Hyrule Dungeon North Abyss South Edge', 'Hyrule Dungeon South Abyss North Edge'),
@@ -1013,6 +1048,32 @@ falldown_pits_as_doors = [('Eastern Courtyard Potholes', 'Eastern Fairy Landing'
dungeon_warps = [('Eastern Fairies\' Warp', 'Eastern Courtyard')] dungeon_warps = [('Eastern Fairies\' Warp', 'Eastern Courtyard')]
dungeon_warps_as_doors = [('Eastern Fairies\' Warp', 'Eastern Courtyard Warp End')] dungeon_warps_as_doors = [('Eastern Fairies\' Warp', 'Eastern Courtyard Warp End')]
interior_doors = [
('Hyrule Dungeon Armory Interior Key Door S', 'Hyrule Dungeon Armory Interior Key Door N'),
('Hyrule Dungeon Map Room Key Door S', 'Hyrule Dungeon North Abyss Key Door N'),
('Desert East Lobby WS', 'Desert East Wing ES'),
('Desert East Wing Key Door EN', 'Desert Compass Key Door WN'),
('Desert North Hall NW', 'Desert Map SW'),
('Desert North Hall NE', 'Desert Map SE'),
('Desert Sandworm Corner NE', 'Desert Bonk Torch SE'),
('Desert Sandworm Corner WS', 'Desert Circle of Pots ES'),
('Desert Circle of Pots NW', 'Desert Big Chest SW'),
('Desert West Wing WS', 'Desert West Lobby ES',),
('Desert Back Lobby NW', 'Desert Tiles 1 SW'),
('Desert Bridge SW', 'Desert Four Statues NW'),
('Desert Four Statues ES', 'Desert Beamos Hall WS',),
('Desert Tiles 2 NE', 'Desert Wall Slide SE'),
]
key_doors = [
('Sewers Key Rat Key Door N', 'Sewers Secret Room Key Door S'),
('Sewers Dark Cross Key Door N', 'Sewers Dark Cross Key Door S'),
('Eastern Dark Square Key Door WN', 'Eastern Cannonball Ledge Key Door EN'),
('Eastern Darkness Up Stairs', 'Eastern Attic Start Down Stairs'),
('Eastern Big Key NE', 'Eastern Compass Area SW'),
('Eastern Darkness S', 'Eastern Courtyard N')
]
default_door_connections = [ default_door_connections = [
('Hyrule Castle Lobby W', 'Hyrule Castle West Lobby E'), ('Hyrule Castle Lobby W', 'Hyrule Castle West Lobby E'),
('Hyrule Castle Lobby E', 'Hyrule Castle East Lobby W'), ('Hyrule Castle Lobby E', 'Hyrule Castle East Lobby W'),

View File

@@ -49,6 +49,8 @@ def create_doors(world, player):
# hyrule dungeon level # hyrule dungeon level
create_spiral_stairs(player, 'Hyrule Dungeon Map Room Up Stairs', DoorType.SpiralStairs, Direction.Up, 0x72, 0, LTH, A, 0x4b, 0xec), create_spiral_stairs(player, 'Hyrule Dungeon Map Room Up Stairs', DoorType.SpiralStairs, Direction.Up, 0x72, 0, LTH, A, 0x4b, 0xec),
create_small_key_door(player, 'Hyrule Dungeon Map Room Key Door S', DoorType.Interior, Direction.South, 0x71, Right, High),
create_small_key_door(player, 'Hyrule Dungeon North Abyss Key Door N', DoorType.Interior, Direction.North, 0x71, Right, High),
create_dir_door(player, 'Hyrule Dungeon North Abyss South Edge', DoorType.Open, Direction.South, 0x72, None, Low), create_dir_door(player, 'Hyrule Dungeon North Abyss South Edge', DoorType.Open, Direction.South, 0x72, None, Low),
create_dir_door(player, 'Hyrule Dungeon North Abyss Catwalk Edge', DoorType.Open, Direction.South, 0x72, None, High), create_dir_door(player, 'Hyrule Dungeon North Abyss Catwalk Edge', DoorType.Open, Direction.South, 0x72, None, High),
create_dir_door(player, 'Hyrule Dungeon South Abyss North Edge', DoorType.Open, Direction.North, 0x82, None, Low), create_dir_door(player, 'Hyrule Dungeon South Abyss North Edge', DoorType.Open, Direction.North, 0x82, None, Low),
@@ -58,20 +60,22 @@ def create_doors(world, player):
create_dir_door(player, 'Hyrule Dungeon Guardroom Catwalk Edge', DoorType.Open, Direction.East, 0x81, None, High), create_dir_door(player, 'Hyrule Dungeon Guardroom Catwalk Edge', DoorType.Open, Direction.East, 0x81, None, High),
create_dir_door(player, 'Hyrule Dungeon Guardroom Abyss Edge', DoorType.Open, Direction.West, 0x81, None, High), create_dir_door(player, 'Hyrule Dungeon Guardroom Abyss Edge', DoorType.Open, Direction.West, 0x81, None, High),
create_dir_door(player, 'Hyrule Dungeon Guardroom N', DoorType.Normal, Direction.North, 0x81, Left, Low), create_dir_door(player, 'Hyrule Dungeon Guardroom N', DoorType.Normal, Direction.North, 0x81, Left, Low),
create_dir_door(player, 'Hyrule Dungeon Armory S', DoorType.Normal, Direction.South, 0x71, Left, Low, 0x1), create_dir_door(player, 'Hyrule Dungeon Armory S', DoorType.Normal, Direction.South, 0x71, Left, Low),
create_small_key_door(player, 'Hyrule Dungeon Armory Interior Key Door N', DoorType.Interior, Direction.North, 0x71, Left, High),
create_small_key_door(player, 'Hyrule Dungeon Armory Interior Key Door S', DoorType.Interior, Direction.South, 0x71, Left, High),
create_spiral_stairs(player, 'Hyrule Dungeon Armory Down Stairs', DoorType.SpiralStairs, Direction.Down, 0x71, 0, HTL, A, 0x11, 0xa8, True), create_spiral_stairs(player, 'Hyrule Dungeon Armory Down Stairs', DoorType.SpiralStairs, Direction.Down, 0x71, 0, HTL, A, 0x11, 0xa8, True),
create_spiral_stairs(player, 'Hyrule Dungeon Staircase Up Stairs', DoorType.SpiralStairs, Direction.Up, 0x70, 2, LTH, A, 0x32, 0x94, True), create_spiral_stairs(player, 'Hyrule Dungeon Staircase Up Stairs', DoorType.SpiralStairs, Direction.Up, 0x70, 2, LTH, A, 0x32, 0x94, True),
create_spiral_stairs(player, 'Hyrule Dungeon Staircase Down Stairs', DoorType.SpiralStairs, Direction.Down, 0x70, 1, HTH, A, 0x11, 0x58), create_spiral_stairs(player, 'Hyrule Dungeon Staircase Down Stairs', DoorType.SpiralStairs, Direction.Down, 0x70, 1, HTH, A, 0x11, 0x58),
create_spiral_stairs(player, 'Hyrule Dungeon Cellblock Up Stairs', DoorType.SpiralStairs, Direction.Up, 0x80, 0, HTH, A, 0x1a, 0x44), create_spiral_stairs(player, 'Hyrule Dungeon Cellblock Up Stairs', DoorType.SpiralStairs, Direction.Up, 0x80, 0, HTH, A, 0x1a, 0x44),
# sewers # sewers
create_blocked_door(player, 'Sewers Behind Tapestry S', DoorType.Normal, Direction.South, 0x41, Mid, High, False, 0x2), create_blocked_door(player, 'Sewers Behind Tapestry S', DoorType.Normal, Direction.South, 0x41, Mid, High, False, False, 0x2),
create_spiral_stairs(player, 'Sewers Behind Tapestry Down Stairs', DoorType.SpiralStairs, Direction.Down, 0x41, 0, HTH, S, 0x12, 0xb0), create_spiral_stairs(player, 'Sewers Behind Tapestry Down Stairs', DoorType.SpiralStairs, Direction.Down, 0x41, 0, HTH, S, 0x12, 0xb0),
create_spiral_stairs(player, 'Sewers Rope Room Up Stairs', DoorType.SpiralStairs, Direction.Up, 0x42, 0, HTH, S, 0x1b, 0x9c), create_spiral_stairs(player, 'Sewers Rope Room Up Stairs', DoorType.SpiralStairs, Direction.Up, 0x42, 0, HTH, S, 0x1b, 0x9c),
create_dir_door(player, 'Sewers Rope Room North Stairs', DoorType.StraightStairs, Direction.North, 0x42, Mid, High), create_dir_door(player, 'Sewers Rope Room North Stairs', DoorType.StraightStairs, Direction.North, 0x42, Mid, High),
create_dir_door(player, 'Sewers Dark Cross South Stairs', DoorType.StraightStairs, Direction.South, 0x32, Mid, High), create_dir_door(player, 'Sewers Dark Cross South Stairs', DoorType.StraightStairs, Direction.South, 0x32, Mid, High),
create_dir_door(player, 'Sewers Dark Cross Key Door N', DoorType.Normal, Direction.North, 0x32, Mid, High), create_small_key_door(player, 'Sewers Dark Cross Key Door N', DoorType.Normal, Direction.North, 0x32, Mid, High),
create_dir_door(player, 'Sewers Dark Cross Key Door S', DoorType.Normal, Direction.South, 0x22, Mid, High), create_small_key_door(player, 'Sewers Dark Cross Key Door S', DoorType.Normal, Direction.South, 0x22, Mid, High),
create_dir_door(player, 'Sewers Water W', DoorType.Normal, Direction.West, 0x22, Bot, High), create_dir_door(player, 'Sewers Water W', DoorType.Normal, Direction.West, 0x22, Bot, High),
create_dir_door(player, 'Sewers Key Rat E', DoorType.Normal, Direction.East, 0x21, Bot, High), create_dir_door(player, 'Sewers Key Rat E', DoorType.Normal, Direction.East, 0x21, Bot, High),
create_small_key_door(player, 'Sewers Key Rat Key Door N', DoorType.Normal, Direction.North, 0x21, Right, High), create_small_key_door(player, 'Sewers Key Rat Key Door N', DoorType.Normal, Direction.North, 0x21, Right, High),
@@ -94,7 +98,7 @@ def create_doors(world, player):
create_dir_door(player, 'Eastern Map Area W', DoorType.Normal, Direction.West, 0xaa, Mid, High), create_dir_door(player, 'Eastern Map Area W', DoorType.Normal, Direction.West, 0xaa, Mid, High),
create_dir_door(player, 'Eastern Compass Area E', DoorType.Normal, Direction.East, 0xa8, Mid, High), create_dir_door(player, 'Eastern Compass Area E', DoorType.Normal, Direction.East, 0xa8, Mid, High),
create_dir_door(player, 'Eastern Compass Area EN', DoorType.Normal, Direction.East, 0xa8, Top, Low), create_dir_door(player, 'Eastern Compass Area EN', DoorType.Normal, Direction.East, 0xa8, Top, Low),
create_blocked_door(player, 'Eastern Compass Area SW', DoorType.Normal, Direction.South, 0xa8, Right, High), ugly_door(create_small_key_door(player, 'Eastern Compass Area SW', DoorType.Normal, Direction.South, 0xa8, Right, High, False, True)),
create_dir_door(player, 'Eastern Courtyard WN', DoorType.Normal, Direction.West, 0xa9, Top, Low), create_dir_door(player, 'Eastern Courtyard WN', DoorType.Normal, Direction.West, 0xa9, Top, Low),
create_dir_door(player, 'Eastern Courtyard EN', DoorType.Normal, Direction.East, 0xa9, Top, Low), create_dir_door(player, 'Eastern Courtyard EN', DoorType.Normal, Direction.East, 0xa9, Top, Low),
create_big_key_door(player, 'Eastern Courtyard N', DoorType.Normal, Direction.North, 0xa9, Mid, High), create_big_key_door(player, 'Eastern Courtyard N', DoorType.Normal, Direction.North, 0xa9, Mid, High),
@@ -104,13 +108,15 @@ def create_doors(world, player):
create_door(player, 'Eastern Courtyard Warp End', DoorType.Warp), create_door(player, 'Eastern Courtyard Warp End', DoorType.Warp),
create_dir_door(player, 'Eastern Map Valley WN', DoorType.Normal, Direction.West, 0xaa, Top, Low), create_dir_door(player, 'Eastern Map Valley WN', DoorType.Normal, Direction.West, 0xaa, Top, Low),
create_dir_door(player, 'Eastern Map Valley SW', DoorType.Normal, Direction.South, 0xaa, Left, High), create_dir_door(player, 'Eastern Map Valley SW', DoorType.Normal, Direction.South, 0xaa, Left, High),
create_small_key_door(player, 'Eastern Dark Square NW', DoorType.Normal, Direction.North, 0xba, Left, High), create_dir_door(player, 'Eastern Dark Square NW', DoorType.Normal, Direction.North, 0xba, Left, High),
create_small_key_door(player, 'Eastern Dark Square Key Door WN', DoorType.Normal, Direction.West, 0xba, Top, High), create_small_key_door(player, 'Eastern Dark Square Key Door WN', DoorType.Normal, Direction.West, 0xba, Top, High),
create_small_key_door(player, 'Eastern Big Key EN', DoorType.Normal, Direction.East, 0xb8, Top, High), create_dir_door(player, 'Eastern Big Key EN', DoorType.Normal, Direction.East, 0xb8, Top, High),
create_dir_door(player, 'Eastern Big Key NE', DoorType.Normal, Direction.North, 0xb8, Right, High), create_big_key_door(player, 'Eastern Big Key NE', DoorType.Normal, Direction.North, 0xb8, Right, High),
create_small_key_door(player, 'Eastern Darkness S', DoorType.Normal, Direction.South, 0x99, Mid, High), ugly_door(create_small_key_door(player, 'Eastern Darkness S', DoorType.Normal, Direction.South, 0x99, Mid, High)),
# Up is a keydoor and down is not. Only the up stairs should be considered a key door for now.
# Todo: add key door?
create_spiral_stairs(player, 'Eastern Darkness Up Stairs', DoorType.SpiralStairs, Direction.Up, 0x99, 0, HTH, Z, 0x1a, 0x6c, False, True), create_spiral_stairs(player, 'Eastern Darkness Up Stairs', DoorType.SpiralStairs, Direction.Up, 0x99, 0, HTH, Z, 0x1a, 0x6c, False, True),
create_spiral_stairs(player, 'Eastern Attic Start Down Stairs', DoorType.SpiralStairs, Direction.Down, 0xda, 0, HTH, Z, 0x11, 0x80, False, True), ugly_door(create_spiral_stairs(player, 'Eastern Attic Start Down Stairs', DoorType.SpiralStairs, Direction.Down, 0xda, 0, HTH, Z, 0x11, 0x80, False, True)),
create_dir_door(player, 'Eastern Attic Start WS', DoorType.Normal, Direction.West, 0xda, Bot, High), create_dir_door(player, 'Eastern Attic Start WS', DoorType.Normal, Direction.West, 0xda, Bot, High),
create_dir_door(player, 'Eastern Attic Switches ES', DoorType.Normal, Direction.East, 0xd9, Bot, High), create_dir_door(player, 'Eastern Attic Switches ES', DoorType.Normal, Direction.East, 0xd9, Bot, High),
create_dir_door(player, 'Eastern Attic Switches WS', DoorType.Normal, Direction.West, 0xd9, Bot, High), create_dir_door(player, 'Eastern Attic Switches WS', DoorType.Normal, Direction.West, 0xd9, Bot, High),
@@ -162,13 +168,13 @@ def create_big_key_door(player, name, type, direction, room, doorIndex, layer):
return d return d
def create_blocked_door(player, name, type, direction, room, doorIndex, layer, toggle=False, trap=0x0): def create_blocked_door(player, name, type, direction, room, doorIndex, layer, toggle=False, key=False, trap=0x0):
d = Door(player, name, type, direction, room, doorIndex, layer, toggle) d = Door(player, name, type, direction, room, doorIndex, layer, toggle)
d.blocked = True d.blocked = True
d.smallKey = key
d.trap = trap d.trap = trap
return d return d
def create_dir_door(player, name, type, direction, room, doorIndex, layer, trap=0x0): def create_dir_door(player, name, type, direction, room, doorIndex, layer, trap=0x0):
d = Door(player, name, type, direction, room, doorIndex, layer) d = Door(player, name, type, direction, room, doorIndex, layer)
d.trap = trap d.trap = trap
@@ -190,3 +196,7 @@ def create_spiral_stairs(player, name, type, direction, room,
d.zeroHzCam = zero_hz_cam d.zeroHzCam = zero_hz_cam
d.zeroVtCam = zero_vt_cam d.zeroVtCam = zero_vt_cam
return d return d
def ugly_door(door):
door.ugly = True
return door

View File

@@ -291,13 +291,14 @@ def create_regions(world, player):
create_dungeon_region(player, 'Hyrule Castle Back Hall', 'A dungeon', None, ['Hyrule Castle Back Hall E', 'Hyrule Castle Back Hall W', 'Hyrule Castle Back Hall Down Stairs']), create_dungeon_region(player, 'Hyrule Castle Back Hall', 'A dungeon', None, ['Hyrule Castle Back Hall E', 'Hyrule Castle Back Hall W', 'Hyrule Castle Back Hall Down Stairs']),
create_dungeon_region(player, 'Hyrule Castle Throne Room', 'A dungeon', None, ['Hyrule Castle Throne Room N', 'Hyrule Castle Throne Room South Stairs']), create_dungeon_region(player, 'Hyrule Castle Throne Room', 'A dungeon', None, ['Hyrule Castle Throne Room N', 'Hyrule Castle Throne Room South Stairs']),
create_dungeon_region(player, 'Hyrule Dungeon Map Room', 'A dungeon', ['Hyrule Castle - Map Chest'], ['Hyrule Dungeon Key Door S', 'Hyrule Dungeon Map Room Up Stairs']), create_dungeon_region(player, 'Hyrule Dungeon Map Room', 'A dungeon', ['Hyrule Castle - Map Chest', 'Hyrule Castle - Map Guard Key Drop'], ['Hyrule Dungeon Map Room Key Door S', 'Hyrule Dungeon Map Room Up Stairs']),
create_dungeon_region(player, 'Hyrule Dungeon North Abyss', 'A dungeon', None, ['Hyrule Dungeon North Abyss South Edge', 'Hyrule Dungeon Key Door N']), create_dungeon_region(player, 'Hyrule Dungeon North Abyss', 'A dungeon', None, ['Hyrule Dungeon North Abyss South Edge', 'Hyrule Dungeon North Abyss Key Door N']),
create_dungeon_region(player, 'Hyrule Dungeon North Abyss Catwalk', 'A dungeon', None, ['Hyrule Dungeon North Abyss Catwalk Edge', 'Hyrule Dungeon North Abyss Catwalk Dropdown']), create_dungeon_region(player, 'Hyrule Dungeon North Abyss Catwalk', 'A dungeon', None, ['Hyrule Dungeon North Abyss Catwalk Edge', 'Hyrule Dungeon North Abyss Catwalk Dropdown']),
create_dungeon_region(player, 'Hyrule Dungeon South Abyss', 'A dungeon', None, ['Hyrule Dungeon South Abyss North Edge', 'Hyrule Dungeon South Abyss West Edge']), create_dungeon_region(player, 'Hyrule Dungeon South Abyss', 'A dungeon', None, ['Hyrule Dungeon South Abyss North Edge', 'Hyrule Dungeon South Abyss West Edge']),
create_dungeon_region(player, 'Hyrule Dungeon South Abyss Catwalk', 'A dungeon', None, ['Hyrule Dungeon South Abyss Catwalk North Edge', 'Hyrule Dungeon South Abyss Catwalk West Edge']), create_dungeon_region(player, 'Hyrule Dungeon South Abyss Catwalk', 'A dungeon', None, ['Hyrule Dungeon South Abyss Catwalk North Edge', 'Hyrule Dungeon South Abyss Catwalk West Edge']),
create_dungeon_region(player, 'Hyrule Dungeon Guardroom', 'A dungeon', None, ['Hyrule Dungeon Guardroom Catwalk Edge', 'Hyrule Dungeon Guardroom Abyss Edge', 'Hyrule Dungeon Guardroom N']), create_dungeon_region(player, 'Hyrule Dungeon Guardroom', 'A dungeon', None, ['Hyrule Dungeon Guardroom Catwalk Edge', 'Hyrule Dungeon Guardroom Abyss Edge', 'Hyrule Dungeon Guardroom N']),
create_dungeon_region(player, 'Hyrule Dungeon Armory', 'A dungeon', ['Hyrule Castle - Boomerang Chest'], ['Hyrule Dungeon Armory S', 'Hyrule Dungeon Armory Down Stairs']), create_dungeon_region(player, 'Hyrule Dungeon Armory Main', 'A dungeon', ['Hyrule Castle - Boomerang Chest', 'Hyrule Castle - Boomerang Guard Key Drop'], ['Hyrule Dungeon Armory S', 'Hyrule Dungeon Armory Interior Key Door N']),
create_dungeon_region(player, 'Hyrule Dungeon Armory North Branch', 'A dungeon', None, ['Hyrule Dungeon Armory Interior Key Door S', 'Hyrule Dungeon Armory Down Stairs']),
create_dungeon_region(player, 'Hyrule Dungeon Staircase', 'A dungeon', None, ['Hyrule Dungeon Staircase Up Stairs', 'Hyrule Dungeon Staircase Down Stairs']), create_dungeon_region(player, 'Hyrule Dungeon Staircase', 'A dungeon', None, ['Hyrule Dungeon Staircase Up Stairs', 'Hyrule Dungeon Staircase Down Stairs']),
create_dungeon_region(player, 'Hyrule Dungeon Cellblock', 'A dungeon', ['Hyrule Castle - Zelda\'s Chest'], ['Hyrule Dungeon Cellblock Up Stairs']), create_dungeon_region(player, 'Hyrule Dungeon Cellblock', 'A dungeon', ['Hyrule Castle - Zelda\'s Chest'], ['Hyrule Dungeon Cellblock Up Stairs']),
@@ -324,9 +325,9 @@ def create_regions(world, player):
create_dungeon_region(player, 'Eastern Courtyard', 'Eastern Palace', ['Eastern Palace - Big Chest'], ['Eastern Courtyard WN', 'Eastern Courtyard EN', 'Eastern Courtyard N', 'Eastern Courtyard Potholes', 'Eastern Courtyard Warp End']), create_dungeon_region(player, 'Eastern Courtyard', 'Eastern Palace', ['Eastern Palace - Big Chest'], ['Eastern Courtyard WN', 'Eastern Courtyard EN', 'Eastern Courtyard N', 'Eastern Courtyard Potholes', 'Eastern Courtyard Warp End']),
create_dungeon_region(player, 'Eastern Fairies', 'Eastern Palace', None, ['Eastern Fairies\' Warp', 'Eastern Fairy Landing']), create_dungeon_region(player, 'Eastern Fairies', 'Eastern Palace', None, ['Eastern Fairies\' Warp', 'Eastern Fairy Landing']),
create_dungeon_region(player, 'Eastern Map Valley', 'Eastern Palace', None, ['Eastern Map Valley WN', 'Eastern Map Valley SW']), create_dungeon_region(player, 'Eastern Map Valley', 'Eastern Palace', None, ['Eastern Map Valley WN', 'Eastern Map Valley SW']),
create_dungeon_region(player, 'Eastern Dark Square', 'Eastern Palace', None, ['Eastern Dark Square NW', 'Eastern Dark Square Key Door WN']), create_dungeon_region(player, 'Eastern Dark Square', 'Eastern Palace', ['Eastern Palace - Dark Square Pot Key'], ['Eastern Dark Square NW', 'Eastern Dark Square Key Door WN']),
create_dungeon_region(player, 'Eastern Big Key', 'Eastern Palace', ['Eastern Palace - Big Key Chest'], ['Eastern Big Key EN', 'Eastern Big Key NE']), create_dungeon_region(player, 'Eastern Big Key', 'Eastern Palace', ['Eastern Palace - Big Key Chest'], ['Eastern Big Key EN', 'Eastern Big Key NE']),
create_dungeon_region(player, 'Eastern Darkness', 'Eastern Palace', None, ['Eastern Darkness S', 'Eastern Darkness Up Stairs']), create_dungeon_region(player, 'Eastern Darkness', 'Eastern Palace', ['Eastern Palace - Dark Eyegore Key Drop'], ['Eastern Darkness S', 'Eastern Darkness Up Stairs']),
create_dungeon_region(player, 'Eastern Attic Start', 'Eastern Palace', None, ['Eastern Attic Start Down Stairs', 'Eastern Attic Start WS']), create_dungeon_region(player, 'Eastern Attic Start', 'Eastern Palace', None, ['Eastern Attic Start Down Stairs', 'Eastern Attic Start WS']),
create_dungeon_region(player, 'Eastern Attic Switches', 'Eastern Palace', None, ['Eastern Attic Switches ES', 'Eastern Attic Switches WS']), create_dungeon_region(player, 'Eastern Attic Switches', 'Eastern Palace', None, ['Eastern Attic Switches ES', 'Eastern Attic Switches WS']),
create_dungeon_region(player, 'Eastern Eyegores', 'Eastern Palace', None, ['Eastern Eyegores ES', 'Eastern Eyegores NE']), create_dungeon_region(player, 'Eastern Eyegores', 'Eastern Palace', None, ['Eastern Eyegores ES', 'Eastern Eyegores NE']),
@@ -411,8 +412,11 @@ def _create_region(player, name, type, hint='Hyrule', locations=None, exits=None
for exit in exits: for exit in exits:
ret.exits.append(Entrance(player, exit, ret)) ret.exits.append(Entrance(player, exit, ret))
for location in locations: for location in locations:
address, crystal, hint_text = location_table[location] if location in key_only_locations:
ret.locations.append(Location(player, location, address, crystal, hint_text, ret)) ret.locations.append(Location(player, location, None, False, None, ret, key_only_locations[location]))
else:
address, crystal, hint_text = location_table[location]
ret.locations.append(Location(player, location, address, crystal, hint_text, ret))
return ret return ret
def mark_light_world_regions(world): def mark_light_world_regions(world):
@@ -478,6 +482,13 @@ default_shop_contents = {
'Potion Shop': [('Red Potion', 120), ('Green Potion', 60), ('Blue Potion', 160)], 'Potion Shop': [('Red Potion', 120), ('Green Potion', 60), ('Blue Potion', 160)],
} }
key_only_locations = {
'Hyrule Castle - Map Guard Key Drop': 'Small Key (Escape)',
'Hyrule Castle - Boomerang Guard Key Drop': 'Small Key (Escape)',
'Eastern Palace - Dark Square Pot Key': 'Small Key (Eastern Palace)',
'Eastern Palace - Dark Eyegore Key Drop': 'Small Key (Eastern Palace)',
}
location_table = {'Mushroom': (0x180013, False, 'in the woods'), location_table = {'Mushroom': (0x180013, False, 'in the woods'),
'Bottle Merchant': (0x2eb18, False, 'with a merchant'), 'Bottle Merchant': (0x2eb18, False, 'with a merchant'),
'Flute Spot': (0x18014a, False, 'underground'), 'Flute Spot': (0x18014a, False, 'underground'),

View File

@@ -258,14 +258,66 @@ def global_rules(world, player):
set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has_Pearl(player) and state.has_sword(player) and state.has_turtle_rock_medallion(player) and state.can_reach('Turtle Rock (Top)', 'Region', player)) # sword required to cast magic (!) set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has_Pearl(player) and state.has_sword(player) and state.has_turtle_rock_medallion(player) and state.can_reach('Turtle Rock (Top)', 'Region', player)) # sword required to cast magic (!)
set_rule(world.get_location('Mimic Cave', player), lambda state: state.has('Hammer', player)) set_rule(world.get_location('Mimic Cave', player), lambda state: state.has('Hammer', player))
# Start of door rando rules
# TODO: Do these need to flag off when door rando is off?
# TODO: Can these replace other rules?
# Hyrule Castle: Can't get keys from guards unless you can kill said guards.
add_rule(world.get_location('Hyrule Castle - Map Guard Key Drop', player), lambda state: state.can_kill_most_things(player))
add_rule(world.get_location('Hyrule Castle - Boomerang Guard Key Drop', player), lambda state: state.can_kill_most_things(player))
# Hyrule Castle: There are three keys and we don't know how we shuffled, so we
# need three keys to be accessible before you use any of these doors.
# TODO: Generate key rules in the shuffler. (But make sure this way works first.)
for door in ['Sewers Key Rat Key Door N', 'Sewers Secret Room Key Door S',
'Sewers Dark Cross Key Door N', 'Sewers Dark Cross Key Door S', 'Hyrule Dungeon Armory Interior Key Door N', 'Hyrule Dungeon Armory Interior Key Door S', 'Hyrule Dungeon Map Room Key Door S', 'Hyrule Dungeon North Abyss Key Door N']:
set_rule(world.get_entrance(door, player), lambda state: state.has_key('Small Key (Escape)', player, 3))
# Sewers: All sorts of things need lamps
# TODO: Need to play nice with other complicated lamp rules
set_rule(world.get_entrance('Sewers Behind Tapestry S', player), lambda state: state.has('Lamp', player))
set_rule(world.get_entrance('Sewers Behind Tapestry Down Stairs', player), lambda state: state.has('Lamp', player))
set_rule(world.get_entrance('Sewers Rope Room Up Stairs', player), lambda state: state.has('Lamp', player))
set_rule(world.get_entrance('Sewers Rope Room North Stairs', player), lambda state: state.has('Lamp', player))
set_rule(world.get_entrance('Sewers Dark Cross South Stairs', player), lambda state: state.has('Lamp', player))
set_rule(world.get_entrance('Sewers Dark Cross Key Door N', player), lambda state: state.has('Lamp', player))
set_rule(world.get_entrance('Sewers Dark Cross Key Door S', player), lambda state: state.has('Lamp', player))
set_rule(world.get_location('Sewers - Dark Cross', player), lambda state: state.has('Lamp', player))
set_rule(world.get_entrance('Sewers Water W', player), lambda state: state.has('Lamp', player))
set_rule(world.get_entrance('Sewers Key Rat E', player), lambda state: state.has('Lamp', player))
set_rule(world.get_entrance('Sewers Key Rat Key Door N', player), lambda state: state.has('Lamp', player))
# Eastern Palace
# The stalfos room and eyegore with a key can be killed with pots.
# Eastern Palace has dark rooms.
for location in ['Eastern Palace - Dark Square Pot Key', 'Eastern Palace - Dark Eyegore Key Drop']:
add_rule(world.get_location(location, player), lambda state: state.has('Lamp', player))
for door in ['Eastern Darkness S', 'Eastern Darkness Up Stairs', 'Eastern Dark Square NW', 'Eastern Dark Square Key Door WN']:
add_rule(world.get_entrance(door, player), lambda state: state.has('Lamp', player))
# Eyegore room needs a bow
set_rule(world.get_entrance('Eastern Eyegores NE', player), lambda state: state.can_shoot_arrows(player))
# Big key rules
set_rule(world.get_location('Eastern Palace - Big Chest', player), lambda state: state.has('Big Key (Eastern Palace)', player))
set_rule(world.get_entrance('Eastern Big Key NE', player), lambda state: state.has('Big Key (Eastern Palace)', player))
set_rule(world.get_entrance('Eastern Courtyard N', player), lambda state: state.has('Big Key (Eastern Palace)', player))
# There are two keys and we don't know how we shuffled, so careful with key doors.
# TODO: Generate key rules in the shuffler. (But make sure this way works first.)
for door in ['Eastern Dark Square Key Door WN', 'Eastern Cannonball Ledge Key Door EN', 'Eastern Darkness Up Stairs', 'Eastern Attic Start Down Stairs']:
set_rule(world.get_entrance(door, player), lambda state: state.has_key('Small Key (Eastern Palace)', player, 2))
# Boss rules. Same as below but no BK or arrow requirement.
set_rule(world.get_location('Eastern Palace - Boss', player), lambda state: world.get_location('Eastern Palace - Boss', player).parent_region.dungeon.boss.can_defeat(state))
set_rule(world.get_location('Eastern Palace - Prize', player), lambda state: world.get_location('Eastern Palace - Prize', player).parent_region.dungeon.boss.can_defeat(state))
# End of door rando rules.
# set_rule(world.get_entrance('Sewers Door', player), lambda state: state.has_key('Small Key (Escape)', player)) # set_rule(world.get_entrance('Sewers Door', player), lambda state: state.has_key('Small Key (Escape)', player))
# set_rule(world.get_entrance('Sewers Back Door', player), lambda state: state.has_key('Small Key (Escape)', player)) # set_rule(world.get_entrance('Sewers Back Door', player), lambda state: state.has_key('Small Key (Escape)', player))
set_rule(world.get_location('Eastern Palace - Big Chest', player), lambda state: state.has('Big Key (Eastern Palace)', player)) # set_rule(world.get_location('Eastern Palace - Boss', player), lambda state: state.can_shoot_arrows(player) and state.has('Big Key (Eastern Palace)', player) and world.get_location('Eastern Palace - Boss', player).parent_region.dungeon.boss.can_defeat(state))
set_rule(world.get_location('Eastern Palace - Boss', player), lambda state: state.can_shoot_arrows(player) and state.has('Big Key (Eastern Palace)', player) and world.get_location('Eastern Palace - Boss', player).parent_region.dungeon.boss.can_defeat(state)) # set_rule(world.get_location('Eastern Palace - Prize', player), lambda state: state.can_shoot_arrows(player) and state.has('Big Key (Eastern Palace)', player) and world.get_location('Eastern Palace - Prize', player).parent_region.dungeon.boss.can_defeat(state))
set_rule(world.get_location('Eastern Palace - Prize', player), lambda state: state.can_shoot_arrows(player) and state.has('Big Key (Eastern Palace)', player) and world.get_location('Eastern Palace - Prize', player).parent_region.dungeon.boss.can_defeat(state)) # for location in ['Eastern Palace - Boss', 'Eastern Palace - Big Chest']:
for location in ['Eastern Palace - Boss', 'Eastern Palace - Big Chest']: # forbid_item(world.get_location(location, player), 'Big Key (Eastern Palace)', player)
forbid_item(world.get_location(location, player), 'Big Key (Eastern Palace)', player)
set_rule(world.get_location('Desert Palace - Big Chest', player), lambda state: state.has('Big Key (Desert Palace)', player)) set_rule(world.get_location('Desert Palace - Big Chest', player), lambda state: state.has('Big Key (Desert Palace)', player))
set_rule(world.get_location('Desert Palace - Torch', player), lambda state: state.has_Boots(player)) set_rule(world.get_location('Desert Palace - Torch', player), lambda state: state.has_Boots(player))
@@ -951,7 +1003,7 @@ def swordless_rules(world, player):
set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has('Hammer', player)) set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has('Hammer', player))
def standard_rules(world, player): def standard_rules(world, player):
add_rule(world.get_entrance('Sewers Door', player), lambda state: state.can_kill_most_things(player)) # add_rule(world.get_entrance('Sewers Door', player), lambda state: state.can_kill_most_things(player))
set_rule(world.get_entrance('Hyrule Castle Exit (East)', player), lambda state: state.can_reach('Sanctuary', 'Region', player)) set_rule(world.get_entrance('Hyrule Castle Exit (East)', player), lambda state: state.can_reach('Sanctuary', 'Region', player))
set_rule(world.get_entrance('Hyrule Castle Exit (West)', player), lambda state: state.can_reach('Sanctuary', 'Region', player)) set_rule(world.get_entrance('Hyrule Castle Exit (West)', player), lambda state: state.can_reach('Sanctuary', 'Region', player))