Adding Customizer support for Crossed OWR

Also made Layout OWR compatible with Mixed OWR with asterisk notation
This commit is contained in:
codemann8
2023-09-05 00:30:53 -05:00
parent c1f98dfb51
commit 927588a3d8
4 changed files with 296 additions and 75 deletions

View File

@@ -87,6 +87,7 @@ class World(object):
self.owedges = [] self.owedges = []
self._owedge_cache = {} self._owedge_cache = {}
self.owswaps = {} self.owswaps = {}
self.owcrossededges = {}
self.owwhirlpools = {} self.owwhirlpools = {}
self.owflutespots = {} self.owflutespots = {}
self.owsectors = {} self.owsectors = {}
@@ -114,6 +115,7 @@ class World(object):
set_player_attr('_region_cache', {}) set_player_attr('_region_cache', {})
set_player_attr('player_names', []) set_player_attr('player_names', [])
set_player_attr('owswaps', [[],[],[]]) set_player_attr('owswaps', [[],[],[]])
set_player_attr('owcrossededges', [])
set_player_attr('owwhirlpools', []) set_player_attr('owwhirlpools', [])
set_player_attr('owsectors', None) set_player_attr('owsectors', None)
set_player_attr('remote_items', False) set_player_attr('remote_items', False)
@@ -321,6 +323,16 @@ class World(object):
if isinstance(edgename, OWEdge): if isinstance(edgename, OWEdge):
return edgename return edgename
try: try:
if edgename[-1] == '*':
edgename = edgename[:-1]
edge = self.check_for_owedge(edgename, player)
if self.is_tile_swapped(edge.owIndex, player):
from OverworldShuffle import parallel_links
if edgename in parallel_links.keys() or edgename in parallel_links.inverse.keys():
edgename = parallel_links[edgename] if edgename in parallel_links.keys() else parallel_links.inverse[edgename][0]
return self.check_for_owedge(edgename, player)
else:
raise Exception("Edge notated with * doesn't have a parallel edge: %s" & edgename)
return self._owedge_cache[(edgename, player)] return self._owedge_cache[(edgename, player)]
except KeyError: except KeyError:
for edge in self.owedges: for edge in self.owedges:
@@ -2248,7 +2260,7 @@ class OWEdge(object):
self.unknownX = 0x0 self.unknownX = 0x0
self.unknownY = 0x0 self.unknownY = 0x0
if self.owIndex < 0x40 or self.owIndex >= 0x80: if self.owIndex & 0x40 == 0:
self.worldType = WorldType.Light self.worldType = WorldType.Light
else: else:
self.worldType = WorldType.Dark self.worldType = WorldType.Dark
@@ -2289,6 +2301,12 @@ class OWEdge(object):
self.specialID = special_id self.specialID = special_id
return self return self
def is_tile_swapped(self, world):
return world.is_tile_swapped(self.owIndex, self.player)
def is_lw(self, world):
return (self.worldType == WorldType.Light) != self.is_tile_swapped(world)
def __eq__(self, other): def __eq__(self, other):
return isinstance(other, self.__class__) and self.name == other.name return isinstance(other, self.__class__) and self.name == other.name

View File

