diff --git a/OverworldShuffle.py b/OverworldShuffle.py index c73c5ea6..0854d1e1 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -632,17 +632,56 @@ def shuffle_tiles(world, groups, result_list, do_grouped, player): parity[5] -= 1 group_parity[group[0]] = parity - attempts = 1000 + # customizer adjustments + undefined_chance = 50 + flipped_groups = list() + always_removed = list() + if world.customizer: + if not do_grouped: + custom_flips = world.customizer.get_owtileflips() + if custom_flips: + nonflipped_groups = list() + forced_flips = list() + forced_nonflips = list() + player_key = player + if 'undefined_chance' in custom_flips[player_key]: + undefined_chance = custom_flips[player_key]['undefined_chance'] + if 'force_flip' in custom_flips[player_key]: + forced_flips = custom_flips[player_key]['force_flip'] + if 'force_no_flip' in custom_flips[player_key]: + forced_nonflips = custom_flips[player_key]['force_no_flip'] + + for group in groups: + if any(owid in group[0] for owid in forced_nonflips): + nonflipped_groups.append(group) + if any(owid in group[0] for owid in forced_flips): + flipped_groups.append(group) + + # Check if there are any groups that appear in both sets + if any(group in flipped_groups for group in nonflipped_groups): + raise GenerationException('Conflict found when flipping tiles') + + for g in nonflipped_groups: + always_removed.append(g) + if undefined_chance == 0: + for g in [g for g in groups if g not in flipped_groups + always_removed]: + always_removed.append(g) + + attempts = 1 + if 0 < undefined_chance < 100: + # do roughly 1000 attempts at a full list + attempts = len(groups) - len(always_removed) + attempts = (attempts ** 1.9) + (attempts * 10) + 1 while True: if attempts == 0: # expected to only occur with custom flips raise GenerationException('Could not find valid tile flips') # tile shuffle happens here - removed = list() - for group in groups: - #if 0x1b in group[0] or 0x13 in group[0] or (0x1a in group[0] and world.owCrossed[player] == 'none'): # TODO: Standard + Inverted - if random.randint(0, 1): - removed.append(group) + removed = copy.deepcopy(always_removed) + if 0 < undefined_chance < 100: + for group in [g for g in groups if g not in always_removed]: + if group not in flipped_groups and random.randint(1, 100) > undefined_chance: + removed.append(group) # save shuffled tiles to list new_results = [[],[],[]] diff --git a/docs/Customizer.md b/docs/Customizer.md index b95081bd..9e45635a 100644 --- a/docs/Customizer.md +++ b/docs/Customizer.md @@ -86,7 +86,30 @@ You may define an item, and a list of locations. The locations may be weighted i #### NotPlacementGroup You may define an item and a list of locations that an item should not be placed at. This will apply to all items of that type. The logic is considered for this. If it is otherwise impossible, the item will be considered for the listed locations. This is important for small key layouts mostly, but it will try other locations first. - + +### ow-tileflips + +This must be defined by player. Each player number should be listed with the appropriate sections and each of these players MUST have `ow_mixed: true` in the `settings` section in order for any values here to take effect. This section has three primary subsections: `force_flip`, `force_no_flip`, and `undefined`. + +#### force_flip / force_no_flip + +`force_flip` and `force_no_flip` should be used for tiles you want to flip or not flip. These sections are optional but must contain a list of OW Screen IDs. It is common to reference OW Screen IDs in hexadecimal (altho decimal is okay to use, if preferred), which range from: + 0x00 to 0x3f - Light World + 0x40 to 0x7f - Dark World + 0x80 - Pedestal/Hobo + 0x81 - Zoras Domain + +Here is an example which forces Links House and Sanctuary screens to stay in their original worlds. Note: It is unnecessary to supply both worlds' IDs. Links House is 0x2c and Big Bomb Shop is 0x6c. +``` +force_no_flip: + - 0x2c + - 0x13 +``` + +#### undefined_chance + +`undefined_chance` should be used to determine how to handle all the remaining tiles that aren't explicitly defined in the earlier step. This represents the percent chance a tile will flip. This value can be set from 0 to 100 (default is 50). A value of 0 means there is a 0% chance it will be flipped. + ### entrances This must be defined by player. Each player number should be listed with the appropriate sections. This section has three primary subsections: `entrances`, `exits`, and `two-way`. @@ -111,10 +134,6 @@ This must be defined by player. Each player number should be listed with the app `Chicken House: Kakariko Shop` if you walk into Chicken House door, you will in the Kakariko Shop. -##### Known Issues - -Chris Houlihan and Links House should be specified together or not at all. - ### doors This must be defined by player. Each player number should be listed with the appropriate sections. This section has three primary subsections: `lobbies` and `doors`. diff --git a/docs/customizer_example.yaml b/docs/customizer_example.yaml index 3d0c7624..188c17d6 100644 --- a/docs/customizer_example.yaml +++ b/docs/customizer_example.yaml @@ -61,6 +61,14 @@ placements: Palace of Darkness - Big Chest: Hammer Capacity Upgrade - Left: Moon Pearl Turtle Rock - Pokey 2 Key Drop: Ice Rod +ow-tileflips: + 1: + force_flip: + - 0x1b + force_no_flip: + - 0x2c + - 0x18 + undefined_chance: 50 entrances: 1: entrances: diff --git a/docs/standardinverted.yaml b/docs/standardinverted.yaml new file mode 100644 index 00000000..c5590090 --- /dev/null +++ b/docs/standardinverted.yaml @@ -0,0 +1,10 @@ +meta: + players: 1 +settings: + 1: + mode: standard + ow_mixed: true +ow-tileflips: + 1: + undefined_chance: 100 + diff --git a/source/classes/CustomSettings.py b/source/classes/CustomSettings.py index fd15253f..8108712e 100644 --- a/source/classes/CustomSettings.py +++ b/source/classes/CustomSettings.py @@ -72,6 +72,7 @@ class CustomSettings(object): args.mystery = True else: settings = defaultdict(lambda: None, player_setting) + args.ow_mixed[p] = get_setting(settings['ow_mixed'], args.ow_mixed[p]) args.shuffle[p] = get_setting(settings['shuffle'], args.shuffle[p]) args.door_shuffle[p] = get_setting(settings['door_shuffle'], args.door_shuffle[p]) args.logic[p] = get_setting(settings['logic'], args.logic[p]) @@ -176,6 +177,11 @@ class CustomSettings(object): return self.file_source['advanced_placements'] return None + def get_owtileflips(self): + if 'ow-tileflips' in self.file_source: + return self.file_source['ow-tileflips'] + return None + def get_entrances(self): if 'entrances' in self.file_source: return self.file_source['entrances']