Skip to content

SC2: Fix unused_items refill to respect item dependencies. #3116

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

Merged
merged 2 commits into from
Apr 11, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 50 additions & 5 deletions worlds/sc2/PoolFilter.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,8 @@ def has_units_per_structure(self) -> bool:

def generate_reduced_inventory(self, inventory_size: int, mission_requirements: List[Tuple[str, Callable]]) -> List[Item]:
"""Attempts to generate a reduced inventory that can fulfill the mission requirements."""
inventory = list(self.item_pool)
locked_items = list(self.locked_items)
inventory: List[Item] = list(self.item_pool)
locked_items: List[Item] = list(self.locked_items)
item_list = get_full_item_list()
self.logical_inventory = [
item.name for item in inventory + locked_items + self.existing_items
Expand Down Expand Up @@ -346,7 +346,7 @@ def attempt_removal(item: Item) -> bool:
removable_generic_items.append(item)

# Main cull process
unused_items = [] # Reusable items for the second pass
unused_items: List[str] = [] # Reusable items for the second pass
while len(inventory) + len(locked_items) > inventory_size:
if len(inventory) == 0:
# There are more items than locations and all of them are already locked due to YAML or logic.
Expand Down Expand Up @@ -394,18 +394,34 @@ def attempt_removal(item: Item) -> bool:
if attempt_removal(item):
unused_items.append(item.name)

unused_items = [
unused_item for unused_item in unused_items
if item_list[unused_item].parent_item is None
or item_list[unused_item].parent_item in (inventory + locked_items + self.existing_items)
]

# Removing extra dependencies
# WoL
logical_inventory_set = set(self.logical_inventory)
if not spider_mine_sources & logical_inventory_set:
inventory = [item for item in inventory if not item.name.endswith("(Spider Mine)")]
unused_items = [item_name for item_name in unused_items if not item_name.endswith("(Spider Mine)")]
if not BARRACKS_UNITS & logical_inventory_set:
inventory = [item for item in inventory if
not (item.name.startswith(ItemNames.TERRAN_INFANTRY_UPGRADE_PREFIX) or item.name == ItemNames.ORBITAL_STRIKE)]
inventory = [
item for item in inventory
if not (item.name.startswith(ItemNames.TERRAN_INFANTRY_UPGRADE_PREFIX)
or item.name == ItemNames.ORBITAL_STRIKE)]
unused_items = [
item_name for item_name in unused_items
if not (item_name.startswith(
ItemNames.TERRAN_INFANTRY_UPGRADE_PREFIX)
or item_name == ItemNames.ORBITAL_STRIKE)]
if not FACTORY_UNITS & logical_inventory_set:
inventory = [item for item in inventory if not item.name.startswith(ItemNames.TERRAN_VEHICLE_UPGRADE_PREFIX)]
unused_items = [item_name for item_name in unused_items if not item_name.startswith(ItemNames.TERRAN_VEHICLE_UPGRADE_PREFIX)]
if not STARPORT_UNITS & logical_inventory_set:
inventory = [item for item in inventory if not item.name.startswith(ItemNames.TERRAN_SHIP_UPGRADE_PREFIX)]
unused_items = [item_name for item_name in unused_items if not item_name.startswith(ItemNames.TERRAN_SHIP_UPGRADE_PREFIX)]
# HotS
# Baneling without sources => remove Baneling and upgrades
if (ItemNames.ZERGLING_BANELING_ASPECT in self.logical_inventory
Expand All @@ -414,62 +430,91 @@ def attempt_removal(item: Item) -> bool:
):
inventory = [item for item in inventory if item.name != ItemNames.ZERGLING_BANELING_ASPECT]
inventory = [item for item in inventory if item_list[item.name].parent_item != ItemNames.ZERGLING_BANELING_ASPECT]
unused_items = [item_name for item_name in unused_items if item_name != ItemNames.ZERGLING_BANELING_ASPECT]
unused_items = [item_name for item_name in unused_items if item_list[item_name].parent_item != ItemNames.ZERGLING_BANELING_ASPECT]
# Spawn Banelings without Zergling => remove Baneling unit, keep upgrades except macro ones
if (ItemNames.ZERGLING_BANELING_ASPECT in self.logical_inventory
and ItemNames.ZERGLING not in self.logical_inventory
and ItemNames.KERRIGAN_SPAWN_BANELINGS in self.logical_inventory
):
inventory = [item for item in inventory if item.name != ItemNames.ZERGLING_BANELING_ASPECT]
inventory = [item for item in inventory if item.name != ItemNames.BANELING_RAPID_METAMORPH]
unused_items = [item_name for item_name in unused_items if item_name != ItemNames.ZERGLING_BANELING_ASPECT]
unused_items = [item_name for item_name in unused_items if item_name != ItemNames.BANELING_RAPID_METAMORPH]
if not {ItemNames.MUTALISK, ItemNames.CORRUPTOR, ItemNames.SCOURGE} & logical_inventory_set:
inventory = [item for item in inventory if not item.name.startswith(ItemNames.ZERG_FLYER_UPGRADE_PREFIX)]
locked_items = [item for item in locked_items if not item.name.startswith(ItemNames.ZERG_FLYER_UPGRADE_PREFIX)]
unused_items = [item_name for item_name in unused_items if not item_name.startswith(ItemNames.ZERG_FLYER_UPGRADE_PREFIX)]
# T3 items removal rules - remove morph and its upgrades if the basic unit isn't in
if not {ItemNames.MUTALISK, ItemNames.CORRUPTOR} & logical_inventory_set:
inventory = [item for item in inventory if not item.name.endswith("(Mutalisk/Corruptor)")]
inventory = [item for item in inventory if item_list[item.name].parent_item != ItemNames.MUTALISK_CORRUPTOR_GUARDIAN_ASPECT]
inventory = [item for item in inventory if item_list[item.name].parent_item != ItemNames.MUTALISK_CORRUPTOR_DEVOURER_ASPECT]
inventory = [item for item in inventory if item_list[item.name].parent_item != ItemNames.MUTALISK_CORRUPTOR_BROOD_LORD_ASPECT]
inventory = [item for item in inventory if item_list[item.name].parent_item != ItemNames.MUTALISK_CORRUPTOR_VIPER_ASPECT]
unused_items = [item_name for item_name in unused_items if not item_name.endswith("(Mutalisk/Corruptor)")]
unused_items = [item_name for item_name in unused_items if item_list[item_name].parent_item != ItemNames.MUTALISK_CORRUPTOR_GUARDIAN_ASPECT]
unused_items = [item_name for item_name in unused_items if item_list[item_name].parent_item != ItemNames.MUTALISK_CORRUPTOR_DEVOURER_ASPECT]
unused_items = [item_name for item_name in unused_items if item_list[item_name].parent_item != ItemNames.MUTALISK_CORRUPTOR_BROOD_LORD_ASPECT]
unused_items = [item_name for item_name in unused_items if item_list[item_name].parent_item != ItemNames.MUTALISK_CORRUPTOR_VIPER_ASPECT]
if ItemNames.ROACH not in logical_inventory_set:
inventory = [item for item in inventory if item.name != ItemNames.ROACH_RAVAGER_ASPECT]
inventory = [item for item in inventory if item_list[item.name].parent_item != ItemNames.ROACH_RAVAGER_ASPECT]
unused_items = [item_name for item_name in unused_items if item_name != ItemNames.ROACH_RAVAGER_ASPECT]
unused_items = [item_name for item_name in unused_items if item_list[item_name].parent_item != ItemNames.ROACH_RAVAGER_ASPECT]
if ItemNames.HYDRALISK not in logical_inventory_set:
inventory = [item for item in inventory if not item.name.endswith("(Hydralisk)")]
inventory = [item for item in inventory if item_list[item.name].parent_item != ItemNames.HYDRALISK_LURKER_ASPECT]
inventory = [item for item in inventory if item_list[item.name].parent_item != ItemNames.HYDRALISK_IMPALER_ASPECT]
unused_items = [item_name for item_name in unused_items if not item_name.endswith("(Hydralisk)")]
unused_items = [item_name for item_name in unused_items if item_list[item_name].parent_item != ItemNames.HYDRALISK_LURKER_ASPECT]
unused_items = [item_name for item_name in unused_items if item_list[item_name].parent_item != ItemNames.HYDRALISK_IMPALER_ASPECT]
# LotV
# Shared unit upgrades between several units
if not {ItemNames.STALKER, ItemNames.INSTIGATOR, ItemNames.SLAYER} & logical_inventory_set:
inventory = [item for item in inventory if not item.name.endswith("(Stalker/Instigator/Slayer)")]
unused_items = [item_name for item_name in unused_items if not item_name.endswith("(Stalker/Instigator/Slayer)")]
if not {ItemNames.PHOENIX, ItemNames.MIRAGE} & logical_inventory_set:
inventory = [item for item in inventory if not item.name.endswith("(Phoenix/Mirage)")]
unused_items = [item_name for item_name in unused_items if not item_name.endswith("(Phoenix/Mirage)")]
if not {ItemNames.VOID_RAY, ItemNames.DESTROYER} & logical_inventory_set:
inventory = [item for item in inventory if not item.name.endswith("(Void Ray/Destroyer)")]
unused_items = [item_name for item_name in unused_items if not item_name.endswith("(Void Ray/Destroyer)")]
if not {ItemNames.IMMORTAL, ItemNames.ANNIHILATOR} & logical_inventory_set:
inventory = [item for item in inventory if not item.name.endswith("(Immortal/Annihilator)")]
unused_items = [item_name for item_name in unused_items if not item_name.endswith("(Immortal/Annihilator)")]
if not {ItemNames.DARK_TEMPLAR, ItemNames.AVENGER, ItemNames.BLOOD_HUNTER} & logical_inventory_set:
inventory = [item for item in inventory if not item.name.endswith("(Dark Templar/Avenger/Blood Hunter)")]
unused_items = [item_name for item_name in unused_items if not item_name.endswith("(Dark Templar/Avenger/Blood Hunter)")]
if not {ItemNames.HIGH_TEMPLAR, ItemNames.SIGNIFIER, ItemNames.ASCENDANT, ItemNames.DARK_TEMPLAR} & logical_inventory_set:
inventory = [item for item in inventory if not item.name.endswith("(Archon)")]
unused_items = [item_name for item_name in unused_items if not item_name.endswith("(Archon)")]
logical_inventory_set.difference_update([item_name for item_name in logical_inventory_set if item_name.endswith("(Archon)")])
if not {ItemNames.HIGH_TEMPLAR, ItemNames.SIGNIFIER, ItemNames.ARCHON_HIGH_ARCHON} & logical_inventory_set:
inventory = [item for item in inventory if not item.name.endswith("(High Templar/Signifier)")]
unused_items = [item_name for item_name in unused_items if not item_name.endswith("(High Templar/Signifier)")]
if ItemNames.SUPPLICANT not in logical_inventory_set:
inventory = [item for item in inventory if item.name != ItemNames.ASCENDANT_POWER_OVERWHELMING]
unused_items = [item_name for item_name in unused_items if item_name != ItemNames.ASCENDANT_POWER_OVERWHELMING]
if not {ItemNames.DARK_ARCHON, ItemNames.DARK_TEMPLAR_DARK_ARCHON_MELD} & logical_inventory_set:
inventory = [item for item in inventory if not item.name.endswith("(Dark Archon)")]
unused_items = [item_name for item_name in unused_items if not item_name.endswith("(Dark Archon)")]
if not {ItemNames.SENTRY, ItemNames.ENERGIZER, ItemNames.HAVOC} & logical_inventory_set:
inventory = [item for item in inventory if not item.name.endswith("(Sentry/Energizer/Havoc)")]
unused_items = [item_name for item_name in unused_items if not item_name.endswith("(Sentry/Energizer/Havoc)")]
if not {ItemNames.SENTRY, ItemNames.ENERGIZER, ItemNames.HAVOC, ItemNames.SHIELD_BATTERY} & logical_inventory_set:
inventory = [item for item in inventory if not item.name.endswith("(Sentry/Energizer/Havoc/Shield Battery)")]
unused_items = [item_name for item_name in unused_items if not item_name.endswith("(Sentry/Energizer/Havoc/Shield Battery)")]
if not {ItemNames.ZEALOT, ItemNames.CENTURION, ItemNames.SENTINEL} & logical_inventory_set:
inventory = [item for item in inventory if not item.name.endswith("(Zealot/Sentinel/Centurion)")]
unused_items = [item_name for item_name in unused_items if not item_name.endswith("(Zealot/Sentinel/Centurion)")]
# Static defense upgrades only if static defense present
if not {ItemNames.PHOTON_CANNON, ItemNames.KHAYDARIN_MONOLITH, ItemNames.NEXUS_OVERCHARGE, ItemNames.SHIELD_BATTERY} & logical_inventory_set:
inventory = [item for item in inventory if item.name != ItemNames.ENHANCED_TARGETING]
unused_items = [item_name for item_name in unused_items if item_name != ItemNames.ENHANCED_TARGETING]
if not {ItemNames.PHOTON_CANNON, ItemNames.KHAYDARIN_MONOLITH, ItemNames.NEXUS_OVERCHARGE} & logical_inventory_set:
inventory = [item for item in inventory if item.name != ItemNames.OPTIMIZED_ORDNANCE]
unused_items = [item_name for item_name in unused_items if item_name != ItemNames.OPTIMIZED_ORDNANCE]

# Cull finished, adding locked items back into inventory
inventory += locked_items
Expand Down
Loading