Merge pull request #12 from aerinon/Swamp

Swamp, Skull and TT
This commit is contained in:
aerinon
2019-10-31 11:20:50 -06:00
committed by GitHub
14 changed files with 2621 additions and 706 deletions
+108 -13
View File
@@ -88,6 +88,9 @@ class World(object):
self.paired_doors = {} self.paired_doors = {}
self.rooms = [] self.rooms = []
self._room_cache = {} self._room_cache = {}
self.dungeon_layouts = {}
self.inaccessible_regions = []
self.key_logic = {}
def intialize_regions(self): def intialize_regions(self):
for region in self.regions: for region in self.regions:
@@ -326,7 +329,7 @@ class World(object):
sphere = [] sphere = []
# build up spheres of collection radius. Everything in each sphere is independent from each other in dependencies and only depends on lower spheres # build up spheres of collection radius. Everything in each sphere is independent from each other in dependencies and only depends on lower spheres
for location in prog_locations: for location in prog_locations:
if location.can_reach(state): if location.can_reach(state) and state.not_flooding_a_key(state.world, location):
sphere.append(location) sphere.append(location)
if not sphere: if not sphere:
@@ -401,6 +404,7 @@ class CollectionState(object):
if locations is None: if locations is None:
locations = self.world.get_filled_locations() locations = self.world.get_filled_locations()
reachable_events = [location for location in locations if location.event and (not key_only or location.item.key) and location.can_reach(self)] reachable_events = [location for location in locations if location.event and (not key_only or location.item.key) and location.can_reach(self)]
reachable_events = self._do_not_flood_the_keys(reachable_events)
for event in reachable_events: for event in reachable_events:
if (event.name, event.player) not in self.events: if (event.name, event.player) not in self.events:
self.events.append((event.name, event.player)) self.events.append((event.name, event.player))
@@ -408,6 +412,20 @@ class CollectionState(object):
new_locations = len(reachable_events) > checked_locations new_locations = len(reachable_events) > checked_locations
checked_locations = len(reachable_events) checked_locations = len(reachable_events)
def _do_not_flood_the_keys(self, reachable_events):
adjusted_checks = list(reachable_events)
for event in reachable_events:
if event.name in flooded_keys.keys() and self.world.get_location(flooded_keys[event.name], event.player) not in reachable_events:
adjusted_checks.remove(event)
if len(adjusted_checks) < len(reachable_events):
return adjusted_checks
return reachable_events
def not_flooding_a_key(self, world, location):
if location.name in flooded_keys.keys():
return world.get_location(flooded_keys[location.name], location.player) in self.locations_checked
return True
def has(self, item, player, count=1): def has(self, item, player, count=1):
if count == 1: if count == 1:
return (item, player) in self.prog_items return (item, player) in self.prog_items
@@ -850,34 +868,79 @@ class Direction(Enum):
Down = 5 Down = 5
class Polarity:
def __init__(self):
self.vector = [0, 0, 0]
def __len__(self):
return len(self.vector)
def __add__(self, other):
result = Polarity()
for i in range(len(self.vector)):
result.vector[i] = pol_add[pol_idx_2[i]](self.vector[i], other.vector[i])
return result
def __iadd__(self, other):
for i in range(len(self.vector)):
self.vector[i] = pol_add[pol_idx_2[i]](self.vector[i], other.vector[i])
return self
def __getitem__(self, item):
return self.vector[item]
def is_neutral(self):
for i in range(len(self.vector)):
if self.vector[i] != 0:
return False
return True
pol_idx = { pol_idx = {
Direction.North: (0, 'Pos'), Direction.North: (0, 'Pos'),
Direction.South: (0, 'Neg'), Direction.South: (0, 'Neg'),
Direction.East: (1, 'Pos'), Direction.East: (1, 'Pos'),
Direction.West: (1, 'Neg'), Direction.West: (1, 'Neg'),
Direction.Up: (2, 'Pos'), Direction.Up: (2, 'Mod'),
Direction.Down: (2, 'Neg') Direction.Down: (2, 'Mod')
}
pol_idx_2 = {
0: 'Add',
1: 'Add',
2: 'Mod'
} }
pol_inc = { pol_inc = {
'Pos': lambda x: x + 1, 'Pos': lambda x: x + 1,
'Neg': lambda x: x - 1, 'Neg': lambda x: x - 1,
'Mod': lambda x: (x + 1) % 2
} }
pol_add = {
'Add': lambda x, y: x + y,
'Mod': lambda x, y: (x + y) % 2
}
@unique
class CrystalBarrier(Enum):
Null = 1 # no special requirement
Blue = 2 # blue must be down and explore state set to Blue
Orange = 3 # orange must be down and explore state set to Orange
Either = 4 # you choose to leave this room in Either state
class Door(object): class Door(object):
def __init__(self, player, name, type, direction, roomIndex, doorIndex, layer, toggle=False): def __init__(self, player, name, type):
self.player = player self.player = player
self.name = name self.name = name
self.type = type self.type = type
self.direction = direction self.direction = None
# rom properties # rom properties
self.roomIndex = roomIndex self.roomIndex = -1
# 0,1,2 + Direction (N:0, W:3, S:6, E:9) for normal # 0,1,2 + Direction (N:0, W:3, S:6, E:9) for normal
# 0-4 for spiral offset thing # 0-4 for spiral offset thing
self.doorIndex = doorIndex self.doorIndex = -1
self.layer = layer # 0 for normal floor, 1 for the inset layer self.layer = -1 # 0 for normal floor, 1 for the inset layer
self.toggle = toggle self.toggle = False
self.trapFlag = 0x0 self.trapFlag = 0x0
self.quadrant = 2 self.quadrant = 2
self.shiftX = 78 self.shiftX = 78
@@ -889,10 +952,13 @@ class Door(object):
# logical properties # logical properties
# self.connected = False # combine with Dest? # self.connected = False # combine with Dest?
self.dest = None self.dest = None
self.blocked = False # Indicates if the door is normally blocked off. (Sanc door or always closed) self.blocked = False # Indicates if the door is normally blocked off as an exit. (Sanc door or always closed)
self.stonewall = False # Indicate that the door cannot be enter until exited (Desert Torches, PoD Eye Statue)
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) self.ugly = False # Indicates that it can't be seen from the front (e.g. back of a big key door)
self.crystal = CrystalBarrier.Null # How your crystal state changes if you use this door
self.req_event = None # if a dungeon event is required for this door - swamp palace mostly
def getAddress(self): def getAddress(self):
if self.type == DoorType.Normal: if self.type == DoorType.Normal:
@@ -943,6 +1009,10 @@ class Door(object):
self.blocked = True self.blocked = True
return self return self
def no_entrance(self):
self.stonewall = True
return self
def trap(self, trapFlag): def trap(self, trapFlag):
self.trapFlag = trapFlag self.trapFlag = trapFlag
return self return self
@@ -951,6 +1021,24 @@ class Door(object):
self.doorListPos = pos self.doorListPos = pos
return self return self
def event(self, event):
self.req_event = event
return self
def barrier(self, crystal):
self.crystal = crystal
return self
def c_switch(self):
self.crystal = CrystalBarrier.Either
return self
def __eq__(self, other):
return isinstance(other, self.__class__) and self.name == other.name
def __hash__(self):
return hash(self.name)
def __str__(self): def __str__(self):
return str(self.__unicode__()) return str(self.__unicode__())
@@ -967,11 +1055,11 @@ class Sector(object):
# todo: make these lazy init? - when do you invalidate them # todo: make these lazy init? - when do you invalidate them
def polarity(self): def polarity(self):
polarity = [0, 0, 0] pol = Polarity()
for door in self.outstanding_doors: for door in self.outstanding_doors:
idx, inc = pol_idx[door.direction] idx, inc = pol_idx[door.direction]
polarity[idx] = pol_inc[inc](polarity[idx]) pol.vector[idx] = pol_inc[inc](pol.vector[idx])
return polarity return pol
def magnitude(self): def magnitude(self):
magnitude = [0, 0, 0] magnitude = [0, 0, 0]
@@ -1006,6 +1094,7 @@ class Location(object):
from Items import ItemFactory from Items import ItemFactory
self.forced_item = ItemFactory([forced_item], player)[0] self.forced_item = ItemFactory([forced_item], player)[0]
self.item = self.forced_item self.item = self.forced_item
self.item.location = self
self.event = True self.event = True
else: else:
self.forced_item = None self.forced_item = None
@@ -1345,3 +1434,9 @@ class Spoiler(object):
path_listings.append("{}\n {}".format(location, "\n => ".join(path_lines))) path_listings.append("{}\n {}".format(location, "\n => ".join(path_lines)))
outfile.write('\n'.join(path_listings)) outfile.write('\n'.join(path_listings))
flooded_keys = {
'Trench 1 Switch': 'Swamp Palace - Trench 1 Pot Key',
'Trench 2 Switch': 'Swamp Palace - Trench 2 Pot Key'
}
+832 -190
View File
File diff suppressed because it is too large Load Diff
+594 -332
View File
@@ -1,5 +1,5 @@
from BaseClasses import Door, DoorType, Direction from BaseClasses import Door, DoorType, Direction, CrystalBarrier
from RoomData import PairedDoor from RoomData import PairedDoor
# constants # constants
@@ -22,310 +22,612 @@ HTH = 0 # High to High 00
HTL = 1 # High to Low 01 HTL = 1 # High to Low 01
LTH = 2 # Low to High 10 LTH = 2 # Low to High 10
LTL = 3 # Low to Low 11 LTL = 3 # Low to Low 11
# Type Shortcuts
Nrml = DoorType.Normal
StrS = DoorType.StraightStairs
Hole = DoorType.Hole
Warp = DoorType.Warp
Sprl = DoorType.SpiralStairs
Lddr = DoorType.Ladder
Open = DoorType.Open
Lgcl = DoorType.Logical
Intr = DoorType.Interior
def create_doors(world, player): def create_doors(world, player):
world.doors += [ world.doors += [
# hyrule castle # hyrule castle
toggle(create_dir_door(player, 'Hyrule Castle Lobby W', DoorType.Normal, Direction.West, 0x61, Mid, High)).pos(0), create_door(player, 'Hyrule Castle Lobby W', Nrml).dir(Direction.West, 0x61, Mid, High).toggler().pos(0),
toggle(create_dir_door(player, 'Hyrule Castle Lobby E', DoorType.Normal, Direction.East, 0x61, Mid, High)).pos(2), create_door(player, 'Hyrule Castle Lobby E', Nrml).dir(Direction.East, 0x61, Mid, High).toggler().pos(2),
create_dir_door(player, 'Hyrule Castle Lobby WN', DoorType.Normal, Direction.West, 0x61, Top, High).pos(1), create_door(player, 'Hyrule Castle Lobby WN', Nrml).dir(Direction.West, 0x61, Top, High).pos(1),
create_dir_door(player, 'Hyrule Castle Lobby North Stairs', DoorType.StraightStairs, Direction.North, 0x61, Mid, High), create_door(player, 'Hyrule Castle Lobby North Stairs', StrS).dir(Direction.North, 0x61, Mid, High),
toggle(create_dir_door(player, 'Hyrule Castle West Lobby E', DoorType.Normal, Direction.East, 0x60, Mid, Low)).pos(1), create_door(player, 'Hyrule Castle West Lobby E', Nrml).dir(Direction.East, 0x60, Mid, Low).toggler().pos(1),
create_dir_door(player, 'Hyrule Castle West Lobby N', DoorType.Normal, Direction.North, 0x60, Right, Low).pos(0), create_door(player, 'Hyrule Castle West Lobby N', Nrml).dir(Direction.North, 0x60, Right, Low).pos(0),
create_dir_door(player, 'Hyrule Castle West Lobby EN', DoorType.Normal, Direction.East, 0x60, Top, High).pos(3), create_door(player, 'Hyrule Castle West Lobby EN', Nrml).dir(Direction.East, 0x60, Top, High).pos(3),
toggle(create_dir_door(player, 'Hyrule Castle East Lobby W', DoorType.Normal, Direction.West, 0x62, Mid, Low)).pos(0), create_door(player, 'Hyrule Castle East Lobby W', Nrml).dir(Direction.West, 0x62, Mid, Low).toggler().pos(0),
create_dir_door(player, 'Hyrule Castle East Lobby N', DoorType.Normal, Direction.North, 0x62, Mid, High).pos(3), create_door(player, 'Hyrule Castle East Lobby N', Nrml).dir(Direction.North, 0x62, Mid, High).pos(3),
create_dir_door(player, 'Hyrule Castle East Lobby NW', DoorType.Normal, Direction.North, 0x62, Left, Low).pos(2), create_door(player, 'Hyrule Castle East Lobby NW', Nrml).dir(Direction.North, 0x62, Left, Low).pos(2),
create_dir_door(player, 'Hyrule Castle East Hall W', DoorType.Normal, Direction.West, 0x52, Top, Low).pos(0), create_door(player, 'Hyrule Castle East Hall W', Nrml).dir(Direction.West, 0x52, Top, Low).pos(0),
create_dir_door(player, 'Hyrule Castle East Hall S', DoorType.Normal, Direction.South, 0x52, Mid, High).pos(2), create_door(player, 'Hyrule Castle East Hall S', Nrml).dir(Direction.South, 0x52, Mid, High).pos(2),
create_dir_door(player, 'Hyrule Castle East Hall SW', DoorType.Normal, Direction.South, 0x52, Left, Low).pos(1), create_door(player, 'Hyrule Castle East Hall SW', Nrml).dir(Direction.South, 0x52, Left, Low).pos(1),
create_dir_door(player, 'Hyrule Castle West Hall E', DoorType.Normal, Direction.East, 0x50, Top, Low).pos(0), create_door(player, 'Hyrule Castle West Hall E', Nrml).dir(Direction.East, 0x50, Top, Low).pos(0),
create_dir_door(player, 'Hyrule Castle West Hall S', DoorType.Normal, Direction.South, 0x50, Right, Low).pos(1), create_door(player, 'Hyrule Castle West Hall S', Nrml).dir(Direction.South, 0x50, Right, Low).pos(1),
create_dir_door(player, 'Hyrule Castle Back Hall W', DoorType.Normal, Direction.West, 0x01, Top, Low).pos(0), create_door(player, 'Hyrule Castle Back Hall W', Nrml).dir(Direction.West, 0x01, Top, Low).pos(0),
create_dir_door(player, 'Hyrule Castle Back Hall E', DoorType.Normal, Direction.East, 0x01, Top, Low).pos(1), create_door(player, 'Hyrule Castle Back Hall E', Nrml).dir(Direction.East, 0x01, Top, Low).pos(1),
create_spiral_stairs(player, 'Hyrule Castle Back Hall Down Stairs', DoorType.SpiralStairs, Direction.Down, 0x01, 0, HTL, A, 0x2a, 0x00), create_door(player, 'Hyrule Castle Back Hall Down Stairs', Sprl).dir(Direction.Down, 0x01, 0, HTL).ss(A, 0x2a, 0x00),
create_dir_door(player, 'Hyrule Castle Throne Room N', DoorType.Normal, Direction.North, 0x51, Mid, High).pos(1), create_door(player, 'Hyrule Castle Throne Room N', Nrml).dir(Direction.North, 0x51, Mid, High).pos(1),
create_dir_door(player, 'Hyrule Castle Throne Room South Stairs', DoorType.StraightStairs, Direction.South, 0x51, Mid, Low), create_door(player, 'Hyrule Castle Throne Room South Stairs', StrS).dir(Direction.South, 0x51, Mid, Low),
# 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_door(player, 'Hyrule Dungeon Map Room Up Stairs', Sprl).dir(Direction.Up, 0x72, 0, LTH).ss(A, 0x4b, 0xec),
small_key(create_dir_door(player, 'Hyrule Dungeon Map Room Key Door S', DoorType.Interior, Direction.South, 0x72, Mid, High)).pos(0), create_door(player, 'Hyrule Dungeon Map Room Key Door S', Intr).dir(Direction.South, 0x72, Mid, High).small_key().pos(0),
small_key(create_dir_door(player, 'Hyrule Dungeon North Abyss Key Door N', DoorType.Interior, Direction.North, 0x72, Mid, High)).pos(0), create_door(player, 'Hyrule Dungeon North Abyss Key Door N', Intr).dir(Direction.North, 0x72, Mid, High).small_key().pos(0),
create_dir_door(player, 'Hyrule Dungeon North Abyss South Edge', DoorType.Open, Direction.South, 0x72, None, Low), create_door(player, 'Hyrule Dungeon North Abyss South Edge', Open).dir(Direction.South, 0x72, None, Low),
create_dir_door(player, 'Hyrule Dungeon North Abyss Catwalk Edge', DoorType.Open, Direction.South, 0x72, None, High), create_door(player, 'Hyrule Dungeon North Abyss Catwalk Edge', Open).dir(Direction.South, 0x72, None, High),
create_door(player, 'Hyrule Dungeon North Abyss Catwalk Dropdown', DoorType.Logical), create_door(player, 'Hyrule Dungeon North Abyss Catwalk Dropdown', Lgcl),
create_dir_door(player, 'Hyrule Dungeon South Abyss North Edge', DoorType.Open, Direction.North, 0x82, None, Low), create_door(player, 'Hyrule Dungeon South Abyss North Edge', Open).dir(Direction.North, 0x82, None, Low),
create_dir_door(player, 'Hyrule Dungeon South Abyss West Edge', DoorType.Open, Direction.West, 0x82, None, Low), create_door(player, 'Hyrule Dungeon South Abyss West Edge', Open).dir(Direction.West, 0x82, None, Low),
create_dir_door(player, 'Hyrule Dungeon South Abyss Catwalk North Edge', DoorType.Open, Direction.North, 0x82, None, High), create_door(player, 'Hyrule Dungeon South Abyss Catwalk North Edge', Open).dir(Direction.North, 0x82, None, High),
create_dir_door(player, 'Hyrule Dungeon South Abyss Catwalk West Edge', DoorType.Open, Direction.West, 0x82, None, High), create_door(player, 'Hyrule Dungeon South Abyss Catwalk West Edge', Open).dir(Direction.West, 0x82, None, High),
create_dir_door(player, 'Hyrule Dungeon Guardroom Catwalk Edge', DoorType.Open, Direction.East, 0x81, None, High), create_door(player, 'Hyrule Dungeon Guardroom Catwalk Edge', Open).dir(Direction.East, 0x81, None, High),
create_dir_door(player, 'Hyrule Dungeon Guardroom Abyss Edge', DoorType.Open, Direction.West, 0x81, None, High), create_door(player, 'Hyrule Dungeon Guardroom Abyss Edge', Open).dir(Direction.West, 0x81, None, High),
create_dir_door(player, 'Hyrule Dungeon Guardroom N', DoorType.Normal, Direction.North, 0x81, Left, Low).pos(0), create_door(player, 'Hyrule Dungeon Guardroom N', Nrml).dir(Direction.North, 0x81, Left, Low).pos(0),
trap(create_dir_door(player, 'Hyrule Dungeon Armory S', DoorType.Normal, Direction.South, 0x71, Left, Low), 0x2).pos(1), create_door(player, 'Hyrule Dungeon Armory S', Nrml).dir(Direction.South, 0x71, Left, Low).trap(0x2).pos(1),
small_key(create_dir_door(player, 'Hyrule Dungeon Armory Interior Key Door N', DoorType.Interior, Direction.North, 0x71, Left, High)).pos(0), create_door(player, 'Hyrule Dungeon Armory Interior Key Door N', Intr).dir(Direction.North, 0x71, Left, High).small_key().pos(0),
small_key(create_dir_door(player, 'Hyrule Dungeon Armory Interior Key Door S', DoorType.Interior, Direction.South, 0x71, Left, High)).pos(0), create_door(player, 'Hyrule Dungeon Armory Interior Key Door S', Intr).dir(Direction.South, 0x71, Left, High).small_key().pos(0),
create_spiral_stairs(player, 'Hyrule Dungeon Armory Down Stairs', DoorType.SpiralStairs, Direction.Down, 0x71, 0, HTL, A, 0x11, 0xa8, True), create_door(player, 'Hyrule Dungeon Armory Down Stairs', Sprl).dir(Direction.Down, 0x71, 0, HTL).ss(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_door(player, 'Hyrule Dungeon Staircase Up Stairs', Sprl).dir(Direction.Up, 0x70, 2, LTH).ss(A, 0x32, 0x94, True),
create_spiral_stairs(player, 'Hyrule Dungeon Staircase Down Stairs', DoorType.SpiralStairs, Direction.Down, 0x70, 1, HTH, A, 0x11, 0x58), create_door(player, 'Hyrule Dungeon Staircase Down Stairs', Sprl).dir(Direction.Down, 0x70, 1, HTH).ss(A, 0x11, 0x58),
create_spiral_stairs(player, 'Hyrule Dungeon Cellblock Up Stairs', DoorType.SpiralStairs, Direction.Up, 0x80, 0, HTH, A, 0x1a, 0x44), create_door(player, 'Hyrule Dungeon Cellblock Up Stairs', Sprl).dir(Direction.Up, 0x80, 0, HTH).ss(A, 0x1a, 0x44),
# sewers # sewers
trap(blocked(create_dir_door(player, 'Sewers Behind Tapestry S', DoorType.Normal, Direction.South, 0x41, Mid, High)), 0x4).pos(0), create_door(player, 'Sewers Behind Tapestry S', Nrml).dir(Direction.South, 0x41, Mid, High).no_exit().trap(0x4).pos(0),
create_spiral_stairs(player, 'Sewers Behind Tapestry Down Stairs', DoorType.SpiralStairs, Direction.Down, 0x41, 0, HTH, S, 0x12, 0xb0), create_door(player, 'Sewers Behind Tapestry Down Stairs', Sprl).dir(Direction.Down, 0x41, 0, HTH).ss(S, 0x12, 0xb0),
create_spiral_stairs(player, 'Sewers Rope Room Up Stairs', DoorType.SpiralStairs, Direction.Up, 0x42, 0, HTH, S, 0x1b, 0x9c), create_door(player, 'Sewers Rope Room Up Stairs', Sprl).dir(Direction.Up, 0x42, 0, HTH).ss(S, 0x1b, 0x9c),
create_dir_door(player, 'Sewers Rope Room North Stairs', DoorType.StraightStairs, Direction.North, 0x42, Mid, High), create_door(player, 'Sewers Rope Room North Stairs', StrS).dir(Direction.North, 0x42, Mid, High),
create_dir_door(player, 'Sewers Dark Cross South Stairs', DoorType.StraightStairs, Direction.South, 0x32, Mid, High), create_door(player, 'Sewers Dark Cross South Stairs', StrS).dir(Direction.South, 0x32, Mid, High),
small_key(create_dir_door(player, 'Sewers Dark Cross Key Door N', DoorType.Normal, Direction.North, 0x32, Mid, High)).pos(0), create_door(player, 'Sewers Dark Cross Key Door N', Nrml).dir(Direction.North, 0x32, Mid, High).small_key().pos(0),
small_key(create_dir_door(player, 'Sewers Dark Cross Key Door S', DoorType.Normal, Direction.South, 0x22, Mid, High)).pos(0), create_door(player, 'Sewers Dark Cross Key Door S', Nrml).dir(Direction.South, 0x22, Mid, High).small_key().pos(0),
create_dir_door(player, 'Sewers Water W', DoorType.Normal, Direction.West, 0x22, Bot, High).pos(1), create_door(player, 'Sewers Water W', Nrml).dir(Direction.West, 0x22, Bot, High).pos(1),
create_dir_door(player, 'Sewers Key Rat E', DoorType.Normal, Direction.East, 0x21, Bot, High).pos(1), create_door(player, 'Sewers Key Rat E', Nrml).dir(Direction.East, 0x21, Bot, High).pos(1),
small_key(create_dir_door(player, 'Sewers Key Rat Key Door N', DoorType.Normal, Direction.North, 0x21, Right, High)).pos(0), create_door(player, 'Sewers Key Rat Key Door N', Nrml).dir(Direction.North, 0x21, Right, High).small_key().pos(0),
small_key(create_dir_door(player, 'Sewers Secret Room Key Door S', DoorType.Normal, Direction.South, 0x11, Right, High)).pos(2), create_door(player, 'Sewers Secret Room Key Door S', Nrml).dir(Direction.South, 0x11, Right, High).small_key().pos(2),
create_door(player, 'Sewers Secret Room Push Block', DoorType.Logical), create_door(player, 'Sewers Secret Room Push Block', Lgcl),
create_spiral_stairs(player, 'Sewers Secret Room Up Stairs', DoorType.SpiralStairs, Direction.Up, 0x11, 0, LTH, S, 0x33, 0x6c, True), create_door(player, 'Sewers Secret Room Up Stairs', Sprl).dir(Direction.Up, 0x11, 0, LTH).ss(S, 0x33, 0x6c, True),
create_spiral_stairs(player, 'Sewers Pull Switch Down Stairs', DoorType.SpiralStairs, Direction.Down, 0x02, 0, HTL, S, 0x12, 0x80), create_door(player, 'Sewers Pull Switch Down Stairs', Sprl).dir(Direction.Down, 0x02, 0, HTL).ss(S, 0x12, 0x80),
trap(toggle(create_dir_door(player, 'Sewers Pull Switch S', DoorType.Normal, Direction.South, 0x02, Mid, Low)), 0x4).pos(0), create_door(player, 'Sewers Pull Switch S', Nrml).dir(Direction.South, 0x02, Mid, Low).trap(0x4).toggler().pos(0),
# logically one way the sanc, but should be linked - also toggle # logically one way the sanc, but should be linked - also toggle
toggle(blocked(create_dir_door(player, 'Sanctuary N', DoorType.Normal, Direction.North, 0x12, Mid, High))).pos(0), create_door(player, 'Sanctuary N', Nrml).dir(Direction.North, 0x12, Mid, High).no_exit().toggler().pos(0),
# Eastern Palace # Eastern Palace
create_dir_door(player, 'Eastern Lobby N', DoorType.Normal, Direction.North, 0xc9, Mid, High).pos(1), create_door(player, 'Eastern Lobby N', Nrml).dir(Direction.North, 0xc9, Mid, High).pos(1),
create_dir_door(player, 'Eastern Cannonball S', DoorType.Normal, Direction.South, 0xb9, Mid, High).pos(2), create_door(player, 'Eastern Cannonball S', Nrml).dir(Direction.South, 0xb9, Mid, High).pos(2),
create_dir_door(player, 'Eastern Cannonball N', DoorType.Normal, Direction.North, 0xb9, Mid, High).pos(1), create_door(player, 'Eastern Cannonball N', Nrml).dir(Direction.North, 0xb9, Mid, High).pos(1),
create_dir_door(player, 'Eastern Cannonball Ledge WN', DoorType.Normal, Direction.West, 0xb9, Top, High).pos(3), create_door(player, 'Eastern Cannonball Ledge WN', Nrml).dir(Direction.West, 0xb9, Top, High).pos(3),
small_key(create_dir_door(player, 'Eastern Cannonball Ledge Key Door EN', DoorType.Normal, Direction.East, 0xb9, Top, High)).pos(0), create_door(player, 'Eastern Cannonball Ledge Key Door EN', Nrml).dir(Direction.East, 0xb9, Top, High).small_key().pos(0),
create_dir_door(player, 'Eastern Courtyard Ledge S', DoorType.Normal, Direction.South, 0xa9, Mid, High).pos(5), create_door(player, 'Eastern Courtyard Ledge S', Nrml).dir(Direction.South, 0xa9, Mid, High).pos(5),
trap(create_dir_door(player, 'Eastern Courtyard Ledge W', DoorType.Normal, Direction.West, 0xa9, Mid, High), 0x4).pos(0), create_door(player, 'Eastern Courtyard Ledge W', Nrml).dir(Direction.West, 0xa9, Mid, High).trap(0x4).pos(0),
trap(create_dir_door(player, 'Eastern Courtyard Ledge E', DoorType.Normal, Direction.East, 0xa9, Mid, High), 0x2).pos(1), create_door(player, 'Eastern Courtyard Ledge E', Nrml).dir(Direction.East, 0xa9, Mid, High).trap(0x2).pos(1),
create_dir_door(player, 'Eastern Map Area W', DoorType.Normal, Direction.West, 0xaa, Mid, High).pos(4), create_door(player, 'Eastern Map Area W', Nrml).dir(Direction.West, 0xaa, Mid, High).pos(4),
create_dir_door(player, 'Eastern Compass Area E', DoorType.Normal, Direction.East, 0xa8, Mid, High).pos(5), create_door(player, 'Eastern Compass Area E', Nrml).dir(Direction.East, 0xa8, Mid, High).pos(5),
create_dir_door(player, 'Eastern Compass Area EN', DoorType.Normal, Direction.East, 0xa8, Top, Low).pos(4), create_door(player, 'Eastern Compass Area EN', Nrml).dir(Direction.East, 0xa8, Top, Low).pos(4),
ugly_door(small_key(create_dir_door(player, 'Eastern Compass Area SW', DoorType.Normal, Direction.South, 0xa8, Right, High))).pos(2), ugly_door(create_door(player, 'Eastern Compass Area SW', Nrml).dir(Direction.South, 0xa8, Right, High)).small_key().pos(2),
create_door(player, 'Eastern Hint Tile Push Block', DoorType.Logical), create_door(player, 'Eastern Hint Tile Push Block', Lgcl),
create_dir_door(player, 'Eastern Courtyard WN', DoorType.Normal, Direction.West, 0xa9, Top, Low).pos(3), create_door(player, 'Eastern Courtyard WN', Nrml).dir(Direction.West, 0xa9, Top, Low).pos(3),
create_dir_door(player, 'Eastern Courtyard EN', DoorType.Normal, Direction.East, 0xa9, Top, Low).pos(4), create_door(player, 'Eastern Courtyard EN', Nrml).dir(Direction.East, 0xa9, Top, Low).pos(4),
big_key(create_dir_door(player, 'Eastern Courtyard N', DoorType.Normal, Direction.North, 0xa9, Mid, High)).pos(2), create_door(player, 'Eastern Courtyard N', Nrml).dir(Direction.North, 0xa9, Mid, High).big_key().pos(2),
create_door(player, 'Eastern Courtyard Potholes', DoorType.Hole), create_door(player, 'Eastern Courtyard Potholes', Hole),
create_door(player, 'Eastern Fairies\' Warp', DoorType.Warp), create_door(player, 'Eastern Fairies\' Warp', Warp),
create_dir_door(player, 'Eastern Map Valley WN', DoorType.Normal, Direction.West, 0xaa, Top, Low).pos(1), create_door(player, 'Eastern Map Valley WN', Nrml).dir(Direction.West, 0xaa, Top, Low).pos(1),
create_dir_door(player, 'Eastern Map Valley SW', DoorType.Normal, Direction.South, 0xaa, Left, High).pos(5), create_door(player, 'Eastern Map Valley SW', Nrml).dir(Direction.South, 0xaa, Left, High).pos(5),
create_dir_door(player, 'Eastern Dark Square NW', DoorType.Normal, Direction.North, 0xba, Left, High).pos(1), create_door(player, 'Eastern Dark Square NW', Nrml).dir(Direction.North, 0xba, Left, High).pos(1),
small_key(create_dir_door(player, 'Eastern Dark Square Key Door WN', DoorType.Normal, Direction.West, 0xba, Top, High)).pos(0), create_door(player, 'Eastern Dark Square Key Door WN', Nrml).dir(Direction.West, 0xba, Top, High).small_key().pos(0),
create_dir_door(player, 'Eastern Big Key EN', DoorType.Normal, Direction.East, 0xb8, Top, High).pos(1), create_door(player, 'Eastern Big Key EN', Nrml).dir(Direction.East, 0xb8, Top, High).pos(1),
big_key(create_dir_door(player, 'Eastern Big Key NE', DoorType.Normal, Direction.North, 0xb8, Right, High)).pos(0), create_door(player, 'Eastern Big Key NE', Nrml).dir(Direction.North, 0xb8, Right, High).big_key().pos(0),
ugly_door(small_key(create_dir_door(player, 'Eastern Darkness S', DoorType.Normal, Direction.South, 0x99, Mid, High))).pos(1), ugly_door(create_door(player, 'Eastern Darkness S', Nrml).dir(Direction.South, 0x99, Mid, High)).small_key().pos(1),
# Up is a keydoor and down is not. Only the up stairs should be considered a key door for now. # Up is a keydoor and down is not. Only the up stairs should be considered a key door for now.
small_key(create_spiral_stairs(player, 'Eastern Darkness Up Stairs', DoorType.SpiralStairs, Direction.Up, 0x99, 0, HTH, Z, 0x1a, 0x6c, False, True)).pos(0), create_door(player, 'Eastern Darkness Up Stairs', Sprl).dir(Direction.Up, 0x99, 0, HTH).ss(Z, 0x1a, 0x6c, False, True).small_key().pos(0),
ugly_door(create_spiral_stairs(player, 'Eastern Attic Start Down Stairs', DoorType.SpiralStairs, Direction.Down, 0xda, 0, HTH, Z, 0x11, 0x80, True, True)), ugly_door(create_door(player, 'Eastern Attic Start Down Stairs', Sprl).dir(Direction.Down, 0xda, 0, HTH).ss(Z, 0x11, 0x80, True, True)),
create_dir_door(player, 'Eastern Attic Start WS', DoorType.Normal, Direction.West, 0xda, Bot, High).trap(0x4).pos(0), create_door(player, 'Eastern Attic Start WS', Nrml).dir(Direction.West, 0xda, Bot, High).trap(0x4).pos(0),
create_dir_door(player, 'Eastern Attic Switches ES', DoorType.Normal, Direction.East, 0xd9, Bot, High).trap(0x1).pos(2), create_door(player, 'Eastern Attic Switches ES', Nrml).dir(Direction.East, 0xd9, Bot, High).trap(0x1).pos(2),
create_dir_door(player, 'Eastern Attic Switches WS', DoorType.Normal, Direction.West, 0xd9, Bot, High).trap(0x4).pos(0), create_door(player, 'Eastern Attic Switches WS', Nrml).dir(Direction.West, 0xd9, Bot, High).trap(0x4).pos(0),
create_dir_door(player, 'Eastern Eyegores ES', DoorType.Normal, Direction.East, 0xd8, Bot, High).pos(2), create_door(player, 'Eastern Eyegores ES', Nrml).dir(Direction.East, 0xd8, Bot, High).pos(2),
create_dir_door(player, 'Eastern Eyegores NE', DoorType.Normal, Direction.North, 0xd8, Right, High).trap(0x4).pos(0), create_door(player, 'Eastern Eyegores NE', Nrml).dir(Direction.North, 0xd8, Right, High).trap(0x4).pos(0),
trap(blocked(create_dir_door(player, 'Eastern Boss SE', DoorType.Normal, Direction.South, 0xc8, Right, High)), 0x4).pos(0), create_door(player, 'Eastern Boss SE', Nrml).dir(Direction.South, 0xc8, Right, High).no_exit().trap(0x4).pos(0),
# Desert Palace # Desert Palace
create_dir_door(player, 'Desert Main Lobby NW Edge', DoorType.Open, Direction.North, 0x84, None, High), create_door(player, 'Desert Main Lobby NW Edge', Open).dir(Direction.North, 0x84, None, High),
create_dir_door(player, 'Desert Main Lobby N Edge', DoorType.Open, Direction.North, 0x84, None, High), create_door(player, 'Desert Main Lobby N Edge', Open).dir(Direction.North, 0x84, None, High),
create_dir_door(player, 'Desert Main Lobby NE Edge', DoorType.Open, Direction.North, 0x84, None, High), create_door(player, 'Desert Main Lobby NE Edge', Open).dir(Direction.North, 0x84, None, High),
create_dir_door(player, 'Desert Main Lobby E Edge', DoorType.Open, Direction.East, 0x84, None, High), create_door(player, 'Desert Main Lobby E Edge', Open).dir(Direction.East, 0x84, None, High),
create_dir_door(player, 'Desert Dead End Edge', DoorType.Open, Direction.South, 0x74, None, High), create_door(player, 'Desert Dead End Edge', Open).dir(Direction.South, 0x74, None, High),
create_dir_door(player, 'Desert East Wing W Edge', DoorType.Open, Direction.West, 0x85, None, High), create_door(player, 'Desert East Wing W Edge', Open).dir(Direction.West, 0x85, None, High),
create_dir_door(player, 'Desert East Wing N Edge', DoorType.Open, Direction.North, 0x85, None, High), create_door(player, 'Desert East Wing N Edge', Open).dir(Direction.North, 0x85, None, High),
create_dir_door(player, 'Desert East Lobby WS', DoorType.Interior, Direction.West, 0x85, Bot, High).pos(3), create_door(player, 'Desert East Lobby WS', Intr).dir(Direction.West, 0x85, Bot, High).pos(3),
create_dir_door(player, 'Desert East Wing ES', DoorType.Interior, Direction.East, 0x85, Bot, High).pos(3), create_door(player, 'Desert East Wing ES', Intr).dir(Direction.East, 0x85, Bot, High).pos(3),
small_key(create_dir_door(player, 'Desert East Wing Key Door EN', DoorType.Interior, Direction.East, 0x85, Top, High)).pos(1), create_door(player, 'Desert East Wing Key Door EN', Intr).dir(Direction.East, 0x85, Top, High).small_key().pos(1),
small_key(create_dir_door(player, 'Desert Compass Key Door WN', DoorType.Interior, Direction.West, 0x85, Top, High)).pos(1), create_door(player, 'Desert Compass Key Door WN', Intr).dir(Direction.West, 0x85, Top, High).small_key().pos(1),
trap(create_dir_door(player, 'Desert Compass NW', DoorType.Normal, Direction.North, 0x85, Left, High), 0x4).pos(0), create_door(player, 'Desert Compass NW', Nrml).dir(Direction.North, 0x85, Right, High).trap(0x4).pos(0),
create_dir_door(player, 'Desert Cannonball S', DoorType.Normal, Direction.South, 0x75, Left, High).pos(1), create_door(player, 'Desert Cannonball S', Nrml).dir(Direction.South, 0x75, Right, High).pos(1),
create_dir_door(player, 'Desert Arrow Pot Corner S Edge', DoorType.Open, Direction.South, 0x75, None, High), create_door(player, 'Desert Arrow Pot Corner S Edge', Open).dir(Direction.South, 0x75, None, High),
create_dir_door(player, 'Desert Arrow Pot Corner W Edge', DoorType.Open, Direction.West, 0x75, None, High), create_door(player, 'Desert Arrow Pot Corner W Edge', Open).dir(Direction.West, 0x75, None, High),
create_dir_door(player, 'Desert North Hall SE Edge', DoorType.Open, Direction.South, 0x74, None, High), create_door(player, 'Desert North Hall SE Edge', Open).dir(Direction.South, 0x74, None, High),
create_dir_door(player, 'Desert North Hall SW Edge', DoorType.Open, Direction.South, 0x74, None, High), create_door(player, 'Desert North Hall SW Edge', Open).dir(Direction.South, 0x74, None, High),
create_dir_door(player, 'Desert North Hall W Edge', DoorType.Open, Direction.West, 0x74, None, High), create_door(player, 'Desert North Hall W Edge', Open).dir(Direction.West, 0x74, None, High),
create_dir_door(player, 'Desert North Hall E Edge', DoorType.Open, Direction.East, 0x74, None, High), create_door(player, 'Desert North Hall E Edge', Open).dir(Direction.East, 0x74, None, High),
create_dir_door(player, 'Desert North Hall NW', DoorType.Interior, Direction.North, 0x74, Left, High).pos(1), create_door(player, 'Desert North Hall NW', Intr).dir(Direction.North, 0x74, Left, High).pos(1),
create_dir_door(player, 'Desert Map SW', DoorType.Interior, Direction.South, 0x74, Left, High).pos(1), create_door(player, 'Desert Map SW', Intr).dir(Direction.South, 0x74, Left, High).pos(1),
create_dir_door(player, 'Desert North Hall NE', DoorType.Interior, Direction.North, 0x74, Right, High).pos(0), create_door(player, 'Desert North Hall NE', Intr).dir(Direction.North, 0x74, Right, High).pos(0),
create_dir_door(player, 'Desert Map SE', DoorType.Interior, Direction.South, 0x74, Right, High).pos(0), create_door(player, 'Desert Map SE', Intr).dir(Direction.South, 0x74, Right, High).pos(0),
create_dir_door(player, 'Desert Sandworm Corner S Edge', DoorType.Open, Direction.South, 0x73, None, High), create_door(player, 'Desert Sandworm Corner S Edge', Open).dir(Direction.South, 0x73, None, High),
create_dir_door(player, 'Desert Sandworm Corner E Edge', DoorType.Open, Direction.East, 0x73, None, High), create_door(player, 'Desert Sandworm Corner E Edge', Open).dir(Direction.East, 0x73, None, High),
create_dir_door(player, 'Desert Sandworm Corner NE', DoorType.Interior, Direction.North, 0x73, Right, High).pos(2), create_door(player, 'Desert Sandworm Corner NE', Intr).dir(Direction.North, 0x73, Right, High).pos(2),
create_dir_door(player, 'Desert Bonk Torch SE', DoorType.Interior, Direction.South, 0x73, Right, High).pos(2), create_door(player, 'Desert Bonk Torch SE', Intr).dir(Direction.South, 0x73, Right, High).pos(2),
create_dir_door(player, 'Desert Sandworm Corner WS', DoorType.Interior, Direction.West, 0x73, Bot, High).pos(1), create_door(player, 'Desert Sandworm Corner WS', Intr).dir(Direction.West, 0x73, Bot, High).pos(1),
# I don't know if I have to mark trap on interior doors yet - haven't mucked them up much # I don't know if I have to mark trap on interior doors yet - haven't mucked them up much
create_dir_door(player, 'Desert Circle of Pots ES', DoorType.Interior, Direction.East, 0x73, Bot, High).pos(1), create_door(player, 'Desert Circle of Pots ES', Intr).dir(Direction.East, 0x73, Bot, High).pos(1),
create_dir_door(player, 'Desert Circle of Pots NW', DoorType.Interior, Direction.North, 0x73, Left, High).pos(0), create_door(player, 'Desert Circle of Pots NW', Intr).dir(Direction.North, 0x73, Left, High).pos(0),
create_dir_door(player, 'Desert Big Chest SW', DoorType.Interior, Direction.South, 0x73, Left, High).pos(0), create_door(player, 'Desert Big Chest SW', Intr).dir(Direction.South, 0x73, Left, High).pos(0),
create_dir_door(player, 'Desert West Wing N Edge', DoorType.Open, Direction.North, 0x83, None, High), create_door(player, 'Desert West Wing N Edge', Open).dir(Direction.North, 0x83, None, High),
create_dir_door(player, 'Desert West Wing WS', DoorType.Interior, Direction.West, 0x83, Bot, High).pos(2), create_door(player, 'Desert West Wing WS', Intr).dir(Direction.West, 0x83, Bot, High).pos(2),
create_dir_door(player, 'Desert West Lobby ES', DoorType.Interior, Direction.East, 0x83, Bot, High).pos(2), create_door(player, 'Desert West Lobby ES', Intr).dir(Direction.East, 0x83, Bot, High).pos(2),
# Desert Back # Desert Back
create_dir_door(player, 'Desert Back Lobby NW', DoorType.Interior, Direction.North, 0x63, Left, High).pos(1), create_door(player, 'Desert Back Lobby NW', Intr).dir(Direction.North, 0x63, Left, High).pos(1),
create_dir_door(player, 'Desert Tiles 1 SW', DoorType.Interior, Direction.South, 0x63, Left, High).pos(1), create_door(player, 'Desert Tiles 1 SW', Intr).dir(Direction.South, 0x63, Left, High).pos(1),
small_key(create_spiral_stairs(player, 'Desert Tiles 1 Up Stairs', DoorType.SpiralStairs, Direction.Up, 0x63, 0, HTH, A, 0x1b, 0x6c, True)).pos(0), create_door(player, 'Desert Tiles 1 Up Stairs', Sprl).dir(Direction.Up, 0x63, 0, HTH).ss(A, 0x1b, 0x6c, True).small_key().pos(0),
create_spiral_stairs(player, 'Desert Bridge Down Stairs', DoorType.SpiralStairs, Direction.Down, 0x53, 0, HTH, A, 0x0f, 0x80, True), create_door(player, 'Desert Bridge Down Stairs', Sprl).dir(Direction.Down, 0x53, 0, HTH).ss(A, 0x0f, 0x80, True),
create_dir_door(player, 'Desert Bridge SW', DoorType.Interior, Direction.South, 0x53, Left, High).pos(0), create_door(player, 'Desert Bridge SW', Intr).dir(Direction.South, 0x53, Left, High).pos(0),
create_dir_door(player, 'Desert Four Statues NW', DoorType.Interior, Direction.North, 0x53, Left, High).pos(0), create_door(player, 'Desert Four Statues NW', Intr).dir(Direction.North, 0x53, Left, High).pos(0),
create_dir_door(player, 'Desert Four Statues ES', DoorType.Interior, Direction.East, 0x53, Bot, High).pos(1), create_door(player, 'Desert Four Statues ES', Intr).dir(Direction.East, 0x53, Bot, High).pos(1),
create_dir_door(player, 'Desert Beamos Hall WS', DoorType.Interior, Direction.West, 0x53, Bot, High).pos(1), create_door(player, 'Desert Beamos Hall WS', Intr).dir(Direction.West, 0x53, Bot, High).pos(1),
small_key(create_dir_door(player, 'Desert Beamos Hall NE', DoorType.Normal, Direction.North, 0x53, Right, High)).pos(2), create_door(player, 'Desert Beamos Hall NE', Nrml).dir(Direction.North, 0x53, Right, High).small_key().pos(2),
small_key(create_dir_door(player, 'Desert Tiles 2 SE', DoorType.Normal, Direction.South, 0x43, Right, High)).pos(2), create_door(player, 'Desert Tiles 2 SE', Nrml).dir(Direction.South, 0x43, Right, High).small_key().pos(2),
create_dir_door(player, 'Desert Tiles 2 NE', DoorType.Interior, Direction.North, 0x43, Right, High).small_key().pos(1), create_door(player, 'Desert Tiles 2 NE', Intr).dir(Direction.North, 0x43, Right, High).small_key().pos(1),
create_dir_door(player, 'Desert Wall Slide SE', DoorType.Interior, Direction.South, 0x43, Right, High).small_key().pos(1), create_door(player, 'Desert Wall Slide SE', Intr).dir(Direction.South, 0x43, Right, High).small_key().pos(1),
# todo: we need a new flag for a door that has a wall on it - you have to traverse it one particular way first create_door(player, 'Desert Wall Slide NW', Nrml).dir(Direction.North, 0x43, Left, High).big_key().pos(0).no_entrance(),
# the above is not a problem until we get to crossed mode create_door(player, 'Desert Boss SW', Nrml).dir(Direction.South, 0x33, Left, High).no_exit().trap(0x4).pos(0),
big_key(create_dir_door(player, 'Desert Wall Slide NW', DoorType.Normal, Direction.North, 0x43, Left, High)).pos(0),
trap(blocked(create_dir_door(player, 'Desert Boss SW', DoorType.Normal, Direction.South, 0x33, Left, High)), 0x4).pos(0),
# Hera # Hera
create_spiral_stairs(player, 'Hera Lobby Down Stairs', DoorType.SpiralStairs, Direction.Down, 0x77, 3, HTL, Z, 0x21, 0x90, False, True), create_door(player, 'Hera Lobby Down Stairs', Sprl).dir(Direction.Down, 0x77, 3, HTL).ss(Z, 0x21, 0x90, False, True),
small_key(create_spiral_stairs(player, 'Hera Lobby Key Stairs', DoorType.SpiralStairs, Direction.Down, 0x77, 1, HTL, A, 0x12, 0x80)).pos(0), create_door(player, 'Hera Lobby Key Stairs', Sprl).dir(Direction.Down, 0x77, 1, HTL).ss(A, 0x12, 0x80).small_key().pos(0),
create_spiral_stairs(player, 'Hera Lobby Up Stairs', DoorType.SpiralStairs, Direction.Up, 0x77, 2, HTL, X, 0x2b, 0x5c, False, True), create_door(player, 'Hera Lobby Up Stairs', Sprl).dir(Direction.Up, 0x77, 2, HTL).ss(X, 0x2b, 0x5c, False, True),
create_spiral_stairs(player, 'Hera Basement Cage Up Stairs', DoorType.SpiralStairs, Direction.Up, 0x87, 3, LTH, Z, 0x42, 0x7c, True, True), create_door(player, 'Hera Basement Cage Up Stairs', Sprl).dir(Direction.Up, 0x87, 3, LTH).ss(Z, 0x42, 0x7c, True, True),
create_spiral_stairs(player, 'Hera Tile Room Up Stairs', DoorType.SpiralStairs, Direction.Up, 0x87, 1, LTH, A, 0x32, 0x6c, True, True), create_door(player, 'Hera Tile Room Up Stairs', Sprl).dir(Direction.Up, 0x87, 1, LTH).ss(A, 0x32, 0x6c, True, True),
create_dir_door(player, 'Hera Tile Room EN', DoorType.Interior, Direction.East, 0x87, Top, High).pos(0), create_door(player, 'Hera Tile Room EN', Intr).dir(Direction.East, 0x87, Top, High).pos(0),
create_dir_door(player, 'Hera Tridorm WN', DoorType.Interior, Direction.West, 0x87, Top, High).pos(0), create_door(player, 'Hera Tridorm WN', Intr).dir(Direction.West, 0x87, Top, High).pos(0),
create_dir_door(player, 'Hera Tridorm SE', DoorType.Interior, Direction.South, 0x87, Right, High).pos(1), create_door(player, 'Hera Tridorm SE', Intr).dir(Direction.South, 0x87, Right, High).pos(1),
create_dir_door(player, 'Hera Torches NE', DoorType.Interior, Direction.North, 0x87, Right, High).pos(1), create_door(player, 'Hera Torches NE', Intr).dir(Direction.North, 0x87, Right, High).pos(1),
create_spiral_stairs(player, 'Hera Beetles Down Stairs', DoorType.SpiralStairs, Direction.Down, 0x31, 2, LTH, X, 0x3a, 0x70, True, True), create_door(player, 'Hera Beetles Down Stairs', Sprl).dir(Direction.Down, 0x31, 2, LTH).ss(X, 0x3a, 0x70, True, True),
create_dir_door(player, 'Hera Beetles WS', DoorType.Interior, Direction.West, 0x31, Bot, High).pos(1), create_door(player, 'Hera Beetles WS', Intr).dir(Direction.West, 0x31, Bot, High).pos(1),
create_door(player, 'Hera Beetles Holes', DoorType.Hole), create_door(player, 'Hera Beetles Holes', Hole),
create_dir_door(player, 'Hera Startile Corner ES', DoorType.Interior, Direction.East, 0x31, Bot, High).pos(1), create_door(player, 'Hera Startile Corner ES', Intr).dir(Direction.East, 0x31, Bot, High).pos(1),
big_key(create_dir_door(player, 'Hera Startile Corner NW', DoorType.Interior, Direction.North, 0x31, Left, High)).pos(0), create_door(player, 'Hera Startile Corner NW', Intr).dir(Direction.North, 0x31, Left, High).big_key().pos(0),
create_door(player, 'Hera Startile Corner Holes', DoorType.Hole), create_door(player, 'Hera Startile Corner Holes', Hole),
# technically ugly but causes lots of failures in basic # technically ugly but causes lots of failures in basic
create_dir_door(player, 'Hera Startile Wide SW', DoorType.Interior, Direction.South, 0x31, Left, High).pos(0), create_door(player, 'Hera Startile Wide SW', Intr).dir(Direction.South, 0x31, Left, High).pos(0),
create_spiral_stairs(player, 'Hera Startile Wide Up Stairs', DoorType.SpiralStairs, Direction.Up, 0x31, 0, HTH, S, 0x6b, 0xac, False, True), create_door(player, 'Hera Startile Wide Up Stairs', Sprl).dir(Direction.Up, 0x31, 0, HTH).ss(S, 0x6b, 0xac, False, True),
create_door(player, 'Hera Startile Wide Holes', DoorType.Hole), create_door(player, 'Hera Startile Wide Holes', Hole),
create_spiral_stairs(player, 'Hera 4F Down Stairs', DoorType.SpiralStairs, Direction.Down, 0x27, 0, HTH, S, 0x62, 0xc0), create_door(player, 'Hera 4F Down Stairs', Sprl).dir(Direction.Down, 0x27, 0, HTH).ss(S, 0x62, 0xc0),
create_spiral_stairs(player, 'Hera 4F Up Stairs', DoorType.SpiralStairs, Direction.Up, 0x27, 1, HTH, A, 0x6b, 0x2c), create_door(player, 'Hera 4F Up Stairs', Sprl).dir(Direction.Up, 0x27, 1, HTH).ss(A, 0x6b, 0x2c),
create_door(player, 'Hera 4F Holes', DoorType.Hole), create_door(player, 'Hera 4F Holes', Hole),
create_door(player, 'Hera Big Chest Landing Exit', DoorType.Logical), create_door(player, 'Hera Big Chest Landing Exit', Lgcl),
create_door(player, 'Hera Big Chest Landing Holes', DoorType.Hole), create_door(player, 'Hera Big Chest Landing Holes', Hole),
create_spiral_stairs(player, 'Hera 5F Down Stairs', DoorType.SpiralStairs, Direction.Down, 0x17, 1, HTH, A, 0x62, 0x40), create_door(player, 'Hera 5F Down Stairs', Sprl).dir(Direction.Down, 0x17, 1, HTH).ss(A, 0x62, 0x40),
create_spiral_stairs(player, 'Hera 5F Up Stairs', DoorType.SpiralStairs, Direction.Up, 0x17, 0, HTH, S, 0x6a, 0x9c), create_door(player, 'Hera 5F Up Stairs', Sprl).dir(Direction.Up, 0x17, 0, HTH).ss(S, 0x6a, 0x9c),
create_door(player, 'Hera 5F Star Hole', DoorType.Hole), create_door(player, 'Hera 5F Star Hole', Hole),
create_door(player, 'Hera 5F Pothole Chain', DoorType.Hole), create_door(player, 'Hera 5F Pothole Chain', Hole),
create_door(player, 'Hera 5F Normal Holes', DoorType.Hole), create_door(player, 'Hera 5F Normal Holes', Hole),
create_door(player, 'Hera Fairies\' Warp', DoorType.Warp), create_door(player, 'Hera Fairies\' Warp', Warp),
create_spiral_stairs(player, 'Hera Boss Down Stairs', DoorType.SpiralStairs, Direction.Down, 0x07, 0, HTH, S, 0x61, 0xb0), create_door(player, 'Hera Boss Down Stairs', Sprl).dir(Direction.Down, 0x07, 0, HTH).ss(S, 0x61, 0xb0),
create_door(player, 'Hera Boss Outer Hole', DoorType.Hole), create_door(player, 'Hera Boss Outer Hole', Hole),
create_door(player, 'Hera Boss Inner Hole', DoorType.Hole), create_door(player, 'Hera Boss Inner Hole', Hole),
# Castle Tower # Castle Tower
create_dir_door(player, 'Tower Lobby NW', DoorType.Interior, Direction.North, 0xe0, Left, High).pos(1), create_door(player, 'Tower Lobby NW', Intr).dir(Direction.North, 0xe0, Left, High).pos(1),
create_dir_door(player, 'Tower Gold Knights SW', DoorType.Interior, Direction.South, 0xe0, Left, High).pos(1), create_door(player, 'Tower Gold Knights SW', Intr).dir(Direction.South, 0xe0, Left, High).pos(1),
create_dir_door(player, 'Tower Gold Knights EN', DoorType.Interior, Direction.East, 0xe0, Top, High).pos(0), create_door(player, 'Tower Gold Knights EN', Intr).dir(Direction.East, 0xe0, Top, High).pos(0),
create_dir_door(player, 'Tower Room 03 WN', DoorType.Interior, Direction.West, 0xe0, Bot, High).pos(0), create_door(player, 'Tower Room 03 WN', Intr).dir(Direction.West, 0xe0, Bot, High).pos(0),
create_spiral_stairs(player, 'Tower Room 03 Up Stairs', DoorType.SpiralStairs, Direction.Up, 0xe0, 0, HTH, S, 0x1a, 0x6c, True, True).small_key().pos(2), create_door(player, 'Tower Room 03 Up Stairs', Sprl).dir(Direction.Up, 0xe0, 0, HTH).ss(S, 0x1a, 0x6c, True, True).small_key().pos(2),
create_spiral_stairs(player, 'Tower Lone Statue Down Stairs', DoorType.SpiralStairs, Direction.Down, 0xd0, 0, HTH, S, 0x11, 0x80, True, True), create_door(player, 'Tower Lone Statue Down Stairs', Sprl).dir(Direction.Down, 0xd0, 0, HTH).ss(S, 0x11, 0x80, True, True),
create_dir_door(player, 'Tower Lone Statue WN', DoorType.Interior, Direction.West, 0xd0, Top, High).pos(1), create_door(player, 'Tower Lone Statue WN', Intr).dir(Direction.West, 0xd0, Top, High).pos(1),
create_dir_door(player, 'Tower Dark Maze EN', DoorType.Interior, Direction.East, 0xd0, Top, High).pos(1), create_door(player, 'Tower Dark Maze EN', Intr).dir(Direction.East, 0xd0, Top, High).pos(1),
create_dir_door(player, 'Tower Dark Maze ES', DoorType.Interior, Direction.East, 0xd0, Bot, High).small_key().pos(0), create_door(player, 'Tower Dark Maze ES', Intr).dir(Direction.East, 0xd0, Bot, High).small_key().pos(0),
create_dir_door(player, 'Tower Dark Chargers WS', DoorType.Interior, Direction.West, 0xd0, Bot, High).small_key().pos(0), create_door(player, 'Tower Dark Chargers WS', Intr).dir(Direction.West, 0xd0, Bot, High).small_key().pos(0),
create_spiral_stairs(player, 'Tower Dark Chargers Up Stairs', DoorType.SpiralStairs, Direction.Up, 0xd0, 2, HTH, X, 0x1b, 0x8c, True, True), create_door(player, 'Tower Dark Chargers Up Stairs', Sprl).dir(Direction.Up, 0xd0, 2, HTH).ss(X, 0x1b, 0x8c, True, True),
create_spiral_stairs(player, 'Tower Dual Statues Down Stairs', DoorType.SpiralStairs, Direction.Down, 0xc0, 2, HTH, X, 0x12, 0xa0, True, True), create_door(player, 'Tower Dual Statues Down Stairs', Sprl).dir(Direction.Down, 0xc0, 2, HTH).ss(X, 0x12, 0xa0, True, True),
create_dir_door(player, 'Tower Dual Statues WS', DoorType.Interior, Direction.West, 0xc0, Bot, High).pos(1), create_door(player, 'Tower Dual Statues WS', Intr).dir(Direction.West, 0xc0, Bot, High).pos(1),
create_dir_door(player, 'Tower Dark Pits ES', DoorType.Interior, Direction.East, 0xc0, Bot, High).pos(1), create_door(player, 'Tower Dark Pits ES', Intr).dir(Direction.East, 0xc0, Bot, High).pos(1),
create_dir_door(player, 'Tower Dark Pits EN', DoorType.Interior, Direction.East, 0xc0, Top, High).pos(0), create_door(player, 'Tower Dark Pits EN', Intr).dir(Direction.East, 0xc0, Top, High).pos(0),
create_dir_door(player, 'Tower Dark Archers WN', DoorType.Interior, Direction.West, 0xc0, Top, High).pos(0), create_door(player, 'Tower Dark Archers WN', Intr).dir(Direction.West, 0xc0, Top, High).pos(0),
create_spiral_stairs(player, 'Tower Dark Archers Up Stairs', DoorType.SpiralStairs, Direction.Up, 0xc0, 0, HTH, S, 0x1b, 0x6c, True, True).small_key().pos(2), create_door(player, 'Tower Dark Archers Up Stairs', Sprl).dir(Direction.Up, 0xc0, 0, HTH).ss(S, 0x1b, 0x6c, True, True).small_key().pos(2),
create_spiral_stairs(player, 'Tower Red Spears Down Stairs', DoorType.SpiralStairs, Direction.Down, 0xb0, 0, HTH, S, 0x12, 0x80, True, True), create_door(player, 'Tower Red Spears Down Stairs', Sprl).dir(Direction.Down, 0xb0, 0, HTH).ss(S, 0x12, 0x80, True, True),
create_dir_door(player, 'Tower Red Spears WN', DoorType.Interior, Direction.West, 0xb0, Top, High).pos(1), create_door(player, 'Tower Red Spears WN', Intr).dir(Direction.West, 0xb0, Top, High).pos(1),
create_dir_door(player, 'Tower Red Guards EN', DoorType.Interior, Direction.East, 0xb0, Top, High).pos(1), create_door(player, 'Tower Red Guards EN', Intr).dir(Direction.East, 0xb0, Top, High).pos(1),
create_dir_door(player, 'Tower Red Guards SW', DoorType.Interior, Direction.South, 0xb0, Left, High).pos(0), create_door(player, 'Tower Red Guards SW', Intr).dir(Direction.South, 0xb0, Left, High).pos(0),
create_dir_door(player, 'Tower Circle of Pots NW', DoorType.Interior, Direction.North, 0xb0, Left, High).pos(0), create_door(player, 'Tower Circle of Pots NW', Intr).dir(Direction.North, 0xb0, Left, High).pos(0),
create_dir_door(player, 'Tower Circle of Pots WS', DoorType.Interior, Direction.West, 0xb0, Bot, High).small_key().pos(2), create_door(player, 'Tower Circle of Pots WS', Intr).dir(Direction.West, 0xb0, Bot, High).small_key().pos(2),
create_dir_door(player, 'Tower Pacifist Run ES', DoorType.Interior, Direction.East, 0xb0, Bot, High).small_key().pos(2), create_door(player, 'Tower Pacifist Run ES', Intr).dir(Direction.East, 0xb0, Bot, High).small_key().pos(2),
create_spiral_stairs(player, 'Tower Pacifist Run Up Stairs', DoorType.SpiralStairs, Direction.Up, 0xb0, 2, LTH, X, 0x33, 0x8c, True, True), create_door(player, 'Tower Pacifist Run Up Stairs', Sprl).dir(Direction.Up, 0xb0, 2, LTH).ss(X, 0x33, 0x8c, True, True),
create_spiral_stairs(player, 'Tower Push Statue Down Stairs', DoorType.SpiralStairs, Direction.Down, 0x40, 0, HTL, X, 0x12, 0xa0, True, True), create_door(player, 'Tower Push Statue Down Stairs', Sprl).dir(Direction.Down, 0x40, 0, HTL).ss(X, 0x12, 0xa0, True, True),
create_dir_door(player, 'Tower Push Statue WS', DoorType.Interior, Direction.West, 0x40, Bot, Low).pos(0), create_door(player, 'Tower Push Statue WS', Intr).dir(Direction.West, 0x40, Bot, Low).pos(0),
create_dir_door(player, 'Tower Catwalk ES', DoorType.Interior, Direction.East, 0x40, Bot, Low).pos(0), create_door(player, 'Tower Catwalk ES', Intr).dir(Direction.East, 0x40, Bot, Low).pos(0),
create_dir_door(player, 'Tower Catwalk North Stairs', DoorType.StraightStairs, Direction.North, 0x40, Left, High), create_door(player, 'Tower Catwalk North Stairs', StrS).dir(Direction.North, 0x40, Left, High),
create_dir_door(player, 'Tower Antechamber South Stairs', DoorType.StraightStairs, Direction.South, 0x30, Left, High), create_door(player, 'Tower Antechamber South Stairs', StrS).dir(Direction.South, 0x30, Left, High),
create_dir_door(player, 'Tower Antechamber NW', DoorType.Interior, Direction.North, 0x30, Left, High).pos(1), create_door(player, 'Tower Antechamber NW', Intr).dir(Direction.North, 0x30, Left, High).pos(1),
create_dir_door(player, 'Tower Altar SW', DoorType.Interior, Direction.South, 0x30, Left, High).pos(1), create_door(player, 'Tower Altar SW', Intr).dir(Direction.South, 0x30, Left, High).pos(1),
create_dir_door(player, 'Tower Altar NW', DoorType.Normal, Direction.North, 0x30, Left, High).pos(0), create_door(player, 'Tower Altar NW', Nrml).dir(Direction.North, 0x30, Left, High).pos(0),
create_dir_door(player, 'Tower Agahnim 1 SW', DoorType.Normal, Direction.South, 0x20, Left, High).no_exit().trap(0x4).pos(0), create_door(player, 'Tower Agahnim 1 SW', Nrml).dir(Direction.South, 0x20, Left, High).no_exit().trap(0x4).pos(0),
#Palace of Darkness # Palace of Darkness
create_door(player, 'PoD Lobby N', DoorType.Interior).dir(Direction.North, 0x4a, Mid, High).pos(2), create_door(player, 'PoD Lobby N', Intr).dir(Direction.North, 0x4a, Mid, High).pos(2),
create_door(player, 'PoD Lobby NW', DoorType.Interior).dir(Direction.North, 0x4a, Left, High).pos(0), create_door(player, 'PoD Lobby NW', Intr).dir(Direction.North, 0x4a, Left, High).pos(0),
create_door(player, 'PoD Lobby NE', DoorType.Interior).dir(Direction.North, 0x4a, Right, High).pos(1), create_door(player, 'PoD Lobby NE', Intr).dir(Direction.North, 0x4a, Right, High).pos(1),
create_door(player, 'PoD Left Cage SW', DoorType.Interior).dir(Direction.North, 0x4a, Left, High).pos(0), create_door(player, 'PoD Left Cage SW', Intr).dir(Direction.North, 0x4a, Left, High).pos(0),
create_door(player, 'PoD Middle Cage S', DoorType.Interior).dir(Direction.North, 0x4a, Mid, High).pos(2), create_door(player, 'PoD Middle Cage S', Intr).dir(Direction.North, 0x4a, Mid, High).pos(2),
create_door(player, 'PoD Middle Cage SE', DoorType.Interior).dir(Direction.North, 0x4a, Right, High).pos(1), create_door(player, 'PoD Middle Cage SE', Intr).dir(Direction.North, 0x4a, Right, High).pos(1),
create_door(player, 'PoD Left Cage Down Stairs', DoorType.SpiralStairs).dir(Direction.Down, 0x4a, 1, HTH).ss(A, 0x12, 0x80, False, True), create_door(player, 'PoD Left Cage Down Stairs', Sprl).dir(Direction.Down, 0x4a, 1, HTH).ss(A, 0x12, 0x80, False, True),
create_door(player, 'PoD Middle Cage Down Stairs', DoorType.SpiralStairs).dir(Direction.Down, 0x4a, 0, HTH).ss(S, 0x12, 0x80, False, True), create_door(player, 'PoD Middle Cage Down Stairs', Sprl).dir(Direction.Down, 0x4a, 0, HTH).ss(S, 0x12, 0x80, False, True),
create_door(player, 'PoD Middle Cage N', DoorType.Normal).dir(Direction.North, 0x4a, Mid, High).small_key().pos(2), create_door(player, 'PoD Middle Cage N', Nrml).dir(Direction.North, 0x4a, Mid, High).small_key().pos(2),
create_door(player, 'PoD Shooter Room Up Stairs', DoorType.SpiralStairs).dir(Direction.Up, 0x09, 1, HTH).ss(A, 0x31, 0x69, True, True), create_door(player, 'PoD Shooter Room Up Stairs', Sprl).dir(Direction.Up, 0x09, 1, HTH).ss(A, 0x1b, 0x6c, True, True),
create_door(player, 'PoD Warp Room Up Stairs', DoorType.SpiralStairs).dir(Direction.Up, 0x09, 0, HTH).ss(S, 0x30, 0x69, True, True), create_door(player, 'PoD Warp Room Up Stairs', Sprl).dir(Direction.Up, 0x09, 0, HTH).ss(S, 0x1a, 0x6c, True, True),
create_door(player, 'PoD Warp Room Warp', DoorType.Warp), create_door(player, 'PoD Warp Room Warp', Warp),
create_door(player, 'PoD Pit Room S', DoorType.Normal).dir(Direction.South, 0x3a, Mid, High).small_key().pos(0), create_door(player, 'PoD Pit Room S', Nrml).dir(Direction.South, 0x3a, Mid, High).small_key().pos(0),
create_door(player, 'PoD Pit Room NW', DoorType.Normal).dir(Direction.North, 0x3a, Left, High).pos(1), create_door(player, 'PoD Pit Room NW', Nrml).dir(Direction.North, 0x3a, Left, High).pos(1),
create_door(player, 'PoD Pit Room NE', DoorType.Normal).dir(Direction.North, 0x3a, Right, High).pos(2), create_door(player, 'PoD Pit Room NE', Nrml).dir(Direction.North, 0x3a, Right, High).pos(2),
create_door(player, 'PoD Pit Room Freefall', DoorType.Hole), create_door(player, 'PoD Pit Room Freefall', Hole),
create_door(player, 'PoD Pit Room Bomb Hole', DoorType.Hole), create_door(player, 'PoD Pit Room Bomb Hole', Hole),
create_door(player, 'PoD Big Key Landing Hole', DoorType.Hole), create_door(player, 'PoD Big Key Landing Hole', Hole),
create_door(player, 'PoD Big Key Landing Down Stairs', DoorType.SpiralStairs).dir(Direction.Down, 0x3a, 0, HTH).ss(A, 0x11, 0x00), create_door(player, 'PoD Big Key Landing Down Stairs', Sprl).dir(Direction.Down, 0x3a, 0, HTH).ss(A, 0x11, 0x00),
create_door(player, 'PoD Basement Ledge Up Stairs', DoorType.SpiralStairs).dir(Direction.Up, 0x0a, 0, HTH).ss(A, 0x1a, 0xec).small_key().pos(0), create_door(player, 'PoD Basement Ledge Up Stairs', Sprl).dir(Direction.Up, 0x0a, 0, HTH).ss(A, 0x1a, 0xec).small_key().pos(0),
create_door(player, 'PoD Basement Ledge Drop Down', DoorType.Logical), create_door(player, 'PoD Basement Ledge Drop Down', Lgcl),
create_door(player, 'PoD Stalfos Basement Warp', DoorType.Warp), create_door(player, 'PoD Stalfos Basement Warp', Warp),
create_door(player, 'PoD Arena Main SW', DoorType.Normal).dir(Direction.South, 0x2a, Left, High).pos(4), create_door(player, 'PoD Arena Main SW', Nrml).dir(Direction.South, 0x2a, Left, High).pos(4),
create_door(player, 'PoD Arena Bridge SE', DoorType.Normal).dir(Direction.South, 0x2a, Right, High).pos(5), create_door(player, 'PoD Arena Bridge SE', Nrml).dir(Direction.South, 0x2a, Right, High).pos(5),
create_door(player, 'PoD Arena Main NW', DoorType.Normal).dir(Direction.North, 0x2a, Left, High).small_key().pos(1), create_door(player, 'PoD Arena Main NW', Nrml).dir(Direction.North, 0x2a, Left, High).small_key().pos(1),
create_door(player, 'PoD Arena Main NE', DoorType.Normal).dir(Direction.North, 0x2a, Right, High).no_exit().trap(0x4).pos(0), create_door(player, 'PoD Arena Main NE', Nrml).dir(Direction.North, 0x2a, Right, High).no_exit().trap(0x4).pos(0),
create_door(player, 'PoD Arena Main Crystal Path', DoorType.Logical), create_door(player, 'PoD Arena Main Crystal Path', Lgcl),
create_door(player, 'PoD Arena Crystals E', DoorType.Normal).dir(Direction.East, 0x2a, Mid, High).pos(3), create_door(player, 'PoD Arena Crystals E', Nrml).dir(Direction.East, 0x2a, Mid, High).pos(3),
create_door(player, 'PoD Arena Crystal Path', DoorType.Logical), create_door(player, 'PoD Arena Crystal Path', Lgcl),
create_door(player, 'PoD Arena Bridge Drop Down', DoorType.Logical), create_door(player, 'PoD Arena Bridge Drop Down', Lgcl),
create_door(player, 'PoD Arena Ledge ES', DoorType.Normal).dir(Direction.East, 0x2a, Bot, High).pos(2), create_door(player, 'PoD Arena Ledge ES', Nrml).dir(Direction.East, 0x2a, Bot, High).pos(2),
create_door(player, 'PoD Sexy Statue W', DoorType.Normal).dir(Direction.West, 0x2b, Mid, High).pos(3), create_door(player, 'PoD Sexy Statue W', Nrml).dir(Direction.West, 0x2b, Mid, High).pos(3),
create_door(player, 'PoD Sexy Statue NW', DoorType.Normal).dir(Direction.North, 0x2b, Left, High).trap(0x1).pos(2), create_door(player, 'PoD Sexy Statue NW', Nrml).dir(Direction.North, 0x2b, Left, High).trap(0x1).pos(2),
create_door(player, 'PoD Map Balcony Drop Down', DoorType.Logical), create_door(player, 'PoD Map Balcony Drop Down', Lgcl),
create_door(player, 'PoD Map Balcony WS', DoorType.Normal).dir(Direction.West, 0x2b, Bot, High).pos(1), create_door(player, 'PoD Map Balcony WS', Nrml).dir(Direction.West, 0x2b, Bot, High).pos(1),
create_door(player, 'PoD Map Balcony South Stairs', DoorType.StraightStairs).dir(Direction.South, 0x2b, Left, High), create_door(player, 'PoD Map Balcony South Stairs', StrS).dir(Direction.South, 0x2b, Left, High),
create_door(player, 'PoD Conveyor North Stairs', DoorType.StraightStairs).dir(Direction.North, 0x3b, Left, High), create_door(player, 'PoD Conveyor North Stairs', StrS).dir(Direction.North, 0x3b, Left, High),
create_door(player, 'PoD Conveyor SW', DoorType.Normal).dir(Direction.South, 0x3b, Left, High).pos(0), create_door(player, 'PoD Conveyor SW', Nrml).dir(Direction.South, 0x3b, Left, High).pos(0),
create_door(player, 'PoD Mimics 1 NW', DoorType.Normal).dir(Direction.North, 0x4b, Left, High).trap(0x4).pos(0), create_door(player, 'PoD Mimics 1 NW', Nrml).dir(Direction.North, 0x4b, Left, High).trap(0x4).pos(0),
create_door(player, 'PoD Mimics 1 SW', DoorType.Interior).dir(Direction.South, 0x4b, Left, High).pos(1), create_door(player, 'PoD Mimics 1 SW', Intr).dir(Direction.South, 0x4b, Left, High).pos(1),
create_door(player, 'PoD Jelly Hall NW', DoorType.Interior).dir(Direction.North, 0x4b, Left, High).pos(1), create_door(player, 'PoD Jelly Hall NW', Intr).dir(Direction.North, 0x4b, Left, High).pos(1),
create_door(player, 'PoD Jelly Hall NE', DoorType.Interior).dir(Direction.North, 0x4b, Right, High).pos(2), create_door(player, 'PoD Jelly Hall NE', Intr).dir(Direction.North, 0x4b, Right, High).pos(2),
create_door(player, 'PoD Warp Hint SE', DoorType.Interior).dir(Direction.South, 0x4b, Right, High).pos(2), create_door(player, 'PoD Warp Hint SE', Intr).dir(Direction.South, 0x4b, Right, High).pos(2),
create_door(player, 'PoD Warp Hint Warp', DoorType.Warp), create_door(player, 'PoD Warp Hint Warp', Warp),
create_door(player, 'PoD Falling Bridge SW', DoorType.Normal).dir(Direction.South, 0x1a, Left, High).small_key().pos(3), create_door(player, 'PoD Falling Bridge SW', Nrml).dir(Direction.South, 0x1a, Left, High).small_key().pos(3),
create_door(player, 'PoD Falling Bridge WN', DoorType.Normal).dir(Direction.West, 0x1a, Top, High).small_key().pos(1), create_door(player, 'PoD Falling Bridge WN', Nrml).dir(Direction.West, 0x1a, Top, High).small_key().pos(1),
create_door(player, 'PoD Falling Bridge EN', DoorType.Interior).dir(Direction.East, 0x1a, Top, High).pos(4), create_door(player, 'PoD Falling Bridge EN', Intr).dir(Direction.East, 0x1a, Top, High).pos(4),
create_door(player, 'PoD Big Chest Balcony W', DoorType.Normal).dir(Direction.West, 0x1a, Mid, High).pos(2), create_door(player, 'PoD Big Chest Balcony W', Nrml).dir(Direction.West, 0x1a, Mid, High).pos(2),
create_door(player, 'PoD Dark Maze EN', DoorType.Normal).dir(Direction.East, 0x19, Top, High).small_key().pos(1), create_door(player, 'PoD Dark Maze EN', Nrml).dir(Direction.East, 0x19, Top, High).small_key().pos(1),
create_door(player, 'PoD Dark Maze E', DoorType.Normal).dir(Direction.East, 0x19, Mid, High).pos(0), create_door(player, 'PoD Dark Maze E', Nrml).dir(Direction.East, 0x19, Mid, High).pos(0),
create_door(player, 'PoD Compass Room WN', DoorType.Interior).dir(Direction.West, 0x1a, Top, High).pos(4), create_door(player, 'PoD Compass Room WN', Intr).dir(Direction.West, 0x1a, Top, High).pos(4),
create_door(player, 'PoD Compass Room SE', DoorType.Interior).dir(Direction.North, 0x1a, Mid, High).small_key().pos(0), create_door(player, 'PoD Compass Room SE', Intr).dir(Direction.North, 0x1a, Mid, High).small_key().pos(0),
create_door(player, 'PoD Harmless Hellway NE', DoorType.Interior).dir(Direction.North, 0x1a, Right, High).small_key().pos(0), create_door(player, 'PoD Harmless Hellway NE', Intr).dir(Direction.North, 0x1a, Right, High).small_key().pos(0),
create_door(player, 'PoD Harmless Hellway SE', DoorType.Normal).dir(Direction.South, 0x1a, Right, High).pos(5), create_door(player, 'PoD Harmless Hellway SE', Nrml).dir(Direction.South, 0x1a, Right, High).pos(5),
create_door(player, 'PoD Compass Room W Down Stairs', DoorType.SpiralStairs).dir(Direction.Down, 0x1a, 0, HTH).ss(S, 0x12, 0x50, True, True), create_door(player, 'PoD Compass Room W Down Stairs', Sprl).dir(Direction.Down, 0x1a, 0, HTH).ss(S, 0x12, 0x50, True, True),
create_door(player, 'PoD Compass Room E Down Stairs', DoorType.SpiralStairs).dir(Direction.Down, 0x1a, 1, HTH).ss(S, 0x11, 0xb0, True, True), create_door(player, 'PoD Compass Room E Down Stairs', Sprl).dir(Direction.Down, 0x1a, 1, HTH).ss(S, 0x11, 0xb0, True, True),
create_door(player, 'PoD Dark Basement W Up Stairs', DoorType.SpiralStairs).dir(Direction.Up, 0x6a, 0, HTH).ss(S, 0x1b, 0x3c, True), create_door(player, 'PoD Dark Basement W Up Stairs', Sprl).dir(Direction.Up, 0x6a, 0, HTH).ss(S, 0x1b, 0x3c, True),
create_door(player, 'PoD Dark Basement E Up Stairs', DoorType.SpiralStairs).dir(Direction.Up, 0x6a, 1, HTH).ss(S, 0x1b, 0x9c, True), create_door(player, 'PoD Dark Basement E Up Stairs', Sprl).dir(Direction.Up, 0x6a, 1, HTH).ss(S, 0x1b, 0x9c, True),
create_door(player, 'PoD Dark Alley NE', DoorType.Normal).dir(Direction.North, 0x6a, Right, High).big_key().pos(0), create_door(player, 'PoD Dark Alley NE', Nrml).dir(Direction.North, 0x6a, Right, High).big_key().pos(0),
create_door(player, 'PoD Mimics 2 SW', DoorType.Normal).dir(Direction.South, 0x1b, Left, High).pos(1), create_door(player, 'PoD Mimics 2 SW', Nrml).dir(Direction.South, 0x1b, Left, High).pos(1),
create_door(player, 'PoD Mimics 2 NW', DoorType.Interior).dir(Direction.North, 0x1b, Left, High).pos(0), create_door(player, 'PoD Mimics 2 NW', Intr).dir(Direction.North, 0x1b, Left, High).pos(0),
create_door(player, 'PoD Bow Statue SW', DoorType.Interior).dir(Direction.South, 0x1b, Left, High).pos(0), create_door(player, 'PoD Bow Statue SW', Intr).dir(Direction.South, 0x1b, Left, High).pos(0),
create_door(player, 'PoD Bow Statue Down Ladder', DoorType.Ladder), create_door(player, 'PoD Bow Statue Down Ladder', Lddr).no_entrance(),
create_door(player, 'PoD Dark Pegs Up Ladder', DoorType.Ladder), create_door(player, 'PoD Dark Pegs Up Ladder', Lddr),
create_door(player, 'PoD Dark Pegs WN', DoorType.Interior).dir(Direction.West, 0x0b, Mid, High).small_key().pos(2), create_door(player, 'PoD Dark Pegs WN', Intr).dir(Direction.West, 0x0b, Mid, High).small_key().pos(2),
create_door(player, 'PoD Lonely Turtle SW', DoorType.Interior).dir(Direction.South, 0x0b, Mid, High).pos(0), create_door(player, 'PoD Lonely Turtle SW', Intr).dir(Direction.South, 0x0b, Mid, High).pos(0),
create_door(player, 'PoD Lonely Turtle EN', DoorType.Interior).dir(Direction.East, 0x0b, Mid, High).small_key().pos(2), create_door(player, 'PoD Lonely Turtle EN', Intr).dir(Direction.East, 0x0b, Mid, High).small_key().pos(2),
create_door(player, 'PoD Turtle Party ES', DoorType.Interior).dir(Direction.East, 0x0b, Mid, High).pos(1), create_door(player, 'PoD Turtle Party ES', Intr).dir(Direction.East, 0x0b, Mid, High).pos(1),
create_door(player, 'PoD Turtle Party NW', DoorType.Interior).dir(Direction.North, 0x0b, Mid, High).pos(0), create_door(player, 'PoD Turtle Party NW', Intr).dir(Direction.North, 0x0b, Mid, High).pos(0),
create_door(player, 'PoD Callback WS', DoorType.Interior).dir(Direction.West, 0x0b, Mid, High).pos(1), create_door(player, 'PoD Callback WS', Intr).dir(Direction.West, 0x0b, Mid, High).pos(1),
create_door(player, 'PoD Callback Warp', DoorType.Warp), create_door(player, 'PoD Callback Warp', Warp),
create_door(player, 'PoD Boss SE', DoorType.Normal).dir(Direction.South, 0x5a, Right, High).no_exit().trap(0x4).pos(0), create_door(player, 'PoD Boss SE', Nrml).dir(Direction.South, 0x5a, Right, High).no_exit().trap(0x4).pos(0),
create_door(player, 'Swamp Lobby Moat', Lgcl),
create_door(player, 'Swamp Entrance Down Stairs', Sprl).dir(Direction.Down, 0x28, 0, HTH).ss(A, 0x11, 0x80).small_key().pos(0),
create_door(player, 'Swamp Entrance Moat', Lgcl),
create_door(player, 'Swamp Pot Row Up Stairs', Sprl).dir(Direction.Up, 0x38, 0, HTH).ss(A, 0x1a, 0x6c, True),
create_door(player, 'Swamp Pot Row WN', Nrml).dir(Direction.West, 0x38, Top, High).pos(0),
create_door(player, 'Swamp Pot Row WS', Nrml).dir(Direction.West, 0x38, Bot, High).small_key().pos(1),
create_door(player, 'Swamp Map Ledge EN', Nrml).dir(Direction.East, 0x37, Top, High).pos(1),
create_door(player, 'Swamp Trench 1 Approach ES', Nrml).dir(Direction.East, 0x37, Bot, High).small_key().pos(3),
create_door(player, 'Swamp Trench 1 Approach Dry', Lgcl),
create_door(player, 'Swamp Trench 1 Approach Key', Lgcl),
create_door(player, 'Swamp Trench 1 Approach Swim Depart', Lgcl),
create_door(player, 'Swamp Trench 1 Nexus Approach', Lgcl),
create_door(player, 'Swamp Trench 1 Nexus Key', Lgcl),
create_door(player, 'Swamp Trench 1 Nexus N', Intr).dir(Direction.North, 0x37, Mid, Low).pos(5),
create_door(player, 'Swamp Trench 1 Alcove S', Intr).dir(Direction.South, 0x37, Mid, Low).pos(5),
create_door(player, 'Swamp Trench 1 Key Ledge Dry', Lgcl),
create_door(player, 'Swamp Trench 1 Key Approach', Lgcl),
create_door(player, 'Swamp Trench 1 Key Ledge Depart', Lgcl),
create_door(player, 'Swamp Trench 1 Key Ledge NW', Intr).dir(Direction.North, 0x37, Left, High).small_key().pos(2),
create_door(player, 'Swamp Trench 1 Departure Dry', Lgcl),
create_door(player, 'Swamp Trench 1 Departure Approach', Lgcl),
create_door(player, 'Swamp Trench 1 Departure Key', Lgcl),
create_door(player, 'Swamp Trench 1 Departure WS', Nrml).dir(Direction.West, 0x37, Bot, High).pos(4),
create_door(player, 'Swamp Hammer Switch SW', Intr).dir(Direction.South, 0x37, Left, High).small_key().pos(2),
create_door(player, 'Swamp Hammer Switch WN', Nrml).dir(Direction.West, 0x37, Top, High).pos(0),
create_door(player, 'Swamp Hub ES', Nrml).dir(Direction.East, 0x36, Bot, High).pos(4),
create_door(player, 'Swamp Hub S', Nrml).dir(Direction.South, 0x36, Mid, High).pos(5),
create_door(player, 'Swamp Hub WS', Nrml).dir(Direction.West, 0x36, Bot, High).pos(3),
create_door(player, 'Swamp Hub WN', Nrml).dir(Direction.West, 0x36, Top, High).small_key().pos(2),
create_door(player, 'Swamp Hub Hook Path', Lgcl),
create_door(player, 'Swamp Hub Dead Ledge EN', Nrml).dir(Direction.East, 0x36, Top, High).pos(0),
create_door(player, 'Swamp Hub North Ledge N', Nrml).dir(Direction.North, 0x36, Mid, High).small_key().pos(1),
create_door(player, 'Swamp Hub North Ledge Drop Down', Lgcl),
create_door(player, 'Swamp Donut Top N', Nrml).dir(Direction.North, 0x46, Mid, High).pos(0),
create_door(player, 'Swamp Donut Top SE', Intr).dir(Direction.South, 0x46, Right, High).pos(2),
create_door(player, 'Swamp Donut Bottom NE', Intr).dir(Direction.North, 0x46, Right, High).pos(2),
create_door(player, 'Swamp Donut Bottom NW', Intr).dir(Direction.North, 0x46, Left, High).pos(1),
create_door(player, 'Swamp Compass Donut SW', Intr).dir(Direction.South, 0x46, Left, High).pos(1),
create_door(player, 'Swamp Compass Donut Push Block', Lgcl),
create_door(player, 'Swamp Crystal Switch EN', Nrml).dir(Direction.East, 0x35, Top, High).small_key().pos(0),
create_door(player, 'Swamp Crystal Switch SE', Intr).dir(Direction.South, 0x35, Right, High).pos(3),
create_door(player, 'Swamp Shortcut NE', Intr).dir(Direction.North, 0x35, Right, High).pos(3),
create_door(player, 'Swamp Shortcut Blue Barrier', Lgcl),
create_door(player, 'Swamp Trench 2 Pots ES', Nrml).dir(Direction.East, 0x35, Bot, High).pos(4),
create_door(player, 'Swamp Trench 2 Pots Blue Barrier', Lgcl),
create_door(player, 'Swamp Trench 2 Pots Dry', Lgcl),
create_door(player, 'Swamp Trench 2 Pots Wet', Lgcl),
create_door(player, 'Swamp Trench 2 Blocks Pots', Lgcl),
create_door(player, 'Swamp Trench 2 Blocks N', Intr).dir(Direction.North, 0x35, Mid, Low).pos(5),
create_door(player, 'Swamp Trench 2 Alcove S', Intr).dir(Direction.South, 0x35, Mid, Low).pos(5),
create_door(player, 'Swamp Trench 2 Departure Wet', Lgcl),
create_door(player, 'Swamp Trench 2 Departure WS', Nrml).dir(Direction.West, 0x35, Bot, High).pos(2),
create_door(player, 'Swamp Big Key Ledge WN', Nrml).dir(Direction.West, 0x35, Top, High).pos(1),
create_door(player, 'Swamp West Shallows ES', Nrml).dir(Direction.East, 0x34, Bot, High).pos(1),
create_door(player, 'Swamp West Shallows Push Blocks', Lgcl),
create_door(player, 'Swamp West Block Path Up Stairs', Sprl).dir(Direction.Up, 0x34, 0, HTH).ss(Z, 0x1b, 0x6c, False, True),
create_door(player, 'Swamp West Block Path Drop Down', Lgcl),
create_door(player, 'Swamp West Ledge Drop Down', Lgcl),
create_door(player, 'Swamp West Ledge Hook Path', Lgcl),
create_door(player, 'Swamp Barrier Ledge Drop Down', Lgcl),
create_door(player, 'Swamp Barrier Ledge - Orange', Lgcl),
create_door(player, 'Swamp Barrier EN', Nrml).dir(Direction.East, 0x34, Top, High).pos(0),
create_door(player, 'Swamp Barrier - Orange', Lgcl),
create_door(player, 'Swamp Barrier Ledge Hook Path', Lgcl),
create_door(player, 'Swamp Attic Down Stairs', Sprl).dir(Direction.Down, 0x54, 0, HTH).ss(Z, 0x12, 0x80, False, True),
create_door(player, 'Swamp Attic Left Pit', Hole),
create_door(player, 'Swamp Attic Right Pit', Hole),
create_door(player, 'Swamp Push Statue S', Nrml).dir(Direction.South, 0x26, Mid, High).small_key().pos(0),
create_door(player, 'Swamp Push Statue NW', Intr).dir(Direction.North, 0x26, Left, High).pos(1),
create_door(player, 'Swamp Push Statue NE', Intr).dir(Direction.North, 0x26, Right, High).pos(2),
create_door(player, 'Swamp Push Statue Down Stairs', Sprl).dir(Direction.Down, 0x26, 2, HTH).ss(X, 0x12, 0xc0, False, True),
create_door(player, 'Swamp Shooters SW', Intr).dir(Direction.South, 0x26, Left, High).pos(1),
create_door(player, 'Swamp Shooters EN', Intr).dir(Direction.East, 0x26, Top, High).pos(3),
create_door(player, 'Swamp Left Elbow WN', Intr).dir(Direction.West, 0x26, Top, High).pos(3),
create_door(player, 'Swamp Left Elbow Down Stairs', Sprl).dir(Direction.Down, 0x26, 0, HTH).ss(S, 0x11, 0x40, True, True),
create_door(player, 'Swamp Right Elbow SE', Intr).dir(Direction.South, 0x26, Right, High).pos(2),
create_door(player, 'Swamp Right Elbow Down Stairs', Sprl).dir(Direction.Down, 0x26, 1, HTH).ss(S, 0x12, 0xb0, True, True),
create_door(player, 'Swamp Drain Left Up Stairs', Sprl).dir(Direction.Up, 0x76, 0, HTH).ss(S, 0x1b, 0x2c, True, True),
create_door(player, 'Swamp Drain WN', Intr).dir(Direction.West, 0x76, Top, Low).pos(0),
create_door(player, 'Swamp Drain Right Switch', Lgcl),
create_door(player, 'Swamp Drain Right Up Stairs', Sprl).dir(Direction.Up, 0x76, 1, HTH).ss(S, 0x1b, 0x9c, True, True),
create_door(player, 'Swamp Flooded Room Up Stairs', Sprl).dir(Direction.Up, 0x76, 2, HTH).ss(X, 0x1a, 0xac, True, True),
create_door(player, 'Swamp Flooded Room WS', Intr).dir(Direction.West, 0x76, Bot, Low).pos(1),
create_door(player, 'Swamp Flooded Spot Ladder', Lgcl),
create_door(player, 'Swamp Flooded Room Ladder', Lgcl),
create_door(player, 'Swamp Basement Shallows NW', Nrml).dir(Direction.North, 0x76, Left, High).toggler().pos(2),
create_door(player, 'Swamp Basement Shallows EN', Intr).dir(Direction.West, 0x76, Top, High).pos(0),
create_door(player, 'Swamp Basement Shallows ES', Intr).dir(Direction.East, 0x76, Bot, High).pos(1),
create_door(player, 'Swamp Waterfall Room SW', Nrml).dir(Direction.South, 0x66, Left, Low).toggler().pos(1),
create_door(player, 'Swamp Waterfall Room NW', Intr).dir(Direction.North, 0x66, Left, Low).pos(3),
create_door(player, 'Swamp Waterfall Room NE', Intr).dir(Direction.North, 0x66, Right, Low).pos(0),
create_door(player, 'Swamp Refill SW', Intr).dir(Direction.South, 0x66, Left, Low).pos(3),
create_door(player, 'Swamp Behind Waterfall SE', Intr).dir(Direction.South, 0x66, Right, Low).pos(0),
create_door(player, 'Swamp Behind Waterfall Up Stairs', Sprl).dir(Direction.Up, 0x66, 0, HTH).ss(S, 0x1a, 0x6c, True, True),
create_door(player, 'Swamp C Down Stairs', Sprl).dir(Direction.Down, 0x16, 0, HTH).ss(S, 0x11, 0x80, True, True),
create_door(player, 'Swamp C SE', Intr).dir(Direction.South, 0x16, Right, High).pos(2),
create_door(player, 'Swamp Waterway NE', Intr).dir(Direction.North, 0x16, Right, High).pos(2),
create_door(player, 'Swamp Waterway N', Intr).dir(Direction.North, 0x16, Mid, High).pos(0),
create_door(player, 'Swamp Waterway NW', Intr).dir(Direction.North, 0x16, Left, High).small_key().pos(1),
create_door(player, 'Swamp I S', Intr).dir(Direction.South, 0x16, Mid, High).pos(0),
create_door(player, 'Swamp T SW', Intr).dir(Direction.South, 0x16, Left, High).small_key().pos(1),
create_door(player, 'Swamp T NW', Nrml).dir(Direction.North, 0x16, Left, High).pos(3),
create_door(player, 'Swamp Boss SW', Nrml).dir(Direction.South, 0x06, Left, High).trap(0x4).pos(0),
create_door(player, 'Skull 1 Lobby WS', Nrml).dir(Direction.West, 0x58, Bot, High).small_key().pos(1),
create_door(player, 'Skull 1 Lobby ES', Intr).dir(Direction.East, 0x58, Bot, High).pos(5),
create_door(player, 'Skull Map Room WS', Intr).dir(Direction.West, 0x58, Bot, High).pos(5),
create_door(player, 'Skull Map Room SE', Nrml).dir(Direction.South, 0x58, Right, High).small_key().pos(2),
create_door(player, 'Skull Pot Circle WN', Intr).dir(Direction.West, 0x58, Top, High).pos(3),
create_door(player, 'Skull Pull Switch EN', Intr).dir(Direction.East, 0x58, Top, High).pos(3),
create_door(player, 'Skull Pot Circle Star Path', Lgcl),
create_door(player, 'Skull Pull Switch S', Intr).dir(Direction.South, 0x58, Left, High).pos(0),
create_door(player, 'Skull Big Chest N', Intr).dir(Direction.North, 0x58, Left, High).no_exit().pos(0),
create_door(player, 'Skull Big Chest Hookpath', Lgcl),
create_door(player, 'Skull Pinball NE', Nrml).dir(Direction.North, 0x68, Right, High).small_key().pos(1),
create_door(player, 'Skull Pinball WS', Nrml).dir(Direction.West, 0x68, Bot, High).no_exit().trap(0x4).pos(0),
create_door(player, 'Skull Compass Room NE', Nrml).dir(Direction.North, 0x67, Right, High).pos(0),
create_door(player, 'Skull Compass Room ES', Nrml).dir(Direction.East, 0x67, Bot, High).pos(2),
create_door(player, 'Skull Left Drop ES', Intr).dir(Direction.East, 0x67, Bot, High).pos(1),
create_door(player, 'Skull Compass Room WS', Intr).dir(Direction.West, 0x67, Bot, High).pos(1),
create_door(player, 'Skull Pot Prison ES', Nrml).dir(Direction.East, 0x57, Bot, High).small_key().pos(2),
create_door(player, 'Skull Pot Prison SE', Nrml).dir(Direction.South, 0x57, Right, High).pos(5),
create_door(player, 'Skull 2 East Lobby WS', Nrml).dir(Direction.West, 0x57, Bot, High).pos(4),
create_door(player, 'Skull 2 East Lobby NW', Intr).dir(Direction.North, 0x57, Left, High).pos(1),
create_door(player, 'Skull Big Key SW', Intr).dir(Direction.South, 0x57, Left, High).pos(1),
create_door(player, 'Skull Big Key WN', Intr).dir(Direction.West, 0x57, Top, High).pos(0),
create_door(player, 'Skull Lone Pot EN', Intr).dir(Direction.East, 0x57, Top, High).pos(0),
create_door(player, 'Skull Small Hall ES', Nrml).dir(Direction.East, 0x56, Bot, High).pos(3),
create_door(player, 'Skull Small Hall WS', Intr).dir(Direction.West, 0x56, Bot, High).pos(2),
create_door(player, 'Skull 2 West Lobby ES', Intr).dir(Direction.East, 0x56, Bot, High).pos(2),
create_door(player, 'Skull 2 West Lobby NW', Intr).dir(Direction.North, 0x56, Left, High).small_key().pos(0),
create_door(player, 'Skull X Room SW', Intr).dir(Direction.South, 0x56, Left, High).small_key().pos(0),
create_door(player, 'Skull Back Drop Star Path', Lgcl),
create_door(player, 'Skull 3 Lobby NW', Nrml).dir(Direction.North, 0x59, Left, High).small_key().pos(0),
create_door(player, 'Skull 3 Lobby WN', Intr).dir(Direction.West, 0x59, Top, High).pos(2),
create_door(player, 'Skull East Bridge EN', Intr).dir(Direction.East, 0x59, Top, High).pos(2),
create_door(player, 'Skull East Bridge ES', Intr).dir(Direction.East, 0x59, Bot, High).pos(3),
create_door(player, 'Skull West Bridge Nook WS', Intr).dir(Direction.West, 0x59, Bot, High).pos(3),
create_door(player, 'Skull Star Pits SW', Nrml).dir(Direction.South, 0x49, Left, High).small_key().pos(2),
create_door(player, 'Skull Star Pits WS', Intr).dir(Direction.West, 0x49, Bot, High).pos(3),
create_door(player, 'Skull Torch Room ES', Intr).dir(Direction.East, 0x49, Bot, High).pos(3),
create_door(player, 'Skull Torch Room EN', Intr).dir(Direction.East, 0x49, Top, High).pos(1),
create_door(player, 'Skull Vines WN', Intr).dir(Direction.West, 0x49, Top, High).pos(1),
create_door(player, 'Skull Vines NW', Nrml).dir(Direction.North, 0x49, Left, High).pos(0),
create_door(player, 'Skull Spike Corner SW', Nrml).dir(Direction.South, 0x39, Left, High).no_exit().trap(0x4).pos(0),
create_door(player, 'Skull Spike Corner WS', Intr).dir(Direction.West, 0x39, Bot, High).small_key().pos(1),
create_door(player, 'Skull Final Drop ES', Intr).dir(Direction.East, 0x39, Bot, High).small_key().pos(1),
create_door(player, 'Skull Final Drop Hole', Hole),
create_door(player, 'Thieves Lobby N Edge', Open).dir(Direction.North, 0xdb, None, Low),
create_door(player, 'Thieves Lobby NE Edge', Open).dir(Direction.North, 0xdb, None, Low),
create_door(player, 'Thieves Lobby E', Nrml).dir(Direction.East, 0xdb, Mid, High).no_exit().trap(0x4).pos(0),
create_door(player, 'Thieves Big Chest Nook WS Edge', Open).dir(Direction.West, 0xdb, None, Low),
create_door(player, 'Thieves Ambush S Edge', Open).dir(Direction.South, 0xcb, None, Low),
create_door(player, 'Thieves Ambush SE Edge', Open).dir(Direction.South, 0xcb, None, Low),
create_door(player, 'Thieves Ambush ES Edge', Open).dir(Direction.East, 0xcb, None, Low),
create_door(player, 'Thieves Ambush EN Edge', Open).dir(Direction.East, 0xcb, None, Low),
create_door(player, 'Thieves Ambush E', Nrml).dir(Direction.East, 0xcb, Mid, High).pos(0),
create_door(player, 'Thieves BK Corner WN Edge', Open).dir(Direction.West, 0xcc, None, Low),
create_door(player, 'Thieves BK Corner WS Edge', Open).dir(Direction.West, 0xcc, None, Low),
create_door(player, 'Thieves BK Corner S Edge', Open).dir(Direction.South, 0xcc, None, Low),
create_door(player, 'Thieves BK Corner SW Edge', Open).dir(Direction.South, 0xcc, None, Low),
create_door(player, 'Thieves BK Corner W', Nrml).dir(Direction.West, 0xcc, Mid, High).pos(2),
create_door(player, 'Thieves BK Corner NW', Nrml).dir(Direction.North, 0xcc, Left, High).pos(1),
create_door(player, 'Thieves BK Corner NE', Nrml).dir(Direction.North, 0xcc, Right, High).big_key().pos(0),
create_door(player, 'Thieves Compass Room NW Edge', Open).dir(Direction.North, 0xdc, None, Low),
create_door(player, 'Thieves Compass Room N Edge', Open).dir(Direction.North, 0xdc, None, Low),
create_door(player, 'Thieves Compass Room WS Edge', Open).dir(Direction.West, 0xdc, None, Low),
create_door(player, 'Thieves Compass Room W', Nrml).dir(Direction.West, 0xdc, Mid, High).pos(0),
create_door(player, 'Thieves Hallway SE', Nrml).dir(Direction.South, 0xbc, Right, High).small_key().pos(1),
create_door(player, 'Thieves Hallway NE', Nrml).dir(Direction.North, 0xbc, Right, High).pos(7),
create_door(player, 'Thieves Pot Alcove Mid WS', Nrml).dir(Direction.West, 0xbc, Bot, High).pos(5),
create_door(player, 'Thieves Pot Alcove Bottom SW', Nrml).dir(Direction.South, 0xbc, Left, High).pos(3),
create_door(player, 'Thieves Conveyor Maze WN', Nrml).dir(Direction.West, 0xbc, Top, High).pos(4),
create_door(player, 'Thieves Hallway WS', Intr).dir(Direction.West, 0xbc, Bot, High).small_key().pos(0),
create_door(player, 'Thieves Pot Alcove Mid ES', Intr).dir(Direction.East, 0xbc, Bot, High).small_key().pos(0),
create_door(player, 'Thieves Conveyor Maze SW', Intr).dir(Direction.South, 0xbc, Left, High).pos(6),
create_door(player, 'Thieves Pot Alcove Top NW', Intr).dir(Direction.North, 0xbc, Left, High).pos(6),
create_door(player, 'Thieves Conveyor Maze EN', Intr).dir(Direction.East, 0xbc, Top, High).pos(2),
create_door(player, 'Thieves Hallway WN', Intr).dir(Direction.West, 0xbc, Top, High).no_exit().pos(2),
create_door(player, 'Thieves Conveyor Maze Down Stairs', Sprl).dir(Direction.Down, 0xbc, 0, HTH).ss(A, 0x11, 0x80, True, True),
create_door(player, 'Thieves Boss SE', Nrml).dir(Direction.South, 0xac, Right, High).no_exit().trap(0x4).pos(0),
create_door(player, 'Thieves Spike Track ES', Nrml).dir(Direction.East, 0xbb, Bot, High).pos(5),
create_door(player, 'Thieves Hellway NW', Nrml).dir(Direction.North, 0xbb, Left, High).pos(0),
create_door(player, 'Thieves Triple Bypass EN', Nrml).dir(Direction.East, 0xbb, Top, High).pos(4),
create_door(player, 'Thieves Hellway Orange Barrier', Lgcl),
create_door(player, 'Thieves Hellway Crystal Orange Barrier', Lgcl),
create_door(player, 'Thieves Hellway Blue Barrier', Lgcl),
create_door(player, 'Thieves Hellway Crystal Blue Barrier', Lgcl),
create_door(player, 'Thieves Spike Track WS', Intr).dir(Direction.West, 0xbb, Bot, High).pos(2),
create_door(player, 'Thieves Hellway Crystal ES', Intr).dir(Direction.East, 0xbb, Bot, High).pos(2),
create_door(player, 'Thieves Spike Track NE', Intr).dir(Direction.North, 0xbb, Right, High).pos(3),
create_door(player, 'Thieves Triple Bypass SE', Intr).dir(Direction.South, 0xbb, Right, High).pos(3),
create_door(player, 'Thieves Hellway Crystal EN', Intr).dir(Direction.East, 0xbb, Top, High).pos(1),
create_door(player, 'Thieves Triple Bypass WN', Intr).dir(Direction.West, 0xbb, Top, High).pos(1),
create_door(player, 'Thieves Spike Switch SW', Nrml).dir(Direction.South, 0xab, Left, High).pos(1),
create_door(player, 'Thieves Spike Switch Up Stairs', Sprl).dir(Direction.Up, 0xab, 0, HTH).ss(Z, 0x1a, 0x6c, True, True).small_key().pos(0),
create_door(player, 'Thieves Attic Down Stairs', Sprl).dir(Direction.Down, 0x64, 0, HTH).ss(Z, 0x11, 0x80, True, True),
create_door(player, 'Thieves Attic ES', Intr).dir(Direction.East, 0x64, Bot, High).pos(0),
create_door(player, 'Thieves Cricket Hall Left WS', Intr).dir(Direction.West, 0x64, Bot, High).pos(0),
create_door(player, 'Thieves Cricket Hall Left Edge', Open).dir(Direction.East, 0x64, None, High),
create_door(player, 'Thieves Cricket Hall Right Edge', Open).dir(Direction.West, 0x65, None, High),
create_door(player, 'Thieves Cricket Hall Right ES', Intr).dir(Direction.East, 0x65, Bot, High).pos(0),
create_door(player, 'Thieves Attic Window WS', Intr).dir(Direction.West, 0x65, Bot, High).pos(0),
create_door(player, 'Thieves Basement Block Up Stairs', Sprl).dir(Direction.Up, 0x45, 0, HTH).ss(A, 0x1a, 0x6c, True, True),
create_door(player, 'Thieves Basement Block WN', Nrml).dir(Direction.West, 0x45, Top, High).trap(0x4).pos(0),
create_door(player, 'Thieves Basement Block Path', Lgcl),
create_door(player, 'Thieves Blocked Entry Path', Lgcl),
create_door(player, 'Thieves Lonely Zazak WS', Nrml).dir(Direction.West, 0x45, Bot, High).pos(2),
create_door(player, 'Thieves Blocked Entry SW', Intr).dir(Direction.South, 0x45, Left, High).pos(1),
create_door(player, 'Thieves Lonely Zazak NW', Intr).dir(Direction.North, 0x45, Left, High).pos(1),
create_door(player, 'Thieves Lonely Zazak ES', Intr).dir(Direction.East, 0x45, Right, High).pos(3),
create_door(player, 'Thieves Blind\'s Cell WS', Intr).dir(Direction.West, 0x45, Right, High).pos(3),
create_door(player, 'Thieves Conveyor Bridge EN', Nrml).dir(Direction.East, 0x44, Top, High).pos(2),
create_door(player, 'Thieves Conveyor Bridge ES', Nrml).dir(Direction.East, 0x44, Bot, High).pos(3),
create_door(player, 'Thieves Conveyor Bridge Block Path', Lgcl),
create_door(player, 'Thieves Conveyor Block Path', Lgcl),
create_door(player, 'Thieves Conveyor Bridge WS', Intr).dir(Direction.West, 0x44, Bot, High).small_key().pos(1),
create_door(player, 'Thieves Big Chest Room ES', Intr).dir(Direction.East, 0x44, Bot, High).small_key().pos(1),
create_door(player, 'Thieves Conveyor Block WN', Intr).dir(Direction.West, 0x44, Top, High).pos(0),
create_door(player, 'Thieves Trap EN', Intr).dir(Direction.East, 0x44, Left, Top).pos(0),
# Door Templates
# create_door(player, '', Nrml).dir(Direction.North, 0x00, Mid, High).pos(),
# create_door(player, '', Intr).dir(Direction.North, 0x00, Left, High).pos(),
# create_door(player, '', Sprl).dir(Direction.North, 0x00, 0, High).ss(),
# create_door(player, '', Open).dir(Direction.North, 0x00, None, High),
# create_door(player, '', Lgcl),
# create_door(player, '', Hole),
# create_door(player, '', Warp),
] ]
create_paired_doors(world, player) create_paired_doors(world, player)
# swamp events
world.get_door('Swamp Trench 1 Approach Key', player).event('Trench 1 Switch')
world.get_door('Swamp Trench 1 Approach Swim Depart', player).event('Trench 1 Switch')
world.get_door('Swamp Trench 1 Key Approach', player).event('Trench 1 Switch')
world.get_door('Swamp Trench 1 Key Ledge Depart', player).event('Trench 1 Switch')
world.get_door('Swamp Trench 1 Departure Approach', player).event('Trench 1 Switch')
world.get_door('Swamp Trench 1 Departure Key', player).event('Trench 1 Switch')
world.get_door('Swamp Trench 2 Pots Wet', player).event('Trench 2 Switch')
world.get_door('Swamp Trench 2 Departure Wet', player).event('Trench 2 Switch')
world.get_door('Swamp Drain WN', player).event('Swamp Drain')
world.get_door('Swamp Flooded Room WS', player).event('Swamp Drain')
world.get_door('Swamp Drain Right Switch', player).event('Swamp Drain')
world.get_door('Swamp Flooded Room Ladder', player).event('Swamp Drain')
# crystal switches and barriers
world.get_door('Hera Lobby Down Stairs', player).c_switch()
world.get_door('Hera Lobby Key Stairs', player).c_switch()
world.get_door('Hera Lobby Up Stairs', player).c_switch()
world.get_door('Hera Basement Cage Up Stairs', player).c_switch()
world.get_door('Hera Tile Room Up Stairs', player).c_switch()
world.get_door('Hera Tile Room EN', player).c_switch()
world.get_door('Hera Tridorm WN', player).c_switch()
world.get_door('Hera Tridorm SE', player).c_switch()
world.get_door('Hera Beetles Down Stairs', player).c_switch()
world.get_door('Hera Beetles WS', player).c_switch()
world.get_door('Hera Beetles Holes', player).c_switch()
world.get_door('Hera Startile Wide SW', player).c_switch()
world.get_door('Hera Startile Wide Up Stairs', player).c_switch()
world.get_door('Hera Startile Wide Holes', player).c_switch()
world.get_door('PoD Arena Main SW', player).c_switch()
world.get_door('PoD Arena Bridge SE', player).c_switch()
world.get_door('PoD Arena Main NW', player).barrier(CrystalBarrier.Orange)
world.get_door('PoD Arena Main NE', player).barrier(CrystalBarrier.Orange)
# maybe you can cross this way with blue up??
world.get_door('PoD Arena Main Crystal Path', player).barrier(CrystalBarrier.Blue)
world.get_door('PoD Arena Crystals E', player).barrier(CrystalBarrier.Blue)
world.get_door('PoD Arena Crystal Path', player).barrier(CrystalBarrier.Blue)
world.get_door('PoD Sexy Statue W', player).c_switch()
world.get_door('PoD Sexy Statue NW', player).c_switch()
world.get_door('PoD Bow Statue SW', player).c_switch()
world.get_door('PoD Bow Statue Down Ladder', player).c_switch()
world.get_door('PoD Dark Pegs Up Ladder', player).c_switch()
world.get_door('PoD Dark Pegs WN', player).c_switch()
world.get_door('Swamp Crystal Switch EN', player).c_switch()
world.get_door('Swamp Crystal Switch SE', player).c_switch()
world.get_door('Swamp Shortcut Blue Barrier', player).barrier(CrystalBarrier.Blue)
world.get_door('Swamp Trench 2 Pots Blue Barrier', player).barrier(CrystalBarrier.Blue)
world.get_door('Swamp Barrier Ledge - Orange', player).barrier(CrystalBarrier.Orange)
world.get_door('Swamp Barrier - Orange', player).barrier(CrystalBarrier.Orange)
world.get_door('Thieves Spike Switch Up Stairs', player).c_switch()
world.get_door('Thieves Spike Switch SW', player).c_switch()
world.get_door('Thieves Attic ES', player).barrier(CrystalBarrier.Blue)
world.get_door('Thieves Hellway Blue Barrier', player).barrier(CrystalBarrier.Blue)
world.get_door('Thieves Hellway Crystal Blue Barrier', player).barrier(CrystalBarrier.Blue)
world.get_door('Thieves Triple Bypass SE', player).barrier(CrystalBarrier.Blue)
world.get_door('Thieves Triple Bypass WN', player).barrier(CrystalBarrier.Blue)
world.get_door('Thieves Triple Bypass EN', player).barrier(CrystalBarrier.Blue)
world.get_door('Thieves Hellway Orange Barrier', player).barrier(CrystalBarrier.Orange)
world.get_door('Thieves Hellway Crystal Orange Barrier', player).barrier(CrystalBarrier.Orange)
def create_paired_doors(world, player): def create_paired_doors(world, player):
world.paired_doors[player] = [ world.paired_doors[player] = [
@@ -336,18 +638,19 @@ def create_paired_doors(world, player):
PairedDoor('PoD Dark Maze E', 'PoD Big Chest Balcony W'), # PoD Bombable by Big Chest PairedDoor('PoD Dark Maze E', 'PoD Big Chest Balcony W'), # PoD Bombable by Big Chest
PairedDoor('PoD Arena Main NW', 'PoD Falling Bridge SW'), # Pod key door by bridge PairedDoor('PoD Arena Main NW', 'PoD Falling Bridge SW'), # Pod key door by bridge
PairedDoor('Sewers Dark Cross Key Door N', 'Sewers Dark Cross Key Door S'), PairedDoor('Sewers Dark Cross Key Door N', 'Sewers Dark Cross Key Door S'),
# PairedDoor('', ''), # Swamp key door above big chest PairedDoor('Swamp Hub WN', 'Swamp Crystal Switch EN'), # Swamp key door crystal switch
PairedDoor('Swamp Hub North Ledge N', 'Swamp Push Statue S'), # Swamp key door above big chest
PairedDoor('PoD Map Balcony WS', 'PoD Arena Ledge ES'), # Pod bombable by arena PairedDoor('PoD Map Balcony WS', 'PoD Arena Ledge ES'), # Pod bombable by arena
# PairedDoor('', ''), # Swamp bombable to random pots PairedDoor('Swamp Hub Dead Ledge EN', 'Swamp Hammer Switch WN'), # Swamp bombable to random pots
# PairedDoor('', ''), # Swamp bombable to map chest PairedDoor('Swamp Pot Row WN', 'Swamp Map Ledge EN'), # Swamp bombable to map chest
# PairedDoor('', ''), # Swamp key door early room $38 PairedDoor('Swamp Pot Row WS', 'Swamp Trench 1 Approach ES'), # Swamp key door early room $38
PairedDoor('PoD Middle Cage N', 'PoD Pit Room S'), PairedDoor('PoD Middle Cage N', 'PoD Pit Room S'),
# PairedDoor('', ''), # GT moldorm key door # PairedDoor('', ''), # GT moldorm key door
# PairedDoor('', ''), # Ice BJ key door # PairedDoor('', ''), # Ice BJ key door
PairedDoor('Desert Tiles 2 SE', 'Desert Beamos Hall NE'), PairedDoor('Desert Tiles 2 SE', 'Desert Beamos Hall NE'),
# PairedDoor('', ''), # Skull 3 key door PairedDoor('Skull 3 Lobby NW', 'Skull Star Pits SW'), # Skull 3 key door
# PairedDoor('', ''), # Skull 1 key door - pot prison to big chest PairedDoor('Skull 1 Lobby WS', 'Skull Pot Prison ES'), # Skull 1 key door - pot prison to big chest
# PairedDoor('', ''), # Skull 1 - pinball key door PairedDoor('Skull Map Room SE', 'Skull Pinball NE'), # Skull 1 - pinball key door
# PairedDoor('', ''), # gt main big key door # PairedDoor('', ''), # gt main big key door
# PairedDoor('', ''), # ice door to spike chest # PairedDoor('', ''), # ice door to spike chest
# PairedDoor('', ''), # gt right side key door to cape bridge # PairedDoor('', ''), # gt right side key door to cape bridge
@@ -359,61 +662,20 @@ def create_paired_doors(world, player):
PairedDoor('Eastern Big Key NE', 'Eastern Compass Area SW'), PairedDoor('Eastern Big Key NE', 'Eastern Compass Area SW'),
# PairedDoor('', ''), # TR somaria hub to pokey # PairedDoor('', ''), # TR somaria hub to pokey
PairedDoor('Eastern Dark Square Key Door WN', 'Eastern Cannonball Ledge Key Door EN'), PairedDoor('Eastern Dark Square Key Door WN', 'Eastern Cannonball Ledge Key Door EN'),
# PairedDoor('', ''), # TT random bomb to pots PairedDoor('Thieves BK Corner NW', 'Thieves Pot Alcove Bottom SW'), # TT random bomb to pots
# PairedDoor('', ''), # TT big key door PairedDoor('Thieves BK Corner NW', 'Thieves Hallway SE'), # TT big key door
# PairedDoor('', ''), # Ice last key door to crystal switch # PairedDoor('', ''), # Ice last key door to crystal switch
# PairedDoor('', ''), # mire hub key door to attic # PairedDoor('', ''), # mire hub key door to attic
# PairedDoor('', ''), # mire hub key door to map # PairedDoor('', ''), # mire hub key door to map
# PairedDoor('', ''), # tr last key door to switch maze # PairedDoor('', ''), # tr last key door to switch maze
# PairedDoor('', '') # TT dashable above PairedDoor('Thieves Ambush E', 'Thieves BK Corner W') # TT dashable above
] ]
def create_door(player, name, type): def create_door(player, name, door_type):
return Door(player, name, type, None, None, None, None) return Door(player, name, door_type)
def create_dir_door(player, name, type, direction, room, doorIndex, layer):
d = Door(player, name, type, direction, room, doorIndex, layer)
return d
def create_spiral_stairs(player, name, type, direction, room,
door_index, layer, quadrant, shift_y, shift_x, zero_hz_cam=False, zero_vt_cam=False):
d = Door(player, name, type, direction, room, door_index, layer)
d.quadrant = quadrant
d.shiftY = shift_y
d.shiftX = shift_x
d.zeroHzCam = zero_hz_cam
d.zeroVtCam = zero_vt_cam
return d
def ugly_door(door): def ugly_door(door):
door.ugly = True door.ugly = True
return door return door
def small_key(door):
door.smallKey = True
return door
def big_key(door):
door.bigKey = True
return door
def trap(door, trapFlag):
door.trapFlag = trapFlag
return door
def toggle(door):
door.toggle = True
return door
def blocked(door):
door.blocked = True
return door
+689
View File
@@ -0,0 +1,689 @@
import random
import collections
from collections import defaultdict
from enum import Enum, unique
import logging
from BaseClasses import DoorType, Direction, CrystalBarrier, RegionType, flooded_keys
from Regions import key_only_locations, dungeon_events, flooded_keys_reverse
@unique
class Hook(Enum):
North = 0
West = 1
South = 2
East = 3
Stairs = 4
class GraphPiece:
def __init__(self):
self.hanger_info = None
self.hooks = {}
self.visited_regions = set()
def generate_dungeon(available_sectors, entrance_region_names, world, player):
logger = logging.getLogger('')
entrance_regions = convert_regions(entrance_region_names, world, player)
doors_to_connect = set()
all_regions = set()
for sector in available_sectors:
for door in sector.outstanding_doors:
doors_to_connect.add(door)
all_regions.update(sector.regions)
proposed_map = {}
choices_master = [[]]
depth = 0
dungeon_cache = {}
backtrack = False
# last_choice = None
while len(proposed_map) < len(doors_to_connect):
# what are my choices?
if depth not in dungeon_cache.keys():
dungeon, hangers, hooks = gen_dungeon_info(available_sectors, entrance_regions, proposed_map, doors_to_connect, world, player)
dungeon_cache[depth] = dungeon, hangers, hooks
valid = check_valid(dungeon, hangers, hooks, proposed_map, doors_to_connect, all_regions)
else:
dungeon, hangers, hooks = dungeon_cache[depth]
valid = True
if valid:
prev_choices = choices_master[depth]
# make a choice
hanger, hook = make_a_choice(dungeon, hangers, hooks, prev_choices)
if hanger is None:
backtrack = True
else:
logger.debug(' '*depth+"%d: Linking %s to %s", depth, hanger.name, hook.name)
proposed_map[hanger] = hook
proposed_map[hook] = hanger
last_choice = (hanger, hook)
choices_master[depth].append(last_choice)
depth += 1
choices_master.append([])
else:
backtrack = True
if backtrack:
backtrack = False
choices_master.pop()
dungeon_cache.pop(depth, None)
depth -= 1
a, b = choices_master[depth][-1]
logger.debug(' '*depth+"%d: Rescinding %s, %s", depth, a.name, b.name)
proposed_map.pop(a, None)
proposed_map.pop(b, None)
queue = collections.deque(proposed_map.items())
while len(queue) > 0:
a, b = queue.pop()
connect_doors(a, b, world, player)
queue.remove((b, a))
master_sector = available_sectors.pop()
for sub_sector in available_sectors:
master_sector.regions.extend(sub_sector.regions)
return master_sector
def gen_dungeon_info(available_sectors, entrance_regions, proposed_map, valid_doors, world, player):
# step 1 create dungeon: Dict<DoorName|Origin, GraphPiece>
dungeon = {}
original_state = extend_reachable_state_improved(entrance_regions, ExplorationState(), proposed_map, valid_doors, world, player)
dungeon['Origin'] = create_graph_piece_from_state(None, original_state, original_state, proposed_map)
doors_to_connect = set()
blue_hooks = []
o_state_cache = {}
for sector in available_sectors:
for door in sector.outstanding_doors:
doors_to_connect.add(door)
if not door.stonewall and door not in proposed_map.keys():
parent = parent_region(door, world, player).parent_region
o_state = extend_reachable_state_improved([parent], ExplorationState(), proposed_map, valid_doors, world, player)
o_state_cache[door.name] = o_state
piece = create_graph_piece_from_state(door, o_state, o_state, proposed_map)
dungeon[door.name] = piece
for hook, crystal in piece.hooks.items():
if crystal == CrystalBarrier.Blue or crystal == CrystalBarrier.Either:
h_type = hook_from_door(hook)
if h_type not in blue_hooks:
blue_hooks.append(h_type) # todo: specific hooks and valid path to c_switch
if len(blue_hooks) > 0:
for sector in available_sectors:
for door in sector.outstanding_doors:
h_type = hanger_from_door(door)
if not door.stonewall and door not in proposed_map.keys() and h_type in blue_hooks:
parent = parent_region(door, world, player).parent_region
blue_start = ExplorationState(CrystalBarrier.Blue)
b_state = extend_reachable_state_improved([parent], blue_start, proposed_map, valid_doors, world, player)
o_state = o_state_cache[door.name]
dungeon[door.name] = create_graph_piece_from_state(door, o_state, b_state, proposed_map)
# catalog hooks: Dict<Hook, Set<>
# and hangers:
avail_hooks = defaultdict(set)
hangers = defaultdict(set)
for key, piece in dungeon.items():
door_hang = piece.hanger_info
if door_hang is not None:
hanger = hanger_from_door(door_hang)
hangers[hanger].add(door_hang)
for door, crystal in piece.hooks.items():
hook = hook_from_door(door)
avail_hooks[hook].add((door, crystal, door_hang))
# thin out invalid hanger
winnow_hangers(hangers, avail_hooks)
return dungeon, hangers, avail_hooks
def make_a_choice(dungeon, hangers, avail_hooks, prev_choices):
# choose a hanger
all_hooks = set()
origin = dungeon['Origin']
for key in avail_hooks.keys():
for hstuff in avail_hooks[key]:
all_hooks.add(hstuff[0])
candidate_hangers = []
for key in hangers.keys():
candidate_hangers.extend(hangers[key])
candidate_hangers.sort(key=lambda x: x.name) # sorting to create predictable seeds
random.shuffle(candidate_hangers) # randomize if equal preference
stage_2_hangers = []
hookable_hangers = collections.deque()
queue = collections.deque(candidate_hangers)
while len(queue) > 0:
c_hang = queue.pop()
if c_hang in all_hooks:
hookable_hangers.append(c_hang)
else:
stage_2_hangers.append(c_hang) # prefer hangers that are not hooks
# todo : prefer hangers with fewer hooks at some point? not sure about this
# this prefer hangers of the fewest type - to catch problems fast
hookable_hangers = sorted(hookable_hangers, key=lambda door: len(hangers[hanger_from_door(door)]), reverse=True)
origin_hangers = []
while len(hookable_hangers) > 0:
c_hang = hookable_hangers.pop()
if c_hang in origin.hooks.keys():
origin_hangers.append(c_hang)
else:
stage_2_hangers.append(c_hang) # prefer hangers that are not hooks on the 'origin'
stage_2_hangers.extend(origin_hangers)
hook = None
next_hanger = None
while hook is None:
if len(stage_2_hangers) == 0:
return None, None
next_hanger = stage_2_hangers.pop(0)
next_hanger_type = hanger_from_door(next_hanger)
hook_candidates = []
for door, crystal, orig_hang in avail_hooks[next_hanger_type]:
if filter_choices(next_hanger, door, orig_hang, prev_choices, hook_candidates):
hook_candidates.append(door)
if len(hook_candidates) > 0:
hook_candidates.sort(key=lambda x: x.name) # sort for deterministic seeds
hook = random.choice(tuple(hook_candidates))
return next_hanger, hook
def filter_choices(next_hanger, door, orig_hang, prev_choices, hook_candidates):
if (next_hanger, door) in prev_choices or (door, next_hanger) in prev_choices:
return False
return next_hanger != door and orig_hang != next_hanger and door not in hook_candidates
def check_valid(dungeon, hangers, hooks, proposed_map, doors_to_connect, all_regions):
# evaluate if everything is still plausible
# only origin is left in the dungeon and not everything is connected
if len(dungeon.keys()) <= 1 and len(proposed_map.keys()) < len(doors_to_connect):
return False
# origin has no more hooks, but not all doors have been proposed
if len(dungeon['Origin'].hooks) == 0 and len(proposed_map.keys()) < len(doors_to_connect):
return False
for key in hangers.keys():
if len(hooks[key]) > 0 and len(hangers[key]) == 0:
return False
# todo: stonewall - check that there's no hook-only that is without a matching hanger
all_visited = set()
for piece in dungeon.values():
all_visited.update(piece.visited_regions)
if len(all_regions.difference(all_visited)) > 0:
return False
new_hangers_found = True
accessible_hook_types = []
hanger_matching = set()
all_hangers = set()
origin_hooks = set(dungeon['Origin'].hooks.keys())
for door_hook in origin_hooks:
h_type = hook_from_door(door_hook)
if h_type not in accessible_hook_types:
accessible_hook_types.append(h_type)
while new_hangers_found:
new_hangers_found = False
for hanger_set in hangers.values():
for hanger in hanger_set:
all_hangers.add(hanger)
h_type = hanger_from_door(hanger)
if (h_type in accessible_hook_types or hanger in origin_hooks) and hanger not in hanger_matching:
new_hangers_found = True
hanger_matching.add(hanger)
matching_hooks = dungeon[hanger.name].hooks.keys()
origin_hooks.update(matching_hooks)
for door_hook in matching_hooks:
new_h_type = hook_from_door(door_hook)
if new_h_type not in accessible_hook_types:
accessible_hook_types.append(new_h_type)
return len(all_hangers.difference(hanger_matching)) == 0
def winnow_hangers(hangers, hooks):
removal_info = []
for hanger, door_set in hangers.items():
for door in door_set:
hook_set = hooks[hanger]
if len(hook_set) == 0:
removal_info.append((hanger, door))
else:
found_valid = False
for door_hook, crystal, orig_hanger in hook_set:
if orig_hanger != door:
found_valid = True
if not found_valid:
removal_info.append((hanger, door))
for hanger, door in removal_info:
hangers[hanger].remove(door)
def create_graph_piece_from_state(door, o_state, b_state, proposed_map):
# todo: info about dungeon events - not sure about that
graph_piece = GraphPiece()
all_unattached = {}
for exp_d in o_state.unattached_doors:
all_unattached[exp_d.door] = exp_d.crystal
for exp_d in b_state.unattached_doors:
d = exp_d.door
if d in all_unattached.keys():
if all_unattached[d] != exp_d.crystal:
if all_unattached[d] == CrystalBarrier.Orange and exp_d.crystal == CrystalBarrier.Blue:
all_unattached[d] = CrystalBarrier.Null
else:
logging.getLogger('').warning('Mismatched state @ %s (o:%s b:%s)', d.name, all_unattached[d], exp_d.crystal)
else:
all_unattached[exp_d.door] = exp_d.crystal
for d, crystal in all_unattached.items():
if (door is None or d != door) and not d.blocked and d not in proposed_map.keys():
graph_piece.hooks[d] = crystal
graph_piece.hanger_info = door
graph_piece.visited_regions.update(o_state.visited_blue)
graph_piece.visited_regions.update(o_state.visited_orange)
graph_piece.visited_regions.update(b_state.visited_blue)
graph_piece.visited_regions.update(b_state.visited_orange)
return graph_piece
def parent_region(door, world, player):
return world.get_entrance(door.name, player)
def hook_from_door(door):
if door.type == DoorType.SpiralStairs:
return Hook.Stairs
if door.type == DoorType.Normal:
dir = {
Direction.North: Hook.North,
Direction.South: Hook.South,
Direction.West: Hook.West,
Direction.East: Hook.East,
}
return dir[door.direction]
return None
def hanger_from_door(door):
if door.type == DoorType.SpiralStairs:
return Hook.Stairs
if door.type == DoorType.Normal:
dir = {
Direction.North: Hook.South,
Direction.South: Hook.North,
Direction.West: Hook.East,
Direction.East: Hook.West,
}
return dir[door.direction]
return None
def connect_doors(a, b, world, player):
# Return on unsupported types.
if a.type in [DoorType.Open, DoorType.StraightStairs, DoorType.Hole, DoorType.Warp, DoorType.Ladder,
DoorType.Interior, DoorType.Logical]:
return
# 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)
def connect_two_way(world, entrancename, exitname, player):
entrance = world.get_entrance(entrancename, player)
ext = world.get_entrance(exitname, player)
# if these were already connected somewhere, remove the backreference
if entrance.connected_region is not None:
entrance.connected_region.entrances.remove(entrance)
if ext.connected_region is not None:
ext.connected_region.entrances.remove(ext)
entrance.connect(ext.parent_region)
ext.connect(entrance.parent_region)
if entrance.parent_region.dungeon:
ext.parent_region.dungeon = entrance.parent_region.dungeon
x = world.check_for_door(entrancename, player)
y = world.check_for_door(exitname, player)
if x is not None:
x.dest = y
if y is not None:
y.dest = x
def connect_one_way(world, entrancename, exitname, player):
entrance = world.get_entrance(entrancename, player)
ext = world.get_entrance(exitname, player)
# if these were already connected somewhere, remove the backreference
if entrance.connected_region is not None:
entrance.connected_region.entrances.remove(entrance)
if ext.connected_region is not None:
ext.connected_region.entrances.remove(ext)
entrance.connect(ext.parent_region)
if entrance.parent_region.dungeon:
ext.parent_region.dungeon = entrance.parent_region.dungeon
x = world.check_for_door(entrancename, player)
y = world.check_for_door(exitname, player)
if x is not None:
x.dest = y
if y is not None:
y.dest = x
class ExplorationState(object):
def __init__(self, init_crystal=CrystalBarrier.Orange):
self.unattached_doors = []
self.avail_doors = []
self.event_doors = []
self.visited_orange = []
self.visited_blue = []
self.events = set()
self.crystal = init_crystal
# key region stuff
self.door_krs = {}
# key validation stuff
self.small_doors = []
self.big_doors = []
self.opened_doors = []
self.big_key_opened = False
self.big_key_special = False
self.found_locations = []
self.ttl_locations = 0
self.used_locations = 0
self.key_locations = 0
self.used_smalls = 0
self.non_door_entrances = []
def copy(self):
ret = ExplorationState()
ret.unattached_doors = list(self.unattached_doors)
ret.avail_doors = list(self.avail_doors)
ret.event_doors = list(self.event_doors)
ret.visited_orange = list(self.visited_orange)
ret.visited_blue = list(self.visited_blue)
ret.events = set(self.events)
ret.crystal = self.crystal
ret.door_krs = self.door_krs.copy()
ret.small_doors = list(self.small_doors)
ret.big_doors = list(self.big_doors)
ret.opened_doors = list(self.opened_doors)
ret.big_key_opened = self.big_key_opened
ret.big_key_special = self.big_key_special
ret.ttl_locations = self.ttl_locations
ret.key_locations = self.key_locations
ret.used_locations = self.used_locations
ret.used_smalls = self.used_smalls
ret.found_locations = list(self.found_locations)
ret.non_door_entrances = list(self.non_door_entrances)
return ret
def next_avail_door(self):
exp_door = self.avail_doors.pop()
self.crystal = exp_door.crystal
return exp_door
def visit_region(self, region, key_region=None, key_checks=False):
if self.crystal == CrystalBarrier.Either:
if region not in self.visited_blue:
self.visited_blue.append(region)
if region not in self.visited_orange:
self.visited_orange.append(region)
elif self.crystal == CrystalBarrier.Orange:
self.visited_orange.append(region)
elif self.crystal == CrystalBarrier.Blue:
self.visited_blue.append(region)
for location in region.locations:
if key_checks and location not in self.found_locations:
if location.name in key_only_locations:
self.key_locations += 1
if location.name not in dungeon_events and '- Prize' not in location.name:
self.ttl_locations += 1
if location not in self.found_locations:
self.found_locations.append(location)
if location.name in dungeon_events and location.name not in self.events:
if self.flooded_key_check(location):
self.perform_event(location.name, key_region)
if location.name in flooded_keys_reverse.keys() and self.location_found(flooded_keys_reverse[location.name]):
self.perform_event(flooded_keys_reverse[location.name], key_region)
if key_checks and region.name == 'Hyrule Dungeon Cellblock' and not self.big_key_opened:
self.big_key_opened = True
self.avail_doors.extend(self.big_doors)
self.big_doors.clear()
def flooded_key_check(self, location):
if location.name not in flooded_keys.keys():
return True
return flooded_keys[location.name] in [x.name for x in self.found_locations]
def location_found(self, location_name):
for l in self.found_locations:
if l.name == location_name:
return True
return False
def perform_event(self, location_name, key_region):
self.events.add(location_name)
queue = collections.deque(self.event_doors)
while len(queue) > 0:
exp_door = queue.pop()
if exp_door.door.req_event == location_name:
self.avail_doors.append(exp_door)
self.event_doors.remove(exp_door)
if key_region is not None:
d_name = exp_door.door.name
if d_name not in self.door_krs.keys():
self.door_krs[d_name] = key_region
def add_all_entrance_doors_check_unattached(self, region, world, player):
door_list = [x for x in get_doors(world, region, player) if x.type in [DoorType.Normal, DoorType.SpiralStairs]]
door_list.extend(get_entrance_doors(world, region, player))
for door in door_list:
if self.can_traverse(door):
if door.dest is None and not self.in_door_list_ic(door, self.unattached_doors):
self.append_door_to_list(door, self.unattached_doors)
elif door.req_event is not None and door.req_event not in self.events and not self.in_door_list(door, self.event_doors):
self.append_door_to_list(door, self.event_doors)
elif not self.in_door_list(door, self.avail_doors):
self.append_door_to_list(door, self.avail_doors)
for entrance in region.entrances:
door = world.check_for_door(entrance.name, player)
if door is None:
self.non_door_entrances.append(entrance)
def add_all_doors_check_unattached(self, region, world, player):
for door in get_doors(world, region, player):
if self.can_traverse(door):
if door.dest is None and not self.in_door_list_ic(door, self.unattached_doors):
self.append_door_to_list(door, self.unattached_doors)
elif door.req_event is not None and door.req_event not in self.events and not self.in_door_list(door, self.event_doors):
self.append_door_to_list(door, self.event_doors)
elif not self.in_door_list(door, self.avail_doors):
self.append_door_to_list(door, self.avail_doors)
def add_all_doors_check_proposed(self, region, proposed_map, valid_doors, world, player):
for door in get_dungeon_doors(region, world, player):
if self.can_traverse(door):
if door.dest is None and not self.in_door_list_ic(door, self.unattached_doors)\
and door not in proposed_map.keys() and door in valid_doors:
self.append_door_to_list(door, self.unattached_doors)
elif door.req_event is not None and door.req_event not in self.events and not self.in_door_list(door, self.event_doors):
self.append_door_to_list(door, self.event_doors)
elif not self.in_door_list(door, self.avail_doors):
self.append_door_to_list(door, self.avail_doors)
def add_all_doors_check_key_region(self, region, key_region, world, player):
for door in get_doors(world, region, player):
if self.can_traverse(door):
if door.req_event is not None and door.req_event not in self.events and not self.in_door_list(door, self.event_doors):
self.append_door_to_list(door, self.event_doors)
elif not self.in_door_list(door, self.avail_doors):
self.append_door_to_list(door, self.avail_doors)
if door.name not in self.door_krs.keys():
self.door_krs[door.name] = key_region
else:
if door.name not in self.door_krs.keys():
self.door_krs[door.name] = key_region
def add_all_doors_check_keys(self, region, key_door_proposal, world, player):
for door in get_doors(world, region, player):
if self.can_traverse(door):
if door in key_door_proposal and door not in self.opened_doors:
if not self.in_door_list(door, self.small_doors):
self.append_door_to_list(door, self.small_doors)
elif door.bigKey and not self.big_key_opened:
if not self.in_door_list(door, self.big_doors):
self.append_door_to_list(door, self.big_doors)
elif door.req_event is not None and door.req_event not in self.events:
if not self.in_door_list(door, self.event_doors):
self.append_door_to_list(door, self.event_doors)
elif not self.in_door_list(door, self.avail_doors):
self.append_door_to_list(door, self.avail_doors)
def visited(self, region):
if self.crystal == CrystalBarrier.Either:
return region in self.visited_blue and region in self.visited_orange
elif self.crystal == CrystalBarrier.Orange:
return region in self.visited_orange
elif self.crystal == CrystalBarrier.Blue:
return region in self.visited_blue
return False
def visited_at_all(self, region):
return region in self.visited_blue or region in self.visited_orange
def can_traverse(self, door):
if door.blocked:
return False
if door.crystal not in [CrystalBarrier.Null, CrystalBarrier.Either]:
return self.crystal == CrystalBarrier.Either or door.crystal == self.crystal
return True
def validate(self, door, region, world):
return self.can_traverse(door) and not self.visited(region) and valid_region_to_explore(region, world)
def in_door_list(self, door, door_list):
for d in door_list:
if d.door == door and d.crystal == self.crystal:
return True
return False
@staticmethod
def in_door_list_ic(door, door_list):
for d in door_list:
if d.door == door:
return True
return False
def append_door_to_list(self, door, door_list):
if door.crystal == CrystalBarrier.Null:
door_list.append(ExplorableDoor(door, self.crystal))
else:
door_list.append(ExplorableDoor(door, door.crystal))
def key_door_sort(self, d):
if d.door.smallKey:
if d.door in self.opened_doors:
return 1
else:
return 0
return 2
class ExplorableDoor(object):
def __init__(self, door, crystal):
self.door = door
self.crystal = crystal
def __str__(self):
return str(self.__unicode__())
def __unicode__(self):
return '%s (%s)' % (self.door.name, self.crystal.name)
def extend_reachable_state(search_regions, state, world, player):
local_state = state.copy()
for region in search_regions:
local_state.visit_region(region)
local_state.add_all_doors_check_unattached(region, world, player)
while len(local_state.avail_doors) > 0:
explorable_door = local_state.next_avail_door()
connect_region = world.get_entrance(explorable_door.door.name, player).connected_region
if connect_region is not None:
if valid_region_to_explore(connect_region, world) and not local_state.visited(connect_region):
local_state.visit_region(connect_region)
local_state.add_all_doors_check_unattached(connect_region, world, player)
return local_state
def extend_reachable_state_improved(search_regions, state, proposed_map, valid_doors, world, player):
local_state = state.copy()
for region in search_regions:
local_state.visit_region(region)
local_state.add_all_doors_check_proposed(region, proposed_map, valid_doors, world, player)
while len(local_state.avail_doors) > 0:
explorable_door = local_state.next_avail_door()
if explorable_door.door in proposed_map:
connect_region = world.get_entrance(proposed_map[explorable_door.door].name, player).parent_region
else:
connect_region = world.get_entrance(explorable_door.door.name, player).connected_region
if connect_region is not None:
if valid_region_to_explore(connect_region, world) and not local_state.visited(connect_region):
local_state.visit_region(connect_region)
local_state.add_all_doors_check_proposed(connect_region, proposed_map, valid_doors, world, player)
return local_state
# cross-utility methods
def valid_region_to_explore(region, world):
return region.type == RegionType.Dungeon or region.name in world.inaccessible_regions
def get_doors(world, region, player):
res = []
for exit in region.exits:
door = world.check_for_door(exit.name, player)
if door is not None:
res.append(door)
return res
def get_dungeon_doors(region, world, player):
res = []
for ext in region.exits:
door = world.check_for_door(ext.name, player)
if door is not None and ext.parent_region.type == RegionType.Dungeon:
res.append(door)
return res
def get_entrance_doors(world, region, player):
res = []
for exit in region.entrances:
door = world.check_for_door(exit.name, player)
if door is not None:
res.append(door)
return res
def convert_regions(region_names, world, player):
region_list = []
for name in region_names:
region_list.append(world.get_region(name, player))
return region_list
+68 -12
View File
@@ -20,11 +20,9 @@ def create_dungeons(world, player):
DP = make_dungeon('Desert Palace', 'Lanmolas', desert_regions, ItemFactory('Big Key (Desert Palace)', player), [ItemFactory('Small Key (Desert Palace)', player)], ItemFactory(['Map (Desert Palace)', 'Compass (Desert Palace)'], player)) DP = make_dungeon('Desert Palace', 'Lanmolas', desert_regions, ItemFactory('Big Key (Desert Palace)', player), [ItemFactory('Small Key (Desert Palace)', player)], ItemFactory(['Map (Desert Palace)', 'Compass (Desert Palace)'], player))
ToH = make_dungeon('Tower of Hera', 'Moldorm', hera_regions, ItemFactory('Big Key (Tower of Hera)', player), [ItemFactory('Small Key (Tower of Hera)', player)], ItemFactory(['Map (Tower of Hera)', 'Compass (Tower of Hera)'], player)) ToH = make_dungeon('Tower of Hera', 'Moldorm', hera_regions, ItemFactory('Big Key (Tower of Hera)', player), [ItemFactory('Small Key (Tower of Hera)', player)], ItemFactory(['Map (Tower of Hera)', 'Compass (Tower of Hera)'], player))
PoD = make_dungeon('Palace of Darkness', 'Helmasaur King', pod_regions, ItemFactory('Big Key (Palace of Darkness)', player), ItemFactory(['Small Key (Palace of Darkness)'] * 6, player), ItemFactory(['Map (Palace of Darkness)', 'Compass (Palace of Darkness)'], player)) PoD = make_dungeon('Palace of Darkness', 'Helmasaur King', pod_regions, ItemFactory('Big Key (Palace of Darkness)', player), ItemFactory(['Small Key (Palace of Darkness)'] * 6, player), ItemFactory(['Map (Palace of Darkness)', 'Compass (Palace of Darkness)'], player))
TT = make_dungeon('Thieves Town', 'Blind', thieves_regions, ItemFactory('Big Key (Thieves Town)', player), [ItemFactory('Small Key (Thieves Town)', player)], ItemFactory(['Map (Thieves Town)', 'Compass (Thieves Town)'], player))
#still standard dungeons SW = make_dungeon('Skull Woods', 'Mothula', skull_regions, ItemFactory('Big Key (Skull Woods)', player), ItemFactory(['Small Key (Skull Woods)'] * 2, player), ItemFactory(['Map (Skull Woods)', 'Compass (Skull Woods)'], player))
TT = make_dungeon('Thieves Town', 'Blind', ['Thieves Town (Entrance)', 'Thieves Town (Deep)', 'Blind Fight'], ItemFactory('Big Key (Thieves Town)', player), [ItemFactory('Small Key (Thieves Town)', player)], ItemFactory(['Map (Thieves Town)', 'Compass (Thieves Town)'], player)) SP = make_dungeon('Swamp Palace', 'Arrghus', swamp_regions, ItemFactory('Big Key (Swamp Palace)', player), [ItemFactory('Small Key (Swamp Palace)', player)], ItemFactory(['Map (Swamp Palace)', 'Compass (Swamp Palace)'], player))
SW = make_dungeon('Skull Woods', 'Mothula', ['Skull Woods Final Section (Entrance)', 'Skull Woods First Section', 'Skull Woods Second Section', 'Skull Woods Second Section (Drop)', 'Skull Woods Final Section (Mothula)', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Left)', 'Skull Woods First Section (Top)'], ItemFactory('Big Key (Skull Woods)', player), ItemFactory(['Small Key (Skull Woods)'] * 2, player), ItemFactory(['Map (Skull Woods)', 'Compass (Skull Woods)'], player))
SP = make_dungeon('Swamp Palace', 'Arrghus', ['Swamp Palace (Entrance)', 'Swamp Palace (First Room)', 'Swamp Palace (Starting Area)', 'Swamp Palace (Center)', 'Swamp Palace (North)'], ItemFactory('Big Key (Swamp Palace)', player), [ItemFactory('Small Key (Swamp Palace)', player)], ItemFactory(['Map (Swamp Palace)', 'Compass (Swamp Palace)'], player))
IP = make_dungeon('Ice Palace', 'Kholdstare', ['Ice Palace (Entrance)', 'Ice Palace (Main)', 'Ice Palace (East)', 'Ice Palace (East Top)', 'Ice Palace (Kholdstare)'], ItemFactory('Big Key (Ice Palace)', player), ItemFactory(['Small Key (Ice Palace)'] * 2, player), ItemFactory(['Map (Ice Palace)', 'Compass (Ice Palace)'], player)) IP = make_dungeon('Ice Palace', 'Kholdstare', ['Ice Palace (Entrance)', 'Ice Palace (Main)', 'Ice Palace (East)', 'Ice Palace (East Top)', 'Ice Palace (Kholdstare)'], ItemFactory('Big Key (Ice Palace)', player), ItemFactory(['Small Key (Ice Palace)'] * 2, player), ItemFactory(['Map (Ice Palace)', 'Compass (Ice Palace)'], player))
MM = make_dungeon('Misery Mire', 'Vitreous', ['Misery Mire (Entrance)', 'Misery Mire (Main)', 'Misery Mire (West)', 'Misery Mire (Final Area)', 'Misery Mire (Vitreous)'], ItemFactory('Big Key (Misery Mire)', player), ItemFactory(['Small Key (Misery Mire)'] * 3, player), ItemFactory(['Map (Misery Mire)', 'Compass (Misery Mire)'], player)) MM = make_dungeon('Misery Mire', 'Vitreous', ['Misery Mire (Entrance)', 'Misery Mire (Main)', 'Misery Mire (West)', 'Misery Mire (Final Area)', 'Misery Mire (Vitreous)'], ItemFactory('Big Key (Misery Mire)', player), ItemFactory(['Small Key (Misery Mire)'] * 3, player), ItemFactory(['Map (Misery Mire)', 'Compass (Misery Mire)'], player))
TR = make_dungeon('Turtle Rock', 'Trinexx', ['Turtle Rock (Entrance)', 'Turtle Rock (First Section)', 'Turtle Rock (Chain Chomp Room)', 'Turtle Rock (Second Section)', 'Turtle Rock (Big Chest)', 'Turtle Rock (Crystaroller Room)', 'Turtle Rock (Dark Room)', 'Turtle Rock (Eye Bridge)', 'Turtle Rock (Trinexx)'], ItemFactory('Big Key (Turtle Rock)', player), ItemFactory(['Small Key (Turtle Rock)'] * 4, player), ItemFactory(['Map (Turtle Rock)', 'Compass (Turtle Rock)'], player)) TR = make_dungeon('Turtle Rock', 'Trinexx', ['Turtle Rock (Entrance)', 'Turtle Rock (First Section)', 'Turtle Rock (Chain Chomp Room)', 'Turtle Rock (Second Section)', 'Turtle Rock (Big Chest)', 'Turtle Rock (Crystaroller Room)', 'Turtle Rock (Dark Room)', 'Turtle Rock (Eye Bridge)', 'Turtle Rock (Trinexx)'], ItemFactory('Big Key (Turtle Rock)', player), ItemFactory(['Small Key (Turtle Rock)'] * 4, player), ItemFactory(['Map (Turtle Rock)', 'Compass (Turtle Rock)'], player))
@@ -155,7 +153,6 @@ def fill_dungeons_restrictive(world, shuffled_locations):
fill_restrictive(world, all_state_base, shuffled_locations, dungeon_items) fill_restrictive(world, all_state_base, shuffled_locations, dungeon_items)
dungeon_music_addresses = {'Eastern Palace - Prize': [0x1559A], dungeon_music_addresses = {'Eastern Palace - Prize': [0x1559A],
'Desert Palace - Prize': [0x1559B, 0x1559C, 0x1559D, 0x1559E], 'Desert Palace - Prize': [0x1559B, 0x1559C, 0x1559D, 0x1559E],
'Tower of Hera - Prize': [0x155C5, 0x1107A, 0x10B8C], 'Tower of Hera - Prize': [0x155C5, 0x1107A, 0x10B8C],
@@ -214,6 +211,36 @@ pod_regions = [
'PoD Turtle Party', 'PoD Dark Alley', 'PoD Callback', 'PoD Boss' 'PoD Turtle Party', 'PoD Dark Alley', 'PoD Callback', 'PoD Boss'
] ]
swamp_regions = [
'Swamp Lobby', 'Swamp Entrance', 'Swamp Pot Row', 'Swamp Map Ledge', 'Swamp Trench 1 Approach',
'Swamp Trench 1 Nexus', 'Swamp Trench 1 Alcove', 'Swamp Trench 1 Key Ledge', 'Swamp Trench 1 Departure',
'Swamp Hammer Switch', 'Swamp Hub', 'Swamp Hub Dead Ledge', 'Swamp Hub North Ledge', 'Swamp Donut Top',
'Swamp Donut Bottom', 'Swamp Compass Donut', 'Swamp Crystal Switch', 'Swamp Shortcut', 'Swamp Trench 2 Pots',
'Swamp Trench 2 Blocks', 'Swamp Trench 2 Alcove', 'Swamp Trench 2 Departure', 'Swamp Big Key Ledge',
'Swamp West Shallows', 'Swamp West Block Path', 'Swamp West Ledge', 'Swamp Barrier Ledge', 'Swamp Barrier',
'Swamp Attic', 'Swamp Push Statue', 'Swamp Shooters', 'Swamp Left Elbow', 'Swamp Right Elbow', 'Swamp Drain Left',
'Swamp Drain Right', 'Swamp Flooded Room', 'Swamp Flooded Spot', 'Swamp Basement Shallows', 'Swamp Waterfall Room',
'Swamp Refill', 'Swamp Behind Waterfall', 'Swamp C', 'Swamp Waterway', 'Swamp I', 'Swamp T', 'Swamp Boss'
]
skull_regions = [
'Skull 1 Lobby', 'Skull Map Room', 'Skull Pot Circle', 'Skull Pull Switch', 'Skull Big Chest', 'Skull Pinball',
'Skull Pot Prison', 'Skull Compass Room', 'Skull Left Drop', 'Skull 2 East Lobby', 'Skull Big Key',
'Skull Lone Pot', 'Skull Small Hall', 'Skull Back Drop', 'Skull 2 West Lobby', 'Skull X Room', 'Skull 3 Lobby',
'Skull East Bridge', 'Skull West Bridge Nook', 'Skull Star Pits', 'Skull Torch Room', 'Skull Vines',
'Skull Spike Corner', 'Skull Final Drop', 'Skull Boss'
]
thieves_regions = [
'Thieves Lobby', 'Thieves Ambush', 'Thieves BK Corner', 'Thieves Compass Room', 'Thieves Big Chest Nook',
'Thieves Hallway', 'Thieves Boss', 'Thieves Pot Alcove Mid', 'Thieves Pot Alcove Bottom', 'Thieves Pot Alcove Top',
'Thieves Conveyor Maze', 'Thieves Spike Track', 'Thieves Hellway', 'Thieves Hellway N Crystal',
'Thieves Hellway S Crystal', 'Thieves Triple Bypass', 'Thieves Spike Switch', 'Thieves Attic',
'Thieves Cricket Hall Left', 'Thieves Cricket Hall Right', 'Thieves Attic Window', 'Thieves Basement Block',
'Thieves Blocked Entry', 'Thieves Lonely Zazak', 'Thieves Blind\'s Cell', 'Thieves Conveyor Bridge',
'Thieves Conveyor Block', 'Thieves Big Chest Room', 'Thieves Trap'
]
dungeon_regions = { dungeon_regions = {
'Hyrule Castle': hyrule_castle_regions, 'Hyrule Castle': hyrule_castle_regions,
@@ -222,9 +249,9 @@ dungeon_regions = {
'Tower of Hera': hera_regions, 'Tower of Hera': hera_regions,
'Agahnims Tower': tower_regions, 'Agahnims Tower': tower_regions,
'Palace of Darkness': pod_regions, 'Palace of Darkness': pod_regions,
# 'Swamp': 'Swamp Palace': swamp_regions,
# 'Skull': 'Skull Woods': skull_regions,
# 'TT': 'Thieves Town': thieves_regions,
# 'Ice': # 'Ice':
# 'Mire': # 'Mire':
# 'TR': # 'TR':
@@ -238,8 +265,10 @@ region_starts = {
'Tower of Hera': ['Hera Lobby'], 'Tower of Hera': ['Hera Lobby'],
'Agahnims Tower': ['Tower Lobby'], 'Agahnims Tower': ['Tower Lobby'],
'Palace of Darkness': ['PoD Lobby'], 'Palace of Darkness': ['PoD Lobby'],
# ['Swamp Lobby'], 'Swamp Palace': ['Swamp Lobby'],
# ['TT Lobby'], 'Skull Woods': ['Skull 1 Lobby', 'Skull 2 East Lobby', 'Skull 2 West Lobby', 'Skull 3 Lobby', 'Skull Pot Circle',
'Skull Pinball', 'Skull Left Drop', 'Skull Back Drop'],
'Thieves Town': ['Thieves Lobby'],
# ['Ice Lobby'], # ['Ice Lobby'],
# ['Mire Lobby'], # ['Mire Lobby'],
# ['TR Main Lobby', 'TR Eye Trap', 'TR Big Chest', 'TR Laser Bridge'], # ['TR Main Lobby', 'TR Eye Trap', 'TR Big Chest', 'TR Laser Bridge'],
@@ -250,8 +279,35 @@ split_region_starts = {
'Desert Palace': [ 'Desert Palace': [
['Desert Back Lobby'], ['Desert Back Lobby'],
['Desert Main Lobby', 'Desert West Lobby', 'Desert East Lobby'] ['Desert Main Lobby', 'Desert West Lobby', 'Desert East Lobby']
],
'Skull Woods': [
['Skull 1 Lobby', 'Skull Pot Circle'],
['Skull 2 West Lobby', 'Skull 2 East Lobby', 'Skull Back Drop'],
['Skull 3 Lobby']
] ]
# 'Skull': ['Skull 1 Lobby', 'Skull 2 Mummy Lobby', 'Skull 2 Key Lobby', 'Skull 3 Lobby'],
} }
dungeon_keys = {
'Hyrule Castle': 'Small Key (Escape)',
'Eastern Palace': 'Small Key (Eastern Palace)',
'Desert Palace': 'Small Key (Desert Palace)',
'Tower of Hera': 'Small Key (Tower of Hera)',
'Agahnims Tower': 'Small Key (Agahnims Tower)',
'Palace of Darkness': 'Small Key (Palace of Darkness)',
'Swamp Palace': 'Small Key (Swamp Palace)',
'Skull Woods': 'Small Key (Skull Woods)',
'Thieves Town': 'Small Key (Thieves Town)'
}
dungeon_bigs = {
'Hyrule Castle': 'Big Key (Escape)',
'Eastern Palace': 'Big Key (Eastern Palace)',
'Desert Palace': 'Big Key (Desert Palace)',
'Tower of Hera': 'Big Key (Tower of Hera)',
'Agahnims Tower': 'Big Key (Agahnims Tower)',
'Palace of Darkness': 'Big Key (Palace of Darkness)',
'Swamp Palace': 'Big Key (Swamp Palace)',
'Skull Woods': 'Big Key (Skull Woods)',
'Thieves Town': 'Big Key (Thieves Town)'
}
+12 -29
View File
@@ -1995,7 +1995,7 @@ def connect_doors(world, doors, targets, player):
def skull_woods_shuffle(world, player): def skull_woods_shuffle(world, player):
connect_random(world, ['Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', 'Skull Woods Second Section Hole'], connect_random(world, ['Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', 'Skull Woods Second Section Hole'],
['Skull Woods First Section (Left)', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Top)', 'Skull Woods Second Section (Drop)'], player) ['Skull Left Drop', 'Skull Pinball', 'Skull Pot Circle', 'Skull Back Drop'], player)
connect_random(world, ['Skull Woods First Section Door', 'Skull Woods Second Section Door (East)', 'Skull Woods Second Section Door (West)'], connect_random(world, ['Skull Woods First Section Door', 'Skull Woods Second Section Door (East)', 'Skull Woods Second Section Door (West)'],
['Skull Woods First Section Exit', 'Skull Woods Second Section Exit (East)', 'Skull Woods Second Section Exit (West)'], player, True) ['Skull Woods First Section Exit', 'Skull Woods Second Section Exit (East)', 'Skull Woods Second Section Exit (West)'], player, True)
@@ -2947,21 +2947,6 @@ mandatory_connections = [('Lake Hylia Central Island Pier', 'Lake Hylia Central
('Cave 45 Mirror Spot', 'Cave 45 Ledge'), ('Cave 45 Mirror Spot', 'Cave 45 Ledge'),
('Graveyard Ledge Mirror Spot', 'Graveyard Ledge'), ('Graveyard Ledge Mirror Spot', 'Graveyard Ledge'),
('Swamp Palace Moat', 'Swamp Palace (First Room)'),
('Swamp Palace Small Key Door', 'Swamp Palace (Starting Area)'),
('Swamp Palace (Center)', 'Swamp Palace (Center)'),
('Swamp Palace (North)', 'Swamp Palace (North)'),
('Thieves Town Big Key Door', 'Thieves Town (Deep)'),
('Skull Woods Torch Room', 'Skull Woods Final Section (Mothula)'),
('Skull Woods First Section Bomb Jump', 'Skull Woods First Section (Top)'), # represents bomb jumping to big chest
('Skull Woods First Section South Door', 'Skull Woods First Section (Right)'),
('Skull Woods First Section West Door', 'Skull Woods First Section (Left)'),
('Skull Woods First Section (Right) North Door', 'Skull Woods First Section'),
('Skull Woods First Section (Left) Door to Right', 'Skull Woods First Section (Right)'),
('Skull Woods First Section (Left) Door to Exit', 'Skull Woods First Section'),
('Skull Woods First Section (Top) One-Way Path', 'Skull Woods First Section'),
('Skull Woods Second Section (Drop)', 'Skull Woods Second Section'),
('Blind Fight', 'Blind Fight'),
('Ice Palace Entrance Room', 'Ice Palace (Main)'), ('Ice Palace Entrance Room', 'Ice Palace (Main)'),
('Ice Palace (East)', 'Ice Palace (East)'), ('Ice Palace (East)', 'Ice Palace (East)'),
('Ice Palace (East Top)', 'Ice Palace (East Top)'), ('Ice Palace (East Top)', 'Ice Palace (East Top)'),
@@ -3075,9 +3060,7 @@ inverted_mandatory_connections = [('Lake Hylia Central Island Pier', 'Lake Hylia
('Swamp Palace Small Key Door', 'Swamp Palace (Starting Area)'), ('Swamp Palace Small Key Door', 'Swamp Palace (Starting Area)'),
('Swamp Palace (Center)', 'Swamp Palace (Center)'), ('Swamp Palace (Center)', 'Swamp Palace (Center)'),
('Swamp Palace (North)', 'Swamp Palace (North)'), ('Swamp Palace (North)', 'Swamp Palace (North)'),
('Thieves Town Big Key Door', 'Thieves Town (Deep)'),
('Skull Woods Torch Room', 'Skull Woods Final Section (Mothula)'), ('Skull Woods Torch Room', 'Skull Woods Final Section (Mothula)'),
('Skull Woods First Section Bomb Jump', 'Skull Woods First Section (Top)'),
('Skull Woods First Section South Door', 'Skull Woods First Section (Right)'), ('Skull Woods First Section South Door', 'Skull Woods First Section (Right)'),
('Skull Woods First Section West Door', 'Skull Woods First Section (Left)'), ('Skull Woods First Section West Door', 'Skull Woods First Section (Left)'),
('Skull Woods First Section (Right) North Door', 'Skull Woods First Section'), ('Skull Woods First Section (Right) North Door', 'Skull Woods First Section'),
@@ -3523,19 +3506,19 @@ default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert Main L
('Agahnims Tower', 'Tower Lobby'), ('Agahnims Tower', 'Tower Lobby'),
('Agahnims Tower Exit', 'Hyrule Castle Ledge'), ('Agahnims Tower Exit', 'Hyrule Castle Ledge'),
('Thieves Town', 'Thieves Town (Entrance)'), ('Thieves Town', 'Thieves Lobby'),
('Thieves Town Exit', 'West Dark World'), ('Thieves Town Exit', 'West Dark World'),
('Skull Woods First Section Hole (East)', 'Skull Woods First Section (Right)'), ('Skull Woods First Section Hole (East)', 'Skull Pinball'),
('Skull Woods First Section Hole (West)', 'Skull Woods First Section (Left)'), ('Skull Woods First Section Hole (West)', 'Skull Left Drop'),
('Skull Woods First Section Hole (North)', 'Skull Woods First Section (Top)'), ('Skull Woods First Section Hole (North)', 'Skull Pot Circle'),
('Skull Woods First Section Door', 'Skull Woods First Section'), ('Skull Woods First Section Door', 'Skull 1 Lobby'),
('Skull Woods First Section Exit', 'Skull Woods Forest'), ('Skull Woods First Section Exit', 'Skull Woods Forest'),
('Skull Woods Second Section Hole', 'Skull Woods Second Section (Drop)'), ('Skull Woods Second Section Hole', 'Skull Back Drop'),
('Skull Woods Second Section Door (East)', 'Skull Woods Second Section'), ('Skull Woods Second Section Door (East)', 'Skull 2 East Lobby'),
('Skull Woods Second Section Door (West)', 'Skull Woods Second Section'), ('Skull Woods Second Section Door (West)', 'Skull 2 West Lobby'),
('Skull Woods Second Section Exit (East)', 'Skull Woods Forest'), ('Skull Woods Second Section Exit (East)', 'Skull Woods Forest'),
('Skull Woods Second Section Exit (West)', 'Skull Woods Forest (West)'), ('Skull Woods Second Section Exit (West)', 'Skull Woods Forest (West)'),
('Skull Woods Final Section', 'Skull Woods Final Section (Entrance)'), ('Skull Woods Final Section', 'Skull 3 Lobby'),
('Skull Woods Final Section Exit', 'Skull Woods Forest (West)'), ('Skull Woods Final Section Exit', 'Skull Woods Forest (West)'),
('Ice Palace', 'Ice Palace (Entrance)'), ('Ice Palace', 'Ice Palace (Entrance)'),
('Ice Palace Exit', 'Dark Lake Hylia Central Island'), ('Ice Palace Exit', 'Dark Lake Hylia Central Island'),
@@ -3543,7 +3526,7 @@ default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert Main L
('Misery Mire Exit', 'Dark Desert'), ('Misery Mire Exit', 'Dark Desert'),
('Palace of Darkness', 'PoD Lobby'), ('Palace of Darkness', 'PoD Lobby'),
('Palace of Darkness Exit', 'East Dark World'), ('Palace of Darkness Exit', 'East Dark World'),
('Swamp Palace', 'Swamp Palace (Entrance)'), # requires additional patch for flooding moat if moved ('Swamp Palace', 'Swamp Lobby'), # requires additional patch for flooding moat if moved
('Swamp Palace Exit', 'South Dark World'), ('Swamp Palace Exit', 'South Dark World'),
('Turtle Rock', 'Turtle Rock (Entrance)'), ('Turtle Rock', 'Turtle Rock (Entrance)'),
@@ -3577,7 +3560,7 @@ inverted_default_dungeon_connections = [('Desert Palace Entrance (South)', 'Dese
('Hyrule Castle Exit (South)', 'Light World'), ('Hyrule Castle Exit (South)', 'Light World'),
('Hyrule Castle Exit (West)', 'Hyrule Castle Ledge'), ('Hyrule Castle Exit (West)', 'Hyrule Castle Ledge'),
('Hyrule Castle Exit (East)', 'Hyrule Castle Ledge'), ('Hyrule Castle Exit (East)', 'Hyrule Castle Ledge'),
('Thieves Town', 'Thieves Town (Entrance)'), ('Thieves Town', 'Thieves Lobby'),
('Thieves Town Exit', 'West Dark World'), ('Thieves Town Exit', 'West Dark World'),
('Skull Woods First Section Hole (East)', 'Skull Woods First Section (Right)'), ('Skull Woods First Section Hole (East)', 'Skull Woods First Section (Right)'),
('Skull Woods First Section Hole (West)', 'Skull Woods First Section (Left)'), ('Skull Woods First Section Hole (West)', 'Skull Woods First Section (Left)'),
+18
View File
@@ -174,6 +174,24 @@ def generate_itempool(world, player):
world.push_item(world.get_location('Floodgate', player), ItemFactory('Open Floodgate', player), False) world.push_item(world.get_location('Floodgate', player), ItemFactory('Open Floodgate', player), False)
world.get_location('Floodgate', player).event = True world.get_location('Floodgate', player).event = True
world.get_location('Floodgate', player).locked = True world.get_location('Floodgate', player).locked = True
world.push_item(world.get_location('Trench 1 Switch', player), ItemFactory('Trench 1 Filled', player), False)
world.get_location('Trench 1 Switch', player).event = True
world.get_location('Trench 1 Switch', player).locked = True
world.push_item(world.get_location('Trench 2 Switch', player), ItemFactory('Trench 2 Filled', player), False)
world.get_location('Trench 2 Switch', player).event = True
world.get_location('Trench 2 Switch', player).locked = True
world.push_item(world.get_location('Swamp Drain', player), ItemFactory('Drained Swamp', player), False)
world.get_location('Swamp Drain', player).event = True
world.get_location('Swamp Drain', player).locked = True
world.push_item(world.get_location('Attic Cracked Floor', player), ItemFactory('Shining Light', player), False)
world.get_location('Attic Cracked Floor', player).event = True
world.get_location('Attic Cracked Floor', player).locked = True
world.push_item(world.get_location('Suspicious Maiden', player), ItemFactory('Maiden Rescued', player), False)
world.get_location('Suspicious Maiden', player).event = True
world.get_location('Suspicious Maiden', player).locked = True
world.push_item(world.get_location('Revealing Light', player), ItemFactory('Maiden Unmasked', player), False)
world.get_location('Revealing Light', player).event = True
world.get_location('Revealing Light', player).locked = True
# set up item pool # set up item pool
if world.custom: if world.custom:
+6
View File
@@ -172,4 +172,10 @@ item_table = {'Bow': (True, False, None, 0x0B, 'You have\nchosen the\narcher cla
'Return Smith': (True, False, 'Event', None, None, None, None, None, None, None, None), 'Return Smith': (True, False, 'Event', None, None, None, None, None, None, None, None),
'Pick Up Purple Chest': (True, False, 'Event', None, None, None, None, None, None, None, None), 'Pick Up Purple Chest': (True, False, 'Event', None, None, None, None, None, None, None, None),
'Open Floodgate': (True, False, 'Event', None, None, None, None, None, None, None, None), 'Open Floodgate': (True, False, 'Event', None, None, None, None, None, None, None, None),
'Trench 1 Filled': (True, False, 'Event', None, None, None, None, None, None, None, None),
'Trench 2 Filled': (True, False, 'Event', None, None, None, None, None, None, None, None),
'Drained Swamp': (True, False, 'Event', None, None, None, None, None, None, None, None),
'Shining Light': (True, False, 'Event', None, None, None, None, None, None, None, None),
'Maiden Rescued': (True, False, 'Event', None, None, None, None, None, None, None, None),
'Maiden Unmasked': (True, False, 'Event', None, None, None, None, None, None, None, None),
} }
+17 -7
View File
@@ -58,11 +58,6 @@ def main(args, seed=None):
create_rooms(world, player) create_rooms(world, player)
create_dungeons(world, player) create_dungeons(world, player)
logger.info('Shuffling dungeons')
for player in range(1, world.players + 1):
link_doors(world, player)
logger.info('Shuffling the World about.') logger.info('Shuffling the World about.')
if world.mode != 'inverted': if world.mode != 'inverted':
@@ -76,6 +71,13 @@ def main(args, seed=None):
mark_dark_world_regions(world) mark_dark_world_regions(world)
logger.info('Shuffling dungeons')
for player in range(1, world.players + 1):
link_doors(world, player)
# todo: mark regions after linking doors - for bunny logic?
logger.info('Generating Item Pool.') logger.info('Generating Item Pool.')
for player in range(1, world.players + 1): for player in range(1, world.players + 1):
@@ -89,7 +91,8 @@ def main(args, seed=None):
# todo: remove this later. this is for debugging # todo: remove this later. this is for debugging
for player in range(1, world.players + 1): for player in range(1, world.players + 1):
all_state = world.get_all_state(keys=True) all_state = world.get_all_state(keys=True)
for bossregion in ['Eastern Boss', 'Desert Boss', 'Hera Boss', 'Tower Agahnim 1', 'PoD Boss']: for bossregion in ['Eastern Boss', 'Desert Boss', 'Hera Boss', 'Tower Agahnim 1', 'PoD Boss', 'Swamp Boss',
'Skull Boss', 'Thieves Boss']:
if world.get_region(bossregion, player) not in all_state.reachable_regions[player]: if world.get_region(bossregion, player) not in all_state.reachable_regions[player]:
raise Exception(bossregion + ' missing from generation') raise Exception(bossregion + ' missing from generation')
@@ -274,6 +277,13 @@ def copy_world(world):
ret.precollected_items = world.precollected_items.copy() ret.precollected_items = world.precollected_items.copy()
ret.state.stale = {player: True for player in range(1, world.players + 1)} ret.state.stale = {player: True for player in range(1, world.players + 1)}
ret.doors = world.doors
ret.paired_doors = world.paired_doors
ret.rooms = world.rooms
ret.inaccessible_regions = world.inaccessible_regions
ret.dungeon_layouts = world.dungeon_layouts
ret.key_logic = world.key_logic
for player in range(1, world.players + 1): for player in range(1, world.players + 1):
set_rules(ret, player) set_rules(ret, player)
@@ -328,7 +338,7 @@ def create_playthrough(world):
sphere = [] sphere = []
# build up spheres of collection radius. Everything in each sphere is independent from each other in dependencies and only depends on lower spheres # build up spheres of collection radius. Everything in each sphere is independent from each other in dependencies and only depends on lower spheres
for location in sphere_candidates: for location in sphere_candidates:
if state.can_reach(location): if state.can_reach(location) and state.not_flooding_a_key(world, location):
sphere.append(location) sphere.append(location)
for location in sphere: for location in sphere:
+134 -23
View File
@@ -193,29 +193,6 @@ def create_regions(world, player):
create_lw_region(player, 'Mimic Cave Ledge', None, ['Mimic Cave']), create_lw_region(player, 'Mimic Cave Ledge', None, ['Mimic Cave']),
create_cave_region(player, 'Mimic Cave', 'Mimic Cave', ['Mimic Cave']), create_cave_region(player, 'Mimic Cave', 'Mimic Cave', ['Mimic Cave']),
create_dungeon_region(player, 'Swamp Palace (Entrance)', 'Swamp Palace', None, ['Swamp Palace Moat', 'Swamp Palace Exit']),
create_dungeon_region(player, 'Swamp Palace (First Room)', 'Swamp Palace', ['Swamp Palace - Entrance'], ['Swamp Palace Small Key Door']),
create_dungeon_region(player, 'Swamp Palace (Starting Area)', 'Swamp Palace', ['Swamp Palace - Map Chest'], ['Swamp Palace (Center)']),
create_dungeon_region(player, 'Swamp Palace (Center)', 'Swamp Palace', ['Swamp Palace - Big Chest', 'Swamp Palace - Compass Chest',
'Swamp Palace - Big Key Chest', 'Swamp Palace - West Chest'], ['Swamp Palace (North)']),
create_dungeon_region(player, 'Swamp Palace (North)', 'Swamp Palace', ['Swamp Palace - Flooded Room - Left', 'Swamp Palace - Flooded Room - Right',
'Swamp Palace - Waterfall Room', 'Swamp Palace - Boss', 'Swamp Palace - Prize']),
create_dungeon_region(player, 'Thieves Town (Entrance)', 'Thieves\' Town', ['Thieves\' Town - Big Key Chest',
'Thieves\' Town - Map Chest',
'Thieves\' Town - Compass Chest',
'Thieves\' Town - Ambush Chest'], ['Thieves Town Big Key Door', 'Thieves Town Exit']),
create_dungeon_region(player, 'Thieves Town (Deep)', 'Thieves\' Town', ['Thieves\' Town - Attic',
'Thieves\' Town - Big Chest',
'Thieves\' Town - Blind\'s Cell'], ['Blind Fight']),
create_dungeon_region(player, 'Blind Fight', 'Thieves\' Town', ['Thieves\' Town - Boss', 'Thieves\' Town - Prize']),
create_dungeon_region(player, 'Skull Woods First Section', 'Skull Woods', ['Skull Woods - Map Chest'], ['Skull Woods First Section Exit', 'Skull Woods First Section Bomb Jump', 'Skull Woods First Section South Door', 'Skull Woods First Section West Door']),
create_dungeon_region(player, 'Skull Woods First Section (Right)', 'Skull Woods', ['Skull Woods - Pinball Room'], ['Skull Woods First Section (Right) North Door']),
create_dungeon_region(player, 'Skull Woods First Section (Left)', 'Skull Woods', ['Skull Woods - Compass Chest', 'Skull Woods - Pot Prison'], ['Skull Woods First Section (Left) Door to Exit', 'Skull Woods First Section (Left) Door to Right']),
create_dungeon_region(player, 'Skull Woods First Section (Top)', 'Skull Woods', ['Skull Woods - Big Chest'], ['Skull Woods First Section (Top) One-Way Path']),
create_dungeon_region(player, 'Skull Woods Second Section (Drop)', 'Skull Woods', None, ['Skull Woods Second Section (Drop)']),
create_dungeon_region(player, 'Skull Woods Second Section', 'Skull Woods', ['Skull Woods - Big Key Chest'], ['Skull Woods Second Section Exit (East)', 'Skull Woods Second Section Exit (West)']),
create_dungeon_region(player, 'Skull Woods Final Section (Entrance)', 'Skull Woods', ['Skull Woods - Bridge Room'], ['Skull Woods Torch Room', 'Skull Woods Final Section Exit']),
create_dungeon_region(player, 'Skull Woods Final Section (Mothula)', 'Skull Woods', ['Skull Woods - Boss', 'Skull Woods - Prize']),
create_dungeon_region(player, 'Ice Palace (Entrance)', 'Ice Palace', None, ['Ice Palace Entrance Room', 'Ice Palace Exit']), create_dungeon_region(player, 'Ice Palace (Entrance)', 'Ice Palace', None, ['Ice Palace Entrance Room', 'Ice Palace Exit']),
create_dungeon_region(player, 'Ice Palace (Main)', 'Ice Palace', ['Ice Palace - Compass Chest', 'Ice Palace - Freezor Chest', create_dungeon_region(player, 'Ice Palace (Main)', 'Ice Palace', ['Ice Palace - Compass Chest', 'Ice Palace - Freezor Chest',
'Ice Palace - Big Chest', 'Ice Palace - Iced T Room'], ['Ice Palace (East)', 'Ice Palace (Kholdstare)']), 'Ice Palace - Big Chest', 'Ice Palace - Iced T Room'], ['Ice Palace (East)', 'Ice Palace (Kholdstare)']),
@@ -418,8 +395,113 @@ def create_regions(world, player):
create_dungeon_region(player, 'PoD Boss', 'Palace of Darkness', ['Palace of Darkness - Boss', 'Palace of Darkness - Prize'], ['PoD Boss SE']), create_dungeon_region(player, 'PoD Boss', 'Palace of Darkness', ['Palace of Darkness - Boss', 'Palace of Darkness - Prize'], ['PoD Boss SE']),
# swamp # swamp
create_dungeon_region(player, 'Swamp Lobby', 'Swamp Palace', None, ['Swamp Palace Exit', 'Swamp Lobby Moat']),
create_dungeon_region(player, 'Swamp Entrance', 'Swamp Palace', ['Swamp Palace - Entrance'], ['Swamp Entrance Down Stairs', 'Swamp Entrance Moat']),
create_dungeon_region(player, 'Swamp Pot Row', 'Swamp Palace', ['Swamp Palace - Pot Row Pot Key'], ['Swamp Pot Row Up Stairs', 'Swamp Pot Row WN', 'Swamp Pot Row WS']),
create_dungeon_region(player, 'Swamp Map Ledge', 'Swamp Palace', ['Swamp Palace - Map Chest'], ['Swamp Map Ledge EN']),
create_dungeon_region(player, 'Swamp Trench 1 Approach', 'Swamp Palace', None, ['Swamp Trench 1 Approach ES', 'Swamp Trench 1 Approach Dry', 'Swamp Trench 1 Approach Key', 'Swamp Trench 1 Approach Swim Depart']),
create_dungeon_region(player, 'Swamp Trench 1 Nexus', 'Swamp Palace', None, ['Swamp Trench 1 Nexus Approach', 'Swamp Trench 1 Nexus N', 'Swamp Trench 1 Nexus Key']),
create_dungeon_region(player, 'Swamp Trench 1 Alcove', 'Swamp Palace', ['Swamp Palace - Trench 1 Pot Key'], ['Swamp Trench 1 Alcove S']),
create_dungeon_region(player, 'Swamp Trench 1 Key Ledge', 'Swamp Palace', None, ['Swamp Trench 1 Key Ledge Dry', 'Swamp Trench 1 Key Approach', 'Swamp Trench 1 Key Ledge Depart', 'Swamp Trench 1 Key Ledge NW']),
create_dungeon_region(player, 'Swamp Trench 1 Departure', 'Swamp Palace', None, ['Swamp Trench 1 Departure Dry', 'Swamp Trench 1 Departure Approach', 'Swamp Trench 1 Departure Key', 'Swamp Trench 1 Departure WS']),
create_dungeon_region(player, 'Swamp Hammer Switch', 'Swamp Palace', ['Trench 1 Switch'], ['Swamp Hammer Switch SW', 'Swamp Hammer Switch WN']),
create_dungeon_region(player, 'Swamp Hub', 'Swamp Palace', ['Swamp Palace - Big Chest', 'Swamp Palace - Hookshot Pot Key'], ['Swamp Hub ES', 'Swamp Hub S', 'Swamp Hub WS', 'Swamp Hub WN', 'Swamp Hub Hook Path']),
create_dungeon_region(player, 'Swamp Hub Dead Ledge', 'Swamp Palace', None, ['Swamp Hub Dead Ledge EN']),
create_dungeon_region(player, 'Swamp Hub North Ledge', 'Swamp Palace', None, ['Swamp Hub North Ledge N', 'Swamp Hub North Ledge Drop Down']),
create_dungeon_region(player, 'Swamp Donut Top', 'Swamp Palace', None, ['Swamp Donut Top N', 'Swamp Donut Top SE']),
create_dungeon_region(player, 'Swamp Donut Bottom', 'Swamp Palace', None, ['Swamp Donut Bottom NE', 'Swamp Donut Bottom NW']),
create_dungeon_region(player, 'Swamp Compass Donut', 'Swamp Palace', ['Swamp Palace - Compass Chest'], ['Swamp Compass Donut SW', 'Swamp Compass Donut Push Block']),
create_dungeon_region(player, 'Swamp Crystal Switch', 'Swamp Palace', ['Trench 2 Switch'], ['Swamp Crystal Switch EN', 'Swamp Crystal Switch SE']),
create_dungeon_region(player, 'Swamp Shortcut', 'Swamp Palace', None, ['Swamp Shortcut NE', 'Swamp Shortcut Blue Barrier']),
create_dungeon_region(player, 'Swamp Trench 2 Pots', 'Swamp Palace', None, ['Swamp Trench 2 Pots ES', 'Swamp Trench 2 Pots Blue Barrier', 'Swamp Trench 2 Pots Dry', 'Swamp Trench 2 Pots Wet']),
create_dungeon_region(player, 'Swamp Trench 2 Blocks', 'Swamp Palace', None, ['Swamp Trench 2 Blocks Pots', 'Swamp Trench 2 Blocks N']),
create_dungeon_region(player, 'Swamp Trench 2 Alcove', 'Swamp Palace', ['Swamp Palace - Trench 2 Pot Key'], ['Swamp Trench 2 Alcove S']),
create_dungeon_region(player, 'Swamp Trench 2 Departure', 'Swamp Palace', None, ['Swamp Trench 2 Departure Wet', 'Swamp Trench 2 Departure WS']),
create_dungeon_region(player, 'Swamp Big Key Ledge', 'Swamp Palace', ['Swamp Palace - Big Key Chest'], ['Swamp Big Key Ledge WN']),
create_dungeon_region(player, 'Swamp West Shallows', 'Swamp Palace', None, ['Swamp West Shallows ES', 'Swamp West Shallows Push Blocks']),
create_dungeon_region(player, 'Swamp West Block Path', 'Swamp Palace', None, ['Swamp West Block Path Up Stairs', 'Swamp West Block Path Drop Down']),
create_dungeon_region(player, 'Swamp West Ledge', 'Swamp Palace', ['Swamp Palace - West Chest'], ['Swamp West Ledge Drop Down', 'Swamp West Ledge Hook Path']),
create_dungeon_region(player, 'Swamp Barrier Ledge', 'Swamp Palace', None, ['Swamp Barrier Ledge Drop Down', 'Swamp Barrier Ledge - Orange', 'Swamp Barrier Ledge Hook Path']),
create_dungeon_region(player, 'Swamp Barrier', 'Swamp Palace', None, ['Swamp Barrier EN', 'Swamp Barrier - Orange']),
create_dungeon_region(player, 'Swamp Attic', 'Swamp Palace', None, ['Swamp Attic Down Stairs', 'Swamp Attic Left Pit', 'Swamp Attic Right Pit']),
create_dungeon_region(player, 'Swamp Push Statue', 'Swamp Palace', None, ['Swamp Push Statue S', 'Swamp Push Statue NW', 'Swamp Push Statue NE', 'Swamp Push Statue Down Stairs']),
create_dungeon_region(player, 'Swamp Shooters', 'Swamp Palace', None, ['Swamp Shooters SW', 'Swamp Shooters EN']),
create_dungeon_region(player, 'Swamp Left Elbow', 'Swamp Palace', None, ['Swamp Left Elbow WN', 'Swamp Left Elbow Down Stairs']),
create_dungeon_region(player, 'Swamp Right Elbow', 'Swamp Palace', None, ['Swamp Right Elbow SE', 'Swamp Right Elbow Down Stairs']),
create_dungeon_region(player, 'Swamp Drain Left', 'Swamp Palace', None, ['Swamp Drain Left Up Stairs', 'Swamp Drain WN']),
create_dungeon_region(player, 'Swamp Drain Right', 'Swamp Palace', ['Swamp Drain'], ['Swamp Drain Right Switch', 'Swamp Drain Right Up Stairs']),
# This is intentionally odd so I don't have to treat the WS door in the Flooded Room oddly (because of how it works when going backward)
create_dungeon_region(player, 'Swamp Flooded Room', 'Swamp Palace', None, ['Swamp Flooded Room Up Stairs', 'Swamp Flooded Room Ladder', 'Swamp Flooded Room WS']),
create_dungeon_region(player, 'Swamp Flooded Spot', 'Swamp Palace', ['Swamp Palace - Flooded Room - Left', 'Swamp Palace - Flooded Room - Right'], ['Swamp Flooded Spot Ladder']),
create_dungeon_region(player, 'Swamp Basement Shallows', 'Swamp Palace', None, ['Swamp Basement Shallows NW', 'Swamp Basement Shallows EN', 'Swamp Basement Shallows ES']),
create_dungeon_region(player, 'Swamp Waterfall Room', 'Swamp Palace', ['Swamp Palace - Waterfall Room'], ['Swamp Waterfall Room SW', 'Swamp Waterfall Room NW', 'Swamp Waterfall Room NE']),
create_dungeon_region(player, 'Swamp Refill', 'Swamp Palace', None, ['Swamp Refill SW']),
create_dungeon_region(player, 'Swamp Behind Waterfall', 'Swamp Palace', None, ['Swamp Behind Waterfall SE', 'Swamp Behind Waterfall Up Stairs']),
create_dungeon_region(player, 'Swamp C', 'Swamp Palace', None, ['Swamp C Down Stairs', 'Swamp C SE']),
create_dungeon_region(player, 'Swamp Waterway', 'Swamp Palace', ['Swamp Palace - Waterway Pot Key'], ['Swamp Waterway NE', 'Swamp Waterway N', 'Swamp Waterway NW']),
create_dungeon_region(player, 'Swamp I', 'Swamp Palace', None, ['Swamp I S']),
create_dungeon_region(player, 'Swamp T', 'Swamp Palace', None, ['Swamp T SW', 'Swamp T NW']),
create_dungeon_region(player, 'Swamp Boss', 'Swamp Palace', ['Swamp Palace - Boss', 'Swamp Palace - Prize'], ['Swamp Boss SW']),
# sw # sw
create_dungeon_region(player, 'Skull 1 Lobby', 'Skull Woods', None, ['Skull Woods First Section Exit', 'Skull 1 Lobby WS', 'Skull 1 Lobby ES']),
create_dungeon_region(player, 'Skull Map Room', 'Skull Woods', ['Skull Woods - Map Chest'], ['Skull Map Room WS', 'Skull Map Room SE']),
create_dungeon_region(player, 'Skull Pot Circle', 'Skull Woods', None, ['Skull Pot Circle WN', 'Skull Pot Circle Star Path']),
create_dungeon_region(player, 'Skull Pull Switch', 'Skull Woods', None, ['Skull Pull Switch EN', 'Skull Pull Switch S']),
create_dungeon_region(player, 'Skull Big Chest', 'Skull Woods', ['Skull Woods - Big Chest'], ['Skull Big Chest N', 'Skull Big Chest Hookpath']),
create_dungeon_region(player, 'Skull Pinball', 'Skull Woods', ['Skull Woods - Pinball Room'], ['Skull Pinball NE', 'Skull Pinball WS']),
create_dungeon_region(player, 'Skull Pot Prison', 'Skull Woods', ['Skull Woods - Pot Prison'], ['Skull Pot Prison ES', 'Skull Pot Prison SE']),
create_dungeon_region(player, 'Skull Compass Room', 'Skull Woods', ['Skull Woods - Compass Chest'], ['Skull Compass Room NE', 'Skull Compass Room ES', 'Skull Compass Room WS']),
create_dungeon_region(player, 'Skull Left Drop', 'Skull Woods', None, ['Skull Left Drop ES']),
create_dungeon_region(player, 'Skull 2 East Lobby', 'Skull Woods', None, ['Skull 2 East Lobby NW', 'Skull 2 East Lobby WS', 'Skull Woods Second Section Exit (East)']),
create_dungeon_region(player, 'Skull Big Key', 'Skull Woods', ['Skull Woods - Big Key Chest'], ['Skull Big Key SW', 'Skull Big Key WN']),
create_dungeon_region(player, 'Skull Lone Pot', 'Skull Woods', None, ['Skull Lone Pot EN']),
create_dungeon_region(player, 'Skull Small Hall', 'Skull Woods', None, ['Skull Small Hall ES', 'Skull Small Hall WS']),
create_dungeon_region(player, 'Skull Back Drop', 'Skull Woods', None, ['Skull Back Drop Star Path', ]),
create_dungeon_region(player, 'Skull 2 West Lobby', 'Skull Woods', ['Skull Woods - West Lobby Pot Key'], ['Skull 2 West Lobby ES', 'Skull 2 West Lobby NW', 'Skull Woods Second Section Exit (West)']),
create_dungeon_region(player, 'Skull X Room', 'Skull Woods', None, ['Skull X Room SW']),
create_dungeon_region(player, 'Skull 3 Lobby', 'Skull Woods', None, ['Skull 3 Lobby NW', 'Skull 3 Lobby WN', 'Skull Woods Final Section Exit']),
create_dungeon_region(player, 'Skull East Bridge', 'Skull Woods', None, ['Skull East Bridge EN', 'Skull East Bridge ES']),
create_dungeon_region(player, 'Skull West Bridge Nook', 'Skull Woods', ['Skull Woods - Bridge Room'], ['Skull West Bridge Nook WS']),
create_dungeon_region(player, 'Skull Star Pits', 'Skull Woods', None, ['Skull Star Pits SW', 'Skull Star Pits WS']),
create_dungeon_region(player, 'Skull Torch Room', 'Skull Woods', None, ['Skull Torch Room ES', 'Skull Torch Room EN']),
create_dungeon_region(player, 'Skull Vines', 'Skull Woods', None, ['Skull Vines WN', 'Skull Vines NW']),
create_dungeon_region(player, 'Skull Spike Corner', 'Skull Woods', ['Skull Woods - Spike Corner Key Drop'], ['Skull Spike Corner SW', 'Skull Spike Corner WS']),
create_dungeon_region(player, 'Skull Final Drop', 'Skull Woods', None, ['Skull Final Drop ES', 'Skull Final Drop Hole']),
create_dungeon_region(player, 'Skull Boss', 'Skull Woods', ['Skull Woods - Boss', 'Skull Woods - Prize']),
# tt # tt
create_dungeon_region(player, 'Thieves Lobby', 'Thieves\' Town', ['Thieves\' Town - Map Chest'], ['Thieves Town Exit', 'Thieves Lobby N Edge', 'Thieves Lobby NE Edge', 'Thieves Lobby E']),
create_dungeon_region(player, 'Thieves Ambush', 'Thieves\' Town', ['Thieves\' Town - Ambush Chest'], ['Thieves Ambush S Edge', 'Thieves Ambush SE Edge', 'Thieves Ambush ES Edge', 'Thieves Ambush EN Edge', 'Thieves Ambush E']),
create_dungeon_region(player, 'Thieves BK Corner', 'Thieves\' Town', None, ['Thieves BK Corner WN Edge', 'Thieves BK Corner WS Edge', 'Thieves BK Corner S Edge', 'Thieves BK Corner SW Edge',
'Thieves BK Corner W', 'Thieves BK Corner NW', 'Thieves BK Corner NE']),
create_dungeon_region(player, 'Thieves Compass Room', 'Thieves\' Town', ['Thieves\' Town - Compass Chest'], ['Thieves Compass Room NW Edge', 'Thieves Compass Room N Edge', 'Thieves Compass Room WS Edge', 'Thieves Compass Room W']),
create_dungeon_region(player, 'Thieves Big Chest Nook', 'Thieves\' Town', ['Thieves\' Town - Big Key Chest'], ['Thieves Big Chest Nook WS Edge']),
create_dungeon_region(player, 'Thieves Hallway', 'Thieves\' Town', ['Thieves\' Town - Hallway Pot Key'], ['Thieves Hallway SE', 'Thieves Hallway NE', 'Thieves Hallway WN', 'Thieves Hallway WS']),
create_dungeon_region(player, 'Thieves Boss', 'Thieves\' Town', ['Revealing Light', 'Thieves\' Town - Boss', 'Thieves\' Town - Prize'], ['Thieves Boss SE']),
create_dungeon_region(player, 'Thieves Pot Alcove Mid', 'Thieves\' Town', None, ['Thieves Pot Alcove Mid ES', 'Thieves Pot Alcove Mid WS']),
create_dungeon_region(player, 'Thieves Pot Alcove Bottom', 'Thieves\' Town', None, ['Thieves Pot Alcove Bottom SW']),
create_dungeon_region(player, 'Thieves Pot Alcove Top', 'Thieves\' Town', None, ['Thieves Pot Alcove Top NW']),
create_dungeon_region(player, 'Thieves Conveyor Maze', 'Thieves\' Town', None, ['Thieves Conveyor Maze SW', 'Thieves Conveyor Maze EN', 'Thieves Conveyor Maze WN', 'Thieves Conveyor Maze Down Stairs']),
create_dungeon_region(player, 'Thieves Spike Track', 'Thieves\' Town', None, ['Thieves Spike Track WS', 'Thieves Spike Track ES', 'Thieves Spike Track NE']),
create_dungeon_region(player, 'Thieves Hellway', 'Thieves\' Town', None, ['Thieves Hellway Orange Barrier', 'Thieves Hellway NW', 'Thieves Hellway Blue Barrier']),
create_dungeon_region(player, 'Thieves Hellway N Crystal', 'Thieves\' Town', None, ['Thieves Hellway Crystal Blue Barrier', 'Thieves Hellway Crystal EN']),
create_dungeon_region(player, 'Thieves Hellway S Crystal', 'Thieves\' Town', None, ['Thieves Hellway Crystal Orange Barrier', 'Thieves Hellway Crystal ES']),
create_dungeon_region(player, 'Thieves Triple Bypass', 'Thieves\' Town', None, ['Thieves Triple Bypass WN', 'Thieves Triple Bypass EN', 'Thieves Triple Bypass SE']),
create_dungeon_region(player, 'Thieves Spike Switch', 'Thieves\' Town', ['Thieves\' Town - Spike Switch Pot Key'], ['Thieves Spike Switch SW', 'Thieves Spike Switch Up Stairs']),
create_dungeon_region(player, 'Thieves Attic', 'Thieves\' Town', None, ['Thieves Attic Down Stairs', 'Thieves Attic ES']),
create_dungeon_region(player, 'Thieves Cricket Hall Left', 'Thieves\' Town', None, ['Thieves Cricket Hall Left WS', 'Thieves Cricket Hall Left Edge']),
create_dungeon_region(player, 'Thieves Cricket Hall Right', 'Thieves\' Town', None, ['Thieves Cricket Hall Right Edge', 'Thieves Cricket Hall Right ES']),
create_dungeon_region(player, 'Thieves Attic Window', 'Thieves\' Town', ['Thieves\' Town - Attic', 'Attic Cracked Floor'], ['Thieves Attic Window WS']),
create_dungeon_region(player, 'Thieves Basement Block', 'Thieves\' Town', None, ['Thieves Basement Block Up Stairs', 'Thieves Basement Block WN', 'Thieves Basement Block Path']),
create_dungeon_region(player, 'Thieves Blocked Entry', 'Thieves\' Town', None, ['Thieves Blocked Entry Path', 'Thieves Blocked Entry SW']),
create_dungeon_region(player, 'Thieves Lonely Zazak', 'Thieves\' Town', None, ['Thieves Lonely Zazak WS', 'Thieves Lonely Zazak ES', 'Thieves Lonely Zazak NW']),
create_dungeon_region(player, 'Thieves Blind\'s Cell', 'Thieves\' Town', ['Thieves\' Town - Blind\'s Cell', 'Suspicious Maiden'], ['Thieves Blind\'s Cell WS']),
create_dungeon_region(player, 'Thieves Conveyor Bridge', 'Thieves\' Town', None, ['Thieves Conveyor Bridge EN', 'Thieves Conveyor Bridge ES', 'Thieves Conveyor Bridge WS', 'Thieves Conveyor Bridge Block Path']),
create_dungeon_region(player, 'Thieves Conveyor Block', 'Thieves\' Town', None, ['Thieves Conveyor Block Path', 'Thieves Conveyor Block WN']),
create_dungeon_region(player, 'Thieves Big Chest Room', 'Thieves\' Town', ['Thieves\' Town - Big Chest'], ['Thieves Big Chest Room ES']),
create_dungeon_region(player, 'Thieves Trap', 'Thieves\' Town', None, ['Thieves Trap EN']),
# ice # ice
# mire # mire
# tr # tr
@@ -545,6 +627,29 @@ key_only_locations = {
'Desert Palace - Desert Tiles 2 Pot Key': 'Small Key (Desert Palace)', 'Desert Palace - Desert Tiles 2 Pot Key': 'Small Key (Desert Palace)',
'Castle Tower - Dark Archer Key Drop': 'Small Key (Agahnims Tower)', 'Castle Tower - Dark Archer Key Drop': 'Small Key (Agahnims Tower)',
'Castle Tower - Circle of Pots Key Drop': 'Small Key (Agahnims Tower)', 'Castle Tower - Circle of Pots Key Drop': 'Small Key (Agahnims Tower)',
'Swamp Palace - Pot Row Pot Key': 'Small Key (Swamp Palace)',
'Swamp Palace - Trench 1 Pot Key': 'Small Key (Swamp Palace)',
'Swamp Palace - Hookshot Pot Key': 'Small Key (Swamp Palace)',
'Swamp Palace - Trench 2 Pot Key': 'Small Key (Swamp Palace)',
'Swamp Palace - Waterway Pot Key': 'Small Key (Swamp Palace)',
'Skull Woods - West Lobby Pot Key': 'Small Key (Skull Woods)',
'Skull Woods - Spike Corner Key Drop': 'Small Key (Skull Woods)',
'Thieves\' Town - Hallway Pot Key': 'Small Key (Thieves Town)',
'Thieves\' Town - Spike Switch Pot Key': 'Small Key (Thieves Town)'
}
dungeon_events = [
'Trench 1 Switch',
'Trench 2 Switch',
'Swamp Drain',
'Attic Cracked Floor',
'Suspicious Maiden',
'Revealing Light'
]
flooded_keys_reverse = {
'Swamp Palace - Trench 1 Pot Key': 'Trench 1 Switch',
'Swamp Palace - Trench 2 Pot Key': 'Trench 2 Switch'
} }
# todo: escape big key? - should be separate from above for dungeon key layout validation # todo: escape big key? - should be separate from above for dungeon key layout validation
@@ -772,6 +877,12 @@ location_table = {'Mushroom': (0x180013, False, 'in the woods'),
'Frog': (None, False, None), 'Frog': (None, False, None),
'Missing Smith': (None, False, None), 'Missing Smith': (None, False, None),
'Dark Blacksmith Ruins': (None, False, None), 'Dark Blacksmith Ruins': (None, False, None),
'Trench 1 Switch': (None, False, None),
'Trench 2 Switch': (None, False, None),
'Swamp Drain': (None, False, None),
'Attic Cracked Floor': (None, False, None),
'Suspicious Maiden': (None, False, None),
'Revealing Light': (None, False, None),
'Eastern Palace - Prize': ([0x1209D, 0x53EF8, 0x53EF9, 0x180052, 0x18007C, 0xC6FE], True, 'Eastern Palace'), 'Eastern Palace - Prize': ([0x1209D, 0x53EF8, 0x53EF9, 0x180052, 0x18007C, 0xC6FE], True, 'Eastern Palace'),
'Desert Palace - Prize': ([0x1209E, 0x53F1C, 0x53F1D, 0x180053, 0x180078, 0xC6FF], True, 'Desert Palace'), 'Desert Palace - Prize': ([0x1209E, 0x53F1C, 0x53F1D, 0x180053, 0x180078, 0xC6FF], True, 'Desert Palace'),
'Tower of Hera - Prize': ([0x120A5, 0x53F0A, 0x53F0B, 0x18005A, 0x18007A, 0xC706], True, 'Tower of Hera'), 'Tower of Hera - Prize': ([0x120A5, 0x53F0A, 0x53F0B, 0x18005A, 0x18007A, 0xC706], True, 'Tower of Hera'),
+1 -1
View File
@@ -18,7 +18,7 @@ from EntranceShuffle import door_addresses
JAP10HASH = '03a63945398191337e896e5771f77173' JAP10HASH = '03a63945398191337e896e5771f77173'
RANDOMIZERBASEHASH = 'fdf74815ca2ad15186daa9de3e68cecb' RANDOMIZERBASEHASH = '78b74698bf286f0cc6d9c2563dd7d59e'
class JsonRom(object): class JsonRom(object):
+122 -88
View File
@@ -1,8 +1,9 @@
import collections import collections
from collections import defaultdict from collections import defaultdict
import logging import logging
from BaseClasses import CollectionState from BaseClasses import CollectionState, DoorType
from Dungeons import region_starts from DungeonGenerator import ExplorationState
from Regions import key_only_locations
def set_rules(world, player): def set_rules(world, player):
@@ -257,11 +258,8 @@ def global_rules(world, player):
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 # Start of door rando rules
# TODO: Do these need to flag off when door rando is off? # TODO: Do these need to flag off when door rando is off? - some of them, yes
# If these generate fine rules with vanilla shuffle - then no. add_key_logic_rules(world, player) # todo - vanilla shuffle rules
# Escape/ Hyrule Castle
generate_key_logic(region_starts['Hyrule Castle'], 'Small Key (Escape)', world, player)
# Eastern Palace # Eastern Palace
# Eyegore room needs a bow # Eyegore room needs a bow
@@ -272,7 +270,6 @@ def global_rules(world, player):
forbid_item(world.get_location('Eastern Palace - Big Chest', player), 'Big Key (Eastern Palace)', player) forbid_item(world.get_location('Eastern Palace - Big Chest', player), '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 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)) set_rule(world.get_entrance('Eastern Courtyard N', player), lambda state: state.has('Big Key (Eastern Palace)', player))
generate_key_logic(region_starts['Eastern Palace'], 'Small Key (Eastern Palace)', world, player)
# Boss rules. Same as below but no BK or arrow requirement. # Boss rules. Same as below but no BK or arrow requirement.
set_defeat_dungeon_boss_rule(world.get_location('Eastern Palace - Prize', player)) set_defeat_dungeon_boss_rule(world.get_location('Eastern Palace - Prize', player))
@@ -286,7 +283,6 @@ def global_rules(world, player):
set_rule(world.get_entrance('Desert Wall Slide NW', player), lambda state: state.has_fire_source(player)) set_rule(world.get_entrance('Desert Wall Slide NW', player), lambda state: state.has_fire_source(player))
set_defeat_dungeon_boss_rule(world.get_location('Desert Palace - Prize', player)) set_defeat_dungeon_boss_rule(world.get_location('Desert Palace - Prize', player))
set_defeat_dungeon_boss_rule(world.get_location('Desert Palace - Boss', player)) set_defeat_dungeon_boss_rule(world.get_location('Desert Palace - Boss', player))
generate_key_logic(region_starts['Desert Palace'], 'Small Key (Desert Palace)', world, player)
# Tower of Hera # Tower of Hera
set_rule(world.get_location('Tower of Hera - Big Chest', player), lambda state: state.has('Big Key (Tower of Hera)', player)) set_rule(world.get_location('Tower of Hera - Big Chest', player), lambda state: state.has('Big Key (Tower of Hera)', player))
@@ -296,10 +292,8 @@ def global_rules(world, player):
set_rule(world.get_entrance('Hera Startile Corner NW', player), lambda state: state.has('Big Key (Tower of Hera)', player)) set_rule(world.get_entrance('Hera Startile Corner NW', player), lambda state: state.has('Big Key (Tower of Hera)', player))
set_defeat_dungeon_boss_rule(world.get_location('Tower of Hera - Boss', player)) set_defeat_dungeon_boss_rule(world.get_location('Tower of Hera - Boss', player))
set_defeat_dungeon_boss_rule(world.get_location('Tower of Hera - Prize', player)) set_defeat_dungeon_boss_rule(world.get_location('Tower of Hera - Prize', player))
generate_key_logic(region_starts['Tower of Hera'], 'Small Key (Tower of Hera)', world, player)
set_rule(world.get_entrance('Tower Altar NW', player), lambda state: state.has_sword(player)) set_rule(world.get_entrance('Tower Altar NW', player), lambda state: state.has_sword(player))
generate_key_logic(region_starts['Agahnims Tower'], 'Small Key (Agahnims Tower)', world, player)
set_rule(world.get_entrance('PoD Mimics 1 NW', player), lambda state: state.can_shoot_arrows(player)) set_rule(world.get_entrance('PoD Mimics 1 NW', player), lambda state: state.can_shoot_arrows(player))
set_rule(world.get_entrance('PoD Mimics 2 NW', player), lambda state: state.can_shoot_arrows(player)) set_rule(world.get_entrance('PoD Mimics 2 NW', player), lambda state: state.can_shoot_arrows(player))
@@ -313,50 +307,70 @@ def global_rules(world, player):
set_rule(world.get_entrance('PoD Dark Pegs Up Ladder', player), lambda state: state.has('Hammer', player)) set_rule(world.get_entrance('PoD Dark Pegs Up Ladder', player), lambda state: state.has('Hammer', player))
set_defeat_dungeon_boss_rule(world.get_location('Palace of Darkness - Boss', player)) set_defeat_dungeon_boss_rule(world.get_location('Palace of Darkness - Boss', player))
set_defeat_dungeon_boss_rule(world.get_location('Palace of Darkness - Prize', player)) set_defeat_dungeon_boss_rule(world.get_location('Palace of Darkness - Prize', player))
generate_key_logic(region_starts['Palace of Darkness'], 'Small Key (Palace of Darkness)', world, player)
set_rule(world.get_entrance('Swamp Lobby Moat', player), lambda state: state.has('Flippers', player) and state.has('Open Floodgate', player))
set_rule(world.get_entrance('Swamp Trench 1 Approach Dry', player), lambda state: not state.has('Trench 1 Filled', player))
set_rule(world.get_entrance('Swamp Trench 1 Key Ledge Dry', player), lambda state: not state.has('Trench 1 Filled', player))
set_rule(world.get_entrance('Swamp Trench 1 Departure Dry', player), lambda state: not state.has('Trench 1 Filled', player))
set_rule(world.get_entrance('Swamp Trench 1 Approach Key', player), lambda state: state.has('Flippers', player) and state.has('Trench 1 Filled', player))
set_rule(world.get_entrance('Swamp Trench 1 Approach Swim Depart', player), lambda state: state.has('Flippers', player) and state.has('Trench 1 Filled', player))
set_rule(world.get_entrance('Swamp Trench 1 Key Approach', player), lambda state: state.has('Flippers', player) and state.has('Trench 1 Filled', player))
set_rule(world.get_entrance('Swamp Trench 1 Key Ledge Depart', player), lambda state: state.has('Flippers', player) and state.has('Trench 1 Filled', player))
set_rule(world.get_entrance('Swamp Trench 1 Departure Approach', player), lambda state: state.has('Flippers', player) and state.has('Trench 1 Filled', player))
set_rule(world.get_entrance('Swamp Trench 1 Departure Key', player), lambda state: state.has('Flippers', player) and state.has('Trench 1 Filled', player))
set_rule(world.get_location('Trench 1 Switch', player), lambda state: state.has('Hammer', player))
set_rule(world.get_entrance('Swamp Hub Hook Path', player), lambda state: state.has('Hookshot', player))
set_rule(world.get_location('Swamp Palace - Hookshot Pot Key', player), lambda state: state.has('Hookshot', player))
set_rule(world.get_entrance('Swamp Trench 2 Pots Dry', player), lambda state: not state.has('Trench 2 Filled', player))
set_rule(world.get_entrance('Swamp Trench 2 Pots Wet', player), lambda state: state.has('Flippers', player) and state.has('Trench 2 Filled', player))
set_rule(world.get_entrance('Swamp Trench 2 Departure Wet', player), lambda state: state.has('Flippers', player) and state.has('Trench 2 Filled', player))
set_rule(world.get_entrance('Swamp West Ledge Hook Path', player), lambda state: state.has('Hookshot', player))
set_rule(world.get_entrance('Swamp Barrier Ledge Hook Path', player), lambda state: state.has('Hookshot', player))
set_rule(world.get_entrance('Swamp Drain Right Switch', player), lambda state: state.has('Drained Swamp', player))
set_rule(world.get_entrance('Swamp Drain WN', player), lambda state: state.has('Drained Swamp', player))
set_rule(world.get_entrance('Swamp Flooded Room WS', player), lambda state: state.has('Drained Swamp', player))
set_rule(world.get_entrance('Swamp Flooded Room Ladder', player), lambda state: state.has('Drained Swamp', player))
set_rule(world.get_location('Swamp Palace - Flooded Room - Left', player), lambda state: state.has('Drained Swamp', player))
set_rule(world.get_location('Swamp Palace - Flooded Room - Right', player), lambda state: state.has('Drained Swamp', player))
set_rule(world.get_entrance('Swamp Waterway NW', player), lambda state: state.has('Flippers', player))
set_rule(world.get_entrance('Swamp Waterway N', player), lambda state: state.has('Flippers', player))
set_rule(world.get_entrance('Swamp Waterway NE', player), lambda state: state.has('Flippers', player))
set_rule(world.get_location('Swamp Palace - Waterway Pot Key', player), lambda state: state.has('Flippers', player))
set_rule(world.get_location('Swamp Palace - Big Chest', player), lambda state: state.has('Big Key (Swamp Palace)', player))
if world.accessibility == 'locations':
forbid_item(world.get_location('Swamp Palace - Big Chest', player), 'Big Key (Swamp Palace)', player)
set_defeat_dungeon_boss_rule(world.get_location('Swamp Palace - Boss', player))
set_defeat_dungeon_boss_rule(world.get_location('Swamp Palace - Prize', player))
set_rule(world.get_entrance('Skull Big Chest Hookpath', player), lambda state: state.has('Hookshot', player))
set_rule(world.get_location('Skull Woods - Big Chest', player), lambda state: state.has('Big Key (Skull Woods)', player))
if world.accessibility == 'locations':
forbid_item(world.get_location('Skull Woods - Big Chest', player), 'Big Key (Skull Woods)', player)
set_rule(world.get_entrance('Skull Torch Room EN', player), lambda state: state.has('Fire Rod', player))
set_rule(world.get_entrance('Skull Vines NW', player), lambda state: state.has_sword(player))
set_defeat_dungeon_boss_rule(world.get_location('Skull Woods - Boss', player))
set_defeat_dungeon_boss_rule(world.get_location('Skull Woods - Prize', player))
set_rule(world.get_entrance('Thieves BK Corner NE', player), lambda state: state.has('Big Key (Thieves Town)', player))
# blind can't have the small key? - not necessarily true anymore - but likely still
set_rule(world.get_location('Thieves\' Town - Big Chest', player), lambda state: (state.has('Big Key (Thieves Town)', player) and state.has('Hammer', player)))
if world.accessibility == 'locations':
forbid_item(world.get_location('Thieves\' Town - Big Chest', player), 'Big Key (Thieves Town)', player)
for entrance in ['Thieves Basement Block Path', 'Thieves Blocked Entry Path', 'Thieves Conveyor Block Path', 'Thieves Conveyor Bridge Block Path']:
set_rule(world.get_entrance(entrance, player), lambda state: state.can_lift_rocks(player))
for location in ['Thieves\' Town - Blind\'s Cell', 'Thieves\' Town - Boss']:
forbid_item(world.get_location(location, player), 'Big Key (Thieves Town)', player)
forbid_item(world.get_location('Thieves\' Town - Blind\'s Cell', player), 'Big Key (Thieves Town)', player)
for location in ['Suspicious Maiden', 'Thieves\' Town - Blind\'s Cell']:
set_rule(world.get_location(location, player), lambda state: state.has('Big Key (Thieves Town)', player))
set_rule(world.get_location('Revealing Light', player), lambda state: state.has('Shining Light', player) and state.has('Maiden Rescued', player))
set_rule(world.get_location('Thieves\' Town - Boss', player), lambda state: state.has('Maiden Unmasked', player) and world.get_location('Thieves\' Town - Boss', player).parent_region.dungeon.boss.can_defeat(state))
set_rule(world.get_location('Thieves\' Town - Prize', player), lambda state: state.has('Maiden Unmasked', player) and world.get_location('Thieves\' Town - Prize', player).parent_region.dungeon.boss.can_defeat(state))
# End of door rando rules. # End of door rando rules.
set_rule(world.get_entrance('Swamp Palace Moat', player), lambda state: state.has('Flippers', player) and state.has('Open Floodgate', player))
add_rule(world.get_location('Sunken Treasure', player), lambda state: state.has('Open Floodgate', player)) add_rule(world.get_location('Sunken Treasure', player), lambda state: state.has('Open Floodgate', player))
set_rule(world.get_entrance('Swamp Palace Small Key Door', player), lambda state: state.has_key('Small Key (Swamp Palace)', player))
set_rule(world.get_entrance('Swamp Palace (Center)', player), lambda state: state.has('Hammer', player))
set_rule(world.get_location('Swamp Palace - Big Chest', player), lambda state: state.has('Big Key (Swamp Palace)', player) or item_name(state, 'Swamp Palace - Big Chest', player) == ('Big Key (Swamp Palace)', player))
if world.accessibility != 'locations':
set_always_allow(world.get_location('Swamp Palace - Big Chest', player), lambda state, item: item.name == 'Big Key (Swamp Palace)' and item.player == player)
set_rule(world.get_entrance('Swamp Palace (North)', player), lambda state: state.has('Hookshot', player))
set_defeat_dungeon_boss_rule(world.get_location('Swamp Palace - Boss', player))
set_defeat_dungeon_boss_rule(world.get_location('Swamp Palace - Prize', player))
for location in ['Swamp Palace - Entrance']:
forbid_item(world.get_location(location, player), 'Big Key (Swamp Palace)', player)
set_rule(world.get_entrance('Thieves Town Big Key Door', player), lambda state: state.has('Big Key (Thieves Town)', player))
set_rule(world.get_entrance('Blind Fight', player), lambda state: state.has_key('Small Key (Thieves Town)', player))
set_defeat_dungeon_boss_rule(world.get_location('Thieves\' Town - Boss', player))
set_defeat_dungeon_boss_rule(world.get_location('Thieves\' Town - Prize', player))
set_rule(world.get_location('Thieves\' Town - Big Chest', player), lambda state: (state.has_key('Small Key (Thieves Town)', player) or item_name(state, 'Thieves\' Town - Big Chest', player) == ('Small Key (Thieves Town)', player)) and state.has('Hammer', player))
if world.accessibility != 'locations':
set_always_allow(world.get_location('Thieves\' Town - Big Chest', player), lambda state, item: item.name == 'Small Key (Thieves Town)' and item.player == player and state.has('Hammer', player))
set_rule(world.get_location('Thieves\' Town - Attic', player), lambda state: state.has_key('Small Key (Thieves Town)', player))
for location in ['Thieves\' Town - Attic', 'Thieves\' Town - Big Chest', 'Thieves\' Town - Blind\'s Cell', 'Thieves\' Town - Boss']:
forbid_item(world.get_location(location, player), 'Big Key (Thieves Town)', player)
for location in ['Thieves\' Town - Attic', 'Thieves\' Town - Boss']:
forbid_item(world.get_location(location, player), 'Small Key (Thieves Town)', player)
set_rule(world.get_entrance('Skull Woods First Section South Door', player), lambda state: state.has_key('Small Key (Skull Woods)', player))
set_rule(world.get_entrance('Skull Woods First Section (Right) North Door', player), lambda state: state.has_key('Small Key (Skull Woods)', player))
set_rule(world.get_entrance('Skull Woods First Section West Door', player), lambda state: state.has_key('Small Key (Skull Woods)', player, 2)) # ideally would only be one key, but we may have spent thst key already on escaping the right section
set_rule(world.get_entrance('Skull Woods First Section (Left) Door to Exit', player), lambda state: state.has_key('Small Key (Skull Woods)', player, 2))
set_rule(world.get_location('Skull Woods - Big Chest', player), lambda state: state.has('Big Key (Skull Woods)', player) or item_name(state, 'Skull Woods - Big Chest', player) == ('Big Key (Skull Woods)', player))
if world.accessibility != 'locations':
set_always_allow(world.get_location('Skull Woods - Big Chest', player), lambda state, item: item.name == 'Big Key (Skull Woods)' and item.player == player)
set_rule(world.get_entrance('Skull Woods Torch Room', player), lambda state: state.has_key('Small Key (Skull Woods)', player, 3) and state.has('Fire Rod', player) and state.has_sword(player)) # sword required for curtain
set_defeat_dungeon_boss_rule(world.get_location('Skull Woods - Boss', player))
set_defeat_dungeon_boss_rule(world.get_location('Skull Woods - Prize', player))
for location in ['Skull Woods - Boss']:
forbid_item(world.get_location(location, player), 'Small Key (Skull Woods)', player)
set_rule(world.get_entrance('Ice Palace Entrance Room', player), lambda state: state.can_melt_things(player)) set_rule(world.get_entrance('Ice Palace Entrance Room', player), lambda state: state.can_melt_things(player))
set_rule(world.get_location('Ice Palace - Big Chest', player), lambda state: state.has('Big Key (Ice Palace)', player)) set_rule(world.get_location('Ice Palace - Big Chest', player), lambda state: state.has('Big Key (Ice Palace)', player))
set_rule(world.get_entrance('Ice Palace (Kholdstare)', player), lambda state: state.can_lift_rocks(player) and state.has('Hammer', player) and state.has('Big Key (Ice Palace)', player) and (state.has_key('Small Key (Ice Palace)', player, 2) or (state.has('Cane of Somaria', player) and state.has_key('Small Key (Ice Palace)', player, 1)))) set_rule(world.get_entrance('Ice Palace (Kholdstare)', player), lambda state: state.can_lift_rocks(player) and state.has('Hammer', player) and state.has('Big Key (Ice Palace)', player) and (state.has_key('Small Key (Ice Palace)', player, 2) or (state.has('Cane of Somaria', player) and state.has_key('Small Key (Ice Palace)', player, 1))))
@@ -880,7 +894,6 @@ def no_glitches_rules(world, player):
add_rule(world.get_location(location, player), lambda state: state.has('Hookshot', player)) 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 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('Paradox Cave Bomb Jump', player), lambda state: False)
set_rule(world.get_entrance('Skull Woods First Section Bomb Jump', player), lambda state: False)
# Light cones in standard depend on which world we actually are in, not which one the location would normally be # 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 # We add Lamp requirements only to those locations which lie in the dark world (or everything if open
@@ -1525,11 +1538,12 @@ def set_bunny_rules(world, player):
# regions for the exits of multi-entrace caves/drops that bunny cannot pass # 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. # 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)', bunny_impassable_caves = ['Bumper Cave', 'Two Brothers House', 'Hookshot Cave', 'Turtle Rock (Entrance)', 'Turtle Rock (Second Section)', 'Turtle Rock (Big Chest)',
'Turtle Rock (Eye Bridge)', 'Pyramid', 'Spiral Cave (Top)', 'Fairy Ascension Cave (Drop)'] 'Turtle Rock (Eye Bridge)', 'Pyramid', 'Spiral Cave (Top)', 'Fairy Ascension Cave (Drop)']
# todo: bunny impassable caves # todo: bunny impassable caves
# sewers drop may or may not be - maybe just new terminology # sewers drop may or may not be - maybe just new terminology
# desert pots are impassible by bunny - need rules for those transitions # desert pots are impassible by bunny - need rules for those transitions
# skull woods drops tend to soft lock bunny
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'] 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']
@@ -1667,83 +1681,103 @@ def set_inverted_bunny_rules(world, player):
add_rule(location, get_rule_to_add(location.parent_region)) add_rule(location, get_rule_to_add(location.parent_region))
def generate_key_logic(start_region_names, small_key_name, world, player): def add_key_logic_rules(world, player):
logger = logging.getLogger('')
key_logic = world.key_logic[player]
for d_name, d_logic in key_logic.items():
for door_name, keys in d_logic.door_rules.items():
logger.debug(' %s needs %s keys', door_name, keys)
add_rule(world.get_entrance(door_name, player), create_key_rule(d_logic.small_key_name, player, keys))
for location in d_logic.bk_restricted:
if location.name not in key_only_locations.keys():
forbid_item(location, d_logic.bk_name, player)
def generate_key_logic(dungeon_name, small_key_name, world, player):
sector, start_region_names = world.dungeon_layouts[player][dungeon_name]
logger = logging.getLogger('') logger = logging.getLogger('')
# Now that the dungeon layout is done, we need to search again to generate key logic. # Now that the dungeon layout is done, we need to search again to generate key logic.
# TODO: This assumes all start doors are accessible, which isn't always true. # TODO: This assumes all start doors are accessible, which isn't always true.
# TODO: This can generate solvable-but-really-annoying layouts due to one ways. state = ExplorationState()
available_doors = [] # Doors to explore # available_doors = [] # Doors to explore
visited_regions = set() # Regions we've been to and don't need to expand # visited_regions = set() # Regions we've been to and don't need to expand
current_kr = 0 # Key regions are numbered, starting at 0 current_kr = 0 # Key regions are numbered, starting at 0
door_krs = {} # Map of key door name to KR it lives in # door_krs = {} # Map of key door name to KR it lives in
kr_parents = {} # Key region to parent map kr_parents = {} # Key region to parent map
kr_location_counts = defaultdict(int) # Number of locations in each key region # kr_location_counts = defaultdict(int) # Number of locations in each key region
# Everything in a start region is in key region 0. # Everything in a start region is in key region 0.
for name in start_region_names: for name in start_region_names:
region = world.get_region(name, player) region = world.get_region(name, player)
visited_regions.add(name) state.visit_region(region, current_kr)
kr_location_counts[current_kr] += len(region.locations) state.add_all_doors_check_key_region(region, current_kr, world, player)
for door in get_doors(world, region, player):
if not door.blocked:
available_doors.append(door)
door_krs[door.name] = current_kr
# Search into the dungeon # Search into the dungeon
logger.debug('Begin key region search. %s', small_key_name) # logger.debug('Begin key region search. %s', small_key_name)
while len(available_doors) > 0: while len(state.avail_doors) > 0:
# Open as many non-key doors as possible before opening a key door. # Open as many non-key doors as possible before opening a key door.
# This guarantees that we're only exploring one key region at a time. # This guarantees that we're only exploring one key region at a time.
available_doors.sort(key=lambda door: 0 if door.smallKey else 1) state.avail_doors.sort(key=state.key_door_sort)
door = available_doors.pop() explorable_door = state.next_avail_door()
door = explorable_door.door
local_kr = state.door_krs[door.name]
# logger.debug(' kr %s: Door %s', local_kr, door.name)
connect_region = world.get_entrance(door.name, player).connected_region
# Bail early if we've been here before or the door is blocked # Bail early if we've been here before or the door is blocked
local_kr = door_krs[door.name] if not state.validate(door, connect_region, world):
logger.debug(' kr %s: Door %s', local_kr, door.name)
exit = world.get_entrance(door.name, player).connected_region
if door.blocked or exit.name in visited_regions:
continue continue
# Once we open a key door, we need a new region. # Once we open a key door, we need a new region.
if door.smallKey: if door.smallKey and door not in state.opened_doors: # we tend to open doors in a DFS manner
current_kr += 1 current_kr += 1
kr_parents[current_kr] = local_kr kr_parents[current_kr] = local_kr
local_kr = current_kr local_kr = current_kr
logger.debug(' New KR %s', current_kr) state.opened_doors.append(door)
if door.dest.smallKey:
state.opened_doors.append(door.dest)
# logger.debug('%s: New KR %s', door.name, current_kr)
# Account for the new region # Account for the new region
visited_regions.add(exit.name) state.visit_region(connect_region, local_kr)
kr_location_counts[local_kr] += len(exit.locations) state.add_all_doors_check_key_region(connect_region, local_kr, world, player)
for new_door in get_doors(world, exit, player): # kr_location_counts[local_kr] += len(exit.locations)
available_doors.append(new_door)
door_krs[new_door.name] = local_kr
# Now that we have doors divided up into key regions, we can analyze the map # Now that we have doors divided up into key regions, we can analyze the map
# Invert the door -> kr map into one that lists doors by region. # Invert the door -> kr map into one that lists doors by region.
kr_doors = defaultdict(list) kr_doors = defaultdict(list)
region_krs = {} region_krs = {}
for door_name in door_krs: for door_name in state.door_krs:
kr = door_krs[door_name] kr = state.door_krs[door_name]
exit = world.get_entrance(door_name, player); entrance = world.get_entrance(door_name, player)
door = world.check_for_door(door_name, player) door = world.check_for_door(door_name, player)
region_krs[exit.parent_region.name] = kr ent_name = entrance.parent_region.name
if ent_name in region_krs.keys():
region_krs[entrance.parent_region.name] = min(region_krs[entrance.parent_region.name], kr)
else:
region_krs[entrance.parent_region.name] = kr
if door.smallKey and not door.blocked: if door.smallKey and not door.blocked:
kr_doors[kr].append(exit) kr_doors[kr].append(entrance)
kr_keys = defaultdict(int) # Number of keys each region needs kr_keys = defaultdict(int) # Number of keys each region needs
for kr in range(0, current_kr + 1): for kr in range(0, current_kr + 1):
logic_doors = [] logic_doors = []
keys = 0 keys = 0
for door in kr_doors[kr]: for door in kr_doors[kr]:
dest_kr = region_krs[door.connected_region.name] dest_kr = region_krs[door.connected_region.name]
if dest_kr > kr: if dest_kr > kr: # may be the case if dest_kr != parent_kr of kr
# This door heads deeper into the dungeon. It needs a full key, and logic # This door heads deeper into the dungeon. It needs a full key, and logic
keys += 1 keys += 1
logic_doors.append(door) logic_doors.append(door)
elif dest_kr == kr: elif dest_kr == kr:
# This door doesn't get us any deeper, but it's possible to waste a key. # This door doesn't get us any deeper, but it's possible to waste a key.
# We're going to see its sibling in this search, so add half a key # If we're going to see its sibling in this search, add half a key
keys += 0.5 actual_door = world.get_door(door.name, player)
if actual_door.type == DoorType.SpiralStairs:
keys += 1
else:
keys += 0.5
logic_doors.append(door) # this may still need logic
# Add key count from parent region # Add key count from parent region
if kr in kr_parents: if kr in kr_parents:
keys += kr_keys[kr_parents[kr]] keys += kr_keys[kr_parents[kr]]
kr_keys[kr] = keys kr_keys[kr] = keys
# Generate logic # Generate logic
for door in logic_doors: for door in logic_doors:
logger.info(' %s in kr %s needs %s keys', door.name, kr, keys) logger.debug(' %s in kr %s needs %s keys', door.name, kr, keys)
add_rule(world.get_entrance(door.name, player), create_key_rule(small_key_name, player, keys)) add_rule(world.get_entrance(door.name, player), create_key_rule(small_key_name, player, keys))
+19 -10
View File
@@ -8,13 +8,13 @@ RecordStairType: {
SpiralWarp: { SpiralWarp: {
lda $040c : cmp.b #$ff : beq .abort ; abort if not in dungeon lda $040c : cmp.b #$ff : beq .abort ; abort if not in dungeon
cmp #$14 : beq .check ; hera is okay cmp #$14 : beq .check ; hera is okay
cmp #$0c : beq .check ; pod is okay cmp #$16 : beq .check ; thieves is okay
cmp #$0A : bcs .abort ; abort if not supported yet -- todo: this needs to be altered/removed as more dungeons are implemented cmp #$0e : bcs .abort ; abort if not supported yet -- todo: this needs to be altered/removed as more dungeons are implemented
.check .check
lda $045e : cmp #$5e : beq .gtg ; abort if not spiral - intended room is in A! lda $045e : cmp #$5e : beq .gtg ; abort if not spiral - intended room is in A!
cmp #$5f : beq .gtg cmp #$5f : beq .gtg
.abort .abort
stz $045e : lda $a2 : and #$0f : rtl ; clear,run highjack code and get out stz $045e : lda $a2 : and #$0f : rtl ; clear,run hijacked code and get out
.gtg .gtg
phb : phk : plb : phx : phy ; push stuff phb : phk : plb : phx : phy ; push stuff
@@ -25,8 +25,10 @@ SpiralWarp: {
sep #$30 sep #$30
lda $00 : sta $a0 lda $00 : sta $a0
; shift quadrant if necessary ; shift quadrant if necessary
stz $07
lda $01 : and #$01 : !sub $a9 lda $01 : and #$01 : !sub $a9
bne .xQuad bne .xQuad
inc $07
lda $22 : bne .skipXQuad ; this is an edge case lda $22 : bne .skipXQuad ; this is an edge case
dec $23 : bra .skipXQuad ; need to -1 if $22 is 0 dec $23 : bra .skipXQuad ; need to -1 if $22 is 0
.xQuad sta $06 : !add $a9 : sta $a9 .xQuad sta $06 : !add $a9 : sta $a9
@@ -42,7 +44,7 @@ SpiralWarp: {
lda $01 : and #$04 : lsr : sta $048a ;fix layer calc 0->0 2->1 lda $01 : and #$04 : lsr : sta $048a ;fix layer calc 0->0 2->1
lda $01 : and #$08 : lsr #2 : sta $0492 ;fix from layer calc 0->0 2->1 lda $01 : and #$08 : lsr #2 : sta $0492 ;fix from layer calc 0->0 2->1
; shift lower coordinates ; shift lower coordinates
lda $02 : sta $22 : bne .adjY : inc $23 lda $02 : sta $22 : bne .adjY : lda $23 : !add $07 : sta $23
.adjY lda $03 : sta $20 : bne .upDownAdj : inc $21 .adjY lda $03 : sta $20 : bne .upDownAdj : inc $21
.upDownAdj ldx #$08 .upDownAdj ldx #$08
lda $0462 : and #$04 : beq .upStairs lda $0462 : and #$04 : beq .upStairs
@@ -90,15 +92,22 @@ LookupSpiralOffset: {
cmp #$02 : beq .quad2 cmp #$02 : beq .quad2
cmp #$03 : beq .quad3 cmp #$03 : beq .quad3
.quad0 .quad0
inc $01 : lda $22 : cmp #$98 : bcc .done ;gt ent and hc stairwell inc $01 : lda $a2
cmp #$0c : beq .q0diff ;gt ent
cmp #$70 : bne .done ;hc stairwell
.q0diff lda $22 : cmp #$98 : bcc .done ;gt ent and hc stairwell
inc $01 : bra .done inc $01 : bra .done
.quad1 .quad1
lda $040c : cmp $0a : beq .q1diff : cmp $0c : bne .done lda $a2
.q1diff lda $22 : cmp #$98 : bcc .done ;swamp/pod dual stairs cmp #$1a : beq .q1diff ;pod compass
cmp #$26 : beq .q1diff ;swamp elbows
cmp #$6a : beq .q1diff ;pod dark basement
cmp #$76 : bne .done ;swamp drain
.q1diff lda $22 : cmp #$98 : bcc .done
inc $01 : bra .done inc $01 : bra .done
.quad2 ;ice room .quad2
lda #$03 : sta $01 lda #$03 : sta $01 : lda $a2
lda $040c : cmp $12 : bne .done cmp #$5f : bne .done ;ice u room
lda $22 : cmp #$78 : bcc .done lda $22 : cmp #$78 : bcc .done
inc $01 : bra .done inc $01 : bra .done
.quad3 lda #$02 : sta $01 ; always 2 .quad3 lda #$02 : sta $01 ; always 2
File diff suppressed because one or more lines are too long