From 112f78c8ce13a0f7e84e92ceb59e79ec0635cd19 Mon Sep 17 00:00:00 2001 From: SirChuckOfTheChuckles Date: Sat, 31 Aug 2024 17:55:27 -0400 Subject: [PATCH 1/4] initial commit --- worlds/sc2/items.py | 15 ++-- worlds/sc2/locations.py | 155 +++++++++++++++++++++++++++-------- worlds/sc2/mission_tables.py | 124 ++++++++++++++++++++++++++-- worlds/sc2/options.py | 15 ++-- worlds/sc2/rules.py | 65 +++++++++++++-- 5 files changed, 313 insertions(+), 61 deletions(-) diff --git a/worlds/sc2/items.py b/worlds/sc2/items.py index c51c6632a6a4..fb26dbeed93e 100644 --- a/worlds/sc2/items.py +++ b/worlds/sc2/items.py @@ -1130,19 +1130,22 @@ def get_full_item_list(): item_names.ZERGLING_HARDENED_CARAPACE: ItemData(200 + SC2HOTS_ITEM_ID_OFFSET, ZergItemType.Mutation_1, 0, SC2Race.ZERG, parent_item=item_names.ZERGLING, origin={"hots"}), item_names.ZERGLING_ADRENAL_OVERLOAD: - ItemData(201 + SC2HOTS_ITEM_ID_OFFSET, ZergItemType.Mutation_1, 1, SC2Race.ZERG, parent_item=item_names.ZERGLING, origin={"hots"}), + ItemData(201 + SC2HOTS_ITEM_ID_OFFSET, ZergItemType.Mutation_1, 1, SC2Race.ZERG, parent_item=item_names.ZERGLING, + origin={"hots"}, classification=ItemClassification.progression), item_names.ZERGLING_METABOLIC_BOOST: ItemData(202 + SC2HOTS_ITEM_ID_OFFSET, ZergItemType.Mutation_1, 2, SC2Race.ZERG, parent_item=item_names.ZERGLING, origin={"hots"}, classification=ItemClassification.filler), item_names.ROACH_HYDRIODIC_BILE: - ItemData(203 + SC2HOTS_ITEM_ID_OFFSET, ZergItemType.Mutation_1, 3, SC2Race.ZERG, parent_item=item_names.ROACH, origin={"hots"}), + ItemData(203 + SC2HOTS_ITEM_ID_OFFSET, ZergItemType.Mutation_1, 3, SC2Race.ZERG, parent_item=item_names.ROACH, + origin={"hots"}, classification=ItemClassification.progression), item_names.ROACH_ADAPTIVE_PLATING: ItemData(204 + SC2HOTS_ITEM_ID_OFFSET, ZergItemType.Mutation_1, 4, SC2Race.ZERG, parent_item=item_names.ROACH, origin={"hots"}), item_names.ROACH_TUNNELING_CLAWS: ItemData(205 + SC2HOTS_ITEM_ID_OFFSET, ZergItemType.Mutation_1, 5, SC2Race.ZERG, parent_item=item_names.ROACH, origin={"hots"}, classification=ItemClassification.filler), item_names.HYDRALISK_FRENZY: - ItemData(206 + SC2HOTS_ITEM_ID_OFFSET, ZergItemType.Mutation_1, 6, SC2Race.ZERG, parent_item=item_names.HYDRALISK, origin={"hots"}), + ItemData(206 + SC2HOTS_ITEM_ID_OFFSET, ZergItemType.Mutation_1, 6, SC2Race.ZERG, parent_item=item_names.HYDRALISK, \ + origin={"hots"}, classification=ItemClassification.progression), item_names.HYDRALISK_ANCILLARY_CARAPACE: ItemData(207 + SC2HOTS_ITEM_ID_OFFSET, ZergItemType.Mutation_1, 7, SC2Race.ZERG, parent_item=item_names.HYDRALISK, origin={"hots"}, classification=ItemClassification.filler), @@ -1341,7 +1344,7 @@ def get_full_item_list(): origin={"ext"}, classification=ItemClassification.filler), item_names.SWARM_QUEEN_BIO_MECHANICAL_TRANSFUSION: ItemData(271 + SC2HOTS_ITEM_ID_OFFSET, ZergItemType.Mutation_3, 11, SC2Race.ZERG, parent_item=item_names.SWARM_QUEEN, - origin={"ext"}), + origin={"ext"}, classification=ItemClassification.progression), item_names.SWARM_QUEEN_RESOURCE_EFFICIENCY: ItemData(272 + SC2HOTS_ITEM_ID_OFFSET, ZergItemType.Mutation_3, 12, SC2Race.ZERG, parent_item=item_names.SWARM_QUEEN, origin={"ext"}), @@ -1762,7 +1765,7 @@ def get_full_item_list(): item_names.HAVOC_DETECT_WEAKNESS: ItemData(374 + SC2LOTV_ITEM_ID_OFFSET, ProtossItemType.Forge_3, 14, SC2Race.PROTOSS, origin={"ext"}, parent_item=item_names.HAVOC), item_names.HAVOC_BLOODSHARD_RESONANCE: ItemData(375 + SC2LOTV_ITEM_ID_OFFSET, ProtossItemType.Forge_3, 15, SC2Race.PROTOSS, origin={"ext"}, parent_item=item_names.HAVOC), item_names.ZEALOT_SENTINEL_CENTURION_LEG_ENHANCEMENTS: ItemData(376 + SC2LOTV_ITEM_ID_OFFSET, ProtossItemType.Forge_3, 16, SC2Race.PROTOSS, origin={"bw"}), - item_names.ZEALOT_SENTINEL_CENTURION_SHIELD_CAPACITY: ItemData(377 + SC2LOTV_ITEM_ID_OFFSET, ProtossItemType.Forge_3, 17, SC2Race.PROTOSS, origin={"bw"}), + item_names.ZEALOT_SENTINEL_CENTURION_SHIELD_CAPACITY: ItemData(377 + SC2LOTV_ITEM_ID_OFFSET, ProtossItemType.Forge_3, 17, SC2Race.PROTOSS, classification=ItemClassification.progression, origin={"bw"}), item_names.ORACLE_BOSONIC_CORE: ItemData(378 + SC2LOTV_ITEM_ID_OFFSET, ProtossItemType.Forge_3, 18, SC2Race.PROTOSS, origin={"ext"}, parent_item=item_names.ORACLE), item_names.SCOUT_RESOURCE_EFFICIENCY: ItemData(379 + SC2LOTV_ITEM_ID_OFFSET, ProtossItemType.Forge_3, 19, SC2Race.PROTOSS, origin={"ext"}, parent_item=item_names.SCOUT), item_names.IMMORTAL_ANNIHILATOR_STALWART_DISRUPTOR_DISPERSION: ItemData(380 + SC2LOTV_ITEM_ID_OFFSET, ProtossItemType.Forge_3, 20, SC2Race.PROTOSS, origin={"ext"}), @@ -1784,7 +1787,7 @@ def get_full_item_list(): item_names.DARK_TEMPLAR_LESSER_SHADOW_FURY: ItemData(509 + SC2LOTV_ITEM_ID_OFFSET, ProtossItemType.War_Council, 9, SC2Race.PROTOSS, parent_item=item_names.DARK_TEMPLAR), item_names.DARK_TEMPLAR_GREATER_SHADOW_FURY: ItemData(510 + SC2LOTV_ITEM_ID_OFFSET, ProtossItemType.War_Council, 10, SC2Race.PROTOSS, parent_item=item_names.DARK_TEMPLAR), item_names.BLOOD_HUNTER_BRUTAL_EFFICIENCY: ItemData(511 + SC2LOTV_ITEM_ID_OFFSET, ProtossItemType.War_Council, 11, SC2Race.PROTOSS, parent_item=item_names.BLOOD_HUNTER), - item_names.SENTRY_DOUBLE_SHIELD_RECHARGE: ItemData(512 + SC2LOTV_ITEM_ID_OFFSET, ProtossItemType.War_Council, 12, SC2Race.PROTOSS, parent_item=item_names.SENTRY), + item_names.SENTRY_DOUBLE_SHIELD_RECHARGE: ItemData(512 + SC2LOTV_ITEM_ID_OFFSET, ProtossItemType.War_Council, 12, SC2Race.PROTOSS, classification=ItemClassification.progression, parent_item=item_names.SENTRY), item_names.ENERGIZER_MOBILE_CHRONO_BEAM: ItemData(513 + SC2LOTV_ITEM_ID_OFFSET, ProtossItemType.War_Council, 13, SC2Race.PROTOSS, classification=ItemClassification.progression, parent_item=item_names.ENERGIZER), item_names.HAVOC_ENDURING_SIGHT: ItemData(514 + SC2LOTV_ITEM_ID_OFFSET, ProtossItemType.War_Council, 14, SC2Race.PROTOSS, parent_item=item_names.HAVOC), item_names.HIGH_TEMPLAR_PLASMA_SURGE: ItemData(515 + SC2LOTV_ITEM_ID_OFFSET, ProtossItemType.War_Council, 15, SC2Race.PROTOSS, parent_item=item_names.HIGH_TEMPLAR), diff --git a/worlds/sc2/locations.py b/worlds/sc2/locations.py index a1e54c88c269..2c31a86623f8 100644 --- a/worlds/sc2/locations.py +++ b/worlds/sc2/locations.py @@ -419,33 +419,6 @@ def get_locations(world: Optional['SC2World']) -> Tuple[LocationData, ...]: and logic.terran_common_unit(state) and (logic.marine_medic_upgrade(state) or adv_tactics)) ), - make_location_data(SC2Mission.THE_DIG.mission_name, "Northwestern Protoss Base", SC2WOL_LOC_ID_OFFSET + 909, LocationType.MASTERY, - lambda state: ( - logic.terran_basic_anti_air(state) - and logic.terran_defense_rating(state, False, True) >= 8 - and logic.terran_defense_rating(state, False, False) >= 6 - and logic.terran_common_unit(state) - and (logic.marine_medic_upgrade(state) or adv_tactics) - and (logic.terran_base_trasher(state) or state.has(item_names.COMMAND_CENTER_SCANNER_SWEEP, player))) - ), - make_location_data(SC2Mission.THE_DIG.mission_name, "Northeastern Protoss Base", SC2WOL_LOC_ID_OFFSET + 910, LocationType.MASTERY, - lambda state: ( - logic.terran_basic_anti_air(state) - and logic.terran_defense_rating(state, False, True) >= 8 - and logic.terran_defense_rating(state, False, False) >= 6 - and logic.terran_common_unit(state) - and (logic.marine_medic_upgrade(state) or adv_tactics) - and (logic.terran_base_trasher(state) or state.has(item_names.COMMAND_CENTER_SCANNER_SWEEP, player))) - ), - make_location_data(SC2Mission.THE_DIG.mission_name, "Eastern Protoss Base", SC2WOL_LOC_ID_OFFSET + 911, LocationType.MASTERY, - lambda state: ( - logic.terran_basic_anti_air(state) - and logic.terran_defense_rating(state, False, True) >= 8 - and logic.terran_defense_rating(state, False, False) >= 6 - and logic.terran_common_unit(state) - and (logic.marine_medic_upgrade(state) or adv_tactics) - and (logic.terran_base_trasher(state) or state.has(item_names.COMMAND_CENTER_SCANNER_SWEEP, player))) - ), make_location_data(SC2Mission.THE_MOEBIUS_FACTOR.mission_name, "Victory", SC2WOL_LOC_ID_OFFSET + 1000, LocationType.VICTORY, lambda state: ( logic.terran_basic_anti_air(state) @@ -711,34 +684,34 @@ def get_locations(world: Optional['SC2World']) -> Tuple[LocationData, ...]: logic.terran_common_unit ), make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION.mission_name, "Victory", SC2WOL_LOC_ID_OFFSET + 1900, LocationType.VICTORY, - logic.engine_of_destruction_requirement + logic.terran_engine_of_destruction_requirement ), make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION.mission_name, "Odin", SC2WOL_LOC_ID_OFFSET + 1901, LocationType.EXTRA, logic.marine_medic_upgrade ), make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION.mission_name, "Loki", SC2WOL_LOC_ID_OFFSET + 1902, LocationType.CHALLENGE, - logic.engine_of_destruction_requirement + logic.terran_engine_of_destruction_requirement ), make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION.mission_name, "Lab Devourer", SC2WOL_LOC_ID_OFFSET + 1903, LocationType.VANILLA, logic.marine_medic_upgrade ), make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION.mission_name, "North Devourer", SC2WOL_LOC_ID_OFFSET + 1904, LocationType.VANILLA, - logic.engine_of_destruction_requirement + logic.terran_engine_of_destruction_requirement ), make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION.mission_name, "Southeast Devourer", SC2WOL_LOC_ID_OFFSET + 1905, LocationType.VANILLA, - logic.engine_of_destruction_requirement + logic.terran_engine_of_destruction_requirement ), make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION.mission_name, "West Base", SC2WOL_LOC_ID_OFFSET + 1906, LocationType.EXTRA, - logic.engine_of_destruction_requirement + logic.terran_engine_of_destruction_requirement ), make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION.mission_name, "Northwest Base", SC2WOL_LOC_ID_OFFSET + 1907, LocationType.EXTRA, - logic.engine_of_destruction_requirement + logic.terran_engine_of_destruction_requirement ), make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION.mission_name, "Northeast Base", SC2WOL_LOC_ID_OFFSET + 1908, LocationType.EXTRA, - logic.engine_of_destruction_requirement + logic.terran_engine_of_destruction_requirement ), make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION.mission_name, "Southeast Base", SC2WOL_LOC_ID_OFFSET + 1909, LocationType.EXTRA, - logic.engine_of_destruction_requirement + logic.terran_engine_of_destruction_requirement ), make_location_data(SC2Mission.MEDIA_BLITZ.mission_name, "Victory", SC2WOL_LOC_ID_OFFSET + 2000, LocationType.VICTORY, logic.terran_competent_comp @@ -2895,6 +2868,118 @@ def get_locations(world: Optional['SC2World']) -> Tuple[LocationData, ...]: make_location_data(SC2Mission.CUTTHROAT_P.mission_name, "West Command Center", SC2_RACESWAP_LOC_ID_OFFSET + 3607, LocationType.EXTRA, logic.protoss_common_unit ), + make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION_Z.mission_name, "Victory", SC2_RACESWAP_LOC_ID_OFFSET + 3700, LocationType.VICTORY, + logic.zerg_engine_of_destruction_requirement + ), + make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION_Z.mission_name, "Odin", SC2_RACESWAP_LOC_ID_OFFSET + 3701, LocationType.EXTRA, + logic.zergling_hydra_roach_start + ), + make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION_Z.mission_name, "Loki", SC2_RACESWAP_LOC_ID_OFFSET + 3702, LocationType.CHALLENGE, + logic.zerg_engine_of_destruction_requirement + ), + make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION_Z.mission_name, "Lab Devourer", SC2_RACESWAP_LOC_ID_OFFSET + 3703, LocationType.VANILLA, + logic.zergling_hydra_roach_start + ), + make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION_Z.mission_name, "North Devourer", SC2_RACESWAP_LOC_ID_OFFSET + 3704, LocationType.VANILLA, + logic.zerg_engine_of_destruction_requirement + ), + make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION_Z.mission_name, "Southeast Devourer", SC2_RACESWAP_LOC_ID_OFFSET + 3705, LocationType.VANILLA, + logic.zerg_engine_of_destruction_requirement + ), + make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION_Z.mission_name, "West Base", SC2_RACESWAP_LOC_ID_OFFSET + 3706, LocationType.EXTRA, + logic.zerg_engine_of_destruction_requirement + ), + make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION_Z.mission_name, "Northwest Base", SC2_RACESWAP_LOC_ID_OFFSET + 3707, LocationType.EXTRA, + logic.zerg_engine_of_destruction_requirement + ), + make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION_Z.mission_name, "Northeast Base", SC2_RACESWAP_LOC_ID_OFFSET + 3708, LocationType.EXTRA, + logic.zerg_engine_of_destruction_requirement + ), + make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION_Z.mission_name, "Southeast Base", SC2_RACESWAP_LOC_ID_OFFSET + 3709, LocationType.EXTRA, + logic.zerg_engine_of_destruction_requirement + ), + make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION_P.mission_name, "Victory", SC2_RACESWAP_LOC_ID_OFFSET + 3800, LocationType.VICTORY, + logic.protoss_engine_of_destruction_requirement + ), + make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION_P.mission_name, "Odin", SC2_RACESWAP_LOC_ID_OFFSET + 3801, LocationType.EXTRA, + logic.zealot_sentry_slayer_start + ), + make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION_P.mission_name, "Loki", SC2_RACESWAP_LOC_ID_OFFSET + 3802, LocationType.CHALLENGE, + logic.protoss_engine_of_destruction_requirement + ), + make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION_P.mission_name, "Lab Devourer", SC2_RACESWAP_LOC_ID_OFFSET + 3803, LocationType.VANILLA, + logic.zealot_sentry_slayer_start + ), + make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION_P.mission_name, "North Devourer", SC2_RACESWAP_LOC_ID_OFFSET + 3804, LocationType.VANILLA, + logic.protoss_engine_of_destruction_requirement + ), + make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION_P.mission_name, "Southeast Devourer", SC2_RACESWAP_LOC_ID_OFFSET + 3805, LocationType.VANILLA, + logic.protoss_engine_of_destruction_requirement + ), + make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION_P.mission_name, "West Base", SC2_RACESWAP_LOC_ID_OFFSET + 3806, LocationType.EXTRA, + logic.protoss_engine_of_destruction_requirement + ), + make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION_P.mission_name, "Northwest Base", SC2_RACESWAP_LOC_ID_OFFSET + 3807, LocationType.EXTRA, + logic.protoss_engine_of_destruction_requirement + ), + make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION_P.mission_name, "Northeast Base", SC2_RACESWAP_LOC_ID_OFFSET + 3808, LocationType.EXTRA, + logic.protoss_engine_of_destruction_requirement + ), + make_location_data(SC2Mission.ENGINE_OF_DESTRUCTION_P.mission_name, "Southeast Base", SC2_RACESWAP_LOC_ID_OFFSET + 3809, LocationType.EXTRA, + logic.protoss_engine_of_destruction_requirement + ), + make_location_data(SC2Mission.MEDIA_BLITZ_Z.mission_name, "Victory", SC2_RACESWAP_LOC_ID_OFFSET + 3900, LocationType.VICTORY, + logic.zerg_competent_comp + ), + make_location_data(SC2Mission.MEDIA_BLITZ_Z.mission_name, "Tower 1", SC2_RACESWAP_LOC_ID_OFFSET + 3901, LocationType.VANILLA, + logic.zerg_competent_comp + ), + make_location_data(SC2Mission.MEDIA_BLITZ_Z.mission_name, "Tower 2", SC2_RACESWAP_LOC_ID_OFFSET + 3902, LocationType.VANILLA, + logic.zerg_competent_comp + ), + make_location_data(SC2Mission.MEDIA_BLITZ_Z.mission_name, "Tower 3", SC2_RACESWAP_LOC_ID_OFFSET + 3903, LocationType.VANILLA, + logic.zerg_competent_comp + ), + make_location_data(SC2Mission.MEDIA_BLITZ_Z.mission_name, "Science Facility", SC2_RACESWAP_LOC_ID_OFFSET + 3904, LocationType.VANILLA), + make_location_data(SC2Mission.MEDIA_BLITZ_Z.mission_name, "All Barracks", SC2_RACESWAP_LOC_ID_OFFSET + 3905, LocationType.EXTRA, + logic.zerg_competent_comp + ), + make_location_data(SC2Mission.MEDIA_BLITZ_Z.mission_name, "All Factories", SC2_RACESWAP_LOC_ID_OFFSET + 3906, LocationType.EXTRA, + logic.zerg_competent_comp + ), + make_location_data(SC2Mission.MEDIA_BLITZ_Z.mission_name, "All Starports", SC2_RACESWAP_LOC_ID_OFFSET + 3907, LocationType.EXTRA, + lambda state: adv_tactics or logic.zerg_competent_comp(state) + ), + make_location_data(SC2Mission.MEDIA_BLITZ_Z.mission_name, "Brutalisk Prime Survives", SC2_RACESWAP_LOC_ID_OFFSET + 3908, LocationType.CHALLENGE, + logic.zerg_competent_comp + ), + make_location_data(SC2Mission.MEDIA_BLITZ_Z.mission_name, "Surprise Attack Ends", SC2_RACESWAP_LOC_ID_OFFSET + 3909, LocationType.EXTRA), + make_location_data(SC2Mission.MEDIA_BLITZ_P.mission_name, "Victory", SC2_RACESWAP_LOC_ID_OFFSET + 4000, LocationType.VICTORY, + logic.protoss_competent_comp + ), + make_location_data(SC2Mission.MEDIA_BLITZ_P.mission_name, "Tower 1", SC2_RACESWAP_LOC_ID_OFFSET + 4001, LocationType.VANILLA, + logic.protoss_competent_comp + ), + make_location_data(SC2Mission.MEDIA_BLITZ_P.mission_name, "Tower 2", SC2_RACESWAP_LOC_ID_OFFSET + 4002, LocationType.VANILLA, + logic.protoss_competent_comp + ), + make_location_data(SC2Mission.MEDIA_BLITZ_P.mission_name, "Tower 3", SC2_RACESWAP_LOC_ID_OFFSET + 4003, LocationType.VANILLA, + logic.protoss_competent_comp + ), + make_location_data(SC2Mission.MEDIA_BLITZ_P.mission_name, "Science Facility", SC2_RACESWAP_LOC_ID_OFFSET + 4004, LocationType.VANILLA), + make_location_data(SC2Mission.MEDIA_BLITZ_P.mission_name, "All Barracks", SC2_RACESWAP_LOC_ID_OFFSET + 4005, LocationType.EXTRA, + logic.protoss_competent_comp + ), + make_location_data(SC2Mission.MEDIA_BLITZ_P.mission_name, "All Factories", SC2_RACESWAP_LOC_ID_OFFSET + 4006, LocationType.EXTRA, + logic.protoss_competent_comp + ), + make_location_data(SC2Mission.MEDIA_BLITZ_P.mission_name, "All Starports", SC2_RACESWAP_LOC_ID_OFFSET + 4007, LocationType.EXTRA, + lambda state: adv_tactics or logic.protoss_competent_comp(state) + ), + make_location_data(SC2Mission.MEDIA_BLITZ_P.mission_name, "Nyon's Vengeance Survives", SC2_RACESWAP_LOC_ID_OFFSET + 4008, LocationType.CHALLENGE, + logic.protoss_competent_comp + ), + make_location_data(SC2Mission.MEDIA_BLITZ_P.mission_name, "Surprise Attack Ends", SC2_RACESWAP_LOC_ID_OFFSET + 4009, LocationType.EXTRA), ] beat_events = [] diff --git a/worlds/sc2/mission_tables.py b/worlds/sc2/mission_tables.py index 784b47de5603..1f1d86f7d258 100644 --- a/worlds/sc2/mission_tables.py +++ b/worlds/sc2/mission_tables.py @@ -118,8 +118,8 @@ def __init__(self, mission_id: int, name: str, campaign: SC2Campaign, area: str, GHOST_OF_A_CHANCE = 16, "Ghost of a Chance", SC2Campaign.WOL, "Covert", SC2Race.ANY, MissionPools.STARTER, "ap_ghost_of_a_chance", MissionFlag.Terran|MissionFlag.NoBuild|MissionFlag.VsTerran THE_GREAT_TRAIN_ROBBERY = 17, "The Great Train Robbery (Terran)", SC2Campaign.WOL, "Rebellion", SC2Race.TERRAN, MissionPools.MEDIUM, "ap_the_great_train_robbery", MissionFlag.Terran|MissionFlag.AutoScroller|MissionFlag.VsTerran|MissionFlag.HasRaceSwap CUTTHROAT = 18, "Cutthroat (Terran)", SC2Campaign.WOL, "Rebellion", SC2Race.TERRAN, MissionPools.MEDIUM, "ap_cutthroat", MissionFlag.Terran|MissionFlag.Countdown|MissionFlag.VsTerran|MissionFlag.HasRaceSwap - ENGINE_OF_DESTRUCTION = 19, "Engine of Destruction", SC2Campaign.WOL, "Rebellion", SC2Race.TERRAN, MissionPools.HARD, "ap_engine_of_destruction", MissionFlag.Terran|MissionFlag.AutoScroller|MissionFlag.VsTerran - MEDIA_BLITZ = 20, "Media Blitz", SC2Campaign.WOL, "Rebellion", SC2Race.TERRAN, MissionPools.MEDIUM, "ap_media_blitz", MissionFlag.Terran|MissionFlag.VsTerran + ENGINE_OF_DESTRUCTION = 19, "Engine of Destruction (Terran)", SC2Campaign.WOL, "Rebellion", SC2Race.TERRAN, MissionPools.HARD, "ap_engine_of_destruction", MissionFlag.Terran|MissionFlag.AutoScroller|MissionFlag.VsTerran|MissionFlag.HasRaceSwap + MEDIA_BLITZ = 20, "Media Blitz (Terran)", SC2Campaign.WOL, "Rebellion", SC2Race.TERRAN, MissionPools.MEDIUM, "ap_media_blitz", MissionFlag.Terran|MissionFlag.VsTerran|MissionFlag.HasRaceSwap PIERCING_OF_THE_SHROUD = 21, "Piercing the Shroud", SC2Campaign.WOL, "Rebellion", SC2Race.TERRAN, MissionPools.STARTER, "ap_piercing_the_shroud", MissionFlag.Terran|MissionFlag.NoBuild|MissionFlag.VsAll GATES_OF_HELL = 26, "Gates of Hell", SC2Campaign.WOL, "Char", SC2Race.TERRAN, MissionPools.HARD, "ap_gates_of_hell", MissionFlag.Terran|MissionFlag.VsZerg BELLY_OF_THE_BEAST = 27, "Belly of the Beast", SC2Campaign.WOL, "Char", SC2Race.ANY, MissionPools.STARTER, "ap_belly_of_the_beast", MissionFlag.Terran|MissionFlag.NoBuild|MissionFlag.VsZerg @@ -210,7 +210,7 @@ def __init__(self, mission_id: int, name: str, campaign: SC2Campaign, area: str, SAFE_HAVEN_P = 95, "Safe Haven (Protoss)", SC2Campaign.WOL, "Colonist", SC2Race.PROTOSS, MissionPools.MEDIUM, "ap_safe_haven", MissionFlag.Protoss|MissionFlag.Countdown|MissionFlag.VsProtoss|MissionFlag.RaceSwap HAVENS_FALL_Z = 96, "Haven's Fall (Zerg)", SC2Campaign.WOL, "Colonist", SC2Race.ZERG, MissionPools.MEDIUM, "ap_havens_fall", MissionFlag.Zerg|MissionFlag.VsZerg|MissionFlag.RaceSwap HAVENS_FALL_P = 97, "Haven's Fall (Protoss)", SC2Campaign.WOL, "Colonist", SC2Race.PROTOSS, MissionPools.MEDIUM, "ap_havens_fall", MissionFlag.Protoss|MissionFlag.VsZerg|MissionFlag.RaceSwap - SMASH_AND_GRAB_Z = 98, "Smash and Grab (Zerg)", SC2Campaign.WOL, "Artifact", SC2Race.ZERG, MissionPools.EASY, "ap_smash_and_grab", MissionFlag.Zerg|MissionFlag.Countdown|MissionFlag.VsPZ|MissionFlag.RaceSwap + SMASH_AND_GRAB_Z = 98, "Smash and Grab (Zerg)", 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 (Protoss)", SC2Campaign.WOL, "Artifact", SC2Race.PROTOSS, MissionPools.EASY, "ap_smash_and_grab", MissionFlag.Protoss|MissionFlag.Countdown|MissionFlag.VsPZ|MissionFlag.RaceSwap # 100/101 - The Dig # 102/103 - Moebius Factor @@ -224,8 +224,10 @@ def __init__(self, mission_id: int, name: str, campaign: SC2Campaign, area: str, THE_GREAT_TRAIN_ROBBERY_P = 117, "The Great Train Robbery (Protoss)", SC2Campaign.WOL, "Rebellion", SC2Race.PROTOSS, MissionPools.MEDIUM, "ap_the_great_train_robbery", MissionFlag.Protoss|MissionFlag.AutoScroller|MissionFlag.VsTerran|MissionFlag.RaceSwap CUTTHROAT_Z = 118, "Cutthroat (Zerg)", SC2Campaign.WOL, "Rebellion", SC2Race.ZERG, MissionPools.MEDIUM, "ap_cutthroat", MissionFlag.Zerg|MissionFlag.Countdown|MissionFlag.VsTerran|MissionFlag.RaceSwap CUTTHROAT_P = 119, "Cutthroat (Protoss)", SC2Campaign.WOL, "Rebellion", SC2Race.PROTOSS, MissionPools.MEDIUM, "ap_cutthroat", MissionFlag.Protoss|MissionFlag.Countdown|MissionFlag.VsTerran|MissionFlag.RaceSwap - # 120/121 - Engine of Destruction - # 122/123 - Media Blitz + ENGINE_OF_DESTRUCTION_Z = 120, "Engine of Destruction (Zerg)", SC2Campaign.WOL, "Rebellion", SC2Race.ZERG, MissionPools.HARD, "ap_engine_of_destruction", MissionFlag.Zerg|MissionFlag.AutoScroller|MissionFlag.VsTerran|MissionFlag.RaceSwap + ENGINE_OF_DESTRUCTION_P = 121, "Engine of Destruction (Protoss)", SC2Campaign.WOL, "Rebellion", SC2Race.PROTOSS, MissionPools.HARD, "ap_engine_of_destruction", MissionFlag.Protoss|MissionFlag.AutoScroller|MissionFlag.VsTerran|MissionFlag.RaceSwap + MEDIA_BLITZ_Z = 122, "Media Blitz (Zerg)", SC2Campaign.WOL, "Rebellion", SC2Race.ZERG, MissionPools.MEDIUM, "ap_media_blitz", MissionFlag.Zerg|MissionFlag.VsTerran|MissionFlag.RaceSwap + MEDIA_BLITZ_P = 123, "Media Blitz (Protoss)", SC2Campaign.WOL, "Rebellion", SC2Race.PROTOSS, MissionPools.MEDIUM, "ap_media_blitz", MissionFlag.Protoss|MissionFlag.VsTerran|MissionFlag.RaceSwap # 124/125 - Piercing the Shroud # 126/127 - Whispers of Doom # 128/129 - A Sinister Turn @@ -270,6 +272,7 @@ def _asdict(self): "connect_to": self.connect_to } + class MissionInfo(NamedTuple): mission: SC2Mission required_world: List[Union[MissionConnection, Dict[Literal["campaign", "connect_to"], int]]] @@ -280,6 +283,117 @@ class MissionInfo(NamedTuple): ui_vertical_padding: int = 0 # How many blank padding tiles go above this mission in the launcher +class FillMission(NamedTuple): + type: MissionPools + connect_to: List[MissionConnection] + category: str + number: int = 0 # number of worlds need beaten + completion_critical: bool = False # missions needed to beat game + or_requirements: bool = False # true if the requirements should be or-ed instead of and-ed + removal_priority: int = 0 # how many missions missing from the pool required to remove this mission + ui_vertical_padding: int = 0 # How many blank padding tiles go above this mission in the launcher + + +vanilla_mission_req_table: Dict[SC2Campaign, Dict[str, MissionInfo]] = { + SC2Campaign.WOL: { + SC2Mission.LIBERATION_DAY.mission_name: MissionInfo(SC2Mission.LIBERATION_DAY, [], SC2Mission.LIBERATION_DAY.area, completion_critical=True), + SC2Mission.THE_OUTLAWS.mission_name: MissionInfo(SC2Mission.THE_OUTLAWS, [MissionConnection(1, SC2Campaign.WOL)], SC2Mission.THE_OUTLAWS.area, completion_critical=True), + SC2Mission.ZERO_HOUR.mission_name: MissionInfo(SC2Mission.ZERO_HOUR, [MissionConnection(2, SC2Campaign.WOL)], SC2Mission.ZERO_HOUR.area, completion_critical=True), + SC2Mission.EVACUATION.mission_name: MissionInfo(SC2Mission.EVACUATION, [MissionConnection(3, SC2Campaign.WOL)], SC2Mission.EVACUATION.area), + SC2Mission.OUTBREAK.mission_name: MissionInfo(SC2Mission.OUTBREAK, [MissionConnection(4, SC2Campaign.WOL)], SC2Mission.OUTBREAK.area), + SC2Mission.SAFE_HAVEN.mission_name: MissionInfo(SC2Mission.SAFE_HAVEN, [MissionConnection(5, SC2Campaign.WOL)], SC2Mission.SAFE_HAVEN.area, number=7), + SC2Mission.HAVENS_FALL.mission_name: MissionInfo(SC2Mission.HAVENS_FALL, [MissionConnection(5, SC2Campaign.WOL)], SC2Mission.HAVENS_FALL.area, number=7), + SC2Mission.SMASH_AND_GRAB.mission_name: MissionInfo(SC2Mission.SMASH_AND_GRAB, [MissionConnection(3, SC2Campaign.WOL)], SC2Mission.SMASH_AND_GRAB.area, completion_critical=True), + SC2Mission.THE_DIG.mission_name: MissionInfo(SC2Mission.THE_DIG, [MissionConnection(8, SC2Campaign.WOL)], SC2Mission.THE_DIG.area, number=8, completion_critical=True), + SC2Mission.THE_MOEBIUS_FACTOR.mission_name: MissionInfo(SC2Mission.THE_MOEBIUS_FACTOR, [MissionConnection(9, SC2Campaign.WOL)], SC2Mission.THE_MOEBIUS_FACTOR.area, number=11, completion_critical=True), + SC2Mission.SUPERNOVA.mission_name: MissionInfo(SC2Mission.SUPERNOVA, [MissionConnection(10, SC2Campaign.WOL)], SC2Mission.SUPERNOVA.area, number=14, completion_critical=True), + SC2Mission.MAW_OF_THE_VOID.mission_name: MissionInfo(SC2Mission.MAW_OF_THE_VOID, [MissionConnection(11, SC2Campaign.WOL)], SC2Mission.MAW_OF_THE_VOID.area, completion_critical=True), + SC2Mission.DEVILS_PLAYGROUND.mission_name: MissionInfo(SC2Mission.DEVILS_PLAYGROUND, [MissionConnection(3, SC2Campaign.WOL)], SC2Mission.DEVILS_PLAYGROUND.area, number=4), + SC2Mission.WELCOME_TO_THE_JUNGLE.mission_name: MissionInfo(SC2Mission.WELCOME_TO_THE_JUNGLE, [MissionConnection(13, SC2Campaign.WOL)], SC2Mission.WELCOME_TO_THE_JUNGLE.area), + SC2Mission.BREAKOUT.mission_name: MissionInfo(SC2Mission.BREAKOUT, [MissionConnection(14, SC2Campaign.WOL)], SC2Mission.BREAKOUT.area, number=8), + SC2Mission.GHOST_OF_A_CHANCE.mission_name: MissionInfo(SC2Mission.GHOST_OF_A_CHANCE, [MissionConnection(14, SC2Campaign.WOL)], SC2Mission.GHOST_OF_A_CHANCE.area, number=8), + SC2Mission.THE_GREAT_TRAIN_ROBBERY.mission_name: MissionInfo(SC2Mission.THE_GREAT_TRAIN_ROBBERY, [MissionConnection(3, SC2Campaign.WOL)], SC2Mission.THE_GREAT_TRAIN_ROBBERY.area, number=6), + SC2Mission.CUTTHROAT.mission_name: MissionInfo(SC2Mission.CUTTHROAT, [MissionConnection(17, SC2Campaign.WOL)], SC2Mission.THE_GREAT_TRAIN_ROBBERY.area), + SC2Mission.ENGINE_OF_DESTRUCTION.mission_name: MissionInfo(SC2Mission.ENGINE_OF_DESTRUCTION, [MissionConnection(18, SC2Campaign.WOL)], SC2Mission.ENGINE_OF_DESTRUCTION.area), + SC2Mission.MEDIA_BLITZ.mission_name: MissionInfo(SC2Mission.MEDIA_BLITZ, [MissionConnection(19, SC2Campaign.WOL)], SC2Mission.MEDIA_BLITZ.area), + SC2Mission.PIERCING_OF_THE_SHROUD.mission_name: MissionInfo(SC2Mission.PIERCING_OF_THE_SHROUD, [MissionConnection(20, SC2Campaign.WOL)], SC2Mission.PIERCING_OF_THE_SHROUD.area), + SC2Mission.GATES_OF_HELL.mission_name: MissionInfo(SC2Mission.GATES_OF_HELL, [MissionConnection(12, SC2Campaign.WOL)], SC2Mission.GATES_OF_HELL.area, completion_critical=True), + SC2Mission.BELLY_OF_THE_BEAST.mission_name: MissionInfo(SC2Mission.BELLY_OF_THE_BEAST, [MissionConnection(22, SC2Campaign.WOL)], SC2Mission.BELLY_OF_THE_BEAST.area, completion_critical=True), + SC2Mission.SHATTER_THE_SKY.mission_name: MissionInfo(SC2Mission.SHATTER_THE_SKY, [MissionConnection(22, SC2Campaign.WOL)], SC2Mission.SHATTER_THE_SKY.area, completion_critical=True), + SC2Mission.ALL_IN.mission_name: MissionInfo(SC2Mission.ALL_IN, [MissionConnection(23, SC2Campaign.WOL), MissionConnection(24, SC2Campaign.WOL)], SC2Mission.ALL_IN.area, or_requirements=True, completion_critical=True) + }, + SC2Campaign.PROPHECY: { + SC2Mission.WHISPERS_OF_DOOM.mission_name: MissionInfo(SC2Mission.WHISPERS_OF_DOOM, [MissionConnection(9, SC2Campaign.WOL)], SC2Mission.WHISPERS_OF_DOOM.area), + SC2Mission.A_SINISTER_TURN.mission_name: MissionInfo(SC2Mission.A_SINISTER_TURN, [MissionConnection(1, SC2Campaign.PROPHECY)], SC2Mission.A_SINISTER_TURN.area), + SC2Mission.ECHOES_OF_THE_FUTURE.mission_name: MissionInfo(SC2Mission.ECHOES_OF_THE_FUTURE, [MissionConnection(2, SC2Campaign.PROPHECY)], SC2Mission.ECHOES_OF_THE_FUTURE.area), + SC2Mission.IN_UTTER_DARKNESS.mission_name: MissionInfo(SC2Mission.IN_UTTER_DARKNESS, [MissionConnection(3, SC2Campaign.PROPHECY)], SC2Mission.IN_UTTER_DARKNESS.area) + }, + SC2Campaign.HOTS: { + SC2Mission.LAB_RAT.mission_name: MissionInfo(SC2Mission.LAB_RAT, [], SC2Mission.LAB_RAT.area, completion_critical=True), + SC2Mission.BACK_IN_THE_SADDLE.mission_name: MissionInfo(SC2Mission.BACK_IN_THE_SADDLE, [MissionConnection(1, SC2Campaign.HOTS)], SC2Mission.BACK_IN_THE_SADDLE.area, completion_critical=True), + SC2Mission.RENDEZVOUS.mission_name: MissionInfo(SC2Mission.RENDEZVOUS, [MissionConnection(2, SC2Campaign.HOTS)], SC2Mission.RENDEZVOUS.area, completion_critical=True), + SC2Mission.HARVEST_OF_SCREAMS.mission_name: MissionInfo(SC2Mission.HARVEST_OF_SCREAMS, [MissionConnection(3, SC2Campaign.HOTS)], SC2Mission.HARVEST_OF_SCREAMS.area), + SC2Mission.SHOOT_THE_MESSENGER.mission_name: MissionInfo(SC2Mission.SHOOT_THE_MESSENGER, [MissionConnection(4, SC2Campaign.HOTS)], SC2Mission.SHOOT_THE_MESSENGER.area), + SC2Mission.ENEMY_WITHIN.mission_name: MissionInfo(SC2Mission.ENEMY_WITHIN, [MissionConnection(5, SC2Campaign.HOTS)], SC2Mission.ENEMY_WITHIN.area), + SC2Mission.DOMINATION.mission_name: MissionInfo(SC2Mission.DOMINATION, [MissionConnection(3, SC2Campaign.HOTS)], SC2Mission.DOMINATION.area), + SC2Mission.FIRE_IN_THE_SKY.mission_name: MissionInfo(SC2Mission.FIRE_IN_THE_SKY, [MissionConnection(7, SC2Campaign.HOTS)], SC2Mission.FIRE_IN_THE_SKY.area), + SC2Mission.OLD_SOLDIERS.mission_name: MissionInfo(SC2Mission.OLD_SOLDIERS, [MissionConnection(8, SC2Campaign.HOTS)], SC2Mission.OLD_SOLDIERS.area), + SC2Mission.WAKING_THE_ANCIENT.mission_name: MissionInfo(SC2Mission.WAKING_THE_ANCIENT, [MissionConnection(6, SC2Campaign.HOTS), MissionConnection(9, SC2Campaign.HOTS)], SC2Mission.WAKING_THE_ANCIENT.area, completion_critical=True, or_requirements=True), + SC2Mission.THE_CRUCIBLE.mission_name: MissionInfo(SC2Mission.THE_CRUCIBLE, [MissionConnection(10, SC2Campaign.HOTS)], SC2Mission.THE_CRUCIBLE.area, completion_critical=True), + SC2Mission.SUPREME.mission_name: MissionInfo(SC2Mission.SUPREME, [MissionConnection(11, SC2Campaign.HOTS)], SC2Mission.SUPREME.area, completion_critical=True), + SC2Mission.INFESTED.mission_name: MissionInfo(SC2Mission.INFESTED, [MissionConnection(6, SC2Campaign.HOTS), MissionConnection(9, SC2Campaign.HOTS), MissionConnection(12, SC2Campaign.HOTS)], SC2Mission.INFESTED.area), + SC2Mission.HAND_OF_DARKNESS.mission_name: MissionInfo(SC2Mission.HAND_OF_DARKNESS, [MissionConnection(13, SC2Campaign.HOTS)], SC2Mission.HAND_OF_DARKNESS.area), + SC2Mission.PHANTOMS_OF_THE_VOID.mission_name: MissionInfo(SC2Mission.PHANTOMS_OF_THE_VOID, [MissionConnection(14, SC2Campaign.HOTS)], SC2Mission.PHANTOMS_OF_THE_VOID.area), + SC2Mission.WITH_FRIENDS_LIKE_THESE.mission_name: MissionInfo(SC2Mission.WITH_FRIENDS_LIKE_THESE, [MissionConnection(6, SC2Campaign.HOTS), MissionConnection(9, SC2Campaign.HOTS), MissionConnection(12, SC2Campaign.HOTS)], SC2Mission.WITH_FRIENDS_LIKE_THESE.area), + SC2Mission.CONVICTION.mission_name: MissionInfo(SC2Mission.CONVICTION, [MissionConnection(16, SC2Campaign.HOTS)], SC2Mission.CONVICTION.area), + SC2Mission.PLANETFALL.mission_name: MissionInfo(SC2Mission.PLANETFALL, [MissionConnection(15, SC2Campaign.HOTS), MissionConnection(17, SC2Campaign.HOTS)], SC2Mission.PLANETFALL.area, completion_critical=True), + SC2Mission.DEATH_FROM_ABOVE.mission_name: MissionInfo(SC2Mission.DEATH_FROM_ABOVE, [MissionConnection(18, SC2Campaign.HOTS)], SC2Mission.DEATH_FROM_ABOVE.area, completion_critical=True), + SC2Mission.THE_RECKONING.mission_name: MissionInfo(SC2Mission.THE_RECKONING, [MissionConnection(19, SC2Campaign.HOTS)], SC2Mission.THE_RECKONING.area, completion_critical=True), + }, + SC2Campaign.PROLOGUE: { + SC2Mission.DARK_WHISPERS.mission_name: MissionInfo(SC2Mission.DARK_WHISPERS, [], SC2Mission.DARK_WHISPERS.area), + SC2Mission.GHOSTS_IN_THE_FOG.mission_name: MissionInfo(SC2Mission.GHOSTS_IN_THE_FOG, [MissionConnection(1, SC2Campaign.PROLOGUE)], SC2Mission.GHOSTS_IN_THE_FOG.area), + SC2Mission.EVIL_AWOKEN.mission_name: MissionInfo(SC2Mission.EVIL_AWOKEN, [MissionConnection(2, SC2Campaign.PROLOGUE)], SC2Mission.EVIL_AWOKEN.area) + }, + SC2Campaign.LOTV: { + SC2Mission.FOR_AIUR.mission_name: MissionInfo(SC2Mission.FOR_AIUR, [], SC2Mission.FOR_AIUR.area, completion_critical=True), + SC2Mission.THE_GROWING_SHADOW.mission_name: MissionInfo(SC2Mission.THE_GROWING_SHADOW, [MissionConnection(1, SC2Campaign.LOTV)], SC2Mission.THE_GROWING_SHADOW.area, completion_critical=True), + SC2Mission.THE_SPEAR_OF_ADUN.mission_name: MissionInfo(SC2Mission.THE_SPEAR_OF_ADUN, [MissionConnection(2, SC2Campaign.LOTV)], SC2Mission.THE_SPEAR_OF_ADUN.area, completion_critical=True), + SC2Mission.SKY_SHIELD.mission_name: MissionInfo(SC2Mission.SKY_SHIELD, [MissionConnection(3, SC2Campaign.LOTV)], SC2Mission.SKY_SHIELD.area, completion_critical=True), + SC2Mission.BROTHERS_IN_ARMS.mission_name: MissionInfo(SC2Mission.BROTHERS_IN_ARMS, [MissionConnection(4, SC2Campaign.LOTV)], SC2Mission.BROTHERS_IN_ARMS.area, completion_critical=True), + SC2Mission.AMON_S_REACH.mission_name: MissionInfo(SC2Mission.AMON_S_REACH, [MissionConnection(3, SC2Campaign.LOTV)], SC2Mission.AMON_S_REACH.area, completion_critical=True), + SC2Mission.LAST_STAND.mission_name: MissionInfo(SC2Mission.LAST_STAND, [MissionConnection(6, SC2Campaign.LOTV)], SC2Mission.LAST_STAND.area, completion_critical=True), + SC2Mission.FORBIDDEN_WEAPON.mission_name: MissionInfo(SC2Mission.FORBIDDEN_WEAPON, [MissionConnection(5, SC2Campaign.LOTV), MissionConnection(7, SC2Campaign.LOTV)], SC2Mission.FORBIDDEN_WEAPON.area, completion_critical=True, or_requirements=True), + SC2Mission.TEMPLE_OF_UNIFICATION.mission_name: MissionInfo(SC2Mission.TEMPLE_OF_UNIFICATION, [MissionConnection(5, SC2Campaign.LOTV), MissionConnection(7, SC2Campaign.LOTV), MissionConnection(8, SC2Campaign.LOTV)], SC2Mission.TEMPLE_OF_UNIFICATION.area, completion_critical=True), + SC2Mission.THE_INFINITE_CYCLE.mission_name: MissionInfo(SC2Mission.THE_INFINITE_CYCLE, [MissionConnection(9, SC2Campaign.LOTV)], SC2Mission.THE_INFINITE_CYCLE.area, completion_critical=True), + SC2Mission.HARBINGER_OF_OBLIVION.mission_name: MissionInfo(SC2Mission.HARBINGER_OF_OBLIVION, [MissionConnection(10, SC2Campaign.LOTV)], SC2Mission.HARBINGER_OF_OBLIVION.area, completion_critical=True), + SC2Mission.UNSEALING_THE_PAST.mission_name: MissionInfo(SC2Mission.UNSEALING_THE_PAST, [MissionConnection(11, SC2Campaign.LOTV)], SC2Mission.UNSEALING_THE_PAST.area, completion_critical=True), + SC2Mission.PURIFICATION.mission_name: MissionInfo(SC2Mission.PURIFICATION, [MissionConnection(12, SC2Campaign.LOTV)], SC2Mission.PURIFICATION.area, completion_critical=True), + SC2Mission.STEPS_OF_THE_RITE.mission_name: MissionInfo(SC2Mission.STEPS_OF_THE_RITE, [MissionConnection(11, SC2Campaign.LOTV)], SC2Mission.STEPS_OF_THE_RITE.area, completion_critical=True), + SC2Mission.RAK_SHIR.mission_name: MissionInfo(SC2Mission.RAK_SHIR, [MissionConnection(14, SC2Campaign.LOTV)], SC2Mission.RAK_SHIR.area, completion_critical=True), + SC2Mission.TEMPLAR_S_CHARGE.mission_name: MissionInfo(SC2Mission.TEMPLAR_S_CHARGE, [MissionConnection(13, SC2Campaign.LOTV), MissionConnection(15, SC2Campaign.LOTV)], SC2Mission.TEMPLAR_S_CHARGE.area, completion_critical=True, or_requirements=True), + SC2Mission.TEMPLAR_S_RETURN.mission_name: MissionInfo(SC2Mission.TEMPLAR_S_RETURN, [MissionConnection(13, SC2Campaign.LOTV), MissionConnection(15, SC2Campaign.LOTV), MissionConnection(16, SC2Campaign.LOTV)], SC2Mission.TEMPLAR_S_RETURN.area, completion_critical=True), + SC2Mission.THE_HOST.mission_name: MissionInfo(SC2Mission.THE_HOST, [MissionConnection(17, SC2Campaign.LOTV)], SC2Mission.THE_HOST.area, completion_critical=True), + SC2Mission.SALVATION.mission_name: MissionInfo(SC2Mission.SALVATION, [MissionConnection(18, SC2Campaign.LOTV)], SC2Mission.SALVATION.area, completion_critical=True), + }, + SC2Campaign.EPILOGUE: { + SC2Mission.INTO_THE_VOID.mission_name: MissionInfo(SC2Mission.INTO_THE_VOID, [MissionConnection(25, SC2Campaign.WOL), MissionConnection(20, SC2Campaign.HOTS), MissionConnection(19, SC2Campaign.LOTV)], SC2Mission.INTO_THE_VOID.area, completion_critical=True), + SC2Mission.THE_ESSENCE_OF_ETERNITY.mission_name: MissionInfo(SC2Mission.THE_ESSENCE_OF_ETERNITY, [MissionConnection(1, SC2Campaign.EPILOGUE)], SC2Mission.THE_ESSENCE_OF_ETERNITY.area, completion_critical=True), + SC2Mission.AMON_S_FALL.mission_name: MissionInfo(SC2Mission.AMON_S_FALL, [MissionConnection(2, SC2Campaign.EPILOGUE)], SC2Mission.AMON_S_FALL.area, completion_critical=True), + }, + SC2Campaign.NCO: { + SC2Mission.THE_ESCAPE.mission_name: MissionInfo(SC2Mission.THE_ESCAPE, [], SC2Mission.THE_ESCAPE.area, completion_critical=True), + SC2Mission.SUDDEN_STRIKE.mission_name: MissionInfo(SC2Mission.SUDDEN_STRIKE, [MissionConnection(1, SC2Campaign.NCO)], SC2Mission.SUDDEN_STRIKE.area, completion_critical=True), + SC2Mission.ENEMY_INTELLIGENCE.mission_name: MissionInfo(SC2Mission.ENEMY_INTELLIGENCE, [MissionConnection(2, SC2Campaign.NCO)], SC2Mission.ENEMY_INTELLIGENCE.area, completion_critical=True), + SC2Mission.TROUBLE_IN_PARADISE.mission_name: MissionInfo(SC2Mission.TROUBLE_IN_PARADISE, [MissionConnection(3, SC2Campaign.NCO)], SC2Mission.TROUBLE_IN_PARADISE.area, completion_critical=True), + SC2Mission.NIGHT_TERRORS.mission_name: MissionInfo(SC2Mission.NIGHT_TERRORS, [MissionConnection(4, SC2Campaign.NCO)], SC2Mission.NIGHT_TERRORS.area, completion_critical=True), + SC2Mission.FLASHPOINT.mission_name: MissionInfo(SC2Mission.FLASHPOINT, [MissionConnection(5, SC2Campaign.NCO)], SC2Mission.FLASHPOINT.area, completion_critical=True), + SC2Mission.IN_THE_ENEMY_S_SHADOW.mission_name: MissionInfo(SC2Mission.IN_THE_ENEMY_S_SHADOW, [MissionConnection(6, SC2Campaign.NCO)], SC2Mission.IN_THE_ENEMY_S_SHADOW.area, completion_critical=True), + SC2Mission.DARK_SKIES.mission_name: MissionInfo(SC2Mission.DARK_SKIES, [MissionConnection(7, SC2Campaign.NCO)], SC2Mission.DARK_SKIES.area, completion_critical=True), + SC2Mission.END_GAME.mission_name: MissionInfo(SC2Mission.END_GAME, [MissionConnection(8, SC2Campaign.NCO)], SC2Mission.END_GAME.area, completion_critical=True), + } +} + lookup_id_to_mission: Dict[int, SC2Mission] = { mission.id: mission for mission in SC2Mission } diff --git a/worlds/sc2/options.py b/worlds/sc2/options.py index 09caea241c2f..792f23578af2 100644 --- a/worlds/sc2/options.py +++ b/worlds/sc2/options.py @@ -7,8 +7,8 @@ from BaseClasses import PlandoOptions from .mission_tables import SC2Campaign, SC2Mission, lookup_name_to_mission, MissionPools, get_missions_with_any_flags_in_list, \ campaign_mission_table, SC2Race, MissionFlag +from .mission_orders import vanilla_shuffle_order, mini_campaign_order from .mission_groups import mission_groups, MissionGroupNames -from .mission_order.options import CustomMissionOrder if TYPE_CHECKING: from worlds.AutoWorld import World @@ -129,7 +129,6 @@ class MissionOrder(Choice): Grid: Missions are arranged into a grid. Completing a mission unlocks the adjacent missions. Corners may be omitted to make the grid more square. Complete the bottom-right mission to win. Golden Path: A required line of missions with several optional branches, similar to the Wings of Liberty campaign. Hopscotch: Missions alternate between mandatory missions and pairs of optional missions. - Custom: Uses the YAML's custom mission order option. See documentation for usage. """ display_name = "Mission Order" option_vanilla = 0 @@ -140,7 +139,6 @@ class MissionOrder(Choice): option_grid = 9 option_golden_path = 10 option_hopscotch = 11 - option_custom = 99 class MaximumCampaignSize(Range): @@ -150,7 +148,7 @@ class MaximumCampaignSize(Range): """ display_name = "Maximum Campaign Size" range_start = 1 - range_end = 101 + range_end = 105 default = 83 @@ -1018,7 +1016,6 @@ class Starcraft2Options(PerGameCommonOptions): vespene_per_item: VespenePerItem starting_supply_per_item: StartingSupplyPerItem - custom_mission_order: CustomMissionOrder def get_option_value(world: Union['SC2World', None], name: str) -> Union[int, FrozenSet]: if world is None: @@ -1132,12 +1129,18 @@ def get_excluded_missions(world: 'SC2World') -> Set[SC2Mission]: return excluded_missions -static_mission_orders = [ +campaign_depending_orders = [ MissionOrder.option_vanilla, MissionOrder.option_vanilla_shuffled, MissionOrder.option_mini_campaign ] +static_mission_orders = { + MissionOrder.option_vanilla: vanilla_shuffle_order, + MissionOrder.option_vanilla_shuffled: vanilla_shuffle_order, + MissionOrder.option_mini_campaign: mini_campaign_order +} + dynamic_mission_orders = [ MissionOrder.option_golden_path, MissionOrder.option_grid, diff --git a/worlds/sc2/rules.py b/worlds/sc2/rules.py index 0dec559ce019..7c2f7a97ff03 100644 --- a/worlds/sc2/rules.py +++ b/worlds/sc2/rules.py @@ -212,12 +212,11 @@ def terran_great_train_robbery_train_stopper(self, state: CollectionState) -> bo """ return ( state.has_any({item_names.SIEGE_TANK, item_names.DIAMONDBACK, item_names.MARAUDER, item_names.CYCLONE, item_names.BANSHEE}, self.player) - or (self.advanced_tactics - and ( - state.has_all({item_names.REAPER, item_names.REAPER_G4_CLUSTERBOMB}, self.player) - or state.has_all({item_names.SPECTRE, item_names.SPECTRE_PSIONIC_LASH}, self.player) - or state.has_any({item_names.VULTURE, item_names.LIBERATOR}, self.player) - ) + or self.advanced_tactics + and ( + state.has_all({item_names.REAPER, item_names.REAPER_G4_CLUSTERBOMB}, self.player) + or state.has_all({item_names.SPECTRE, item_names.SPECTRE_PSIONIC_LASH}, self.player) + or state.has_any({item_names.VULTURE, item_names.LIBERATOR}, self.player) ) ) @@ -238,7 +237,7 @@ def zerg_great_train_robbery_train_stopper(self, state: CollectionState) -> bool ) ) ) - + def protoss_great_train_robbery_train_stopper(self, state: CollectionState) -> bool: """ Ability to deal with trains (moving target with a lot of HP) @@ -258,7 +257,6 @@ def protoss_great_train_robbery_train_stopper(self, state: CollectionState) -> b ) ) ) - ) def terran_can_rescue(self, state) -> bool: @@ -389,7 +387,7 @@ def terran_respond_to_colony_infestations(self, state: CollectionState) -> bool: and self.terran_defense_rating(state, True) >= 3 ) - def engine_of_destruction_requirement(self, state: CollectionState): + def terran_engine_of_destruction_requirement(self, state: CollectionState): return ( self.marine_medic_upgrade(state) and (state.has(item_names.WRAITH, self.player) @@ -400,6 +398,54 @@ def engine_of_destruction_requirement(self, state: CollectionState): ) ) + def zerg_engine_of_destruction_requirement(self, state: CollectionState): + return ( + self.zergling_hydra_roach_start(state) + and state.has(item_names.SWARM_QUEEN, self.player) + and ( + self.zerg_competent_anti_air(state) + and self.zerg_common_unit(state) + ) + + ) + + + def protoss_engine_of_destruction_requirement(self, state: CollectionState): + return ( + self.zealot_sentry_slayer_start(state) + and ( + state.has(item_names.SENTRY, self.player) + or (self.advanced_tactics + and state.has(item_names.SHIELD_BATTERY, self.player) + ) + ) + and ( + self.protoss_competent_anti_air(state) + and self.protoss_common_unit(state) + ) + ) + + def zergling_hydra_roach_start(self, state: CollectionState): + """ + Created mainly for engine of destruction start, but works for other missions with no-build starts. + :param state: + :return: + """ + return ( + state.has_any({item_names.ZERGLING_ADRENAL_OVERLOAD, item_names.HYDRALISK_FRENZY, item_names.ROACH_HYDRIODIC_BILE}, self.player) + ) + + def zealot_sentry_slayer_start(self, state: CollectionState): + """ + Created mainly for engine of destruction start, but works for other missions with no-build starts. + :param state: + :return: + """ + return ( + state.has_any({item_names.ZEALOT_WHIRLWIND, item_names.SENTRY_DOUBLE_SHIELD_RECHARGE, item_names.SLAYER_PHASE_BLINK}, self.player) + ) + + def all_in_requirement(self, state: CollectionState): """ All-in @@ -702,6 +748,7 @@ def the_reckoning_requirement(self, state: CollectionState) -> bool: # LotV + def protoss_defense_rating(self, state: CollectionState, zerg_enemy: bool) -> int: """ Ability to handle defensive missions From baaae767fe6c5c5ca9edbb0c96f3a65fe2f81f9b Mon Sep 17 00:00:00 2001 From: SirChuckOfTheChuckles Date: Sat, 31 Aug 2024 20:40:39 -0400 Subject: [PATCH 2/4] real fixes real fixes --- worlds/sc2/locations.py | 4 ++-- worlds/sc2/rules.py | 28 +++++++++++++++++++++------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/worlds/sc2/locations.py b/worlds/sc2/locations.py index 2c31a86623f8..4f8f5a1f986a 100644 --- a/worlds/sc2/locations.py +++ b/worlds/sc2/locations.py @@ -2950,7 +2950,7 @@ def get_locations(world: Optional['SC2World']) -> Tuple[LocationData, ...]: make_location_data(SC2Mission.MEDIA_BLITZ_Z.mission_name, "All Starports", SC2_RACESWAP_LOC_ID_OFFSET + 3907, LocationType.EXTRA, lambda state: adv_tactics or logic.zerg_competent_comp(state) ), - make_location_data(SC2Mission.MEDIA_BLITZ_Z.mission_name, "Brutalisk Prime Survives", SC2_RACESWAP_LOC_ID_OFFSET + 3908, LocationType.CHALLENGE, + make_location_data(SC2Mission.MEDIA_BLITZ_Z.mission_name, "Odin Not Trashed", SC2_RACESWAP_LOC_ID_OFFSET + 3908, LocationType.CHALLENGE, logic.zerg_competent_comp ), make_location_data(SC2Mission.MEDIA_BLITZ_Z.mission_name, "Surprise Attack Ends", SC2_RACESWAP_LOC_ID_OFFSET + 3909, LocationType.EXTRA), @@ -2976,7 +2976,7 @@ def get_locations(world: Optional['SC2World']) -> Tuple[LocationData, ...]: make_location_data(SC2Mission.MEDIA_BLITZ_P.mission_name, "All Starports", SC2_RACESWAP_LOC_ID_OFFSET + 4007, LocationType.EXTRA, lambda state: adv_tactics or logic.protoss_competent_comp(state) ), - make_location_data(SC2Mission.MEDIA_BLITZ_P.mission_name, "Nyon's Vengeance Survives", SC2_RACESWAP_LOC_ID_OFFSET + 4008, LocationType.CHALLENGE, + make_location_data(SC2Mission.MEDIA_BLITZ_P.mission_name, "Odin Not Trashed", SC2_RACESWAP_LOC_ID_OFFSET + 4008, LocationType.CHALLENGE, logic.protoss_competent_comp ), make_location_data(SC2Mission.MEDIA_BLITZ_P.mission_name, "Surprise Attack Ends", SC2_RACESWAP_LOC_ID_OFFSET + 4009, LocationType.EXTRA), diff --git a/worlds/sc2/rules.py b/worlds/sc2/rules.py index 7c2f7a97ff03..6d3b643a71b6 100644 --- a/worlds/sc2/rules.py +++ b/worlds/sc2/rules.py @@ -401,7 +401,7 @@ def terran_engine_of_destruction_requirement(self, state: CollectionState): def zerg_engine_of_destruction_requirement(self, state: CollectionState): return ( self.zergling_hydra_roach_start(state) - and state.has(item_names.SWARM_QUEEN, self.player) + and self.zerg_repair_odin(state) and ( self.zerg_competent_anti_air(state) and self.zerg_common_unit(state) @@ -413,18 +413,29 @@ def zerg_engine_of_destruction_requirement(self, state: CollectionState): def protoss_engine_of_destruction_requirement(self, state: CollectionState): return ( self.zealot_sentry_slayer_start(state) - and ( - state.has(item_names.SENTRY, self.player) - or (self.advanced_tactics - and state.has(item_names.SHIELD_BATTERY, self.player) - ) - ) + and self.protoss_repair_odin(state) and ( self.protoss_competent_anti_air(state) and self.protoss_common_unit(state) ) ) + def zerg_repair_odin(self, state: CollectionState): + return ( + state.has_all({item_names.SWARM_QUEEN_BIO_MECHANICAL_TRANSFUSION, item_names.SWARM_QUEEN}, self.player) + or (self.advanced_tactics + and state.has(item_names.SWARM_QUEEN, self.player) + ) + ) + + def protoss_repair_odin(self, state: CollectionState): + return ( + state.has(item_names.SENTRY, self.player) + or (self.advanced_tactics + and state.has(item_names.SHIELD_BATTERY, self.player) + ) + ) + def zergling_hydra_roach_start(self, state: CollectionState): """ Created mainly for engine of destruction start, but works for other missions with no-build starts. @@ -445,7 +456,10 @@ def zealot_sentry_slayer_start(self, state: CollectionState): state.has_any({item_names.ZEALOT_WHIRLWIND, item_names.SENTRY_DOUBLE_SHIELD_RECHARGE, item_names.SLAYER_PHASE_BLINK}, self.player) ) +<<<<<<< HEAD +======= +>>>>>>> c614949c1 (real fixes) def all_in_requirement(self, state: CollectionState): """ All-in From 0b0593937db0ee597900511e8c3ebeec54bd59fa Mon Sep 17 00:00:00 2001 From: SirChuckOfTheChuckles Date: Sat, 31 Aug 2024 20:57:12 -0400 Subject: [PATCH 3/4] rebase inconsistencies --- worlds/sc2/locations.py | 35 ++++++++++- worlds/sc2/mission_tables.py | 112 +---------------------------------- worlds/sc2/options.py | 13 ++-- worlds/sc2/rules.py | 4 -- 4 files changed, 39 insertions(+), 125 deletions(-) diff --git a/worlds/sc2/locations.py b/worlds/sc2/locations.py index 4f8f5a1f986a..d2601dfa35db 100644 --- a/worlds/sc2/locations.py +++ b/worlds/sc2/locations.py @@ -419,6 +419,33 @@ def get_locations(world: Optional['SC2World']) -> Tuple[LocationData, ...]: and logic.terran_common_unit(state) and (logic.marine_medic_upgrade(state) or adv_tactics)) ), + make_location_data(SC2Mission.THE_DIG.mission_name, "Northwestern Protoss Base", SC2WOL_LOC_ID_OFFSET + 909, LocationType.MASTERY, + lambda state: ( + logic.terran_basic_anti_air(state) + and logic.terran_defense_rating(state, False, True) >= 8 + and logic.terran_defense_rating(state, False, False) >= 6 + and logic.terran_common_unit(state) + and (logic.marine_medic_upgrade(state) or adv_tactics) + and (logic.terran_base_trasher(state) or state.has(item_names.COMMAND_CENTER_SCANNER_SWEEP, player))) + ), + make_location_data(SC2Mission.THE_DIG.mission_name, "Northeastern Protoss Base", SC2WOL_LOC_ID_OFFSET + 910, LocationType.MASTERY, + lambda state: ( + logic.terran_basic_anti_air(state) + and logic.terran_defense_rating(state, False, True) >= 8 + and logic.terran_defense_rating(state, False, False) >= 6 + and logic.terran_common_unit(state) + and (logic.marine_medic_upgrade(state) or adv_tactics) + and (logic.terran_base_trasher(state) or state.has(item_names.COMMAND_CENTER_SCANNER_SWEEP, player))) + ), + make_location_data(SC2Mission.THE_DIG.mission_name, "Eastern Protoss Base", SC2WOL_LOC_ID_OFFSET + 911, LocationType.MASTERY, + lambda state: ( + logic.terran_basic_anti_air(state) + and logic.terran_defense_rating(state, False, True) >= 8 + and logic.terran_defense_rating(state, False, False) >= 6 + and logic.terran_common_unit(state) + and (logic.marine_medic_upgrade(state) or adv_tactics) + and (logic.terran_base_trasher(state) or state.has(item_names.COMMAND_CENTER_SCANNER_SWEEP, player))) + ), make_location_data(SC2Mission.THE_MOEBIUS_FACTOR.mission_name, "Victory", SC2WOL_LOC_ID_OFFSET + 1000, LocationType.VICTORY, lambda state: ( logic.terran_basic_anti_air(state) @@ -2951,7 +2978,9 @@ def get_locations(world: Optional['SC2World']) -> Tuple[LocationData, ...]: lambda state: adv_tactics or logic.zerg_competent_comp(state) ), make_location_data(SC2Mission.MEDIA_BLITZ_Z.mission_name, "Odin Not Trashed", SC2_RACESWAP_LOC_ID_OFFSET + 3908, LocationType.CHALLENGE, - logic.zerg_competent_comp + lambda state: ( + logic.zerg_competent_comp(state) + and logic.zerg_repair_odin(state)) ), make_location_data(SC2Mission.MEDIA_BLITZ_Z.mission_name, "Surprise Attack Ends", SC2_RACESWAP_LOC_ID_OFFSET + 3909, LocationType.EXTRA), make_location_data(SC2Mission.MEDIA_BLITZ_P.mission_name, "Victory", SC2_RACESWAP_LOC_ID_OFFSET + 4000, LocationType.VICTORY, @@ -2977,7 +3006,9 @@ def get_locations(world: Optional['SC2World']) -> Tuple[LocationData, ...]: lambda state: adv_tactics or logic.protoss_competent_comp(state) ), make_location_data(SC2Mission.MEDIA_BLITZ_P.mission_name, "Odin Not Trashed", SC2_RACESWAP_LOC_ID_OFFSET + 4008, LocationType.CHALLENGE, - logic.protoss_competent_comp + lambda state: ( + logic.protoss_competent_comp(state) + and logic.protoss_repair_odin(state)) ), make_location_data(SC2Mission.MEDIA_BLITZ_P.mission_name, "Surprise Attack Ends", SC2_RACESWAP_LOC_ID_OFFSET + 4009, LocationType.EXTRA), ] diff --git a/worlds/sc2/mission_tables.py b/worlds/sc2/mission_tables.py index 1f1d86f7d258..7e4e2ee48758 100644 --- a/worlds/sc2/mission_tables.py +++ b/worlds/sc2/mission_tables.py @@ -210,7 +210,7 @@ def __init__(self, mission_id: int, name: str, campaign: SC2Campaign, area: str, SAFE_HAVEN_P = 95, "Safe Haven (Protoss)", SC2Campaign.WOL, "Colonist", SC2Race.PROTOSS, MissionPools.MEDIUM, "ap_safe_haven", MissionFlag.Protoss|MissionFlag.Countdown|MissionFlag.VsProtoss|MissionFlag.RaceSwap HAVENS_FALL_Z = 96, "Haven's Fall (Zerg)", SC2Campaign.WOL, "Colonist", SC2Race.ZERG, MissionPools.MEDIUM, "ap_havens_fall", MissionFlag.Zerg|MissionFlag.VsZerg|MissionFlag.RaceSwap HAVENS_FALL_P = 97, "Haven's Fall (Protoss)", SC2Campaign.WOL, "Colonist", SC2Race.PROTOSS, MissionPools.MEDIUM, "ap_havens_fall", MissionFlag.Protoss|MissionFlag.VsZerg|MissionFlag.RaceSwap - SMASH_AND_GRAB_Z = 98, "Smash and Grab (Zerg)", SC2Campaign.WOL, "Artifact", SC2Race.ZERG, MissionPools.EASY, "ap_smash_and_grab", MissionFlag.Zerg|MissionFlag.Countdown|MissionFlag.VsPZ|MissionFlag.RaceSwap + SMASH_AND_GRAB_Z = 98, "Smash and Grab (Zerg)", 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 (Protoss)", SC2Campaign.WOL, "Artifact", SC2Race.PROTOSS, MissionPools.EASY, "ap_smash_and_grab", MissionFlag.Protoss|MissionFlag.Countdown|MissionFlag.VsPZ|MissionFlag.RaceSwap # 100/101 - The Dig # 102/103 - Moebius Factor @@ -283,116 +283,6 @@ class MissionInfo(NamedTuple): ui_vertical_padding: int = 0 # How many blank padding tiles go above this mission in the launcher -class FillMission(NamedTuple): - type: MissionPools - connect_to: List[MissionConnection] - category: str - number: int = 0 # number of worlds need beaten - completion_critical: bool = False # missions needed to beat game - or_requirements: bool = False # true if the requirements should be or-ed instead of and-ed - removal_priority: int = 0 # how many missions missing from the pool required to remove this mission - ui_vertical_padding: int = 0 # How many blank padding tiles go above this mission in the launcher - - -vanilla_mission_req_table: Dict[SC2Campaign, Dict[str, MissionInfo]] = { - SC2Campaign.WOL: { - SC2Mission.LIBERATION_DAY.mission_name: MissionInfo(SC2Mission.LIBERATION_DAY, [], SC2Mission.LIBERATION_DAY.area, completion_critical=True), - SC2Mission.THE_OUTLAWS.mission_name: MissionInfo(SC2Mission.THE_OUTLAWS, [MissionConnection(1, SC2Campaign.WOL)], SC2Mission.THE_OUTLAWS.area, completion_critical=True), - SC2Mission.ZERO_HOUR.mission_name: MissionInfo(SC2Mission.ZERO_HOUR, [MissionConnection(2, SC2Campaign.WOL)], SC2Mission.ZERO_HOUR.area, completion_critical=True), - SC2Mission.EVACUATION.mission_name: MissionInfo(SC2Mission.EVACUATION, [MissionConnection(3, SC2Campaign.WOL)], SC2Mission.EVACUATION.area), - SC2Mission.OUTBREAK.mission_name: MissionInfo(SC2Mission.OUTBREAK, [MissionConnection(4, SC2Campaign.WOL)], SC2Mission.OUTBREAK.area), - SC2Mission.SAFE_HAVEN.mission_name: MissionInfo(SC2Mission.SAFE_HAVEN, [MissionConnection(5, SC2Campaign.WOL)], SC2Mission.SAFE_HAVEN.area, number=7), - SC2Mission.HAVENS_FALL.mission_name: MissionInfo(SC2Mission.HAVENS_FALL, [MissionConnection(5, SC2Campaign.WOL)], SC2Mission.HAVENS_FALL.area, number=7), - SC2Mission.SMASH_AND_GRAB.mission_name: MissionInfo(SC2Mission.SMASH_AND_GRAB, [MissionConnection(3, SC2Campaign.WOL)], SC2Mission.SMASH_AND_GRAB.area, completion_critical=True), - SC2Mission.THE_DIG.mission_name: MissionInfo(SC2Mission.THE_DIG, [MissionConnection(8, SC2Campaign.WOL)], SC2Mission.THE_DIG.area, number=8, completion_critical=True), - SC2Mission.THE_MOEBIUS_FACTOR.mission_name: MissionInfo(SC2Mission.THE_MOEBIUS_FACTOR, [MissionConnection(9, SC2Campaign.WOL)], SC2Mission.THE_MOEBIUS_FACTOR.area, number=11, completion_critical=True), - SC2Mission.SUPERNOVA.mission_name: MissionInfo(SC2Mission.SUPERNOVA, [MissionConnection(10, SC2Campaign.WOL)], SC2Mission.SUPERNOVA.area, number=14, completion_critical=True), - SC2Mission.MAW_OF_THE_VOID.mission_name: MissionInfo(SC2Mission.MAW_OF_THE_VOID, [MissionConnection(11, SC2Campaign.WOL)], SC2Mission.MAW_OF_THE_VOID.area, completion_critical=True), - SC2Mission.DEVILS_PLAYGROUND.mission_name: MissionInfo(SC2Mission.DEVILS_PLAYGROUND, [MissionConnection(3, SC2Campaign.WOL)], SC2Mission.DEVILS_PLAYGROUND.area, number=4), - SC2Mission.WELCOME_TO_THE_JUNGLE.mission_name: MissionInfo(SC2Mission.WELCOME_TO_THE_JUNGLE, [MissionConnection(13, SC2Campaign.WOL)], SC2Mission.WELCOME_TO_THE_JUNGLE.area), - SC2Mission.BREAKOUT.mission_name: MissionInfo(SC2Mission.BREAKOUT, [MissionConnection(14, SC2Campaign.WOL)], SC2Mission.BREAKOUT.area, number=8), - SC2Mission.GHOST_OF_A_CHANCE.mission_name: MissionInfo(SC2Mission.GHOST_OF_A_CHANCE, [MissionConnection(14, SC2Campaign.WOL)], SC2Mission.GHOST_OF_A_CHANCE.area, number=8), - SC2Mission.THE_GREAT_TRAIN_ROBBERY.mission_name: MissionInfo(SC2Mission.THE_GREAT_TRAIN_ROBBERY, [MissionConnection(3, SC2Campaign.WOL)], SC2Mission.THE_GREAT_TRAIN_ROBBERY.area, number=6), - SC2Mission.CUTTHROAT.mission_name: MissionInfo(SC2Mission.CUTTHROAT, [MissionConnection(17, SC2Campaign.WOL)], SC2Mission.THE_GREAT_TRAIN_ROBBERY.area), - SC2Mission.ENGINE_OF_DESTRUCTION.mission_name: MissionInfo(SC2Mission.ENGINE_OF_DESTRUCTION, [MissionConnection(18, SC2Campaign.WOL)], SC2Mission.ENGINE_OF_DESTRUCTION.area), - SC2Mission.MEDIA_BLITZ.mission_name: MissionInfo(SC2Mission.MEDIA_BLITZ, [MissionConnection(19, SC2Campaign.WOL)], SC2Mission.MEDIA_BLITZ.area), - SC2Mission.PIERCING_OF_THE_SHROUD.mission_name: MissionInfo(SC2Mission.PIERCING_OF_THE_SHROUD, [MissionConnection(20, SC2Campaign.WOL)], SC2Mission.PIERCING_OF_THE_SHROUD.area), - SC2Mission.GATES_OF_HELL.mission_name: MissionInfo(SC2Mission.GATES_OF_HELL, [MissionConnection(12, SC2Campaign.WOL)], SC2Mission.GATES_OF_HELL.area, completion_critical=True), - SC2Mission.BELLY_OF_THE_BEAST.mission_name: MissionInfo(SC2Mission.BELLY_OF_THE_BEAST, [MissionConnection(22, SC2Campaign.WOL)], SC2Mission.BELLY_OF_THE_BEAST.area, completion_critical=True), - SC2Mission.SHATTER_THE_SKY.mission_name: MissionInfo(SC2Mission.SHATTER_THE_SKY, [MissionConnection(22, SC2Campaign.WOL)], SC2Mission.SHATTER_THE_SKY.area, completion_critical=True), - SC2Mission.ALL_IN.mission_name: MissionInfo(SC2Mission.ALL_IN, [MissionConnection(23, SC2Campaign.WOL), MissionConnection(24, SC2Campaign.WOL)], SC2Mission.ALL_IN.area, or_requirements=True, completion_critical=True) - }, - SC2Campaign.PROPHECY: { - SC2Mission.WHISPERS_OF_DOOM.mission_name: MissionInfo(SC2Mission.WHISPERS_OF_DOOM, [MissionConnection(9, SC2Campaign.WOL)], SC2Mission.WHISPERS_OF_DOOM.area), - SC2Mission.A_SINISTER_TURN.mission_name: MissionInfo(SC2Mission.A_SINISTER_TURN, [MissionConnection(1, SC2Campaign.PROPHECY)], SC2Mission.A_SINISTER_TURN.area), - SC2Mission.ECHOES_OF_THE_FUTURE.mission_name: MissionInfo(SC2Mission.ECHOES_OF_THE_FUTURE, [MissionConnection(2, SC2Campaign.PROPHECY)], SC2Mission.ECHOES_OF_THE_FUTURE.area), - SC2Mission.IN_UTTER_DARKNESS.mission_name: MissionInfo(SC2Mission.IN_UTTER_DARKNESS, [MissionConnection(3, SC2Campaign.PROPHECY)], SC2Mission.IN_UTTER_DARKNESS.area) - }, - SC2Campaign.HOTS: { - SC2Mission.LAB_RAT.mission_name: MissionInfo(SC2Mission.LAB_RAT, [], SC2Mission.LAB_RAT.area, completion_critical=True), - SC2Mission.BACK_IN_THE_SADDLE.mission_name: MissionInfo(SC2Mission.BACK_IN_THE_SADDLE, [MissionConnection(1, SC2Campaign.HOTS)], SC2Mission.BACK_IN_THE_SADDLE.area, completion_critical=True), - SC2Mission.RENDEZVOUS.mission_name: MissionInfo(SC2Mission.RENDEZVOUS, [MissionConnection(2, SC2Campaign.HOTS)], SC2Mission.RENDEZVOUS.area, completion_critical=True), - SC2Mission.HARVEST_OF_SCREAMS.mission_name: MissionInfo(SC2Mission.HARVEST_OF_SCREAMS, [MissionConnection(3, SC2Campaign.HOTS)], SC2Mission.HARVEST_OF_SCREAMS.area), - SC2Mission.SHOOT_THE_MESSENGER.mission_name: MissionInfo(SC2Mission.SHOOT_THE_MESSENGER, [MissionConnection(4, SC2Campaign.HOTS)], SC2Mission.SHOOT_THE_MESSENGER.area), - SC2Mission.ENEMY_WITHIN.mission_name: MissionInfo(SC2Mission.ENEMY_WITHIN, [MissionConnection(5, SC2Campaign.HOTS)], SC2Mission.ENEMY_WITHIN.area), - SC2Mission.DOMINATION.mission_name: MissionInfo(SC2Mission.DOMINATION, [MissionConnection(3, SC2Campaign.HOTS)], SC2Mission.DOMINATION.area), - SC2Mission.FIRE_IN_THE_SKY.mission_name: MissionInfo(SC2Mission.FIRE_IN_THE_SKY, [MissionConnection(7, SC2Campaign.HOTS)], SC2Mission.FIRE_IN_THE_SKY.area), - SC2Mission.OLD_SOLDIERS.mission_name: MissionInfo(SC2Mission.OLD_SOLDIERS, [MissionConnection(8, SC2Campaign.HOTS)], SC2Mission.OLD_SOLDIERS.area), - SC2Mission.WAKING_THE_ANCIENT.mission_name: MissionInfo(SC2Mission.WAKING_THE_ANCIENT, [MissionConnection(6, SC2Campaign.HOTS), MissionConnection(9, SC2Campaign.HOTS)], SC2Mission.WAKING_THE_ANCIENT.area, completion_critical=True, or_requirements=True), - SC2Mission.THE_CRUCIBLE.mission_name: MissionInfo(SC2Mission.THE_CRUCIBLE, [MissionConnection(10, SC2Campaign.HOTS)], SC2Mission.THE_CRUCIBLE.area, completion_critical=True), - SC2Mission.SUPREME.mission_name: MissionInfo(SC2Mission.SUPREME, [MissionConnection(11, SC2Campaign.HOTS)], SC2Mission.SUPREME.area, completion_critical=True), - SC2Mission.INFESTED.mission_name: MissionInfo(SC2Mission.INFESTED, [MissionConnection(6, SC2Campaign.HOTS), MissionConnection(9, SC2Campaign.HOTS), MissionConnection(12, SC2Campaign.HOTS)], SC2Mission.INFESTED.area), - SC2Mission.HAND_OF_DARKNESS.mission_name: MissionInfo(SC2Mission.HAND_OF_DARKNESS, [MissionConnection(13, SC2Campaign.HOTS)], SC2Mission.HAND_OF_DARKNESS.area), - SC2Mission.PHANTOMS_OF_THE_VOID.mission_name: MissionInfo(SC2Mission.PHANTOMS_OF_THE_VOID, [MissionConnection(14, SC2Campaign.HOTS)], SC2Mission.PHANTOMS_OF_THE_VOID.area), - SC2Mission.WITH_FRIENDS_LIKE_THESE.mission_name: MissionInfo(SC2Mission.WITH_FRIENDS_LIKE_THESE, [MissionConnection(6, SC2Campaign.HOTS), MissionConnection(9, SC2Campaign.HOTS), MissionConnection(12, SC2Campaign.HOTS)], SC2Mission.WITH_FRIENDS_LIKE_THESE.area), - SC2Mission.CONVICTION.mission_name: MissionInfo(SC2Mission.CONVICTION, [MissionConnection(16, SC2Campaign.HOTS)], SC2Mission.CONVICTION.area), - SC2Mission.PLANETFALL.mission_name: MissionInfo(SC2Mission.PLANETFALL, [MissionConnection(15, SC2Campaign.HOTS), MissionConnection(17, SC2Campaign.HOTS)], SC2Mission.PLANETFALL.area, completion_critical=True), - SC2Mission.DEATH_FROM_ABOVE.mission_name: MissionInfo(SC2Mission.DEATH_FROM_ABOVE, [MissionConnection(18, SC2Campaign.HOTS)], SC2Mission.DEATH_FROM_ABOVE.area, completion_critical=True), - SC2Mission.THE_RECKONING.mission_name: MissionInfo(SC2Mission.THE_RECKONING, [MissionConnection(19, SC2Campaign.HOTS)], SC2Mission.THE_RECKONING.area, completion_critical=True), - }, - SC2Campaign.PROLOGUE: { - SC2Mission.DARK_WHISPERS.mission_name: MissionInfo(SC2Mission.DARK_WHISPERS, [], SC2Mission.DARK_WHISPERS.area), - SC2Mission.GHOSTS_IN_THE_FOG.mission_name: MissionInfo(SC2Mission.GHOSTS_IN_THE_FOG, [MissionConnection(1, SC2Campaign.PROLOGUE)], SC2Mission.GHOSTS_IN_THE_FOG.area), - SC2Mission.EVIL_AWOKEN.mission_name: MissionInfo(SC2Mission.EVIL_AWOKEN, [MissionConnection(2, SC2Campaign.PROLOGUE)], SC2Mission.EVIL_AWOKEN.area) - }, - SC2Campaign.LOTV: { - SC2Mission.FOR_AIUR.mission_name: MissionInfo(SC2Mission.FOR_AIUR, [], SC2Mission.FOR_AIUR.area, completion_critical=True), - SC2Mission.THE_GROWING_SHADOW.mission_name: MissionInfo(SC2Mission.THE_GROWING_SHADOW, [MissionConnection(1, SC2Campaign.LOTV)], SC2Mission.THE_GROWING_SHADOW.area, completion_critical=True), - SC2Mission.THE_SPEAR_OF_ADUN.mission_name: MissionInfo(SC2Mission.THE_SPEAR_OF_ADUN, [MissionConnection(2, SC2Campaign.LOTV)], SC2Mission.THE_SPEAR_OF_ADUN.area, completion_critical=True), - SC2Mission.SKY_SHIELD.mission_name: MissionInfo(SC2Mission.SKY_SHIELD, [MissionConnection(3, SC2Campaign.LOTV)], SC2Mission.SKY_SHIELD.area, completion_critical=True), - SC2Mission.BROTHERS_IN_ARMS.mission_name: MissionInfo(SC2Mission.BROTHERS_IN_ARMS, [MissionConnection(4, SC2Campaign.LOTV)], SC2Mission.BROTHERS_IN_ARMS.area, completion_critical=True), - SC2Mission.AMON_S_REACH.mission_name: MissionInfo(SC2Mission.AMON_S_REACH, [MissionConnection(3, SC2Campaign.LOTV)], SC2Mission.AMON_S_REACH.area, completion_critical=True), - SC2Mission.LAST_STAND.mission_name: MissionInfo(SC2Mission.LAST_STAND, [MissionConnection(6, SC2Campaign.LOTV)], SC2Mission.LAST_STAND.area, completion_critical=True), - SC2Mission.FORBIDDEN_WEAPON.mission_name: MissionInfo(SC2Mission.FORBIDDEN_WEAPON, [MissionConnection(5, SC2Campaign.LOTV), MissionConnection(7, SC2Campaign.LOTV)], SC2Mission.FORBIDDEN_WEAPON.area, completion_critical=True, or_requirements=True), - SC2Mission.TEMPLE_OF_UNIFICATION.mission_name: MissionInfo(SC2Mission.TEMPLE_OF_UNIFICATION, [MissionConnection(5, SC2Campaign.LOTV), MissionConnection(7, SC2Campaign.LOTV), MissionConnection(8, SC2Campaign.LOTV)], SC2Mission.TEMPLE_OF_UNIFICATION.area, completion_critical=True), - SC2Mission.THE_INFINITE_CYCLE.mission_name: MissionInfo(SC2Mission.THE_INFINITE_CYCLE, [MissionConnection(9, SC2Campaign.LOTV)], SC2Mission.THE_INFINITE_CYCLE.area, completion_critical=True), - SC2Mission.HARBINGER_OF_OBLIVION.mission_name: MissionInfo(SC2Mission.HARBINGER_OF_OBLIVION, [MissionConnection(10, SC2Campaign.LOTV)], SC2Mission.HARBINGER_OF_OBLIVION.area, completion_critical=True), - SC2Mission.UNSEALING_THE_PAST.mission_name: MissionInfo(SC2Mission.UNSEALING_THE_PAST, [MissionConnection(11, SC2Campaign.LOTV)], SC2Mission.UNSEALING_THE_PAST.area, completion_critical=True), - SC2Mission.PURIFICATION.mission_name: MissionInfo(SC2Mission.PURIFICATION, [MissionConnection(12, SC2Campaign.LOTV)], SC2Mission.PURIFICATION.area, completion_critical=True), - SC2Mission.STEPS_OF_THE_RITE.mission_name: MissionInfo(SC2Mission.STEPS_OF_THE_RITE, [MissionConnection(11, SC2Campaign.LOTV)], SC2Mission.STEPS_OF_THE_RITE.area, completion_critical=True), - SC2Mission.RAK_SHIR.mission_name: MissionInfo(SC2Mission.RAK_SHIR, [MissionConnection(14, SC2Campaign.LOTV)], SC2Mission.RAK_SHIR.area, completion_critical=True), - SC2Mission.TEMPLAR_S_CHARGE.mission_name: MissionInfo(SC2Mission.TEMPLAR_S_CHARGE, [MissionConnection(13, SC2Campaign.LOTV), MissionConnection(15, SC2Campaign.LOTV)], SC2Mission.TEMPLAR_S_CHARGE.area, completion_critical=True, or_requirements=True), - SC2Mission.TEMPLAR_S_RETURN.mission_name: MissionInfo(SC2Mission.TEMPLAR_S_RETURN, [MissionConnection(13, SC2Campaign.LOTV), MissionConnection(15, SC2Campaign.LOTV), MissionConnection(16, SC2Campaign.LOTV)], SC2Mission.TEMPLAR_S_RETURN.area, completion_critical=True), - SC2Mission.THE_HOST.mission_name: MissionInfo(SC2Mission.THE_HOST, [MissionConnection(17, SC2Campaign.LOTV)], SC2Mission.THE_HOST.area, completion_critical=True), - SC2Mission.SALVATION.mission_name: MissionInfo(SC2Mission.SALVATION, [MissionConnection(18, SC2Campaign.LOTV)], SC2Mission.SALVATION.area, completion_critical=True), - }, - SC2Campaign.EPILOGUE: { - SC2Mission.INTO_THE_VOID.mission_name: MissionInfo(SC2Mission.INTO_THE_VOID, [MissionConnection(25, SC2Campaign.WOL), MissionConnection(20, SC2Campaign.HOTS), MissionConnection(19, SC2Campaign.LOTV)], SC2Mission.INTO_THE_VOID.area, completion_critical=True), - SC2Mission.THE_ESSENCE_OF_ETERNITY.mission_name: MissionInfo(SC2Mission.THE_ESSENCE_OF_ETERNITY, [MissionConnection(1, SC2Campaign.EPILOGUE)], SC2Mission.THE_ESSENCE_OF_ETERNITY.area, completion_critical=True), - SC2Mission.AMON_S_FALL.mission_name: MissionInfo(SC2Mission.AMON_S_FALL, [MissionConnection(2, SC2Campaign.EPILOGUE)], SC2Mission.AMON_S_FALL.area, completion_critical=True), - }, - SC2Campaign.NCO: { - SC2Mission.THE_ESCAPE.mission_name: MissionInfo(SC2Mission.THE_ESCAPE, [], SC2Mission.THE_ESCAPE.area, completion_critical=True), - SC2Mission.SUDDEN_STRIKE.mission_name: MissionInfo(SC2Mission.SUDDEN_STRIKE, [MissionConnection(1, SC2Campaign.NCO)], SC2Mission.SUDDEN_STRIKE.area, completion_critical=True), - SC2Mission.ENEMY_INTELLIGENCE.mission_name: MissionInfo(SC2Mission.ENEMY_INTELLIGENCE, [MissionConnection(2, SC2Campaign.NCO)], SC2Mission.ENEMY_INTELLIGENCE.area, completion_critical=True), - SC2Mission.TROUBLE_IN_PARADISE.mission_name: MissionInfo(SC2Mission.TROUBLE_IN_PARADISE, [MissionConnection(3, SC2Campaign.NCO)], SC2Mission.TROUBLE_IN_PARADISE.area, completion_critical=True), - SC2Mission.NIGHT_TERRORS.mission_name: MissionInfo(SC2Mission.NIGHT_TERRORS, [MissionConnection(4, SC2Campaign.NCO)], SC2Mission.NIGHT_TERRORS.area, completion_critical=True), - SC2Mission.FLASHPOINT.mission_name: MissionInfo(SC2Mission.FLASHPOINT, [MissionConnection(5, SC2Campaign.NCO)], SC2Mission.FLASHPOINT.area, completion_critical=True), - SC2Mission.IN_THE_ENEMY_S_SHADOW.mission_name: MissionInfo(SC2Mission.IN_THE_ENEMY_S_SHADOW, [MissionConnection(6, SC2Campaign.NCO)], SC2Mission.IN_THE_ENEMY_S_SHADOW.area, completion_critical=True), - SC2Mission.DARK_SKIES.mission_name: MissionInfo(SC2Mission.DARK_SKIES, [MissionConnection(7, SC2Campaign.NCO)], SC2Mission.DARK_SKIES.area, completion_critical=True), - SC2Mission.END_GAME.mission_name: MissionInfo(SC2Mission.END_GAME, [MissionConnection(8, SC2Campaign.NCO)], SC2Mission.END_GAME.area, completion_critical=True), - } -} lookup_id_to_mission: Dict[int, SC2Mission] = { mission.id: mission for mission in SC2Mission diff --git a/worlds/sc2/options.py b/worlds/sc2/options.py index 792f23578af2..cc9cf000a599 100644 --- a/worlds/sc2/options.py +++ b/worlds/sc2/options.py @@ -7,8 +7,8 @@ from BaseClasses import PlandoOptions from .mission_tables import SC2Campaign, SC2Mission, lookup_name_to_mission, MissionPools, get_missions_with_any_flags_in_list, \ campaign_mission_table, SC2Race, MissionFlag -from .mission_orders import vanilla_shuffle_order, mini_campaign_order from .mission_groups import mission_groups, MissionGroupNames +from .mission_order.options import CustomMissionOrder if TYPE_CHECKING: from worlds.AutoWorld import World @@ -129,6 +129,7 @@ class MissionOrder(Choice): Grid: Missions are arranged into a grid. Completing a mission unlocks the adjacent missions. Corners may be omitted to make the grid more square. Complete the bottom-right mission to win. Golden Path: A required line of missions with several optional branches, similar to the Wings of Liberty campaign. Hopscotch: Missions alternate between mandatory missions and pairs of optional missions. + Custom: Uses the YAML's custom mission order option. See documentation for usage. """ display_name = "Mission Order" option_vanilla = 0 @@ -139,6 +140,7 @@ class MissionOrder(Choice): option_grid = 9 option_golden_path = 10 option_hopscotch = 11 + option_custom = 99 class MaximumCampaignSize(Range): @@ -1016,6 +1018,7 @@ class Starcraft2Options(PerGameCommonOptions): vespene_per_item: VespenePerItem starting_supply_per_item: StartingSupplyPerItem + custom_mission_order: CustomMissionOrder def get_option_value(world: Union['SC2World', None], name: str) -> Union[int, FrozenSet]: if world is None: @@ -1129,18 +1132,12 @@ def get_excluded_missions(world: 'SC2World') -> Set[SC2Mission]: return excluded_missions -campaign_depending_orders = [ +static_mission_orders = [ MissionOrder.option_vanilla, MissionOrder.option_vanilla_shuffled, MissionOrder.option_mini_campaign ] -static_mission_orders = { - MissionOrder.option_vanilla: vanilla_shuffle_order, - MissionOrder.option_vanilla_shuffled: vanilla_shuffle_order, - MissionOrder.option_mini_campaign: mini_campaign_order -} - dynamic_mission_orders = [ MissionOrder.option_golden_path, MissionOrder.option_grid, diff --git a/worlds/sc2/rules.py b/worlds/sc2/rules.py index 6d3b643a71b6..57e75c6d23de 100644 --- a/worlds/sc2/rules.py +++ b/worlds/sc2/rules.py @@ -456,10 +456,6 @@ def zealot_sentry_slayer_start(self, state: CollectionState): state.has_any({item_names.ZEALOT_WHIRLWIND, item_names.SENTRY_DOUBLE_SHIELD_RECHARGE, item_names.SLAYER_PHASE_BLINK}, self.player) ) -<<<<<<< HEAD - -======= ->>>>>>> c614949c1 (real fixes) def all_in_requirement(self, state: CollectionState): """ All-in From 43252a7e4e50cd0b2d78ac03a132400ead2fac19 Mon Sep 17 00:00:00 2001 From: SirChuckOfTheChuckles Date: Sat, 31 Aug 2024 20:58:47 -0400 Subject: [PATCH 4/4] small fix :) --- worlds/sc2/rules.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/worlds/sc2/rules.py b/worlds/sc2/rules.py index 57e75c6d23de..b91e61dfe20a 100644 --- a/worlds/sc2/rules.py +++ b/worlds/sc2/rules.py @@ -212,11 +212,12 @@ def terran_great_train_robbery_train_stopper(self, state: CollectionState) -> bo """ return ( state.has_any({item_names.SIEGE_TANK, item_names.DIAMONDBACK, item_names.MARAUDER, item_names.CYCLONE, item_names.BANSHEE}, self.player) - or self.advanced_tactics - and ( - state.has_all({item_names.REAPER, item_names.REAPER_G4_CLUSTERBOMB}, self.player) - or state.has_all({item_names.SPECTRE, item_names.SPECTRE_PSIONIC_LASH}, self.player) - or state.has_any({item_names.VULTURE, item_names.LIBERATOR}, self.player) + or (self.advanced_tactics + and ( + state.has_all({item_names.REAPER, item_names.REAPER_G4_CLUSTERBOMB}, self.player) + or state.has_all({item_names.SPECTRE, item_names.SPECTRE_PSIONIC_LASH}, self.player) + or state.has_any({item_names.VULTURE, item_names.LIBERATOR}, self.player) + ) ) )