Files
Grinch-AP/worlds/sc2/test/test_usecases.py

606 lines
30 KiB
Python
Raw Normal View History

"""
Unit tests for yaml usecases we want to support
"""
from .test_base import Sc2SetupTestBase
from .. import get_all_missions, mission_tables, options
from ..item import item_groups, item_tables, item_names
from ..mission_tables import SC2Race, SC2Mission, SC2Campaign, MissionFlag
from ..options import (
EnabledCampaigns, MasteryLocations, MissionOrder, EnableRaceSwapVariants, ShuffleCampaigns,
ShuffleNoBuild, StarterUnit, RequiredTactics, KerriganPresence, KerriganLevelItemDistribution, GrantStoryTech,
GrantStoryLevels, BasebustLocations, ChallengeLocations, DifficultyCurve, EnableMorphling, ExcludeOverpoweredItems,
ExcludeVeryHardMissions, ExtraLocations, GenericUpgradeItems, GenericUpgradeResearch, GenericUpgradeResearchSpeedup,
KerriganPrimalStatus, KeyMode, MissionOrderScouting, EnableMissionRaceBalancing,
NovaGhostOfAChanceVariant, PreventativeLocations, SpeedrunLocations, TakeOverAIAllies, VanillaItemsOnly
)
class TestSupportedUseCases(Sc2SetupTestBase):
def test_vanilla_all_campaigns_generates(self) -> None:
world_options = {
'mission_order': options.MissionOrder.option_vanilla,
'enabled_campaigns': EnabledCampaigns.valid_keys,
}
self.generate_world(world_options)
world_regions = [region.name for region in self.multiworld.regions if region.name != "Menu"]
self.assertEqual(len(world_regions), 83, "Unexpected number of missions for vanilla mission order")
def test_terran_with_nco_units_only_generates(self):
world_options = {
'enabled_campaigns': {
SC2Campaign.WOL.campaign_name,
SC2Campaign.NCO.campaign_name
},
'excluded_items': {
item_groups.ItemGroupNames.TERRAN_UNITS: 0,
},
'unexcluded_items': {
item_groups.ItemGroupNames.NCO_UNITS: 0,
},
'max_number_of_upgrades': 2,
}
self.generate_world(world_options)
self.assertTrue(self.multiworld.itempool)
world_item_names = [item.name for item in self.multiworld.itempool]
self.assertIn(item_names.MARINE, world_item_names)
self.assertIn(item_names.RAVEN, world_item_names)
self.assertIn(item_names.LIBERATOR, world_item_names)
self.assertIn(item_names.BATTLECRUISER, world_item_names)
self.assertNotIn(item_names.DIAMONDBACK, world_item_names)
self.assertNotIn(item_names.DIAMONDBACK_BURST_CAPACITORS, world_item_names)
self.assertNotIn(item_names.VIKING, world_item_names)
def test_nco_with_nobuilds_excluded_generates(self):
world_options = {
'enabled_campaigns': {
SC2Campaign.NCO.campaign_name
},
'shuffle_no_build': options.ShuffleNoBuild.option_false,
'mission_order': options.MissionOrder.option_mini_campaign,
}
self.generate_world(world_options)
self.assertTrue(self.multiworld.itempool)
missions = get_all_missions(self.world.custom_mission_order)
self.assertNotIn(mission_tables.SC2Mission.THE_ESCAPE, missions)
self.assertNotIn(mission_tables.SC2Mission.IN_THE_ENEMY_S_SHADOW, missions)
for mission in missions:
self.assertEqual(mission_tables.SC2Campaign.NCO, mission.campaign)
def test_terran_with_nco_upgrades_units_only_generates(self):
world_options = {
'enabled_campaigns': {
SC2Campaign.WOL.campaign_name,
SC2Campaign.NCO.campaign_name
},
'mission_order': options.MissionOrder.option_vanilla_shuffled,
'excluded_items': {
item_groups.ItemGroupNames.TERRAN_ITEMS: 0,
},
'unexcluded_items': {
item_groups.ItemGroupNames.NCO_MAX_PROGRESSIVE_ITEMS: 0,
item_groups.ItemGroupNames.NCO_MIN_PROGRESSIVE_ITEMS: 1,
},
'excluded_missions': [
# These missions have trouble fulfilling Terran Power Rating under these terms
SC2Mission.SUPERNOVA.mission_name,
SC2Mission.WELCOME_TO_THE_JUNGLE.mission_name,
SC2Mission.TROUBLE_IN_PARADISE.mission_name,
],
'mastery_locations': MasteryLocations.option_disabled,
}
self.generate_world(world_options)
world_item_names = [item.name for item in self.multiworld.itempool + self.multiworld.precollected_items[1]]
self.assertTrue(world_item_names)
missions = get_all_missions(self.world.custom_mission_order)
for mission in missions:
self.assertIn(mission_tables.MissionFlag.Terran, mission.flags)
self.assertIn(item_names.MARINE, world_item_names)
self.assertIn(item_names.MARAUDER, world_item_names)
self.assertIn(item_names.BUNKER, world_item_names)
self.assertIn(item_names.BANSHEE, world_item_names)
self.assertIn(item_names.BATTLECRUISER_ATX_LASER_BATTERY, world_item_names)
self.assertIn(item_names.NOVA_C20A_CANISTER_RIFLE, world_item_names)
self.assertGreaterEqual(world_item_names.count(item_names.BANSHEE_PROGRESSIVE_CROSS_SPECTRUM_DAMPENERS), 2)
self.assertGreaterEqual(world_item_names.count(item_names.PROGRESSIVE_TERRAN_SHIP_WEAPON), 3)
self.assertNotIn(item_names.MEDIC, world_item_names)
self.assertNotIn(item_names.PSI_DISRUPTER, world_item_names)
self.assertNotIn(item_names.BATTLECRUISER_PROGRESSIVE_MISSILE_PODS, world_item_names)
self.assertNotIn(item_names.HELLION_INFERNAL_PLATING, world_item_names)
self.assertNotIn(item_names.CELLULAR_REACTOR, world_item_names)
self.assertNotIn(item_names.TECH_REACTOR, world_item_names)
def test_nco_and_2_wol_missions_only_can_generate_with_vanilla_items_only(self) -> None:
world_options = {
'enabled_campaigns': {
SC2Campaign.WOL.campaign_name,
SC2Campaign.NCO.campaign_name
},
'excluded_missions': [
mission.mission_name for mission in mission_tables.SC2Mission
if mission.campaign == mission_tables.SC2Campaign.WOL
and mission.mission_name not in (mission_tables.SC2Mission.LIBERATION_DAY.mission_name, mission_tables.SC2Mission.THE_OUTLAWS.mission_name)
],
'mission_order': options.MissionOrder.option_grid,
'maximum_campaign_size': options.MaximumCampaignSize.range_end,
'mastery_locations': options.MasteryLocations.option_disabled,
'vanilla_items_only': True,
}
self.generate_world(world_options)
world_item_names = [item.name for item in self.multiworld.itempool]
self.assertTrue(item_names)
self.assertNotIn(item_names.LIBERATOR, world_item_names)
self.assertNotIn(item_names.MARAUDER_PROGRESSIVE_STIMPACK, world_item_names)
self.assertNotIn(item_names.HELLION_HELLBAT, world_item_names)
self.assertNotIn(item_names.BATTLECRUISER_CLOAK, world_item_names)
def test_free_protoss_only_generates(self) -> None:
world_options = {
'enabled_campaigns': {
SC2Campaign.PROPHECY.campaign_name,
SC2Campaign.PROLOGUE.campaign_name
},
# todo(mm): Currently, these settings don't generate on grid because there are not enough EASY missions
'mission_order': options.MissionOrder.option_vanilla_shuffled,
'maximum_campaign_size': options.MaximumCampaignSize.range_end,
'accessibility': 'locations',
}
self.generate_world(world_options)
world_item_names = [item.name for item in self.multiworld.itempool]
self.assertTrue(world_item_names)
missions = get_all_missions(self.world.custom_mission_order)
self.assertEqual(len(missions), 7, "Wrong number of missions in free protoss seed")
for mission in missions:
self.assertIn(mission.campaign, (mission_tables.SC2Campaign.PROLOGUE, mission_tables.SC2Campaign.PROPHECY))
for item_name in world_item_names:
self.assertIn(item_tables.item_table[item_name].race, (mission_tables.SC2Race.ANY, mission_tables.SC2Race.PROTOSS))
def test_resource_filler_items_may_be_put_in_start_inventory(self) -> None:
NUM_RESOURCE_ITEMS = 10
world_options = {
'start_inventory': {
item_names.STARTING_MINERALS: NUM_RESOURCE_ITEMS,
item_names.STARTING_VESPENE: NUM_RESOURCE_ITEMS,
item_names.STARTING_SUPPLY: NUM_RESOURCE_ITEMS,
},
}
self.generate_world(world_options)
start_item_names = [item.name for item in self.multiworld.precollected_items[self.player]]
self.assertEqual(start_item_names.count(item_names.STARTING_MINERALS), NUM_RESOURCE_ITEMS, "Wrong number of starting minerals in starting inventory")
self.assertEqual(start_item_names.count(item_names.STARTING_VESPENE), NUM_RESOURCE_ITEMS, "Wrong number of starting vespene in starting inventory")
self.assertEqual(start_item_names.count(item_names.STARTING_SUPPLY), NUM_RESOURCE_ITEMS, "Wrong number of starting supply in starting inventory")
def test_excluding_protoss_excludes_campaigns_and_items(self) -> None:
world_options = {
'selected_races': {
SC2Race.TERRAN.get_title(),
SC2Race.ZERG.get_title(),
},
'enabled_campaigns': options.EnabledCampaigns.valid_keys,
'mission_order': options.MissionOrder.option_grid,
}
self.generate_world(world_options)
world_item_names = [item.name for item in self.multiworld.itempool]
world_regions = [region.name for region in self.multiworld.regions]
world_regions.remove('Menu')
for item_name in world_item_names:
self.assertNotEqual(item_tables.item_table[item_name].race, mission_tables.SC2Race.PROTOSS, f"{item_name} is a PROTOSS item!")
for region in world_regions:
self.assertNotIn(mission_tables.lookup_name_to_mission[region].campaign,
(mission_tables.SC2Campaign.LOTV, mission_tables.SC2Campaign.PROPHECY, mission_tables.SC2Campaign.PROLOGUE),
f"{region} is a PROTOSS mission!")
def test_excluding_terran_excludes_campaigns_and_items(self) -> None:
world_options = {
'selected_races': {
SC2Race.ZERG.get_title(),
SC2Race.PROTOSS.get_title(),
},
'enabled_campaigns': EnabledCampaigns.valid_keys,
'mission_order': options.MissionOrder.option_grid,
}
self.generate_world(world_options)
world_item_names = [item.name for item in self.multiworld.itempool]
world_regions = [region.name for region in self.multiworld.regions]
world_regions.remove('Menu')
for item_name in world_item_names:
self.assertNotEqual(item_tables.item_table[item_name].race, mission_tables.SC2Race.TERRAN,
f"{item_name} is a TERRAN item!")
for region in world_regions:
self.assertNotIn(mission_tables.lookup_name_to_mission[region].campaign,
(mission_tables.SC2Campaign.WOL, mission_tables.SC2Campaign.NCO),
f"{region} is a TERRAN mission!")
def test_excluding_zerg_excludes_campaigns_and_items(self) -> None:
world_options = {
'selected_races': {
SC2Race.TERRAN.get_title(),
SC2Race.PROTOSS.get_title(),
},
'enabled_campaigns': EnabledCampaigns.valid_keys,
'mission_order': options.MissionOrder.option_grid,
'excluded_missions': [
SC2Mission.THE_INFINITE_CYCLE.mission_name
]
}
self.generate_world(world_options)
world_item_names = [item.name for item in self.multiworld.itempool]
world_regions = [region.name for region in self.multiworld.regions]
world_regions.remove('Menu')
for item_name in world_item_names:
self.assertNotEqual(item_tables.item_table[item_name].race, mission_tables.SC2Race.ZERG,
f"{item_name} is a ZERG item!")
# have to manually exclude the only non-zerg HotS mission...
for region in filter(lambda region: region != "With Friends Like These", world_regions):
self.assertNotIn(mission_tables.lookup_name_to_mission[region].campaign,
([mission_tables.SC2Campaign.HOTS]),
f"{region} is a ZERG mission!")
def test_excluding_faction_on_vanilla_order_excludes_epilogue(self) -> None:
world_options = {
'selected_races': {
SC2Race.TERRAN.get_title(),
SC2Race.PROTOSS.get_title(),
},
'enabled_campaigns': EnabledCampaigns.valid_keys,
'mission_order': options.MissionOrder.option_vanilla,
}
self.generate_world(world_options)
world_regions = [region.name for region in self.multiworld.regions]
world_regions.remove('Menu')
for region in world_regions:
self.assertNotIn(mission_tables.lookup_name_to_mission[region].campaign,
([mission_tables.SC2Campaign.EPILOGUE]),
f"{region} is an epilogue mission!")
def test_race_swap_pick_one_has_correct_length_and_includes_swaps(self) -> None:
world_options = {
'selected_races': options.SelectedRaces.valid_keys,
'enable_race_swap': options.EnableRaceSwapVariants.option_pick_one,
'enabled_campaigns': {
SC2Campaign.WOL.campaign_name,
},
'mission_order': options.MissionOrder.option_grid,
'excluded_missions': [mission_tables.SC2Mission.ZERO_HOUR.mission_name],
}
self.generate_world(world_options)
world_regions = [region.name for region in self.multiworld.regions]
world_regions.remove('Menu')
NUM_WOL_MISSIONS = len([mission for mission in SC2Mission if mission.campaign == SC2Campaign.WOL and MissionFlag.RaceSwap not in mission.flags])
races = set(mission_tables.lookup_name_to_mission[mission].race for mission in world_regions)
self.assertEqual(len(world_regions), NUM_WOL_MISSIONS)
self.assertTrue(SC2Race.ZERG in races or SC2Race.PROTOSS in races)
def test_start_inventory_upgrade_level_includes_only_correct_bundle(self) -> None:
world_options = {
'start_inventory': {
item_groups.ItemGroupNames.TERRAN_GENERIC_UPGRADES: 1,
},
'locked_items': {
# One unit of each class to guarantee upgrades are available
item_names.MARINE: 1,
item_names.VULTURE: 1,
item_names.BANSHEE: 1,
},
'generic_upgrade_items': options.GenericUpgradeItems.option_bundle_unit_class,
'selected_races': {
SC2Race.TERRAN.get_title(),
},
'enable_race_swap': options.EnableRaceSwapVariants.option_disabled,
'enabled_campaigns': {
SC2Campaign.WOL.campaign_name,
},
'mission_order': options.MissionOrder.option_grid,
}
self.generate_world(world_options)
self.assertTrue(self.multiworld.itempool)
world_item_names = [item.name for item in self.multiworld.itempool]
start_inventory = [item.name for item in self.multiworld.precollected_items[self.player]]
# Start inventory
self.assertIn(item_names.PROGRESSIVE_TERRAN_INFANTRY_UPGRADE, start_inventory)
self.assertIn(item_names.PROGRESSIVE_TERRAN_VEHICLE_UPGRADE, start_inventory)
self.assertIn(item_names.PROGRESSIVE_TERRAN_SHIP_UPGRADE, start_inventory)
self.assertNotIn(item_names.PROGRESSIVE_TERRAN_INFANTRY_WEAPON, start_inventory)
self.assertNotIn(item_names.PROGRESSIVE_TERRAN_INFANTRY_ARMOR, start_inventory)
self.assertNotIn(item_names.PROGRESSIVE_TERRAN_VEHICLE_WEAPON, start_inventory)
self.assertNotIn(item_names.PROGRESSIVE_TERRAN_VEHICLE_ARMOR, start_inventory)
self.assertNotIn(item_names.PROGRESSIVE_TERRAN_SHIP_WEAPON, start_inventory)
self.assertNotIn(item_names.PROGRESSIVE_TERRAN_SHIP_ARMOR, start_inventory)
self.assertNotIn(item_names.PROGRESSIVE_TERRAN_ARMOR_UPGRADE, start_inventory)
# Additional items in pool -- standard tactics will require additional levels
self.assertIn(item_names.PROGRESSIVE_TERRAN_INFANTRY_UPGRADE, world_item_names)
self.assertIn(item_names.PROGRESSIVE_TERRAN_VEHICLE_UPGRADE, world_item_names)
self.assertIn(item_names.PROGRESSIVE_TERRAN_SHIP_UPGRADE, world_item_names)
self.assertNotIn(item_names.PROGRESSIVE_TERRAN_INFANTRY_WEAPON, world_item_names)
self.assertNotIn(item_names.PROGRESSIVE_TERRAN_INFANTRY_ARMOR, world_item_names)
self.assertNotIn(item_names.PROGRESSIVE_TERRAN_VEHICLE_WEAPON, world_item_names)
self.assertNotIn(item_names.PROGRESSIVE_TERRAN_VEHICLE_ARMOR, world_item_names)
self.assertNotIn(item_names.PROGRESSIVE_TERRAN_SHIP_WEAPON, world_item_names)
self.assertNotIn(item_names.PROGRESSIVE_TERRAN_SHIP_ARMOR, world_item_names)
self.assertNotIn(item_names.PROGRESSIVE_TERRAN_ARMOR_UPGRADE, world_item_names)
def test_kerrigan_max_active_abilities(self):
target_number: int = 8
world_options = {
**self.ALL_CAMPAIGNS,
'mission_order': options.MissionOrder.option_grid,
'maximum_campaign_size': options.MaximumCampaignSize.range_end,
'selected_races': {
SC2Race.ZERG.get_title(),
},
'enable_race_swap': options.EnableRaceSwapVariants.option_shuffle_all,
'kerrigan_max_active_abilities': target_number,
}
self.generate_world(world_options)
world_item_names = [item.name for item in self.multiworld.itempool]
kerrigan_actives = [item_name for item_name in world_item_names if item_name in item_groups.kerrigan_active_abilities]
self.assertLessEqual(len(kerrigan_actives), target_number)
def test_kerrigan_max_passive_abilities(self):
target_number: int = 3
world_options = {
**self.ALL_CAMPAIGNS,
'mission_order': options.MissionOrder.option_grid,
'maximum_campaign_size': options.MaximumCampaignSize.range_end,
'selected_races': {
SC2Race.ZERG.get_title(),
},
'enable_race_swap': options.EnableRaceSwapVariants.option_shuffle_all,
'kerrigan_max_passive_abilities': target_number,
}
self.generate_world(world_options)
world_item_names = [item.name for item in self.multiworld.itempool]
kerrigan_passives = [item_name for item_name in world_item_names if item_name in item_groups.kerrigan_passives]
self.assertLessEqual(len(kerrigan_passives), target_number)
def test_spear_of_adun_max_active_abilities(self):
target_number: int = 8
world_options = {
**self.ALL_CAMPAIGNS,
'mission_order': options.MissionOrder.option_grid,
'maximum_campaign_size': options.MaximumCampaignSize.range_end,
'selected_races': {
SC2Race.PROTOSS.get_title(),
},
'enable_race_swap': options.EnableRaceSwapVariants.option_shuffle_all,
'spear_of_adun_max_active_abilities': target_number,
}
self.generate_world(world_options)
world_item_names = [item.name for item in self.multiworld.itempool]
spear_of_adun_actives = [item_name for item_name in world_item_names if item_name in item_tables.spear_of_adun_calldowns]
self.assertLessEqual(len(spear_of_adun_actives), target_number)
def test_spear_of_adun_max_autocasts(self):
target_number: int = 2
world_options = {
**self.ALL_CAMPAIGNS,
'mission_order': options.MissionOrder.option_grid,
'maximum_campaign_size': options.MaximumCampaignSize.range_end,
'selected_races': {
SC2Race.PROTOSS.get_title(),
},
'enable_race_swap': options.EnableRaceSwapVariants.option_shuffle_all,
'spear_of_adun_max_passive_abilities': target_number,
}
self.generate_world(world_options)
world_item_names = [item.name for item in self.multiworld.itempool]
spear_of_adun_autocasts = [item_name for item_name in world_item_names if item_name in item_tables.spear_of_adun_castable_passives]
self.assertLessEqual(len(spear_of_adun_autocasts), target_number)
def test_nova_max_weapons(self):
target_number: int = 3
world_options = {
**self.ALL_CAMPAIGNS,
'mission_order': options.MissionOrder.option_grid,
'maximum_campaign_size': options.MaximumCampaignSize.range_end,
'selected_races': {
SC2Race.TERRAN.get_title(),
},
'enable_race_swap': options.EnableRaceSwapVariants.option_shuffle_all,
'nova_max_weapons': target_number,
}
self.generate_world(world_options)
world_item_names = [item.name for item in self.multiworld.itempool]
nova_weapons = [item_name for item_name in world_item_names if item_name in item_groups.nova_weapons]
self.assertLessEqual(len(nova_weapons), target_number)
def test_nova_max_gadgets(self):
target_number: int = 3
world_options = {
**self.ALL_CAMPAIGNS,
'mission_order': options.MissionOrder.option_grid,
'maximum_campaign_size': options.MaximumCampaignSize.range_end,
'selected_races': {
SC2Race.TERRAN.get_title(),
},
'enable_race_swap': options.EnableRaceSwapVariants.option_shuffle_all,
'nova_max_gadgets': target_number,
}
self.generate_world(world_options)
world_item_names = [item.name for item in self.multiworld.itempool]
nova_gadgets = [item_name for item_name in world_item_names if item_name in item_groups.nova_gadgets]
self.assertLessEqual(len(nova_gadgets), target_number)
def test_mercs_only(self) -> None:
world_options = {
**self.ALL_CAMPAIGNS,
'selected_races': [
SC2Race.TERRAN.get_title(),
SC2Race.ZERG.get_title(),
],
'required_tactics': options.RequiredTactics.option_any_units,
'excluded_items': {
item_groups.ItemGroupNames.TERRAN_UNITS: 0,
item_groups.ItemGroupNames.ZERG_UNITS: 0,
},
'unexcluded_items': {
item_groups.ItemGroupNames.TERRAN_MERCENARIES: 0,
item_groups.ItemGroupNames.ZERG_MERCENARIES: 0,
},
'start_inventory': {
item_names.PROGRESSIVE_FAST_DELIVERY: 1,
item_names.ROGUE_FORCES: 1,
item_names.UNRESTRICTED_MUTATION: 1,
item_names.EVOLUTIONARY_LEAP: 1,
},
'mission_order': options.MissionOrder.option_grid,
'excluded_missions': [
SC2Mission.ENEMY_WITHIN.mission_name, # Requires a unit for Niadra to build
],
}
self.generate_world(world_options)
world_item_names = [item.name for item in self.multiworld.itempool]
terran_nonmerc_units = tuple(
item_name
for item_name in world_item_names
if item_name in item_groups.terran_units and item_name not in item_groups.terran_mercenaries
)
zerg_nonmerc_units = tuple(
item_name
for item_name in world_item_names
if item_name in item_groups.zerg_units and item_name not in item_groups.zerg_mercenaries
)
self.assertTupleEqual(terran_nonmerc_units, ())
self.assertTupleEqual(zerg_nonmerc_units, ())
def test_zerg_hots_no_terran_items(self) -> None:
# The actual situation the bug got caught
world_options = {
'basebust_locations': BasebustLocations.option_enabled,
'challenge_locations': ChallengeLocations.option_enabled,
'difficulty_curve': DifficultyCurve.option_standard,
'enable_morphling': EnableMorphling.option_false,
'enable_race_swap': EnableRaceSwapVariants.option_disabled,
'enabled_campaigns': [SC2Campaign.HOTS.campaign_name],
'ensure_generic_items': 25,
'exclude_overpowered_items': ExcludeOverpoweredItems.option_false,
'exclude_very_hard_missions': ExcludeVeryHardMissions.option_default,
'excluded_missions': [
SC2Mission.SUPREME.mission_name
],
'extra_locations': ExtraLocations.option_enabled,
'generic_upgrade_items': GenericUpgradeItems.option_individual_items,
'generic_upgrade_missions': 0,
'generic_upgrade_research': GenericUpgradeResearch.option_auto_in_no_build,
'generic_upgrade_research_speedup': GenericUpgradeResearchSpeedup.option_false,
'grant_story_levels': GrantStoryLevels.option_disabled,
'grant_story_tech': GrantStoryTech.option_no_grant,
'kerrigan_level_item_distribution': KerriganLevelItemDistribution.option_size_14,
'kerrigan_level_item_sum': 86,
'kerrigan_levels_per_mission_completed': 0,
'kerrigan_levels_per_mission_completed_cap': -1,
'kerrigan_max_active_abilities': 12,
'kerrigan_max_passive_abilities': 5,
'kerrigan_presence': KerriganPresence.option_vanilla,
'kerrigan_primal_status': KerriganPrimalStatus.option_vanilla,
'kerrigan_total_level_cap': -1,
'key_mode': KeyMode.option_progressive_questlines,
'mastery_locations': MasteryLocations.option_disabled,
'max_number_of_upgrades': -1,
'max_upgrade_level': 4,
'maximum_campaign_size': 40,
'min_number_of_upgrades': 2,
'mission_order': MissionOrder.option_mini_campaign,
'mission_order_scouting': MissionOrderScouting.option_none,
'mission_race_balancing': EnableMissionRaceBalancing.option_semi_balanced,
'nova_ghost_of_a_chance_variant': NovaGhostOfAChanceVariant.option_wol,
'preventative_locations': PreventativeLocations.option_enabled,
'required_tactics': RequiredTactics.option_standard,
'shuffle_campaigns': ShuffleCampaigns.option_true,
'shuffle_no_build': ShuffleNoBuild.option_true,
'speedrun_locations': SpeedrunLocations.option_disabled,
'start_primary_abilities': 0,
'starter_unit': StarterUnit.option_balanced,
'starting_supply_per_item': 2,
'take_over_ai_allies': TakeOverAIAllies.option_false,
'vanilla_items_only': VanillaItemsOnly.option_false,
'victory_cache': 0,
}
self.generate_world(world_options)
world_item_names = [item.name for item in self.multiworld.itempool]
self.assertNotIn(item_names.COMMAND_CENTER_SCANNER_SWEEP, world_item_names)
self.assertNotIn(item_names.COMMAND_CENTER_EXTRA_SUPPLIES, world_item_names)
self.assertNotIn(item_names.ULTRA_CAPACITORS, world_item_names)
self.assertNotIn(item_names.ORBITAL_DEPOTS, world_item_names)
self.assertNotIn(item_names.DOMINION_TROOPER, world_item_names)
def test_all_kerrigan_missions_are_nobuild_and_grant_story_tech_is_on(self) -> None:
# The actual situation the bug got caught
world_options = {
'mission_order': MissionOrder.option_vanilla_shuffled,
'selected_races': [
SC2Race.TERRAN.get_title(),
SC2Race.ZERG.get_title(),
SC2Race.PROTOSS.get_title(),
],
'enabled_campaigns': [
SC2Campaign.WOL.campaign_name,
SC2Campaign.PROPHECY.campaign_name,
SC2Campaign.HOTS.campaign_name,
SC2Campaign.PROLOGUE.campaign_name,
SC2Campaign.LOTV.campaign_name,
SC2Campaign.EPILOGUE.campaign_name,
SC2Campaign.NCO.campaign_name,
],
'enable_race_swap': EnableRaceSwapVariants.option_shuffle_all_non_vanilla, # Causes no build Kerrigan missions to be present, only nobuilds remain
'shuffle_campaigns': ShuffleCampaigns.option_true,
'shuffle_no_build': ShuffleNoBuild.option_true,
'starter_unit': StarterUnit.option_balanced,
'required_tactics': RequiredTactics.option_standard,
'kerrigan_presence': KerriganPresence.option_vanilla,
'kerrigan_levels_per_mission_completed': 0,
'kerrigan_levels_per_mission_completed_cap': -1,
'kerrigan_level_item_sum': 87,
'kerrigan_level_item_distribution': KerriganLevelItemDistribution.option_size_7,
'kerrigan_total_level_cap': -1,
'start_primary_abilities': 0,
'grant_story_tech': GrantStoryTech.option_grant,
'grant_story_levels': GrantStoryLevels.option_additive,
}
self.generate_world(world_options)
# Just check that the world itself generates under those rules and no exception is thrown