diff --git a/worlds/sc2/items.py b/worlds/sc2/items.py index eb206969bc97..da26cae62622 100644 --- a/worlds/sc2/items.py +++ b/worlds/sc2/items.py @@ -2031,10 +2031,6 @@ def get_basic_units(world: 'SC2World', race: SC2Race) -> typing.Set[str]: item_names.REAVER: 1, # any high templar variant: 2 } -pvx_air_defense_ratings = { - item_names.CORSAIR: 1, - # phoenix or mirage: 1 -} kerrigan_levels = [ item_name for item_name, item_data in item_table.items() diff --git a/worlds/sc2/locations.py b/worlds/sc2/locations.py index 89e62c9227ad..4f3f4237e30f 100644 --- a/worlds/sc2/locations.py +++ b/worlds/sc2/locations.py @@ -1726,7 +1726,7 @@ def get_locations(world: Optional['SC2World']) -> Tuple[LocationData, ...]: make_location_data(SC2Mission.EVACUATION_P.mission_name, "Reach Hanson", SC2_RACESWAP_LOC_ID_OFFSET + 804, LocationType.EXTRA), make_location_data(SC2Mission.EVACUATION_P.mission_name, "Secret Resource Stash", SC2_RACESWAP_LOC_ID_OFFSET + 805, LocationType.EXTRA), make_location_data(SC2Mission.EVACUATION_P.mission_name, "Flawless", SC2_RACESWAP_LOC_ID_OFFSET + 806, LocationType.CHALLENGE, - lambda state: logic.protoss_defense_rating(state, True, False) >= 2 and + lambda state: logic.protoss_defense_rating(state, True) >= 2 and logic.protoss_common_unit(state) and (adv_tactics and logic.protoss_basic_anti_air(state) or logic.protoss_competent_anti_air(state))), @@ -1755,28 +1755,28 @@ def get_locations(world: Optional['SC2World']) -> Tuple[LocationData, ...]: lambda state: logic.zerg_defense_rating(state, True, False) >= 2 and logic.zerg_common_unit(state)), make_location_data(SC2Mission.OUTBREAK_P.mission_name, "Victory", SC2_RACESWAP_LOC_ID_OFFSET + 1000, LocationType.VICTORY, - lambda state: logic.protoss_defense_rating(state, True, False) >= 4 and + lambda state: logic.protoss_defense_rating(state, True) >= 4 and logic.protoss_common_unit(state)), make_location_data(SC2Mission.OUTBREAK_P.mission_name, "Left Infestor", SC2_RACESWAP_LOC_ID_OFFSET + 1001, LocationType.VANILLA, - lambda state: logic.protoss_defense_rating(state, True, False) >= 2 and + lambda state: logic.protoss_defense_rating(state, True) >= 2 and logic.protoss_common_unit(state)), make_location_data(SC2Mission.OUTBREAK_P.mission_name, "Right Infestor", SC2_RACESWAP_LOC_ID_OFFSET + 1002, LocationType.VANILLA, - lambda state: logic.protoss_defense_rating(state, True, False) >= 2 and + lambda state: logic.protoss_defense_rating(state, True) >= 2 and logic.protoss_common_unit(state)), make_location_data(SC2Mission.OUTBREAK_P.mission_name, "North Infested Command Center", SC2_RACESWAP_LOC_ID_OFFSET + 1003, LocationType.EXTRA, - lambda state: logic.protoss_defense_rating(state, True, False) >= 2 and + lambda state: logic.protoss_defense_rating(state, True) >= 2 and logic.protoss_common_unit(state)), make_location_data(SC2Mission.OUTBREAK_P.mission_name, "South Infested Command Center", SC2_RACESWAP_LOC_ID_OFFSET + 1004, LocationType.EXTRA, - lambda state: logic.protoss_defense_rating(state, True, False) >= 2 and + lambda state: logic.protoss_defense_rating(state, True) >= 2 and logic.protoss_common_unit(state)), make_location_data(SC2Mission.OUTBREAK_P.mission_name, "Northwest Bar", SC2_RACESWAP_LOC_ID_OFFSET + 1005, LocationType.EXTRA, - lambda state: logic.protoss_defense_rating(state, True, False) >= 2 and + lambda state: logic.protoss_defense_rating(state, True) >= 2 and logic.protoss_common_unit(state)), make_location_data(SC2Mission.OUTBREAK_P.mission_name, "North Bar", SC2_RACESWAP_LOC_ID_OFFSET + 1006, LocationType.EXTRA, - lambda state: logic.protoss_defense_rating(state, True, False) >= 2 and + lambda state: logic.protoss_defense_rating(state, True) >= 2 and logic.protoss_common_unit(state)), make_location_data(SC2Mission.OUTBREAK_P.mission_name, "South Bar", SC2_RACESWAP_LOC_ID_OFFSET + 1007, LocationType.EXTRA, - lambda state: logic.protoss_defense_rating(state, True, False) >= 2 and + lambda state: logic.protoss_defense_rating(state, True) >= 2 and logic.protoss_common_unit(state)), # 110X/120X - Safe Haven # 130X/140X - Haven's Fall diff --git a/worlds/sc2/rules.py b/worlds/sc2/rules.py index 75b4eee78716..ea2c83c0b602 100644 --- a/worlds/sc2/rules.py +++ b/worlds/sc2/rules.py @@ -6,7 +6,7 @@ get_enabled_campaigns, MissionOrder, EnableMorphling, get_enabled_races from .items import get_basic_units, tvx_defense_ratings, tvz_defense_ratings, kerrigan_actives, tvx_air_defense_ratings, \ kerrigan_levels, get_full_item_list, zvx_air_defense_ratings, zvx_defense_ratings, pvx_defense_ratings, \ - pvz_defense_ratings, pvx_air_defense_ratings + pvz_defense_ratings from .mission_tables import SC2Race, SC2Campaign from . import item_names @@ -380,13 +380,14 @@ def zerg_defense_rating(self, state: CollectionState, zerg_enemy: bool, air_enem if zerg_enemy: defense_score += 1 # Igniter - if state.has(item_names.ROACH_PRIMAL_IGNITER_ASPECT, self.player) and (state.has(item_names.ROACH, self.player) or self.morphling_enabled) and zerg_enemy: + if self.morph_igniter(state) and zerg_enemy: defense_score += 2 if state.has(item_names.PRIMAL_IGNITER_CONCENTRATED_FIRE, self.player): defense_score += 1 # Creep Tumors if state.has_any({item_names.SWARM_QUEEN, item_names.OVERLORD_OVERSEER_ASPECT}, self.player): - defense_score += 1 + if not zerg_enemy: + defense_score += 1 if state.has(item_names.MALIGNANT_CREEP, self.player): defense_score += 1 # Infested Siege Tanks @@ -436,6 +437,10 @@ def morph_lurker(self, state: CollectionState) -> bool: def morph_impaler_or_lurker(self, state: CollectionState) -> bool: return self.morph_impaler(state) or self.morph_lurker(state) + def morph_igniter(self, state: CollectionState) -> bool: + return (state.has(item_names.ROACH, self.player) or self.morphling_enabled) \ + and state.has(item_names.ROACH_PRIMAL_IGNITER_ASPECT, self.player) + def zerg_competent_comp(self, state: CollectionState) -> bool: advanced = self.advanced_tactics core_unit = state.has_any({item_names.ROACH, item_names.ABERRATION, item_names.ZERGLING}, self.player) @@ -542,7 +547,7 @@ def the_reckoning_requirement(self, state: CollectionState) -> bool: # LotV - def protoss_defense_rating(self, state: CollectionState, zerg_enemy: bool, air_enemy: bool = True) -> int: + def protoss_defense_rating(self, state: CollectionState, zerg_enemy: bool) -> int: """ Ability to handle defensive missions :param state: @@ -561,15 +566,11 @@ def protoss_defense_rating(self, state: CollectionState, zerg_enemy: bool, air_e # High Templar variants vs zerg if state.has_any({item_names.HIGH_TEMPLAR, item_names.SIGNIFIER, item_names.ASCENDANT}, self.player) and zerg_enemy: defense_score += 2 - # Phoenix/Mirage vs air - if state.has_any({item_names.PHOENIX, item_names.MIRAGE}, self.player) and air_enemy: - defense_score += 1 # General enemy-based rules + # No anti-air defense dict here, use an existing logic rule instead if zerg_enemy: defense_score += sum((pvz_defense_ratings[item] for item in pvz_defense_ratings if state.has(item, self.player))) - if air_enemy: - defense_score += sum((pvx_air_defense_ratings[item] for item in pvx_air_defense_ratings if state.has(item, self.player))) # Advanced Tactics bumps defense rating requirements down by 2 if self.advanced_tactics: defense_score += 2