Merge branch 'OverworldShuffleDev' into OverworldShuffle

This commit is contained in:
codemann8
2021-05-10 11:39:15 -05:00
13 changed files with 212 additions and 212 deletions

View File

@@ -25,7 +25,6 @@ class World(object):
self.teams = 1 self.teams = 1
self.owShuffle = owShuffle.copy() self.owShuffle = owShuffle.copy()
self.owKeepSimilar = {} self.owKeepSimilar = {}
self.owParallelWorlds = {}
self.shuffle = shuffle.copy() self.shuffle = shuffle.copy()
self.doorShuffle = doorShuffle.copy() self.doorShuffle = doorShuffle.copy()
self.intensity = {} self.intensity = {}
@@ -2096,7 +2095,6 @@ class Spoiler(object):
'goal': self.world.goal, 'goal': self.world.goal,
'ow_shuffle': self.world.owShuffle, 'ow_shuffle': self.world.owShuffle,
'ow_keepsimilar': self.world.owKeepSimilar, 'ow_keepsimilar': self.world.owKeepSimilar,
'ow_parallel': self.world.owParallelWorlds,
'shuffle': self.world.shuffle, 'shuffle': self.world.shuffle,
'door_shuffle': self.world.doorShuffle, 'door_shuffle': self.world.doorShuffle,
'intensity': self.world.intensity, 'intensity': self.world.intensity,
@@ -2174,9 +2172,8 @@ class Spoiler(object):
outfile.write('Triforce Pieces Total:'.ljust(line_width) + '%s\n' % self.metadata['triforcepool'][player]) outfile.write('Triforce Pieces Total:'.ljust(line_width) + '%s\n' % self.metadata['triforcepool'][player])
outfile.write('Difficulty:'.ljust(line_width) + '%s\n' % self.metadata['item_pool'][player]) outfile.write('Difficulty:'.ljust(line_width) + '%s\n' % self.metadata['item_pool'][player])
outfile.write('Item Functionality:'.ljust(line_width) + '%s\n' % self.metadata['item_functionality'][player]) outfile.write('Item Functionality:'.ljust(line_width) + '%s\n' % self.metadata['item_functionality'][player])
outfile.write('Overworld Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['ow_shuffle'][player]) outfile.write('Overworld Layout Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['ow_shuffle'][player])
outfile.write('Keep OW Edges Together:'.ljust(line_width) + '%s\n' % ('Yes' if self.metadata['ow_keepsimilar'][player] else 'No')) outfile.write('Keep OW Edges Together:'.ljust(line_width) + '%s\n' % ('Yes' if self.metadata['ow_keepsimilar'][player] else 'No'))
outfile.write('Parallel Worlds:'.ljust(line_width) + '%s\n' % ('Yes' if self.metadata['ow_parallel'][player] else 'No'))
outfile.write('Entrance Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['shuffle'][player]) outfile.write('Entrance Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['shuffle'][player])
outfile.write('Door Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['door_shuffle'][player]) outfile.write('Door Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['door_shuffle'][player])
outfile.write('Intensity:'.ljust(line_width) + '%s\n' % self.metadata['intensity'][player]) outfile.write('Intensity:'.ljust(line_width) + '%s\n' % self.metadata['intensity'][player])

View File

@@ -1,5 +1,10 @@
# Changelog # Changelog
### 0.1.2.2
- Re-purposed OW Shuffle setting to Layout Shuffle
- Merged Parallel Worlds setting into Layout Shuffle
- Added guaranteed Flute hint for OW Shuffle modes
### 0.1.2.1 ### 0.1.2.1
- Made possible fix for Standard - Made possible fix for Standard
- Merged DR v0.3.1.10 - Fixed Standard generation - Merged DR v0.3.1.10 - Fixed Standard generation

3
CLI.py
View File

