Merge branch 'pr/8' into OverworldShuffleDev

This commit is contained in:
codemann8
2022-05-14 11:23:30 -05:00
parent ce1e3c23b0
commit 377660a1f5
2 changed files with 221 additions and 377 deletions

View File

@@ -984,289 +984,6 @@ OWTileRegions = bidict({
'Zoras Domain': 0x81 'Zoras Domain': 0x81
}) })
OWTileGroups = {
("Woods", "Regular", "None"): (
[
0x00, 0x2d, 0x80
],
[
0x40, 0x6d
]
),
("Lumberjack", "Regular", "None"): (
[
0x02
],
[
0x42
]
),
("Mountain Entry", "Entrance", "None"): (
[
0x03
],
[
0x43
]
),
("East Mountain", "Regular", "None"): (
[
0x05
],
[
0x45
]
),
("East Mountain", "Entrance", "None"): (
[
0x07
],
[
0x47
]
),
("Lake", "Regular", "Zora"): (
[
0x0f, 0x81
],
[
0x4f
]
),
("Lake", "Regular", "Lake"): (
[
0x35
],
[
0x75
]
),
("Mountain Entry", "Regular", "None"): (
[
0x0a
],
[
0x4a
]
),
("Woods Pass", "Regular", "None"): (
[
0x10
],
[
0x50
]
),
("Fortune", "Regular", "None"): (
[
0x11
],
[
0x51
]
),
("Whirlpools", "Regular", "Pond"): (
[
0x12
],
[
0x52
]
),
("Whirlpools", "Regular", "Witch"): (
[
0x15
],
[
0x55
]
),
("Whirlpools", "Regular", "CWhirlpool"): (
[
0x33
],
[
0x73
]
),
("Whirlpools", "Regular", "Southeast"): (
[
0x3f
],
[
0x7f
]
),
("Castle", "Entrance", "None"): (
[
0x13, 0x14
],
[
0x53, 0x54
]
),
("Castle", "Regular", "None"): (
[
0x1a, 0x1b
],
[
0x5a, 0x5b
]
),
("Witch", "Regular", "None"): (
[
0x16
],
[
0x56
]
),
("Water Approach", "Regular", "None"): (
[
0x17
],
[
0x57
]
),
("Village", "Regular", "None"): (
[
0x18
],
[
0x58
]
),
("Wooden Bridge", "Regular", "None"): (
[
0x1d
],
[
0x5d
]
),
("Eastern", "Regular", "None"): (
[
0x1e
],
[
0x5e
]
),
("Blacksmith", "Regular", "None"): (
[
0x22
],
[
0x62
]
),
("Dunes", "Regular", "None"): (
[
0x25
],
[
0x65
]
),
("Game", "Regular", "None"): (
[
0x28, 0x29
],
[
0x68, 0x69
]
),
("Grove", "Regular", "None"): (
[
0x2a
],
[
0x6a
]
),
("Central Bonk Rocks", "Regular", "None"): (
[
0x2b
],
[
0x6b
]
),
("Links", "Regular", "None"): (
[
0x2c
],
[
0x6c
]
),
("Tree Line", "Regular", "None"): (
[
0x2e
],
[
0x6e
]
),
("Nook", "Regular", "None"): (
[
0x2f
],
[
0x6f
]
),
("Desert", "Regular", "None"): (
[
0x30, 0x3a
],
[
0x70, 0x7a
]
),
("Grove Approach", "Regular", "None"): (
[
0x32
],
[
0x72
]
),
("Hype", "Regular", "None"): (
[
0x34
],
[
0x74
]
),
("Shopping Mall", "Regular", "None"): (
[
0x37
],
[
0x77
]
),
("Swamp", "Regular", "None"): (
[
0x3b
],
[
0x7b
]
),
("South Pass", "Regular", "None"): (
[
0x3c
],
[
0x7c
]
)
}
parallel_links = bidict({'Lost Woods SW': 'Skull Woods SW', parallel_links = bidict({'Lost Woods SW': 'Skull Woods SW',
'Lost Woods SC': 'Skull Woods SC', 'Lost Woods SC': 'Skull Woods SC',
'Lost Woods SE': 'Skull Woods SE', 'Lost Woods SE': 'Skull Woods SE',

View File

@@ -1,9 +1,10 @@
import RaceRandom as random, logging, copy import RaceRandom as random, logging, copy
from collections import OrderedDict from collections import OrderedDict, defaultdict
from DungeonGenerator import GenerationException from DungeonGenerator import GenerationException
from BaseClasses import OWEdge, WorldType, RegionType, Direction, Terrain, PolSlot, Entrance from BaseClasses import OWEdge, WorldType, RegionType, Direction, Terrain, PolSlot, Entrance
from Regions import mark_dark_world_regions, mark_light_world_regions from Regions import mark_dark_world_regions, mark_light_world_regions
from OWEdges import OWTileRegions, OWTileGroups, OWEdgeGroups, OWExitTypes, OpenStd, parallel_links, IsParallel from OWEdges import OWTileRegions, OWEdgeGroups, OWExitTypes, OpenStd, parallel_links, IsParallel
from Utils import bidict
version_number = '0.2.7.2' version_number = '0.2.7.2'
version_branch = '-u' version_branch = '-u'
@@ -101,8 +102,8 @@ def link_overworld(world, player):
else: else:
raise NotImplementedError('Invalid OW Edge swap scenario') raise NotImplementedError('Invalid OW Edge swap scenario')
return new_groups return new_groups
tile_groups = reorganize_tile_groups(world, player) tile_groups = define_tile_groups(world, player, False)
trimmed_groups = copy.deepcopy(OWEdgeGroups) trimmed_groups = copy.deepcopy(OWEdgeGroups)
swapped_edges = list() swapped_edges = list()
@@ -133,14 +134,15 @@ def link_overworld(world, player):
trimmed_groups[(std, region, axis, terrain, IsParallel.No, 1)][1].append(['Frog WC']) trimmed_groups[(std, region, axis, terrain, IsParallel.No, 1)][1].append(['Frog WC'])
trimmed_groups[group] = (forward_edges, back_edges) trimmed_groups[group] = (forward_edges, back_edges)
connected_edges = []
if world.owShuffle[player] != 'vanilla':
trimmed_groups = remove_reserved(world, trimmed_groups, connected_edges, player)
trimmed_groups = reorganize_groups(world, trimmed_groups, player)
# tile shuffle # tile shuffle
logging.getLogger('').debug('Swapping overworld tiles') logging.getLogger('').debug('Swapping overworld tiles')
if world.owMixed[player]: if world.owMixed[player]:
swapped_edges = shuffle_tiles(world, tile_groups, world.owswaps[player], player) swapped_edges = shuffle_tiles(world, tile_groups, world.owswaps[player], False, player)
# move swapped regions/edges to other world
trimmed_groups = performSwap(trimmed_groups, swapped_edges)
assert len(swapped_edges) == 0, 'Not all edges were swapped successfully: ' + ', '.join(swapped_edges )
update_world_regions(world, player) update_world_regions(world, player)
@@ -175,13 +177,30 @@ def link_overworld(world, player):
# crossed shuffle # crossed shuffle
logging.getLogger('').debug('Crossing overworld edges') logging.getLogger('').debug('Crossing overworld edges')
if world.owCrossed[player] in ['grouped', 'limited', 'chaos']: crossed_edges = list()
# more Maze Race/Suburb/Frog/Dig Game fixes
parallel_links_new = bidict(parallel_links) # shallow copy is enough (deep copy is broken)
if world.owKeepSimilar[player]:
del parallel_links_new['Maze Race ES']
del parallel_links_new['Kakariko Suburb WS']
#TODO: Revisit with changes to Limited/Allowed
if world.owCrossed[player] not in ['none', 'grouped', 'polar', 'chaos']:
for edge in swapped_edges:
if edge not in parallel_links_new and edge not in parallel_links_new.inverse:
crossed_edges.append(edge)
if world.owCrossed[player] in ['grouped', 'limited'] or (world.owShuffle[player] == 'vanilla' and world.owCrossed[player] == 'chaos'):
if world.owCrossed[player] == 'grouped': if world.owCrossed[player] == 'grouped':
ow_crossed_tiles = [[],[],[]] # the idea is to XOR the new swaps with the ones from Mixed so that non-parallel edges still work
crossed_edges = shuffle_tiles(world, tile_groups, ow_crossed_tiles, player) # Polar corresponds to Grouped with no swaps in 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)
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
s = list(map(lambda x: 'O' if x not in ow_crossed_tiles[0] else 'X', [i for i in range(0x40, 0x82)])) s = list(map(lambda x: 'O' if x not in ow_crossed_tiles else 'X', [i for i in range(0x40, 0x82)]))
text_output = tile_swap_spoiler_table.replace('s', '%s') % ( s[0x02], s[0x07], text_output = tile_swap_spoiler_table.replace('s', '%s') % ( s[0x02], s[0x07],
s[0x00], s[0x03], s[0x05], s[0x00], s[0x03], s[0x05],
s[0x00], s[0x02],s[0x03], s[0x05], s[0x07], s[0x0a], s[0x0f], s[0x00], s[0x02],s[0x03], s[0x05], s[0x07], s[0x0a], s[0x0f],
@@ -197,38 +216,38 @@ def link_overworld(world, player):
s[0x30], s[0x35], s[0x30], s[0x35],
s[0x41], s[0x3a],s[0x3b],s[0x3c], s[0x3f]) s[0x41], s[0x3a],s[0x3b],s[0x3c], s[0x3f])
world.spoiler.set_map('groups', text_output, ow_crossed_tiles, player) world.spoiler.set_map('groups', text_output, ow_crossed_tiles, player)
elif world.owCrossed[player] in ['limited', 'chaos']: else:
crossed_edges = list()
crossed_candidates = list() crossed_candidates = list()
for group in trimmed_groups.keys(): for group in trimmed_groups.keys():
(mode, wrld, dir, terrain, parallel, count) = group (mode, wrld, dir, terrain, parallel, count) = group
if parallel == IsParallel.Yes and wrld == WorldType.Light and (mode == OpenStd.Open or world.mode[player] != '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 forward_set[0] in parallel_links_new or forward_set[0] in parallel_links_new.inverse:
if world.owCrossed[player] == 'chaos' and random.randint(0, 1): if world.owKeepSimilar[player]:
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): if world.owCrossed[player] == 'chaos' and random.randint(0, 1):
crossed_edges.append(edge) for edge in forward_set:
crossed_edges.append(edge)
elif world.owCrossed[player] == 'limited': elif world.owCrossed[player] == 'limited':
crossed_candidates.append([edge]) 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([edge])
if world.owCrossed[player] == 'limited': if world.owCrossed[player] == 'limited':
random.shuffle(crossed_candidates) random.shuffle(crossed_candidates)
for edge_set in crossed_candidates[:9]: for edge_set in crossed_candidates[:9]:
for edge in edge_set: for edge in edge_set:
crossed_edges.append(edge) crossed_edges.append(edge)
for edge in copy.deepcopy(crossed_edges): for edge in copy.deepcopy(crossed_edges):
if edge in parallel_links: if edge in parallel_links_new:
crossed_edges.append(parallel_links[edge]) crossed_edges.append(parallel_links_new[edge])
elif edge in parallel_links.inverse: elif edge in parallel_links_new.inverse:
crossed_edges.append(parallel_links.inverse[edge][0]) crossed_edges.append(parallel_links_new.inverse[edge][0])
trimmed_groups = performSwap(trimmed_groups, crossed_edges) # after tile swap and crossed, determine edges that need to swap
assert len(crossed_edges) == 0, 'Not all edges were crossed successfully: ' + ', '.join(crossed_edges) edges_to_swap = [e for e in swapped_edges+crossed_edges if (e not in swapped_edges) or (e not in crossed_edges)]
# whirlpool shuffle # whirlpool shuffle
logging.getLogger('').debug('Shuffling whirlpools') logging.getLogger('').debug('Shuffling whirlpools')
@@ -251,14 +270,14 @@ def link_overworld(world, player):
else: else:
if ((world.owCrossed[player] == 'none' or (world.owCrossed[player] == 'polar' and not world.owMixed[player])) and (world.get_region(from_region, player).type == RegionType.LightWorld)) \ if ((world.owCrossed[player] == 'none' or (world.owCrossed[player] == 'polar' and not world.owMixed[player])) and (world.get_region(from_region, player).type == RegionType.LightWorld)) \
or world.owCrossed[player] not in ['none', 'polar', 'grouped'] \ or world.owCrossed[player] not in ['none', 'polar', 'grouped'] \
or (world.owCrossed[player] == 'grouped' and ((from_owid < 0x40) == (from_owid not in ow_crossed_tiles[0]))): or (world.owCrossed[player] == 'grouped' and ((world.get_region(from_region, player).type == RegionType.LightWorld) == (from_owid not in ow_crossed_tiles))):
whirlpool_candidates[0].append(tuple((from_owid, from_whirlpool, from_region))) whirlpool_candidates[0].append(tuple((from_owid, from_whirlpool, from_region)))
else: else:
whirlpool_candidates[1].append(tuple((from_owid, from_whirlpool, from_region))) whirlpool_candidates[1].append(tuple((from_owid, from_whirlpool, from_region)))
if ((world.owCrossed[player] == 'none' or (world.owCrossed[player] == 'polar' and not world.owMixed[player])) and (world.get_region(to_region, player).type == RegionType.LightWorld)) \ if ((world.owCrossed[player] == 'none' or (world.owCrossed[player] == 'polar' and not world.owMixed[player])) and (world.get_region(to_region, player).type == RegionType.LightWorld)) \
or world.owCrossed[player] not in ['none', 'polar', 'grouped'] \ or world.owCrossed[player] not in ['none', 'polar', 'grouped'] \
or (world.owCrossed[player] == 'grouped' and ((to_owid < 0x40) == (to_owid not in ow_crossed_tiles[0]))): or (world.owCrossed[player] == 'grouped' and ((world.get_region(to_region, player).type == RegionType.LightWorld) == (to_owid not in ow_crossed_tiles))):
whirlpool_candidates[0].append(tuple((to_owid, to_whirlpool, to_region))) whirlpool_candidates[0].append(tuple((to_owid, to_whirlpool, to_region)))
else: else:
whirlpool_candidates[1].append(tuple((to_owid, to_whirlpool, to_region))) whirlpool_candidates[1].append(tuple((to_owid, to_whirlpool, to_region)))
@@ -278,9 +297,12 @@ def link_overworld(world, player):
# layout shuffle # layout shuffle
logging.getLogger('').debug('Shuffling overworld layout') logging.getLogger('').debug('Shuffling overworld layout')
connected_edges = []
if world.owShuffle[player] == 'vanilla': if world.owShuffle[player] == 'vanilla':
# apply outstanding swaps
trimmed_groups = performSwap(trimmed_groups, edges_to_swap)
assert len(edges_to_swap) == 0, 'Not all edges were swapped successfully: ' + ', '.join(edges_to_swap)
# 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:
@@ -303,8 +325,7 @@ def link_overworld(world, player):
connect_custom(world, connected_edges, player) connect_custom(world, connected_edges, player)
# layout shuffle # layout shuffle
trimmed_groups = remove_reserved(world, trimmed_groups, connected_edges, player) groups = adjust_edge_groups(world, trimmed_groups, edges_to_swap, player)
groups = reorganize_groups(world, trimmed_groups, player)
tries = 20 tries = 20
valid_layout = False valid_layout = False
@@ -523,33 +544,98 @@ def connect_two_way(world, edgename1, edgename2, player, connected_edges=None):
if not (parallel_forward_edge in connected_edges) and not (parallel_back_edge in connected_edges): if not (parallel_forward_edge in connected_edges) and not (parallel_back_edge in connected_edges):
connect_two_way(world, parallel_forward_edge, parallel_back_edge, player, connected_edges) connect_two_way(world, parallel_forward_edge, parallel_back_edge, player, connected_edges)
except KeyError: except KeyError:
# 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): def shuffle_tiles(world, groups, result_list, do_grouped, player):
swapped_edges = list() swapped_edges = list()
valid_whirlpool_parity = False if not do_grouped:
group_parity = {}
for group_data in groups:
group = group_data[0]
parity = [0, 0, 0, 0, 0]
# vertical land
if 0x00 in group:
parity[0] += 1
if 0x0f in group:
parity[0] += 1
if 0x80 in group:
parity[0] -= 1
if 0x81 in group:
parity[0] -= 1
# horizontal land
if 0x1a in group:
parity[1] -= 1
if 0x1b in group:
parity[1] += 1
if 0x28 in group:
parity[1] += 1
if 0x29 in group:
parity[1] -= 1
if 0x30 in group:
parity[1] -= 2
if 0x3a in group:
parity[1] += 2
# horizontal water
if 0x2d in group:
parity[2] += 1
if 0x80 in group:
parity[2] -= 1
# whirlpool
if 0x0f in group:
parity[3] += 1
if 0x12 in group:
parity[3] += 1
if 0x33 in group:
parity[3] += 1
if 0x35 in group:
parity[3] += 1
# dropdown exit
if 0x00 in group or 0x02 in group or 0x13 in group or 0x15 in group or 0x18 in group or 0x22 in group:
parity[4] += 1
if 0x1b in group and world.mode[player] != 'standard':
parity[4] += 1
if 0x1b in group and world.shuffle_ganon:
parity[4] -= 1
group_parity[group[0]] = parity
attempts = 1000
while True:
if attempts == 0: # expected to only occur with custom swaps
raise GenerationException('Could not find valid tile swaps')
while not valid_whirlpool_parity:
# tile shuffle happens here # tile shuffle happens here
removed = list() removed = list()
for group in groups.keys(): for group in groups:
# if group[0] in ['Links', 'Central Bonk Rocks', 'Castle']: # TODO: Standard + Inverted # if 0x1b in group[0] or (0x1a in group[0] and world.owCrossed[player] == 'none'): # TODO: Standard + Inverted
if random.randint(0, 1): if random.randint(0, 1):
removed.append(group) removed.append(group)
# save shuffled tiles to list # save shuffled tiles to list
new_results = [[],[],[]] new_results = [[],[],[]]
for group in groups.keys(): for group in groups:
if group not in removed: if group not in removed:
(owids, lw_regions, dw_regions) = groups[group] (owids, lw_regions, dw_regions) = group
(exist_owids, exist_lw_regions, exist_dw_regions) = new_results (exist_owids, exist_lw_regions, exist_dw_regions) = new_results
exist_owids.extend(owids) exist_owids.extend(owids)
exist_lw_regions.extend(lw_regions) exist_lw_regions.extend(lw_regions)
exist_dw_regions.extend(dw_regions) exist_dw_regions.extend(dw_regions)
# check whirlpool parity if not do_grouped:
valid_whirlpool_parity = world.owCrossed[player] not in ['none', 'grouped'] or len([o for o in new_results[0] if o in [0x0f, 0x12, 0x15, 0x33, 0x35, 0x3f, 0x55, 0x7f]]) % 2 == 0 parity = [sum(group_parity[group[0][0]][i] for group in groups if group not in removed) for i in range(5)]
parity[3] %= 2 # actual parity
if world.owCrossed[player] == 'none' and parity[:4] != [0, 0, 0, 0]:
attempts -= 1
continue
# ensure sanc can be placed in LW in certain modes
if world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull', 'lean', 'crossed', 'insanity'] \
and world.mode[player] != 'inverted' \
and (world.mode[player] == 'standard' or world.doorShuffle[player] != 'crossed' or world.intensity[player] < 3):
free_dw_drops = parity[4] + (1 if world.shuffle_ganon else 0)
free_drops = 6 + (1 if world.mode[player] != 'standard' else 0) + (1 if world.shuffle_ganon else 0)
if free_dw_drops == free_drops:
attempts -= 1
continue
break
(exist_owids, exist_lw_regions, exist_dw_regions) = result_list (exist_owids, exist_lw_regions, exist_dw_regions) = result_list
exist_owids.extend(new_results[0]) exist_owids.extend(new_results[0])
@@ -557,7 +643,7 @@ def shuffle_tiles(world, groups, result_list, player):
exist_dw_regions.extend(new_results[2]) exist_dw_regions.extend(new_results[2])
# replace LW edges with DW # replace LW edges with DW
if world.owCrossed[player] != 'polar': if world.owCrossed[player] not in ['polar', 'grouped', 'chaos']:
# in polar, the actual edge connections remain vanilla # in polar, the actual edge connections remain vanilla
def getSwappedEdges(world, lst, player): def getSwappedEdges(world, lst, player):
for regionname in lst: for regionname in lst:
@@ -571,43 +657,75 @@ def shuffle_tiles(world, groups, result_list, player):
return swapped_edges return swapped_edges
def reorganize_tile_groups(world, player): def define_tile_groups(world, player, do_grouped):
def get_group_key(group): groups = [[i, i + 0x40] for i in range(0x40)]
#(name, groupType, whirlpoolGroup) = group
new_group = list(group) def get_group(id):
if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull', 'simple', 'restricted']: for group in groups:
new_group[1] = None if id in group:
if not world.owWhirlpoolShuffle[player] and world.owCrossed[player] == 'none': return group
new_group[2] = None
return tuple(new_group) def merge_groups(tile_links):
for link in tile_links:
merged_group = []
for id in link:
if id not in merged_group:
group = get_group(id)
groups.remove(group)
merged_group += group
groups.append(merged_group)
def can_shuffle_group(group): def can_shuffle_group(group):
(name, groupType, whirlpoolGroup) = group # escape sequence should stay normal in standard
return name not in ['Castle', 'Links', 'Central Bonk Rocks'] \ if world.mode[player] == 'standard' and (0x1b in group or 0x2b in group or 0x2c in group):
or (world.mode[player] != 'standard' and (name != 'Castle' \ return False
or world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull'] \
or (world.mode[player] == 'open' and world.doorShuffle[player] == 'crossed') \ # sanctuary/chapel should not be swapped if S+Q guaranteed to output on that screen
or world.owCrossed[player] in ['grouped', 'polar', 'chaos'])) \ if 0x13 in group and ((world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull'] \
or (world.mode[player] == 'standard' and world.shuffle[player] in ['lean', 'crossed', 'insanity'] and name == 'Castle' and groupType == 'Entrance') and (world.mode[player] in ['standard', 'inverted'] or world.doorShuffle[player] != 'crossed' or world.intensity[player] < 3)) \
or (world.shuffle[player] == 'lite' and world.mode[player] == 'inverted')):
groups = {} return False
for group in OWTileGroups.keys():
if can_shuffle_group(group): return True
groups[get_group_key(group)] = ([], [], [])
for group in OWTileGroups.keys(): for i in [0x00, 0x03, 0x05, 0x18, 0x1b, 0x1e, 0x30, 0x35]:
groups.remove(get_group(i + 1))
groups.remove(get_group(i + 8))
groups.remove(get_group(i + 9))
groups.append([0x80])
groups.append([0x81])
if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull', 'simple']:
merge_groups([[0x03, 0x0a], [0x28, 0x29]])
if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull', 'simple', 'restricted', 'full', 'lite']:
merge_groups([[0x13, 0x14]])
if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'simple', 'restricted']:
merge_groups([[0x05, 0x07]])
if world.shuffle[player] == 'vanilla' or (world.mode[player] == 'standard' and world.shuffle[player] in ['dungeonssimple', 'dungeonsfull']):
merge_groups([[0x13, 0x14, 0x1b]])
if (world.owShuffle[player] == 'vanilla' and world.owCrossed[player] == 'none') or do_grouped:
merge_groups([[0x00, 0x2d, 0x80], [0x0f, 0x81], [0x1a, 0x1b], [0x28, 0x29], [0x30, 0x3a]])
if world.owShuffle[player] == 'parallel' and world.owKeepSimilar[player] and world.owCrossed[player] == 'none':
merge_groups([[0x28, 0x29]])
if (not world.owWhirlpoolShuffle[player] and world.owCrossed[player] == 'none') or do_grouped:
merge_groups([[0x0f, 0x35], [0x12, 0x15, 0x33, 0x3f]])
tile_groups = []
for group in groups:
if can_shuffle_group(group): if can_shuffle_group(group):
(lw_owids, dw_owids) = OWTileGroups[group] lw_regions = []
(exist_owids, exist_lw_regions, exist_dw_regions) = groups[get_group_key(group)] dw_regions = []
exist_owids.extend(lw_owids) for id in group:
exist_owids.extend(dw_owids) (lw_regions if id < 0x40 or id >= 0x80 else dw_regions).extend(OWTileRegions.inverse[id])
for owid in lw_owids: tile_groups.append((group, lw_regions, dw_regions))
exist_lw_regions.extend(OWTileRegions.inverse[owid])
for owid in dw_owids: return tile_groups
exist_dw_regions.extend(OWTileRegions.inverse[owid])
groups[get_group_key(group)] = (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 = {}
@@ -615,7 +733,6 @@ def remove_reserved(world, groupedlist, connected_edges, player):
new_grouping[group] = ([], []) new_grouping[group] = ([], [])
for group in groupedlist.keys(): for group in groupedlist.keys():
(_, region, _, _, _, _) = group
(forward_edges, back_edges) = groupedlist[group] (forward_edges, back_edges) = groupedlist[group]
# remove edges already connected (thru plando and other forced connections) # remove edges already connected (thru plando and other forced connections)
@@ -623,15 +740,6 @@ def remove_reserved(world, groupedlist, connected_edges, player):
forward_edges = list(list(filter((edge).__ne__, i)) for i in forward_edges) forward_edges = list(list(filter((edge).__ne__, i)) for i in forward_edges)
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
if world.owShuffle[player] == 'parallel' and region == WorldType.Dark:
for edge in parallel_links:
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)
for edge in parallel_links.inverse:
forward_edges = list(list(filter((parallel_links.inverse[edge][0]).__ne__, i)) for i in forward_edges)
back_edges = list(list(filter((parallel_links.inverse[edge][0]).__ne__, i)) for i in back_edges)
forward_edges = list(filter(([]).__ne__, forward_edges)) forward_edges = list(filter(([]).__ne__, forward_edges))
back_edges = list(filter(([]).__ne__, back_edges)) back_edges = list(filter(([]).__ne__, back_edges))
@@ -674,7 +782,26 @@ def reorganize_groups(world, groups, player):
exist_back_edges.extend(back_edges) exist_back_edges.extend(back_edges)
new_grouping[new_group] = (exist_forward_edges, exist_back_edges) new_grouping[new_group] = (exist_forward_edges, exist_back_edges)
return list(new_grouping.values()) return new_grouping
def adjust_edge_groups(world, trimmed_groups, edges_to_swap, player):
groups = defaultdict(lambda: ([],[]))
for (key, group) in trimmed_groups.items():
(mode, wrld, dir, terrain, parallel, count) = key
if mode == OpenStd.Standard:
groups[key] = group
else:
if world.owCrossed[player] == 'chaos':
groups[(mode, None, dir, terrain, parallel, count)][0].extend(group[0])
groups[(mode, None, dir, terrain, parallel, count)][1].extend(group[1])
else:
for i in range(2):
for edge_set in group[i]:
new_world = int(wrld)
if edge_set[0] in edges_to_swap:
new_world += 1
groups[(mode, WorldType(new_world % 2), dir, terrain, parallel, count)][i].append(edge_set)
return list(groups.values())
def create_flute_exits(world, player): def create_flute_exits(world, player):
for region in (r for r in world.regions if r.player == player and r.terrain == Terrain.Land and r.name not in ['Zoras Domain', 'Master Sword Meadow', 'Hobo Bridge']): for region in (r for r in world.regions if r.player == player and r.terrain == Terrain.Land and r.name not in ['Zoras Domain', 'Master Sword Meadow', 'Hobo Bridge']):