908 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			908 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|   | from dataclasses import dataclass, fields, Field | ||
|  | from typing import FrozenSet, Union, Set | ||
|  | 
 | ||
|  | 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 | ||
|  | from worlds.AutoWorld import World | ||
|  | 
 | ||
|  | 
 | ||
|  | class GameDifficulty(Choice): | ||
|  |     """
 | ||
|  |     The difficulty of the campaign, affects enemy AI, starting units, and game speed. | ||
|  | 
 | ||
|  |     For those unfamiliar with the Archipelago randomizer, the recommended settings are one difficulty level | ||
|  |     lower than the vanilla game | ||
|  |     """
 | ||
|  |     display_name = "Game Difficulty" | ||
|  |     option_casual = 0 | ||
|  |     option_normal = 1 | ||
|  |     option_hard = 2 | ||
|  |     option_brutal = 3 | ||
|  |     default = 1 | ||
|  | 
 | ||
|  | 
 | ||
|  | class GameSpeed(Choice): | ||
|  |     """Optional setting to override difficulty-based game speed.""" | ||
|  |     display_name = "Game Speed" | ||
|  |     option_default = 0 | ||
|  |     option_slower = 1 | ||
|  |     option_slow = 2 | ||
|  |     option_normal = 3 | ||
|  |     option_fast = 4 | ||
|  |     option_faster = 5 | ||
|  |     default = option_default | ||
|  | 
 | ||
|  | 
 | ||
|  | class DisableForcedCamera(Toggle): | ||
|  |     """
 | ||
|  |     Prevents the game from moving or locking the camera without the player's consent. | ||
|  |     """
 | ||
|  |     display_name = "Disable Forced Camera Movement" | ||
|  | 
 | ||
|  | 
 | ||
|  | class SkipCutscenes(Toggle): | ||
|  |     """
 | ||
|  |     Skips all cutscenes and prevents dialog from blocking progress. | ||
|  |     """
 | ||
|  |     display_name = "Skip Cutscenes" | ||
|  | 
 | ||
|  | 
 | ||
|  | class AllInMap(Choice): | ||
|  |     """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 | ||
|  | 
 | ||
|  | 
 | ||
|  | class MissionOrder(Choice): | ||
|  |     """
 | ||
|  |     Determines the order the missions are played in.  The last three mission orders end in a random mission. | ||
|  |     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. | ||
|  |     Gauntlet (7): Linear series of 7 random missions to complete the campaign. | ||
|  |     Mini Gauntlet (4): Linear series of 4 random missions to complete the campaign. | ||
|  |     Tiny Grid (4): A 2x2 version of Grid.  Complete the bottom-right mission to win. | ||
|  |     Grid (variable): A grid that will resize to use all non-excluded missions.  Corners may be omitted to make the grid more square.  Complete the bottom-right mission to win. | ||
|  |     """
 | ||
|  |     display_name = "Mission Order" | ||
|  |     option_vanilla = 0 | ||
|  |     option_vanilla_shuffled = 1 | ||
|  |     option_mini_campaign = 2 | ||
|  |     option_medium_grid = 3 | ||
|  |     option_mini_grid = 4 | ||
|  |     option_blitz = 5 | ||
|  |     option_gauntlet = 6 | ||
|  |     option_mini_gauntlet = 7 | ||
|  |     option_tiny_grid = 8 | ||
|  |     option_grid = 9 | ||
|  | 
 | ||
|  | 
 | ||
|  | class MaximumCampaignSize(Range): | ||
|  |     """
 | ||
|  |     Sets an upper bound on how many missions to include when a variable-size mission order is selected. | ||
|  |     If a set-size mission order is selected, does nothing. | ||
|  |     """
 | ||
|  |     display_name = "Maximum Campaign Size" | ||
|  |     range_start = 1 | ||
|  |     range_end = 83 | ||
|  |     default = 83 | ||
|  | 
 | ||
|  | 
 | ||
|  | class GridTwoStartPositions(Toggle): | ||
|  |     """
 | ||
|  |     If turned on and 'grid' mission order is selected, removes a mission from the starting | ||
|  |     corner sets the adjacent two missions as the starter missions. | ||
|  |     """
 | ||
|  |     display_name = "Start with two unlocked missions on grid" | ||
|  |     default = Toggle.option_false | ||
|  | 
 | ||
|  | 
 | ||
|  | class ColorChoice(Choice): | ||
|  |     option_white = 0 | ||
|  |     option_red = 1 | ||
|  |     option_blue = 2 | ||
|  |     option_teal = 3 | ||
|  |     option_purple = 4 | ||
|  |     option_yellow = 5 | ||
|  |     option_orange = 6 | ||
|  |     option_green = 7 | ||
|  |     option_light_pink = 8 | ||
|  |     option_violet = 9 | ||
|  |     option_light_grey = 10 | ||
|  |     option_dark_green = 11 | ||
|  |     option_brown = 12 | ||
|  |     option_light_green = 13 | ||
|  |     option_dark_grey = 14 | ||
|  |     option_pink = 15 | ||
|  |     option_rainbow = 16 | ||
|  |     option_default = 17 | ||
|  |     default = option_default | ||
|  | 
 | ||
|  | 
 | ||
|  | class PlayerColorTerranRaynor(ColorChoice): | ||
|  |     """Determines in-game team color for playable Raynor's Raiders (Terran) factions.""" | ||
|  |     display_name = "Terran Player Color (Raynor)" | ||
|  | 
 | ||
|  | 
 | ||