@@ -205,20 +205,40 @@ def link_overworld(world, player):
# crossed shuffle # crossed shuffle
logging.getLogger('').debug('Crossing overworld edges') logging.getLogger('').debug('Crossing overworld edges')
crossed_edges = list()
#TODO: Revisit with changes to Limited/Allowed # customizer setup
if world.owCrossed[player] not in ['none', 'grouped', 'polar', 'chaos']: force_crossed = set()
force_noncrossed = set()
count_crossed = 0
limited_crossed = 9 if world.owCrossed[player] == 'limited' else -1
if world.customizer:
custom_crossed = world.customizer.get_owcrossed()
if custom_crossed and player in custom_crossed:
custom_crossed = custom_crossed[player]
if 'force_crossed' in custom_crossed and len(custom_crossed['force_crossed']) > 0:
for edgename in custom_crossed['force_crossed']:
edge = world.check_for_owedge(edgename, player)
force_crossed.add(edge.name)
if 'force_noncrossed' in custom_crossed and len(custom_crossed['force_noncrossed']) > 0:
for edgename in custom_crossed['force_noncrossed']:
edge = world.check_for_owedge(edgename, player)
force_noncrossed.add(edge.name)
if 'limit_crossed' in custom_crossed:
limited_crossed = custom_crossed['limit_crossed']
if limited_crossed > -1:
# connect forced crossed non-parallel edges based on previously determined tile flips
for edge in swapped_edges: for edge in swapped_edges:
crossed_edges.append(edge)
if world.owCrossed[player] in ['grouped', 'limited'] or (world.owShuffle[player] == 'vanilla' and world.owCrossed[player] == 'chaos'):
if edge not in parallel_links_new: if edge not in parallel_links_new:
world.owcrossededges[player].append(edge)
count_crossed = count_crossed + 1
if world.owCrossed[player] == 'grouped' or (world.owShuffle[player] == 'vanilla' and world.owCrossed[player] == 'chaos') or limited_crossed > -1:
if world.owCrossed[player] == 'grouped': if world.owCrossed[player] == 'grouped':
# the idea is to XOR the new flips with the ones from Mixed so that non-parallel edges still work # the idea is to XOR the new flips with the ones from Mixed so that non-parallel edges still work
# Polar corresponds to Grouped with no flips in ow_crossed_tiles_mask # Polar corresponds to Grouped with no flips in ow_crossed_tiles_mask
ow_crossed_tiles_mask = [[],[],[]] ow_crossed_tiles_mask = [[],[],[]]
crossed_edges = shuffle_tiles(world, define_tile_groups(world, player, True), ow_crossed_tiles_mask, True, player) world.owcrossededges[player] = shuffle_tiles(world, define_tile_groups(world, player, True), ow_crossed_tiles_mask, True, player)
ow_crossed_tiles = [i for i in range(0x82) if (i in world.owswaps[player][0]) != (i in ow_crossed_tiles_mask[0])] ow_crossed_tiles = [i for i in range(0x82) if (i in world.owswaps[player][0]) != (i in ow_crossed_tiles_mask[0])]
# update spoiler # update spoiler
@@ -244,32 +264,77 @@ def link_overworld(world, player):
(mode, wrld, dir, terrain, parallel, count) = group (mode, wrld, dir, terrain, parallel, count) = group
if wrld == WorldType.Light and mode != OpenStd.Standard: if wrld == WorldType.Light and mode != OpenStd.Standard:
for (forward_set, back_set) in zip(trimmed_groups[group][0], trimmed_groups[group][1]): for (forward_set, back_set) in zip(trimmed_groups[group][0], trimmed_groups[group][1]):
if world.owKeepSimilar[player]:
if world.owCrossed[player] == 'chaos' and random.randint(0, 1):
for edge in forward_set:
crossed_edges.append(edge)
elif world.owCrossed[player] == 'limited':
crossed_candidates.append(forward_set)
if forward_set[0] in parallel_links_new: if forward_set[0] in parallel_links_new:
forward_parallel = [parallel_links_new[e] for e in forward_set]
back_parallel = [parallel_links_new[e] for e in back_set]
forward_combine = forward_set+forward_parallel
back_combine = back_set+back_parallel
combine_set = forward_combine+back_combine
skip_forward = False
if world.owShuffle[player] == 'vanilla':
if any(edge in force_crossed for edge in combine_set):
if not any(edge in force_noncrossed for edge in combine_set):
if any(edge in force_crossed for edge in forward_combine):
world.owcrossededges[player].extend(forward_set)
count_crossed = count_crossed + 1
continue
else:
world.owcrossededges[player].extend(back_set)
count_crossed = count_crossed + 1
continue
else:
raise GenerationException('Conflict detected in force_crossed and force_noncrossed')
if any(edge in list(force_noncrossed)+world.owcrossededges[player] for edge in combine_set):
continue
else: else:
for edge in forward_set: skip_back = False
if world.owCrossed[player] == 'chaos' and random.randint(0, 1): if any(edge in force_crossed for edge in forward_combine):
crossed_edges.append(edge) if not any(edge in force_noncrossed for edge in forward_combine):
elif world.owCrossed[player] == 'limited': world.owcrossededges[player].extend(forward_set)
crossed_candidates.append([edge]) count_crossed = count_crossed + 1
if world.owCrossed[player] == 'limited': skip_forward = True
else:
raise GenerationException('Conflict detected in force_crossed and force_noncrossed')
if any(edge in force_crossed for edge in back_combine):
if not any(edge in force_noncrossed for edge in back_combine):
world.owcrossededges[player].extend(back_set)
count_crossed = count_crossed + 1
skip_back = True
else:
raise GenerationException('Conflict detected in force_crossed and force_noncrossed')
if any(edge in list(force_noncrossed)+world.owcrossededges[player] for edge in forward_combine):
skip_forward = True
if any(edge in list(force_noncrossed)+world.owcrossededges[player] for edge in back_combine):
skip_back = True
if not skip_back:
if limited_crossed > -1:
crossed_candidates.append(back_set)
elif random.randint(0, 1):
world.owcrossededges[player].extend(back_set)
count_crossed = count_crossed + 1
if not skip_forward:
if limited_crossed > -1:
crossed_candidates.append(forward_set)
elif random.randint(0, 1):
world.owcrossededges[player].extend(forward_set)
count_crossed = count_crossed + 1
assert len(world.owcrossededges[player]) == len(set(world.owcrossededges[player])), "Same edge added to crossed edges"
if limited_crossed > -1:
limit = limited_crossed - count_crossed
random.shuffle(crossed_candidates) random.shuffle(crossed_candidates)
for edge_set in crossed_candidates[:9]: for edge_set in crossed_candidates[:limit]:
for edge in edge_set: world.owcrossededges[player].extend(edge_set)
crossed_edges.append(edge) assert len(world.owcrossededges[player]) == len(set(world.owcrossededges[player])), "Same edge candidate added to crossed edges"
for edge in copy.deepcopy(crossed_edges):
for edge in copy.deepcopy(world.owcrossededges[player]):
if edge in parallel_links_new: if edge in parallel_links_new:
crossed_edges.append(parallel_links_new[edge]) if parallel_links_new[edge] not in world.owcrossededges[player]:
elif edge in parallel_links_new.inverse: world.owcrossededges[player].append(parallel_links_new[edge])
crossed_edges.append(parallel_links_new.inverse[edge][0])
# after tile flip and crossed, determine edges that need to flip # after tile flip and crossed, determine edges that need to flip
edges_to_swap = [e for e in swapped_edges+crossed_edges if (e not in swapped_edges) or (e not in crossed_edges)] edges_to_swap = [e for e in swapped_edges+world.owcrossededges[player] if (e not in swapped_edges) or (e not in world.owcrossededges[player])]
# whirlpool shuffle # whirlpool shuffle
logging.getLogger('').debug('Shuffling whirlpools') logging.getLogger('').debug('Shuffling whirlpools')
@@ -367,53 +432,142 @@ def link_overworld(world, player):
# layout shuffle # layout shuffle
groups = adjust_edge_groups(world, trimmed_groups, edges_to_swap, player) groups = adjust_edge_groups(world, trimmed_groups, edges_to_swap, player)
connect_custom(world, connected_edges, groups, player) connect_custom(world, connected_edges, groups, (force_crossed, force_noncrossed), player)
tries = 100 tries = 100
valid_layout = False valid_layout = False
connected_edge_cache = connected_edges.copy() connected_edge_cache = connected_edges.copy()
groups_cache = copy.deepcopy(groups)
while not valid_layout and tries > 0: while not valid_layout and tries > 0:
def connect_set(forward_set, back_set, connected_edges):
if forward_set is not None and back_set is not None:
assert len(forward_set) == len(back_set)
for (forward_edge, back_edge) in zip(forward_set, back_set):
connect_two_way(world, forward_edge, back_edge, player, connected_edges)
elif forward_set is not None:
logging.getLogger('').warning("Edge '%s' could not find a valid connection" % forward_set[0])
elif back_set is not None:
logging.getLogger('').warning("Edge '%s' could not find a valid connection" % back_set[0])
connected_edges = connected_edge_cache.copy() connected_edges = connected_edge_cache.copy()
groups = copy.deepcopy(groups_cache)
groupKeys = list(groups.keys())
if world.mode[player] == 'standard': if world.mode[player] == 'standard':
random.shuffle(groups[2:]) # keep first 2 groups (Standard) first random.shuffle(groupKeys[2:]) # keep first 2 groups (Standard) first
else: else:
random.shuffle(groups) random.shuffle(groupKeys)
for (forward_edge_sets, back_edge_sets) in groups: for key in groupKeys:
assert len(forward_edge_sets) == len(back_edge_sets) (mode, wrld, dir, terrain, parallel, count) = key
(forward_edge_sets, back_edge_sets) = groups[key]
def remove_connected():
s = 0
while s < len(forward_edge_sets):
forward_set = forward_edge_sets[s]
if forward_set[0] in connected_edges:
del forward_edge_sets[s]
continue
s += 1
s = 0
while s < len(back_edge_sets):
back_set = back_edge_sets[s]
if back_set[0] in connected_edges:
del back_edge_sets[s]
continue
s += 1
assert len(forward_edge_sets) == len(back_edge_sets)
remove_connected()
random.shuffle(forward_edge_sets) random.shuffle(forward_edge_sets)
random.shuffle(back_edge_sets) random.shuffle(back_edge_sets)
if len(forward_edge_sets) > 0: if wrld is None and len(force_crossed) + len(force_noncrossed) > 0:
f = 0 # divide forward/back sets into LW/DW
b = 0 forward_lw_sets, forward_dw_sets = [], []
while f < len(forward_edge_sets) and b < len(back_edge_sets): back_lw_sets, back_dw_sets = [], []
forward_set = forward_edge_sets[f] forward_parallel_lw_sets, forward_parallel_dw_sets = [], []
back_set = back_edge_sets[b] back_parallel_lw_sets, back_parallel_dw_sets = [], []
while forward_set[0] in connected_edges:
f += 1 for edge_set in forward_edge_sets:
if f < len(forward_edge_sets): if world.check_for_owedge(edge_set[0], player).is_lw(world):
forward_set = forward_edge_sets[f] forward_lw_sets.append(edge_set)
if parallel == IsParallel.Yes:
forward_parallel_lw_sets.append([parallel_links_new[e] for e in edge_set])
else:
forward_dw_sets.append(edge_set)
if parallel == IsParallel.Yes:
forward_parallel_dw_sets.append([parallel_links_new[e] for e in edge_set])
for edge_set in back_edge_sets:
if world.check_for_owedge(edge_set[0], player).is_lw(world):
back_lw_sets.append(edge_set)
if parallel == IsParallel.Yes:
back_parallel_lw_sets.append([parallel_links_new[e] for e in edge_set])
else:
back_dw_sets.append(edge_set)
if parallel == IsParallel.Yes:
back_parallel_dw_sets.append([parallel_links_new[e] for e in edge_set])
crossed_sets = []
noncrossed_sets = []
def add_to_crossed_sets(sets, parallel_sets):
for i in range(0, len(sets)):
affected_edges = set(sets[i]+(parallel_sets[i] if parallel == IsParallel.Yes else []))
if sets[i] not in crossed_sets and len(set.intersection(set(force_crossed), affected_edges)) > 0:
crossed_sets.append(sets[i])
if sets not in noncrossed_sets and len(set.intersection(set(force_noncrossed), affected_edges)) > 0:
noncrossed_sets.append(sets[i])
if sets[i] in crossed_sets and sets[i] in noncrossed_sets:
raise GenerationException('Conflict in force crossed/non-crossed definition')
add_to_crossed_sets(forward_lw_sets, forward_parallel_lw_sets)
add_to_crossed_sets(forward_dw_sets, forward_parallel_dw_sets)
add_to_crossed_sets(back_lw_sets, back_parallel_lw_sets)
add_to_crossed_sets(back_dw_sets, back_parallel_dw_sets)
# random connect forced crossed/noncrossed
c = 0
while c < len(noncrossed_sets):
if noncrossed_sets[c] in forward_edge_sets:
forward_set = noncrossed_sets[c]
if forward_set in forward_lw_sets:
back_set = next(s for s in back_lw_sets if s in back_edge_sets and s not in crossed_sets)
else: else:
forward_set = None back_set = next(s for s in back_dw_sets if s in back_edge_sets and s not in crossed_sets)
break elif noncrossed_sets[c] in back_edge_sets:
f += 1 back_set = noncrossed_sets[c]
while back_set[0] in connected_edges: if back_set in back_lw_sets:
b += 1 forward_set = next(s for s in forward_lw_sets if s in forward_edge_sets and s not in crossed_sets)
if b < len(back_edge_sets):
back_set = back_edge_sets[b]
else: else:
back_set = None forward_set = next(s for s in forward_dw_sets if s in forward_edge_sets and s not in crossed_sets)
break else:
b += 1 c = c + 1
if forward_set is not None and back_set is not None: continue
assert len(forward_set) == len(back_set) connect_set(forward_set, back_set, connected_edges)
for (forward_edge, back_edge) in zip(forward_set, back_set): remove_connected()
connect_two_way(world, forward_edge, back_edge, player, connected_edges) c = c + 1
elif forward_set is not None: c = 0
logging.getLogger('').warning("Edge '%s' could not find a valid connection" % forward_set[0]) while c < len(crossed_sets):
elif back_set is not None: if crossed_sets[c] in forward_edge_sets:
logging.getLogger('').warning("Edge '%s' could not find a valid connection" % back_set[0]) forward_set = crossed_sets[c]
if forward_set in forward_lw_sets:
back_set = next(s for s in back_dw_sets if s in back_edge_sets)
else:
back_set = next(s for s in back_lw_sets if s in back_edge_sets)
elif crossed_sets[c] in back_edge_sets:
back_set = crossed_sets[c]
if back_set in back_lw_sets:
forward_set = next(s for s in forward_dw_sets if s in forward_edge_sets)
else:
forward_set = next(s for s in forward_lw_sets if s in forward_edge_sets)
else:
c = c + 1
continue
connect_set(forward_set, back_set, connected_edges)
remove_connected()
c = c + 1
while len(forward_edge_sets) > 0 and len(back_edge_sets) > 0:
connect_set(forward_edge_sets[0], back_edge_sets[0], connected_edges)
remove_connected()
assert len(connected_edges) == len(default_connections) * 2, connected_edges assert len(connected_edges) == len(default_connections) * 2, connected_edges
world.owsectors[player] = build_sectors(world, player) world.owsectors[player] = build_sectors(world, player)
@@ -583,8 +737,9 @@ def link_overworld(world, player):
s[0x3a],s[0x3b],s[0x3c], s[0x3f]) s[0x3a],s[0x3b],s[0x3c], s[0x3f])
world.spoiler.set_map('flute', text_output, new_spots, player) world.spoiler.set_map('flute', text_output, new_spots, player)
def connect_custom(world, connected_edges, groups, player): def connect_custom(world, connected_edges, groups, forced, player):
def remove_pair_from_pool(edgename1, edgename2): forced_crossed, forced_noncrossed = forced
def remove_pair_from_pool(edgename1, edgename2, is_crossed):
def add_to_unresolved(forward_set, back_set): def add_to_unresolved(forward_set, back_set):
if len(forward_set) > 1: if len(forward_set) > 1:
if edgename1 in forward_set: if edgename1 in forward_set:
@@ -593,8 +748,8 @@ def connect_custom(world, connected_edges, groups, player):
else: else:
back_set.remove(edgename1) back_set.remove(edgename1)
forward_set.remove(edgename2) forward_set.remove(edgename2)
unresolved_similars.append(tuple((forward_set, back_set))) unresolved_similars.append(tuple((forward_set, back_set, is_crossed)))
for forward_pool, back_pool in groups: for forward_pool, back_pool in groups.values():
if not len(forward_pool): if not len(forward_pool):
continue continue
if len(forward_pool[0]) == 1: if len(forward_pool[0]) == 1:
@@ -635,7 +790,7 @@ def connect_custom(world, connected_edges, groups, player):
else: else:
break break
for pair in unresolved_similars: for pair in unresolved_similars:
forward_set, back_set = pair forward_set, back_set, _ = pair
if edgename1 in forward_set: if edgename1 in forward_set:
if edgename2 in back_set: if edgename2 in back_set:
unresolved_similars.remove(pair) unresolved_similars.remove(pair)
@@ -659,24 +814,45 @@ def connect_custom(world, connected_edges, groups, player):
custom_edges = custom_edges[player] custom_edges = custom_edges[player]
if 'two-way' in custom_edges: if 'two-way' in custom_edges:
unresolved_similars = [] unresolved_similars = []
def validate_crossed_allowed(edge1, edge2, is_crossed):
return not ((not is_crossed and (edge1 in forced_crossed or edge2 in forced_crossed))
or (is_crossed and (edge1 in forced_noncrossed or edge2 in forced_noncrossed)))
for edgename1, edgename2 in custom_edges['two-way'].items(): for edgename1, edgename2 in custom_edges['two-way'].items():
edge1 = world.check_for_owedge(edgename1, player) edge1 = world.check_for_owedge(edgename1, player)
edge2 = world.check_for_owedge(edgename2, player) edge2 = world.check_for_owedge(edgename2, player)
if edgename1 not in connected_edges and edgename2 not in connected_edges: is_crossed = edge1.is_lw(world) != edge2.is_lw(world)
if not validate_crossed_allowed(edge1.name, edge2.name, is_crossed):
if edgename2[-1] == '*':
edge2 = world.check_for_owedge(edge2.name + '*', player)
is_crossed = not is_crossed
else:
raise GenerationException('Violation of force crossed rules: \'%s\' <-> \'%s\'', edgename1, edgename2)
if edge1.name not in connected_edges and edge2.name not in connected_edges:
# attempt connection # attempt connection
remove_pair_from_pool(edgename1, edgename2) remove_pair_from_pool(edge1.name, edge2.name, is_crossed)
connect_two_way(world, edgename1, edgename2, player, connected_edges) connect_two_way(world, edge1.name, edge2.name, player, connected_edges)
# resolve parallel # resolve parallel
remove_pair_from_pool(parallel_forward_edge, parallel_back_edge)
elif not edge1.dest or not edge2.dest or edge1.dest.name != edgename2 or edge2.dest.name != edgename1:
if world.owShuffle[player] == 'parallel' and edge1.name in parallel_links_new: if world.owShuffle[player] == 'parallel' and edge1.name in parallel_links_new:
parallel_forward_edge = parallel_links_new[edge1.name] parallel_forward_edge = parallel_links_new[edge1.name]
parallel_back_edge = parallel_links_new[edge2.name] parallel_back_edge = parallel_links_new[edge2.name]
if validate_crossed_allowed(parallel_forward_edge, parallel_back_edge, is_crossed):
remove_pair_from_pool(parallel_forward_edge, parallel_back_edge, is_crossed)
else:
raise GenerationException('Violation of force crossed rules on parallel connection: \'%s\' <-> \'%s\'', edgename1, edgename2)
elif not edge1.dest or not edge2.dest or edge1.dest.name != edge2.name or edge2.dest.name != edge1.name:
raise GenerationException('OW Edge already connected: \'%s\' <-> \'%s\'', edgename1, edgename2) raise GenerationException('OW Edge already connected: \'%s\' <-> \'%s\'', edgename1, edgename2)
# connect leftover similars # connect leftover similars
for forward_pool, back_pool in unresolved_similars: for forward_pool, back_pool, is_crossed in unresolved_similars:
for (forward_edge, back_edge) in zip(forward_pool, back_pool): for (forward_edge, back_edge) in zip(forward_pool, back_pool):
connect_two_way(world, forward_edge, back_edge, player, connected_edges) if validate_crossed_allowed(forward_edge, back_edge, is_crossed):
connect_two_way(world, forward_edge, back_edge, player, connected_edges)
else:
raise GenerationException('Violation of force crossed rules on unresolved similars: \'%s\' <-> \'%s\'', forward_edge, back_edge)
if world.owShuffle[player] == 'parallel' and forward_edge in parallel_links_new:
parallel_forward_edge = parallel_links_new[forward_edge]
parallel_back_edge = parallel_links_new[back_edge]
if not validate_crossed_allowed(parallel_forward_edge, parallel_back_edge, is_crossed):
raise GenerationException('Violation of force crossed rules on parallel unresolved similars: \'%s\' <-> \'%s\'', forward_edge, back_edge)
def connect_two_way(world, edgename1, edgename2, player, connected_edges=None): def connect_two_way(world, edgename1, edgename2, player, connected_edges=None):
edge1 = world.get_entrance(edgename1, player) edge1 = world.get_entrance(edgename1, player)
@@ -1054,12 +1230,16 @@ def reorganize_groups(world, groups, player):
def adjust_edge_groups(world, trimmed_groups, edges_to_swap, player): def adjust_edge_groups(world, trimmed_groups, edges_to_swap, player):
groups = defaultdict(lambda: ([],[])) groups = defaultdict(lambda: ([],[]))
limited_crossed = False
if world.customizer:
custom_crossed = world.customizer.get_owcrossed()
limited_crossed = custom_crossed and (player in custom_crossed) and ('limit_crossed' in custom_crossed[player])
for (key, group) in trimmed_groups.items(): for (key, group) in trimmed_groups.items():
(mode, wrld, dir, terrain, parallel, count) = key (mode, wrld, dir, terrain, parallel, count) = key
if mode == OpenStd.Standard: if mode == OpenStd.Standard:
groups[key] = group groups[key] = group
else: else:
if world.owCrossed[player] == 'chaos': if world.owCrossed[player] == 'chaos' and not limited_crossed:
groups[(mode, None, dir, terrain, parallel, count)][0].extend(group[0]) groups[(mode, None, dir, terrain, parallel, count)][0].extend(group[0])
groups[(mode, None, dir, terrain, parallel, count)][1].extend(group[1]) groups[(mode, None, dir, terrain, parallel, count)][1].extend(group[1])
else: else:
@@ -1069,7 +1249,7 @@ def adjust_edge_groups(world, trimmed_groups, edges_to_swap, player):
if edge_set[0] in edges_to_swap: if edge_set[0] in edges_to_swap:
new_world += 1 new_world += 1
groups[(mode, WorldType(new_world % 2), dir, terrain, parallel, count)][i].append(edge_set) groups[(mode, WorldType(new_world % 2), dir, terrain, parallel, count)][i].append(edge_set)
return list(groups.values()) return groups
def create_flute_exits(world, player): def create_flute_exits(world, player):
flute_in_pool = True if player not in world.customitemarray else any(i for i, n in world.customitemarray[player].items() if i == 'flute' and n > 0) flute_in_pool = True if player not in world.customitemarray else any(i for i, n in world.customitemarray[player].items() if i == 'flute' and n > 0)

