From f6e8584d19c58325a063627a301787bb17ef82b1 Mon Sep 17 00:00:00 2001 From: aerinon Date: Thu, 21 Nov 2019 14:04:29 -0700 Subject: [PATCH] Fixed Death Mountain Return Ledge dungeons Multiplayer support for inaccessible regions --- BaseClasses.py | 2 +- DoorShuffle.py | 55 +++++++++++++++++++++++++++++---------------- DungeonGenerator.py | 12 +++++----- 3 files changed, 43 insertions(+), 26 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index e897adfa..7a11c515 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -89,7 +89,7 @@ class World(object): self.rooms = [] self._room_cache = {} self.dungeon_layouts = {} - self.inaccessible_regions = [] + self.inaccessible_regions = {} self.key_logic = {} def intialize_regions(self): diff --git a/DoorShuffle.py b/DoorShuffle.py index 7ac30e07..3ccf1ff4 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -301,7 +301,7 @@ def within_dungeon(world, player): last_key = key else: ds = generate_dungeon(sector_list, origin_list, world, player) - find_new_entrances(ds, connections, potentials, enabled_entrances) + find_new_entrances(ds, connections, potentials, enabled_entrances, world, player) ds.name = key layout_starts = origin_list if len(entrance_list) <= 0 else entrance_list dungeon_layouts.append((ds, layout_starts)) @@ -333,7 +333,7 @@ def determine_entrance_list(world, player): for ent in region.entrances: parent = ent.parent_region if parent.type != RegionType.Dungeon or parent.name == 'Sewer Drop': - if parent.name not in world.inaccessible_regions: + if parent.name not in world.inaccessible_regions[player]: entrance_map[key].append(region_name) else: if ent.parent_region not in potential_entrances.keys(): @@ -361,10 +361,20 @@ def remove_drop_origins(entrance_list): return [x for x in entrance_list if x not in drop_entrances] -def find_new_entrances(sector, connections, potentials, enabled): +def find_new_entrances(sector, connections, potentials, enabled, world, player): for region in sector.regions: if region.name in connections.keys() and connections[region.name] in potentials.keys(): - enabled.extend(potentials.pop(connections[region.name])) + new_region = connections[region.name] + enabled.extend(potentials.pop(new_region)) + # see if this unexplored region connects elsewhere + queue = collections.deque(new_region.exits) + while len(queue) > 0: + ext = queue.popleft() + region_name = ext.connected_region.name + if region_name in connections.keys() and connections[region_name] in potentials.keys(): + enabled.extend(potentials.pop(connections[region_name])) + if ext.connected_region.name in world.inaccessible_regions[player]: + queue.extend(ext.connected_region.exits) def within_dungeon_legacy(world, player): @@ -781,8 +791,8 @@ def find_proposal(proposal, buckets, candidates): return proposal -def valid_region_to_explore(region, world): - return region.type == RegionType.Dungeon or region.name in world.inaccessible_regions +def valid_region_to_explore(region, world, player): + return region.type == RegionType.Dungeon or region.name in world.inaccessible_regions[player] def shuffle_key_doors(dungeon_sector, entrances, world, player): @@ -982,7 +992,7 @@ def validate_key_layout_r(state, key_layout, flat_proposal, world, player): exp_door = state.next_avail_door() door = exp_door.door connect_region = world.get_entrance(door.name, player).connected_region - if state.validate(door, connect_region, world): + if state.validate(door, connect_region, world, player): state.visit_region(connect_region, key_checks=True) state.add_all_doors_check_keys(connect_region, flat_proposal, world, player) smalls_avail = len(state.small_doors) > 0 @@ -1235,6 +1245,7 @@ def overworld_prep(world, player): # todo : multiplayer? def find_inaccessible_regions(world, player): + world.inaccessible_regions[player] = [] if world.mode != 'inverted': start_regions = ['Links House', 'Sanctuary'] else: @@ -1250,33 +1261,39 @@ def find_inaccessible_regions(world, player): connect = ext.connected_region if connect is not None and connect.type is not RegionType.Dungeon and connect not in queue and connect not in visited_regions: queue.append(connect) - world.inaccessible_regions.extend([r.name for r in all_regions.difference(visited_regions) if r.type is not RegionType.Cave]) + world.inaccessible_regions[player].extend([r.name for r in all_regions.difference(visited_regions) if r.type is not RegionType.Cave]) if world.mode == 'standard': - world.inaccessible_regions.append('Hyrule Castle Ledge') - world.inaccessible_regions.append('Sewer Drop') + world.inaccessible_regions[player].append('Hyrule Castle Ledge') + world.inaccessible_regions[player].append('Sewer Drop') logger = logging.getLogger('') logger.info('Inaccessible Regions:') - for r in world.inaccessible_regions: + for r in world.inaccessible_regions[player]: logger.info('%s', r) def add_inaccessible_doors(world, player): - if 'Skull Woods Forest (West)' in world.inaccessible_regions: + if 'Skull Woods Forest (West)' in world.inaccessible_regions[player]: create_door(world, player, 'Skull Woods Second Section Door (West)', 'Skull Woods Forest (West)') create_door(world, player, 'Skull Woods Second Section Hole', 'Skull Woods Forest (West)') create_door(world, player, 'Skull Woods Final Section', 'Skull Woods Forest (West)') - if 'Dark Death Mountain Ledge' in world.inaccessible_regions: + if 'Dark Death Mountain Ledge' in world.inaccessible_regions[player]: create_door(world, player, 'Dark Death Mountain Ledge (East)', 'Dark Death Mountain Ledge') create_door(world, player, 'Dark Death Mountain Ledge (West)', 'Dark Death Mountain Ledge') create_door(world, player, 'Mimic Cave Mirror Spot', 'Dark Death Mountain Ledge') - if 'Mimic Cave Ledge' in world.inaccessible_regions: + if 'Mimic Cave Ledge' in world.inaccessible_regions[player]: create_door(world, player, 'Mimic Cave', 'Mimic Cave Ledge') - if 'Dark Death Mountain Isolated Ledge' in world.inaccessible_regions: + if 'Dark Death Mountain Isolated Ledge' in world.inaccessible_regions[player]: create_door(world, player, 'Turtle Rock Isolated Ledge Entrance', 'Dark Death Mountain Isolated Ledge') - if 'Death Mountain Floating Island (Dark World)' in world.inaccessible_regions: + if 'Death Mountain Floating Island (Dark World)' in world.inaccessible_regions[player]: create_door(world, player, 'Hookshot Cave Back Entrance', 'Death Mountain Floating Island (Dark World)') - # todo: desert palace lone stairs - if world.mode == 'standard' and 'Hyrule Castle Ledge' in world.inaccessible_regions: + if 'Bumper Cave Ledge' in world.inaccessible_regions[player]: + create_door(world, player, 'Bumper Cave (Top)', 'Bumper Cave Ledge') + create_door(world, player, 'Bumper Cave Ledge Mirror Spot', 'Bumper Cave Ledge') + if 'Death Mountain Return Ledge' in world.inaccessible_regions[player]: + create_door(world, player, 'Death Mountain Return Cave (West)', 'Death Mountain Return Ledge') + if 'Desert Palace Lone Stairs' in world.inaccessible_regions[player]: + create_door(world, player, 'Desert Palace Entrance (East)', 'Desert Palace Lone Stairs') + if world.mode == 'standard' and 'Hyrule Castle Ledge' in world.inaccessible_regions[player]: create_door(world, player, 'Hyrule Castle Entrance (East)', 'Hyrule Castle Ledge') create_door(world, player, 'Hyrule Castle Entrance (West)', 'Hyrule Castle Ledge') @@ -1349,7 +1366,7 @@ def explore_state(state, world, player): while len(state.avail_doors) > 0: door = state.next_avail_door().door connect_region = world.get_entrance(door.name, player).connected_region - if state.can_traverse(door) and not state.visited(connect_region) and valid_region_to_explore(connect_region, world): + if state.can_traverse(door) and not state.visited(connect_region) and valid_region_to_explore(connect_region, world, player): state.visit_region(connect_region) state.add_all_doors_check_unattached(connect_region, world, player) diff --git a/DungeonGenerator.py b/DungeonGenerator.py index e1cbd778..e76eb78b 100644 --- a/DungeonGenerator.py +++ b/DungeonGenerator.py @@ -679,8 +679,8 @@ class ExplorationState(object): return not isOrigin or not door.bigKey or len(self.found_locations) > 0 # return not door.bigKey or len([x for x in self.found_locations if '- Prize' not in x.name]) > 0 - def validate(self, door, region, world): - return self.can_traverse(door) and not self.visited(region) and valid_region_to_explore(region, world) + def validate(self, door, region, world, player): + return self.can_traverse(door) and not self.visited(region) and valid_region_to_explore(region, world, player) def in_door_list(self, door, door_list): for d in door_list: @@ -739,7 +739,7 @@ def extend_reachable_state(search_regions, state, world, player): 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): + if valid_region_to_explore(connect_region, world, player) 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 @@ -757,15 +757,15 @@ def extend_reachable_state_improved(search_regions, state, proposed_map, valid_d 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): + if valid_region_to_explore(connect_region, world, player) 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, isOrigin, world, player) return local_state # cross-utility methods -def valid_region_to_explore(region, world): - return region is not None and (region.type == RegionType.Dungeon or region.name in world.inaccessible_regions) +def valid_region_to_explore(region, world, player): + return region is not None and (region.type == RegionType.Dungeon or region.name in world.inaccessible_regions[player]) def get_doors(world, region, player):