diff --git a/Fill.py b/Fill.py index 8aca4b98e558..4ce02ec77f39 100644 --- a/Fill.py +++ b/Fill.py @@ -508,6 +508,32 @@ def distribute_items_restrictive(multiworld: MultiWorld, f"{[(item.location, item) for item in multiworld.itempool if item.location is not None]}" ) + # cheap quick guard against unreachable goals to avoid wasting fill and progression balancing time + # collect all items and sweep pre_fill advancements because fill doesn't catch when they're unreachable + guard_state = multiworld.state.copy() + # super metroid can fail this check because of maxdiff, which it corrects in post fill, so we set maxdiff to max in + # our state to prevent a false warning. + smbm = getattr(guard_state, "smbm", None) + if smbm is not None: + for p in multiworld.player_ids: + if multiworld.game[p] == "Super Metroid" and p in smbm: + smbm[p].maxDiff = 8675309 + + for item in multiworld.itempool: + if item.advancement: + guard_state.collect(item, True) + pre_fill_advancements = [ + location for location in multiworld.get_locations() + if location.item is not None and location.item.advancement + ] + guard_state.sweep_for_advancements(locations=pre_fill_advancements) + unreachable_goals = [ + multiworld.player_name[player] for player in multiworld.player_ids + if not multiworld.has_beaten_game(guard_state, player) + ] + if unreachable_goals: + logging.warning(f"Prefill check failed for the following players. Generation may fail: {unreachable_goals}") + fill_locations = sorted(multiworld.get_unfilled_locations()) multiworld.random.shuffle(fill_locations) # get items to distribute @@ -900,7 +926,7 @@ def item_percentage(player: int, num: int) -> float: items_to_replace.sort() multiworld.random.shuffle(items_to_replace) - # Start swapping items. Since we swap into earlier spheres, no need for accessibility checks. + # Start swapping items. Since we swap into earlier spheres, no need for accessibility checks. while replacement_locations and items_to_replace: old_location = items_to_replace.pop() for i, new_location in enumerate(replacement_locations):