Skip to content

Commit

Permalink
sc2: Many typing and style fixes; fixed some broken logic functions
Browse files Browse the repository at this point in the history
  • Loading branch information
MatthewMarinets committed Dec 11, 2024
1 parent 93273ed commit 7d65aaa
Show file tree
Hide file tree
Showing 9 changed files with 65 additions and 116 deletions.
26 changes: 15 additions & 11 deletions worlds/sc2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class SC2World(World):
options_dataclass = Starcraft2Options
options: Starcraft2Options

item_name_groups = item_groups.item_name_groups
item_name_groups = item_groups.item_name_groups # type: ignore
location_name_groups = location_groups.get_location_groups()
locked_locations: List[str]
"""Locations locked to contain specific items, such as victory events or forced resources"""
Expand Down Expand Up @@ -568,7 +568,7 @@ def flag_start_inventory(world: SC2World, item_list: List[FilterItem]) -> None:


def flag_start_unit(world: SC2World, item_list: List[FilterItem], starter_unit: int) -> None:
first_mission = get_first_mission(world, world.custom_mission_order)
first_mission = get_random_first_mission(world, world.custom_mission_order)
first_race = first_mission.race

if first_race == SC2Race.ANY:
Expand All @@ -585,7 +585,7 @@ def flag_start_unit(world: SC2World, item_list: List[FilterItem], starter_unit:
}

# The race of the early unit has been chosen
basic_units = get_basic_units(world, first_race)
basic_units = get_basic_units(world.options.required_tactics.value, first_race)
if starter_unit == StarterUnit.option_balanced:
basic_units = basic_units.difference(not_balanced_starting_units)
if first_mission == SC2Mission.DARK_WHISPERS:
Expand Down Expand Up @@ -678,7 +678,7 @@ def flag_start_abilities(world: SC2World, item_list: List[FilterItem]) -> None:
def flag_unused_upgrade_types(world: SC2World, item_list: List[FilterItem]) -> None:
"""Excludes +armour/attack upgrades based on generic upgrade strategy."""
include_upgrades = world.options.generic_upgrade_missions == 0
upgrade_items: GenericUpgradeItems = world.options.generic_upgrade_items
upgrade_items = world.options.generic_upgrade_items.value
for item in item_list:
if item.data.type in item_tables.upgrade_item_types:
if not include_upgrades or (item.name not in upgrade_included_names[upgrade_items]):
Expand Down Expand Up @@ -801,14 +801,18 @@ def pad_item_pool_with_filler(self: SC2World, num_items: int, pool: List[Item]):
pool.append(item)


def get_first_mission(world: SC2World, mission_order: SC2MissionOrder) -> SC2Mission:
def get_random_first_mission(world: SC2World, mission_order: SC2MissionOrder) -> SC2Mission:
# Pick an arbitrary lowest-difficulty starer mission
missions = mission_order.get_starting_missions()
missions = [(mission_order.mission_pools.get_modified_mission_difficulty(mission), mission) for mission in missions]
missions.sort(key = lambda difficulty_mission_tuple: difficulty_mission_tuple[0])
(lowest_difficulty, _) = missions[0]
missions = [mission for (difficulty, mission) in missions if difficulty == lowest_difficulty]
return world.random.choice(missions)
starting_missions = mission_order.get_starting_missions()
mission_difficulties = [
(mission_order.mission_pools.get_modified_mission_difficulty(mission), mission)
for mission in starting_missions
]
mission_difficulties.sort(key = lambda difficulty_mission_tuple: difficulty_mission_tuple[0])
(lowest_difficulty, _) = mission_difficulties[0]
first_mission_candidates = [mission for (difficulty, mission) in mission_difficulties if difficulty == lowest_difficulty]
return world.random.choice(first_mission_candidates)


def get_all_missions(mission_order: SC2MissionOrder) -> List[SC2Mission]:
return mission_order.get_used_missions()
Expand Down
6 changes: 3 additions & 3 deletions worlds/sc2/locations.py
Original file line number Diff line number Diff line change
Expand Up @@ -3530,7 +3530,7 @@ def get_locations(world: Optional['SC2World']) -> Tuple[LocationData, ...]:
make_location_data(SC2Mission.MEDIA_BLITZ_Z.mission_name, "Science Facility", SC2_RACESWAP_LOC_ID_OFFSET + 3904, LocationType.VANILLA,
lambda state: (
logic.advanced_tactics
or logic.zerg_competent_comp_competent_aa
or logic.zerg_competent_comp_competent_aa(state)
)
),
make_location_data(SC2Mission.MEDIA_BLITZ_Z.mission_name, "All Barracks", SC2_RACESWAP_LOC_ID_OFFSET + 3905, LocationType.EXTRA,
Expand Down Expand Up @@ -5261,7 +5261,7 @@ def get_locations(world: Optional['SC2World']) -> Tuple[LocationData, ...]:
make_location_data(SC2Mission.UNSEALING_THE_PAST_T.mission_name, "First Stasis Lock", SC2_RACESWAP_LOC_ID_OFFSET + 12702, LocationType.EXTRA,
lambda state: (
logic.advanced_tactics
or logic.terran_unsealing_the_past_requirement
or logic.terran_unsealing_the_past_requirement(state)
)),
make_location_data(SC2Mission.UNSEALING_THE_PAST_T.mission_name, "Second Stasis Lock", SC2_RACESWAP_LOC_ID_OFFSET + 12703, LocationType.EXTRA,
logic.terran_unsealing_the_past_requirement
Expand Down Expand Up @@ -5297,7 +5297,7 @@ def get_locations(world: Optional['SC2World']) -> Tuple[LocationData, ...]:
make_location_data(SC2Mission.UNSEALING_THE_PAST_Z.mission_name, "First Stasis Lock", SC2_RACESWAP_LOC_ID_OFFSET + 12802, LocationType.EXTRA,
lambda state: (
logic.advanced_tactics
or logic.zerg_unsealing_the_past_requirement
or logic.zerg_unsealing_the_past_requirement(state)
)),
make_location_data(SC2Mission.UNSEALING_THE_PAST_Z.mission_name, "Second Stasis Lock", SC2_RACESWAP_LOC_ID_OFFSET + 12803, LocationType.EXTRA,
logic.zerg_unsealing_the_past_requirement
Expand Down
4 changes: 2 additions & 2 deletions worlds/sc2/mission_order/mission_pools.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from enum import IntEnum
from typing import TYPE_CHECKING, Dict, Set, List
from typing import TYPE_CHECKING, Dict, Set, List, Iterable

from ..mission_tables import SC2Mission, lookup_id_to_mission, MissionFlag, SC2Campaign
from worlds.AutoWorld import World
Expand Down Expand Up @@ -63,7 +63,7 @@ def __init__(self) -> None:
self._flag_ratios = {}
self._flag_weights = {}

def set_exclusions(self, excluded: List[SC2Mission], unexcluded: List[SC2Mission]) -> None:
def set_exclusions(self, excluded: Iterable[SC2Mission], unexcluded: Iterable[SC2Mission]) -> None:
"""Prevents all the missions that appear in the `excluded` list, but not in the `unexcluded` list,
from appearing in the mission order."""
total_exclusions = [mission.id for mission in excluded if mission not in unexcluded]
Expand Down
1 change: 1 addition & 0 deletions worlds/sc2/mission_order/structs.py
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ def dict_to_entry_rule(self, data: Dict[str, Any], start_node: MissionOrderNode,
)
missions.extend(exits)
return BeatMissionsEntryRule(missions, visual_reqs)
raise ValueError(f"Invalid data for entry rule: {data}")

def resolve_address(self, address: str, start_node: MissionOrderNode) -> List[MissionOrderNode]:
if address.startswith("../") or address == "..":
Expand Down
6 changes: 3 additions & 3 deletions worlds/sc2/mission_tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ class SC2CampaignGoal(NamedTuple):
SC2Mission.GATES_OF_HELL: f'{SC2Mission.GATES_OF_HELL.mission_name}: Victory',
SC2Mission.SHATTER_THE_SKY: f'{SC2Mission.SHATTER_THE_SKY.mission_name}: Victory'
},
SC2Campaign.PROPHECY: None,
SC2Campaign.PROPHECY: {},
SC2Campaign.HOTS: {
SC2Mission.THE_CRUCIBLE: f'{SC2Mission.THE_CRUCIBLE.mission_name}: Victory',
SC2Mission.HAND_OF_DARKNESS: f'{SC2Mission.HAND_OF_DARKNESS.mission_name}: Victory',
Expand Down Expand Up @@ -496,7 +496,7 @@ def get_goal_location(mission: SC2Mission) -> Union[str, None]:
return primary_campaign_goal.location

campaign_alt_goals = campaign_alt_final_mission_locations[campaign]
if campaign_alt_goals is not None and mission in campaign_alt_goals:
if mission in campaign_alt_goals:
return campaign_alt_goals.get(mission)

return mission.mission_name + ": Victory"
Expand All @@ -513,7 +513,7 @@ def get_campaign_potential_goal_missions(campaign: SC2Campaign) -> List[SC2Missi
if primary_goal_mission is not None:
missions.append(primary_goal_mission.mission)
alt_goal_locations = campaign_alt_final_mission_locations[campaign]
if alt_goal_locations is not None:
if alt_goal_locations:
for mission in alt_goal_locations.keys():
missions.append(mission)

Expand Down
28 changes: 19 additions & 9 deletions worlds/sc2/options.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
from dataclasses import fields, Field
from dataclasses import fields, Field, dataclass
from typing import *

from Options import *
from Options import (
Choice, Toggle, DefaultOnToggle, OptionSet, Range,
PerGameCommonOptions, Option, VerifyKeys,
is_iterable_except_str,
)
from Utils import get_fuzzy_results
from BaseClasses import PlandoOptions
from .mission_tables import (
Expand Down Expand Up @@ -1077,21 +1081,27 @@ class Starcraft2Options(PerGameCommonOptions):

custom_mission_order: CustomMissionOrder

def get_option_value(world: Union['SC2World', None], name: str) -> Union[int, FrozenSet]:
def get_option_value(world: Union['SC2World', None], name: str) -> int:
"""
You should basically never use this unless `world` can be `None`.
Use `world.options.<option_name>.value` instead for better typing, autocomplete, and error messages.
"""
if world is None:
field: Field = [class_field for class_field in fields(Starcraft2Options) if class_field.name == name][0]
if isinstance(field.type, str):
if field.type in globals():
return globals()[field.type].default
import Options
return Options.__dict__[field.type].default
return field.type.default

player_option = getattr(world.options, name)

return player_option.value


def get_enabled_races(world: 'SC2World') -> Set[SC2Race]:
selection = get_option_value(world, 'selected_races')
def get_enabled_races(world: Optional['SC2World']) -> Set[SC2Race]:
selection: int = world.options.selected_races.value if world else SelectRaces.default
if selection == SelectRaces.option_all:
return set(SC2Race)
enabled = {SC2Race.ANY}
Expand All @@ -1104,7 +1114,7 @@ def get_enabled_races(world: 'SC2World') -> Set[SC2Race]:
return enabled


def get_enabled_campaigns(world: 'SC2World') -> Set[SC2Campaign]:
def get_enabled_campaigns(world: Optional['SC2World']) -> Set[SC2Campaign]:
enabled_campaigns = set()
if get_option_value(world, "enable_wol_missions"):
enabled_campaigns.add(SC2Campaign.WOL)
Expand Down Expand Up @@ -1192,15 +1202,15 @@ def get_excluded_missions(world: 'SC2World') -> Set[SC2Mission]:
static_mission_orders = [
MissionOrder.option_vanilla,
MissionOrder.option_vanilla_shuffled,
MissionOrder.option_mini_campaign
MissionOrder.option_mini_campaign,
]

dynamic_mission_orders = [
MissionOrder.option_golden_path,
MissionOrder.option_grid,
MissionOrder.option_gauntlet,
MissionOrder.option_blitz,
MissionOrder.option_hopscotch
MissionOrder.option_hopscotch,
]

LEGACY_GRID_ORDERS = {3, 4, 8} # Medium Grid, Mini Grid, and Tiny Grid respectively
Expand All @@ -1210,7 +1220,7 @@ def get_excluded_missions(world: 'SC2World') -> Set[SC2Mission]:
]

# Names of upgrades to be included for different options
upgrade_included_names: Dict[GenericUpgradeItems, Set[str]] = {
upgrade_included_names: Dict[int, Set[str]] = {
GenericUpgradeItems.option_individual_items: {
item_names.PROGRESSIVE_TERRAN_INFANTRY_WEAPON,
item_names.PROGRESSIVE_TERRAN_INFANTRY_ARMOR,
Expand Down
8 changes: 4 additions & 4 deletions worlds/sc2/regions.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ def create_mission_order(
adjust_mission_pools(world, mission_pools)
setup_mission_pool_balancing(world, mission_pools)

mission_order_type = get_option_value(world, "mission_order")
mission_order_type = world.options.mission_order
if mission_order_type == MissionOrder.option_custom:
mission_order_dict = get_option_value(world, "custom_mission_order")
mission_order_dict = world.options.custom_mission_order.value
else:
mission_order_option = create_regular_mission_order(world, mission_pools)
if mission_order_type in static_mission_orders:
Expand Down Expand Up @@ -157,7 +157,7 @@ def setup_mission_pool_balancing(world: 'SC2World', pools: SC2MOGenMissionPools)
pools.set_flag_balances(flag_ratios, flag_weights)

def create_regular_mission_order(world: 'SC2World', mission_pools: SC2MOGenMissionPools) -> Dict[str, Dict[str, Any]]:
mission_order_type = get_option_value(world, "mission_order")
mission_order_type = world.options.mission_order.value

if mission_order_type in static_mission_orders:
return create_static_mission_order(world, mission_order_type, mission_pools)
Expand Down Expand Up @@ -422,7 +422,7 @@ def make_hopscotch(world: 'SC2World', size: int) -> Dict[str, Dict[str, Any]]:
return mission_order

def create_dynamic_mission_order(world: 'SC2World', mission_order_type: int, mission_pools: SC2MOGenMissionPools) -> Dict[str, Dict[str, Any]]:
num_missions = min(mission_pools.get_allowed_mission_count(), get_option_value(world, "maximum_campaign_size"))
num_missions = min(mission_pools.get_allowed_mission_count(), world.options.maximum_campaign_size.value)
num_missions = max(1, num_missions)
if mission_order_type == MissionOrder.option_golden_path:
return make_golden_path(world, num_missions)
Expand Down
Loading

0 comments on commit 7d65aaa

Please sign in to comment.