From 1371c63a8debded46b764ac1953134b1f0491bfa Mon Sep 17 00:00:00 2001 From: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Date: Fri, 29 Nov 2024 07:14:23 +0100 Subject: [PATCH] Core: Actually take item from pool when plandoing from_pool (#2420) * Actually take item from pool when plandoing from_pool * Remove the awkward index thing * oops left a comment in * there wasn't a line break here before * Only remove if actually found, check against player number * oops * Go back to index based system so we can just remove at the end * Comment * Fix error on None * Update Fill.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> --------- Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> --- Fill.py | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/Fill.py b/Fill.py index 706cca657457..912b4d05bed9 100644 --- a/Fill.py +++ b/Fill.py @@ -978,15 +978,32 @@ def failed(warning: str, force: typing.Union[bool, str]) -> None: multiworld.random.shuffle(items) count = 0 err: typing.List[str] = [] - successful_pairs: typing.List[typing.Tuple[Item, Location]] = [] + successful_pairs: typing.List[typing.Tuple[int, Item, Location]] = [] + claimed_indices: typing.Set[typing.Optional[int]] = set() for item_name in items: - item = multiworld.worlds[player].create_item(item_name) + index_to_delete: typing.Optional[int] = None + if from_pool: + try: + # If from_pool, try to find an existing item with this name & player in the itempool and use it + index_to_delete, item = next( + (i, item) for i, item in enumerate(multiworld.itempool) + if item.player == player and item.name == item_name and i not in claimed_indices + ) + except StopIteration: + warn( + f"Could not remove {item_name} from pool for {multiworld.player_name[player]} as it's already missing from it.", + placement['force']) + item = multiworld.worlds[player].create_item(item_name) + else: + item = multiworld.worlds[player].create_item(item_name) + for location in reversed(candidates): if (location.address is None) == (item.code is None): # either both None or both not None if not location.item: if location.item_rule(item): if location.can_fill(multiworld.state, item, False): - successful_pairs.append((item, location)) + successful_pairs.append((index_to_delete, item, location)) + claimed_indices.add(index_to_delete) candidates.remove(location) count = count + 1 break @@ -998,6 +1015,7 @@ def failed(warning: str, force: typing.Union[bool, str]) -> None: err.append(f"Cannot place {item_name} into already filled location {location}.") else: err.append(f"Mismatch between {item_name} and {location}, only one is an event.") + if count == maxcount: break if count < placement['count']['min']: @@ -1005,17 +1023,16 @@ def failed(warning: str, force: typing.Union[bool, str]) -> None: failed( f"Plando block failed to place {m - count} of {m} item(s) for {multiworld.player_name[player]}, error(s): {' '.join(err)}", placement['force']) - for (item, location) in successful_pairs: + + # Sort indices in reverse so we can remove them one by one + successful_pairs = sorted(successful_pairs, key=lambda successful_pair: successful_pair[0] or 0, reverse=True) + + for (index, item, location) in successful_pairs: multiworld.push_item(location, item, collect=False) location.locked = True logging.debug(f"Plando placed {item} at {location}") - if from_pool: - try: - multiworld.itempool.remove(item) - except ValueError: - warn( - f"Could not remove {item} from pool for {multiworld.player_name[player]} as it's already missing from it.", - placement['force']) + if index is not None: # If this item is from_pool and was found in the pool, remove it. + multiworld.itempool.pop(index) except Exception as e: raise Exception(