Skip to content

Commit

Permalink
Add an option to exclude Very Hard missions. Cleaned up some option d…
Browse files Browse the repository at this point in the history
…ocumentation
  • Loading branch information
Ziktofel committed Jan 21, 2024
1 parent f933c0e commit d344228
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 23 deletions.
83 changes: 76 additions & 7 deletions worlds/sc2/Options.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from dataclasses import dataclass, fields, Field
from typing import Dict, FrozenSet, Union, Set
from typing import FrozenSet, Union, Set

from BaseClasses import MultiWorld
from Options import Choice, Option, Toggle, DefaultOnToggle, ItemSet, OptionSet, Range, PerGameCommonOptions
from .MissionTables import SC2Campaign, SC2Mission
from Options import Choice, Toggle, DefaultOnToggle, ItemSet, OptionSet, Range, PerGameCommonOptions
from .MissionTables import SC2Campaign, SC2Mission, lookup_name_to_mission, MissionPools, get_no_build_missions, \
campaign_mission_table


class GameDifficulty(Choice):
Expand All @@ -19,6 +21,7 @@ class GameDifficulty(Choice):
option_brutal = 3
default = 1


class GameSpeed(Choice):
"""Optional setting to override difficulty-based game speed."""
display_name = "Game Speed"
Expand All @@ -30,6 +33,7 @@ class GameSpeed(Choice):
option_faster = 5
default = option_default


class DisableForcedCamera(Toggle):
"""
Prevents the game from moving or locking the camera without the player's consent.
Expand All @@ -43,8 +47,9 @@ class SkipCutscenes(Toggle):
"""
display_name = "Skip Cutscenes"


class AllInMap(Choice):
"""Determines what version of All-In (final map) that will be generated for the campaign."""
"""Determines what version of All-In (WoL final map) that will be generated for the campaign."""
display_name = "All In Map"
option_ground = 0
option_air = 1
Expand All @@ -53,9 +58,9 @@ class AllInMap(Choice):
class MissionOrder(Choice):
"""
Determines the order the missions are played in. The last three mission orders end in a random mission.
Vanilla (29): Keeps the standard mission order and branching from the WoL Campaign.
Vanilla Shuffled (29): Keeps same branching paths from the WoL Campaign but randomizes the order of missions within.
Mini Campaign (15): Shorter version of the campaign with randomized missions and optional branches.
Vanilla (83 total if all campaigns enabled): Keeps the standard mission order and branching from the vanilla Campaigns.
Vanilla Shuffled (83 total if all campaigns enabled): Keeps same branching paths from the vanilla Campaigns but randomizes the order of missions within.
Mini Campaign (47 total if all campaigns enabled): Shorter version of the campaign with randomized missions and optional branches.
Medium Grid (16): A 4x4 grid of random missions. Start at the top-left and forge a path towards bottom-right mission to win.
Mini Grid (9): A 3x3 version of Grid. Complete the bottom-right mission to win.
Blitz (12): 12 random missions that open up very quickly. Complete the bottom-right mission to win.
Expand Down Expand Up @@ -177,6 +182,11 @@ class EnableLotVMissions(DefaultOnToggle):
class EnableEpilogueMissions(DefaultOnToggle):
"""
Enables missions from Epilogue campaign.
These missions are considered very hard.
Enabling Wings of Liberty, Heart of the Swarm and Legacy of the Void is strongly recommended in order to play Epilogue.
Not recommended for short mission orders.
See also: Exclude Very Hard Missions
"""
display_name = "Enable Epilogue missions"

Expand Down Expand Up @@ -321,6 +331,7 @@ class EnsureGenericItems(Range):
Mercenaries, Kerrigan levels and abilities, and Spear of Adun abilities
Increasing this percentage will make units less common.
"""
display_name = "Ensure Generic Items"
range_start = 0
range_end = 100
default = 25
Expand Down Expand Up @@ -565,6 +576,28 @@ class ExcludedMissions(OptionSet):
valid_keys = {mission.mission_name for mission in SC2Mission}


class ExcludeVeryHardMissions(Choice):
"""
Excludes Very Hard missions outside of Epilogue campaign (All-In, Salvation, and all Epilogue missions are considered Very Hard).
Doesn't apply to "Vanilla" mission order.
Default: Not excluded for mission orders "Vanilla Shuffled" or "Grid" with Maximum Campaign Size >= 20,
excluded for any other order
Yes: Non-Epilogue Very Hard missions are excluded and won't be generated
No: Non-Epilogue Very Hard missions can appear normally. Not recommended for too short mission orders.
See also: Excluded Missions, Enable Epilogue Missions, Maximum Campaign Size
"""
display_name = "Exclude Very Hard Missions"
option_default = 0
option_true = 1
option_false = 2

@classmethod
def get_option_name(cls, value):
return ["Default", "Yes", "No"][int(value)]


class LocationInclusion(Choice):
option_enabled = 0
option_resources = 1
Expand Down Expand Up @@ -643,6 +676,7 @@ class MineralsPerItem(Range):
"""
Configures how many minerals per resource item are given.
"""
display_name = "Minerals Per Item"
range_start = 0
range_end = 500
default = 25
Expand All @@ -652,6 +686,7 @@ class VespenePerItem(Range):
"""
Configures how many vespene per resource item is given.
"""
display_name = "Vespene Per Item"
range_start = 0
range_end = 500
default = 25
Expand All @@ -661,6 +696,7 @@ class StartingSupplyPerItem(Range):
"""
Configures how many starting supply per item is given.
"""
display_name = "Starting Supply Per Item"
range_start = 0
range_end = 200
default = 5
Expand Down Expand Up @@ -713,6 +749,7 @@ class Starcraft2Options(PerGameCommonOptions):
locked_items: LockedItems
excluded_items: ExcludedItems
excluded_missions: ExcludedMissions
exclude_very_hard_missions: ExcludeVeryHardMissions
nco_items: NovaCovertOpsItems
bw_items: BroodWarItems
ext_items: ExtendedItems
Expand Down Expand Up @@ -762,6 +799,38 @@ def get_disabled_campaigns(multiworld: MultiWorld, player: int) -> Set[SC2Campai
return disabled_campaigns


def get_excluded_missions(multiworld: MultiWorld, player: int) -> Set[SC2Mission]:
mission_order_type = get_option_value(multiworld, player, "mission_order")
excluded_mission_names = get_option_value(multiworld, player, "excluded_missions")
shuffle_no_build = get_option_value(multiworld, player, "shuffle_no_build")
disabled_campaigns = get_disabled_campaigns(multiworld, player)

excluded_missions: Set[SC2Mission] = set([lookup_name_to_mission[name] for name in excluded_mission_names])

# Excluding Very Hard missions depending on options
if (get_option_value(multiworld, player, "exclude_very_hard_missions") == ExcludeVeryHardMissions.option_true
) or (
get_option_value(multiworld, player, "exclude_very_hard_missions") == ExcludeVeryHardMissions.option_default
and (
mission_order_type not in [MissionOrder.option_vanilla_shuffled, MissionOrder.option_grid]
or (
mission_order_type == MissionOrder.option_grid
and get_option_value(multiworld, player, "maximum_campaign_size") < 20
)
)
):
excluded_missions.union([mission for mission in SC2Mission if
mission.pool == MissionPools.VERY_HARD and mission.campaign != SC2Campaign.EPILOGUE])
# Omitting No-Build missions if not shuffling no-build
if not shuffle_no_build:
excluded_missions = excluded_missions.union(get_no_build_missions())
# Omitting missions not in enabled campaigns
for campaign in disabled_campaigns:
excluded_missions = excluded_missions.union(campaign_mission_table[campaign])

return excluded_missions


campaign_depending_orders = [
MissionOrder.option_vanilla,
MissionOrder.option_vanilla_shuffled,
Expand Down
27 changes: 11 additions & 16 deletions worlds/sc2/PoolFilter.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from .Options import get_option_value, MissionOrder, \
get_enabled_campaigns, get_disabled_campaigns, RequiredTactics, kerrigan_unit_available, GrantStoryTech, \
TakeOverAIAllies, SpearOfAdunPresence, SpearOfAdunAutonomouslyCastAbilityPresence, campaign_depending_orders, \
ShuffleCampaigns
ShuffleCampaigns, get_excluded_missions, ExcludeVeryHardMissions, ShuffleNoBuild
from . import ItemNames

# Items with associated upgrades
Expand Down Expand Up @@ -39,10 +39,8 @@ def filter_missions(multiworld: MultiWorld, player: int) -> Dict[MissionPools, L
mission_order_type = get_option_value(multiworld, player, "mission_order")
shuffle_no_build = get_option_value(multiworld, player, "shuffle_no_build")
enabled_campaigns = get_enabled_campaigns(multiworld, player)
disabled_campaigns = get_disabled_campaigns(multiworld, player)
excluded_mission_names = get_option_value(multiworld, player, "excluded_missions")
grant_story_tech = get_option_value(multiworld, player, "grant_story_tech") == GrantStoryTech.option_true
excluded_missions: Set[SC2Mission] = set([lookup_name_to_mission[name] for name in excluded_mission_names])
excluded_missions: Set[SC2Mission] = get_excluded_missions(multiworld, player)
mission_pools: Dict[MissionPools, List[SC2Mission]] = {}
for mission in SC2Mission:
if not mission_pools.get(mission.pool):
Expand All @@ -65,12 +63,6 @@ def filter_missions(multiworld: MultiWorld, player: int) -> Dict[MissionPools, L
mission_pools[MissionPools.FINAL] = [list(campaign_alt_final_mission_locations[goal_campaign].keys())[0]]
remove_final_mission_from_other_pools(mission_pools)
return mission_pools
# Omitting No-Build missions if not shuffling no-build
if not shuffle_no_build:
excluded_missions = excluded_missions.union(get_no_build_missions())
# Omitting missions not in enabled campaigns
for campaign in disabled_campaigns:
excluded_missions = excluded_missions.union(campaign_mission_table[campaign])

# Finding the goal map
goal_priorities = {campaign: get_campaign_goal_priority(campaign, excluded_missions) for campaign in enabled_campaigns}
Expand All @@ -95,22 +87,25 @@ def filter_missions(multiworld: MultiWorld, player: int) -> Dict[MissionPools, L

# Mission pool changes
adv_tactics = get_option_value(multiworld, player, "required_tactics") != RequiredTactics.option_standard

def move_mission(mission: SC2Mission, current_pool, new_pool):
if mission in mission_pools[current_pool]:
mission_pools[current_pool].remove(mission)
mission_pools[new_pool].append(mission)
# WoL
if not get_option_value(multiworld, player, 'shuffle_no_build'):
if shuffle_no_build == ShuffleNoBuild.option_false or adv_tactics:
# Replacing No Build missions with Easy missions
move_mission(SC2Mission.ZERO_HOUR, MissionPools.EASY, MissionPools.STARTER)
move_mission(SC2Mission.EVACUATION, MissionPools.EASY, MissionPools.STARTER)
move_mission(SC2Mission.DEVILS_PLAYGROUND, MissionPools.EASY, MissionPools.STARTER)
# Pushing Outbreak to Normal, as it cannot be placed as the second mission on Build-Only
move_mission(SC2Mission.OUTBREAK, MissionPools.EASY, MissionPools.MEDIUM)
# Pushing extra Normal missions to Easy
# Pushing this to Easy
move_mission(SC2Mission.THE_GREAT_TRAIN_ROBBERY, MissionPools.MEDIUM, MissionPools.EASY)
move_mission(SC2Mission.ECHOES_OF_THE_FUTURE, MissionPools.MEDIUM, MissionPools.EASY)
move_mission(SC2Mission.CUTTHROAT, MissionPools.MEDIUM, MissionPools.EASY)
if shuffle_no_build == ShuffleNoBuild.option_false:
# Pushing Outbreak to Normal, as it cannot be placed as the second mission on Build-Only
move_mission(SC2Mission.OUTBREAK, MissionPools.EASY, MissionPools.MEDIUM)
# Pushing extra Normal missions to Easy
move_mission(SC2Mission.ECHOES_OF_THE_FUTURE, MissionPools.MEDIUM, MissionPools.EASY)
move_mission(SC2Mission.CUTTHROAT, MissionPools.MEDIUM, MissionPools.EASY)
# Additional changes on Advanced Tactics
if adv_tactics:
move_mission(SC2Mission.THE_GREAT_TRAIN_ROBBERY, MissionPools.EASY, MissionPools.STARTER)
Expand Down

0 comments on commit d344228

Please sign in to comment.