Expanded and restructured OW Shuffle to include more Crossed options

This commit is contained in:
codemann8
2021-08-24 02:39:24 -05:00
parent d1b0b57d53
commit b2bcdfd286
14 changed files with 344 additions and 421 deletions

View File

@@ -2980,7 +2980,7 @@ class Settings(object):
@staticmethod @staticmethod
def make_code(w, p): def make_code(w, p):
code = bytes([ code = bytes([
(dr_mode[w.doorShuffle[p]] << 6) | (or_mode[w.owShuffle[p]] << 5) | (0x10 if w.owCrossed[p] else 0) | (0x08 if w.owMixed[p] else 0) | er_mode[w.shuffle[p]], (dr_mode[w.doorShuffle[p]] << 6) | (or_mode[w.owShuffle[p]] << 5) | (0x10 if w.owCrossed[p] != 'none' else 0) | (0x08 if w.owMixed[p] else 0) | er_mode[w.shuffle[p]],
(logic_mode[w.logic[p]] << 5) | (world_mode[w.mode[p]] << 3) (logic_mode[w.logic[p]] << 5) | (world_mode[w.mode[p]] << 3)
| (sword_mode[w.swords[p]] << 1) | (1 if w.retro[p] else 0), | (sword_mode[w.swords[p]] << 1) | (1 if w.retro[p] else 0),

2
CLI.py
View File

@@ -146,7 +146,7 @@ def parse_settings():
"openpyramid": False, "openpyramid": False,
"shuffleganon": True, "shuffleganon": True,
"ow_shuffle": "vanilla", "ow_shuffle": "vanilla",
"ow_crossed": False, "ow_crossed": "none",
"ow_keepsimilar": False, "ow_keepsimilar": False,
"ow_mixed": False, "ow_mixed": False,
"ow_fluteshuffle": "vanilla", "ow_fluteshuffle": "vanilla",

View File

@@ -215,7 +215,7 @@ def vanilla_key_logic(world, player):
analyze_dungeon(key_layout, world, player) analyze_dungeon(key_layout, world, player)
world.key_logic[player][builder.name] = key_layout.key_logic world.key_logic[player][builder.name] = key_layout.key_logic
log_key_logic(builder.name, key_layout.key_logic) log_key_logic(builder.name, key_layout.key_logic)
# if world.shuffle[player] == 'vanilla' and world.owShuffle[player] == 'vanilla' and not world.owCrossed[player] and not world.owMixed[player] and world.accessibility[player] == 'items' and not world.retro[player] and not world.keydropshuffle[player]: # if world.shuffle[player] == 'vanilla' and world.owShuffle[player] == 'vanilla' and world.owCrossed[player] == 'none' and not world.owMixed[player] and world.accessibility[player] == 'items' and not world.retro[player] and not world.keydropshuffle[player]:
# validate_vanilla_key_logic(world, player) # validate_vanilla_key_logic(world, player)

View File

@@ -263,7 +263,7 @@ def main(args, seed=None, fish=None):
customize_shops(world, player) customize_shops(world, player)
balance_money_progression(world) balance_money_progression(world)
if world.owShuffle[1] != 'vanilla' or world.owCrossed[1] or world.owMixed[1] or str(world.seed).startswith('M'): if world.owShuffle[1] != 'vanilla' or world.owCrossed[1] != 'none' or world.owMixed[1] or str(world.seed).startswith('M'):
outfilebase = f'OR_{args.outputname if args.outputname else world.seed}' outfilebase = f'OR_{args.outputname if args.outputname else world.seed}'
else: else:
outfilebase = f'DR_{args.outputname if args.outputname else world.seed}' outfilebase = f'DR_{args.outputname if args.outputname else world.seed}'

View File

@@ -135,8 +135,8 @@ def roll_settings(weights):
overworld_shuffle = get_choice('overworld_shuffle') overworld_shuffle = get_choice('overworld_shuffle')
ret.ow_shuffle = overworld_shuffle if overworld_shuffle != 'none' else 'vanilla' ret.ow_shuffle = overworld_shuffle if overworld_shuffle != 'none' else 'vanilla'
ret.ow_crossed = get_choice('overworld_crossed')
ret.ow_keepsimilar = get_choice('overworld_keepsimilar') == 'on' ret.ow_keepsimilar = get_choice('overworld_keepsimilar') == 'on'
ret.ow_crossed = get_choice('overworld_crossed') == 'on'
ret.ow_mixed = get_choice('overworld_mixed') == 'on' ret.ow_mixed = get_choice('overworld_mixed') == 'on'
overworld_flute = get_choice('flute_shuffle') overworld_flute = get_choice('flute_shuffle')
ret.ow_fluteshuffle = overworld_flute if overworld_flute != 'none' else 'vanilla' ret.ow_fluteshuffle = overworld_flute if overworld_flute != 'none' else 'vanilla'

View File

@@ -11,10 +11,108 @@ def link_overworld(world, player):
for exitname, destname in temporary_mandatory_connections: for exitname, destname in temporary_mandatory_connections:
connect_two_way(world, exitname, destname, player) connect_two_way(world, exitname, destname, player)
trimmed_groups = copy.deepcopy(OWEdgeGroups) def performSwap(groups, swaps):
def getParallel(edgename):
if edgename in parallel_links:
return parallel_links[edgename]
elif edgename in parallel_links.inverse:
return parallel_links.inverse[edgename][0]
else:
raise Exception('No parallel edge found for edge %s', edgename)
# adjust Frog/Dig Game swap manually due to NP/P relationship with LW def getNewSets(all_set, other_set):
if world.owShuffle[player] == 'parallel' and not world.owKeepSimilar[player]: new_all_set = list(map(getParallel, all_set))
if not all(edge in orig_swaps for edge in new_all_set):
raise Exception('Cannot move a parallel edge without the other')
else:
for edge in new_all_set:
swaps.remove(edge)
new_other_set = getNewSet(other_set)
return (new_all_set, new_other_set)
def getNewSet(edge_set):
new_set = []
for edge in edge_set:
if edge in orig_swaps:
new_edge = getParallel(edge)
if new_edge not in orig_swaps:
raise Exception('Cannot move a parallel edge without the other')
new_set.append(new_edge)
swaps.remove(new_edge)
else:
new_set.append(edge)
return new_set
# swaps edges from one pool to another
orig_swaps = copy.deepcopy(swaps)
new_groups = {}
for group in groups.keys():
new_groups[group] = ([],[])
for group in groups.keys():
(mode, wrld, dir, terrain, parallel, count) = group
for (forward_set, back_set) in zip(groups[group][0], groups[group][1]):
anyF = any(edge in orig_swaps for edge in forward_set)
anyB = any(edge in orig_swaps for edge in back_set)
allF = all(edge in orig_swaps for edge in forward_set)
allB = all(edge in orig_swaps for edge in back_set)
if not (anyF or anyB):
# no change
new_groups[group][0].append(forward_set)
new_groups[group][1].append(back_set)
elif allF and allB:
# move both sets
if parallel == IsParallel.Yes and not (all(edge in orig_swaps for edge in map(getParallel, forward_set)) and all(edge in orig_swaps for edge in map(getParallel, back_set))):
raise Exception('Cannot move a parallel edge without the other')
new_groups[(OpenStd.Open, WorldType((int(wrld) + 1) % 2), dir, terrain, parallel, count)][0].append(forward_set)
new_groups[(OpenStd.Open, WorldType((int(wrld) + 1) % 2), dir, terrain, parallel, count)][1].append(back_set)
for edge in forward_set:
swaps.remove(edge)
for edge in back_set:
swaps.remove(edge)
elif anyF or anyB:
if parallel == IsParallel.Yes:
if allF or allB:
# move one set
if allF and not (world.owKeepSimilar[player] and anyB):
(new_forward_set, new_back_set) = getNewSets(forward_set, back_set)
elif allB and not (world.owKeepSimilar[player] and anyF):
(new_back_set, new_forward_set) = getNewSets(back_set, forward_set)
else:
raise Exception('Cannot move an edge out of a Similar group')
new_groups[group][0].append(new_forward_set)
new_groups[group][1].append(new_back_set)
else:
# move individual edges
if not world.owKeepSimilar[player]:
new_groups[group][0].append(getNewSet(forward_set) if anyF else forward_set)
new_groups[group][1].append(getNewSet(back_set) if anyB else back_set)
else:
raise Exception('Cannot move an edge out of a Similar group')
else:
raise NotImplementedError('Cannot move one side of a non-parallel connection')
else:
raise NotImplementedError('Invalid OW Edge swap scenario')
groups = new_groups
tile_groups = reorganize_tile_groups(world, player)
trimmed_groups = copy.deepcopy(OWEdgeGroups)
swapped_edges = list()
# restructure Maze Race/Suburb/Frog/Dig Game manually due to NP/P relationship
if world.owKeepSimilar[player]:
for group in trimmed_groups.keys():
(std, region, axis, terrain, parallel, _) = group
if parallel == IsParallel.Yes:
(forward_edges, back_edges) = trimmed_groups[group]
if ['Maze Race ES'] in forward_edges:
forward_edges = list(filter((['Maze Race ES']).__ne__, forward_edges))
trimmed_groups[(std, region, axis, terrain, IsParallel.No, 1)][0].append(['Maze Race ES'])
if ['Kakariko Suburb WS'] in back_edges:
back_edges = list(filter((['Kakariko Suburb WS']).__ne__, back_edges))
trimmed_groups[(std, region, axis, terrain, IsParallel.No, 1)][1].append(['Kakariko Suburb WS'])
trimmed_groups[group] = (forward_edges, back_edges)
else:
for group in trimmed_groups.keys(): for group in trimmed_groups.keys():
(std, region, axis, terrain, _, _) = group (std, region, axis, terrain, _, _) = group
(forward_edges, back_edges) = trimmed_groups[group] (forward_edges, back_edges) = trimmed_groups[group]
@@ -29,131 +127,17 @@ def link_overworld(world, player):
trimmed_groups[group] = (forward_edges, back_edges) trimmed_groups[group] = (forward_edges, back_edges)
# tile shuffle # tile shuffle
logging.getLogger('').debug('Swapping overworld tiles')
if world.owMixed[player]: if world.owMixed[player]:
tile_groups = {} swapped_edges = shuffle_tiles(world, tile_groups, world.owswaps[player], player)
for (name, groupType) in OWTileGroups.keys():
if world.mode[player] != 'standard' or name not in ['Castle', 'Links', 'Central Bonk Rocks']:
if world.shuffle[player] in ['vanilla', 'simple', 'dungeonssimple']:
tile_groups[(name,)] = ([], [], [])
else:
tile_groups[(name, groupType)] = ([], [], [])
for (name, groupType) in OWTileGroups.keys(): # move swapped regions/edges to other world
if world.mode[player] != 'standard' or name not in ['Castle', 'Links', 'Central Bonk Rocks']: performSwap(trimmed_groups, swapped_edges)
(lw_owids, dw_owids) = OWTileGroups[(name, groupType,)] assert len(swapped_edges) == 0, 'Not all edges were swapped successfully: ' + ', '.join(swapped_edges )
if world.shuffle[player] in ['vanilla', 'simple', 'dungeonssimple']:
(exist_owids, exist_lw_regions, exist_dw_regions) = tile_groups[(name,)]
exist_owids.extend(lw_owids)
exist_owids.extend(dw_owids)
for owid in lw_owids:
exist_lw_regions.extend(OWTileRegions.inverse[owid])
for owid in dw_owids:
exist_dw_regions.extend(OWTileRegions.inverse[owid])
tile_groups[(name,)] = (exist_owids, exist_lw_regions, exist_dw_regions)
else:
(exist_owids, exist_lw_regions, exist_dw_regions) = tile_groups[(name, groupType)]
exist_owids.extend(lw_owids)
exist_owids.extend(dw_owids)
for owid in lw_owids:
exist_lw_regions.extend(OWTileRegions.inverse[owid])
for owid in dw_owids:
exist_dw_regions.extend(OWTileRegions.inverse[owid])
tile_groups[(name, groupType)] = (exist_owids, exist_lw_regions, exist_dw_regions)
# tile shuffle happens here, the groups that remain in the list are the tiles that get swapped
removed = list()
for group in tile_groups.keys():
if random.randint(0, 1):
removed.append(group)
for group in removed:
tile_groups.pop(group, None)
# save shuffled tiles to world object
for group in tile_groups.keys():
(owids, lw_regions, dw_regions) = tile_groups[group]
(exist_owids, exist_lw_regions, exist_dw_regions) = world.owswaps[player]
exist_owids.extend(owids)
exist_lw_regions.extend(lw_regions)
exist_dw_regions.extend(dw_regions)
world.owswaps[player] = [exist_owids, exist_lw_regions, exist_dw_regions]
# replace LW edges with DW
ignore_list = list() #TODO: Remove ignore_list when special OW areas are included in pool
for edgeset in temporary_mandatory_connections:
for edge in edgeset:
ignore_list.append(edge)
swapped_edges = list()
def getSwappedEdges(world, lst, player):
for regionname in lst:
region = world.get_region(regionname, player)
for exit in region.exits:
if exit.spot_type == 'OWEdge' and exit.name not in ignore_list:
swapped_edges.append(exit.name)
getSwappedEdges(world, world.owswaps[player][1], player)
getSwappedEdges(world, world.owswaps[player][2], player)
def performSwap(groups, swaps, nonParallelOnly=False):
try:
for group in groups.keys():
(mode, wrld, dir, terrain, parallel, count) = group
for p in range(0, len(groups[group])):
edgepool = groups[group][p]
for s in range(0, len(edgepool)):
if s <= len(edgepool):
for e in range(0, len(edgepool[s])):
if len(edgepool) > 0 and edgepool[s][e] in swaps:
if parallel == IsParallel.Yes:
if not nonParallelOnly:
if wrld == WorldType.Light and edgepool[s][e] in parallel_links:
logging.getLogger('').debug('%s was moved', edgepool[s][e])
swaps.remove(edgepool[s][e])
groups[group][p][s][e] = parallel_links[edgepool[s][e]]
elif wrld == WorldType.Dark and edgepool[s][e] in parallel_links.inverse:
logging.getLogger('').debug('%s was moved', edgepool[s][e])
swaps.remove(edgepool[s][e])
groups[group][p][s][e] = parallel_links.inverse[edgepool[s][e]][0]
else:
for edge in edgepool[s]:
logging.getLogger('').debug('%s was moved', edge)
swaps.remove(edge)
groups[(mode, WorldType((int(wrld) + 1) % 2), dir, terrain, parallel, count)][p].append(edgepool[s])
groups[group][p].remove(edgepool[s])
except IndexError:
#TODO: Figure out a way to handle index changes on the fly when removing items
logging.getLogger('').warning('OW Tile Swap encountered minor IndexError... retrying')
if world.owShuffle[player] != 'parallel' and 0x28 in world.owswaps[player][0]: # handle Frog/Dig Game swap manually due to NP/P relationship with LW
trimmed_groups[(OpenStd.Open, WorldType.Dark, PolSlot.EastWest, Terrain.Land, IsParallel.Yes, 1)][0].append(['Maze Race ES'])
trimmed_groups[(OpenStd.Open, WorldType.Dark, PolSlot.EastWest, Terrain.Land, IsParallel.Yes, 1)][1].append(['Kakariko Suburb WS'])
trimmed_groups[(OpenStd.Open, WorldType.Light, PolSlot.EastWest, Terrain.Land, IsParallel.Yes, 1)][0].remove(['Maze Race ES'])
trimmed_groups[(OpenStd.Open, WorldType.Light, PolSlot.EastWest, Terrain.Land, IsParallel.Yes, 1)][1].remove(['Kakariko Suburb WS'])
trimmed_groups[(OpenStd.Open, WorldType.Light, PolSlot.EastWest, Terrain.Land, IsParallel.No, 2)][0].append(['Dig Game EC', 'Dig Game ES'])
trimmed_groups[(OpenStd.Open, WorldType.Light, PolSlot.EastWest, Terrain.Land, IsParallel.No, 2)][1].append(['Frog WC', 'Frog WS'])
trimmed_groups[(OpenStd.Open, WorldType.Dark, PolSlot.EastWest, Terrain.Land, IsParallel.No, 2)] = [[],[]]
swapped_edges.remove('Maze Race ES')
swapped_edges.remove('Kakariko Suburb WS')
swapped_edges.remove('Dig Game EC')
swapped_edges.remove('Dig Game ES')
swapped_edges.remove('Frog WC')
swapped_edges.remove('Frog WS')
tries = 5
while tries > 0:
performSwap(trimmed_groups, swapped_edges)
if len(swapped_edges) == 0:
tries = 0
continue
tries -= 1
assert len(swapped_edges) == 0
#move swapped regions to other world
update_world_regions(world, player) update_world_regions(world, player)
# make new connections # apply tile logical connections
for owid in ow_connections.keys(): for owid in ow_connections.keys():
if (world.mode[player] == 'inverted') == (owid in world.owswaps[player][0] and world.owMixed[player]): if (world.mode[player] == 'inverted') == (owid in world.owswaps[player][0] and world.owMixed[player]):
for (exitname, regionname) in ow_connections[owid][0]: for (exitname, regionname) in ow_connections[owid][0]:
@@ -162,10 +146,50 @@ def link_overworld(world, player):
for (exitname, regionname) in ow_connections[owid][1]: for (exitname, regionname) in ow_connections[owid][1]:
connect_simple(world, exitname, regionname, player) connect_simple(world, exitname, regionname, player)
connected_edges = [] # crossed shuffle
logging.getLogger('').debug('Crossing overworld edges')
if world.owCrossed[player] in ['grouped', 'limited']:
if world.owCrossed[player] == 'grouped':
crossed_edges = shuffle_tiles(world, tile_groups, [[],[],[]], player)
elif world.owCrossed[player] in ['limited', 'chaos']:
crossed_edges = list()
crossed_candidates = list()
for group in trimmed_groups.keys():
(mode, wrld, dir, terrain, parallel, count) = group
if parallel == IsParallel.Yes and wrld == WorldType.Light and (mode == OpenStd.Open or world.mode[player] != 'standard'):
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)
else:
for edge in forward_set:
if world.owCrossed[player] == 'chaos' and random.randint(0, 1):
crossed_edges.append(edge)
elif world.owCrossed[player] == 'limited':
crossed_candidates.append(forward_set)
break
if world.owCrossed[player] == 'limited':
random.shuffle(crossed_candidates)
for edge_set in crossed_candidates[:9]:
for edge in edge_set:
crossed_edges.append(edge)
for edge in copy.deepcopy(crossed_edges):
if edge in parallel_links:
crossed_edges.append(parallel_links[edge])
elif edge in parallel_links.inverse:
crossed_edges.append(parallel_links.inverse[edge][0])
performSwap(trimmed_groups, crossed_edges)
assert len(crossed_edges) == 0, 'Not all edges were crossed successfully: ' + ', '.join(crossed_edges)
# layout shuffle # layout shuffle
if world.owShuffle[player] == 'vanilla' and not world.owCrossed[player]: logging.getLogger('').debug('Shuffling overworld layout')
connected_edges = []
if world.owShuffle[player] == 'vanilla':
# vanilla transitions # vanilla transitions
groups = list(trimmed_groups.values()) groups = list(trimmed_groups.values())
for (forward_edge_sets, back_edge_sets) in groups: for (forward_edge_sets, back_edge_sets) in groups:
@@ -174,100 +198,61 @@ def link_overworld(world, player):
assert len(forward_set) == len(back_set) assert len(forward_set) == len(back_set)
for (forward_edge, back_edge) in zip(forward_set, back_set): for (forward_edge, back_edge) in zip(forward_set, back_set):
connect_two_way(world, forward_edge, back_edge, player, connected_edges) connect_two_way(world, forward_edge, back_edge, player, connected_edges)
assert len(connected_edges) == len(default_connections) * 2, connected_edges
else: else:
if world.owKeepSimilar[player] and world.owShuffle[player] == 'parallel': if world.owKeepSimilar[player] and world.owShuffle[player] in ['vanilla', 'parallel']:
for exitname, destname in parallelsimilar_connections: for exitname, destname in parallelsimilar_connections:
connect_two_way(world, exitname, destname, player, connected_edges) connect_two_way(world, exitname, destname, player, connected_edges)
if world.owShuffle[player] == 'vanilla' and world.owCrossed[player]:
if world.mode[player] == 'standard':
# connect vanilla std
for group in trimmed_groups.keys():
(std, _, _, _, _, _) = group
if std == OpenStd.Standard:
(forward_set, back_set) = trimmed_groups[group]
for (forward_edges, back_edges) in zip(forward_set, back_set):
for (forward_edge, back_edge) in zip(forward_edges, back_edges):
connect_two_way(world, forward_edge, back_edge, player, connected_edges)
# connect non-parallel edges
for group in trimmed_groups.keys():
(_, _, _, _, parallel, _) = group
if parallel == IsParallel.No:
(forward_set, back_set) = trimmed_groups[group]
for (forward_edges, back_edges) in zip(forward_set, back_set):
for (forward_edge, back_edge) in zip(forward_edges, back_edges):
if forward_edge not in connected_edges and back_edge not in connected_edges:
connect_two_way(world, forward_edge, back_edge, player, connected_edges)
#TODO: Remove, just for testing #TODO: Remove, just for testing
for exitname, destname in test_connections: for exitname, destname in test_connections:
connect_two_way(world, exitname, destname, player, connected_edges) connect_two_way(world, exitname, destname, player, connected_edges)
connect_custom(world, connected_edges, player) connect_custom(world, connected_edges, player)
# layout shuffle
trimmed_groups = remove_reserved(world, trimmed_groups, connected_edges, player) trimmed_groups = remove_reserved(world, trimmed_groups, connected_edges, player)
groups = reorganize_groups(world, trimmed_groups, player) groups = reorganize_groups(world, trimmed_groups, player)
# all layout shuffling occurs here if world.mode[player] == 'standard':
if world.owShuffle[player] != 'vanilla': random.shuffle(groups[2:]) # keep first 2 groups (Standard) first
# layout shuffle
if world.mode[player] == 'standard':
random.shuffle(groups[2:]) # keep first 2 groups (Standard) first
else:
random.shuffle(groups)
for (forward_edge_sets, back_edge_sets) in groups:
assert len(forward_edge_sets) == len(back_edge_sets)
random.shuffle(forward_edge_sets)
random.shuffle(back_edge_sets)
if len(forward_edge_sets) > 0:
f = 0
b = 0
while f < len(forward_edge_sets) and b < len(back_edge_sets):
forward_set = forward_edge_sets[f]
back_set = back_edge_sets[b]
while forward_set[0] in connected_edges:
f += 1
if f < len(forward_edge_sets):
forward_set = forward_edge_sets[f]
else:
forward_set = None
break
f += 1
while back_set[0] in connected_edges:
b += 1
if b < len(back_edge_sets):
back_set = back_edge_sets[b]
else:
back_set = None
break
b += 1
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])
else: else:
# vanilla/crossed shuffle random.shuffle(groups)
for (forward_edge_sets, back_edge_sets) in groups:
assert len(forward_edge_sets) == len(back_edge_sets)
for (forward_set, back_set) in zip(forward_edge_sets, back_edge_sets):
assert len(forward_set) == len(back_set)
swapped = random.randint(0, 1)
for (forward_edge, back_edge) in zip(forward_set, back_set):
if forward_edge not in connected_edges and back_edge not in connected_edges:
if swapped:
forward_edge = parallel_links[forward_edge] if forward_edge in parallel_links else parallel_links.inverse[forward_edge][0]
connect_two_way(world, forward_edge, back_edge, player, connected_edges)
assert len(connected_edges) == len(default_connections) * 2, connected_edges for (forward_edge_sets, back_edge_sets) in groups:
assert len(forward_edge_sets) == len(back_edge_sets)
random.shuffle(forward_edge_sets)
random.shuffle(back_edge_sets)
if len(forward_edge_sets) > 0:
f = 0
b = 0
while f < len(forward_edge_sets) and b < len(back_edge_sets):
forward_set = forward_edge_sets[f]
back_set = back_edge_sets[b]
while forward_set[0] in connected_edges:
f += 1
if f < len(forward_edge_sets):
forward_set = forward_edge_sets[f]
else:
forward_set = None
break
f += 1
while back_set[0] in connected_edges:
b += 1
if b < len(back_edge_sets):
back_set = back_edge_sets[b]
else:
back_set = None
break
b += 1
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])
assert len(connected_edges) == len(default_connections) * 2, connected_edges
# flute shuffle # flute shuffle
def connect_flutes(flute_destinations): def connect_flutes(flute_destinations):
@@ -352,6 +337,19 @@ def connect_simple(world, exitname, regionname, player):
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)
edge2 = world.get_entrance(edgename2, player) edge2 = world.get_entrance(edgename2, player)
x = world.check_for_owedge(edgename1, player)
y = world.check_for_owedge(edgename2, player)
if x is None:
raise Exception('%s is not a valid edge.', edgename1)
elif y is None:
raise Exception('%s is not a valid edge.', edgename2)
if connected_edges is not None:
if edgename1 in connected_edges or edgename2 in connected_edges:
if (x.dest and x.dest.name == edgename2) and (y.dest and y.dest.name == edgename1):
return
else:
raise Exception('Edges \'%s\' and \'%s\' already connected elsewhere', edgename1, edgename2)
# if these were already connected somewhere, remove the backreference # if these were already connected somewhere, remove the backreference
if edge1.connected_region is not None: if edge1.connected_region is not None:
@@ -361,17 +359,10 @@ def connect_two_way(world, edgename1, edgename2, player, connected_edges=None):
edge1.connect(edge2.parent_region) edge1.connect(edge2.parent_region)
edge2.connect(edge1.parent_region) edge2.connect(edge1.parent_region)
x = world.check_for_owedge(edgename1, player) x.dest = y
y = world.check_for_owedge(edgename2, player) y.dest = x
if x is None:
logging.getLogger('').error('%s is not a valid edge.', edgename1)
elif y is None:
logging.getLogger('').error('%s is not a valid edge.', edgename2)
else:
x.dest = y
y.dest = x
if world.owShuffle[player] != 'vanilla' or world.owMixed[player] or world.owCrossed[player]: if world.owShuffle[player] != 'vanilla' or world.owMixed[player] or world.owCrossed[player] != 'none':
world.spoiler.set_overworld(edgename2, edgename1, 'both', player) world.spoiler.set_overworld(edgename2, edgename1, 'both', player)
if connected_edges is not None: if connected_edges is not None:
@@ -379,7 +370,7 @@ def connect_two_way(world, edgename1, edgename2, player, connected_edges=None):
connected_edges.append(edgename2) connected_edges.append(edgename2)
# connecting parallel connections # connecting parallel connections
if world.owShuffle[player] == 'parallel' or (world.owShuffle[player] == 'vanilla' and world.owCrossed[player]): if world.owShuffle[player] in ['vanilla', 'parallel']:
if (edgename1 in parallel_links.keys() or edgename1 in parallel_links.inverse.keys()): if (edgename1 in parallel_links.keys() or edgename1 in parallel_links.inverse.keys()):
try: try:
parallel_forward_edge = parallel_links[edgename1] if edgename1 in parallel_links.keys() else parallel_links.inverse[edgename1][0] parallel_forward_edge = parallel_links[edgename1] if edgename1 in parallel_links.keys() else parallel_links.inverse[edgename1][0]
@@ -390,6 +381,77 @@ def connect_two_way(world, edgename1, edgename2, player, connected_edges=None):
# TODO: Figure out why non-parallel edges are getting into parallel groups # TODO: Figure out why non-parallel edges are getting into parallel groups
raise KeyError('No parallel edge for edge %s' % edgename2) raise KeyError('No parallel edge for edge %s' % edgename2)
def shuffle_tiles(world, groups, result_list, player):
swapped_edges = list()
# tile shuffle happens here
removed = list()
for group in groups.keys():
if random.randint(0, 1):
removed.append(group)
# save shuffled tiles to list
for group in groups.keys():
if group not in removed:
(owids, lw_regions, dw_regions) = groups[group]
(exist_owids, exist_lw_regions, exist_dw_regions) = result_list
exist_owids.extend(owids)
exist_lw_regions.extend(lw_regions)
exist_dw_regions.extend(dw_regions)
result_list = [exist_owids, exist_lw_regions, exist_dw_regions]
# replace LW edges with DW
ignore_list = list() #TODO: Remove ignore_list when special OW areas are included in pool
for edgeset in temporary_mandatory_connections:
for edge in edgeset:
ignore_list.append(edge)
if world.owCrossed[player] != 'polar':
# in polar, the actual edge connections remain vanilla
def getSwappedEdges(world, lst, player):
for regionname in lst:
region = world.get_region(regionname, player)
for exit in region.exits:
if exit.spot_type == 'OWEdge' and exit.name not in ignore_list:
swapped_edges.append(exit.name)
getSwappedEdges(world, result_list[1], player)
getSwappedEdges(world, result_list[2], player)
return swapped_edges
def reorganize_tile_groups(world, player):
groups = {}
for (name, groupType) in OWTileGroups.keys():
if world.mode[player] != 'standard' or name not in ['Castle', 'Links', 'Central Bonk Rocks']:
if world.shuffle[player] in ['vanilla', 'simple', 'dungeonssimple']:
groups[(name,)] = ([], [], [])
else:
groups[(name, groupType)] = ([], [], [])
for (name, groupType) in OWTileGroups.keys():
if world.mode[player] != 'standard' or name not in ['Castle', 'Links', 'Central Bonk Rocks']:
(lw_owids, dw_owids) = OWTileGroups[(name, groupType,)]
if world.shuffle[player] in ['vanilla', 'simple', 'dungeonssimple']:
(exist_owids, exist_lw_regions, exist_dw_regions) = groups[(name,)]
exist_owids.extend(lw_owids)
exist_owids.extend(dw_owids)
for owid in lw_owids:
exist_lw_regions.extend(OWTileRegions.inverse[owid])
for owid in dw_owids:
exist_dw_regions.extend(OWTileRegions.inverse[owid])
groups[(name,)] = (exist_owids, exist_lw_regions, exist_dw_regions)
else:
(exist_owids, exist_lw_regions, exist_dw_regions) = groups[(name, groupType)]
exist_owids.extend(lw_owids)
exist_owids.extend(dw_owids)
for owid in lw_owids:
exist_lw_regions.extend(OWTileRegions.inverse[owid])
for owid in dw_owids:
exist_dw_regions.extend(OWTileRegions.inverse[owid])
groups[(name, groupType)] = (exist_owids, exist_lw_regions, exist_dw_regions)
return groups
def remove_reserved(world, groupedlist, connected_edges, player): def remove_reserved(world, groupedlist, connected_edges, player):
new_grouping = {} new_grouping = {}
for group in groupedlist.keys(): for group in groupedlist.keys():
@@ -405,7 +467,7 @@ def remove_reserved(world, groupedlist, connected_edges, player):
back_edges = list(list(filter((edge).__ne__, i)) for i in back_edges) back_edges = list(list(filter((edge).__ne__, i)) for i in back_edges)
# remove parallel edges from pool, since they get added during shuffle # remove parallel edges from pool, since they get added during shuffle
if (not world.owCrossed[player] and world.owShuffle[player] == 'parallel') and region == WorldType.Dark: if world.owShuffle[player] == 'parallel' and region == WorldType.Dark:
for edge in parallel_links: for edge in parallel_links:
forward_edges = list(list(filter((parallel_links[edge]).__ne__, i)) for i in forward_edges) forward_edges = list(list(filter((parallel_links[edge]).__ne__, i)) for i in forward_edges)
back_edges = list(list(filter((parallel_links[edge]).__ne__, i)) for i in back_edges) back_edges = list(list(filter((parallel_links[edge]).__ne__, i)) for i in back_edges)
@@ -428,250 +490,87 @@ def reorganize_groups(world, groups, player):
# predefined shuffle groups get reorganized here # predefined shuffle groups get reorganized here
# this restructures the candidate pool based on the chosen settings # this restructures the candidate pool based on the chosen settings
if world.owShuffle[player] == 'full': if world.owShuffle[player] == 'full':
if world.owCrossed[player]:
if world.owKeepSimilar[player]:
if world.mode[player] == 'standard':
# tuple goes to (A,_,C,D,_,F)
for grouping in (groups,):
new_grouping = {}
for group in grouping.keys():
(std, _, axis, terrain, _, count) = group
new_grouping[(std, axis, terrain, count)] = ([], [])
for group in grouping.keys():
(std, _, axis, terrain, _, count) = group
(forward_edges, back_edges) = grouping[group]
(exist_forward_edges, exist_back_edges) = new_grouping[(std, axis, terrain, count)]
exist_forward_edges.extend(forward_edges)
exist_back_edges.extend(back_edges)
new_grouping[(std, axis, terrain, count)] = (exist_forward_edges, exist_back_edges)
return list(new_grouping.values())
else:
# tuple goes to (_,_,C,D,_,F)
for grouping in (groups,):
new_grouping = {}
for group in grouping.keys():
(_, _, axis, terrain, _, count) = group
new_grouping[(axis, terrain, count)] = ([], [])
for group in grouping.keys():
(_, _, axis, terrain, _, count) = group
(forward_edges, back_edges) = grouping[group]
(exist_forward_edges, exist_back_edges) = new_grouping[(axis, terrain, count)]
exist_forward_edges.extend(forward_edges)
exist_back_edges.extend(back_edges)
new_grouping[(axis, terrain, count)] = (exist_forward_edges, exist_back_edges)
return list(new_grouping.values())
else:
if world.mode[player] == 'standard':
# tuple goes to (A,_,C,D,_,_)
for grouping in (groups,):
new_grouping = {}
for group in grouping.keys():
(std, _, axis, terrain, _, _) = group
new_grouping[(std, axis, terrain)] = ([], [])
for group in grouping.keys():
(std, _, axis, terrain, _, _) = group
(forward_edges, back_edges) = grouping[group]
forward_edges = [[i] for l in forward_edges for i in l]
back_edges = [[i] for l in back_edges for i in l]
(exist_forward_edges, exist_back_edges) = new_grouping[(std, axis, terrain)]
exist_forward_edges.extend(forward_edges)
exist_back_edges.extend(back_edges)
new_grouping[(std, axis, terrain)] = (exist_forward_edges, exist_back_edges)
return list(new_grouping.values())
else:
# tuple goes to (_,_,C,D,_,_)
for grouping in (groups,):
new_grouping = {}
for group in grouping.keys():
(_, _, axis, terrain, _, _) = group
new_grouping[(axis, terrain)] = ([], [])
for group in grouping.keys():
(_, _, axis, terrain, _, _) = group
(forward_edges, back_edges) = grouping[group]
forward_edges = [[i] for l in forward_edges for i in l]
back_edges = [[i] for l in back_edges for i in l]
(exist_forward_edges, exist_back_edges) = new_grouping[(axis, terrain)]
exist_forward_edges.extend(forward_edges)
exist_back_edges.extend(back_edges)
new_grouping[(axis, terrain)] = (exist_forward_edges, exist_back_edges)
return list(new_grouping.values())
else:
if world.owKeepSimilar[player]:
if world.mode[player] == 'standard':
# tuple goes to (A,B,C,D,_,F)
for grouping in (groups,):
new_grouping = {}
for group in grouping.keys():
(std, region, axis, terrain, _, count) = group
new_grouping[(std, region, axis, terrain, count)] = ([], [])
for group in grouping.keys():
(std, region, axis, terrain, _, count) = group
(forward_edges, back_edges) = grouping[group]
(exist_forward_edges, exist_back_edges) = new_grouping[(std, region, axis, terrain, count)]
exist_forward_edges.extend(forward_edges)
exist_back_edges.extend(back_edges)
new_grouping[(std, region, axis, terrain, count)] = (exist_forward_edges, exist_back_edges)
return list(new_grouping.values())
else:
# tuple goes to (_,B,C,D,_,F)
for grouping in (groups,):
new_grouping = {}
for group in grouping.keys():
(_, region, axis, terrain, _, count) = group
new_grouping[(region, axis, terrain, count)] = ([], [])
for group in grouping.keys():
(_, region, axis, terrain, _, count) = group
(forward_edges, back_edges) = grouping[group]
(exist_forward_edges, exist_back_edges) = new_grouping[(region, axis, terrain, count)]
exist_forward_edges.extend(forward_edges)
exist_back_edges.extend(back_edges)
new_grouping[(region, axis, terrain, count)] = (exist_forward_edges, exist_back_edges)
return list(new_grouping.values())
else:
if world.mode[player] == 'standard':
# tuple goes to (A,B,C,D,_,_)
for grouping in (groups,):
new_grouping = {}
for group in grouping.keys():
(std, region, axis, terrain, _, _) = group
new_grouping[(std, region, axis, terrain)] = ([], [])
for group in grouping.keys():
(std, region, axis, terrain, _, _) = group
(forward_edges, back_edges) = grouping[group]
forward_edges = [[i] for l in forward_edges for i in l]
back_edges = [[i] for l in back_edges for i in l]
(exist_forward_edges, exist_back_edges) = new_grouping[(std, region, axis, terrain)]
exist_forward_edges.extend(forward_edges)
exist_back_edges.extend(back_edges)
new_grouping[(std, region, axis, terrain)] = (exist_forward_edges, exist_back_edges)
return list(new_grouping.values())
else:
# tuple goes to (_,B,C,D,_,_)
for grouping in (groups,):
new_grouping = {}
for group in grouping.keys():
(_, region, axis, terrain, _, _) = group
new_grouping[(region, axis, terrain)] = ([], [])
for group in grouping.keys():
(_, region, axis, terrain, _, _) = group
(forward_edges, back_edges) = grouping[group]
forward_edges = [[i] for l in forward_edges for i in l]
back_edges = [[i] for l in back_edges for i in l]
(exist_forward_edges, exist_back_edges) = new_grouping[(region, axis, terrain)]
exist_forward_edges.extend(forward_edges)
exist_back_edges.extend(back_edges)
new_grouping[(region, axis, terrain)] = (exist_forward_edges, exist_back_edges)
return list(new_grouping.values())
elif world.owShuffle[player] == 'parallel' and world.owCrossed[player]:
if world.owKeepSimilar[player]: if world.owKeepSimilar[player]:
if world.mode[player] == 'standard': if world.mode[player] == 'standard':
# tuple goes to (A,_,C,D,E,F) # tuple goes to (A,B,C,D,_,F)
for grouping in (groups,): for grouping in (groups,):
new_grouping = {} new_grouping = {}
for group in grouping.keys(): for group in grouping.keys():
(std, _, axis, terrain, parallel, count) = group (std, region, axis, terrain, _, count) = group
new_grouping[(std, axis, terrain, parallel, count)] = ([], []) new_grouping[(std, region, axis, terrain, count)] = ([], [])
for group in grouping.keys(): for group in grouping.keys():
(std, _, axis, terrain, parallel, count) = group (std, region, axis, terrain, _, count) = group
(forward_edges, back_edges) = grouping[group] (forward_edges, back_edges) = grouping[group]
(exist_forward_edges, exist_back_edges) = new_grouping[(std, axis, terrain, parallel, count)] (exist_forward_edges, exist_back_edges) = new_grouping[(std, region, axis, terrain, count)]
exist_forward_edges.extend(forward_edges) exist_forward_edges.extend(forward_edges)
exist_back_edges.extend(back_edges) exist_back_edges.extend(back_edges)
new_grouping[(std, axis, terrain, parallel, count)] = (exist_forward_edges, exist_back_edges) new_grouping[(std, region, axis, terrain, count)] = (exist_forward_edges, exist_back_edges)
return list(new_grouping.values()) return list(new_grouping.values())
else: else:
# tuple goes to (_,_,C,D,E,F) # tuple goes to (_,B,C,D,_,F)
for grouping in (groups,): for grouping in (groups,):
new_grouping = {} new_grouping = {}
for group in grouping.keys(): for group in grouping.keys():
(_, _, axis, terrain, parallel, count) = group (_, region, axis, terrain, _, count) = group
new_grouping[(axis, terrain, parallel, count)] = ([], []) new_grouping[(region, axis, terrain, count)] = ([], [])
for group in grouping.keys(): for group in grouping.keys():
(_, _, axis, terrain, parallel, count) = group (_, region, axis, terrain, _, count) = group
(forward_edges, back_edges) = grouping[group] (forward_edges, back_edges) = grouping[group]
(exist_forward_edges, exist_back_edges) = new_grouping[(axis, terrain, parallel, count)] (exist_forward_edges, exist_back_edges) = new_grouping[(region, axis, terrain, count)]
exist_forward_edges.extend(forward_edges) exist_forward_edges.extend(forward_edges)
exist_back_edges.extend(back_edges) exist_back_edges.extend(back_edges)
new_grouping[(axis, terrain, parallel, count)] = (exist_forward_edges, exist_back_edges) new_grouping[(region, axis, terrain, count)] = (exist_forward_edges, exist_back_edges)
return list(new_grouping.values()) return list(new_grouping.values())
else: else:
if world.mode[player] == 'standard': if world.mode[player] == 'standard':
# tuple goes to (A,_,C,D,E,_) # tuple goes to (A,B,C,D,_,_)
for grouping in (groups,): for grouping in (groups,):
new_grouping = {} new_grouping = {}
for group in grouping.keys(): for group in grouping.keys():
(std, _, axis, terrain, parallel, _) = group (std, region, axis, terrain, _, _) = group
new_grouping[(std, axis, terrain, parallel)] = ([], []) new_grouping[(std, region, axis, terrain)] = ([], [])
for group in grouping.keys(): for group in grouping.keys():
(std, _, axis, terrain, parallel, _) = group (std, region, axis, terrain, _, _) = group
(forward_edges, back_edges) = grouping[group] (forward_edges, back_edges) = grouping[group]
forward_edges = [[i] for l in forward_edges for i in l] forward_edges = [[i] for l in forward_edges for i in l]
back_edges = [[i] for l in back_edges for i in l] back_edges = [[i] for l in back_edges for i in l]
(exist_forward_edges, exist_back_edges) = new_grouping[(std, axis, terrain, parallel)] (exist_forward_edges, exist_back_edges) = new_grouping[(std, region, axis, terrain)]
exist_forward_edges.extend(forward_edges) exist_forward_edges.extend(forward_edges)
exist_back_edges.extend(back_edges) exist_back_edges.extend(back_edges)
new_grouping[(std, axis, terrain, parallel)] = (exist_forward_edges, exist_back_edges) new_grouping[(std, region, axis, terrain)] = (exist_forward_edges, exist_back_edges)
return list(new_grouping.values()) return list(new_grouping.values())
else: else:
# tuple goes to (_,_,C,D,E,_) # tuple goes to (_,B,C,D,_,_)
for grouping in (groups,): for grouping in (groups,):
new_grouping = {} new_grouping = {}
for group in grouping.keys(): for group in grouping.keys():
(_, _, axis, terrain, parallel, _) = group (_, region, axis, terrain, _, _) = group
new_grouping[(axis, terrain, parallel)] = ([], []) new_grouping[(region, axis, terrain)] = ([], [])
for group in grouping.keys(): for group in grouping.keys():
(_, _, axis, terrain, parallel, _) = group (_, region, axis, terrain, _, _) = group
(forward_edges, back_edges) = grouping[group] (forward_edges, back_edges) = grouping[group]
forward_edges = [[i] for l in forward_edges for i in l] forward_edges = [[i] for l in forward_edges for i in l]
back_edges = [[i] for l in back_edges for i in l] back_edges = [[i] for l in back_edges for i in l]
(exist_forward_edges, exist_back_edges) = new_grouping[(axis, terrain, parallel)] (exist_forward_edges, exist_back_edges) = new_grouping[(region, axis, terrain)]
exist_forward_edges.extend(forward_edges) exist_forward_edges.extend(forward_edges)
exist_back_edges.extend(back_edges) exist_back_edges.extend(back_edges)
new_grouping[(axis, terrain, parallel)] = (exist_forward_edges, exist_back_edges) new_grouping[(region, axis, terrain)] = (exist_forward_edges, exist_back_edges)
return list(new_grouping.values()) return list(new_grouping.values())
elif world.owShuffle[player] == 'parallel' or (world.owShuffle[player] == 'vanilla' and world.owCrossed[player]): elif world.owShuffle[player] == 'parallel':
if world.owKeepSimilar[player]: if world.owKeepSimilar[player]:
if world.mode[player] == 'standard': if world.mode[player] == 'standard':
# tuple stays (A,B,C,D,E,F) # tuple stays (A,B,C,D,E,F)

View File

@@ -162,8 +162,7 @@ def prefill_world(world, plando, text_patches):
world.owShuffle = {1: modestr.strip()} world.owShuffle = {1: modestr.strip()}
elif line.startswith('!owCrossed'): elif line.startswith('!owCrossed'):
_, modestr = line.split(':', 1) _, modestr = line.split(':', 1)
modestr = modestr.strip().lower() world.owCrossed = {1: modestr.strip()}
world.owCrossed = {1: True if modestr in ('true', 'yes', 'on', 'enabled') else False}
elif line.startswith('!owKeepSimilar'): elif line.startswith('!owKeepSimilar'):
_, modestr = line.split(':', 1) _, modestr = line.split(':', 1)
modestr = modestr.strip().lower() modestr = modestr.strip().lower()

View File

@@ -246,6 +246,6 @@ Ganon: Triforce
# set Overworld connections (lines starting with $, separate edges with =) # set Overworld connections (lines starting with $, separate edges with =)
!owShuffle: parallel !owShuffle: parallel
#!owMixed: true # Mixed OW not supported yet #!owMixed: true # Mixed OW not supported yet
!owCrossed: true !owCrossed: none
!owKeepSimilar: true !owKeepSimilar: true
$Links House NE = Kakariko Village SE $Links House NE = Kakariko Village SE

