mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 20:21:32 -06:00
Core: Fix a playthrough crash when a world uses "placement based logic" (#3915)
* Fix playthrough * oops * oops 2 * I don't like this * that should do it * Update BaseClasses.py Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com> * Update BaseClasses.py --------- Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
This commit is contained in:
@@ -559,7 +559,9 @@ class MultiWorld():
|
|||||||
else:
|
else:
|
||||||
return all((self.has_beaten_game(state, p) for p in range(1, self.players + 1)))
|
return all((self.has_beaten_game(state, p) for p in range(1, self.players + 1)))
|
||||||
|
|
||||||
def can_beat_game(self, starting_state: Optional[CollectionState] = None) -> bool:
|
def can_beat_game(self,
|
||||||
|
starting_state: Optional[CollectionState] = None,
|
||||||
|
locations: Optional[Iterable[Location]] = None) -> bool:
|
||||||
if starting_state:
|
if starting_state:
|
||||||
if self.has_beaten_game(starting_state):
|
if self.has_beaten_game(starting_state):
|
||||||
return True
|
return True
|
||||||
@@ -568,7 +570,9 @@ class MultiWorld():
|
|||||||
state = CollectionState(self)
|
state = CollectionState(self)
|
||||||
if self.has_beaten_game(state):
|
if self.has_beaten_game(state):
|
||||||
return True
|
return True
|
||||||
prog_locations = {location for location in self.get_locations() if location.item
|
|
||||||
|
base_locations = self.get_locations() if locations is None else locations
|
||||||
|
prog_locations = {location for location in base_locations if location.item
|
||||||
and location.item.advancement and location not in state.locations_checked}
|
and location.item.advancement and location not in state.locations_checked}
|
||||||
|
|
||||||
while prog_locations:
|
while prog_locations:
|
||||||
@@ -1603,21 +1607,19 @@ class Spoiler:
|
|||||||
|
|
||||||
# in the second phase, we cull each sphere such that the game is still beatable,
|
# in the second phase, we cull each sphere such that the game is still beatable,
|
||||||
# reducing each range of influence to the bare minimum required inside it
|
# reducing each range of influence to the bare minimum required inside it
|
||||||
restore_later: Dict[Location, Item] = {}
|
required_locations = {location for sphere in collection_spheres for location in sphere}
|
||||||
for num, sphere in reversed(tuple(enumerate(collection_spheres))):
|
for num, sphere in reversed(tuple(enumerate(collection_spheres))):
|
||||||
to_delete: Set[Location] = set()
|
to_delete: Set[Location] = set()
|
||||||
for location in sphere:
|
for location in sphere:
|
||||||
# we remove the item at location and check if game is still beatable
|
# we remove the location from required_locations to sweep from, and check if the game is still beatable
|
||||||
logging.debug('Checking if %s (Player %d) is required to beat the game.', location.item.name,
|
logging.debug('Checking if %s (Player %d) is required to beat the game.', location.item.name,
|
||||||
location.item.player)
|
location.item.player)
|
||||||
old_item = location.item
|
required_locations.remove(location)
|
||||||
location.item = None
|
if multiworld.can_beat_game(state_cache[num], required_locations):
|
||||||
if multiworld.can_beat_game(state_cache[num]):
|
|
||||||
to_delete.add(location)
|
to_delete.add(location)
|
||||||
restore_later[location] = old_item
|
|
||||||
else:
|
else:
|
||||||
# still required, got to keep it around
|
# still required, got to keep it around
|
||||||
location.item = old_item
|
required_locations.add(location)
|
||||||
|
|
||||||
# cull entries in spheres for spoiler walkthrough at end
|
# cull entries in spheres for spoiler walkthrough at end
|
||||||
sphere -= to_delete
|
sphere -= to_delete
|
||||||
@@ -1634,7 +1636,7 @@ class Spoiler:
|
|||||||
logging.debug('Checking if %s (Player %d) is required to beat the game.', item.name, item.player)
|
logging.debug('Checking if %s (Player %d) is required to beat the game.', item.name, item.player)
|
||||||
precollected_items.remove(item)
|
precollected_items.remove(item)
|
||||||
multiworld.state.remove(item)
|
multiworld.state.remove(item)
|
||||||
if not multiworld.can_beat_game():
|
if not multiworld.can_beat_game(multiworld.state, required_locations):
|
||||||
# Add the item back into `precollected_items` and collect it into `multiworld.state`.
|
# Add the item back into `precollected_items` and collect it into `multiworld.state`.
|
||||||
multiworld.push_precollected(item)
|
multiworld.push_precollected(item)
|
||||||
else:
|
else:
|
||||||
@@ -1676,9 +1678,6 @@ class Spoiler:
|
|||||||
self.create_paths(state, collection_spheres)
|
self.create_paths(state, collection_spheres)
|
||||||
|
|
||||||
# repair the multiworld again
|
# repair the multiworld again
|
||||||
for location, item in restore_later.items():
|
|
||||||
location.item = item
|
|
||||||
|
|
||||||
for item in removed_precollected:
|
for item in removed_precollected:
|
||||||
multiworld.push_precollected(item)
|
multiworld.push_precollected(item)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user