Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fill: allow for single player fill restrictive placement and sweeping #2415

Merged
merged 9 commits into from
May 4, 2024
5 changes: 3 additions & 2 deletions BaseClasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -693,9 +693,10 @@ def can_reach(self,
spot = self.multiworld.get_region(spot, player)
return spot.can_reach(self)

def sweep_for_events(self, key_only: bool = False, locations: Optional[Iterable[Location]] = None) -> None:
def sweep_for_events(self, key_only: bool = False, locations: Optional[Iterable[Location]] = None,
player: Optional[int] = None) -> None:
alwaysintreble marked this conversation as resolved.
Show resolved Hide resolved
if locations is None:
locations = self.multiworld.get_filled_locations()
locations = self.multiworld.get_filled_locations(player)
reachable_events = True
# since the loop has a good chance to run more than once, only filter the events once
locations = {location for location in locations if location.event and location not in self.events and
Expand Down
18 changes: 11 additions & 7 deletions Fill.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ def _log_fill_progress(name: str, placed: int, total_items: int) -> None:
logging.info(f"Current fill step ({name}) at {placed}/{total_items} items placed.")


def sweep_from_pool(base_state: CollectionState, itempool: typing.Sequence[Item] = tuple()) -> CollectionState:
def sweep_from_pool(base_state: CollectionState, itempool: typing.Sequence[Item] = tuple(),
player: typing.Optional[int] = None) -> CollectionState:
new_state = base_state.copy()
for item in itempool:
new_state.collect(item, True)
new_state.sweep_for_events()
new_state.sweep_for_events(player=player)
return new_state


Expand Down Expand Up @@ -66,7 +67,7 @@ def fill_restrictive(world: MultiWorld, base_state: CollectionState, locations:
item_pool.pop(p)
break
maximum_exploration_state = sweep_from_pool(
base_state, item_pool + unplaced_items)
base_state, item_pool + unplaced_items, item.player if single_player_placement else None)

has_beaten_game = world.has_beaten_game(maximum_exploration_state)

Expand Down Expand Up @@ -112,7 +113,8 @@ def fill_restrictive(world: MultiWorld, base_state: CollectionState, locations:

location.item = None
placed_item.location = None
swap_state = sweep_from_pool(base_state, [placed_item] if unsafe else [])
swap_state = sweep_from_pool(base_state, [placed_item] if unsafe else [],
item.player if single_player_placement else None)
# unsafe means swap_state assumes we can somehow collect placed_item before item_to_place
# by continuing to swap, which is not guaranteed. This is unsafe because there is no mechanic
# to clean that up later, so there is a chance generation fails.
Expand Down Expand Up @@ -171,7 +173,7 @@ def fill_restrictive(world: MultiWorld, base_state: CollectionState, locations:

if cleanup_required:
# validate all placements and remove invalid ones
state = sweep_from_pool(base_state, [])
state = sweep_from_pool(base_state, [], item.player if single_player_placement else None)
for placement in placements:
if world.accessibility[placement.item.player] != "minimal" and not placement.can_reach(state):
placement.item.location = None
Expand Down Expand Up @@ -446,14 +448,16 @@ def mark_for_locking(location: Location):

if prioritylocations:
# "priority fill"
fill_restrictive(world, world.state, prioritylocations, progitempool, swap=False, on_place=mark_for_locking,
fill_restrictive(world, world.state, prioritylocations, progitempool,
single_player_placement=world.players == 1, swap=False, on_place=mark_for_locking,
name="Priority")
accessibility_corrections(world, world.state, prioritylocations, progitempool)
defaultlocations = prioritylocations + defaultlocations

if progitempool:
# "advancement/progression fill"
fill_restrictive(world, world.state, defaultlocations, progitempool, name="Progression")
fill_restrictive(world, world.state, defaultlocations, progitempool, single_player_placement=world.players == 1,
name="Progression")
if progitempool:
raise FillError(
f'Not enough locations for progress items. There are {len(progitempool)} more items than locations')
Expand Down
Loading