コード例 #1
0
 async def query_available_abilities(
         self,
         units: Union[List[Unit], "Units"],
         ignore_resource_requirements: bool = False
 ) -> List[List[AbilityId]]:
     """ Query abilities of multiple units """
     if not isinstance(units, list):
         """ Deprecated, accepting a single unit may be removed in the future, query a list of units instead """
         assert isinstance(units, Unit)
         units = [units]
         input_was_a_list = False
     else:
         input_was_a_list = True
     assert len(units) > 0
     result = await self._execute(query=query_pb.RequestQuery(
         abilities=[
             query_pb.RequestQueryAvailableAbilities(unit_tag=unit.tag)
             for unit in units
         ],
         ignore_resource_requirements=ignore_resource_requirements))
     """ Fix for bots that only query a single unit """
     if not input_was_a_list:
         return [[AbilityId(a.ability_id) for a in b.abilities]
                 for b in result.query.abilities][0]
     return [[AbilityId(a.ability_id) for a in b.abilities]
             for b in result.query.abilities]
コード例 #2
0
def generate_redirect_abilities_dict(data: dict):
    ability_data = data["Ability"]
    unit_data = data["Unit"]
    upgrade_data = data["Upgrade"]

    # Load pickled game data files
    path = os.path.dirname(__file__)
    pickled_files_folder_path = os.path.join(path, "test", "pickle_data")
    pickled_files = os.listdir(pickled_files_folder_path)
    random_pickled_file = next(f for f in pickled_files if f.endswith(".xz"))
    with lzma.open(
            os.path.join(pickled_files_folder_path, random_pickled_file),
            "rb") as f:
        raw_game_data, raw_game_info, raw_observation = pickle.load(f)
        game_data = GameData(raw_game_data.data)

    all_redirect_abilities: Dict[AbilityId, AbilityId] = OrderedDict2()

    entry: dict
    for entry in ability_data:
        ability_id_value: int = entry["id"]
        try:
            ability_id: AbilityId = AbilityId(ability_id_value)
        except Exception as e:
            print(f"Error with ability id value {ability_id_value}")
            continue

        generic_redirect_ability_value: int = game_data.abilities[
            ability_id_value]._proto.remaps_to_ability_id
        if generic_redirect_ability_value:
            # Might be 0 if it has no redirect ability
            all_redirect_abilities[ability_id] = AbilityId(
                generic_redirect_ability_value)

    return all_redirect_abilities
コード例 #3
0
def generate_redirect_abilities_dict(data: dict):
    ability_data = data["Ability"]
    unit_data = data["Unit"]
    upgrade_data = data["Upgrade"]

    # Load pickled game data files
    pickled_file_path = Path(
        __file__).parent / "test" / "pickle_data" / "AcropolisLE.xz"
    assert pickled_file_path.is_file(
    ), f"Could not find pickled data file {pickled_file_path}"
    logger.info(f"Loading pickled game data file {pickled_file_path}")
    with lzma.open(pickled_file_path.absolute(), "rb") as f:
        raw_game_data, raw_game_info, raw_observation = pickle.load(f)
        game_data = GameData(raw_game_data.data)

    all_redirect_abilities: Dict[AbilityId, AbilityId] = OrderedDict2()

    entry: dict
    for entry in ability_data:
        ability_id_value: int = entry["id"]
        try:
            ability_id: AbilityId = AbilityId(ability_id_value)
        except Exception as e:
            logger.info(f"Error with ability id value {ability_id_value}")
            continue

        generic_redirect_ability_value: int = game_data.abilities[
            ability_id_value]._proto.remaps_to_ability_id
        if generic_redirect_ability_value:
            # Might be 0 if it has no redirect ability
            all_redirect_abilities[ability_id] = AbilityId(
                generic_redirect_ability_value)

    return all_redirect_abilities
コード例 #4
0
ファイル: client.py プロジェクト: NMVRodrigues/zergrush
 async def query_available_abilities(self, unit):
     assert isinstance(unit, Unit)
     result = await self._execute(query=query_pb.RequestQuery(
         abilities=[query_pb.RequestQueryAvailableAbilities(
             unit_tag=unit.tag
         )]
     ))
     return [AbilityId(a.ability_id) for a in result.query.abilities[0].abilities]
コード例 #5
0
    def ability_specialization_allowed_for(self, a_id, u_id):
        """Can this unit use this specialization, e.g. do not allow LIFT_COMMANDCENTER for BARRACKS."""
        assert isinstance(a_id, int)
        assert isinstance(u_id, int)

        a_name = AbilityId(a_id).name.upper()
        u_name = UnitTypeId(u_id).name

        if not self.is_specialization(a_name):
            return True

        for postfix in ["FLYING", "BURROWED", "MP"]:
            u_name = remove_postfix(u_name, postfix)

        return u_name in a_name
コード例 #6
0
 async def query_available_abilities(self,
                                     units,
                                     ignore_resource_requirements=False):
     if not isinstance(units, list):
         assert isinstance(units, Unit)
         units = [units]
     assert len(units) > 0
     result = await self._execute(query=query_pb.RequestQuery(
         abilities=[
             query_pb.RequestQueryAvailableAbilities(unit_tag=unit.tag)
             for unit in units
         ],
         ignore_resource_requirements=ignore_resource_requirements))
     return [[AbilityId(a.ability_id) for a in b.abilities]
             for b in result.query.abilities]
コード例 #7
0
    async def query_available_abilities_with_tag(
        self,
        units: Union[List[Unit], Units],
        ignore_resource_requirements: bool = False
    ) -> Dict[int, Set[AbilityId]]:
        """ Query abilities of multiple units """

        result = await self._execute(query=query_pb.RequestQuery(
            abilities=(query_pb.RequestQueryAvailableAbilities(
                unit_tag=unit.tag) for unit in units),
            ignore_resource_requirements=ignore_resource_requirements,
        ))
        return {
            b.unit_tag: {AbilityId(a.ability_id)
                         for a in b.abilities}
            for b in result.query.abilities
        }
コード例 #8
0
    async def military_executioner(self, actions):
        '''
        Actions is a vector with the nodes corresponding to:
        - for each control_group
          - for each ability
            - priority
            - pos[0]
            - pos[1]

        They result in the following abilities:
        - to_actions(*)
        '''
        todo_actions = []
        idx = 0

        for control_group in self.control_groups:
            group_units = control_group.select_units(self.units)

            for ability_id in C.ZERG_MILITARY_ABILITIES_IDS:
                ability_id = AbilityId(ability_id)
                priority, pos0, pos1 = actions[idx], actions[idx +
                                                             1], actions[idx +
                                                                         2]
                target = self.normal_to_mapscale(Point2([pos0, pos1]))

                self.feed_interest_map(target)

                if priority > 0.5:
                    for unit in group_units:
                        if ability["target"] == "None" and await self.can_cast(
                                unit, ability_id):
                            todo_actions.append(unit(ability_id))
                        elif ability["target"] == "Unit":
                            target_unit = self.state.units.closest_to(target)
                            if await self.can_cast(unit, ability_id):
                                todo_actions.append(
                                    unit(ability_id, target_unit))
                    # end group_units
                    self.log_action(ability_id, target, control_group)
            # end abilities
                idx += 3
        # end control_groups
        await self.do_actions(todo_actions)
コード例 #9
0
def get_unit_abilities(data: dict):
    ability_data = data["Ability"]
    unit_data = data["Unit"]
    upgrade_data = data["Upgrade"]

    all_unit_abilities: Dict[UnitTypeId, Set[AbilityId]] = OrderedDict2()
    entry: dict
    for entry in unit_data:
        entry_unit_abilities = entry.get("abilities", [])
        unit_type = UnitTypeId(entry["id"])
        current_collected_unit_abilities: Set[AbilityId] = OrderedSet2()
        for ability_info in entry_unit_abilities:
            ability_id_value: int = ability_info.get("ability", 0)
            if ability_id_value:
                ability_id: AbilityId = AbilityId(ability_id_value)
                current_collected_unit_abilities.add(ability_id)

        # logger.info(unit_type, current_unit_abilities)
        if current_collected_unit_abilities:
            all_unit_abilities[unit_type] = current_collected_unit_abilities
    return all_unit_abilities
コード例 #10
0
    def serialize_ability(self, a):
        """Return None to skip this."""

        # TODO: Buffs
        # TODO: Check interceptors: BUILD_INTERCEPTORS
        # TODO: Calldowns: SUPPLYDROP_SUPPLYDROP, CALLDOWNMULE_CALLDOWNMULE
        # TODO: Infestors: INFESTEDTERRANS_INFESTEDTERRANS, INFESTORENSNARE_INFESTORENSNARE

        # Unmangled id and name, i.e. unit specific variants also
        real_id = a._proto.ability_id
        real_name = AbilityId(a._proto.ability_id).name

        # Check if useless
        if (
            a.id.name.endswith("_DOORDEFAULTCLOSE")
            or a.id.name.endswith("_BRIDGERETRACT")
            or a.id.name.endswith("_BRIDGEEXTEND")
            or "CRITTER" in real_name
        ):
            return None

        is_morph = (
            "MORPH" in a.id.name
            or a.id.name.startswith("LARVATRAIN_")
            or a.id.name.startswith("UPGRADETO")
            or a.id.name.startswith("BURROW")
            or a.id.name in ["LIFT", "LAND", "SIEGEMODE_SIEGEMODE", "UNSIEGE_UNSIEGE"]
        )

        is_building = a._proto.is_building or a.id.name == "BUILDAUTOTURRET_AUTOTURRET"

        target_name = AbilityData.Target.Name(a._proto.target)
        if a.id.name in ["BUILD_REACTOR", "BUILD_TECHLAB"]:
            assert target_name == "PointOrNone", f"{a.id.name}: {target_name}"
            if "REACTOR" in a.id.name:
                unit_id = UnitTypeId.REACTOR.value
            elif "TECHLAB" in a.id.name:
                unit_id = UnitTypeId.TECHLAB.value
            else:
                assert False, "Invalid add-on"
            build = {"target": {"BuildInstant": {"produces": unit_id}}}
        elif is_building:
            if real_id in self.create_abilities:
                unit_id = self.create_abilities[real_id]
            else:
                unit_id = 0

            if a._proto.is_instant_placement:
                assert target_name == "PointOrNone", f"{a.id.name}: {target_name}"
                build = {"target": {"BuildInstant": {"produces": unit_id}}}
            elif target_name == "Unit":
                build = {"target": {"BuildOnUnit": {"produces": unit_id}}}
            else:
                assert target_name == "Point", f"{a.id.name}: {target_name}"
                build = {"target": {"Build": {"produces": unit_id}}}
        elif "RESEARCH_" in a.id.name:
            assert target_name == "None", f"{a.id.name}: {target_name}"
            if real_id not in self.upgrade_abilities:
                # Not in the game anymore
                return None

            build = {
                "target": {"Research": {"upgrade": self.upgrade_abilities[real_id]}}
            }
        elif is_morph:
            if real_id in self.create_abilities:
                unit_id = self.create_abilities[real_id]
            else:
                unit_id = 0
                for prefix in SPEC_PREFIX:
                    if real_name.startswith(prefix):
                        name = remove_prefix(real_name, prefix)
                        if name in ["SWARMHOST", "LURKER"]:
                            name += "MP"
                        cands = [
                            u for u in self.data_units if name == u["name"].upper()
                        ]
                        assert len(cands) == 1, name
                        unit_id = cands[0]["id"]
                        break
                for infix in SPEC_INFIX:
                    if infix in real_name:
                        name = real_name[: real_name.find(infix)]
                        cands = [
                            u for u in self.data_units if name == u["name"].upper()
                        ]
                        assert len(cands) == 1, name
                        unit_id = cands[0]["id"]
                        break

            if target_name == "Point":
                build = {"target": {"MorphPlace": {"produces": unit_id}}}
            else:
                assert target_name == "None", f"{a.id.name}: {target_name}"
                build = {"target": {"Morph": {"produces": unit_id}}}
        elif "WARPGATETRAIN_" in a.id.name or "TRAINWARP_ADEPT" == a.id.name:
            assert target_name == "Point", f"{a.id.name}: {target_name}"
            build = {"target": {"TrainPlace": {"produces": 0}}}
        elif "TRAIN_" in a.id.name or a.id.name == "SPAWNCHANGELING_SPAWNCHANGELING":
            assert target_name == "None", f"{a.id.name}: {target_name}"
            build = {"target": {"Train": {"produces": 0}}}
        elif a.id.name.startswith("EFFECT_"):
            # TODO: Effects
            build = {"target": target_name}
        elif a.id.name.startswith("HALLUCINATION_"):
            # TODO: Hallucinations?
            assert target_name == "None", f"{a.id.name}: {target_name}"
            build = {"target": target_name}
        else:
            build = {"target": target_name}

        return {
            **{
                "id": real_id,
                "name": real_name,
                "cast_range": a._proto.cast_range,
                "energy_cost": 0,
                "allow_minimap": a._proto.allow_minimap,
                "allow_autocast": a._proto.allow_autocast,
                "cost": EMPTY_COST,
                "effect": [],
                "buff": [],
                "cooldown": 0,
            },
            **build,
        }
コード例 #11
0
def patch():
    assert SOURCE_DIR.exists()
    TARGET_DIR.mkdir(exist_ok=True)

    with (SOURCE_DIR / "ability.toml").open() as f:
        c_ability = toml.load(f)

    with (SOURCE_DIR / "unit.toml").open() as f:
        c_unit = toml.load(f)

    with (SOURCE_DIR / "upgrade.toml").open() as f:
        c_upgrade = toml.load(f)

    with (Path("generate") / "patches" /
          "ability_requirement.toml").open() as f:
        patch_ability_requirement = toml.load(f)

    with (Path("generate") / "patches" /
          "ability_produces_replace.toml").open() as f:
        patch_ability_produces_replace = toml.load(f)

    with (Path("generate") / "patches" /
          "ability_produces_missing.toml").open() as f:
        patch_ability_produces_missing = toml.load(f)

    with (Path("generate") / "patches" /
          "unit_ability_missing.toml").open() as f:
        patch_unit_ability_missing = toml.load(f)

    with (Path("generate") / "patches" /
          "unit_ability_disallowed.toml").open() as f:
        patch_unit_ability_disallowed = toml.load(f)

    # Patch unit abilities
    for unit in c_unit["Unit"]:
        unit_id = unit["id"]
        current_abilities = [int(a["ability"]) for a in unit["abilities"]]

        for p in patch_unit_ability_missing.get(str(unit_id), []):
            assert (
                int(p["ability"]) not in current_abilities
            ), f"Already defined: ({unit['name']}) {unit_id} {p['ability']}"
            unit["abilities"].append(p)

    # Patch replacement ability products
    for abil in c_ability["Ability"]:
        abil_id = abil["id"]
        abil_name = abil["name"]

        if isinstance(abil["target"], dict):
            keys = abil["target"].keys()
            assert len(keys) == 1
            k = list(keys)[0]

            if k == "Research":
                assert abil["target"][k]["upgrade"] != 0
            else:
                if abil["target"][k]["produces"] == 0:
                    p = patch_ability_produces_replace.get(str(abil_id))
                    assert p, f"Missing ability product: [{abil_id}] # {abil_name}"
                    abil["target"][k]["produces"] = p["produces"]

    # Patch missing ability products
    for abil in c_ability["Ability"]:
        abil_id = abil["id"]
        patch_target = patch_ability_produces_missing.get(str(abil_id))
        if patch_target is None:
            continue

        assert set(patch_target.keys()) == {"target"}
        abil.update(patch_target)

    # Patch unit requirements
    for unit in c_unit["Unit"]:
        unit_id = unit["id"]
        unit_name = unit["name"]
        for i, ability in list(enumerate(unit["abilities"]))[::-1]:
            assert set(ability.keys()) <= {
                "ability",
                "requirements",
            }, f"Keys? {ability.keys()}"
            ability_id = ability["ability"]

            # Check if disallowed
            d0 = patch_unit_ability_disallowed.get(str(unit_id))
            if d0:
                d1 = d0.get(str(ability_id))
                if d1 is not None:
                    assert d1["disallow"]
                    del unit["abilities"][i]
                    continue

            if ability.get("requirements") == "???":
                # Check if defined
                ability_name = AbilityId(ability_id).name
                patch_name = f"[{unit_id}.{ability_id}] # {unit_name} - {ability_name}"
                p0 = patch_ability_requirement.get(str(unit["id"]))
                assert p0, f"Missing unit requirement: {patch_name}"
                p1 = p0.get(str(ability_id))
                assert p1, f"Missing unit requirement: {patch_name}"
                ability["requirements"] = p1["requirements"]
            else:
                # Check if defined even if not used
                ability_name = AbilityId(ability_id).name
                patch_name = f"[{unit_id}.{ability_id}] # {unit_name} - {ability_name}"
                p0 = patch_ability_requirement.get(str(unit["id"]))
                if p0:
                    p1 = p0.get(str(ability_id))
                    assert not p1, f"Redundant unit requirement: {patch_name}"
                    # assert not p1, f"Redundant unit requirement: {patch_name}"

    with (T_TOML_DIR / "ability.toml").open("w") as f:
        toml.dump(c_ability, f)

    with (T_TOML_DIR / "unit.toml").open("w") as f:
        toml.dump(c_unit, f)

    with (T_TOML_DIR / "upgrade.toml").open("w") as f:
        toml.dump(c_upgrade, f)

    with (TARGET_DIR / "ability.json").open("w") as f:
        json.dump(c_ability, f, separators=(",", ":"))

    with (TARGET_DIR / "unit.json").open("w") as f:
        json.dump(c_unit, f, separators=(",", ":"))

    with (TARGET_DIR / "upgrade.json").open("w") as f:
        json.dump(c_upgrade, f, separators=(",", ":"))
コード例 #12
0
def get_unit_train_build_abilities(data):
    ability_data = data["Ability"]
    unit_data = data["Unit"]
    upgrade_data = data["Upgrade"]

    # From which abilities can a unit be trained
    train_abilities: Dict[UnitTypeId, Set[AbilityId]] = OrderedDict2()
    # If the ability requires a placement position
    ability_requires_placement: Set[AbilityId] = set()
    # Map ability to unittypeid
    ability_to_unittypeid_dict: Dict[AbilityId, UnitTypeId] = OrderedDict2()

    # From which abilities can a unit be morphed
    # unit_morph_abilities: Dict[UnitTypeId, Set[AbilityId]] = {}

    entry: dict
    for entry in ability_data:
        """
        "target": "PointOrUnit"
        """
        if isinstance(entry.get("target", {}), str):
            continue
        ability_id: AbilityId = AbilityId(entry["id"])
        created_unit_type_id: UnitTypeId

        # Check if it is a unit train ability
        requires_placement = False
        train_unit_type_id_value: int = entry.get("target", {}).get(
            "Train", {}).get("produces", 0)
        train_place_unit_type_id_value: int = entry.get("target", {}).get(
            "TrainPlace", {}).get("produces", 0)
        morph_unit_type_id_value: int = entry.get("target", {}).get(
            "Morph", {}).get("produces", 0)
        build_unit_type_id_value: int = entry.get("target", {}).get(
            "Build", {}).get("produces", 0)
        build_on_unit_unit_type_id_value: int = entry.get("target", {}).get(
            "BuildOnUnit", {}).get("produces", 0)

        if not train_unit_type_id_value and train_place_unit_type_id_value:
            train_unit_type_id_value = train_place_unit_type_id_value
            requires_placement = True

        # Collect larva morph abilities, and one way morphs (exclude burrow, hellbat morph, siege tank siege)
        # Also doesnt include building addons
        if not train_unit_type_id_value and (
                "LARVATRAIN_" in ability_id.name or ability_id in {
                    AbilityId.MORPHTOBROODLORD_BROODLORD,
                    AbilityId.MORPHZERGLINGTOBANELING_BANELING,
                    AbilityId.MORPHTORAVAGER_RAVAGER,
                    AbilityId.MORPH_LURKER,
                    AbilityId.UPGRADETOLAIR_LAIR,
                    AbilityId.UPGRADETOHIVE_HIVE,
                    AbilityId.UPGRADETOGREATERSPIRE_GREATERSPIRE,
                    AbilityId.UPGRADETOORBITAL_ORBITALCOMMAND,
                    AbilityId.UPGRADETOPLANETARYFORTRESS_PLANETARYFORTRESS,
                    AbilityId.MORPH_OVERLORDTRANSPORT,
                    AbilityId.MORPH_OVERSEER,
                }):
            # If all morph units are used, unit_trained_from.py will be "wrong" because it will list that a siege tank can be trained from siegetanksieged and similar:
            # UnitTypeId.SIEGETANK: {UnitTypeId.SIEGETANKSIEGED, UnitTypeId.FACTORY},
            # if not train_unit_type_id_value and morph_unit_type_id_value:
            train_unit_type_id_value = morph_unit_type_id_value

        # Add all build abilities, like construct buildings and train queen (exception)
        if not train_unit_type_id_value and build_unit_type_id_value:
            train_unit_type_id_value = build_unit_type_id_value
            if "BUILD_" in entry["name"]:
                requires_placement = True

        # Add build gas building (refinery, assimilator, extractor)
        # TODO: target needs to be a unit, not a position, but i dont want to store an extra line just for this - needs to be an exception in bot_ai.py
        if not train_unit_type_id_value and build_on_unit_unit_type_id_value:
            train_unit_type_id_value = build_on_unit_unit_type_id_value

        if train_unit_type_id_value:
            created_unit_type_id = UnitTypeId(train_unit_type_id_value)

            if created_unit_type_id not in train_abilities:
                train_abilities[created_unit_type_id] = {ability_id}
            else:
                train_abilities[created_unit_type_id].add(ability_id)
            if requires_placement:
                ability_requires_placement.add(ability_id)

            ability_to_unittypeid_dict[ability_id] = created_unit_type_id
    """
    unit_train_abilities = {
        UnitTypeId.GATEWAY: {
            UnitTypeId.ADEPT: {
                "ability": AbilityId.TRAIN_ADEPT,
                "requires_techlab": False,
                "required_building": UnitTypeId.CYBERNETICSCORE, # Or None
                "requires_placement_position": False, # True for warp gate
                "requires_power": True, # If a pylon nearby is required
            },
            UnitTypeId.Zealot: {
                "ability": AbilityId.GATEWAYTRAIN_ZEALOT,
                ...
            }
        }
    }
    """
    unit_train_abilities: Dict[UnitTypeId,
                               Dict[str, Union[AbilityId, bool,
                                               UnitTypeId]]] = OrderedDict2()
    for entry in unit_data:
        unit_abilities = entry.get("abilities", [])
        unit_type = UnitTypeId(entry["id"])
        current_unit_train_abilities = OrderedDict2()
        for ability_info in unit_abilities:
            ability_id_value: int = ability_info.get("ability", 0)
            if ability_id_value:
                ability_id: AbilityId = AbilityId(ability_id_value)
                # Ability is not a train ability
                if ability_id not in ability_to_unittypeid_dict:
                    continue

                requires_techlab: bool = False
                required_building: Optional[UnitTypeId] = None
                requires_placement_position: bool = False
                requires_power: bool = False
                """
                requirements = [
                    {
                        "addon": 5
                    },
                    {
                        "building": 29
                    }
                  ]
                """
                requirements: List[Dict[str, int]] = ability_info.get(
                    "requirements", [])
                if requirements:
                    # Assume train abilities only have one tech building requirement; thors requiring armory and techlab is seperatedly counted
                    assert (
                        len([
                            req
                            for req in requirements if req.get("building", 0)
                        ]) <= 1
                    ), f"Error: Building {unit_type} has more than one tech requirements with train ability {ability_id}"
                    # UnitTypeId 5 == Techlab
                    requires_techlab: bool = any(req for req in requirements
                                                 if req.get("addon", 0) == 5)
                    requires_tech_builing_id_value: int = next(
                        (req["building"]
                         for req in requirements if req.get("building", 0)), 0)
                    if requires_tech_builing_id_value:
                        required_building = UnitTypeId(
                            requires_tech_builing_id_value)

                if ability_id in ability_requires_placement:
                    requires_placement_position = True

                requires_power = entry.get("needs_power", False)

                resulting_unit = ability_to_unittypeid_dict[ability_id]

                ability_dict = {"ability": ability_id}
                # Only add boolean values and tech requirement if they actually exist, to make the resulting dict file smaller
                if requires_techlab:
                    ability_dict["requires_techlab"] = requires_techlab
                if required_building:
                    ability_dict["required_building"] = required_building
                if requires_placement_position:
                    ability_dict[
                        "requires_placement_position"] = requires_placement_position
                if requires_power:
                    ability_dict["requires_power"] = requires_power
                current_unit_train_abilities[resulting_unit] = ability_dict

        if current_unit_train_abilities:
            unit_train_abilities[unit_type] = current_unit_train_abilities

    return unit_train_abilities
コード例 #13
0
def get_upgrade_abilities(data):
    ability_data = data["Ability"]
    unit_data = data["Unit"]
    upgrade_data = data["Upgrade"]

    ability_to_upgrade_dict: Dict[AbilityId, UpgradeId] = OrderedDict2()
    """
    We want to be able to research an upgrade by doing
    await self.can_research(UpgradeId, return_idle_structures=True) -> returns list of idle structures that can research it
    So we need to assign each upgrade id one building type, and its research ability and requirements (e.g. armory for infantry level 2)
    """

    # Collect all upgrades and their corresponding abilities
    entry: dict
    for entry in ability_data:
        if isinstance(entry.get("target", {}), str):
            continue
        ability_id: AbilityId = AbilityId(entry["id"])
        researched_ability_id: UnitTypeId

        upgrade_id_value: int = entry.get("target",
                                          {}).get("Research",
                                                  {}).get("upgrade", 0)
        if upgrade_id_value:
            upgrade_id: UpgradeId = UpgradeId(upgrade_id_value)

            ability_to_upgrade_dict[ability_id] = upgrade_id
    """
    unit_research_abilities = {
        UnitTypeId.ENGINEERINGBAY: {
            UpgradeId.TERRANINFANTRYWEAPONSLEVEL1:
            {
                "ability": AbilityId.ENGINEERINGBAYRESEARCH_TERRANINFANTRYWEAPONSLEVEL1,
                "required_building": None,
                "requires_power": False, # If a pylon nearby is required
            },
            UpgradeId.TERRANINFANTRYWEAPONSLEVEL2: {
                "ability": AbilityId.ENGINEERINGBAYRESEARCH_TERRANINFANTRYWEAPONSLEVEL2,
                "required_building": UnitTypeId.ARMORY,
                "requires_power": False, # If a pylon nearby is required
            },
        }
    }
    """
    unit_research_abilities = OrderedDict2()
    for entry in unit_data:
        unit_abilities = entry.get("abilities", [])
        unit_type = UnitTypeId(entry["id"])

        if unit_type == UnitTypeId.TECHLAB:
            continue

        current_unit_research_abilities = OrderedDict2()
        for ability_info in unit_abilities:
            ability_id_value: int = ability_info.get("ability", 0)
            if ability_id_value:
                ability_id: AbilityId = AbilityId(ability_id_value)
                # Upgrade is not a known upgrade ability
                if ability_id not in ability_to_upgrade_dict:
                    continue

                required_building = None
                required_upgrade = None
                requirements = ability_info.get("requirements", [])
                if requirements:
                    req_building_id_value = next(
                        (req["building"]
                         for req in requirements if req.get("building", 0)),
                        None)
                    if req_building_id_value:
                        req_building_id = UnitTypeId(req_building_id_value)
                        required_building = req_building_id

                    req_upgrade_id_value = next(
                        (req["upgrade"]
                         for req in requirements if req.get("upgrade", 0)),
                        None)
                    if req_upgrade_id_value:
                        req_upgrade_id = UpgradeId(req_upgrade_id_value)
                        required_upgrade = req_upgrade_id

                requires_power = entry.get("needs_power", False)

                resulting_upgrade = ability_to_upgrade_dict[ability_id]

                research_info = {"ability": ability_id}
                if required_building:
                    research_info["required_building"] = required_building
                if required_upgrade:
                    research_info["required_upgrade"] = required_upgrade
                if requires_power:
                    research_info["requires_power"] = requires_power
                current_unit_research_abilities[
                    resulting_upgrade] = research_info

        if current_unit_research_abilities:
            unit_research_abilities[
                unit_type] = current_unit_research_abilities

    return unit_research_abilities
コード例 #14
0
 def exact_id(self) -> AbilityId:
     """ Returns the exact ID of the ability """
     return AbilityId(self._proto.ability_id)
コード例 #15
0
 def id(self) -> AbilityId:
     """ Returns the generic remap ID. See sc2/dicts/generic_redirect_abilities.py """
     if self._proto.remaps_to_ability_id:
         return AbilityId(self._proto.remaps_to_ability_id)
     return AbilityId(self._proto.ability_id)
コード例 #16
0
 def exact_id(self) -> AbilityId:
     return AbilityId(self.ability_id)