From 0e78bf90a413049babd13588f56a5c467c3a2d39 Mon Sep 17 00:00:00 2001 From: Magnemania Date: Sun, 9 Apr 2023 13:23:05 -0400 Subject: [PATCH 1/2] Shortened hints for WoL --- worlds/sc2wol/Items.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/worlds/sc2wol/Items.py b/worlds/sc2wol/Items.py index 9776e4fed1a..9318ddbd33a 100644 --- a/worlds/sc2wol/Items.py +++ b/worlds/sc2wol/Items.py @@ -175,6 +175,9 @@ def get_basic_units(multiworld: MultiWorld, player: int) -> typing.Set[str]: item_name_groups = {} for item, data in item_table.items(): item_name_groups.setdefault(data.type, []).append(item) + if data.type in ("Armory 1", "Armory 2") and '(' in item: + short_name = item[:item.find(' (')] + item_name_groups[short_name] = [item] item_name_groups["Missions"] = ["Beat " + mission_name for mission_name in vanilla_mission_req_table] filler_items: typing.Tuple[str, ...] = ( From 216afa0ed5cd4ba4db579e6e2caa527ef7c21c0b Mon Sep 17 00:00:00 2001 From: Magnemania Date: Sun, 9 Apr 2023 16:20:52 -0400 Subject: [PATCH 2/2] Generic upgrade options for WoL --- Starcraft2Client.py | 38 ++++++++++++++++++++++++++++++++----- worlds/sc2wol/Items.py | 40 +++++++++++++++++++++++++++++++++++++++ worlds/sc2wol/Options.py | 34 +++++++++++++++++++++++++++++++++ worlds/sc2wol/__init__.py | 13 +++++++++++-- 4 files changed, 118 insertions(+), 7 deletions(-) diff --git a/Starcraft2Client.py b/Starcraft2Client.py index 855d9a64d42..aa4f3a98c1c 100644 --- a/Starcraft2Client.py +++ b/Starcraft2Client.py @@ -32,7 +32,7 @@ from sc2.main import run_game from sc2.player import Bot from worlds.sc2wol import SC2WoLWorld -from worlds.sc2wol.Items import lookup_id_to_name, item_table, ItemData, type_flaggroups +from worlds.sc2wol.Items import lookup_id_to_name, item_table, ItemData, type_flaggroups, upgrade_numbers from worlds.sc2wol.Locations import SC2WOL_LOC_ID_OFFSET from worlds.sc2wol.MissionTables import lookup_id_to_mission from worlds.sc2wol.Regions import MissionInfo @@ -192,6 +192,8 @@ class SC2Context(CommonContext): announcements = queue.Queue() sc2_run_task: typing.Optional[asyncio.Task] = None missions_unlocked: bool = False # allow launching missions ignoring requirements + generic_upgrade_missions = 0 + generic_upgrade_items = 0 current_tooltip = None last_loc_list = None difficulty_override = -1 @@ -223,6 +225,8 @@ def on_package(self, cmd: str, args: dict): self.mission_order = args["slot_data"].get("mission_order", 0) self.final_mission = args["slot_data"].get("final_mission", 29) self.player_color = args["slot_data"].get("player_color", 2) + self.generic_upgrade_missions = args["slot_data"].get("generic_upgrade_missions", 0) + self.generic_upgrade_items = args["slot_data"].get("generic_upgrade_items", 0) self.build_location_to_mission_mapping() @@ -530,7 +534,8 @@ async def main(): ] -def calculate_items(items: typing.List[NetworkItem]) -> typing.List[int]: +def calculate_items(ctx: SC2Context) -> typing.List[int]: + items = ctx.items_received network_item: NetworkItem accumulators: typing.List[int] = [0 for _ in type_flaggroups] @@ -544,12 +549,35 @@ def calculate_items(items: typing.List[NetworkItem]) -> typing.List[int]: # exists multiple times elif item_data.type == "Upgrade": - accumulators[type_flaggroups[item_data.type]] += 1 << item_data.number + flaggroup = type_flaggroups[item_data.type] + if ctx.generic_upgrade_items == 0: + accumulators[flaggroup] += 1 << item_data.number + else: + for bundled_number in upgrade_numbers[item_data.number]: + accumulators[flaggroup] += 1 << bundled_number # sum else: accumulators[type_flaggroups[item_data.type]] += item_data.number + # Upgrades from completed missions + if ctx.generic_upgrade_missions > 0: + upgrade_flaggroup = type_flaggroups["Upgrade"] + num_missions = ctx.generic_upgrade_missions * len(ctx.mission_req_table) + amounts = [ + num_missions // 100, + 2 * num_missions // 100, + 3 * num_missions // 100 + ] + upgrade_count = 0 + completed = len([id for id in ctx.mission_id_to_location_ids if SC2WOL_LOC_ID_OFFSET + victory_modulo * id in ctx.checked_locations]) + for amount in amounts: + if completed >= amount: + upgrade_count += 1 + # Equivalent to "Progressive Upgrade" item + for bundled_number in upgrade_numbers[5]: + accumulators[upgrade_flaggroup] += upgrade_count << bundled_number + return accumulators @@ -602,7 +630,7 @@ async def on_step(self, iteration: int): game_state = 0 if not self.setup_done: self.setup_done = True - start_items = calculate_items(self.ctx.items_received) + start_items = calculate_items(self.ctx) if self.ctx.difficulty_override >= 0: difficulty = calc_difficulty(self.ctx.difficulty_override) else: @@ -632,7 +660,7 @@ async def on_step(self, iteration: int): "Starcraft 2 (This is likely a map issue)") if self.last_received_update < len(self.ctx.items_received): - current_items = calculate_items(self.ctx.items_received) + current_items = calculate_items(self.ctx) await self.chat_send("UpdateTech {} {} {} {} {} {} {} {}".format( current_items[0], current_items[1], current_items[2], current_items[3], current_items[4], current_items[5], current_items[6], current_items[7])) diff --git a/worlds/sc2wol/Items.py b/worlds/sc2wol/Items.py index 9318ddbd33a..95540f06c89 100644 --- a/worlds/sc2wol/Items.py +++ b/worlds/sc2wol/Items.py @@ -50,6 +50,13 @@ def get_full_item_list(): "Progressive Vehicle Armor": ItemData(104 + SC2WOL_ITEM_ID_OFFSET, "Upgrade", 6, quantity=3), "Progressive Ship Weapon": ItemData(105 + SC2WOL_ITEM_ID_OFFSET, "Upgrade", 8, quantity=3), "Progressive Ship Armor": ItemData(106 + SC2WOL_ITEM_ID_OFFSET, "Upgrade", 10, quantity=3), + # Upgrade bundle 'number' values are used as indices to get affected 'number's + "Progressive Weapon Upgrade": ItemData(107 + SC2WOL_ITEM_ID_OFFSET, "Upgrade", 0, quantity=3), + "Progressive Armor Upgrade": ItemData(108 + SC2WOL_ITEM_ID_OFFSET, "Upgrade", 1, quantity=3), + "Progressive Infantry Upgrade": ItemData(109 + SC2WOL_ITEM_ID_OFFSET, "Upgrade", 2, quantity=3), + "Progressive Vehicle Upgrade": ItemData(110 + SC2WOL_ITEM_ID_OFFSET, "Upgrade", 3, quantity=3), + "Progressive Starship Upgrade": ItemData(111 + SC2WOL_ITEM_ID_OFFSET, "Upgrade", 4, quantity=3), + "Progressive Upgrade": ItemData(112 + SC2WOL_ITEM_ID_OFFSET, "Upgrade", 5, quantity=3), "Projectile Accelerator (Bunker)": ItemData(200 + SC2WOL_ITEM_ID_OFFSET, "Armory 1", 0, parent_item="Bunker"), "Neosteel Bunker (Bunker)": ItemData(201 + SC2WOL_ITEM_ID_OFFSET, "Armory 1", 1, parent_item="Bunker"), @@ -203,6 +210,39 @@ def get_basic_units(multiworld: MultiWorld, player: int) -> typing.Set[str]: "Psi Disruptor": 3 } +# 'number' values of upgrades for upgrade bundle items +upgrade_numbers = [ + {0, 4, 8}, # Weapon + {2, 6, 10}, # Armor + {0, 2}, # Infantry + {4, 6}, # Vehicle + {8, 10}, # Starship + {0, 2, 4, 6, 8, 10} # All +] +# Names of upgrades to be included for different options +upgrade_included_names = [ + { # Individual Items + "Progressive Infantry Weapon", + "Progressive Infantry Armor", + "Progressive Vehicle Weapon", + "Progressive Vehicle Armor" + "Progressive Ship Weapon", + "Progressive Ship Armor" + }, + { # Bundle Weapon And Armor + "Progressive Weapon Upgrade", + "Progressive Armor Upgrade" + }, + { # Bundle Unit Class + "Progressive Infantry Upgrade", + "Progressive Vehicle Upgrade", + "Progressive Starship Upgrade" + }, + { # Bundle All + "Progressive Upgrade" + } +] + lookup_id_to_name: typing.Dict[int, str] = {data.code: item_name for item_name, data in get_full_item_list().items() if data.code} # Map type to expected int diff --git a/worlds/sc2wol/Options.py b/worlds/sc2wol/Options.py index 0189273aabf..064bb6b38a8 100644 --- a/worlds/sc2wol/Options.py +++ b/worlds/sc2wol/Options.py @@ -119,6 +119,38 @@ class UnitsAlwaysHaveUpgrades(DefaultOnToggle): display_name = "Units Always Have Upgrades" +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 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. + Bundle Weapon And Armor: All types of weapon upgrades are one item, + and all types of armor upgrades are one item, + resulting in 6 total items. + Bundle Unit Class: Weapon and armor upgrades are merged, + but Infantry, Vehicle, and Starship upgrades are bundled separately, + resulting in 9 total items. + Bundle All: All weapon and armor upgrades are one item, + resulting in 3 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 LockedItems(ItemSet): """Guarantees that these items will be unlockable""" display_name = "Locked Items" @@ -150,6 +182,8 @@ class ExcludedMissions(OptionSet): "early_unit": EarlyUnit, "required_tactics": RequiredTactics, "units_always_have_upgrades": UnitsAlwaysHaveUpgrades, + "generic_upgrade_missions": GenericUpgradeMissions, + "generic_upgrade_items": GenericUpgradeItems, "locked_items": LockedItems, "excluded_items": ExcludedItems, "excluded_missions": ExcludedMissions diff --git a/worlds/sc2wol/__init__.py b/worlds/sc2wol/__init__.py index 60de2008047..d6ccf9610ac 100644 --- a/worlds/sc2wol/__init__.py +++ b/worlds/sc2wol/__init__.py @@ -4,7 +4,7 @@ from BaseClasses import Item, MultiWorld, Location, Tutorial, ItemClassification from worlds.AutoWorld import WebWorld, World from .Items import StarcraftWoLItem, item_table, filler_items, item_name_groups, get_full_item_list, \ - get_basic_units + get_basic_units, ItemData, upgrade_included_names from .Locations import get_locations from .Regions import create_regions from .Options import sc2wol_options, get_option_value @@ -175,8 +175,17 @@ def get_item_pool(multiworld: MultiWorld, player: int, mission_req_table: Dict[s # YAML items yaml_locked_items = get_option_value(multiworld, player, 'locked_items') + # Adjust generic upgrade availability based on options + include_upgrades = get_option_value(multiworld, player, 'generic_upgrade_missions') == 0 + upgrade_items = get_option_value(multiworld, player, 'generic_upgrade_items') + + def item_allowed(name: str, data: ItemData) -> bool: + return name not in excluded_items and \ + (data.type != "Upgrade" or (include_upgrades and \ + name in upgrade_included_names[upgrade_items])) + for name, data in item_table.items(): - if name not in excluded_items: + if item_allowed(name, data): for _ in range(data.quantity): item = create_item_with_correct_settings(player, name) if name in yaml_locked_items: