feat: skull woods er options
This commit is contained in:
@@ -23,6 +23,7 @@ class EntrancePool(object):
|
||||
self.decoupled_exits = []
|
||||
self.original_entrances = set()
|
||||
self.original_exits = set()
|
||||
self.same_world_restricted = {}
|
||||
|
||||
self.world = world
|
||||
self.player = player
|
||||
@@ -90,6 +91,10 @@ def link_entrances_new(world, player):
|
||||
if mode not in modes:
|
||||
raise RuntimeError(f'Shuffle mode {mode} is not yet supported')
|
||||
mode_cfg = copy.deepcopy(modes[mode])
|
||||
|
||||
if world.linked_drops[player] != 'unset':
|
||||
mode_cfg['keep_drops_together'] = 'on' if world.linked_drops[player] == 'linked' else 'off'
|
||||
|
||||
avail_pool.swapped = mode_cfg['undefined'] == 'swap'
|
||||
if avail_pool.is_standard():
|
||||
do_standard_connections(avail_pool)
|
||||
@@ -97,11 +102,7 @@ def link_entrances_new(world, player):
|
||||
for pool_name, pool in pool_list.items():
|
||||
special_shuffle = pool['special'] if 'special' in pool else None
|
||||
if special_shuffle == 'drops':
|
||||
holes, targets = find_entrances_and_targets_drops(avail_pool, pool['entrances'])
|
||||
if avail_pool.swapped:
|
||||
connect_swapped(holes, targets, avail_pool)
|
||||
else:
|
||||
connect_random(holes, targets, avail_pool)
|
||||
handle_skull_woods_drops(avail_pool, pool['entrances'], mode_cfg)
|
||||
elif special_shuffle == 'fixed_shuffle':
|
||||
do_fixed_shuffle(avail_pool, pool['entrances'])
|
||||
elif special_shuffle == 'same_world':
|
||||
@@ -124,12 +125,7 @@ def link_entrances_new(world, player):
|
||||
elif special_shuffle == 'vanilla':
|
||||
do_vanilla_connect(pool, avail_pool)
|
||||
elif special_shuffle == 'skull':
|
||||
entrances, exits = find_entrances_and_exits(avail_pool, pool['entrances'])
|
||||
if avail_pool.swapped:
|
||||
connect_swapped(entrances, exits, avail_pool, True)
|
||||
else:
|
||||
connect_random(entrances, exits, avail_pool, True)
|
||||
avail_pool.skull_handled = True
|
||||
handle_skull_woods_entrances(avail_pool, pool['entrances'])
|
||||
else:
|
||||
entrances, exits = find_entrances_and_exits(avail_pool, pool['entrances'])
|
||||
do_main_shuffle(entrances, exits, avail_pool, mode_cfg)
|
||||
@@ -239,12 +235,13 @@ def do_main_shuffle(entrances, exits, avail, mode_def):
|
||||
# mandatory exits
|
||||
rem_entrances, rem_exits = set(), set()
|
||||
if not cross_world:
|
||||
determine_dungeon_restrictions(avail)
|
||||
mand_exits = figure_out_must_exits_same_world(entrances, exits, avail)
|
||||
must_exit_lw, must_exit_dw, lw_entrances, dw_entrances, multi_exit_caves, hyrule_forced = mand_exits
|
||||
if hyrule_forced:
|
||||
do_mandatory_connections(avail, lw_entrances, hyrule_forced, must_exit_lw)
|
||||
else:
|
||||
do_mandatory_connections(avail, lw_entrances, multi_exit_caves, must_exit_lw)
|
||||
must_exit_lw, must_exit_dw, lw_entrances, dw_entrances, multi_exit_caves = mand_exits
|
||||
lw_candidates = filter_restricted_caves(multi_exit_caves, 'LightWorld', avail)
|
||||
other_candidates = [x for x in multi_exit_caves if x not in lw_candidates] # remember those not passed in
|
||||
do_mandatory_connections(avail, lw_entrances, lw_candidates, must_exit_lw)
|
||||
multi_exit_caves = other_candidates + lw_candidates # rebuild list from the lw_candidates and those not passed
|
||||
# remove old man house as connector - not valid for dw must_exit if it is a spawn point
|
||||
if not avail.inverted:
|
||||
new_mec = []
|
||||
@@ -254,7 +251,10 @@ def do_main_shuffle(entrances, exits, avail, mode_def):
|
||||
else:
|
||||
new_mec.append(cave_option)
|
||||
multi_exit_caves = new_mec
|
||||
do_mandatory_connections(avail, dw_entrances, multi_exit_caves, must_exit_dw)
|
||||
dw_candidates = filter_restricted_caves(multi_exit_caves, 'DarkWorld', avail)
|
||||
other_candidates = [x for x in multi_exit_caves if x not in dw_candidates] # remember those not passed in
|
||||
do_mandatory_connections(avail, dw_entrances, dw_candidates, must_exit_dw)
|
||||
multi_exit_caves = other_candidates + dw_candidates # rebuild list from the dw_candidates and those not passed
|
||||
rem_entrances.update(lw_entrances)
|
||||
rem_entrances.update(dw_entrances)
|
||||
else:
|
||||
@@ -351,6 +351,10 @@ def do_main_shuffle(entrances, exits, avail, mode_def):
|
||||
if bonk_fairy_exception(x):
|
||||
lw_entrances.append(x) if x in LW_Entrances else dw_entrances.append(x)
|
||||
do_same_world_connectors(lw_entrances, dw_entrances, multi_exit_caves, avail)
|
||||
if avail.world.doorShuffle[avail.player] != 'vanilla':
|
||||
determine_dungeon_restrictions(avail)
|
||||
possibles = figure_out_possible_exits(rem_exits)
|
||||
do_same_world_possible_connectors(lw_entrances, dw_entrances, possibles, avail)
|
||||
unused_entrances.update(lw_entrances)
|
||||
unused_entrances.update(dw_entrances)
|
||||
else:
|
||||
@@ -436,12 +440,16 @@ def do_holes_and_linked_drops(entrances, exits, avail, cross_world, keep_togethe
|
||||
|
||||
if not keep_together:
|
||||
targets = [avail.one_way_map[x] for x in holes_to_shuffle]
|
||||
connect_random(holes_to_shuffle, targets, avail)
|
||||
if avail.swapped:
|
||||
connect_swapped(holes_to_shuffle, targets, avail)
|
||||
else:
|
||||
connect_random(holes_to_shuffle, targets, avail)
|
||||
remove_from_list(entrances, holes_to_shuffle)
|
||||
remove_from_list(exits, targets)
|
||||
return # we're done here
|
||||
|
||||
hole_entrances, hole_targets = [], []
|
||||
leftover_hole_entrances, leftover_hole_targets = [], []
|
||||
for hole in drop_map:
|
||||
if hole in avail.original_entrances and hole in linked_drop_map:
|
||||
linked_entrance = linked_drop_map[hole]
|
||||
@@ -451,40 +459,39 @@ def do_holes_and_linked_drops(entrances, exits, avail, cross_world, keep_togethe
|
||||
target_drop = avail.one_way_map[hole]
|
||||
if target_exit in exits and target_drop in exits:
|
||||
hole_targets.append((target_exit, target_drop))
|
||||
else:
|
||||
if hole in avail.original_entrances and hole in entrances:
|
||||
leftover_hole_entrances.append(hole)
|
||||
if drop_map[hole] in exits:
|
||||
leftover_hole_targets.append(drop_map[hole])
|
||||
|
||||
random.shuffle(hole_entrances)
|
||||
if not cross_world and 'Sanctuary Grave' in holes_to_shuffle:
|
||||
hc = avail.world.get_entrance('Hyrule Castle Exit (South)', avail.player)
|
||||
is_hc_in_dw = avail.world.mode[avail.player] == 'inverted'
|
||||
if hc.connected_region:
|
||||
is_hc_in_dw = hc.connected_region.type == RegionType.DarkWorld
|
||||
chosen_entrance = None
|
||||
if is_hc_in_dw:
|
||||
if avail.swapped:
|
||||
chosen_entrance = next(e for e in hole_entrances if e[0] in DW_Entrances and e[0] != 'Sanctuary')
|
||||
if not cross_world:
|
||||
if 'Sanctuary Grave' in holes_to_shuffle:
|
||||
hc = avail.world.get_entrance('Hyrule Castle Exit (South)', avail.player)
|
||||
is_hc_in_dw = avail.world.mode[avail.player] == 'inverted'
|
||||
if hc.connected_region:
|
||||
is_hc_in_dw = hc.connected_region.type == RegionType.DarkWorld
|
||||
chosen_entrance = None
|
||||
if is_hc_in_dw:
|
||||
if avail.swapped:
|
||||
chosen_entrance = next(e for e in hole_entrances if e[0] in DW_Entrances and e[0] != 'Sanctuary')
|
||||
if not chosen_entrance:
|
||||
chosen_entrance = next(e for e in hole_entrances if e[0] in DW_Entrances)
|
||||
if not chosen_entrance:
|
||||
chosen_entrance = next(e for e in hole_entrances if e[0] in DW_Entrances)
|
||||
if not chosen_entrance:
|
||||
if avail.swapped:
|
||||
chosen_entrance = next(e for e in hole_entrances if e[0] in LW_Entrances and e[0] != 'Sanctuary')
|
||||
if not chosen_entrance:
|
||||
chosen_entrance = next(e for e in hole_entrances if e[0] in LW_Entrances)
|
||||
if avail.swapped:
|
||||
chosen_entrance = next(e for e in hole_entrances if e[0] in LW_Entrances and e[0] != 'Sanctuary')
|
||||
if not chosen_entrance:
|
||||
chosen_entrance = next(e for e in hole_entrances if e[0] in LW_Entrances)
|
||||
|
||||
if chosen_entrance:
|
||||
hole_entrances.remove(chosen_entrance)
|
||||
sanc_interior = next(target for target in hole_targets if target[0] == 'Sanctuary Exit')
|
||||
hole_targets.remove(sanc_interior)
|
||||
connect_two_way(chosen_entrance[0], sanc_interior[0], avail) # two-way exit
|
||||
connect_entrance(chosen_entrance[1], sanc_interior[1], avail) # hole
|
||||
remove_from_list(entrances, [chosen_entrance[0], chosen_entrance[1]])
|
||||
remove_from_list(exits, [sanc_interior[0], sanc_interior[1]])
|
||||
if avail.swapped and drop_map[chosen_entrance[1]] != sanc_interior[1]:
|
||||
swap_ent, swap_ext = connect_swap(chosen_entrance[0], sanc_interior[0], avail)
|
||||
swap_drop, swap_tgt = connect_swap(chosen_entrance[1], sanc_interior[1], avail)
|
||||
hole_entrances.remove((swap_ent, swap_drop))
|
||||
hole_targets.remove((swap_ext, swap_tgt))
|
||||
remove_from_list(entrances, [swap_ent, swap_drop])
|
||||
remove_from_list(exits, [swap_ext, swap_tgt])
|
||||
if chosen_entrance:
|
||||
connect_hole_via_interior(chosen_entrance, 'Sanctuary Exit', hole_entrances, hole_targets, entrances, exits, avail)
|
||||
if 'Skull Woods First Section Hole (North)' in holes_to_shuffle:
|
||||
chosen_entrance = next(e for e in hole_entrances if e[0] in DW_Entrances)
|
||||
connect_hole_via_interior(chosen_entrance, 'Skull Woods First Section Exit', hole_entrances, hole_targets, entrances, exits, avail)
|
||||
if 'Skull Woods Second Section Hole' in holes_to_shuffle:
|
||||
chosen_entrance = next(e for e in hole_entrances if e[0] in DW_Entrances)
|
||||
connect_hole_via_interior(chosen_entrance, 'Skull Woods Second Section Exit (East)', hole_entrances, hole_targets, entrances, exits, avail)
|
||||
|
||||
random.shuffle(hole_targets)
|
||||
while len(hole_entrances):
|
||||
@@ -506,6 +513,31 @@ def do_holes_and_linked_drops(entrances, exits, avail, cross_world, keep_togethe
|
||||
remove_from_list(entrances, [swap_ent, swap_drop])
|
||||
remove_from_list(exits, [swap_ext, swap_tgt])
|
||||
|
||||
if leftover_hole_entrances and leftover_hole_targets:
|
||||
remove_from_list(entrances, leftover_hole_entrances)
|
||||
remove_from_list(exits, leftover_hole_targets)
|
||||
if avail.swapped:
|
||||
connect_swapped(leftover_hole_entrances, leftover_hole_targets, avail)
|
||||
else:
|
||||
connect_random(leftover_hole_entrances, leftover_hole_targets, avail)
|
||||
|
||||
|
||||
def connect_hole_via_interior(chosen_entrance, interior, hole_entrances, hole_targets, entrances, exits, avail):
|
||||
hole_entrances.remove(chosen_entrance)
|
||||
interior = next(target for target in hole_targets if target[0] == interior)
|
||||
hole_targets.remove(interior)
|
||||
connect_two_way(chosen_entrance[0], interior[0], avail)
|
||||
connect_entrance(chosen_entrance[1], interior[1], avail)
|
||||
remove_from_list(entrances, [chosen_entrance[0], chosen_entrance[1]])
|
||||
remove_from_list(exits, [interior[0], interior[1]])
|
||||
if avail.swapped and drop_map[chosen_entrance[1]] != interior[1]:
|
||||
swap_ent, swap_ext = connect_swap(chosen_entrance[0], interior[0], avail)
|
||||
swap_drop, swap_tgt = connect_swap(chosen_entrance[1], interior[1], avail)
|
||||
hole_entrances.remove((swap_ent, swap_drop))
|
||||
hole_targets.remove((swap_ext, swap_tgt))
|
||||
remove_from_list(entrances, [swap_ent, swap_drop])
|
||||
remove_from_list(exits, [swap_ext, swap_tgt])
|
||||
|
||||
|
||||
def do_links_house(entrances, exits, avail, cross_world):
|
||||
lh_exit = 'Links House Exit'
|
||||
@@ -628,38 +660,77 @@ def figure_out_true_exits(exits, avail):
|
||||
return multi_exit_caves
|
||||
|
||||
|
||||
# todo: figure out hyrule forced better
|
||||
def figure_out_possible_exits(exits):
|
||||
possible_multi_exit_caves = []
|
||||
for item in doors_possible_connectors:
|
||||
if item in exits:
|
||||
remove_from_list(exits, item)
|
||||
possible_multi_exit_caves.append(item)
|
||||
return possible_multi_exit_caves
|
||||
|
||||
|
||||
def determine_dungeon_restrictions(avail):
|
||||
check_for_hc = (avail.is_standard() or avail.world.doorShuffle[avail.player] != 'vanilla')
|
||||
for check in dungeon_restriction_checks:
|
||||
dungeon_exits, drop_regions = check
|
||||
if check_for_hc and any('Hyrule Castle' in x for x in dungeon_exits):
|
||||
avail.same_world_restricted.update({x: 'LightWorld' for x in dungeon_exits})
|
||||
else:
|
||||
restriction = None
|
||||
for x in dungeon_exits:
|
||||
ent = avail.world.get_entrance(x, avail.player)
|
||||
if ent.connected_region:
|
||||
if ent.connected_region.type == RegionType.LightWorld:
|
||||
restriction = 'LightWorld'
|
||||
elif ent.connected_region.type == RegionType.DarkWorld:
|
||||
restriction = 'DarkWorld'
|
||||
# Holes only restrict
|
||||
for x in drop_regions:
|
||||
region = avail.world.get_region(x, avail.player)
|
||||
ent = next((ent for ent in region.entrances if ent.parent_region and ent.parent_region.type in [RegionType.LightWorld, RegionType.DarkWorld]), None)
|
||||
if ent:
|
||||
if ent.parent_region.type == RegionType.LightWorld and not avail.inverted:
|
||||
restriction = 'LightWorld'
|
||||
elif ent.parent_region.type == RegionType.DarkWorld and avail.inverted:
|
||||
restriction = 'DarkWorld'
|
||||
if restriction:
|
||||
avail.same_world_restricted.update({x: restriction for x in dungeon_exits})
|
||||
|
||||
|
||||
def figure_out_must_exits_same_world(entrances, exits, avail):
|
||||
lw_entrances, dw_entrances = [], []
|
||||
hyrule_forced = None
|
||||
check_for_hc = (avail.is_standard() or avail.world.doorShuffle[avail.player] != 'vanilla')
|
||||
|
||||
for x in entrances:
|
||||
lw_entrances.append(x) if x in LW_Entrances else dw_entrances.append(x)
|
||||
|
||||
multi_exit_caves = figure_out_connectors(exits)
|
||||
if check_for_hc:
|
||||
for option in multi_exit_caves:
|
||||
if any(x in option for x in ['Hyrule Castle Exit (South)', 'Hyrule Castle Exit (East)',
|
||||
'Hyrule Castle Exit (West)']):
|
||||
hyrule_forced = [option]
|
||||
if hyrule_forced:
|
||||
remove_from_list(multi_exit_caves, hyrule_forced)
|
||||
if not avail.inverted and not avail.skull_handled:
|
||||
skull_connector = [x for x in ['Skull Woods Second Section Exit (West)', 'Skull Woods Second Section Exit (East)'] if x in exits]
|
||||
multi_exit_caves.append(skull_connector)
|
||||
|
||||
must_exit_lw, must_exit_dw, unfiltered_lw, unfiltered_dw = must_exits_helper(avail, lw_entrances, dw_entrances)
|
||||
|
||||
return must_exit_lw, must_exit_dw, lw_entrances, dw_entrances, multi_exit_caves, hyrule_forced
|
||||
return must_exit_lw, must_exit_dw, lw_entrances, dw_entrances, multi_exit_caves
|
||||
|
||||
|
||||
def must_exits_helper(avail, lw_entrances, dw_entrances):
|
||||
must_exit_lw_orig = (Inverted_LW_Must_Exit if avail.inverted else LW_Must_Exit).copy()
|
||||
must_exit_dw_orig = (Inverted_DW_Must_Exit if avail.inverted else DW_Must_Exit).copy()
|
||||
if not avail.inverted and not avail.skull_handled:
|
||||
must_exit_dw_orig.append(('Skull Woods Second Section Door (West)', 'Skull Woods Final Section'))
|
||||
must_exit_dw_orig.append('Skull Woods Second Section Door (West)')
|
||||
must_exit_lw = must_exit_filter(avail, must_exit_lw_orig, lw_entrances)
|
||||
must_exit_dw = must_exit_filter(avail, must_exit_dw_orig, dw_entrances)
|
||||
return must_exit_lw, must_exit_dw, flatten(must_exit_lw_orig), flatten(must_exit_dw_orig)
|
||||
|
||||
|
||||
def filter_restricted_caves(multi_exit_caves, restriction, avail):
|
||||
candidates = []
|
||||
for cave in multi_exit_caves:
|
||||
if all(x not in avail.same_world_restricted or avail.same_world_restricted[x] == restriction for x in cave):
|
||||
candidates.append(cave)
|
||||
return candidates
|
||||
|
||||
|
||||
def flatten(list_to_flatten):
|
||||
ret = []
|
||||
for item in list_to_flatten:
|
||||
@@ -672,11 +743,14 @@ def flatten(list_to_flatten):
|
||||
|
||||
def figure_out_must_exits_cross_world(entrances, exits, avail):
|
||||
multi_exit_caves = figure_out_connectors(exits)
|
||||
if not avail.skull_handled:
|
||||
skull_connector = [x for x in ['Skull Woods Second Section Exit (West)', 'Skull Woods Second Section Exit (East)'] if x in exits]
|
||||
multi_exit_caves.append(skull_connector)
|
||||
|
||||
must_exit_lw = (Inverted_LW_Must_Exit if avail.inverted else LW_Must_Exit).copy()
|
||||
must_exit_dw = (Inverted_DW_Must_Exit if avail.inverted else DW_Must_Exit).copy()
|
||||
if not avail.inverted and not avail.skull_handled:
|
||||
must_exit_dw.append(('Skull Woods Second Section Door (West)', 'Skull Woods Final Section'))
|
||||
must_exit_dw.append('Skull Woods Second Section Door (West)')
|
||||
must_exit = must_exit_filter(avail, must_exit_lw + must_exit_dw, entrances)
|
||||
|
||||
return must_exit, multi_exit_caves
|
||||
@@ -687,7 +761,7 @@ def do_same_world_connectors(lw_entrances, dw_entrances, caves, avail):
|
||||
random.shuffle(dw_entrances)
|
||||
random.shuffle(caves)
|
||||
while caves:
|
||||
# connect highest exit count caves first, prevent issue where we have 2 or 3 exits across worlds left to fill
|
||||
# connect highest-exit-count caves first, prevent issue where we have 2 or 3 exits across worlds left to fill
|
||||
cave_candidate = (None, 0)
|
||||
for i, cave in enumerate(caves):
|
||||
if isinstance(cave, str):
|
||||
@@ -696,12 +770,19 @@ def do_same_world_connectors(lw_entrances, dw_entrances, caves, avail):
|
||||
cave_candidate = (i, len(cave))
|
||||
cave = caves.pop(cave_candidate[0])
|
||||
|
||||
target = lw_entrances if random.randint(0, 1) == 0 else dw_entrances
|
||||
if isinstance(cave, str):
|
||||
cave = (cave,)
|
||||
target, restriction = None, None
|
||||
if any(x in avail.same_world_restricted for x in cave):
|
||||
restriction = next(avail.same_world_restricted[x] for x in cave if x in avail.same_world_restricted)
|
||||
target = lw_entrances if restriction == 'LightWorld' else dw_entrances
|
||||
if target is None:
|
||||
target = lw_entrances if random.randint(0, 1) == 0 else dw_entrances
|
||||
|
||||
# check if we can still fit the cave into our target group
|
||||
if len(target) < len(cave):
|
||||
if restriction:
|
||||
raise Exception('Not enough entrances for restricted cave, algorithm needs revision (main)')
|
||||
# need to use other set
|
||||
target = lw_entrances if target is dw_entrances else dw_entrances
|
||||
|
||||
@@ -715,6 +796,18 @@ def do_same_world_connectors(lw_entrances, dw_entrances, caves, avail):
|
||||
connect_two_way(target.pop(), ext, avail)
|
||||
|
||||
|
||||
def do_same_world_possible_connectors(lw_entrances, dw_entrances, possibles, avail):
|
||||
random.shuffle(possibles)
|
||||
while possibles:
|
||||
possible = possibles.pop()
|
||||
target = None
|
||||
if possible in avail.same_world_restricted:
|
||||
target = lw_entrances if avail.same_world_restricted[possible] == 'LightWorld' else dw_entrances
|
||||
if target is None:
|
||||
target = lw_entrances if random.randint(0, 1) == 0 else dw_entrances
|
||||
connect_two_way(target.pop(), possible, avail)
|
||||
determine_dungeon_restrictions(avail)
|
||||
|
||||
def do_cross_world_connectors(entrances, caves, avail):
|
||||
random.shuffle(entrances)
|
||||
random.shuffle(caves)
|
||||
@@ -762,6 +855,37 @@ def do_cross_world_connectors(entrances, caves, avail):
|
||||
break
|
||||
|
||||
|
||||
def handle_skull_woods_drops(avail, pool, mode_cfg):
|
||||
skull_woods = avail.world.skullwoods[avail.player]
|
||||
if skull_woods in ['restricted', 'loose']:
|
||||
for drop in pool:
|
||||
target = drop_map[drop]
|
||||
connect_entrance(drop, target, avail)
|
||||
elif skull_woods == 'original':
|
||||
holes, targets = find_entrances_and_targets_drops(avail, pool)
|
||||
if avail.swapped:
|
||||
connect_swapped(holes, targets, avail)
|
||||
else:
|
||||
connect_random(holes, targets, avail)
|
||||
elif skull_woods == 'followlinked':
|
||||
keep_together = mode_cfg['keep_drops_together'] == 'on' if 'keep_drops_together' in mode_cfg else True
|
||||
if keep_together:
|
||||
for drop in ['Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)']:
|
||||
target = drop_map[drop]
|
||||
connect_entrance(drop, target, avail)
|
||||
|
||||
|
||||
def handle_skull_woods_entrances(avail, pool):
|
||||
skull_woods = avail.world.skullwoods[avail.player]
|
||||
if skull_woods in ['restricted', 'original']:
|
||||
entrances, exits = find_entrances_and_exits(avail, pool)
|
||||
if avail.swapped:
|
||||
connect_swapped(entrances, exits, avail, True)
|
||||
else:
|
||||
connect_random(entrances, exits, avail, True)
|
||||
avail.skull_handled = True
|
||||
|
||||
|
||||
def do_fixed_shuffle(avail, entrance_list):
|
||||
max_size = 0
|
||||
options = {}
|
||||
@@ -803,8 +927,6 @@ def do_same_world_shuffle(avail, pool_def):
|
||||
multi_exit = pool_def['connectors']
|
||||
# complete_entrance_set = set()
|
||||
lw_entrances, dw_entrances, multi_exits_caves, other_exits = [], [], [], []
|
||||
hyrule_forced = None
|
||||
check_for_hc = avail.is_standard() or avail.world.doorShuffle[avail.player] != 'vanilla'
|
||||
|
||||
single_entrances, single_exits = find_entrances_and_exits(avail, single_exit)
|
||||
other_exits.extend(single_exits)
|
||||
@@ -814,12 +936,7 @@ def do_same_world_shuffle(avail, pool_def):
|
||||
for option in multi_exit:
|
||||
multi_entrances, multi_exits = find_entrances_and_exits(avail, option)
|
||||
# complete_entrance_set.update(multi_entrances)
|
||||
if check_for_hc and any(x in multi_entrances for x in ['Hyrule Castle Entrance (South)',
|
||||
'Hyrule Castle Entrance (East)',
|
||||
'Hyrule Castle Entrance (West)']):
|
||||
hyrule_forced = [multi_exits]
|
||||
else:
|
||||
multi_exits_caves.append(multi_exits)
|
||||
multi_exits_caves.append(multi_exits)
|
||||
for x in multi_entrances:
|
||||
(dw_entrances, lw_entrances)[x in LW_Entrances].append(x)
|
||||
|
||||
@@ -828,11 +945,16 @@ def do_same_world_shuffle(avail, pool_def):
|
||||
must_exit_lw = must_exit_filter(avail, must_exit_lw, lw_entrances)
|
||||
must_exit_dw = must_exit_filter(avail, must_exit_dw, dw_entrances)
|
||||
|
||||
if hyrule_forced:
|
||||
do_mandatory_connections(avail, lw_entrances, hyrule_forced, must_exit_lw)
|
||||
else:
|
||||
do_mandatory_connections(avail, lw_entrances, multi_exits_caves, must_exit_lw)
|
||||
do_mandatory_connections(avail, dw_entrances, multi_exits_caves, must_exit_dw)
|
||||
determine_dungeon_restrictions(avail)
|
||||
lw_candidates = filter_restricted_caves(multi_exits_caves, 'LightWorld', avail)
|
||||
other_candidates = [x for x in multi_exits_caves if x not in lw_candidates] # remember those not passed in
|
||||
do_mandatory_connections(avail, lw_entrances, lw_candidates, must_exit_lw)
|
||||
multi_exits_caves = other_candidates + lw_candidates # rebuild list from the lw_candidates and those not passed
|
||||
|
||||
dw_candidates = filter_restricted_caves(multi_exits_caves, 'DarkWorld', avail)
|
||||
other_candidates = [x for x in multi_exits_caves if x not in dw_candidates] # remember those not passed in
|
||||
do_mandatory_connections(avail, dw_entrances, dw_candidates, must_exit_dw)
|
||||
multi_exits_caves = other_candidates + dw_candidates # rebuild list from the dw_candidates and those not passed
|
||||
|
||||
# connect caves
|
||||
random.shuffle(lw_entrances)
|
||||
@@ -845,8 +967,15 @@ def do_same_world_shuffle(avail, pool_def):
|
||||
cave_candidate = (i, len(cave))
|
||||
cave = multi_exits_caves.pop(cave_candidate[0])
|
||||
|
||||
target = lw_entrances if random.randint(0, 1) == 0 else dw_entrances
|
||||
target, restriction = None, None
|
||||
if any(x in avail.same_world_restricted for x in cave):
|
||||
restriction = next(avail.same_world_restricted[x] for x in cave if x in avail.same_world_restricted)
|
||||
target = lw_entrances if restriction == 'LightWorld' else dw_entrances
|
||||
if target is None:
|
||||
target = lw_entrances if random.randint(0, 1) == 0 else dw_entrances
|
||||
if len(target) < len(cave): # swap because we ran out of entrances in that world
|
||||
if restriction:
|
||||
raise Exception('Not enough entrances for restricted cave, algorithm needs revision (dungeonsfull)')
|
||||
target = lw_entrances if target is dw_entrances else dw_entrances
|
||||
|
||||
for ext in cave:
|
||||
@@ -1386,6 +1515,12 @@ modes = {
|
||||
'entrances': ['Skull Woods First Section Door', 'Skull Woods Second Section Door (East)',
|
||||
'Skull Woods Second Section Door (West)']
|
||||
},
|
||||
'skull_layout': {
|
||||
'special': 'vanilla',
|
||||
'condition': '',
|
||||
'entrances': ['Skull Woods First Section Door', 'Skull Woods Second Section Door (East)',
|
||||
'Skull Woods Second Section Door (West)']
|
||||
},
|
||||
'single_entrance_dungeon': {
|
||||
'entrances': ['Eastern Palace', 'Tower of Hera', 'Thieves Town', 'Skull Woods Final Section',
|
||||
'Palace of Darkness', 'Ice Palace', 'Misery Mire', 'Swamp Palace', 'Ganons Tower']
|
||||
@@ -1419,13 +1554,15 @@ modes = {
|
||||
'sanc_flag': 'light_world', # always light world flag
|
||||
'entrances': ['Eastern Palace', 'Tower of Hera', 'Thieves Town', 'Skull Woods Final Section',
|
||||
'Agahnims Tower', 'Palace of Darkness', 'Ice Palace', 'Misery Mire', 'Swamp Palace',
|
||||
'Ganons Tower'],
|
||||
'Ganons Tower', 'Desert Palace Entrance (North)', 'Dark Death Mountain Ledge (East)'],
|
||||
'connectors': [['Hyrule Castle Entrance (South)', 'Hyrule Castle Entrance (East)',
|
||||
'Hyrule Castle Entrance (West)'],
|
||||
['Desert Palace Entrance (South)', 'Desert Palace Entrance (East)',
|
||||
'Desert Palace Entrance (West)', 'Desert Palace Entrance (North)'],
|
||||
'Desert Palace Entrance (West)'],
|
||||
['Turtle Rock', 'Turtle Rock Isolated Ledge Entrance',
|
||||
'Dark Death Mountain Ledge (West)', 'Dark Death Mountain Ledge (East)']]
|
||||
'Dark Death Mountain Ledge (West)'],
|
||||
['Skull Woods Second Section Door (East)', 'Skull Woods Second Section Door (West)',
|
||||
'Skull Woods First Section Door']]
|
||||
},
|
||||
}
|
||||
},
|
||||
@@ -1611,6 +1748,12 @@ modes = {
|
||||
'entrances': ['Skull Woods First Section Door', 'Skull Woods Second Section Door (East)',
|
||||
'Skull Woods Second Section Door (West)']
|
||||
},
|
||||
'skull_layout': {
|
||||
'special': 'vanilla',
|
||||
'condition': '',
|
||||
'entrances': ['Skull Woods First Section Door', 'Skull Woods Second Section Door (East)',
|
||||
'Skull Woods Second Section Door (West)']
|
||||
},
|
||||
'single_entrance_dungeon': {
|
||||
'entrances': ['Eastern Palace', 'Tower of Hera', 'Thieves Town', 'Skull Woods Final Section',
|
||||
'Palace of Darkness', 'Ice Palace', 'Misery Mire', 'Swamp Palace', 'Ganons Tower']
|
||||
@@ -1700,6 +1843,12 @@ modes = {
|
||||
'entrances': ['Skull Woods First Section Door', 'Skull Woods Second Section Door (East)',
|
||||
'Skull Woods Second Section Door (West)']
|
||||
},
|
||||
'skull_layout': {
|
||||
'special': 'vanilla',
|
||||
'condition': '',
|
||||
'entrances': ['Skull Woods First Section Door', 'Skull Woods Second Section Door (East)',
|
||||
'Skull Woods Second Section Door (West)']
|
||||
},
|
||||
'single_entrance_dungeon': {
|
||||
'entrances': ['Eastern Palace', 'Tower of Hera', 'Thieves Town', 'Skull Woods Final Section',
|
||||
'Palace of Darkness', 'Ice Palace', 'Misery Mire', 'Swamp Palace', 'Ganons Tower']
|
||||
@@ -1801,7 +1950,10 @@ linked_drop_map = {
|
||||
'Lumberjack Tree Tree': 'Lumberjack Tree Cave',
|
||||
'Sanctuary Grave': 'Sanctuary',
|
||||
'Pyramid Hole': 'Pyramid Entrance',
|
||||
'Inverted Pyramid Hole': 'Inverted Pyramid Entrance'
|
||||
'Inverted Pyramid Hole': 'Inverted Pyramid Entrance',
|
||||
|
||||
'Skull Woods First Section Hole (North)': 'Skull Woods First Section Door',
|
||||
'Skull Woods Second Section Hole': 'Skull Woods Second Section Door (East)',
|
||||
}
|
||||
|
||||
entrance_map = {
|
||||
@@ -2066,6 +2218,19 @@ Connector_Exit_Set = {
|
||||
'Turtle Rock Isolated Ledge Exit', 'Turtle Rock Ledge Exit (West)'
|
||||
}
|
||||
|
||||
dungeon_restriction_checks = [
|
||||
(['Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)', 'Sanctuary Exit'], ['Sewer Drop']),
|
||||
(['Desert Palace Exit (South)', 'Desert Palace Exit (East)', 'Desert Palace Exit (West)', 'Desert Palace Exit (North)'], []),
|
||||
(['Turtle Rock Exit (Front)', 'Turtle Rock Isolated Ledge Exit', 'Turtle Rock Ledge Exit (West)', 'Turtle Rock Ledge Exit (East)'], []),
|
||||
(['Skull Woods First Section Exit', 'Skull Woods Second Section Exit (East)', 'Skull Woods Second Section Exit (West)', 'Skull Woods Final Section Exit'],
|
||||
['Skull Pinball', 'Skull Left Drop', 'Skull Pot Circle', 'Skull Back Drop'])
|
||||
]
|
||||
|
||||
doors_possible_connectors = [
|
||||
'Sanctuary Exit', 'Desert Palace Exit (North)', 'Skull Woods First Section Exit',
|
||||
'Skull Woods Second Section Exit (East)', 'Skull Woods Second Section Exit (West)', 'Skull Woods Final Section Exit'
|
||||
]
|
||||
|
||||
# Entrances that cannot be used to access a must_exit entrance - symmetrical to allow reverse lookups
|
||||
Must_Exit_Invalid_Connections = defaultdict(set, {
|
||||
'Dark Death Mountain Ledge (East)': {'Dark Death Mountain Ledge (West)', 'Mimic Cave'},
|
||||
|
||||
Reference in New Issue
Block a user