A lot of generation improvements and bug squashing
This commit is contained in:
@@ -1225,15 +1225,15 @@ def simple_dungeon_builder(name, sector_list):
|
||||
def create_dungeon_builders(all_sectors, connections_tuple, world, player,
|
||||
dungeon_entrances=None, split_dungeon_entrances=None):
|
||||
logger = logging.getLogger('')
|
||||
logger.info('Shuffling Dungeon Sectors')
|
||||
|
||||
if dungeon_entrances is None:
|
||||
dungeon_entrances = default_dungeon_entrances
|
||||
if split_dungeon_entrances is None:
|
||||
split_dungeon_entrances = split_region_starts
|
||||
define_sector_features(all_sectors)
|
||||
finished, dungeon_map = False, {}
|
||||
finished, dungeon_map, attempts = False, {}, 0
|
||||
while not finished:
|
||||
logger.info('Shuffling Dungeon Sectors')
|
||||
candidate_sectors = dict.fromkeys(all_sectors)
|
||||
global_pole = GlobalPolarity(candidate_sectors)
|
||||
|
||||
@@ -1248,6 +1248,7 @@ def create_dungeon_builders(all_sectors, connections_tuple, world, player,
|
||||
for r_name in ['Hyrule Dungeon Cellblock', 'Sanctuary']: # need to deliver zelda
|
||||
assign_sector(find_sector(r_name, candidate_sectors), current_dungeon,
|
||||
candidate_sectors, global_pole)
|
||||
standard_stair_check(dungeon_map, current_dungeon, candidate_sectors, global_pole)
|
||||
entrances_map, potentials, connections = connections_tuple
|
||||
accessible_sectors, reverse_d_map = set(), {}
|
||||
for key in dungeon_entrances.keys():
|
||||
@@ -1324,11 +1325,27 @@ def create_dungeon_builders(all_sectors, connections_tuple, world, player,
|
||||
assign_the_rest(dungeon_map, neutral_sectors, global_pole, builder_info)
|
||||
dungeon_map.update(complete_dungeons)
|
||||
finished = True
|
||||
except NeutralizingException:
|
||||
pass
|
||||
except (NeutralizingException, GenerationException) as e:
|
||||
attempts += 1
|
||||
logger.debug(f'Attempt {attempts} failed with {str(e)}')
|
||||
if attempts >= 10:
|
||||
raise Exception('Could not find a valid seed quickly, something is likely horribly wrong.', e)
|
||||
return dungeon_map
|
||||
|
||||
|
||||
def standard_stair_check(dungeon_map, dungeon, candidate_sectors, global_pole):
|
||||
# this is because there must be at least one non-dead stairway in hc to get out
|
||||
# this check may not be necessary
|
||||
filtered_sectors = [x for x in candidate_sectors if any(y for y in x.outstanding_doors if not y.dead and y.type == DoorType.SpiralStairs)]
|
||||
valid = False
|
||||
while not valid:
|
||||
chosen_sector = random.choice(filtered_sectors)
|
||||
filtered_sectors.remove(chosen_sector)
|
||||
valid = global_pole.is_valid_choice(dungeon_map, dungeon, [chosen_sector])
|
||||
if valid:
|
||||
assign_sector(chosen_sector, dungeon, candidate_sectors, global_pole)
|
||||
|
||||
|
||||
def identify_destination_sectors(accessible_sectors, reverse_d_map, dungeon_map, connections, dungeon_entrances, split_dungeon_entrances):
|
||||
accessible_overworld, found_connections, explored = set(), set(), False
|
||||
|
||||
@@ -1578,6 +1595,8 @@ def assign_crystal_switch_sectors(dungeon_map, crystal_switches, crystal_barrier
|
||||
if len(crystal_switches) == 0:
|
||||
raise GenerationException('No crystal switches to assign')
|
||||
sector_list = list(crystal_switches)
|
||||
if len(population) > len(sector_list):
|
||||
raise GenerationException('Not enough crystal switch sectors for those needed')
|
||||
choices = random.sample(sector_list, k=len(population))
|
||||
for i, choice in enumerate(choices):
|
||||
builder = dungeon_map[population[i]]
|
||||
@@ -1588,7 +1607,7 @@ def assign_crystal_switch_sectors(dungeon_map, crystal_switches, crystal_barrier
|
||||
def ensure_crystal_switches_reachable(dungeon_map, crystal_switches, polarized_sectors, crystal_barriers, global_pole):
|
||||
invalid_builders = []
|
||||
for name, builder in dungeon_map.items():
|
||||
if builder.c_switch_present and not builder.c_locked:
|
||||
if builder.c_switch_present and builder.c_switch_required and not builder.c_locked:
|
||||
invalid_builders.append(builder)
|
||||
while len(invalid_builders) > 0:
|
||||
valid_builders = []
|
||||
@@ -1597,7 +1616,7 @@ def ensure_crystal_switches_reachable(dungeon_map, crystal_switches, polarized_s
|
||||
reachable_crystals = defaultdict()
|
||||
for sector in builder.sectors:
|
||||
if sector.equations is None:
|
||||
sector.equations = calc_sector_equations(sector, builder)
|
||||
sector.equations = calc_sector_equations(sector)
|
||||
if sector.is_entrance_sector() and not sector.destination_entrance:
|
||||
need_switch = True
|
||||
for region in sector.get_start_regions():
|
||||
@@ -1631,7 +1650,7 @@ def ensure_crystal_switches_reachable(dungeon_map, crystal_switches, polarized_s
|
||||
valid, sector, which_list = False, None, None
|
||||
while not valid:
|
||||
if len(candidates) <= 0:
|
||||
raise GenerationException(f'need to provide more sophisticatedted crystal connection for {entrance_sector}')
|
||||
raise GenerationException(f'need to provide more sophisticated crystal connection for {entrance_sector}')
|
||||
sector, which_list = random.choice(list(candidates.items()))
|
||||
del candidates[sector]
|
||||
valid = global_pole.is_valid_choice(dungeon_map, builder, [sector])
|
||||
@@ -1690,7 +1709,7 @@ def find_pol_cand_for_c_switch(access, reachable_crystals, polarized_candidates)
|
||||
|
||||
def pol_cand_matches_access_reach(sector, access, reachable_crystals):
|
||||
if sector.equations is None:
|
||||
sector.equations = calc_sector_equations(sector, None)
|
||||
sector.equations = calc_sector_equations(sector)
|
||||
for eq in sector.equations:
|
||||
key, cost_door = eq.cost
|
||||
if key in access.keys() and access[key]:
|
||||
@@ -1712,7 +1731,7 @@ def find_crystal_cand(access, crystal_switches):
|
||||
|
||||
def crystal_cand_matches_access(sector, access):
|
||||
if sector.equations is None:
|
||||
sector.equations = calc_sector_equations(sector, None)
|
||||
sector.equations = calc_sector_equations(sector)
|
||||
for eq in sector.equations:
|
||||
key, cost_door = eq.cost
|
||||
if key in access.keys() and access[key] and eq.c_switch and len(sector.outstanding_doors) > 1:
|
||||
@@ -1984,6 +2003,9 @@ def polarity_step_3(dungeon_map, polarized_sectors, global_pole):
|
||||
sample_target = 100 if combos > 10 else combos * 2
|
||||
while best_choices is None or samples < sample_target:
|
||||
samples += 1
|
||||
if len(odd_candidates) < len(odd_builders):
|
||||
raise GenerationException(f'Unable to fix dungeon parity - not enough candidates.'
|
||||
f' Ref: {next(iter(odd_builders)).name}')
|
||||
choices = random.sample(odd_candidates, k=len(odd_builders))
|
||||
valid = global_pole.is_valid_multi_choice(dungeon_map, odd_builders, choices)
|
||||
charge = calc_total_charge(dungeon_map, odd_builders, choices)
|
||||
@@ -3649,14 +3671,14 @@ def copy_door_equations(builder, sector_list):
|
||||
for sector in builder.sectors + sector_list:
|
||||
if sector.equations is None:
|
||||
# todo: sort equations?
|
||||
sector.equations = calc_sector_equations(sector, builder)
|
||||
sector.equations = calc_sector_equations(sector)
|
||||
curr_list = equations[sector] = []
|
||||
for equation in sector.equations:
|
||||
curr_list.append(equation.copy())
|
||||
return equations
|
||||
|
||||
|
||||
def calc_sector_equations(sector, builder):
|
||||
def calc_sector_equations(sector):
|
||||
equations = []
|
||||
is_entrance = sector.is_entrance_sector() and not sector.destination_entrance
|
||||
if is_entrance:
|
||||
@@ -3686,6 +3708,8 @@ def calc_door_equation(door, sector, look_for_entrance):
|
||||
eq.benefit[hook_from_door(door)].append(door)
|
||||
eq.required = True
|
||||
eq.c_switch = door.crystal == CrystalBarrier.Either
|
||||
# exceptions for long entrances ???
|
||||
# if door.name in ['PoD Dark Alley']:
|
||||
eq.entrance_flag = True
|
||||
return eq, flag
|
||||
eq = DoorEquation(door)
|
||||
|
||||
Reference in New Issue
Block a user