|  | class PlayerColorProtoss(ColorChoice): | ||
|  |     """Determines in-game team color for playable Protoss factions.""" | ||
|  |     display_name = "Protoss Player Color" | ||
|  | 
 | ||
|  | 
 | ||
|  | class PlayerColorZerg(ColorChoice): | ||
|  |     """Determines in-game team color for playable Zerg factions before Kerrigan becomes Primal Kerrigan.""" | ||
|  |     display_name = "Zerg Player Color" | ||
|  | 
 | ||
|  | 
 | ||
|  | class PlayerColorZergPrimal(ColorChoice): | ||
|  |     """Determines in-game team color for playable Zerg factions after Kerrigan becomes Primal Kerrigan.""" | ||
|  |     display_name = "Zerg Player Color (Primal)" | ||
|  | 
 | ||
|  | 
 | ||
|  | class EnableWolMissions(DefaultOnToggle): | ||
|  |     """
 | ||
|  |     Enables missions from main Wings of Liberty campaign. | ||
|  |     """
 | ||
|  |     display_name = "Enable Wings of Liberty missions" | ||
|  | 
 | ||
|  | 
 | ||
|  | class EnableProphecyMissions(DefaultOnToggle): | ||
|  |     """
 | ||
|  |     Enables missions from Prophecy mini-campaign. | ||
|  |     """
 | ||
|  |     display_name = "Enable Prophecy missions" | ||
|  | 
 | ||
|  | 
 | ||
|  | class EnableHotsMissions(DefaultOnToggle): | ||
|  |     """
 | ||
|  |     Enables missions from Heart of the Swarm campaign. | ||
|  |     """
 | ||
|  |     display_name = "Enable Heart of the Swarm missions" | ||
|  | 
 | ||
|  | 
 | ||
|  | class EnableLotVPrologueMissions(DefaultOnToggle): | ||
|  |     """
 | ||
|  |     Enables missions from Prologue campaign. | ||
|  |     """
 | ||
|  |     display_name = "Enable Prologue (Legacy of the Void) missions" | ||
|  | 
 | ||
|  | 
 | ||
|  | class EnableLotVMissions(DefaultOnToggle): | ||
|  |     """
 | ||
|  |     Enables missions from Legacy of the Void campaign. | ||
|  |     """
 | ||
|  |     display_name = "Enable Legacy of the Void (main campaign) missions" | ||
|  | 
 | ||
|  | 
 | ||
|  | 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" | ||
|  | 
 | ||
|  | 
 | ||
|  | class EnableNCOMissions(DefaultOnToggle): | ||
|  |     """
 | ||
|  |     Enables missions from Nova Covert Ops campaign. | ||
|  | 
 | ||
|  |     Note: For best gameplay experience it's recommended to also enable Wings of Liberty campaign. | ||
|  |     """
 | ||
|  |     display_name = "Enable Nova Covert Ops missions" | ||
|  | 
 | ||
|  | 
 | ||
|  | class ShuffleCampaigns(DefaultOnToggle): | ||
|  |     """
 | ||
|  |     Shuffles the missions between campaigns if enabled. | ||
|  |     Only available for Vanilla Shuffled and Mini Campaign mission order | ||
|  |     """
 | ||
|  |     display_name = "Shuffle Campaigns" | ||
|  | 
 | ||
|  | 
 | ||
|  | class ShuffleNoBuild(DefaultOnToggle): | ||
|  |     """
 | ||
|  |     Determines if the no-build missions are included in the shuffle. | ||
|  |     If turned off, the no-build missions will not appear. Has no effect for Vanilla mission order. | ||
|  |     """
 | ||
|  |     display_name = "Shuffle No-Build Missions" | ||
|  | 
 | ||
|  | 
 | ||
|  | class StarterUnit(Choice): | ||
|  |     """
 | ||
|  |     Unlocks a random unit at the start of the game. | ||
|  | 
 | ||
|  |     Off: No units are provided, the first unit must be obtained from the randomizer | ||
|  |     Balanced: A unit that doesn't give the player too much power early on is given | ||
|  |     Any Starter Unit: Any starter unit can be given | ||
|  |     """
 | ||
|  |     display_name = "Starter Unit" | ||
|  |     option_off = 0 | ||
|  |     option_balanced = 1 | ||
|  |     option_any_starter_unit = 2 | ||
|  | 
 | ||
|  | 
 | ||
|  | class RequiredTactics(Choice): | ||
|  |     """
 | ||
|  |     Determines the maximum tactical difficulty of the world (separate from mission difficulty).  Higher settings | ||
|  |     increase randomness. | ||
|  | 
 | ||
|  |     Standard:  All missions can be completed with good micro and macro. | ||
|  |     Advanced:  Completing missions may require relying on starting units and micro-heavy units. | ||
|  |     No Logic:  Units and upgrades may be placed anywhere.  LIKELY TO RENDER THE RUN IMPOSSIBLE ON HARDER DIFFICULTIES! | ||
|  |                Locks Grant Story Tech option to true. | ||
|  |     """
 | ||
|  |     display_name = "Required Tactics" | ||
|  |     option_standard = 0 | ||
|  |     option_advanced = 1 | ||
|  |     option_no_logic = 2 | ||
|  | 
 | ||
|  | 
 | ||
|  | class GenericUpgradeMissions(Range): | ||
|  |     """Determines the percentage of missions in the mission order that must be completed before
 | ||
|  |     level 1 of all weapon and armor upgrades is unlocked.  Level 2 upgrades require double the amount of missions, | ||
|  |     and level 3 requires triple the amount.  The required amounts are always rounded down. | ||
|  |     If set to 0, upgrades are instead added to the item pool and must be found to be used."""
 | ||
|  |     display_name = "Generic Upgrade Missions" | ||
|  |     range_start = 0 | ||
|  |     range_end = 100 | ||
|  |     default = 0 | ||
|  | 
 | ||
|  | 
 | ||
|  | class GenericUpgradeResearch(Choice): | ||
|  |     """Determines how weapon and armor upgrades affect missions once unlocked.
 | ||
|  | 
 | ||
|  |     Vanilla:  Upgrades must be researched as normal. | ||
|  |     Auto In No-Build:  In No-Build missions, upgrades are automatically researched. | ||
|  |     In all other missions, upgrades must be researched as normal. | ||
|  |     Auto In Build:  In No-Build missions, upgrades are unavailable as normal. | ||
|  |     In all other missions, upgrades are automatically researched. | ||
|  |     Always Auto:  Upgrades are automatically researched in all missions."""
 | ||
|  |     display_name = "Generic Upgrade Research" | ||
|  |     option_vanilla = 0 | ||
|  |     option_auto_in_no_build = 1 | ||
|  |     option_auto_in_build = 2 | ||
|  |     option_always_auto = 3 | ||
|  | 
 | ||
|  | 
 | ||
|  | class GenericUpgradeItems(Choice): | ||
|  |     """Determines how weapon and armor upgrades are split into items.  All options produce 3 levels of each item.
 | ||
|  |     Does nothing if upgrades are unlocked by completed mission counts. | ||
|  | 
 | ||
|  |     Individual Items:  All weapon and armor upgrades are each an item, | ||
|  |     resulting in 18 total upgrade items for Terran and 15 total items for Zerg and Protoss each. | ||
|  |     Bundle Weapon And Armor:  All types of weapon upgrades are one item per race, | ||
|  |     and all types of armor upgrades are one item per race, | ||
|  |     resulting in 18 total items. | ||
|  |     Bundle Unit Class:  Weapon and armor upgrades are merged, | ||
|  |     but upgrades are bundled separately for each race: | ||
|  |     Infantry, Vehicle, and Starship upgrades for Terran (9 items), | ||
|  |     Ground and Flyer upgrades for Zerg (6 items), | ||
|  |     Ground and Air upgrades for Protoss (6 items), | ||
|  |     resulting in 21 total items. | ||
|  |     Bundle All:  All weapon and armor upgrades are one item per race, | ||
|  |     resulting in 9 total items."""
 | ||
|  |     display_name = "Generic Upgrade Items" | ||
|  |     option_individual_items = 0 | ||
|  |     option_bundle_weapon_and_armor = 1 | ||
|  |     option_bundle_unit_class = 2 | ||
|  |     option_bundle_all = 3 | ||
|  | 
 | ||
|  | 
 | ||
|  | class NovaCovertOpsItems(Toggle): | ||
|  |     """
 | ||
|  |     If turned on, the equipment upgrades from Nova Covert Ops may be present in the world. | ||
|  | 
 | ||
|  |     If Nova Covert Ops campaign is enabled, this option is locked to be turned on. | ||
|  |     """
 | ||
|  |     display_name = "Nova Covert Ops Items" | ||
|  |     default = Toggle.option_true | ||
|  | 
 | ||
|  | 
 | ||
|  | class BroodWarItems(Toggle): | ||
|  |     """If turned on, returning items from StarCraft: Brood War may appear in the world.""" | ||
|  |     display_name = "Brood War Items" | ||
|  |     default = Toggle.option_true | ||
|  | 
 | ||
|  | 
 | ||
|  | class ExtendedItems(Toggle): | ||
|  |     """If turned on, original items that did not appear in Campaign mode may appear in the world.""" | ||
|  |     display_name = "Extended Items" | ||
|  |     default = Toggle.option_true | ||
|  | 
 | ||
|  | 
 | ||
|  | # Current maximum number of upgrades for a unit | ||
|  | MAX_UPGRADES_OPTION = 12 | ||
|  | 
 | ||
|  | 
 | ||
|  | class EnsureGenericItems(Range): | ||
|  |     """
 | ||
|  |     Specifies a minimum percentage of the generic item pool that will be present for the slot. | ||
|  |     The generic item pool is the pool of all generically useful items after all exclusions. | ||
|  |     Generically-useful items include: Worker upgrades, Building upgrades, economy upgrades, | ||
|  |     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 | ||
|  | 
 | ||
|  | 
 | ||
|  | class MinNumberOfUpgrades(Range): | ||
|  |     """
 | ||
|  |     Set a minimum to the number of upgrades a unit/structure can have. | ||
|  |     Note that most units have 4 or 6 upgrades. | ||
|  |     If a unit has fewer upgrades than the minimum, it will have all of its upgrades. | ||
|  | 
 | ||
|  |     Doesn't affect shared unit upgrades. | ||
|  |     """
 | ||
|  |     display_name = "Minimum number of upgrades per unit/structure" | ||
|  |     range_start = 0 | ||
|  |     range_end = MAX_UPGRADES_OPTION | ||
|  |     default = 2 | ||
|  | 
 | ||
|  | 
 | ||
|  | class MaxNumberOfUpgrades(Range): | ||
|  |     """
 | ||
|  |     Set a maximum to the number of upgrades a unit/structure can have. -1 is used to define unlimited. | ||
|  |     Note that most unit have 4 to 6 upgrades. | ||
|  | 
 | ||
|  |     Doesn't affect shared unit upgrades. | ||
|  |     """
 | ||
|  |     display_name = "Maximum number of upgrades per unit/structure" | ||
|  |     range_start = -1 | ||
|  |     range_end = MAX_UPGRADES_OPTION | ||
|  |     default = -1 | ||
|  | 
 | ||
|  | 
 | ||
|  | class KerriganPresence(Choice): | ||
|  |     """
 | ||
|  |     Determines whether Kerrigan is playable outside of missions that require her. | ||
|  | 
 | ||
|  |     Vanilla: Kerrigan is playable as normal, appears in the same missions as in vanilla game. | ||
|  |     Not Present:  Kerrigan is not playable, unless the mission requires her to be present.  Other hero units stay playable, | ||
|  |         and locations normally requiring Kerrigan can be checked by any unit. | ||
|  |         Kerrigan level items, active abilities and passive abilities affecting her will not appear. | ||
|  |         In missions where the Kerrigan unit is required, story abilities are given in same way as Grant Story Tech is set to true | ||
|  |     Not Present And No Passives:  In addition to the above, Kerrigan's passive abilities affecting other units (such as Twin Drones) will not appear. | ||
|  | 
 | ||
|  |     Note: Always set to "Not Present" if Heart of the Swarm campaign is disabled. | ||
|  |     """
 | ||
|  |     display_name = "Kerrigan Presence" | ||
|  |     option_vanilla = 0 | ||
|  |     option_not_present = 1 | ||
|  |     option_not_present_and_no_passives = 2 | ||
|  | 
 | ||
|  | 
 | ||
|  | class KerriganLevelsPerMissionCompleted(Range): | ||
|  |     """
 | ||
|  |     Determines how many levels Kerrigan gains when a mission is beaten. | ||
|  | 
 | ||
|  |     NOTE: Setting this too low can result in generation failures if The Infinite Cycle or Supreme are in the mission pool. | ||
|  |     """
 | ||
|  |     display_name = "Levels Per Mission Beaten" | ||
|  |     range_start = 0 | ||
|  |     range_end = 20 | ||
|  |     default = 0 | ||
|  | 
 | ||
|  | 
 | ||
|  | class KerriganLevelsPerMissionCompletedCap(Range): | ||
|  |     """
 | ||
|  |     Limits how many total levels Kerrigan can gain from beating missions.  This does not affect levels gained from items.   | ||
|  |     Set to -1 to disable this limit. | ||
|  | 
 | ||
|  |     NOTE: The following missions have these level requirements: | ||
|  |     Supreme: 35 | ||
|  |     The Infinite Cycle: 70 | ||
|  |     See Grant Story Levels for more details. | ||
|  |     """
 | ||
|  |     display_name = "Levels Per Mission Beaten Cap" | ||
|  |     range_start = -1 | ||
|  |     range_end = 140 | ||
|  |     default = -1 | ||
|  | 
 | ||
|  | 
 | ||
|  | class KerriganLevelItemSum(Range): | ||
|  |     """
 | ||
|  |     Determines the sum of the level items in the world.  This does not affect levels gained from beating missions. | ||
|  | 
 | ||
|  |     NOTE: The following missions have these level requirements: | ||
|  |     Supreme: 35 | ||
|  |     The Infinite Cycle: 70 | ||
|  |     See Grant Story Levels for more details. | ||
|  |     """
 | ||
|  |     display_name = "Kerrigan Level Item Sum" | ||
|  |     range_start = 0 | ||
|  |     range_end = 140 | ||
|  |     default = 70 | ||
|  | 
 | ||
|  | 
 | ||
|  | class KerriganLevelItemDistribution(Choice): | ||
|  |     """Determines the amount and size of Kerrigan level items.
 | ||
|  | 
 | ||
|  |     Vanilla:  Uses the distribution in the vanilla campaign. | ||
|  |     This entails 32 individual levels and 6 packs of varying sizes. | ||
|  |     This distribution always adds up to 70, ignoring the Level Item Sum setting. | ||
|  |     Smooth:  Uses a custom, condensed distribution of 10 items between sizes 4 and 10, | ||
|  |     intended to fit more levels into settings with little room for filler while keeping some variance in level gains. | ||
|  |     This distribution always adds up to 70, ignoring the Level Item Sum setting. | ||
|  |     Size 70:  Uses items worth 70 levels each. | ||
|  |     Size 35:  Uses items worth 35 levels each. | ||
|  |     Size 14:  Uses items worth 14 levels each. | ||
|  |     Size 10:  Uses items worth 10 levels each. | ||
|  |     Size 7:  Uses items worth 7 levels each. | ||
|  |     Size 5:  Uses items worth 5 levels each. | ||
|  |     Size 2:  Uses items worth 2 level eachs. | ||
|  |     Size 1:  Uses individual levels.  As there are not enough locations in the game for this distribution, | ||
|  |     this will result in a greatly reduced total level, and is likely to remove many other items."""
 | ||
|  |     display_name = "Kerrigan Level Item Distribution" | ||
|  |     option_vanilla = 0 | ||
|  |     option_smooth = 1 | ||
|  |     option_size_70 = 2 | ||
|  |     option_size_35 = 3 | ||
|  |     option_size_14 = 4 | ||
|  |     option_size_10 = 5 | ||
|  |     option_size_7 = 6 | ||
|  |     option_size_5 = 7 | ||
|  |     option_size_2 = 8 | ||
|  |     option_size_1 = 9 | ||
|  |     default = option_smooth | ||
|  | 
 | ||
|  | 
 | ||
|  | class KerriganTotalLevelCap(Range): | ||
|  |     """
 | ||
|  |     Limits how many total levels Kerrigan can gain from any source.  Depending on your other settings, | ||
|  |     there may be more levels available in the world, but they will not affect Kerrigan.   | ||
|  |     Set to -1 to disable this limit. | ||
|  | 
 | ||
|  |     NOTE: The following missions have these level requirements: | ||
|  |     Supreme: 35 | ||
|  |     The Infinite Cycle: 70 | ||
|  |     See Grant Story Levels for more details. | ||
|  |     """
 | ||
|  |     display_name = "Total Level Cap" | ||
|  |     range_start = -1 | ||
|  |     range_end = 140 | ||
|  |     default = -1 | ||
|  | 
 | ||
|  | 
 | ||
|  | class StartPrimaryAbilities(Range): | ||
|  |     """Number of Primary Abilities (Kerrigan Tier 1, 2, and 4) to start the game with.
 | ||
|  |     If set to 4, a Tier 7 ability is also included."""
 | ||
|  |     display_name = "Starting Primary Abilities" | ||
|  |     range_start = 0 | ||
|  |     range_end = 4 | ||
|  |     default = 0 | ||
|  | 
 | ||
|  | 
 | ||
|  | class KerriganPrimalStatus(Choice): | ||
|  |     """Determines when Kerrigan appears in her Primal Zerg form.
 | ||
|  |     This greatly increases her energy regeneration. | ||
|  | 
 | ||
|  |     Vanilla:  Kerrigan is human in missions that canonically appear before The Crucible, | ||
|  |     and zerg thereafter. | ||
|  |     Always Zerg:  Kerrigan is always zerg. | ||
|  |     Always Human:  Kerrigan is always human. | ||
|  |     Level 35:  Kerrigan is human until reaching level 35, and zerg thereafter. | ||
|  |     Half Completion:  Kerrigan is human until half of the missions in the world are completed, | ||
|  |     and zerg thereafter. | ||
|  |     Item:  Kerrigan's Primal Form is an item. She is human until it is found, and zerg thereafter.""" | ||
|  |     display_name = "Kerrigan Primal Status" | ||
|  |     option_vanilla = 0 | ||
|  |     option_always_zerg = 1 | ||
|  |     option_always_human = 2 | ||
|  |     option_level_35 = 3 | ||
|  |     option_half_completion = 4 | ||
|  |     option_item = 5 | ||
|  | 
 | ||
|  | 
 | ||
|  | class SpearOfAdunPresence(Choice): | ||
|  |     """
 | ||
|  |     Determines in which missions Spear of Adun calldowns will be available. | ||
|  |     Affects only abilities used from Spear of Adun top menu. | ||
|  | 
 | ||
|  |     Not Present: Spear of Adun calldowns are unavailable. | ||
|  |     LotV Protoss: Spear of Adun calldowns are only available in LotV main campaign | ||
|  |     Protoss: Spear od Adun calldowns are available in any Protoss mission | ||
|  |     Everywhere: Spear od Adun calldowns are available in any mission of any race | ||
|  |     """
 | ||
|  |     display_name = "Spear of Adun Presence" | ||
|  |     option_not_present = 0 | ||
|  |     option_lotv_protoss = 1 | ||
|  |     option_protoss = 2 | ||
|  |     option_everywhere = 3 | ||
|  |     default = option_lotv_protoss | ||
|  | 
 | ||
|  |     # Fix case | ||
|  |     @classmethod | ||
|  |     def get_option_name(cls, value: int) -> str: | ||
|  |         if value == SpearOfAdunPresence.option_lotv_protoss: | ||
|  |             return "LotV Protoss" | ||
|  |         else: | ||
|  |             return super().get_option_name(value) | ||
|  | 
 | ||
|  | 
 | ||
|  | class SpearOfAdunPresentInNoBuild(Toggle): | ||
|  |     """
 | ||
|  |     Determines if Spear of Adun calldowns are available in no-build missions. | ||
|  | 
 | ||
|  |     If turned on, Spear of Adun calldown powers are available in missions specified under "Spear of Adun Presence". | ||
|  |     If turned off, Spear of Adun calldown powers are unavailable in all no-build missions | ||
|  |     """
 | ||
|  |     display_name = "Spear of Adun Present in No-Build" | ||
|  | 
 | ||
|  | 
 | ||
|  | class SpearOfAdunAutonomouslyCastAbilityPresence(Choice): | ||
|  |     """
 | ||
|  |     Determines availability of Spear of Adun powers, that are autonomously cast. | ||
|  |     Affects abilities like Reconstruction Beam or Overwatch | ||
|  | 
 | ||
|  |     Not Presents: Autocasts are not available. | ||
|  |     LotV Protoss: Spear of Adun autocasts are only available in LotV main campaign | ||
|  |     Protoss: Spear od Adun autocasts are available in any Protoss mission | ||
|  |     Everywhere: Spear od Adun autocasts are available in any mission of any race | ||
|  |     """
 | ||
|  |     display_name = "Spear of Adun Autonomously Cast Powers Presence" | ||
|  |     option_not_present = 0 | ||
|  |     option_lotv_protoss = 1 | ||
|  |     option_protoss = 2 | ||
|  |     option_everywhere = 3 | ||
|  |     default = option_lotv_protoss | ||
|  | 
 | ||
|  |     # Fix case | ||
|  |     @classmethod | ||
|  |     def get_option_name(cls, value: int) -> str: | ||
|  |         if value == SpearOfAdunPresence.option_lotv_protoss: | ||
|  |             return "LotV Protoss" | ||
|  |         else: | ||
|  |             return super().get_option_name(value) | ||
|  | 
 | ||
|  | 
 | ||
|  | class SpearOfAdunAutonomouslyCastPresentInNoBuild(Toggle): | ||
|  |     """
 | ||
|  |     Determines if Spear of Adun autocasts are available in no-build missions. | ||
|  | 
 | ||
|  |     If turned on, Spear of Adun autocasts are available in missions specified under "Spear of Adun Autonomously Cast Powers Presence". | ||
|  |     If turned off, Spear of Adun autocasts are unavailable in all no-build missions | ||
|  |     """
 | ||
|  |     display_name = "Spear of Adun Autonomously Cast Powers Present in No-Build" | ||
|  | 
 | ||
|  | 
 | ||
|  | class GrantStoryTech(Toggle): | ||
|  |     """
 | ||
|  |     If set true, grants special tech required for story mission completion for duration of the mission. | ||
|  |     Otherwise, you need to find these tech by a normal means as items. | ||
|  |     Affects story missions like Back in the Saddle and Supreme | ||
|  | 
 | ||
|  |     Locked to true if Required Tactics is set to no logic. | ||
|  |     """
 | ||
|  |     display_name = "Grant Story Tech" | ||
|  | 
 | ||
|  | 
 | ||
|  | class GrantStoryLevels(Choice): | ||
|  |     """
 | ||
|  |     If enabled, grants Kerrigan the required minimum levels for the following missions: | ||
|  |     Supreme: 35 | ||
|  |     The Infinite Cycle: 70 | ||
|  |     The bonus levels only apply during the listed missions, and can exceed the Total Level Cap. | ||
|  | 
 | ||
|  |     If disabled, either of these missions is included, and there are not enough levels in the world, generation may fail.   | ||
|  |     To prevent this, either increase the amount of levels in the world, or enable this option. | ||
|  | 
 | ||
|  |     If disabled and Required Tactics is set to no logic, this option is forced to Minimum. | ||
|  | 
 | ||
|  |     Disabled: Kerrigan does not get bonus levels for these missions, | ||
|  |               instead the levels must be gained from items or beating missions. | ||
|  |     Additive: Kerrigan gains bonus levels equal to the mission's required level. | ||
|  |     Minimum: Kerrigan is either at her real level, or at the mission's required level, | ||
|  |              depending on which is higher. | ||
|  |     """
 | ||
|  |     display_name = "Grant Story Levels" | ||
|  |     option_disabled = 0 | ||
|  |     option_additive = 1 | ||
|  |     option_minimum = 2 | ||
|  |     default = option_minimum | ||
|  | 
 | ||
|  | 
 | ||
|  | class TakeOverAIAllies(Toggle): | ||
|  |     """
 | ||
|  |     On maps supporting this feature allows you to take control over an AI Ally. | ||
|  |     """
 | ||
|  |     display_name = "Take Over AI Allies" | ||
|  | 
 | ||
|  | 
 | ||
|  | class LockedItems(ItemSet): | ||
|  |     """Guarantees that these items will be unlockable""" | ||
|  |     display_name = "Locked Items" | ||
|  | 
 | ||
|  | 
 | ||
|  | class ExcludedItems(ItemSet): | ||
|  |     """Guarantees that these items will not be unlockable""" | ||
|  |     display_name = "Excluded Items" | ||
|  | 
 | ||
|  | 
 | ||
|  | class ExcludedMissions(OptionSet): | ||
|  |     """Guarantees that these missions will not appear in the campaign
 | ||
|  |     Doesn't apply to vanilla mission order. | ||
|  |     It may be impossible to build a valid campaign if too many missions are excluded."""
 | ||
|  |     display_name = "Excluded Missions" | ||
|  |     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 | ||
|  |     option_disabled = 2 | ||
|  | 
 | ||
|  | 
 | ||
|  | class VanillaLocations(LocationInclusion): | ||
|  |     """
 | ||
|  |     Enables or disables item rewards for completing vanilla objectives. | ||
|  |     Vanilla objectives are bonus objectives from the vanilla game, | ||
|  |     along with some additional objectives to balance the missions. | ||
|  |     Enable these locations for a balanced experience. | ||
|  | 
 | ||
|  |     Enabled: All locations fitting into this do their normal rewards | ||
|  |     Resources: Forces these locations to contain Starting Resources | ||
|  |     Disabled: Removes item rewards from these locations. | ||
|  | 
 | ||
|  |     Note: Individual locations subject to plando are always enabled, so the plando can be placed properly. | ||
|  |     See also: Excluded Locations, Item Plando (https://archipelago.gg/tutorial/Archipelago/plando/en#item-plando) | ||
|  |     """
 | ||
|  |     display_name = "Vanilla Locations" | ||
|  | 
 | ||
|  | 
 | ||
|  | class ExtraLocations(LocationInclusion): | ||
|  |     """
 | ||
|  |     Enables or disables item rewards for mission progress and minor objectives. | ||
|  |     This includes mandatory mission objectives, | ||
|  |     collecting reinforcements and resource pickups, | ||
|  |     destroying structures, and overcoming minor challenges. | ||
|  |     Enables these locations to add more checks and items to your world. | ||
|  | 
 | ||
|  |     Enabled: All locations fitting into this do their normal rewards | ||
|  |     Resources: Forces these locations to contain Starting Resources | ||
|  |     Disabled: Removes item rewards from these locations. | ||
|  | 
 | ||
|  |     Note: Individual locations subject to plando are always enabled, so the plando can be placed properly. | ||
|  |     See also: Excluded Locations, Item Plando (https://archipelago.gg/tutorial/Archipelago/plando/en#item-plando) | ||
|  |     """
 | ||