6
Rom.py
View File

@@ -646,16 +646,16 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
# patch overworld edges # patch overworld edges
inverted_buffer = [0] * 0x82 inverted_buffer = [0] * 0x82
if world.owShuffle[player] != 'vanilla' or world.owCrossed[player] or world.owMixed[player]: if world.owShuffle[player] != 'vanilla' or world.owCrossed[player] != 'none' or world.owMixed[player]:
owMode = 0 owMode = 0
if world.owShuffle[player] == 'parallel': if world.owShuffle[player] == 'parallel':
owMode = 1 owMode = 1
elif world.owShuffle[player] == 'full': elif world.owShuffle[player] == 'full':
owMode = 2 owMode = 2
if world.owKeepSimilar[player] and (world.owShuffle[player] != 'vanilla' or world.owCrossed[player]): if world.owKeepSimilar[player] and (world.owShuffle[player] != 'vanilla' or world.owCrossed[player] in ['limited', 'chaos']):
owMode |= 0x100 owMode |= 0x100
if world.owCrossed[player]: if world.owCrossed[player] != 'none':
owMode |= 0x200 owMode |= 0x200
world.fix_fake_world[player] = True world.fix_fake_world[player] = True
if world.owMixed[player]: if world.owMixed[player]:

View File

@@ -2053,7 +2053,7 @@ def set_inverted_big_bomb_rules(world, player):
else: else:
raise Exception('No logic found for routing from %s to the pyramid.' % bombshop_entrance.name) raise Exception('No logic found for routing from %s to the pyramid.' % bombshop_entrance.name)
if world.owShuffle[player] != 'vanilla' or world.owMixed[player] or world.owCrossed[player]: if world.owShuffle[player] != 'vanilla' or world.owMixed[player] or world.owCrossed[player] != 'none':
add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: False) #temp disable progression until routing to Pyramid get be guaranteed add_rule(world.get_entrance('Pyramid Fairy', player), lambda state: False) #temp disable progression until routing to Pyramid get be guaranteed

View File

@@ -117,8 +117,13 @@
] ]
}, },
"ow_crossed": { "ow_crossed": {
"action": "store_true", "choices": [
"type": "bool" "none",
"polar",
"grouped",
"limited",
"chaos"
]
}, },
"ow_keepsimilar": { "ow_keepsimilar": {
"action": "store_true", "action": "store_true",

View File

@@ -202,7 +202,15 @@
" will have an independent map shape." " will have an independent map shape."
], ],
"ow_crossed": [ "ow_crossed": [
"This allows cross-world connections to occur on the overworld." ], "This allows cross-world connections to occur on the overworld.",
"None: No transitions are cross-world connections.",
"Polar: Only used when Mixed is enabled. This retains original",
" connections even when overworld tiles are swapped.",
"Limited: Exactly nine transitions are randomly chosen as",
" cross-world connections (to emulate the nine portals).",
"Chaos: Every transition has a 50/50 chance to become a",
" crossworld connection."
],
"ow_keepsimilar": [ "ow_keepsimilar": [
"This keeps similar edge transitions together. ie. the two west edges on", "This keeps similar edge transitions together. ie. the two west edges on",
"Potion Shop will be paired with another similar pair." ], "Potion Shop will be paired with another similar pair." ],

View File

@@ -118,6 +118,11 @@
"randomizer.overworld.overworldshuffle.full": "Full", "randomizer.overworld.overworldshuffle.full": "Full",
"randomizer.overworld.crossed": "Crossed", "randomizer.overworld.crossed": "Crossed",
"randomizer.overworld.crossed.none": "None",
"randomizer.overworld.crossed.polar": "Polar",
"randomizer.overworld.crossed.grouped": "Grouped",
"randomizer.overworld.crossed.limited": "Limited",
"randomizer.overworld.crossed.chaos": "Chaos",
"randomizer.overworld.keepsimilar": "Keep Similar Edges Together", "randomizer.overworld.keepsimilar": "Keep Similar Edges Together",
"randomizer.overworld.mixed": "Mixed", "randomizer.overworld.mixed": "Mixed",

View File

@@ -21,8 +21,15 @@
}, },
"rightOverworldFrame": { "rightOverworldFrame": {
"crossed": { "crossed": {
"type": "checkbox", "type": "selectbox",
"default": false "default": "vanilla",
"options": [
"none",
"polar",
"grouped",
"limited",
"chaos"
]
}, },
"mixed": { "mixed": {
"type": "checkbox", "type": "checkbox",