diff --git a/worlds/sc2/locations.py b/worlds/sc2/locations.py index 1048b0f241db..57c5bb95af9d 100644 --- a/worlds/sc2/locations.py +++ b/worlds/sc2/locations.py @@ -1622,47 +1622,47 @@ def get_locations(world: Optional['SC2World']) -> Tuple[LocationData, ...]: lambda state: logic.end_game_requirement(state)), # Mission Variants - LocationData("Smash and Grab (Z)", "Smash and Grab (Zerg): Victory", SC2_RACESWAP_LOC_ID_OFFSET + 100, LocationType.VICTORY, + LocationData("Smash and Grab (Z)", "Smash and Grab (Zerg): Victory", SC2_RACESWAP_LOC_ID_OFFSET + 1500, LocationType.VICTORY, lambda state: logic.zerg_common_unit(state) and (adv_tactics and logic.zerg_basic_anti_air(state) or logic.zerg_competent_anti_air(state))), - LocationData("Smash and Grab (Z)", "Smash and Grab (Zerg): First Relic", SC2_RACESWAP_LOC_ID_OFFSET + 101, LocationType.VANILLA), - LocationData("Smash and Grab (Z)", "Smash and Grab (Zerg): Second Relic", SC2_RACESWAP_LOC_ID_OFFSET + 102, LocationType.VANILLA), - LocationData("Smash and Grab (Z)", "Smash and Grab (Zerg): Third Relic", SC2_RACESWAP_LOC_ID_OFFSET + 103, LocationType.VANILLA, + LocationData("Smash and Grab (Z)", "Smash and Grab (Zerg): First Relic", SC2_RACESWAP_LOC_ID_OFFSET + 1501, LocationType.VANILLA), + LocationData("Smash and Grab (Z)", "Smash and Grab (Zerg): Second Relic", SC2_RACESWAP_LOC_ID_OFFSET + 1502, LocationType.VANILLA), + LocationData("Smash and Grab (Z)", "Smash and Grab (Zerg): Third Relic", SC2_RACESWAP_LOC_ID_OFFSET + 1503, LocationType.VANILLA, lambda state: logic.zerg_common_unit(state) and (adv_tactics and logic.zerg_basic_kerriganless_anti_air(state) or logic.zerg_competent_anti_air(state))), - LocationData("Smash and Grab (Z)", "Smash and Grab (Zerg): Fourth Relic", SC2_RACESWAP_LOC_ID_OFFSET + 104, LocationType.VANILLA, + LocationData("Smash and Grab (Z)", "Smash and Grab (Zerg): Fourth Relic", SC2_RACESWAP_LOC_ID_OFFSET + 1504, LocationType.VANILLA, lambda state: logic.zerg_common_unit(state) and (adv_tactics and logic.zerg_basic_kerriganless_anti_air(state) or logic.zerg_competent_anti_air(state))), - LocationData("Smash and Grab (Z)", "Smash and Grab (Zerg): First Forcefield Area Busted", SC2_RACESWAP_LOC_ID_OFFSET + 105, LocationType.EXTRA, + LocationData("Smash and Grab (Z)", "Smash and Grab (Zerg): First Forcefield Area Busted", SC2_RACESWAP_LOC_ID_OFFSET + 1505, LocationType.EXTRA, lambda state: logic.zerg_common_unit(state) and (adv_tactics and logic.zerg_basic_kerriganless_anti_air(state) or logic.zerg_competent_anti_air(state))), - LocationData("Smash and Grab (Z)", "Smash and Grab (Zerg): Second Forcefield Area Busted", SC2_RACESWAP_LOC_ID_OFFSET + 106, LocationType.EXTRA, + LocationData("Smash and Grab (Z)", "Smash and Grab (Zerg): Second Forcefield Area Busted", SC2_RACESWAP_LOC_ID_OFFSET + 1506, LocationType.EXTRA, lambda state: logic.zerg_common_unit(state) and (adv_tactics and logic.zerg_basic_kerriganless_anti_air(state) or logic.zerg_competent_anti_air(state))), - LocationData("Smash and Grab (P)", "Smash and Grab (Protoss): Victory", SC2_RACESWAP_LOC_ID_OFFSET + 200, LocationType.VICTORY, + LocationData("Smash and Grab (P)", "Smash and Grab (Protoss): Victory", SC2_RACESWAP_LOC_ID_OFFSET + 1600, LocationType.VICTORY, lambda state: logic.protoss_common_unit(state) and (adv_tactics and logic.protoss_basic_anti_air(state) or logic.protoss_competent_anti_air(state))), - LocationData("Smash and Grab (P)", "Smash and Grab (Protoss): First Relic", SC2_RACESWAP_LOC_ID_OFFSET + 201, LocationType.VANILLA), - LocationData("Smash and Grab (P)", "Smash and Grab (Protoss): Second Relic", SC2_RACESWAP_LOC_ID_OFFSET + 202, LocationType.VANILLA), - LocationData("Smash and Grab (P)", "Smash and Grab (Protoss): Third Relic", SC2_RACESWAP_LOC_ID_OFFSET + 203, LocationType.VANILLA, + LocationData("Smash and Grab (P)", "Smash and Grab (Protoss): First Relic", SC2_RACESWAP_LOC_ID_OFFSET + 1601, LocationType.VANILLA), + LocationData("Smash and Grab (P)", "Smash and Grab (Protoss): Second Relic", SC2_RACESWAP_LOC_ID_OFFSET + 1602, LocationType.VANILLA), + LocationData("Smash and Grab (P)", "Smash and Grab (Protoss): Third Relic", SC2_RACESWAP_LOC_ID_OFFSET + 1603, LocationType.VANILLA, lambda state: logic.protoss_common_unit(state) and (adv_tactics and logic.protoss_basic_anti_air(state) or logic.protoss_competent_anti_air(state))), - LocationData("Smash and Grab (P)", "Smash and Grab (Protoss): Fourth Relic", SC2_RACESWAP_LOC_ID_OFFSET + 204, LocationType.VANILLA, + LocationData("Smash and Grab (P)", "Smash and Grab (Protoss): Fourth Relic", SC2_RACESWAP_LOC_ID_OFFSET + 1604, LocationType.VANILLA, lambda state: logic.protoss_common_unit(state) and (adv_tactics and logic.protoss_basic_anti_air(state) or logic.protoss_competent_anti_air(state))), - LocationData("Smash and Grab (P)", "Smash and Grab (Protoss): First Forcefield Area Busted", SC2_RACESWAP_LOC_ID_OFFSET + 205, LocationType.EXTRA, + LocationData("Smash and Grab (P)", "Smash and Grab (Protoss): First Forcefield Area Busted", SC2_RACESWAP_LOC_ID_OFFSET + 1605, LocationType.EXTRA, lambda state: logic.protoss_common_unit(state) and (adv_tactics and logic.protoss_basic_anti_air(state) or logic.protoss_competent_anti_air(state))), - LocationData("Smash and Grab (P)", "Smash and Grab (Protoss): Second Forcefield Area Busted", SC2_RACESWAP_LOC_ID_OFFSET + 206, LocationType.EXTRA, + LocationData("Smash and Grab (P)", "Smash and Grab (Protoss): Second Forcefield Area Busted", SC2_RACESWAP_LOC_ID_OFFSET + 1606, LocationType.EXTRA, lambda state: logic.protoss_common_unit(state) and (adv_tactics and logic.protoss_basic_anti_air(state) or logic.protoss_competent_anti_air(state))), diff --git a/worlds/sc2/mission_tables.py b/worlds/sc2/mission_tables.py index 1dda357318c8..b0d9ee9ce824 100644 --- a/worlds/sc2/mission_tables.py +++ b/worlds/sc2/mission_tables.py @@ -36,7 +36,8 @@ class MissionFlag(IntFlag): VsTerran = auto() VsZerg = auto() VsProtoss = auto() - RaceSwap = auto() # The mission uses a faction other than the one it uses in vanilla + HasRaceSwap = auto() # The mission has variants that use different factions from the vanilla experience. + RaceSwap = auto() # The mission uses different factions from the vanilla experience. AiAlly = AiTerranAlly|AiZergAlly|AiProtossAlly TimedDefense = AutoScroller|Defense @@ -106,7 +107,7 @@ def __init__(self, mission_id: int, name: str, campaign: SC2Campaign, area: str, OUTBREAK = 5, "Outbreak", SC2Campaign.WOL, "Colonist", SC2Race.TERRAN, MissionPools.EASY, "ap_outbreak", MissionFlag.Terran|MissionFlag.Defense|MissionFlag.VsZerg SAFE_HAVEN = 6, "Safe Haven", SC2Campaign.WOL, "Colonist", SC2Race.TERRAN, MissionPools.MEDIUM, "ap_safe_haven", MissionFlag.Terran|MissionFlag.Countdown|MissionFlag.VsProtoss HAVENS_FALL = 7, "Haven's Fall", SC2Campaign.WOL, "Colonist", SC2Race.TERRAN, MissionPools.MEDIUM, "ap_havens_fall", MissionFlag.Terran|MissionFlag.VsZerg - SMASH_AND_GRAB = 8, "Smash and Grab", SC2Campaign.WOL, "Artifact", SC2Race.TERRAN, MissionPools.EASY, "ap_smash_and_grab", MissionFlag.Terran|MissionFlag.Countdown|MissionFlag.VsPZ + SMASH_AND_GRAB = 8, "Smash and Grab (T)", SC2Campaign.WOL, "Artifact", SC2Race.TERRAN, MissionPools.EASY, "ap_smash_and_grab", MissionFlag.Terran|MissionFlag.Countdown|MissionFlag.VsPZ|MissionFlag.HasRaceSwap THE_DIG = 9, "The Dig", SC2Campaign.WOL, "Artifact", SC2Race.TERRAN, MissionPools.MEDIUM, "ap_the_dig", MissionFlag.Terran|MissionFlag.TimedDefense|MissionFlag.VsProtoss THE_MOEBIUS_FACTOR = 10, "The Moebius Factor", SC2Campaign.WOL, "Artifact", SC2Race.TERRAN, MissionPools.MEDIUM, "ap_the_moebius_factor", MissionFlag.Terran|MissionFlag.Countdown|MissionFlag.VsZerg SUPERNOVA = 11, "Supernova", SC2Campaign.WOL, "Artifact", SC2Race.TERRAN, MissionPools.HARD, "ap_supernova", MissionFlag.Terran|MissionFlag.Countdown|MissionFlag.VsProtoss @@ -196,8 +197,8 @@ def __init__(self, mission_id: int, name: str, campaign: SC2Campaign, area: str, END_GAME = 83, "End Game", SC2Campaign.NCO, "_3", SC2Race.TERRAN, MissionPools.VERY_HARD, "ap_end_game", MissionFlag.Terran|MissionFlag.Nova|MissionFlag.Defense|MissionFlag.VsTerran # Race-Swapped Variants - SMASH_AND_GRAB_Z = 84, "Smash and Grab (Z)", SC2Campaign.WOL, "Artifact", SC2Race.ZERG, MissionPools.EASY, "ap_smash_and_grab", MissionFlag.Zerg|MissionFlag.Countdown|MissionFlag.VsPZ|MissionFlag.RaceSwap - SMASH_AND_GRAB_P = 85, "Smash and Grab (P)", SC2Campaign.WOL, "Artifact", SC2Race.PROTOSS, MissionPools.EASY, "ap_smash_and_grab", MissionFlag.Protoss|MissionFlag.Countdown|MissionFlag.VsPZ|MissionFlag.RaceSwap + SMASH_AND_GRAB_Z = 98, "Smash and Grab (Z)", SC2Campaign.WOL, "Artifact", SC2Race.ZERG, MissionPools.EASY, "ap_smash_and_grab", MissionFlag.Zerg|MissionFlag.Countdown|MissionFlag.VsPZ|MissionFlag.RaceSwap + SMASH_AND_GRAB_P = 99, "Smash and Grab (P)", SC2Campaign.WOL, "Artifact", SC2Race.PROTOSS, MissionPools.EASY, "ap_smash_and_grab", MissionFlag.Protoss|MissionFlag.Countdown|MissionFlag.VsPZ|MissionFlag.RaceSwap class MissionConnection: diff --git a/worlds/sc2/options.py b/worlds/sc2/options.py index 44ccdfac13e8..f8664a5256bb 100644 --- a/worlds/sc2/options.py +++ b/worlds/sc2/options.py @@ -1025,6 +1025,8 @@ def get_disabled_flags(world: 'SC2World') -> MissionFlag: # filter out no-build missions if not get_option_value(world, "shuffle_no_build"): excluded |= MissionFlag.NoBuild + if get_option_value(world, "enable_race_swap") == EnableRaceSwapVariants.option_disabled: + excluded |= MissionFlag.RaceSwap # TODO: add more flags to potentially exclude once we have a way to get that from the player return MissionFlag(excluded) @@ -1034,6 +1036,7 @@ def get_excluded_missions(world: 'SC2World') -> Set[SC2Mission]: excluded_mission_names = world.options.excluded_missions.value disabled_campaigns = get_disabled_campaigns(world) disabled_flags = get_disabled_flags(world) + just_one_variant = get_option_value(world, "enable_race_swap") == EnableRaceSwapVariants.option_pick_one excluded_missions: Set[SC2Mission] = set([lookup_name_to_mission[name] for name in excluded_mission_names]) @@ -1048,12 +1051,13 @@ def get_excluded_missions(world: 'SC2World') -> Set[SC2Mission]: [mission for mission in SC2Mission if mission.pool == MissionPools.VERY_HARD and mission.campaign != SC2Campaign.EPILOGUE] ) - # Omitting No-Build missions if not shuffling no-build + # Omitting missions with flags we don't want if disabled_flags: excluded_missions = excluded_missions.union(get_missions_with_any_flags_in_list(disabled_flags)) # Omitting missions not in enabled campaigns for campaign in disabled_campaigns: excluded_missions = excluded_missions.union(campaign_mission_table[campaign]) + # TODO: if just_one_variant: return excluded_missions