sc2: Fixing random fill errors in unit tests (#6045)

This commit is contained in:
Phaneros
2026-03-27 14:45:38 -07:00
committed by GitHub
parent 116ab2286a
commit 4276c6d6b0
9 changed files with 154 additions and 88 deletions

View File

@@ -156,15 +156,17 @@ This page includes all data associated with all games.
## How do I join a MultiWorld game?
1. Run ArchipelagoStarcraft2Client.exe.
1. Run ArchipelagoLauncher.exe.
- macOS users should instead follow the instructions found at ["Running in macOS"](#running-in-macos) for this step
only.
2. In the Archipelago tab, type `/connect [server IP]`.
2. Search for the Starcraft 2 Client in the launcher to open the game-specific client
- Alternatively, steps 1 and 2 can be combined by providing the `"Starcraft 2 Client"` launch argument to the launcher.
3. In the Archipelago tab, type `/connect [server IP]`.
- If you're running through the website, the server IP should be displayed near the top of the room page.
- The server IP may also be typed into the top bar, and then clicking "Connect"
3. Type your slot name from your YAML when prompted.
4. If the server has a password, enter that when prompted.
5. Once connected, switch to the 'StarCraft 2 Launcher' tab in the client. There, you can see all the missions in your
4. Type your slot name from your YAML when prompted.
5. If the server has a password, enter that when prompted.
6. Once connected, switch to the 'StarCraft 2 Launcher' tab in the client. There, you can see all the missions in your
world.
Unreachable missions will have greyed-out text. Completed missions (all locations collected) will have white text.
@@ -173,7 +175,22 @@ Mission buttons will have a color corresponding to the faction you play as in th
Click on an available mission to start it.
## The game isn't launching when I try to start a mission.
## Troubleshooting
### I can't connect to my seed.
Rooms on the Archipelago website go to sleep after two hours of inactivity; reload or refresh the room page
to start them back up.
When restarting the room, the connection port may change (the numbers after "archipelago.gg:"),
make sure that is accurate.
Your slot name should be displayed on the room page as well; make sure that exactly matches the slot name you
type into your client, and note that it is case-sensitive.
If none of these things solve the problem, visit the [Discord](https://discord.com/invite/8Z65BR2) and check
the #software-announcements channel to see if there's a listed outage, or visit the #starcraft-2 channel for
tech support.
### The game isn't launching when I try to start a mission.
Usually, this is caused by the mod files not being downloaded.
Make sure you have run `/download_data` in the Archipelago tab before playing.
@@ -183,12 +200,12 @@ Make sure that you are running an up-to-date version of the client.
Check the [Archipelago Releases Page](https://github.com/ArchipelagoMW/Archipelago/releases) to
look up what the latest version is (RC releases are not necessary; that stands for "Release Candidate").
If these things are in order, check the log file for issues (stored at `[Archipelago Directory]/logs/Starcraft2Client.txt`).
If these things are in order, check the log file for issues (stored at `[Archipelago Directory]/logs/SC2Client_<date>.txt`).
If you can't figure out the log file, visit our [Discord's](https://discord.com/invite/8Z65BR2) tech-support channel
for help.
Please include a specific description of what's going wrong and attach your log file to your message.
## My keyboard shortcuts profile is not available when I play *StarCraft 2 Archipelago*.
### My keyboard shortcuts profile is not available when I play *StarCraft 2 Archipelago*.
For your keyboard shortcuts profile to work in Archipelago, you need to copy your shortcuts file from
`Documents/StarCraft II/Accounts/######/Hotkeys` to `Documents/StarCraft II/Hotkeys`.

View File

@@ -249,7 +249,6 @@ def get_locations(world: Optional["SC2World"]) -> Tuple[LocationData, ...]:
LocationType.VICTORY,
lambda state: (
logic.terran_common_unit(state)
and logic.terran_defense_rating(state, True) >= 2
and (adv_tactics or logic.terran_basic_anti_air(state))
),
),
@@ -271,10 +270,7 @@ def get_locations(world: Optional["SC2World"]) -> Tuple[LocationData, ...]:
"Third Group Rescued",
SC2WOL_LOC_ID_OFFSET + 303,
LocationType.VANILLA,
lambda state: (
logic.terran_common_unit(state)
and logic.terran_defense_rating(state, True) >= 2
),
logic.terran_common_unit,
),
make_location_data(
SC2Mission.ZERO_HOUR.mission_name,
@@ -320,20 +316,14 @@ def get_locations(world: Optional["SC2World"]) -> Tuple[LocationData, ...]:
"Hold Just a Little Longer",
SC2WOL_LOC_ID_OFFSET + 309,
LocationType.EXTRA,
lambda state: (
logic.terran_common_unit(state)
and logic.terran_defense_rating(state, True) >= 2
),
logic.terran_common_unit,
),
make_location_data(
SC2Mission.ZERO_HOUR.mission_name,
"Cavalry's on the Way",
SC2WOL_LOC_ID_OFFSET + 310,
LocationType.EXTRA,
lambda state: (
logic.terran_common_unit(state)
and logic.terran_defense_rating(state, True) >= 2
),
logic.terran_common_unit,
),
make_location_data(
SC2Mission.EVACUATION.mission_name,

View File

@@ -182,7 +182,7 @@ class ValidInventory:
del self.logical_inventory[item.name]
item.filter_flags |= remove_flag
return ""
def remove_child_items(
parent_item: StarcraftItem,
remove_flag: ItemFilterFlags = ItemFilterFlags.FilterExcluded,
@@ -247,13 +247,13 @@ class ValidInventory:
# Limit the maximum number of upgrades
if max_upgrades_per_unit != -1:
for group_name, group_items in group_to_item.items():
self.world.random.shuffle(group_to_item[group])
for group_items in group_to_item.values():
self.world.random.shuffle(group_items)
cull_items_over_maximum(group_items, max_upgrades_per_unit)
# Requesting minimum upgrades for items that have already been locked/placed when minimum required
if min_upgrades_per_unit != -1:
for group_name, group_items in group_to_item.items():
for group_items in group_to_item.values():
self.world.random.shuffle(group_items)
request_minimum_items(group_items, min_upgrades_per_unit)
@@ -349,7 +349,7 @@ class ValidInventory:
ItemFilterFlags.Removed not in item.filter_flags
and ((ItemFilterFlags.Unexcludable|ItemFilterFlags.Excluded) & item.filter_flags) != ItemFilterFlags.Excluded
)
# Actually remove culled items; we won't re-add them
inventory = [
item for item in inventory
@@ -373,7 +373,7 @@ class ValidInventory:
item for item in cullable_items
if not ((ItemFilterFlags.Removed|ItemFilterFlags.Uncullable) & item.filter_flags)
]
# Handle too many requested
if current_inventory_size - start_inventory_size > inventory_size - filler_amount:
for item in inventory:
@@ -414,7 +414,7 @@ class ValidInventory:
removable_transport_hooks = [item for item in inventory_transport_hooks if not (ItemFilterFlags.Unexcludable & item.filter_flags)]
if len(inventory_transport_hooks) > 1 and removable_transport_hooks:
inventory.remove(removable_transport_hooks[0])
# Weapon/Armour upgrades
def exclude_wa(prefix: str) -> List[StarcraftItem]:
return [
@@ -439,7 +439,7 @@ class ValidInventory:
inventory = exclude_wa(item_names.PROTOSS_GROUND_UPGRADE_PREFIX)
if used_item_names.isdisjoint(item_groups.protoss_air_wa):
inventory = exclude_wa(item_names.PROTOSS_AIR_UPGRADE_PREFIX)
# Part 4: Last-ditch effort to reduce inventory size; upgrades can go in start inventory
current_inventory_size = len(inventory)
precollect_items = current_inventory_size - inventory_size - start_inventory_size - filler_amount
@@ -453,7 +453,7 @@ class ValidInventory:
for item in promotable[:precollect_items]:
item.filter_flags |= ItemFilterFlags.StartInventory
start_inventory_size += 1
assert current_inventory_size - start_inventory_size <= inventory_size - filler_amount, (
f"Couldn't reduce inventory to fit. target={inventory_size}, poolsize={current_inventory_size}, "
f"start_inventory={starcraft_item}, filler_amount={filler_amount}"

View File

@@ -129,7 +129,7 @@ def adjust_mission_pools(world: 'SC2World', pools: SC2MOGenMissionPools):
if grant_story_tech == GrantStoryTech.option_grant:
# Additional starter mission if player is granted story tech
pools.move_mission(SC2Mission.ENEMY_WITHIN, Difficulty.EASY, Difficulty.STARTER)
pools.move_mission(SC2Mission.THE_ESCAPE, Difficulty.MEDIUM, Difficulty.STARTER)
pools.move_mission(SC2Mission.THE_ESCAPE, Difficulty.EASY, Difficulty.STARTER)
pools.move_mission(SC2Mission.IN_THE_ENEMY_S_SHADOW, Difficulty.MEDIUM, Difficulty.STARTER)
if not war_council_nerfs or grant_story_tech == GrantStoryTech.option_grant:
pools.move_mission(SC2Mission.TEMPLAR_S_RETURN, Difficulty.MEDIUM, Difficulty.STARTER)

View File

@@ -1660,11 +1660,11 @@ class SC2Logic:
Created mainly for engine of destruction start, but works for other missions with no-build starts.
"""
return state.has_any((
item_names.ZEALOT_WHIRLWIND,
item_names.SENTRY_DOUBLE_SHIELD_RECHARGE,
item_names.SLAYER_PHASE_BLINK,
item_names.STALKER_INSTIGATOR_SLAYER_DISINTEGRATING_PARTICLES,
item_names.STALKER_INSTIGATOR_SLAYER_PARTICLE_REFLECTION,
item_names.ZEALOT_WHIRLWIND,
item_names.SENTRY_DOUBLE_SHIELD_RECHARGE,
item_names.SLAYER_PHASE_BLINK,
item_names.STALKER_INSTIGATOR_SLAYER_DISINTEGRATING_PARTICLES,
item_names.STALKER_INSTIGATOR_SLAYER_PARTICLE_REFLECTION,
), self.player)
# Mission-specific rules

View File

@@ -0,0 +1,52 @@
"""
Slow-running tests that are run infrequently.
Run this file explicitly with `python3 -m unittest worlds.sc2.test.slow_tests`
"""
from .test_base import Sc2SetupTestBase
from Fill import FillError
from .. import mission_tables, options
class LargeTests(Sc2SetupTestBase):
def test_any_starter_mission_works(self) -> None:
base_options = {
options.OPTION_NAME[options.SelectedRaces]: list(options.SelectedRaces.valid_keys),
options.OPTION_NAME[options.RequiredTactics]: options.RequiredTactics.option_standard,
options.OPTION_NAME[options.MissionOrder]: options.MissionOrder.option_custom,
options.OPTION_NAME[options.ExcludeOverpoweredItems]: True,
# options.OPTION_NAME[options.ExtraLocations]: options.ExtraLocations.option_disabled,
options.OPTION_NAME[options.VanillaLocations]: options.VanillaLocations.option_disabled,
}
missions_to_check = [
mission for mission in mission_tables.SC2Mission
if mission.pool == mission_tables.MissionPools.STARTER
]
failed_missions: list[tuple[mission_tables.SC2Mission, int]] = []
NUM_ATTEMPTS = 3
for mission in missions_to_check:
for attempt in range(NUM_ATTEMPTS):
mission_options = base_options | {
options.OPTION_NAME[options.CustomMissionOrder]: {
"Test Campaign": {
"Test Layout": {
"type": "hopscotch",
"size": 25,
"goal": True,
"missions": [
{"index": 0, "mission_pool": [mission.mission_name]}
]
}
}
}
}
try:
self.generate_world(mission_options)
self.fill_after_generation()
assert self.multiworld.worlds[1].custom_mission_order.get_starting_missions()[0] == mission
except FillError as ex:
failed_missions.append((mission, self.multiworld.seed))
if failed_missions:
for failed_mission in failed_missions:
print(failed_mission)
self.assertFalse(failed_missions)

View File

@@ -1,4 +1,4 @@
from typing import *
from typing import Any, cast
import unittest
import random
from argparse import Namespace
@@ -6,18 +6,11 @@ from BaseClasses import MultiWorld, CollectionState, PlandoOptions
from Generate import get_seed_name
from worlds import AutoWorld
from test.general import gen_steps, call_all
from Fill import distribute_items_restrictive
from test.bases import WorldTestBase
from .. import SC2World, SC2Campaign
from .. import client
from .. import options
class Sc2TestBase(WorldTestBase):
game = client.SC2Context.game
world: SC2World
player: ClassVar[int] = 1
skip_long_tests: bool = True
class Sc2SetupTestBase(unittest.TestCase):
"""
@@ -37,10 +30,11 @@ class Sc2SetupTestBase(unittest.TestCase):
PROTOSS_CAMPAIGNS = {
'enabled_campaigns': {SC2Campaign.PROPHECY.campaign_name, SC2Campaign.PROLOGUE.campaign_name, SC2Campaign.LOTV.campaign_name,}
}
seed: Optional[int] = None
seed: int | None = None
game = SC2World.game
player = 1
def generate_world(self, options: Dict[str, Any]) -> None:
def generate_world(self, options: dict[str, Any]) -> None:
self.multiworld = MultiWorld(1)
self.multiworld.game[self.player] = self.game
self.multiworld.player_name = {self.player: "Tester"}
@@ -63,3 +57,11 @@ class Sc2SetupTestBase(unittest.TestCase):
except Exception as ex:
ex.add_note(f"Seed: {self.multiworld.seed}")
raise
def fill_after_generation(self) -> None:
assert self.multiworld
try:
distribute_items_restrictive(self.multiworld)
except Exception as ex:
ex.add_note(f"Seed: {self.multiworld.seed}")
raise

View File

@@ -1,20 +1,24 @@
"""
Unit tests for world generation
"""
from typing import *
from typing import Any
from .test_base import Sc2SetupTestBase
from .. import mission_groups, mission_tables, options, locations, SC2Mission, SC2Campaign, SC2Race, unreleased_items, \
RequiredTactics
from .. import (
mission_groups, mission_tables, options, locations,
SC2Mission, SC2Campaign, SC2Race, unreleased_items,
RequiredTactics,
)
from ..item import item_groups, item_tables, item_names
from .. import get_all_missions, get_random_first_mission
from ..options import EnabledCampaigns, NovaGhostOfAChanceVariant, MissionOrder, ExcludeOverpoweredItems, \
VanillaItemsOnly, MaximumCampaignSize
from ..options import (
EnabledCampaigns, NovaGhostOfAChanceVariant, MissionOrder, ExcludeOverpoweredItems,
VanillaItemsOnly, MaximumCampaignSize,
)
class TestItemFiltering(Sc2SetupTestBase):
def test_explicit_locks_excludes_interact_and_set_flags(self):
def test_explicit_locks_excludes_interact_and_set_flags(self) -> None:
world_options = {
**self.ALL_CAMPAIGNS,
'locked_items': {
@@ -46,7 +50,7 @@ class TestItemFiltering(Sc2SetupTestBase):
regen_biosteel_items = [x for x in itempool if x == item_names.PROGRESSIVE_REGENERATIVE_BIO_STEEL]
self.assertEqual(len(regen_biosteel_items), 2)
def test_unexcludes_cancel_out_excludes(self):
def test_unexcludes_cancel_out_excludes(self) -> None:
world_options = {
'grant_story_tech': options.GrantStoryTech.option_grant,
'excluded_items': {
@@ -121,7 +125,7 @@ class TestItemFiltering(Sc2SetupTestBase):
itempool = [item.name for item in self.multiworld.itempool]
self.assertNotIn(item_names.MARINE, itempool)
def test_excluding_groups_excludes_all_items_in_group(self):
def test_excluding_groups_excludes_all_items_in_group(self) -> None:
world_options = {
'excluded_items': {
item_groups.ItemGroupNames.BARRACKS_UNITS.lower(): -1,
@@ -133,7 +137,7 @@ class TestItemFiltering(Sc2SetupTestBase):
for item_name in item_groups.barracks_units:
self.assertNotIn(item_name, itempool)
def test_excluding_mission_groups_excludes_all_missions_in_group(self):
def test_excluding_mission_groups_excludes_all_missions_in_group(self) -> None:
world_options = {
**self.ZERG_CAMPAIGNS,
'enable_race_swap': options.EnableRaceSwapVariants.option_shuffle_all,
@@ -164,7 +168,7 @@ class TestItemFiltering(Sc2SetupTestBase):
self.assertNotEqual(item_data.type, item_tables.TerranItemType.Nova_Gear)
self.assertNotEqual(item_name, item_names.NOVA_PROGRESSIVE_STEALTH_SUIT_MODULE)
def test_starter_unit_populates_start_inventory(self):
def test_starter_unit_populates_start_inventory(self) -> None:
world_options = {
'enabled_campaigns': {
SC2Campaign.WOL.campaign_name,
@@ -308,7 +312,7 @@ class TestItemFiltering(Sc2SetupTestBase):
self.generate_world(world_options)
world_items = [(item.name, item_tables.item_table[item.name]) for item in self.multiworld.itempool]
self.assertTrue(world_items)
occurrences: Dict[str, int] = {}
occurrences: dict[str, int] = {}
for item_name, _ in world_items:
if item_name in item_groups.terran_progressive_items:
if item_name in item_groups.nova_equipment:
@@ -528,7 +532,7 @@ class TestItemFiltering(Sc2SetupTestBase):
Orbital command got replaced. The item is still there for backwards compatibility.
It shouldn't be generated.
"""
world_options = {}
world_options: dict[str, Any] = {}
self.generate_world(world_options)
itempool = [item.name for item in self.multiworld.itempool]
@@ -595,7 +599,7 @@ class TestItemFiltering(Sc2SetupTestBase):
self.assertIn(speedrun_location_name, all_location_names)
self.assertNotIn(speedrun_location_name, world_location_names)
def test_nco_and_wol_picks_correct_starting_mission(self):
def test_nco_and_wol_picks_correct_starting_mission(self) -> None:
world_options = {
'mission_order': MissionOrder.option_vanilla,
'enabled_campaigns': {
@@ -606,7 +610,7 @@ class TestItemFiltering(Sc2SetupTestBase):
self.generate_world(world_options)
self.assertEqual(get_random_first_mission(self.world, self.world.custom_mission_order), mission_tables.SC2Mission.LIBERATION_DAY)
def test_excluding_mission_short_name_excludes_all_variants_of_mission(self):
def test_excluding_mission_short_name_excludes_all_variants_of_mission(self) -> None:
world_options = {
'excluded_missions': [
mission_tables.SC2Mission.ZERO_HOUR.mission_name.split(" (")[0]
@@ -625,7 +629,7 @@ class TestItemFiltering(Sc2SetupTestBase):
self.assertNotIn(mission_tables.SC2Mission.ZERO_HOUR_Z, missions)
self.assertNotIn(mission_tables.SC2Mission.ZERO_HOUR_P, missions)
def test_excluding_mission_variant_excludes_just_that_variant(self):
def test_excluding_mission_variant_excludes_just_that_variant(self) -> None:
world_options = {
'excluded_missions': [
mission_tables.SC2Mission.ZERO_HOUR.mission_name
@@ -644,7 +648,7 @@ class TestItemFiltering(Sc2SetupTestBase):
self.assertIn(mission_tables.SC2Mission.ZERO_HOUR_Z, missions)
self.assertIn(mission_tables.SC2Mission.ZERO_HOUR_P, missions)
def test_weapon_armor_upgrades(self):
def test_weapon_armor_upgrades(self) -> None:
world_options = {
# Vanilla WoL with all missions
'mission_order': options.MissionOrder.option_vanilla,
@@ -682,7 +686,7 @@ class TestItemFiltering(Sc2SetupTestBase):
self.assertGreaterEqual(len(vehicle_weapon_items), 3)
self.assertEqual(len(other_bundle_items), 0)
def test_weapon_armor_upgrades_with_bundles(self):
def test_weapon_armor_upgrades_with_bundles(self) -> None:
world_options = {
# Vanilla WoL with all missions
'mission_order': options.MissionOrder.option_vanilla,
@@ -720,7 +724,7 @@ class TestItemFiltering(Sc2SetupTestBase):
self.assertGreaterEqual(len(vehicle_upgrade_items), 3)
self.assertEqual(len(other_bundle_items), 0)
def test_weapon_armor_upgrades_all_in_air(self):
def test_weapon_armor_upgrades_all_in_air(self) -> None:
world_options = {
# Vanilla WoL with all missions
'mission_order': options.MissionOrder.option_vanilla,
@@ -753,7 +757,7 @@ class TestItemFiltering(Sc2SetupTestBase):
self.assertGreaterEqual(len(vehicle_weapon_items), 3)
self.assertGreaterEqual(len(ship_weapon_items), 3)
def test_weapon_armor_upgrades_generic_upgrade_missions(self):
def test_weapon_armor_upgrades_generic_upgrade_missions(self) -> None:
"""
Tests the case when there aren't enough missions in order to get required weapon/armor upgrades
for logic requirements.
@@ -782,7 +786,7 @@ class TestItemFiltering(Sc2SetupTestBase):
# Under standard tactics you need to place L3 upgrades for available unit classes
self.assertEqual(len(upgrade_items), 3)
def test_weapon_armor_upgrades_generic_upgrade_missions_no_logic(self):
def test_weapon_armor_upgrades_generic_upgrade_missions_no_logic(self) -> None:
"""
Tests the case when there aren't enough missions in order to get required weapon/armor upgrades
for logic requirements.
@@ -813,7 +817,7 @@ class TestItemFiltering(Sc2SetupTestBase):
# No logic won't take the fallback to trigger
self.assertEqual(len(upgrade_items), 0)
def test_weapon_armor_upgrades_generic_upgrade_missions_no_countermeasure_needed(self):
def test_weapon_armor_upgrades_generic_upgrade_missions_no_countermeasure_needed(self) -> None:
world_options = {
# Vanilla WoL with all missions
'mission_order': options.MissionOrder.option_vanilla,
@@ -837,7 +841,7 @@ class TestItemFiltering(Sc2SetupTestBase):
# No additional starting inventory item placement is needed
self.assertEqual(len(upgrade_items), 0)
def test_kerrigan_levels_per_mission_triggering_pre_fill(self):
def test_kerrigan_levels_per_mission_triggering_pre_fill(self) -> None:
world_options = {
**self.ALL_CAMPAIGNS,
'mission_order': options.MissionOrder.option_custom,
@@ -878,7 +882,7 @@ class TestItemFiltering(Sc2SetupTestBase):
self.assertGreater(len(kerrigan_1_stacks), 0)
def test_kerrigan_levels_per_mission_and_generic_upgrades_both_triggering_pre_fill(self):
def test_kerrigan_levels_per_mission_and_generic_upgrades_both_triggering_pre_fill(self) -> None:
world_options = {
**self.ALL_CAMPAIGNS,
'mission_order': options.MissionOrder.option_custom,
@@ -925,7 +929,7 @@ class TestItemFiltering(Sc2SetupTestBase):
self.assertNotIn(item_names.KERRIGAN_LEVELS_70, itempool)
self.assertNotIn(item_names.KERRIGAN_LEVELS_70, starting_inventory)
def test_locking_required_items(self):
def test_locking_required_items(self) -> None:
world_options = {
**self.ALL_CAMPAIGNS,
'mission_order': options.MissionOrder.option_custom,
@@ -962,7 +966,7 @@ class TestItemFiltering(Sc2SetupTestBase):
self.assertIn(item_names.KERRIGAN_MEND, itempool)
def test_fully_balanced_mission_races(self):
def test_fully_balanced_mission_races(self) -> None:
"""
Tests whether fully balanced mission race balancing actually is fully balanced.
"""
@@ -1080,7 +1084,7 @@ class TestItemFiltering(Sc2SetupTestBase):
self.generate_world(world_options)
itempool = [item.name for item in self.multiworld.itempool]
upgrade_item_counts: Dict[str, int] = {}
upgrade_item_counts: dict[str, int] = {}
for item_name in itempool:
if item_tables.item_table[item_name].type in (
item_tables.TerranItemType.Upgrade,
@@ -1252,7 +1256,7 @@ class TestItemFiltering(Sc2SetupTestBase):
self.generate_world(world_options)
itempool = [item.name for item in self.multiworld.itempool]
items_to_check: List[str] = unreleased_items
items_to_check: list[str] = unreleased_items
for item in items_to_check:
self.assertNotIn(item, itempool)
@@ -1273,7 +1277,7 @@ class TestItemFiltering(Sc2SetupTestBase):
self.generate_world(world_options)
itempool = [item.name for item in self.multiworld.itempool]
items_to_check: List[str] = unreleased_items
items_to_check: list[str] = unreleased_items
for item in items_to_check:
self.assertIn(item, itempool)

View File

@@ -1,9 +1,10 @@
import unittest
from .test_base import Sc2TestBase
from .test_base import Sc2SetupTestBase
from .. import mission_tables, SC2Campaign
from .. import options
from ..mission_order.layout_types import Grid
class TestGridsizes(unittest.TestCase):
def test_grid_sizes_meet_specs(self):
self.assertTupleEqual((1, 2, 0), Grid.get_grid_dimensions(2))
@@ -24,17 +25,17 @@ class TestGridsizes(unittest.TestCase):
self.assertTupleEqual((5, 7, 2), Grid.get_grid_dimensions(33))
class TestGridGeneration(Sc2TestBase):
options = {
"mission_order": options.MissionOrder.option_grid,
"excluded_missions": [mission_tables.SC2Mission.ZERO_HOUR.mission_name,],
"enabled_campaigns": {
SC2Campaign.WOL.campaign_name,
SC2Campaign.PROPHECY.campaign_name,
}
}
class TestGridGeneration(Sc2SetupTestBase):
def test_size_matches_exclusions(self):
world_options = {
options.OPTION_NAME[options.MissionOrder]: options.MissionOrder.option_grid,
options.OPTION_NAME[options.ExcludedMissions]: [mission_tables.SC2Mission.ZERO_HOUR.mission_name],
options.OPTION_NAME[options.EnabledCampaigns]: {
SC2Campaign.WOL.campaign_name,
SC2Campaign.PROPHECY.campaign_name,
}
}
self.generate_world(world_options)
self.assertNotIn(mission_tables.SC2Mission.ZERO_HOUR.mission_name, self.multiworld.regions)
# WoL has 29 missions. -1 for Zero Hour being excluded, +1 for the automatically-added menu location
self.assertEqual(len(self.multiworld.regions), 29)