@@ -94,7 +94,7 @@ def parse_cli(argv, no_defaults=False):
for player in range(1, multiargs.multi + 1): for player in range(1, multiargs.multi + 1):
playerargs = parse_cli(shlex.split(getattr(ret, f"p{player}")), True) playerargs = parse_cli(shlex.split(getattr(ret, f"p{player}")), True)
for name in ['logic', 'mode', 'swords', 'goal', 'difficulty', 'item_functionality', 'ow_shuffle', 'ow_keepsimilar', 'ow_parallel', for name in ['logic', 'mode', 'swords', 'goal', 'difficulty', 'item_functionality', 'ow_shuffle', 'ow_keepsimilar',
'shuffle', 'door_shuffle', 'intensity', 'crystals_ganon', 'crystals_gt', 'openpyramid', 'shuffle', 'door_shuffle', 'intensity', 'crystals_ganon', 'crystals_gt', 'openpyramid',
'mapshuffle', 'compassshuffle', 'keyshuffle', 'bigkeyshuffle', 'startinventory', 'mapshuffle', 'compassshuffle', 'keyshuffle', 'bigkeyshuffle', 'startinventory',
'triforce_pool_min', 'triforce_pool_max', 'triforce_goal_min', 'triforce_goal_max', 'triforce_pool_min', 'triforce_pool_max', 'triforce_goal_min', 'triforce_goal_max',
@@ -144,7 +144,6 @@ def parse_settings():
"shuffleganon": True, "shuffleganon": True,
"ow_shuffle": "vanilla", "ow_shuffle": "vanilla",
"ow_keepsimilar": False, "ow_keepsimilar": False,
"ow_parallel": False,
"shuffle": "vanilla", "shuffle": "vanilla",
"shufflepots": False, "shufflepots": False,

View File

@@ -74,7 +74,6 @@ def main(args, seed=None, fish=None):
world.crystals_ganon_orig = args.crystals_ganon.copy() world.crystals_ganon_orig = args.crystals_ganon.copy()
world.crystals_gt_orig = args.crystals_gt.copy() world.crystals_gt_orig = args.crystals_gt.copy()
world.owKeepSimilar = args.ow_keepsimilar.copy() world.owKeepSimilar = args.ow_keepsimilar.copy()
world.owParallelWorlds = args.ow_parallel.copy()
world.open_pyramid = args.openpyramid.copy() world.open_pyramid = args.openpyramid.copy()
world.boss_shuffle = args.shufflebosses.copy() world.boss_shuffle = args.shufflebosses.copy()
world.enemy_shuffle = args.shuffleenemies.copy() world.enemy_shuffle = args.shuffleenemies.copy()

View File

@@ -154,7 +154,6 @@ 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_keepsimilar = get_choice('ow_keepsimilar') ret.ow_keepsimilar = get_choice('ow_keepsimilar')
ret.ow_parallel = get_choice('ow_parallel')
entrance_shuffle = get_choice('entrance_shuffle') entrance_shuffle = get_choice('entrance_shuffle')
ret.shuffle = entrance_shuffle if entrance_shuffle != 'none' else 'vanilla' ret.shuffle = entrance_shuffle if entrance_shuffle != 'none' else 'vanilla'
door_shuffle = get_choice('door_shuffle') door_shuffle = get_choice('door_shuffle')

View File

@@ -3,7 +3,7 @@ from BaseClasses import OWEdge, WorldType, Direction, Terrain
from Utils import bidict from Utils import bidict
from OWEdges import OWEdgeGroups, IsParallel from OWEdges import OWEdgeGroups, IsParallel
__version__ = '0.1.2.1u' __version__ = '0.1.2.2u'
def link_overworld(world, player): def link_overworld(world, player):
# setup mandatory connections # setup mandatory connections
@@ -21,7 +21,7 @@ def link_overworld(world, player):
for exitname, destname in default_connections: for exitname, destname in default_connections:
connect_two_way(world, exitname, destname, player) connect_two_way(world, exitname, destname, player)
else: else:
if world.owKeepSimilar[player] and world.owParallelWorlds[player]: if world.owKeepSimilar[player] and world.owShuffle[player] == 'parallel':
for exitname, destname in parallelsimilar_connections: for exitname, destname in parallelsimilar_connections:
connect_two_way(world, exitname, destname, player) connect_two_way(world, exitname, destname, player)
connected_edges.append(exitname) connected_edges.append(exitname)
@@ -38,181 +38,181 @@ def link_overworld(world, player):
if world.owShuffle[player] == 'full': if world.owShuffle[player] == 'full':
#predefined shuffle groups get reorganized here #predefined shuffle groups get reorganized here
if world.owKeepSimilar[player]: if world.owKeepSimilar[player]:
if world.owParallelWorlds[player]: if world.mode[player] == 'standard':
if world.mode[player] == 'standard': #tuple stays (A,B,C,D,_,F)
#tuple stays (A,B,C,D,E,F) for grouping in (trimmed_groups, None):
for grouping in (trimmed_groups, None): if grouping is not None: #TODO: Figure out why ^ has to be a tuple for this to work
if grouping is not None: #TODO: Figure out why ^ has to be a tuple for this to work new_grouping = {}
groups = list(grouping.values())
else:
#tuple goes to (_,B,C,D,E,F)
for grouping in (trimmed_groups, None):
if grouping is not None: #TODO: Figure out why ^ has to be a tuple for this to work
new_grouping = {}
for group in grouping.keys(): for group in grouping.keys():
(_, region, axis, terrain, parallel, count) = group (std, region, axis, terrain, _, count) = group
new_grouping[(region, axis, terrain, parallel, count)] = ([], []) new_grouping[(std, region, axis, terrain, count)] = ([], [])
for group in grouping.keys(): for group in grouping.keys():
(_, region, 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[(region, 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[(region, axis, terrain, parallel, count)] = (exist_forward_edges, exist_back_edges) new_grouping[(std, region, axis, terrain, count)] = (exist_forward_edges, exist_back_edges)
groups = list(new_grouping.values()) groups = list(new_grouping.values())
else: else:
if world.mode[player] == 'standard': #tuple goes to (_,B,C,D,_,F)
#tuple stays (A,B,C,D,_,F) for grouping in (trimmed_groups, None):
for grouping in (trimmed_groups, None): if grouping is not None: #TODO: Figure out why ^ has to be a tuple for this to work
if grouping is not None: #TODO: Figure out why ^ has to be a tuple for this to work new_grouping = {}
new_grouping = {}
for group in grouping.keys(): for group in grouping.keys():
(std, region, axis, terrain, _, count) = group (_, region, axis, terrain, _, count) = group
new_grouping[(std, region, axis, terrain, count)] = ([], []) new_grouping[(region, axis, terrain, count)] = ([], [])
for group in grouping.keys(): for group in grouping.keys():
(std, region, axis, terrain, _, 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[(std, region, axis, terrain, 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[(std, region, axis, terrain, count)] = (exist_forward_edges, exist_back_edges) new_grouping[(region, axis, terrain, count)] = (exist_forward_edges, exist_back_edges)
groups = list(new_grouping.values()) groups = list(new_grouping.values())
else:
#tuple goes to (_,B,C,D,_,F)
for grouping in (trimmed_groups, None):
if grouping is not None: #TODO: Figure out why ^ has to be a tuple for this to work
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)
groups = list(new_grouping.values())
else: else:
if world.owParallelWorlds[player]: if world.mode[player] == 'standard':
if world.mode[player] == 'standard': #tuple stays (A,B,C,D,_,_)
#tuple stays (A,B,C,D,E,_) for grouping in (trimmed_groups, None):
for grouping in (trimmed_groups, None): if grouping is not None: #TODO: Figure out why ^ has to be a tuple for this to work
if grouping is not None: #TODO: Figure out why ^ has to be a tuple for this to work new_grouping = {}
new_grouping = {}
for group in grouping.keys(): for group in grouping.keys():
(std, region, axis, terrain, parallel, _) = group (std, region, axis, terrain, _, _) = group
new_grouping[(std, region, axis, terrain, parallel)] = ([], []) 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]
for group in grouping.keys(): (exist_forward_edges, exist_back_edges) = new_grouping[(std, region, axis, terrain)]
(std, region, axis, terrain, parallel, _) = group exist_forward_edges.extend(forward_edges)
(forward_edges, back_edges) = grouping[group] exist_back_edges.extend(back_edges)
forward_edges = [[i] for l in forward_edges for i in l] new_grouping[(std, region, axis, terrain)] = (exist_forward_edges, exist_back_edges)
back_edges = [[i] for l in back_edges for i in l]
(exist_forward_edges, exist_back_edges) = new_grouping[(std, region, axis, terrain, parallel)]
exist_forward_edges.extend(forward_edges)
exist_back_edges.extend(back_edges)
new_grouping[(std, region, axis, terrain, parallel)] = (exist_forward_edges, exist_back_edges)
groups = list(new_grouping.values()) groups = list(new_grouping.values())
else:
#tuple goes to (_,B,C,D,E,_)
for grouping in (trimmed_groups, None):
if grouping is not None: #TODO: Figure out why ^ has to be a tuple for this to work
new_grouping = {}
for group in grouping.keys():
(_, region, axis, terrain, parallel, _) = group
new_grouping[(region, axis, terrain, parallel)] = ([], [])
for group in grouping.keys():
(_, region, axis, terrain, parallel, _) = 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, parallel)]
exist_forward_edges.extend(forward_edges)
exist_back_edges.extend(back_edges)
new_grouping[(region, axis, terrain, parallel)] = (exist_forward_edges, exist_back_edges)
groups = list(new_grouping.values())
else: else:
if world.mode[player] == 'standard': #tuple goes to (_,B,C,D,_,_)
#tuple stays (A,B,C,D,_,_) for grouping in (trimmed_groups, None):
for grouping in (trimmed_groups, None): if grouping is not None: #TODO: Figure out why ^ has to be a tuple for this to work
if grouping is not None: #TODO: Figure out why ^ has to be a tuple for this to work new_grouping = {}
new_grouping = {}
for group in grouping.keys(): for group in grouping.keys():
(std, region, axis, terrain, _, _) = group (_, region, axis, terrain, _, _) = group
new_grouping[(std, region, axis, terrain)] = ([], []) 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]
for group in grouping.keys(): (exist_forward_edges, exist_back_edges) = new_grouping[(region, axis, terrain)]
(std, region, axis, terrain, _, _) = group exist_forward_edges.extend(forward_edges)
(forward_edges, back_edges) = grouping[group] exist_back_edges.extend(back_edges)
forward_edges = [[i] for l in forward_edges for i in l] new_grouping[(region, axis, terrain)] = (exist_forward_edges, exist_back_edges)
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)
groups = list(new_grouping.values()) groups = list(new_grouping.values())
else: elif world.owShuffle[player] == 'parallel':
#tuple goes to (_,B,C,D,_,_) #predefined shuffle groups get reorganized here
for grouping in (trimmed_groups, None): if world.owKeepSimilar[player]:
if grouping is not None: #TODO: Figure out why ^ has to be a tuple for this to work if world.mode[player] == 'standard':
new_grouping = {} #tuple stays (A,B,C,D,E,F)
for grouping in (trimmed_groups, None):
if grouping is not None: #TODO: Figure out why ^ has to be a tuple for this to work
groups = list(grouping.values())
else:
#tuple goes to (_,B,C,D,E,F)
for grouping in (trimmed_groups, None):
if grouping is not None: #TODO: Figure out why ^ has to be a tuple for this to work
new_grouping = {}
for group in grouping.keys(): for group in grouping.keys():
(_, region, axis, terrain, _, _) = group (_, region, axis, terrain, parallel, count) = group
new_grouping[(region, axis, terrain)] = ([], []) new_grouping[(region, axis, terrain, parallel, count)] = ([], [])
for group in grouping.keys():
(_, region, axis, terrain, parallel, count) = group
(forward_edges, back_edges) = grouping[group]
(exist_forward_edges, exist_back_edges) = new_grouping[(region, axis, terrain, parallel, count)]
exist_forward_edges.extend(forward_edges)
exist_back_edges.extend(back_edges)
new_grouping[(region, axis, terrain, parallel, count)] = (exist_forward_edges, exist_back_edges)
groups = list(new_grouping.values())
else:
if world.mode[player] == 'standard':
#tuple stays (A,B,C,D,E,_)
for grouping in (trimmed_groups, None):
if grouping is not None: #TODO: Figure out why ^ has to be a tuple for this to work
new_grouping = {}
for group in grouping.keys():
(std, region, axis, terrain, parallel, _) = group
new_grouping[(std, region, axis, terrain, parallel)] = ([], [])
for group in grouping.keys():
(std, region, axis, terrain, parallel, _) = 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]
for group in grouping.keys(): (exist_forward_edges, exist_back_edges) = new_grouping[(std, region, axis, terrain, parallel)]
(_, region, axis, terrain, _, _) = group exist_forward_edges.extend(forward_edges)
(forward_edges, back_edges) = grouping[group] exist_back_edges.extend(back_edges)
forward_edges = [[i] for l in forward_edges for i in l] new_grouping[(std, region, axis, terrain, parallel)] = (exist_forward_edges, exist_back_edges)
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)
groups = list(new_grouping.values()) groups = list(new_grouping.values())
else:
#all shuffling occurs here #tuple goes to (_,B,C,D,E,_)
random.shuffle(groups) for grouping in (trimmed_groups, None):
for (forward_edge_sets, back_edge_sets) in groups: if grouping is not None: #TODO: Figure out why ^ has to be a tuple for this to work
assert len(forward_edge_sets) == len(back_edge_sets) new_grouping = {}
random.shuffle(back_edge_sets)
for (forward_set, back_set) in zip(forward_edge_sets, back_edge_sets):
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.append(forward_edge)
connected_edges.append(back_edge)
if world.owParallelWorlds[player] and forward_edge in parallel_links.keys():
connect_two_way(world, parallel_links[forward_edge], parallel_links[back_edge], player)
connected_edges.append(parallel_links[forward_edge])
connected_edges.append(parallel_links[back_edge])
assert len(connected_edges) == len(default_connections) * 2, connected_edges for group in grouping.keys():
(_, region, axis, terrain, parallel, _) = group
new_grouping[(region, axis, terrain, parallel)] = ([], [])
for group in grouping.keys():
(_, region, axis, terrain, parallel, _) = 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, parallel)]
exist_forward_edges.extend(forward_edges)
exist_back_edges.extend(back_edges)
new_grouping[(region, axis, terrain, parallel)] = (exist_forward_edges, exist_back_edges)
groups = list(new_grouping.values())
else: else:
raise NotImplementedError('Shuffling not supported yet') raise NotImplementedError('Shuffling not supported yet')
#all shuffling occurs here
random.shuffle(groups)
for (forward_edge_sets, back_edge_sets) in groups:
assert len(forward_edge_sets) == len(back_edge_sets)
random.shuffle(back_edge_sets)
for (forward_set, back_set) in zip(forward_edge_sets, back_edge_sets):
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.append(forward_edge)
connected_edges.append(back_edge)
if world.owShuffle[player] == 'parallel' and forward_edge in parallel_links.keys():
connect_two_way(world, parallel_links[forward_edge], parallel_links[back_edge], player)
connected_edges.append(parallel_links[forward_edge])
connected_edges.append(parallel_links[back_edge])
assert len(connected_edges) == len(default_connections) * 2, connected_edges
def connect_custom(world, connected_edges, player): def connect_custom(world, connected_edges, player):
if hasattr(world, 'custom_overworld') and world.custom_overworld[player]: if hasattr(world, 'custom_overworld') and world.custom_overworld[player]:
@@ -262,7 +262,7 @@ 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)
if world.owParallelWorlds[player] 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)

