From 89ab4aff9cd4aef8e23be76a4bbab99475fe67ee Mon Sep 17 00:00:00 2001 From: TheCondor07 Date: Fri, 19 Aug 2022 13:50:44 -0700 Subject: [PATCH] SC2: Logic changes and fixes, 6 new locations, 2 removed locations (#933) --- worlds/sc2wol/Items.py | 28 ++++---- worlds/sc2wol/Locations.py | 133 ++++++++++++++++++++++-------------- worlds/sc2wol/LogicMixin.py | 21 ++++-- worlds/sc2wol/Regions.py | 5 +- worlds/sc2wol/__init__.py | 2 +- 5 files changed, 116 insertions(+), 73 deletions(-) diff --git a/worlds/sc2wol/Items.py b/worlds/sc2wol/Items.py index 4ecff7e1..59b59bc1 100644 --- a/worlds/sc2wol/Items.py +++ b/worlds/sc2wol/Items.py @@ -49,27 +49,27 @@ item_table = { "Projectile Accelerator (Bunker)": ItemData(200 + SC2WOL_ITEM_ID_OFFSET, "Armory 1", 0), "Neosteel Bunker (Bunker)": ItemData(201 + SC2WOL_ITEM_ID_OFFSET, "Armory 1", 1), - "Titanium Housing (Missile Turret)": ItemData(202 + SC2WOL_ITEM_ID_OFFSET, "Armory 1", 2), + "Titanium Housing (Missile Turret)": ItemData(202 + SC2WOL_ITEM_ID_OFFSET, "Armory 1", 2, classification=ItemClassification.filler), "Hellstorm Batteries (Missile Turret)": ItemData(203 + SC2WOL_ITEM_ID_OFFSET, "Armory 1", 3), "Advanced Construction (SCV)": ItemData(204 + SC2WOL_ITEM_ID_OFFSET, "Armory 1", 4), "Dual-Fusion Welders (SCV)": ItemData(205 + SC2WOL_ITEM_ID_OFFSET, "Armory 1", 5), - "Fire-Suppression System (Building)": ItemData(206 + SC2WOL_ITEM_ID_OFFSET, "Armory 1", 6), + "Fire-Suppression System (Building)": ItemData(206 + SC2WOL_ITEM_ID_OFFSET, "Armory 1", 6, classification=ItemClassification.filler), "Orbital Command (Building)": ItemData(207 + SC2WOL_ITEM_ID_OFFSET, "Armory 1", 7), "Stimpack (Marine)": ItemData(208 + SC2WOL_ITEM_ID_OFFSET, "Armory 1", 8), - "Combat Shield (Marine)": ItemData(209 + SC2WOL_ITEM_ID_OFFSET, "Armory 1", 9), - "Advanced Medic Facilities (Medic)": ItemData(210 + SC2WOL_ITEM_ID_OFFSET, "Armory 1", 10), - "Stabilizer Medpacks (Medic)": ItemData(211 + SC2WOL_ITEM_ID_OFFSET, "Armory 1", 11), + "Combat Shield (Marine)": ItemData(209 + SC2WOL_ITEM_ID_OFFSET, "Armory 1", 9, classification=ItemClassification.progression), + "Advanced Medic Facilities (Medic)": ItemData(210 + SC2WOL_ITEM_ID_OFFSET, "Armory 1", 10, classification=ItemClassification.progression), + "Stabilizer Medpacks (Medic)": ItemData(211 + SC2WOL_ITEM_ID_OFFSET, "Armory 1", 11, classification=ItemClassification.progression), "Incinerator Gauntlets (Firebat)": ItemData(212 + SC2WOL_ITEM_ID_OFFSET, "Armory 1", 12, classification=ItemClassification.filler), "Juggernaut Plating (Firebat)": ItemData(213 + SC2WOL_ITEM_ID_OFFSET, "Armory 1", 13), "Concussive Shells (Marauder)": ItemData(214 + SC2WOL_ITEM_ID_OFFSET, "Armory 1", 14), "Kinetic Foam (Marauder)": ItemData(215 + SC2WOL_ITEM_ID_OFFSET, "Armory 1", 15), "U-238 Rounds (Reaper)": ItemData(216 + SC2WOL_ITEM_ID_OFFSET, "Armory 1", 16), - "G-4 Clusterbomb (Reaper)": ItemData(217 + SC2WOL_ITEM_ID_OFFSET, "Armory 1", 17, classification=ItemClassification.filler), + "G-4 Clusterbomb (Reaper)": ItemData(217 + SC2WOL_ITEM_ID_OFFSET, "Armory 1", 17, classification=ItemClassification.progression), "Twin-Linked Flamethrower (Hellion)": ItemData(300 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 0, classification=ItemClassification.filler), "Thermite Filaments (Hellion)": ItemData(301 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 1), - "Cerberus Mine (Vulture)": ItemData(302 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 2), - "Replenishable Magazine (Vulture)": ItemData(303 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 3), + "Cerberus Mine (Vulture)": ItemData(302 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 2, classification=ItemClassification.filler), + "Replenishable Magazine (Vulture)": ItemData(303 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 3, classification=ItemClassification.filler), "Multi-Lock Weapons System (Goliath)": ItemData(304 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 4), "Ares-Class Targeting System (Goliath)": ItemData(305 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 5), "Tri-Lithium Power Cell (Diamondback)": ItemData(306 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 6, classification=ItemClassification.filler), @@ -77,9 +77,9 @@ item_table = { "Maelstrom Rounds (Siege Tank)": ItemData(308 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 8), "Shaped Blast (Siege Tank)": ItemData(309 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 9), "Rapid Deployment Tube (Medivac)": ItemData(310 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 10, classification=ItemClassification.filler), - "Advanced Healing AI (Medivac)": ItemData(311 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 11), + "Advanced Healing AI (Medivac)": ItemData(311 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 11, classification=ItemClassification.filler), "Tomahawk Power Cells (Wraith)": ItemData(312 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 12, classification=ItemClassification.filler), - "Displacement Field (Wraith)": ItemData(313 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 13), + "Displacement Field (Wraith)": ItemData(313 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 13, classification=ItemClassification.filler), "Ripwave Missiles (Viking)": ItemData(314 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 14), "Phobos-Class Weapons System (Viking)": ItemData(315 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 15), "Cross-Spectrum Dampeners (Banshee)": ItemData(316 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 16, classification=ItemClassification.filler), @@ -88,7 +88,7 @@ item_table = { "Defensive Matrix (Battlecruiser)": ItemData(319 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 19, classification=ItemClassification.filler), "Ocular Implants (Ghost)": ItemData(320 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 20), "Crius Suit (Ghost)": ItemData(321 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 21), - "Psionic Lash (Spectre)": ItemData(322 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 22), + "Psionic Lash (Spectre)": ItemData(322 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 22, classification=ItemClassification.progression), "Nyx-Class Cloaking Module (Spectre)": ItemData(323 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 23), "330mm Barrage Cannon (Thor)": ItemData(324 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 24, classification=ItemClassification.filler), "Immortality Protocol (Thor)": ItemData(325 + SC2WOL_ITEM_ID_OFFSET, "Armory 2", 25, classification=ItemClassification.filler), @@ -97,12 +97,12 @@ item_table = { "Missile Turret": ItemData(401 + SC2WOL_ITEM_ID_OFFSET, "Building", 1, classification=ItemClassification.progression), "Sensor Tower": ItemData(402 + SC2WOL_ITEM_ID_OFFSET, "Building", 2), - "War Pigs": ItemData(500 + SC2WOL_ITEM_ID_OFFSET, "Mercenary", 0), + "War Pigs": ItemData(500 + SC2WOL_ITEM_ID_OFFSET, "Mercenary", 0, classification=ItemClassification.progression), "Devil Dogs": ItemData(501 + SC2WOL_ITEM_ID_OFFSET, "Mercenary", 1, classification=ItemClassification.filler), "Hammer Securities": ItemData(502 + SC2WOL_ITEM_ID_OFFSET, "Mercenary", 2), - "Spartan Company": ItemData(503 + SC2WOL_ITEM_ID_OFFSET, "Mercenary", 3), + "Spartan Company": ItemData(503 + SC2WOL_ITEM_ID_OFFSET, "Mercenary", 3, classification=ItemClassification.progression), "Siege Breakers": ItemData(504 + SC2WOL_ITEM_ID_OFFSET, "Mercenary", 4), - "Hel's Angel": ItemData(505 + SC2WOL_ITEM_ID_OFFSET, "Mercenary", 5), + "Hel's Angel": ItemData(505 + SC2WOL_ITEM_ID_OFFSET, "Mercenary", 5, classification=ItemClassification.progression), "Dusk Wings": ItemData(506 + SC2WOL_ITEM_ID_OFFSET, "Mercenary", 6), "Jackson's Revenge": ItemData(507 + SC2WOL_ITEM_ID_OFFSET, "Mercenary", 7), diff --git a/worlds/sc2wol/Locations.py b/worlds/sc2wol/Locations.py index 92dfb033..3425dc71 100644 --- a/worlds/sc2wol/Locations.py +++ b/worlds/sc2wol/Locations.py @@ -44,7 +44,7 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L LocationData("Zero Hour", "Beat Zero Hour", None, lambda state: state._sc2wol_has_common_unit(world, player)), LocationData("Evacuation", "Evacuation: Victory", SC2WOL_LOC_ID_OFFSET + 400, - lambda state: state._sc2wol_has_mobile_anti_air(world, player)), + lambda state: state._sc2wol_has_anti_air(world, player)), LocationData("Evacuation", "Evacuation: First Chysalis", SC2WOL_LOC_ID_OFFSET + 401), LocationData("Evacuation", "Evacuation: Second Chysalis", SC2WOL_LOC_ID_OFFSET + 402, lambda state: state._sc2wol_has_common_unit(world, player)), @@ -52,7 +52,7 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L lambda state: state._sc2wol_has_common_unit(world, player)), LocationData("Evacuation", "Beat Evacuation", None, lambda state: state._sc2wol_has_common_unit(world, player) and - state._sc2wol_has_mobile_anti_air(world, player)), + state._sc2wol_has_competent_anti_air(world, player)), LocationData("Outbreak", "Outbreak: Victory", SC2WOL_LOC_ID_OFFSET + 500, lambda state: state._sc2wol_has_common_unit(world, player) or state.has("Reaper", player)), LocationData("Outbreak", "Outbreak: Left Infestor", SC2WOL_LOC_ID_OFFSET + 501, @@ -63,19 +63,37 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L lambda state: state._sc2wol_has_common_unit(world, player) or state.has("Reaper", player)), LocationData("Safe Haven", "Safe Haven: Victory", SC2WOL_LOC_ID_OFFSET + 600, lambda state: state._sc2wol_has_common_unit(world, player) and - state._sc2wol_has_mobile_anti_air(world, player)), + state._sc2wol_has_competent_anti_air(world, player)), + LocationData("Safe Haven", "Safe Haven: North Nexus", SC2WOL_LOC_ID_OFFSET + 601, + lambda state: state._sc2wol_has_common_unit(world, player) and + state._sc2wol_has_competent_anti_air(world, player)), + LocationData("Safe Haven", "Safe Haven: East Nexus", SC2WOL_LOC_ID_OFFSET + 602, + lambda state: state._sc2wol_has_common_unit(world, player) and + state._sc2wol_has_competent_anti_air(world, player)), + LocationData("Safe Haven", "Safe Haven: South Nexus", SC2WOL_LOC_ID_OFFSET + 603, + lambda state: state._sc2wol_has_common_unit(world, player) and + state._sc2wol_has_competent_anti_air(world, player)), LocationData("Safe Haven", "Beat Safe Haven", None, lambda state: state._sc2wol_has_common_unit(world, player) and - state._sc2wol_has_mobile_anti_air(world, player)), + state._sc2wol_has_competent_anti_air(world, player)), LocationData("Haven's Fall", "Haven's Fall: Victory", SC2WOL_LOC_ID_OFFSET + 700, lambda state: state._sc2wol_has_common_unit(world, player) and - state._sc2wol_has_mobile_anti_air(world, player)), + state._sc2wol_has_competent_anti_air(world, player)), + LocationData("Haven's Fall", "Haven's Fall: North Hive", SC2WOL_LOC_ID_OFFSET + 701, + lambda state: state._sc2wol_has_common_unit(world, player) and + state._sc2wol_has_competent_anti_air(world, player)), + LocationData("Haven's Fall", "Haven's Fall: East Hive", SC2WOL_LOC_ID_OFFSET + 702, + lambda state: state._sc2wol_has_common_unit(world, player) and + state._sc2wol_has_competent_anti_air(world, player)), + LocationData("Haven's Fall", "Haven's Fall: South Hive", SC2WOL_LOC_ID_OFFSET + 703, + lambda state: state._sc2wol_has_common_unit(world, player) and + state._sc2wol_has_competent_anti_air(world, player)), LocationData("Haven's Fall", "Beat Haven's Fall", None, lambda state: state._sc2wol_has_common_unit(world, player) and - state._sc2wol_has_mobile_anti_air(world, player)), + state._sc2wol_has_competent_anti_air(world, player)), LocationData("Smash and Grab", "Smash and Grab: Victory", SC2WOL_LOC_ID_OFFSET + 800, lambda state: state._sc2wol_has_common_unit(world, player) and - state._sc2wol_has_mobile_anti_air(world, player)), + state._sc2wol_has_competent_anti_air(world, player)), LocationData("Smash and Grab", "Smash and Grab: First Relic", SC2WOL_LOC_ID_OFFSET + 801), LocationData("Smash and Grab", "Smash and Grab: Second Relic", SC2WOL_LOC_ID_OFFSET + 802), LocationData("Smash and Grab", "Smash and Grab: Third Relic", SC2WOL_LOC_ID_OFFSET + 803, @@ -101,11 +119,7 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L state._sc2wol_has_anti_air(world, player) and state._sc2wol_has_heavy_defense(world, player)), LocationData("The Moebius Factor", "The Moebius Factor: Victory", SC2WOL_LOC_ID_OFFSET + 1000, - lambda state: state._sc2wol_has_air(world, player)), - LocationData("The Moebius Factor", "The Moebius Factor: 1st Data Core ", SC2WOL_LOC_ID_OFFSET + 1001, - lambda state: True), - LocationData("The Moebius Factor", "The Moebius Factor: 2nd Data Core", SC2WOL_LOC_ID_OFFSET + 1002, - lambda state: state._sc2wol_has_air(world, player)), + lambda state: state._sc2wol_has_air(world, player) and state._sc2wol_has_anti_air(world, player)), LocationData("The Moebius Factor", "The Moebius Factor: South Rescue", SC2WOL_LOC_ID_OFFSET + 1003, lambda state: state._sc2wol_able_to_rescue(world, player)), LocationData("The Moebius Factor", "The Moebius Factor: Wall Rescue", SC2WOL_LOC_ID_OFFSET + 1004, @@ -121,33 +135,46 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L LocationData("The Moebius Factor", "Beat The Moebius Factor", None, lambda state: state._sc2wol_has_air(world, player)), LocationData("Supernova", "Supernova: Victory", SC2WOL_LOC_ID_OFFSET + 1100, - lambda state: state._sc2wol_has_common_unit(world, player)), + lambda state: state._sc2wol_beats_protoss_deathball(world, player)), LocationData("Supernova", "Supernova: West Relic", SC2WOL_LOC_ID_OFFSET + 1101), - LocationData("Supernova", "Supernova: North Relic", SC2WOL_LOC_ID_OFFSET + 1102, - lambda state: state._sc2wol_has_common_unit(world, player)), + LocationData("Supernova", "Supernova: North Relic", SC2WOL_LOC_ID_OFFSET + 1102), LocationData("Supernova", "Supernova: South Relic", SC2WOL_LOC_ID_OFFSET + 1103, - lambda state: state._sc2wol_has_common_unit(world, player)), + lambda state: state._sc2wol_beats_protoss_deathball(world, player)), LocationData("Supernova", "Supernova: East Relic", SC2WOL_LOC_ID_OFFSET + 1104, - lambda state: state._sc2wol_has_common_unit(world, player)), + lambda state: state._sc2wol_beats_protoss_deathball(world, player)), LocationData("Supernova", "Beat Supernova", None, - lambda state: state._sc2wol_has_common_unit(world, player)), + lambda state: state._sc2wol_beats_protoss_deathball(world, player)), LocationData("Maw of the Void", "Maw of the Void: Victory", SC2WOL_LOC_ID_OFFSET + 1200, - lambda state: state.has('Battlecruiser', player) or state.has('Science Vessel', player) and - state._sc2wol_has_air(world, player)), + lambda state: state.has('Battlecruiser', player) or + state._sc2wol_has_air(world, player) and + state._sc2wol_has_competent_anti_air(world, player) and + state.has('Science Vessel', player)), LocationData("Maw of the Void", "Maw of the Void: Landing Zone Cleared", SC2WOL_LOC_ID_OFFSET + 1201), - LocationData("Maw of the Void", "Maw of the Void: Expansion Prisoners", SC2WOL_LOC_ID_OFFSET + 1202), + LocationData("Maw of the Void", "Maw of the Void: Expansion Prisoners", SC2WOL_LOC_ID_OFFSET + 1202, + lambda state: state.has('Battlecruiser', player) or + state._sc2wol_has_air(world, player) and + state._sc2wol_has_competent_anti_air(world, player) and + state.has('Science Vessel', player)), LocationData("Maw of the Void", "Maw of the Void: South Close Prisoners", SC2WOL_LOC_ID_OFFSET + 1203, - lambda state: state.has('Battlecruiser', player) or state.has('Science Vessel', player) and - state._sc2wol_has_air(world, player)), + lambda state: state.has('Battlecruiser', player) or + state._sc2wol_has_air(world, player) and + state._sc2wol_has_competent_anti_air(world, player) and + state.has('Science Vessel', player)), LocationData("Maw of the Void", "Maw of the Void: South Far Prisoners", SC2WOL_LOC_ID_OFFSET + 1204, - lambda state: state.has('Battlecruiser', player) or state.has('Science Vessel', player) and - state._sc2wol_has_air(world, player)), + lambda state: state.has('Battlecruiser', player) or + state._sc2wol_has_air(world, player) and + state._sc2wol_has_competent_anti_air(world, player) and + state.has('Science Vessel', player)), LocationData("Maw of the Void", "Maw of the Void: North Prisoners", SC2WOL_LOC_ID_OFFSET + 1205, - lambda state: state.has('Battlecruiser', player) or state.has('Science Vessel', player) and - state._sc2wol_has_air(world, player)), + lambda state: state.has('Battlecruiser', player) or + state._sc2wol_has_air(world, player) and + state._sc2wol_has_competent_anti_air(world, player) and + state.has('Science Vessel', player)), LocationData("Maw of the Void", "Beat Maw of the Void", None, - lambda state: state.has('Battlecruiser', player) or state.has('Science Vessel', player) and - state._sc2wol_has_air(world, player)), + lambda state: state.has('Battlecruiser', player) or + state._sc2wol_has_air(world, player) and + state._sc2wol_has_competent_anti_air(world, player) and + state.has('Science Vessel', player)), LocationData("Devil's Playground", "Devil's Playground: Victory", SC2WOL_LOC_ID_OFFSET + 1300, lambda state: state._sc2wol_has_common_unit(world, player) or state.has("Reaper", player)), LocationData("Devil's Playground", "Devil's Playground: Tosh's Miners", SC2WOL_LOC_ID_OFFSET + 1301), @@ -157,17 +184,17 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L lambda state: state._sc2wol_has_common_unit(world, player) or state.has("Reaper", player)), LocationData("Welcome to the Jungle", "Welcome to the Jungle: Victory", SC2WOL_LOC_ID_OFFSET + 1400, lambda state: state._sc2wol_has_common_unit(world, player) and - state._sc2wol_has_mobile_anti_air(world, player)), + state._sc2wol_has_competent_anti_air(world, player)), LocationData("Welcome to the Jungle", "Welcome to the Jungle: Close Relic", SC2WOL_LOC_ID_OFFSET + 1401), LocationData("Welcome to the Jungle", "Welcome to the Jungle: West Relic", SC2WOL_LOC_ID_OFFSET + 1402, lambda state: state._sc2wol_has_common_unit(world, player) and - state._sc2wol_has_mobile_anti_air(world, player)), + state._sc2wol_has_competent_anti_air(world, player)), LocationData("Welcome to the Jungle", "Welcome to the Jungle: North-East Relic", SC2WOL_LOC_ID_OFFSET + 1403, lambda state: state._sc2wol_has_common_unit(world, player) and - state._sc2wol_has_mobile_anti_air(world, player)), + state._sc2wol_has_competent_anti_air(world, player)), LocationData("Welcome to the Jungle", "Beat Welcome to the Jungle", None, lambda state: state._sc2wol_has_common_unit(world, player) and - state._sc2wol_has_mobile_anti_air(world, player)), + state._sc2wol_has_competent_anti_air(world, player)), LocationData("Breakout", "Breakout: Victory", SC2WOL_LOC_ID_OFFSET + 1500), LocationData("Breakout", "Breakout: Diamondback Prison", SC2WOL_LOC_ID_OFFSET + 1501), LocationData("Breakout", "Breakout: Siegetank Prison", SC2WOL_LOC_ID_OFFSET + 1502), @@ -180,7 +207,8 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L LocationData("Ghost of a Chance", "Ghost of a Chance: Third Island Spectres", SC2WOL_LOC_ID_OFFSET + 1605), LocationData("Ghost of a Chance", "Beat Ghost of a Chance", None), LocationData("The Great Train Robbery", "The Great Train Robbery: Victory", SC2WOL_LOC_ID_OFFSET + 1700, - lambda state: state._sc2wol_has_train_killers(world, player)), + lambda state: state._sc2wol_has_train_killers(world, player) and + state._sc2wol_has_anti_air(world, player)), LocationData("The Great Train Robbery", "The Great Train Robbery: North Defiler", SC2WOL_LOC_ID_OFFSET + 1701), LocationData("The Great Train Robbery", "The Great Train Robbery: Mid Defiler", SC2WOL_LOC_ID_OFFSET + 1702), LocationData("The Great Train Robbery", "The Great Train Robbery: South Defiler", SC2WOL_LOC_ID_OFFSET + 1703), @@ -198,20 +226,20 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L LocationData("Cutthroat", "Beat Cutthroat", None, lambda state: state._sc2wol_has_common_unit(world, player)), LocationData("Engine of Destruction", "Engine of Destruction: Victory", SC2WOL_LOC_ID_OFFSET + 1900, - lambda state: state._sc2wol_has_mobile_anti_air(world, player)), + lambda state: state._sc2wol_has_competent_anti_air(world, player)), LocationData("Engine of Destruction", "Engine of Destruction: Odin", SC2WOL_LOC_ID_OFFSET + 1901), LocationData("Engine of Destruction", "Engine of Destruction: Loki", SC2WOL_LOC_ID_OFFSET + 1902, - lambda state: state._sc2wol_has_mobile_anti_air(world, player) and + lambda state: state._sc2wol_has_competent_anti_air(world, player) and state._sc2wol_has_common_unit(world, player) or state.has('Wraith', player)), LocationData("Engine of Destruction", "Engine of Destruction: Lab Devourer", SC2WOL_LOC_ID_OFFSET + 1903), LocationData("Engine of Destruction", "Engine of Destruction: North Devourer", SC2WOL_LOC_ID_OFFSET + 1904, - lambda state: state._sc2wol_has_mobile_anti_air(world, player) and + lambda state: state._sc2wol_has_competent_anti_air(world, player) and state._sc2wol_has_common_unit(world, player) or state.has('Wraith', player)), LocationData("Engine of Destruction", "Engine of Destruction: Southeast Devourer", SC2WOL_LOC_ID_OFFSET + 1905, - lambda state: state._sc2wol_has_mobile_anti_air(world, player) and + lambda state: state._sc2wol_has_competent_anti_air(world, player) and state._sc2wol_has_common_unit(world, player) or state.has('Wraith', player)), LocationData("Engine of Destruction", "Beat Engine of Destruction", None, - lambda state: state._sc2wol_has_mobile_anti_air(world, player) and + lambda state: state._sc2wol_has_competent_anti_air(world, player) and state._sc2wol_has_common_unit(world, player) or state.has('Wraith', player)), LocationData("Media Blitz", "Media Blitz: Victory", SC2WOL_LOC_ID_OFFSET + 2000, lambda state: state._sc2wol_has_competent_comp(world, player)), @@ -224,13 +252,19 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L LocationData("Media Blitz", "Media Blitz: Science Facility", SC2WOL_LOC_ID_OFFSET + 2004), LocationData("Media Blitz", "Beat Media Blitz", None, lambda state: state._sc2wol_has_competent_comp(world, player)), - LocationData("Piercing the Shroud", "Piercing the Shroud: Victory", SC2WOL_LOC_ID_OFFSET + 2100), + LocationData("Piercing the Shroud", "Piercing the Shroud: Victory", SC2WOL_LOC_ID_OFFSET + 2100, + lambda state: state.has_any({'Combat Shield (Marine)', 'Stabilizer Medpacks (Medic)'}, player)), LocationData("Piercing the Shroud", "Piercing the Shroud: Holding Cell Relic", SC2WOL_LOC_ID_OFFSET + 2101), - LocationData("Piercing the Shroud", "Piercing the Shroud: Brutalisk Relic", SC2WOL_LOC_ID_OFFSET + 2102), - LocationData("Piercing the Shroud", "Piercing the Shroud: First Escape Relic", SC2WOL_LOC_ID_OFFSET + 2103), - LocationData("Piercing the Shroud", "Piercing the Shroud: Second Escape Relic", SC2WOL_LOC_ID_OFFSET + 2104), - LocationData("Piercing the Shroud", "Piercing the Shroud: Brutalisk ", SC2WOL_LOC_ID_OFFSET + 2105), - LocationData("Piercing the Shroud", "Beat Piercing the Shroud", None), + LocationData("Piercing the Shroud", "Piercing the Shroud: Brutalisk Relic", SC2WOL_LOC_ID_OFFSET + 2102, + lambda state: state.has_any({'Combat Shield (Marine)', 'Stabilizer Medpacks (Medic)'}, player)), + LocationData("Piercing the Shroud", "Piercing the Shroud: First Escape Relic", SC2WOL_LOC_ID_OFFSET + 2103, + lambda state: state.has_any({'Combat Shield (Marine)', 'Stabilizer Medpacks (Medic)'}, player)), + LocationData("Piercing the Shroud", "Piercing the Shroud: Second Escape Relic", SC2WOL_LOC_ID_OFFSET + 2104, + lambda state: state.has_any({'Combat Shield (Marine)', 'Stabilizer Medpacks (Medic)'}, player)), + LocationData("Piercing the Shroud", "Piercing the Shroud: Brutalisk ", SC2WOL_LOC_ID_OFFSET + 2105, + lambda state: state.has_any({'Combat Shield (Marine)', 'Stabilizer Medpacks (Medic)'}, player)), + LocationData("Piercing the Shroud", "Beat Piercing the Shroud", None, + lambda state: state.has_any({'Combat Shield (Marine)', 'Stabilizer Medpacks (Medic)'}, player)), LocationData("Whispers of Doom", "Whispers of Doom: Victory", SC2WOL_LOC_ID_OFFSET + 2200), LocationData("Whispers of Doom", "Whispers of Doom: First Hatchery", SC2WOL_LOC_ID_OFFSET + 2201), LocationData("Whispers of Doom", "Whispers of Doom: Second Hatchery", SC2WOL_LOC_ID_OFFSET + 2202), @@ -251,13 +285,12 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L lambda state: state._sc2wol_has_protoss_common_units(world, player)), LocationData("Echoes of the Future", "Beat Echoes of the Future", None, lambda state: state._sc2wol_has_protoss_medium_units(world, player)), - LocationData("In Utter Darkness", "In Utter Darkness: Defeat", SC2WOL_LOC_ID_OFFSET + 2500, - lambda state: state._sc2wol_has_protoss_medium_units(world, player)), + LocationData("In Utter Darkness", "In Utter Darkness: Defeat", SC2WOL_LOC_ID_OFFSET + 2500), LocationData("In Utter Darkness", "In Utter Darkness: Protoss Archive", SC2WOL_LOC_ID_OFFSET + 2501, lambda state: state._sc2wol_has_protoss_medium_units(world, player)), - LocationData("In Utter Darkness", "In Utter Darkness: Kills", SC2WOL_LOC_ID_OFFSET + 2502), - LocationData("In Utter Darkness", "Beat In Utter Darkness", None, - lambda state: state._sc2wol_has_protoss_medium_units(world, player)), + LocationData("In Utter Darkness", "In Utter Darkness: Kills", SC2WOL_LOC_ID_OFFSET + 2502, + lambda state: state._sc2wol_has_protoss_common_units(world, player)), + LocationData("In Utter Darkness", "Beat In Utter Darkness", None), LocationData("Gates of Hell", "Gates of Hell: Victory", SC2WOL_LOC_ID_OFFSET + 2600, lambda state: state._sc2wol_has_competent_comp(world, player)), LocationData("Gates of Hell", "Gates of Hell: Large Army", SC2WOL_LOC_ID_OFFSET + 2601, diff --git a/worlds/sc2wol/LogicMixin.py b/worlds/sc2wol/LogicMixin.py index baf77dc6..7a081426 100644 --- a/worlds/sc2wol/LogicMixin.py +++ b/worlds/sc2wol/LogicMixin.py @@ -10,16 +10,17 @@ class SC2WoLLogic(LogicMixin): return self.has_any({'Marine', 'Marauder'}, player) def _sc2wol_has_air(self, world: MultiWorld, player: int) -> bool: - return self.has_any({'Viking', 'Wraith', 'Medivac', 'Banshee', 'Hercules'}, player) + return self.has_any({'Viking', 'Wraith', 'Banshee'}, player) or \ + self.has_any({'Hercules', 'Medivac'}, player) and self._sc2wol_has_common_unit(world, player) def _sc2wol_has_air_anti_air(self, world: MultiWorld, player: int) -> bool: return self.has_any({'Viking', 'Wraith'}, player) - def _sc2wol_has_mobile_anti_air(self, world: MultiWorld, player: int) -> bool: + def _sc2wol_has_competent_anti_air(self, world: MultiWorld, player: int) -> bool: return self.has_any({'Marine', 'Goliath'}, player) or self._sc2wol_has_air_anti_air(world, player) def _sc2wol_has_anti_air(self, world: MultiWorld, player: int) -> bool: - return self.has('Missile Turret', player) or self._sc2wol_has_mobile_anti_air(world, player) + return self.has_any({'Missile Turret', 'Thor', 'War Pigs', 'Spartan Company', "Hel's Angel", 'Battlecruiser'}, player) or self._sc2wol_has_competent_anti_air(world, player) def _sc2wol_has_heavy_defense(self, world: MultiWorld, player: int) -> bool: return (self.has_any({'Siege Tank', 'Vulture'}, player) or @@ -28,13 +29,15 @@ class SC2WoLLogic(LogicMixin): def _sc2wol_has_competent_comp(self, world: MultiWorld, player: int) -> bool: return (self.has('Marine', player) or self.has('Marauder', player) and - self._sc2wol_has_mobile_anti_air(world, player)) and self.has_any({'Medivac', 'Medic'}, player) or \ - self.has('Thor', player) or self.has("Banshee", player) and self._sc2wol_has_mobile_anti_air(world, player) or \ - self.has('Battlecruiser', player) and self._sc2wol_has_common_unit(world, player) + self._sc2wol_has_competent_anti_air(world, player)) and self.has_any({'Medivac', 'Medic'}, player) or \ + self.has('Thor', player) or self.has("Banshee", player) and self._sc2wol_has_competent_anti_air(world, player) or \ + self.has('Battlecruiser', player) and self._sc2wol_has_common_unit(world, player) or \ + self.has('Siege Tank', player) and self._sc2wol_has_competent_anti_air(world, player) def _sc2wol_has_train_killers(self, world: MultiWorld, player: int) -> bool: return (self.has_any({'Siege Tank', 'Diamondback'}, player) or - self.has_all({'Reaper', "G-4 Clusterbomb"}, player) or self.has_all({'Spectre', 'Psionic Lash'}, player)) + self.has_all({'Reaper', "G-4 Clusterbomb"}, player) or self.has_all({'Spectre', 'Psionic Lash'}, player) + or self.has('Marauders', player)) def _sc2wol_able_to_rescue(self, world: MultiWorld, player: int) -> bool: return self.has_any({'Medivac', 'Hercules', 'Raven', 'Viking'}, player) @@ -46,6 +49,10 @@ class SC2WoLLogic(LogicMixin): return self._sc2wol_has_protoss_common_units(world, player) and \ self.has_any({'Stalker', 'Void Ray', 'Phoenix', 'Carrier'}, player) + def _sc2wol_beats_protoss_deathball(self, world: MultiWorld, player: int) -> bool: + return self.has_any({'Banshee', 'Battlecruiser'}, player) and self._sc2wol_has_competent_anti_air or \ + self._sc2wol_has_competent_comp(world, player) and self._sc2wol_has_air_anti_air(world, player) + def _sc2wol_cleared_missions(self, world: MultiWorld, player: int, mission_count: int) -> bool: return self.has_group("Missions", player, mission_count) diff --git a/worlds/sc2wol/Regions.py b/worlds/sc2wol/Regions.py index 3a00b604..4e207529 100644 --- a/worlds/sc2wol/Regions.py +++ b/worlds/sc2wol/Regions.py @@ -200,7 +200,10 @@ def create_regions(world: MultiWorld, player: int, locations: Tuple[LocationData connect(world, player, names, "Menu", missions[i]) else: connect(world, player, names, missions[connection], missions[i], - (lambda name: (lambda state: state.has(f"Beat {name}", player)))(missions[connection])) + (lambda name, missions_req: (lambda state: state.has(f"Beat {name}", player) and + state._sc2wol_cleared_missions(world, player, + missions_req))) + (missions[connection], vanilla_shuffle_order[i].number)) connections.append(connection + 1) mission_req_table.update({missions[i]: MissionInfo( diff --git a/worlds/sc2wol/__init__.py b/worlds/sc2wol/__init__.py index 33522569..cf3175bd 100644 --- a/worlds/sc2wol/__init__.py +++ b/worlds/sc2wol/__init__.py @@ -33,7 +33,7 @@ class SC2WoLWorld(World): game = "Starcraft 2 Wings of Liberty" web = Starcraft2WoLWebWorld() - data_version = 2 + data_version = 3 item_name_to_id = {name: data.code for name, data in item_table.items()} location_name_to_id = {location.name: location.code for location in get_locations(None, None)}