Handle multiple startpoints and some blocked doors

Better blocked door handling:
- Start dungeon layout at the entrance
- Hold off on linking from blocked doors until the end of the dungeon, so they either point deeper in, or get added as a loop.
- Now that we care what the start is, properly handle the fact that dungeons have multiple starts.
This commit is contained in:
tolmar
2019-09-15 21:14:51 -07:00
parent 6ac00c2968
commit 9fa26ef067

View File

@@ -156,26 +156,31 @@ def shuffle_dungeon(world, player, start_region_names, dungeon_region_names):
logger = logging.getLogger('') logger = logging.getLogger('')
# Part one - generate a random layout # Part one - generate a random layout
available_regions = [] available_regions = []
for name in dungeon_region_names: for name in [r for r in dungeon_region_names if r not in start_region_names]:
available_regions.append(world.get_region(name, player)) available_regions.append(world.get_region(name, player))
random.shuffle(available_regions) random.shuffle(available_regions)
# Pick a random region and make its doors the open set # Add all start regions to the open set.
available_doors = [] available_doors = []
region = available_regions.pop() for name in start_region_names:
logger.info("Starting in %s", region.name) logger.info("Starting in %s", name)
available_doors.extend(get_doors(world, region, player)) available_doors.extend(get_doors(world, world.get_region(name, player), player))
# Loop until all available doors are used # Loop until all available doors are used
while len(available_doors) > 0: while len(available_doors) > 0:
# Pick a random available door to connect # Pick a random available door to connect, prioritizing ones that aren't blocked.
# TODO: Is there an existing "remove random from list" in this codebase? # This makes them either get picked up through another door (so they head deeper
# into the dungeon), or puts them late in the dungeon (so they probably are part
# of a loop). Panic if neither of these happens.
random.shuffle(available_doors) random.shuffle(available_doors)
available_doors.sort(key=lambda door: 1 if door.blocked else 0)
door = available_doors.pop() door = available_doors.pop()
logger.info('Linking %s', door.name) logger.info('Linking %s', door.name)
# Find an available region that has a compatible door # Find an available region that has a compatible door
connect_region, connect_door = find_compatible_door_in_regions(world, door, available_regions, player) connect_region, connect_door = find_compatible_door_in_regions(world, door, available_regions, player)
if connect_region is not None: # Also ignore compatible doors if they're blocked; these should only be used to
# create loops.
if connect_region is not None and not door.blocked:
logger.info(' Found new region %s via %s', connect_region.name, connect_door.name) logger.info(' Found new region %s via %s', connect_region.name, connect_door.name)
# Apply connection and add the new region's doors to the available list # Apply connection and add the new region's doors to the available list
maybe_connect_two_way(world, door, connect_door, player) maybe_connect_two_way(world, door, connect_door, player)
@@ -186,6 +191,11 @@ def shuffle_dungeon(world, player, start_region_names, dungeon_region_names):
else: else:
# If there's no available region with a door, use an internal connection # 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(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.')
shuffle_dungeon(world, player, start_region_names, dungeon_region_names)
return
logger.info(' Adding loop via %s', connect_door.name) logger.info(' Adding loop via %s', connect_door.name)
maybe_connect_two_way(world, door, connect_door, player) maybe_connect_two_way(world, door, connect_door, player)
available_doors.remove(connect_door) available_doors.remove(connect_door)