From d682e72bd8589bbaf666961a60265e596caeec51 Mon Sep 17 00:00:00 2001 From: MadiMadsen <137329235+MadiMadsen@users.noreply.github.com> Date: Fri, 2 Feb 2024 14:32:33 -0600 Subject: [PATCH 1/2] Change LOTV to not Require LOTV Prologue to be completed to start Change logic of mission requirements to fit in line with Base LOTV where prologue is completely optional to do instead of mandatory. allows for more mission variety at the start of a seed which will make it easier for players to progress. (Also doing 6 mission in a row to get to shakuras/korhal felt bad) --- worlds/sc2/MissionTables.py | 22 +++++++++++----------- worlds/sc2/Regions.py | 9 +-------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/worlds/sc2/MissionTables.py b/worlds/sc2/MissionTables.py index 90c46440d223..58e3d3403919 100644 --- a/worlds/sc2/MissionTables.py +++ b/worlds/sc2/MissionTables.py @@ -263,12 +263,12 @@ def vanilla_shuffle_order() -> Dict[SC2Campaign, List[FillMission]]: FillMission(MissionPools.FINAL, [MissionConnection(18, SC2Campaign.HOTS)], "Korhal", completion_critical=True), ], SC2Campaign.PROLOGUE: [ - FillMission(MissionPools.STARTER, [MissionConnection(-1, SC2Campaign.PROLOGUE)], "_1", completion_critical=True), - FillMission(MissionPools.MEDIUM, [MissionConnection(0, SC2Campaign.PROLOGUE)], "_2", completion_critical=True, removal_priority=1), - FillMission(MissionPools.FINAL, [MissionConnection(1, SC2Campaign.PROLOGUE)], "_3", completion_critical=True) + FillMission(MissionPools.STARTER, [MissionConnection(-1, SC2Campaign.PROLOGUE)], "_1"), + FillMission(MissionPools.MEDIUM, [MissionConnection(0, SC2Campaign.PROLOGUE)], "_2", removal_priority=1), + FillMission(MissionPools.FINAL, [MissionConnection(1, SC2Campaign.PROLOGUE)], "_3") ], SC2Campaign.LOTV: [ - FillMission(MissionPools.STARTER, [MissionConnection(2, SC2Campaign.PROLOGUE)], "Aiur", completion_critical=True), + FillMission(MissionPools.STARTER, [MissionConnection(-1, SC2Campaign.LOTV)], "Aiur", completion_critical=True), FillMission(MissionPools.EASY, [MissionConnection(0, SC2Campaign.LOTV)], "Aiur", completion_critical=True, removal_priority=3), FillMission(MissionPools.EASY, [MissionConnection(1, SC2Campaign.LOTV)], "Aiur", completion_critical=True), FillMission(MissionPools.MEDIUM, [MissionConnection(2, SC2Campaign.LOTV)], "Korhal", completion_critical=True), @@ -344,11 +344,11 @@ def mini_campaign_order() -> Dict[SC2Campaign, List[FillMission]]: FillMission(MissionPools.FINAL, [MissionConnection(11, SC2Campaign.HOTS)], "Korhal", completion_critical=True), ], SC2Campaign.PROLOGUE: [ - FillMission(MissionPools.EASY, [MissionConnection(-1, SC2Campaign.PROLOGUE)], "_1", completion_critical=True), - FillMission(MissionPools.FINAL, [MissionConnection(0, SC2Campaign.PROLOGUE)], "_2", completion_critical=True) + FillMission(MissionPools.EASY, [MissionConnection(-1, SC2Campaign.PROLOGUE)], "_1"), + FillMission(MissionPools.FINAL, [MissionConnection(0, SC2Campaign.PROLOGUE)], "_2") ], SC2Campaign.LOTV: [ - FillMission(MissionPools.STARTER, [MissionConnection(1, SC2Campaign.PROLOGUE)], "Aiur", completion_critical=True), + FillMission(MissionPools.STARTER, [MissionConnection(-1, SC2Campaign.LOTV)], "Aiur",completion_critical=True), FillMission(MissionPools.EASY, [MissionConnection(0, SC2Campaign.LOTV)], "Aiur", completion_critical=True), FillMission(MissionPools.EASY, [MissionConnection(1, SC2Campaign.LOTV)], "Korhal", completion_critical=True), FillMission(MissionPools.MEDIUM, [MissionConnection(1, SC2Campaign.LOTV)], "Shakuras", completion_critical=True), @@ -534,12 +534,12 @@ def blitz_order() -> Dict[SC2Campaign, List[FillMission]]: 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, completion_critical=True), - SC2Mission.GHOSTS_IN_THE_FOG.mission_name: MissionInfo(SC2Mission.GHOSTS_IN_THE_FOG, [MissionConnection(1, SC2Campaign.PROLOGUE)], SC2Mission.GHOSTS_IN_THE_FOG.area, completion_critical=True), - SC2Mission.EVIL_AWOKEN.mission_name: MissionInfo(SC2Mission.EVIL_AWOKEN, [MissionConnection(2, SC2Campaign.PROLOGUE)], SC2Mission.EVIL_AWOKEN.area, completion_critical=True) + 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, [MissionConnection(3, SC2Campaign.PROLOGUE)], SC2Mission.FOR_AIUR.area, completion_critical=True), + 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), diff --git a/worlds/sc2/Regions.py b/worlds/sc2/Regions.py index 500c5363fe04..4db5d69d5c63 100644 --- a/worlds/sc2/Regions.py +++ b/worlds/sc2/Regions.py @@ -183,14 +183,7 @@ def wol_cleared_missions(state: CollectionState, mission_count: int) -> bool: lambda state: state.has("Beat Ghosts in the Fog", player)) if SC2Campaign.LOTV in enabled_campaigns: - if SC2Campaign.PROLOGUE in enabled_campaigns: - connect(multiworld, player, names, "Evil Awoken", "For Aiur!", - lambda state: state.has("Beat Evil Awoken", player)) - else: - vanilla_mission_reqs[SC2Campaign.LOTV] = vanilla_mission_reqs[SC2Campaign.LOTV].copy() - vanilla_mission_reqs[SC2Campaign.LOTV][SC2Mission.FOR_AIUR.mission_name] = MissionInfo( - SC2Mission.FOR_AIUR, [], SC2Mission.FOR_AIUR.area) - connect(multiworld, player, names, "Menu", "For Aiur!") + connect(multiworld, player, names, "Menu", "For Aiur!") connect(multiworld, player, names, "For Aiur!", "The Growing Shadow", lambda state: state.has("Beat For Aiur!", player)), connect(multiworld, player, names, "The Growing Shadow", "The Spear of Adun", From fb13c9a40ab16bbb8754b0195a66e5f8209c1883 Mon Sep 17 00:00:00 2001 From: Salzkorn Date: Sat, 3 Feb 2024 11:36:28 +0100 Subject: [PATCH 2/2] Generation: Add reusable items to second pass item placement --- worlds/sc2/PoolFilter.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/worlds/sc2/PoolFilter.py b/worlds/sc2/PoolFilter.py index 33420594563b..f780f82b984b 100644 --- a/worlds/sc2/PoolFilter.py +++ b/worlds/sc2/PoolFilter.py @@ -274,7 +274,7 @@ def attempt_removal(item: Item) -> bool: unit_nb_upgrades = {} for item in inventory: cItem = item_list[item.name] - if cItem.type in UPGRADABLE_ITEMS and item.name not in unit_avail_upgrades: + if cItem.parent_item in UPGRADABLE_ITEMS and item.name not in unit_avail_upgrades: unit_avail_upgrades[item.name] = [] unit_nb_upgrades[item.name] = 0 elif cItem.parent_item is not None: @@ -287,7 +287,7 @@ def attempt_removal(item: Item) -> bool: # For those two categories, we count them but dont include them in removal for item in locked_items + self.existing_items: cItem = item_list[item.name] - if cItem.type in UPGRADABLE_ITEMS and item.name not in unit_avail_upgrades: + if cItem.parent_item in UPGRADABLE_ITEMS and item.name not in unit_avail_upgrades: unit_avail_upgrades[item.name] = [] unit_nb_upgrades[item.name] = 0 elif cItem.parent_item is not None: @@ -346,6 +346,7 @@ def attempt_removal(item: Item) -> bool: removable_generic_items.append(item) # Main cull process + unused_items = [] # Reusable items for the second pass while len(inventory) + len(locked_items) > inventory_size: if len(inventory) == 0: # There are more items than locations and all of them are already locked due to YAML or logic. @@ -389,7 +390,9 @@ def attempt_removal(item: Item) -> bool: continue attempt_removal(item_to_remove) else: - attempt_removal(item) + # Unimportant upgrades may be added again in the second pass + if attempt_removal(item): + unused_items.append(item.name) # Removing extra dependencies # WoL @@ -475,7 +478,9 @@ def attempt_removal(item: Item) -> bool: replacement_items = [item for item in self.item_pool if (item not in inventory and item not in self.locked_items - and item.name in second_pass_placeable_items)] + and ( + item.name in second_pass_placeable_items + or item.name in unused_items))] self.multiworld.random.shuffle(replacement_items) while len(inventory) < inventory_size and len(replacement_items) > 0: item = replacement_items.pop()