View File

@@ -69,6 +69,24 @@ placements:
Palace of Darkness - Big Chest: Hammer Palace of Darkness - Big Chest: Hammer
Capacity Upgrade - Left: Moon Pearl Capacity Upgrade - Left: Moon Pearl
Turtle Rock - Pokey 2 Key Drop: Ice Rod Turtle Rock - Pokey 2 Key Drop: Ice Rod
ow-edges:
1:
two-way:
Kakariko Fortune ES*: Sanctuary WN*
Central Bonk Rocks EC: Potion Shop WN
Central Bonk Rocks ES: Potion Shop WC
ow-crossed:
1:
force_crossed:
- Links House ES*
- Kakariko Fortune ES*
force_noncrossed:
- Links House NE
limit_crossed: 9 # emulates Limited Crossed
ow-whirlpools:
1:
two-way:
River Bend Whirlpool: Lake Hylia Whirlpool
ow-tileflips: ow-tileflips:
1: 1:
force_flip: force_flip:

View File

@@ -201,6 +201,11 @@ class CustomSettings(object):
return self.file_source['ow-edges'] return self.file_source['ow-edges']
return None return None
def get_owcrossed(self):
if 'ow-crossed' in self.file_source:
return self.file_source['ow-crossed']
return None
def get_whirlpools(self): def get_whirlpools(self):
if 'ow-whirlpools' in self.file_source: if 'ow-whirlpools' in self.file_source:
return self.file_source['ow-whirlpools'] return self.file_source['ow-whirlpools']