diff --git a/src/Helpers.py b/src/Helpers.py index 4d037e3..316aa43 100644 --- a/src/Helpers.py +++ b/src/Helpers.py @@ -211,6 +211,18 @@ def format_to_valid_identifier(input: str) -> str: input = "_" + input return input.replace(" ", "_") +def remove_specific_item(source: list[Item], item: Item) -> Item: + """Remove and return an item from a list in a more precise way, base AP only check for name and player id before removing. + \nThis checks that the item IS the exact same in the list. + \nRaise ValueError if the item is not in the list.""" + # Inspired by https://stackoverflow.com/a/58761459 + for i in range(len(source)): # check all elements of the list like a normal remove does + if item is source[i]: + return source.pop(i) + + # if we reach here we didn't get any item + raise ValueError(f"Item '{item.name}' could not be found in source list") + class ProgItemsCat(IntEnum): VALUE = 1 CATEGORY = 2 diff --git a/src/__init__.py b/src/__init__.py index 1961bcb..69dd9d1 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -20,7 +20,7 @@ from .Items import ManualItem from .Rules import set_rules from .Options import manual_options_data -from .Helpers import is_item_enabled, get_option_value, get_items_for_player, resolve_yaml_option, format_state_prog_items_key, ProgItemsCat +from .Helpers import is_item_enabled, get_option_value, remove_specific_item, resolve_yaml_option, format_state_prog_items_key, ProgItemsCat from BaseClasses import CollectionState, ItemClassification, Item from Options import PerGameCommonOptions @@ -245,7 +245,7 @@ def stringCheck(string: str) -> ItemClassification: for starting_item in items: items_started.append(starting_item) self.multiworld.push_precollected(starting_item) - pool.remove(starting_item) + remove_specific_item(pool, starting_item) self.start_inventory = {i.name: items_started.count(i) for i in items_started} @@ -379,7 +379,7 @@ def generate_basic(self): location.place_locked_item(item_to_place) # remove the item we're about to place from the pool so it isn't placed twice - self.multiworld.itempool.remove(item_to_place) + remove_specific_item(self.multiworld.itempool, item_to_place) after_generate_basic(self, self.multiworld, self.player) @@ -490,7 +490,7 @@ def adjust_filler_items(self, item_pool, traps): else: logging.warning("Could not remove enough non-progression items from the pool.") break - item_pool.remove(popped) + remove_specific_item(item_pool, popped) return item_pool diff --git a/src/hooks/World.py b/src/hooks/World.py index fe2e82e..62db224 100644 --- a/src/hooks/World.py +++ b/src/hooks/World.py @@ -12,7 +12,7 @@ from ..Data import game_table, item_table, location_table, region_table # These helper methods allow you to determine if an option has been set, or what its value is, for any player in the multiworld -from ..Helpers import is_option_enabled, get_option_value, format_state_prog_items_key, ProgItemsCat +from ..Helpers import is_option_enabled, get_option_value, format_state_prog_items_key, ProgItemsCat, remove_specific_item # calling logging.info("message") anywhere below in this file will output the message to both console and log file import logging @@ -80,7 +80,7 @@ def before_create_items_filler(item_pool: list, world: World, multiworld: MultiW for itemName in itemNamesToRemove: item = next(i for i in item_pool if i.name == itemName) - item_pool.remove(item) + remove_specific_item(item_pool, item) return item_pool @@ -90,7 +90,7 @@ def before_create_items_filler(item_pool: list, world: World, multiworld: MultiW # location = next(l for l in multiworld.get_unfilled_locations(player=player) if l.name == "Location Name") # item_to_place = next(i for i in item_pool if i.name == "Item Name") # location.place_locked_item(item_to_place) - # item_pool.remove(item_to_place) + # remove_specific_item(item_pool, item_to_place) # The complete item pool prior to being set for generation is provided here, in case you want to make changes to it def after_create_items(item_pool: list, world: World, multiworld: MultiWorld, player: int) -> list: