diff --git a/BaseClasses.py b/BaseClasses.py index 55d586a7..77f3d93e 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -2897,6 +2897,7 @@ class Spoiler(object): 'pseudoboots': self.world.pseudoboots, 'triforcegoal': self.world.treasure_hunt_count, 'triforcepool': self.world.treasure_hunt_total, + 'race': self.world.settings.world_rep['meta']['race'], 'code': {p: Settings.make_code(self.world, p) for p in range(1, self.world.players + 1)} } diff --git a/Fill.py b/Fill.py index 0c1033b2..64abd448 100644 --- a/Fill.py +++ b/Fill.py @@ -279,6 +279,10 @@ def recovery_placement(item_to_place, locations, world, state, base_state, itemp if spot_to_fill: return spot_to_fill return None + # explicitly fail these cases + elif world.algorithm in ['dungeon_only', 'major_only']: + raise FillError(f'Rare placement for {world.algorithm} detected. {item_to_place} unable to be placed.' + f' Try a different seed') else: other_locations = [x for x in locations if x not in attempted] for location in other_locations: @@ -425,7 +429,7 @@ def distribute_items_restrictive(world, gftower_trash=False, fill_locations=None else: max_trash = gt_count scaled_trash = math.floor(max_trash * scale_factor) - if world.goal[player] in ['triforcehunt', 'trinity', 'ganonhunt']: + if world.goal[player] in ['triforcehunt', 'trinity', 'ganonhunt'] or world.algorithm == 'dungeon_only': gftower_trash_count = random.randint(scaled_trash, max_trash) else: gftower_trash_count = random.randint(0, scaled_trash) diff --git a/Main.py b/Main.py index 66122931..6f0bad59 100644 --- a/Main.py +++ b/Main.py @@ -36,7 +36,7 @@ from source.overworld.EntranceShuffle2 import link_entrances_new from source.tools.BPS import create_bps_from_data from source.classes.CustomSettings import CustomSettings -version_number = '1.2.0.16' +version_number = '1.2.0.17' version_branch = '-u' __version__ = f'{version_number}{version_branch}' diff --git a/RELEASENOTES.md b/RELEASENOTES.md index a84d0551..e3d09589 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -109,6 +109,11 @@ These are now independent of retro mode and have three options: None, Random, an # Bug Fixes and Notes +* 1.2.0.17u + * Fixed logic bug that allowed Pearl to be behind Graveyard Cave or King's Tomb entrances with only Mirror and West Dark World access (cross world shuffles only) + * Removed backup locations for Dungeon Only and Major Only algorithms. If item cannot be placed in the appropriate location, the seed will fail to generate instead + * Fix for Non-ER Inverted Experimental (Aga and GT weren't logically swapped) + * Fix for customizer setting crystals to 0 for either GT/Ganon * 1.2.0.16u * Fix for partial key logic on vanilla Mire * Fix for Kholdstare Shell collision when at Lanmo 2 diff --git a/source/classes/CustomSettings.py b/source/classes/CustomSettings.py index a177a141..c5ff7e78 100644 --- a/source/classes/CustomSettings.py +++ b/source/classes/CustomSettings.py @@ -2,6 +2,7 @@ import os import urllib.request import urllib.parse import yaml +from typing import Any from yaml.representer import Representer from collections import defaultdict from pathlib import Path @@ -46,8 +47,8 @@ class CustomSettings(object): return meta['players'] def adjust_args(self, args): - def get_setting(value, default): - if value: + def get_setting(value: Any, default): + if value or value == 0: if isinstance(value, dict): return random.choices(list(value.keys()), list(value.values()), k=1)[0] else: diff --git a/source/item/FillUtil.py b/source/item/FillUtil.py index 0eee5f69..87d6381d 100644 --- a/source/item/FillUtil.py +++ b/source/item/FillUtil.py @@ -151,9 +151,6 @@ def create_item_pool_config(world): config.item_pool[player] = determine_major_items(world, player) config.location_groups[0].locations = set(groups.locations) config.reserved_locations[player].update(groups.locations) - backup = (mode_grouping['Heart Pieces'] + mode_grouping['Dungeon Trash'] + mode_grouping['Shops'] - + mode_grouping['Overworld Trash'] + mode_grouping['GT Trash'] + mode_grouping['RetroShops']) - config.location_groups[1].locations = set(backup) elif world.algorithm == 'dungeon_only': config.location_groups = [ LocationGroup('Dungeons'), @@ -171,9 +168,6 @@ def create_item_pool_config(world): for player in range(1, world.players + 1): config.item_pool[player] = determine_major_items(world, player) config.location_groups[0].locations = set(dungeon_set) - backup = (mode_grouping['Heart Pieces'] + mode_grouping['Overworld Major'] - + mode_grouping['Overworld Trash'] + mode_grouping['Shops'] + mode_grouping['RetroShops']) - config.location_groups[1].locations = set(backup) def district_item_pool_config(world): @@ -419,11 +413,7 @@ def filter_locations(item_to_place, locations, world, vanilla_skip=False, potion if item_to_place.name in config.item_pool[item_to_place.player]: restricted = config.location_groups[0].locations filtered = [l for l in locations if l.name in restricted] - if len(filtered) == 0: - restricted = config.location_groups[1].locations - filtered = [l for l in locations if l.name in restricted] - # bias toward certain location in overflow? (thinking about this for major_bias) - return filtered if len(filtered) > 0 else locations + return filtered if world.algorithm == 'district': config = world.item_pool_config if ((isinstance(item_to_place,str) and item_to_place == 'Placeholder')