From 1f735882d9f6dc4ce8276d034595a2e836ceab92 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Fri, 7 May 2021 04:23:07 -0500 Subject: [PATCH 1/6] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 990970ba..4dda8c1c 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ This is a very new mode of LTTPR so the tools and info is very limited. There is - Big Red Bomb may require bomb duping as ledge drops may be in the way of your path to the Pyramid Fairy crack - Do NOT grab the Frogsmith until you have seen the Blacksmith location. Doing so may prevent you from continuing in your save file. - Inverted regions/rules/logic is NOT implemented yet. Generation should fail 100%. -- If you fake flipper, beware of transitioning south. You could end up at the top of the waterfall in the southeast of either world. If you mistakenly drop down, it is important to NOT make any other movements and S+Q immediately or there will be a hardlock. Falling from the waterfall is avoidable but it is super easy to do as it is super close the the transition. +- If you fake flipper, beware of transitioning south. You could end up at the top of the waterfall in the southeast of either world. If you mistakenly drop down, it is important to NOT make any other movements and S+Q immediately or there will be a hardlock. Falling from the waterfall is avoidable but it is super easy to do as it is super close to the transition. ### Known bugs: - ~~Camera unlocks, this is a known issue and will eventually be fixed at a later time~~ _(Fixed with 0.1.1.2)_ From 1f3f20b92300679131fa0a38566dd478c106ce8e Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 9 May 2021 19:06:13 -0500 Subject: [PATCH 2/6] Merged Parallel Worlds into OW Layout Shuffle setting --- BaseClasses.py | 5 +- CLI.py | 3 +- Main.py | 1 - Mystery.py | 1 - OverworldShuffle.py | 316 +++++++++--------- README.md | 28 +- resources/app/cli/args.json | 9 +- resources/app/cli/lang/en.json | 12 +- resources/app/gui/lang/en.json | 6 +- .../app/gui/randomize/overworld/widgets.json | 7 +- source/classes/constants.py | 3 +- 11 files changed, 183 insertions(+), 208 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index 2f06414a..d03ea0bb 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -25,7 +25,6 @@ class World(object): self.teams = 1 self.owShuffle = owShuffle.copy() self.owKeepSimilar = {} - self.owParallelWorlds = {} self.shuffle = shuffle.copy() self.doorShuffle = doorShuffle.copy() self.intensity = {} @@ -2096,7 +2095,6 @@ class Spoiler(object): 'goal': self.world.goal, 'ow_shuffle': self.world.owShuffle, 'ow_keepsimilar': self.world.owKeepSimilar, - 'ow_parallel': self.world.owParallelWorlds, 'shuffle': self.world.shuffle, 'door_shuffle': self.world.doorShuffle, '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('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('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('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('Door Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['door_shuffle'][player]) outfile.write('Intensity:'.ljust(line_width) + '%s\n' % self.metadata['intensity'][player]) diff --git a/CLI.py b/CLI.py index 6b6a52a1..e1ae72b6 100644 --- a/CLI.py +++ b/CLI.py @@ -94,7 +94,7 @@ def parse_cli(argv, no_defaults=False): for player in range(1, multiargs.multi + 1): 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', 'mapshuffle', 'compassshuffle', 'keyshuffle', 'bigkeyshuffle', 'startinventory', 'triforce_pool_min', 'triforce_pool_max', 'triforce_goal_min', 'triforce_goal_max', @@ -144,7 +144,6 @@ def parse_settings(): "shuffleganon": True, "ow_shuffle": "vanilla", "ow_keepsimilar": False, - "ow_parallel": False, "shuffle": "vanilla", "shufflepots": False, diff --git a/Main.py b/Main.py index 45ae4d02..ee4d7b9b 100644 --- a/Main.py +++ b/Main.py @@ -74,7 +74,6 @@ def main(args, seed=None, fish=None): world.crystals_ganon_orig = args.crystals_ganon.copy() world.crystals_gt_orig = args.crystals_gt.copy() world.owKeepSimilar = args.ow_keepsimilar.copy() - world.owParallelWorlds = args.ow_parallel.copy() world.open_pyramid = args.openpyramid.copy() world.boss_shuffle = args.shufflebosses.copy() world.enemy_shuffle = args.shuffleenemies.copy() diff --git a/Mystery.py b/Mystery.py index f4dd0960..b26e6ff9 100644 --- a/Mystery.py +++ b/Mystery.py @@ -154,7 +154,6 @@ def roll_settings(weights): overworld_shuffle = get_choice('overworld_shuffle') ret.ow_shuffle = overworld_shuffle if overworld_shuffle != 'none' else 'vanilla' ret.ow_keepsimilar = get_choice('ow_keepsimilar') - ret.ow_parallel = get_choice('ow_parallel') entrance_shuffle = get_choice('entrance_shuffle') ret.shuffle = entrance_shuffle if entrance_shuffle != 'none' else 'vanilla' door_shuffle = get_choice('door_shuffle') diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 901582f2..f1adb4a3 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -21,7 +21,7 @@ def link_overworld(world, player): for exitname, destname in default_connections: connect_two_way(world, exitname, destname, player) else: - if world.owKeepSimilar[player] and world.owParallelWorlds[player]: + if world.owKeepSimilar[player] and world.owShuffle[player] == 'parallel': for exitname, destname in parallelsimilar_connections: connect_two_way(world, exitname, destname, player) connected_edges.append(exitname) @@ -38,181 +38,181 @@ def link_overworld(world, player): if world.owShuffle[player] == 'full': #predefined shuffle groups get reorganized here if world.owKeepSimilar[player]: - if world.owParallelWorlds[player]: - if world.mode[player] == 'standard': - #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 = {} + if world.mode[player] == 'standard': + #tuple stays (A,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, parallel, count) = group - 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) + 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) - groups = list(new_grouping.values()) + groups = list(new_grouping.values()) else: - if world.mode[player] == 'standard': - #tuple stays (A,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 = {} + #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(): - (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) + 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: - #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()) + groups = list(new_grouping.values()) else: - if world.owParallelWorlds[player]: - 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 = {} + if world.mode[player] == 'standard': + #tuple stays (A,B,C,D,_,_) + 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, _, _) = 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] - 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] - - (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) + (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()) - 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()) + groups = list(new_grouping.values()) else: - if world.mode[player] == 'standard': - #tuple stays (A,B,C,D,_,_) - 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 = {} + #tuple goes to (_,B,C,D,_,_) + 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, _, _) = group - new_grouping[(std, region, axis, terrain)] = ([], []) + 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] - 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) + (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()) - else: - #tuple goes to (_,B,C,D,_,_) - 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 = {} + groups = list(new_grouping.values()) + elif world.owShuffle[player] == 'parallel': + #predefined shuffle groups get reorganized here + if world.owKeepSimilar[player]: + if world.mode[player] == 'standard': + #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(): - (_, region, axis, terrain, _, _) = group - new_grouping[(region, axis, terrain)] = ([], []) + for group in grouping.keys(): + (_, region, axis, terrain, parallel, count) = group + 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(): - (_, 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) + (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()) - - #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.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]) + 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 = {} - 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: 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): 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) 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: 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) diff --git a/README.md b/README.md index 4dda8c1c..2616d0ce 100644 --- a/README.md +++ b/README.md @@ -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. # Known Issues -(Updated 2021-05-04) +(Updated 2021-05-09) ### 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 @@ -40,24 +40,24 @@ 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) -## Overworld Shuffle (--ow_shuffle) - -### Full - -OW Transitions are shuffled within each world separately. +## Overworld Layout Shuffle (--ow_shuffle) ### Vanilla 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) 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 @@ -71,16 +71,10 @@ Show the help message and exit. --ow_shuffle ``` -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 ``` 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 diff --git a/resources/app/cli/args.json b/resources/app/cli/args.json index 1e3ecdf1..812d1af1 100644 --- a/resources/app/cli/args.json +++ b/resources/app/cli/args.json @@ -111,19 +111,14 @@ "ow_shuffle": { "choices": [ "vanilla", - "simple", - "full", - "crossed" + "parallel", + "full" ] }, "ow_keepsimilar": { "action": "store_true", "type": "bool" }, - "ow_parallel": { - "action": "store_true", - "type": "bool" - }, "shuffle": { "choices": [ "vanilla", diff --git a/resources/app/cli/lang/en.json b/resources/app/cli/lang/en.json index 3c4825f6..7050ebe6 100644 --- a/resources/app/cli/lang/en.json +++ b/resources/app/cli/lang/en.json @@ -194,19 +194,17 @@ "the overworld vanilla." ], "ow_shuffle": [ - "Select Overworld Shuffling Algorithm. (default: %(default)s)", + "This shuffles the layout of the overworld.", "Vanilla: All overworld transitions are connected the same", " way they were in the base game.", - "Simple: Overworld retains the same vanilla shape, but some overworld", - " screens will be swapped with their opposite world version.", - "Full: Overworld screen transitions will lead to other", - " overworld screens from the same world.", - "Crossed: Overworld screen transitions can lead to any other overworld screen." + "Parallel: Overworld transitions are shuffled, but both worlds", + " will have the same pattern/shape.", + "Full: Overworld transitions are shuffled, but both worlds", + " will have an independent map shape." ], "ow_keepsimilar": [ "This keeps similar edge transitions together. ie. the two west edges on", "Potion Shop will be paired with another similar pair." ], - "ow_parallel": [ "This ensures the layouts of both worlds are the same shape." ], "door_shuffle": [ "Select Door Shuffling Algorithm. (default: %(default)s)", "Basic: Doors are mixed within a single dungeon.", diff --git a/resources/app/gui/lang/en.json b/resources/app/gui/lang/en.json index 5bbb8897..4ec592e4 100644 --- a/resources/app/gui/lang/en.json +++ b/resources/app/gui/lang/en.json @@ -109,14 +109,12 @@ "randomizer.enemizer.enemizercli.online": "(get online)", - "randomizer.overworld.overworldshuffle": "Overworld Shuffle", + "randomizer.overworld.overworldshuffle": "Layout Shuffle", "randomizer.overworld.overworldshuffle.vanilla": "Vanilla", - "randomizer.overworld.overworldshuffle.simple": "Simple", + "randomizer.overworld.overworldshuffle.parallel": "Parallel", "randomizer.overworld.overworldshuffle.full": "Full", - "randomizer.overworld.overworldshuffle.crossed": "Crossed", "randomizer.overworld.keepsimilar": "Keep Similar Edges Together", - "randomizer.overworld.parallelworlds": "Parallel Worlds", "randomizer.entrance.openpyramid": "Pre-open Pyramid Hole", "randomizer.entrance.shuffleganon": "Include Ganon's Tower and Pyramid Hole in shuffle pool", diff --git a/resources/app/gui/randomize/overworld/widgets.json b/resources/app/gui/randomize/overworld/widgets.json index ee79e5a4..4a0f2034 100644 --- a/resources/app/gui/randomize/overworld/widgets.json +++ b/resources/app/gui/randomize/overworld/widgets.json @@ -2,19 +2,16 @@ "widgets": { "overworldshuffle": { "type": "selectbox", - "default": "full", + "default": "parallel", "options": [ "vanilla", + "parallel", "full" ] }, "keepsimilar": { "type": "checkbox", "default": true - }, - "parallelworlds": { - "type": "checkbox", - "default": true } } } \ No newline at end of file diff --git a/source/classes/constants.py b/source/classes/constants.py index 0d722627..68df9519 100644 --- a/source/classes/constants.py +++ b/source/classes/constants.py @@ -72,8 +72,7 @@ SETTINGSTOPROCESS = { }, "overworld": { "overworldshuffle": "ow_shuffle", - "keepsimilar": "ow_keepsimilar", - "parallelworlds": "ow_parallel" + "keepsimilar": "ow_keepsimilar" }, "entrance": { "openpyramid": "openpyramid", From 15c2d13de3bea82b83979a0f32a027bd3fdf635d Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 9 May 2021 19:35:03 -0500 Subject: [PATCH 3/6] Added Parallel to list that enables OW Shuffle --- Rom.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Rom.py b/Rom.py index c8c1ccde..6b94bf3c 100644 --- a/Rom.py +++ b/Rom.py @@ -595,8 +595,12 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): if world.owShuffle[player] != 'vanilla': rom.write_byte(0x18004C, 0x01) #patch for allowing Frogsmith to enter multi-entrance caves - if world.owShuffle[player] == 'full': - rom.write_byte(0x150002, 2) + if world.owShuffle[player] == 'parallel': + owMode = 1 + elif world.owShuffle[player] == 'full': + owMode = 2 + + rom.write_byte(0x150002, owMode) for edge in world.owedges: if edge.dest is not None and isinstance(edge.dest, OWEdge) and edge.player == player: From a7b148383c249f83213cdc993fc0c6f5e78cdd59 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 9 May 2021 19:46:22 -0500 Subject: [PATCH 4/6] Added OW flags to ROM --- Rom.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Rom.py b/Rom.py index 6b94bf3c..edbee122 100644 --- a/Rom.py +++ b/Rom.py @@ -601,6 +601,12 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): 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: if edge.dest is not None and isinstance(edge.dest, OWEdge) and edge.player == player: From c7b0620681d582251132adf8b03702433f484c81 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 10 May 2021 10:14:22 -0500 Subject: [PATCH 5/6] Added guaranteed Flute hint in OW shuffle --- Rom.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Rom.py b/Rom.py index edbee122..ce0ad5be 100644 --- a/Rom.py +++ b/Rom.py @@ -2003,8 +2003,17 @@ def write_strings(rom, world, player, team): this_hint = location + ' contains ' + hint_text(world.get_location(location, player).item) + '.' 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. items_to_hint = RelevantItems.copy() + if world.owShuffle[player] in ['parallel','full']: + items_to_hint.remove('Ocarina') if world.keyshuffle[player]: items_to_hint.extend(SmallKeys) if world.bigkeyshuffle[player]: @@ -2012,6 +2021,7 @@ def write_strings(rom, world, player, team): random.shuffle(items_to_hint) 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 += 1 if world.owShuffle[player] in ['parallel', 'full'] else 0 while hint_count > 0: this_item = items_to_hint.pop(0) this_location = world.find_items_not_key_only(this_item, player) From 586efbd757780fbd60c15071fced026bf57b51d4 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 10 May 2021 11:38:01 -0500 Subject: [PATCH 6/6] Version bump --- CHANGELOG.md | 5 +++++ OverworldShuffle.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d24f0c45..0dbaf44f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # 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 - Made possible fix for Standard - Merged DR v0.3.1.10 - Fixed Standard generation diff --git a/OverworldShuffle.py b/OverworldShuffle.py index f1adb4a3..a3151d9d 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -3,7 +3,7 @@ from BaseClasses import OWEdge, WorldType, Direction, Terrain from Utils import bidict from OWEdges import OWEdgeGroups, IsParallel -__version__ = '0.1.2.1u' +__version__ = '0.1.2.2u' def link_overworld(world, player): # setup mandatory connections