diff --git a/BaseClasses.py b/BaseClasses.py index 552d39e0..03378f4e 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -850,6 +850,7 @@ class Door(object): self.blocked = False # Indicates if the door is normally blocked off. (Sanc door or always closed) 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.ugly = False # Indicates that it can't be seen from the front (e.g. back of a big key door) def getAddress(self): if self.type == DoorType.Normal: diff --git a/DoorShuffle.py b/DoorShuffle.py index 11574520..94f4b89e 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -159,12 +159,20 @@ def shuffle_dungeon(world, player, start_region_names, dungeon_region_names): for name in [r for r in dungeon_region_names if r not in start_region_names]: available_regions.append(world.get_region(name, player)) random.shuffle(available_regions) + + # "Ugly" doors are doors that we don't want to see from the front, because of some + # sort of unsupported key door. To handle them, make a map of "ugly regions" and + # never link across them. + ugly_regions = {} + next_ugly_region = 1 # Add all start regions to the open set. available_doors = [] for name in start_region_names: logger.info("Starting in %s", name) - available_doors.extend(get_doors(world, world.get_region(name, player), player)) + for door in get_doors(world, world.get_region(name, player), player): + ugly_regions[door.name] = 0 + available_doors.append(door) # Loop until all available doors are used while len(available_doors) > 0: @@ -173,7 +181,7 @@ def shuffle_dungeon(world, player, start_region_names, dungeon_region_names): # into the dungeon), or puts them late in the dungeon (so they probably are part # of a loop). Panic if neither of these happens. random.shuffle(available_doors) - available_doors.sort(key=lambda door: 1 if door.blocked else 0) + available_doors.sort(key=lambda door: 1 if door.blocked else 2 if door.ugly else 0) door = available_doors.pop() logger.info('Linking %s', door.name) # Find an available region that has a compatible door @@ -184,13 +192,27 @@ def shuffle_dungeon(world, player, start_region_names, dungeon_region_names): logger.info(' Found new region %s via %s', connect_region.name, connect_door.name) # Apply connection and add the new region's doors to the available list maybe_connect_two_way(world, door, connect_door, player) - available_doors.extend(get_doors(world, connect_region, player)) + # Figure out the new room's ugliness region + new_room_ugly_region = ugly_regions[door.name] + if connect_door.ugly: + next_ugly_region += 1 + new_room_ugly_region = next_ugly_region + # Add the doors + for door in get_doors(world, connect_region, player): + ugly_regions[door.name] = new_room_ugly_region + available_doors.append(door) + # If an ugly door is anything but the connect door, panic and die + if door != connect_door and door.ugly: + logger.info('Failed because of ugly door, trying again.') + shuffle_dungeon(world, player, start_region_names, dungeon_region_names) + return + # We've used this region and door, so don't use them again available_regions.remove(connect_region) available_doors.remove(connect_door) else: # If there's no available region with a door, use an internal connection - connect_door = find_compatible_door_in_list(world, door, available_doors, player) + connect_door = find_compatible_door_in_list(ugly_regions, world, door, available_doors, player) # If we don't have a door at this point, it's time to panic and retry. if connect_door is None: logger.info('Failed because of blocked door, trying again.') @@ -233,8 +255,10 @@ def find_compatible_door_in_regions(world, door, regions, player): return region, proposed_door return None, None -def find_compatible_door_in_list(world, door, doors, player): +def find_compatible_door_in_list(ugly_regions, world, door, doors, player): for proposed_door in doors: + if ugly_regions[door.name] != ugly_regions[proposed_door.name]: + continue if doors_compatible(door, proposed_door): return proposed_door diff --git a/Doors.py b/Doors.py index 76a00c15..d6130398 100644 --- a/Doors.py +++ b/Doors.py @@ -112,10 +112,10 @@ def create_doors(world, player): create_small_key_door(player, 'Eastern Dark Square Key Door WN', DoorType.Normal, Direction.West, 0xba, Top, High), create_dir_door(player, 'Eastern Big Key EN', DoorType.Normal, Direction.East, 0xb8, Top, High), create_big_key_door(player, 'Eastern Big Key NE', DoorType.Normal, Direction.North, 0xb8, Right, High), - create_small_key_door(player, 'Eastern Darkness S', DoorType.Normal, Direction.South, 0x99, Mid, High), + ugly_door(create_small_key_door(player, 'Eastern Darkness S', DoorType.Normal, Direction.South, 0x99, Mid, High)), # TODO: Up is a keydoor and down is not. Are they both spiralkeys or what? create_spiral_stairs(player, 'Eastern Darkness Up Stairs', DoorType.SpiralStairs, Direction.Up, 0x99, 0, HTH, Z, 0x1a, 0x6c, False, True), - create_spiral_stairs(player, 'Eastern Attic Start Down Stairs', DoorType.SpiralStairs, Direction.Down, 0xda, 0, HTH, Z, 0x11, 0x80, False, True), + ugly_door(create_spiral_stairs(player, 'Eastern Attic Start Down Stairs', DoorType.SpiralStairs, Direction.Down, 0xda, 0, HTH, Z, 0x11, 0x80, False, True)), create_dir_door(player, 'Eastern Attic Start WS', DoorType.Normal, Direction.West, 0xda, Bot, High), create_dir_door(player, 'Eastern Attic Switches ES', DoorType.Normal, Direction.East, 0xd9, Bot, High), create_dir_door(player, 'Eastern Attic Switches WS', DoorType.Normal, Direction.West, 0xd9, Bot, High), @@ -169,3 +169,7 @@ def create_spiral_stairs(player, name, type, direction, room, d.zeroHzCam = zero_hz_cam d.zeroVtCam = zero_vt_cam return d + +def ugly_door(door): + door.ugly = True + return door