View File

@@ -9,7 +9,7 @@ See https://alttpr.com/ for more details on the normal randomizer.
This is a very new mode of LTTPR so the tools and info is very limited. There is a [OW Rando Cheat Sheet](https://zelda.codemann8.com/images/shared/ow-rando-reference-sheet.png) that shows all the transitions that exist and are candidates for shuffle. There is a rumor that some OW tracking capability will be coming to CodeTracker, an EmoTracker package for LTTPR. This is a very new mode of LTTPR so the tools and info is very limited. There is a [OW Rando Cheat Sheet](https://zelda.codemann8.com/images/shared/ow-rando-reference-sheet.png) that shows all the transitions that exist and are candidates for shuffle. There is a rumor that some OW tracking capability will be coming to CodeTracker, an EmoTracker package for LTTPR.
# Known Issues # Known Issues
(Updated 2021-05-05) (Updated 2021-05-09)
### If you want to playtest this, know these things: ### If you want to playtest this, know these things:
- Big Red Bomb may require bomb duping as ledge drops may be in the way of your path to the Pyramid Fairy crack - Big Red Bomb may require bomb duping as ledge drops may be in the way of your path to the Pyramid Fairy crack
@@ -40,23 +40,23 @@ Alternatively, run ```Gui.py``` for a simple graphical user interface. (WIP)
Only extra settings are found here. All door and entrance randomizer settings are supported. See their [readme](https://github.com/Aerinon/ALttPDoorRandomizer/blob/master/README.md) Only extra settings are found here. All door and entrance randomizer settings are supported. See their [readme](https://github.com/Aerinon/ALttPDoorRandomizer/blob/master/README.md)
## Overworld Shuffle (--ow_shuffle) ## Overworld Layout Shuffle (--ow_shuffle)
### Full
OW Transitions are shuffled within each world separately.
### Vanilla ### Vanilla
OW is not shuffled. OW is not shuffled.
### Parallel
OW Transitions are shuffled, but both worlds will have a matching layout.
### Full
OW Transitions are shuffled within each world separately.
## Keep Similar Edges Together (--ow_keepsimilar) ## Keep Similar Edges Together (--ow_keepsimilar)
This keeps similar edge transitions together. ie. The 2 west edges of Potion Shop area will be paired to another set of two similar edges This keeps similar edge transitions together. ie. The 2 west edges of Potion Shop will be paired to another set of two similar edges
## Parallel Worlds (--ow_parallel)
This ensures matching layouts of Light and Dark worlds. Any remaining edge transitions that don't have a matching counterpart will be shuffled amongst themselves. ie. If going right from Link's House leads to Blacksmith, then going right from Big Bomb Shop will lead to Hammer Pegs
# Command Line Options # Command Line Options
@@ -71,16 +71,10 @@ Show the help message and exit.
--ow_shuffle <mode> --ow_shuffle <mode>
``` ```
For specifying the overworld shuffle you want as above. (default: vanilla) For specifying the overworld layout shuffle you want as above. (default: vanilla)
``` ```
--ow_keepsimilar --ow_keepsimilar
``` ```
This keeps similar edge transitions paired together with other pairs of transitions This keeps similar edge transitions paired together with other pairs of transitions
```
--ow_parallel
```
This ensures the layout of both worlds have the same shape

24
Rom.py
View File

@@ -595,8 +595,18 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
if world.owShuffle[player] != 'vanilla': if world.owShuffle[player] != 'vanilla':
rom.write_byte(0x18004C, 0x01) #patch for allowing Frogsmith to enter multi-entrance caves rom.write_byte(0x18004C, 0x01) #patch for allowing Frogsmith to enter multi-entrance caves
if world.owShuffle[player] == 'full': if world.owShuffle[player] == 'parallel':
rom.write_byte(0x150002, 2) owMode = 1
elif world.owShuffle[player] == 'full':
owMode = 2
rom.write_byte(0x150002, owMode)
owFlags = 0
if world.owKeepSimilar[player]:
owFlags += 0x1
write_int16(rom, 0x150003, owFlags)
for edge in world.owedges: for edge in world.owedges:
if edge.dest is not None and isinstance(edge.dest, OWEdge) and edge.player == player: if edge.dest is not None and isinstance(edge.dest, OWEdge) and edge.player == player:
@@ -1993,8 +2003,17 @@ def write_strings(rom, world, player, team):
this_hint = location + ' contains ' + hint_text(world.get_location(location, player).item) + '.' this_hint = location + ' contains ' + hint_text(world.get_location(location, player).item) + '.'
tt[hint_locations.pop(0)] = this_hint tt[hint_locations.pop(0)] = this_hint
# Adding a guaranteed hint for the Flute in overworld shuffle.
if world.owShuffle[player] in ['parallel','full']:
this_location = world.find_items_not_key_only('Ocarina', player)
if this_location:
this_hint = this_location[0].item.hint_text + ' can be found ' + hint_text(this_location[0]) + '.'
tt[hint_locations.pop(0)] = this_hint
# Lastly we write hints to show where certain interesting items are. It is done the way it is to re-use the silver code and also to give one hint per each type of item regardless of how many exist. This supports many settings well. # Lastly we write hints to show where certain interesting items are. It is done the way it is to re-use the silver code and also to give one hint per each type of item regardless of how many exist. This supports many settings well.
items_to_hint = RelevantItems.copy() items_to_hint = RelevantItems.copy()
if world.owShuffle[player] in ['parallel','full']:
items_to_hint.remove('Ocarina')
if world.keyshuffle[player]: if world.keyshuffle[player]:
items_to_hint.extend(SmallKeys) items_to_hint.extend(SmallKeys)
if world.bigkeyshuffle[player]: if world.bigkeyshuffle[player]:
@@ -2002,6 +2021,7 @@ def write_strings(rom, world, player, team):
random.shuffle(items_to_hint) random.shuffle(items_to_hint)
hint_count = 5 if world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull'] else 8 hint_count = 5 if world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull'] else 8
hint_count += 2 if world.doorShuffle[player] == 'crossed' else 0 hint_count += 2 if world.doorShuffle[player] == 'crossed' else 0
hint_count += 1 if world.owShuffle[player] in ['parallel', 'full'] else 0
while hint_count > 0: while hint_count > 0:
this_item = items_to_hint.pop(0) this_item = items_to_hint.pop(0)
this_location = world.find_items_not_key_only(this_item, player) this_location = world.find_items_not_key_only(this_item, player)

View File

@@ -111,19 +111,14 @@
"ow_shuffle": { "ow_shuffle": {
"choices": [ "choices": [
"vanilla", "vanilla",
"simple", "parallel",
"full", "full"
"crossed"
] ]
}, },
"ow_keepsimilar": { "ow_keepsimilar": {
"action": "store_true", "action": "store_true",
"type": "bool" "type": "bool"
}, },
"ow_parallel": {
"action": "store_true",
"type": "bool"
},
"shuffle": { "shuffle": {
"choices": [ "choices": [
"vanilla", "vanilla",

View File

@@ -194,19 +194,17 @@
"the overworld vanilla." "the overworld vanilla."
], ],
"ow_shuffle": [ "ow_shuffle": [
"Select Overworld Shuffling Algorithm. (default: %(default)s)", "This shuffles the layout of the overworld.",
"Vanilla: All overworld transitions are connected the same", "Vanilla: All overworld transitions are connected the same",
" way they were in the base game.", " way they were in the base game.",
"Simple: Overworld retains the same vanilla shape, but some overworld", "Parallel: Overworld transitions are shuffled, but both worlds",
" screens will be swapped with their opposite world version.", " will have the same pattern/shape.",
"Full: Overworld screen transitions will lead to other", "Full: Overworld transitions are shuffled, but both worlds",
" overworld screens from the same world.", " will have an independent map shape."
"Crossed: Overworld screen transitions can lead to any other overworld screen."
], ],
"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." ],
"ow_parallel": [ "This ensures the layouts of both worlds are the same shape." ],
"door_shuffle": [ "door_shuffle": [
"Select Door Shuffling Algorithm. (default: %(default)s)", "Select Door Shuffling Algorithm. (default: %(default)s)",
"Basic: Doors are mixed within a single dungeon.", "Basic: Doors are mixed within a single dungeon.",

View File

@@ -109,14 +109,12 @@
"randomizer.enemizer.enemizercli.online": "(get online)", "randomizer.enemizer.enemizercli.online": "(get online)",
"randomizer.overworld.overworldshuffle": "Overworld Shuffle", "randomizer.overworld.overworldshuffle": "Layout Shuffle",
"randomizer.overworld.overworldshuffle.vanilla": "Vanilla", "randomizer.overworld.overworldshuffle.vanilla": "Vanilla",
"randomizer.overworld.overworldshuffle.simple": "Simple", "randomizer.overworld.overworldshuffle.parallel": "Parallel",
"randomizer.overworld.overworldshuffle.full": "Full", "randomizer.overworld.overworldshuffle.full": "Full",
"randomizer.overworld.overworldshuffle.crossed": "Crossed",
"randomizer.overworld.keepsimilar": "Keep Similar Edges Together", "randomizer.overworld.keepsimilar": "Keep Similar Edges Together",
"randomizer.overworld.parallelworlds": "Parallel Worlds",
"randomizer.entrance.openpyramid": "Pre-open Pyramid Hole", "randomizer.entrance.openpyramid": "Pre-open Pyramid Hole",
"randomizer.entrance.shuffleganon": "Include Ganon's Tower and Pyramid Hole in shuffle pool", "randomizer.entrance.shuffleganon": "Include Ganon's Tower and Pyramid Hole in shuffle pool",

View File

@@ -2,19 +2,16 @@
"widgets": { "widgets": {
"overworldshuffle": { "overworldshuffle": {
"type": "selectbox", "type": "selectbox",
"default": "full", "default": "parallel",
"options": [ "options": [
"vanilla", "vanilla",
"parallel",
"full" "full"
] ]
}, },
"keepsimilar": { "keepsimilar": {
"type": "checkbox", "type": "checkbox",
"default": true "default": true
},
"parallelworlds": {
"type": "checkbox",
"default": true
} }
} }
} }

View File

@@ -72,8 +72,7 @@ SETTINGSTOPROCESS = {
}, },
"overworld": { "overworld": {
"overworldshuffle": "ow_shuffle", "overworldshuffle": "ow_shuffle",
"keepsimilar": "ow_keepsimilar", "keepsimilar": "ow_keepsimilar"
"parallelworlds": "ow_parallel"
}, },
"entrance": { "entrance": {
"openpyramid": "openpyramid", "openpyramid": "openpyramid",