|  |     display_name = "Extra Locations" | ||
|  | 
 | ||
|  | 
 | ||
|  | class ChallengeLocations(LocationInclusion): | ||
|  |     """
 | ||
|  |     Enables or disables item rewards for completing challenge tasks. | ||
|  |     Challenges are tasks that are more difficult than completing the mission, and are often based on achievements. | ||
|  |     You might be required to visit the same mission later after getting stronger in order to finish these tasks. | ||
|  |     Enable these locations to increase the difficulty of completing the multiworld. | ||
|  | 
 | ||
|  |     Enabled: All locations fitting into this do their normal rewards | ||
|  |     Resources: Forces these locations to contain Starting Resources | ||
|  |     Disabled: Removes item rewards from these locations. | ||
|  | 
 | ||
|  |     Note: Individual locations subject to plando are always enabled, so the plando can be placed properly. | ||
|  |     See also: Excluded Locations, Item Plando (https://archipelago.gg/tutorial/Archipelago/plando/en#item-plando) | ||
|  |     """
 | ||
|  |     display_name = "Challenge Locations" | ||
|  | 
 | ||
|  | 
 | ||
|  | class MasteryLocations(LocationInclusion): | ||
|  |     """
 | ||
|  |     Enables or disables item rewards for overcoming especially difficult challenges. | ||
|  |     These challenges are often based on Mastery achievements and Feats of Strength. | ||
|  |     Enable these locations to add the most difficult checks to the world. | ||
|  | 
 | ||
|  |     Enabled: All locations fitting into this do their normal rewards | ||
|  |     Resources: Forces these locations to contain Starting Resources | ||
|  |     Disabled: Removes item rewards from these locations. | ||
|  | 
 | ||
|  |     Note: Individual locations subject to plando are always enabled, so the plando can be placed properly. | ||
|  |     See also: Excluded Locations, Item Plando (https://archipelago.gg/tutorial/Archipelago/plando/en#item-plando) | ||
|  |     """
 | ||
|  |     display_name = "Mastery Locations" | ||
|  | 
 | ||
|  | 
 | ||
|  | class MineralsPerItem(Range): | ||
|  |     """
 | ||
|  |     Configures how many minerals are given per resource item. | ||
|  |     """
 | ||
|  |     display_name = "Minerals Per Item" | ||
|  |     range_start = 0 | ||
|  |     range_end = 500 | ||
|  |     default = 25 | ||
|  | 
 | ||
|  | 
 | ||
|  | class VespenePerItem(Range): | ||
|  |     """
 | ||
|  |     Configures how much vespene gas is given per resource item. | ||
|  |     """
 | ||
|  |     display_name = "Vespene Per Item" | ||
|  |     range_start = 0 | ||
|  |     range_end = 500 | ||
|  |     default = 25 | ||
|  | 
 | ||
|  | 
 | ||
|  | class StartingSupplyPerItem(Range): | ||
|  |     """
 | ||
|  |     Configures how much starting supply per is given per item. | ||
|  |     """
 | ||
|  |     display_name = "Starting Supply Per Item" | ||
|  |     range_start = 0 | ||
|  |     range_end = 200 | ||
|  |     default = 5 | ||
|  | 
 | ||
|  | 
 | ||
|  | @dataclass | ||
|  | class Starcraft2Options(PerGameCommonOptions): | ||
|  |     game_difficulty: GameDifficulty | ||
|  |     game_speed: GameSpeed | ||
|  |     disable_forced_camera: DisableForcedCamera | ||
|  |     skip_cutscenes: SkipCutscenes | ||
|  |     all_in_map: AllInMap | ||
|  |     mission_order: MissionOrder | ||
|  |     maximum_campaign_size: MaximumCampaignSize | ||
|  |     grid_two_start_positions: GridTwoStartPositions | ||
|  |     player_color_terran_raynor: PlayerColorTerranRaynor | ||
|  |     player_color_protoss: PlayerColorProtoss | ||
|  |     player_color_zerg: PlayerColorZerg | ||
|  |     player_color_zerg_primal: PlayerColorZergPrimal | ||
|  |     enable_wol_missions: EnableWolMissions | ||
|  |     enable_prophecy_missions: EnableProphecyMissions | ||
|  |     enable_hots_missions: EnableHotsMissions | ||
|  |     enable_lotv_prologue_missions: EnableLotVPrologueMissions | ||
|  |     enable_lotv_missions: EnableLotVMissions | ||
|  |     enable_epilogue_missions: EnableEpilogueMissions | ||
|  |     enable_nco_missions: EnableNCOMissions | ||
|  |     shuffle_campaigns: ShuffleCampaigns | ||
|  |     shuffle_no_build: ShuffleNoBuild | ||
|  |     starter_unit: StarterUnit | ||
|  |     required_tactics: RequiredTactics | ||
|  |     ensure_generic_items: EnsureGenericItems | ||
|  |     min_number_of_upgrades: MinNumberOfUpgrades | ||
|  |     max_number_of_upgrades: MaxNumberOfUpgrades | ||
|  |     generic_upgrade_missions: GenericUpgradeMissions | ||
|  |     generic_upgrade_research: GenericUpgradeResearch | ||
|  |     generic_upgrade_items: GenericUpgradeItems | ||
|  |     kerrigan_presence: KerriganPresence | ||
|  |     kerrigan_levels_per_mission_completed: KerriganLevelsPerMissionCompleted | ||
|  |     kerrigan_levels_per_mission_completed_cap: KerriganLevelsPerMissionCompletedCap | ||
|  |     kerrigan_level_item_sum: KerriganLevelItemSum | ||
|  |     kerrigan_level_item_distribution: KerriganLevelItemDistribution | ||
|  |     kerrigan_total_level_cap: KerriganTotalLevelCap | ||
|  |     start_primary_abilities: StartPrimaryAbilities | ||
|  |     kerrigan_primal_status: KerriganPrimalStatus | ||
|  |     spear_of_adun_presence: SpearOfAdunPresence | ||
|  |     spear_of_adun_present_in_no_build: SpearOfAdunPresentInNoBuild | ||
|  |     spear_of_adun_autonomously_cast_ability_presence: SpearOfAdunAutonomouslyCastAbilityPresence | ||
|  |     spear_of_adun_autonomously_cast_present_in_no_build: SpearOfAdunAutonomouslyCastPresentInNoBuild | ||
|  |     grant_story_tech: GrantStoryTech | ||
|  |     grant_story_levels: GrantStoryLevels | ||
|  |     take_over_ai_allies: TakeOverAIAllies | ||
|  |     locked_items: LockedItems | ||
|  |     excluded_items: ExcludedItems | ||
|  |     excluded_missions: ExcludedMissions | ||
|  |     exclude_very_hard_missions: ExcludeVeryHardMissions | ||
|  |     nco_items: NovaCovertOpsItems | ||
|  |     bw_items: BroodWarItems | ||
|  |     ext_items: ExtendedItems | ||
|  |     vanilla_locations: VanillaLocations | ||
|  |     extra_locations: ExtraLocations | ||
|  |     challenge_locations: ChallengeLocations | ||
|  |     mastery_locations: MasteryLocations | ||
|  |     minerals_per_item: MineralsPerItem | ||
|  |     vespene_per_item: VespenePerItem | ||
|  |     starting_supply_per_item: StartingSupplyPerItem | ||
|  | 
 | ||
|  | 
 | ||
|  | def get_option_value(world: World, name: str) -> Union[int,  FrozenSet]: | ||
|  |     if world is None: | ||
|  |         field: Field = [class_field for class_field in fields(Starcraft2Options) if class_field.name == name][0] | ||
|  |         return field.type.default | ||
|  | 
 | ||
|  |     player_option = getattr(world.options, name) | ||
|  | 
 | ||
|  |     return player_option.value | ||
|  | 
 | ||
|  | 
 | ||
|  | def get_enabled_campaigns(world: World) -> Set[SC2Campaign]: | ||
|  |     enabled_campaigns = set() | ||
|  |     if get_option_value(world, "enable_wol_missions"): | ||
|  |         enabled_campaigns.add(SC2Campaign.WOL) | ||
|  |     if get_option_value(world, "enable_prophecy_missions"): | ||
|  |         enabled_campaigns.add(SC2Campaign.PROPHECY) | ||
|  |     if get_option_value(world, "enable_hots_missions"): | ||
|  |         enabled_campaigns.add(SC2Campaign.HOTS) | ||
|  |     if get_option_value(world, "enable_lotv_prologue_missions"): | ||
|  |         enabled_campaigns.add(SC2Campaign.PROLOGUE) | ||
|  |     if get_option_value(world, "enable_lotv_missions"): | ||
|  |         enabled_campaigns.add(SC2Campaign.LOTV) | ||
|  |     if get_option_value(world, "enable_epilogue_missions"): | ||
|  |         enabled_campaigns.add(SC2Campaign.EPILOGUE) | ||
|  |     if get_option_value(world, "enable_nco_missions"): | ||
|  |         enabled_campaigns.add(SC2Campaign.NCO) | ||
|  |     return enabled_campaigns | ||
|  | 
 | ||
|  | 
 | ||
|  | def get_disabled_campaigns(world: World) -> Set[SC2Campaign]: | ||
|  |     all_campaigns = set(SC2Campaign) | ||
|  |     enabled_campaigns = get_enabled_campaigns(world) | ||
|  |     disabled_campaigns = all_campaigns.difference(enabled_campaigns) | ||
|  |     disabled_campaigns.remove(SC2Campaign.GLOBAL) | ||
|  |     return disabled_campaigns | ||
|  | 
 | ||
|  | 
 | ||
|  | def get_excluded_missions(world: World) -> Set[SC2Mission]: | ||
|  |     mission_order_type = get_option_value(world, "mission_order") | ||
|  |     excluded_mission_names = get_option_value(world, "excluded_missions") | ||
|  |     shuffle_no_build = get_option_value(world, "shuffle_no_build") | ||
|  |     disabled_campaigns = get_disabled_campaigns(world) | ||
|  | 
 | ||
|  |     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(world, "exclude_very_hard_missions") == ExcludeVeryHardMissions.option_true | ||
|  |         ) or ( | ||
|  |             get_option_value(world, "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(world, "maximum_campaign_size") < 20 | ||
|  |                     ) | ||
|  |             ) | ||
|  |     ): | ||
|  |         excluded_missions = 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, | ||
|  |     MissionOrder.option_mini_campaign | ||
|  | ] | ||
|  | 
 | ||
|  | kerrigan_unit_available = [ | ||
|  |     KerriganPresence.option_vanilla, | ||
|  | ] |