diff --git a/BaseClasses.py b/BaseClasses.py index 478dd1cf..634c2a83 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -531,7 +531,7 @@ class MultiWorld(): beatable_fulfilled = False - def location_conditition(location: Location): + def location_condition(location: Location): """Determine if this location has to be accessible, location is already filtered by location_relevant""" if location.player in players["minimal"]: return False @@ -548,7 +548,7 @@ class MultiWorld(): def all_done(): """Check if all access rules are fulfilled""" if beatable_fulfilled: - if any(location_conditition(location) for location in locations): + if any(location_condition(location) for location in locations): return False # still locations required to be collected return True diff --git a/Fill.py b/Fill.py index c62eaabd..4b095eb1 100644 --- a/Fill.py +++ b/Fill.py @@ -4,9 +4,10 @@ import collections import itertools from collections import Counter, deque -from BaseClasses import CollectionState, Location, LocationProgressType, MultiWorld, Item +from BaseClasses import CollectionState, Location, LocationProgressType, MultiWorld, Item, ItemClassification from worlds.AutoWorld import call_all +from worlds.generic.Rules import add_item_rule class FillError(RuntimeError): @@ -209,6 +210,34 @@ def fast_fill(world: MultiWorld, return item_pool[placing:], fill_locations[placing:] +def accessibility_corrections(world: MultiWorld, state: CollectionState, locations, pool=[]): + maximum_exploration_state = sweep_from_pool(state, pool) + minimal_players = {player for player in world.player_ids if world.accessibility[player] == "minimal"} + unreachable_locations = [location for location in world.get_locations() if location.player in minimal_players and + not location.can_reach(maximum_exploration_state)] + for location in unreachable_locations: + if (location.item is not None and location.item.advancement and location.address is not None and not + location.locked and location.item.player not in minimal_players): + pool.append(location.item) + state.remove(location.item) + location.item = None + location.event = False + if location in state.events: + state.events.remove(location) + locations.append(location) + + if pool: + fill_restrictive(world, state, locations, pool) + + +def inaccessible_location_rules(world: MultiWorld, state: CollectionState, locations): + maximum_exploration_state = sweep_from_pool(state, []) + unreachable_locations = [location for location in locations if not location.can_reach(maximum_exploration_state)] + for location in unreachable_locations: + add_item_rule(location, lambda item: not ((item.classification & 0b0011) and + world.accessibility[item.player] != 'minimal')) + + def distribute_items_restrictive(world: MultiWorld) -> None: fill_locations = sorted(world.get_unfilled_locations()) world.random.shuffle(fill_locations) @@ -239,7 +268,15 @@ def distribute_items_restrictive(world: MultiWorld) -> None: defaultlocations = locations[LocationProgressType.DEFAULT] excludedlocations = locations[LocationProgressType.EXCLUDED] - fill_restrictive(world, world.state, prioritylocations, progitempool, lock=True) + prioritylocations_lock = prioritylocations.copy() + + fill_restrictive(world, world.state, prioritylocations, progitempool) + accessibility_corrections(world, world.state, prioritylocations, progitempool) + + for location in prioritylocations_lock: + if location.item: + location.locked = True + if prioritylocations: defaultlocations = prioritylocations + defaultlocations @@ -248,6 +285,9 @@ def distribute_items_restrictive(world: MultiWorld) -> None: if progitempool: raise FillError( f'Not enough locations for progress items. There are {len(progitempool)} more items than locations') + accessibility_corrections(world, world.state, defaultlocations) + + inaccessible_location_rules(world, world.state, defaultlocations) remaining_fill(world, excludedlocations, filleritempool) if excludedlocations: