Beispiel #1
0
    def add_researchable(self, tech_group: GenieTechEffectBundleGroup) -> None:
        """
        Adds a tech group to the list of researchables.

        :param tech_group: The GenieTechLineGroup the building researches.
        """
        if not self.contains_researchable(tech_group.get_id()):
            self.researches.append(tech_group)
    def get_researchable_tech(tech_group: GenieTechEffectBundleGroup) -> None:
        """
        Creates the ResearchableTech object for a Tech.

        :param tech_group: Tech group that is a technology.
        :type tech_group: ...dataformat.converter_object.ConverterObjectGroup
        """
        dataset = tech_group.data
        research_location_id = tech_group.get_research_location_id()
        research_location = dataset.building_lines[research_location_id]

        name_lookup_dict = internal_name_lookups.get_entity_lookups(
            dataset.game_version)
        tech_lookup_dict = internal_name_lookups.get_tech_lookups(
            dataset.game_version)
        civ_lookup_dict = internal_name_lookups.get_civ_lookups(
            dataset.game_version)

        research_location_name = name_lookup_dict[research_location_id][0]
        tech_name = tech_lookup_dict[tech_group.get_id()][0]

        obj_ref = f"{tech_name}.ResearchableTech"
        obj_name = f"{tech_name}Researchable"
        researchable_raw_api_object = RawAPIObject(obj_ref, obj_name,
                                                   dataset.nyan_api_objects)
        researchable_raw_api_object.add_raw_parent(
            "engine.util.research.ResearchableTech")

        # Location of the object depends on whether it'a a unique tech or a normal tech
        if tech_group.is_unique():
            # Add object to the Civ object
            civ_id = tech_group.get_civilization()
            civ = dataset.civ_groups[civ_id]
            civ_name = civ_lookup_dict[civ_id][0]

            researchable_location = ForwardRef(civ, civ_name)

        else:
            # Add object to the research location's Research ability
            researchable_location = ForwardRef(
                research_location, f"{research_location_name}.Research")

        researchable_raw_api_object.set_location(researchable_location)

        # Tech
        tech_forward_ref = ForwardRef(tech_group, tech_name)
        researchable_raw_api_object.add_raw_member(
            "tech", tech_forward_ref, "engine.util.research.ResearchableTech")

        # Cost
        cost_ref = f"{tech_name}.ResearchableTech.{tech_name}Cost"
        cost_raw_api_object = RawAPIObject(cost_ref, f"{tech_name}Cost",
                                           dataset.nyan_api_objects)
        cost_raw_api_object.add_raw_parent(
            "engine.util.cost.type.ResourceCost")
        tech_forward_ref = ForwardRef(tech_group, obj_ref)
        cost_raw_api_object.set_location(tech_forward_ref)

        payment_mode = dataset.nyan_api_objects[
            "engine.util.payment_mode.type.Advance"]
        cost_raw_api_object.add_raw_member("payment_mode", payment_mode,
                                           "engine.util.cost.Cost")

        cost_amounts = []
        for resource_amount in tech_group.tech[
                "research_resource_costs"].value:
            resource_id = resource_amount["type_id"].value

            resource = None
            resource_name = ""
            if resource_id == -1:
                # Not a valid resource
                continue

            if resource_id == 0:
                resource = dataset.pregen_nyan_objects[
                    "util.resource.types.Food"].get_nyan_object()
                resource_name = "Food"

            elif resource_id == 1:
                resource = dataset.pregen_nyan_objects[
                    "util.resource.types.Carbon"].get_nyan_object()
                resource_name = "Carbon"

            elif resource_id == 2:
                resource = dataset.pregen_nyan_objects[
                    "util.resource.types.Ore"].get_nyan_object()
                resource_name = "Ore"

            elif resource_id == 3:
                resource = dataset.pregen_nyan_objects[
                    "util.resource.types.Nova"].get_nyan_object()
                resource_name = "Nova"

            else:
                # Other resource ids are handled differently
                continue

            # Skip resources that are only expected to be there
            if not resource_amount["enabled"].value:
                continue

            amount = resource_amount["amount"].value

            cost_amount_ref = f"{cost_ref}.{resource_name}Amount"
            cost_amount = RawAPIObject(cost_amount_ref,
                                       f"{resource_name}Amount",
                                       dataset.nyan_api_objects)
            cost_amount.add_raw_parent("engine.util.resource.ResourceAmount")
            cost_forward_ref = ForwardRef(tech_group, cost_ref)
            cost_amount.set_location(cost_forward_ref)

            cost_amount.add_raw_member("type", resource,
                                       "engine.util.resource.ResourceAmount")
            cost_amount.add_raw_member("amount", amount,
                                       "engine.util.resource.ResourceAmount")

            cost_amount_forward_ref = ForwardRef(tech_group, cost_amount_ref)
            cost_amounts.append(cost_amount_forward_ref)
            tech_group.add_raw_api_object(cost_amount)

        cost_raw_api_object.add_raw_member(
            "amount", cost_amounts, "engine.util.cost.type.ResourceCost")

        cost_forward_ref = ForwardRef(tech_group, cost_ref)
        researchable_raw_api_object.add_raw_member(
            "cost", cost_forward_ref, "engine.util.research.ResearchableTech")

        research_time = tech_group.tech["research_time"].value

        researchable_raw_api_object.add_raw_member(
            "research_time", research_time,
            "engine.util.research.ResearchableTech")

        # Create sound object
        sound_ref = f"{tech_name}.ResearchableTech.Sound"
        sound_raw_api_object = RawAPIObject(sound_ref, "ResearchSound",
                                            dataset.nyan_api_objects)
        sound_raw_api_object.add_raw_parent("engine.util.sound.Sound")
        sound_location = ForwardRef(tech_group,
                                    f"{tech_name}.ResearchableTech")
        sound_raw_api_object.set_location(sound_location)

        # AoE doesn't support sounds here, so this is empty
        sound_raw_api_object.add_raw_member("play_delay", 0,
                                            "engine.util.sound.Sound")
        sound_raw_api_object.add_raw_member("sounds", [],
                                            "engine.util.sound.Sound")

        sound_forward_ref = ForwardRef(tech_group, sound_ref)
        researchable_raw_api_object.add_raw_member(
            "research_sounds", [sound_forward_ref],
            "engine.util.research.ResearchableTech")

        tech_group.add_raw_api_object(sound_raw_api_object)

        # Condition
        unlock_conditions = []
        if tech_group.get_id() > -1:
            unlock_conditions.extend(
                AoCAuxiliarySubprocessor.get_condition(tech_group,
                                                       obj_ref,
                                                       tech_group.get_id(),
                                                       top_level=True))

        researchable_raw_api_object.add_raw_member(
            "condition", unlock_conditions,
            "engine.util.research.ResearchableTech")

        tech_group.add_raw_api_object(researchable_raw_api_object)
        tech_group.add_raw_api_object(cost_raw_api_object)
Beispiel #3
0
    def tech_group_to_tech(tech_group: GenieTechEffectBundleGroup) -> None:
        """
        Creates raw API objects for a tech group.

        :param tech_group: Tech group that gets converted to a tech.
        :type tech_group: ..dataformat.converter_object.ConverterObjectGroup
        """
        tech_id = tech_group.get_id()

        # Skip Dark Age tech
        if tech_id == 104:
            return

        dataset = tech_group.data

        name_lookup_dict = internal_name_lookups.get_entity_lookups(dataset.game_version)
        tech_lookup_dict = internal_name_lookups.get_tech_lookups(dataset.game_version)

        # Start with the Tech object
        tech_name = tech_lookup_dict[tech_id][0]
        raw_api_object = RawAPIObject(tech_name, tech_name,
                                      dataset.nyan_api_objects)
        raw_api_object.add_raw_parent("engine.util.tech.Tech")

        if isinstance(tech_group, UnitLineUpgrade):
            unit_line = dataset.unit_lines[tech_group.get_line_id()]
            head_unit_id = unit_line.get_head_unit_id()
            obj_location = f"data/game_entity/generic/{name_lookup_dict[head_unit_id][1]}/"

        else:
            obj_location = f"data/tech/generic/{tech_lookup_dict[tech_id][1]}/"

        raw_api_object.set_location(obj_location)
        raw_api_object.set_filename(tech_lookup_dict[tech_id][1])
        tech_group.add_raw_api_object(raw_api_object)

        # =======================================================================
        # Types
        # =======================================================================
        raw_api_object.add_raw_member("types", [], "engine.util.tech.Tech")

        # =======================================================================
        # Name
        # =======================================================================
        name_ref = f"{tech_name}.{tech_name}Name"
        name_raw_api_object = RawAPIObject(name_ref,
                                           f"{tech_name}Name",
                                           dataset.nyan_api_objects)
        name_raw_api_object.add_raw_parent("engine.util.language.translated.type.TranslatedString")
        name_location = ForwardRef(tech_group, tech_name)
        name_raw_api_object.set_location(name_location)

        name_raw_api_object.add_raw_member("translations",
                                           [],
                                           "engine.util.language.translated.type.TranslatedString")

        name_forward_ref = ForwardRef(tech_group, name_ref)
        raw_api_object.add_raw_member("name", name_forward_ref, "engine.util.tech.Tech")
        tech_group.add_raw_api_object(name_raw_api_object)

        # =======================================================================
        # Description
        # =======================================================================
        description_ref = f"{tech_name}.{tech_name}Description"
        description_raw_api_object = RawAPIObject(description_ref,
                                                  f"{tech_name}Description",
                                                  dataset.nyan_api_objects)
        description_raw_api_object.add_raw_parent(
            "engine.util.language.translated.type.TranslatedMarkupFile")
        description_location = ForwardRef(tech_group, tech_name)
        description_raw_api_object.set_location(description_location)

        description_raw_api_object.add_raw_member("translations",
                                                  [],
                                                  "engine.util.language.translated.type.TranslatedMarkupFile")

        description_forward_ref = ForwardRef(tech_group, description_ref)
        raw_api_object.add_raw_member("description",
                                      description_forward_ref,
                                      "engine.util.tech.Tech")
        tech_group.add_raw_api_object(description_raw_api_object)

        # =======================================================================
        # Long description
        # =======================================================================
        long_description_ref = f"{tech_name}.{tech_name}LongDescription"
        long_description_raw_api_object = RawAPIObject(long_description_ref,
                                                       f"{tech_name}LongDescription",
                                                       dataset.nyan_api_objects)
        long_description_raw_api_object.add_raw_parent(
            "engine.util.language.translated.type.TranslatedMarkupFile")
        long_description_location = ForwardRef(tech_group, tech_name)
        long_description_raw_api_object.set_location(long_description_location)

        long_description_raw_api_object.add_raw_member("translations",
                                                       [],
                                                       "engine.util.language.translated.type.TranslatedMarkupFile")

        long_description_forward_ref = ForwardRef(tech_group, long_description_ref)
        raw_api_object.add_raw_member("long_description",
                                      long_description_forward_ref,
                                      "engine.util.tech.Tech")
        tech_group.add_raw_api_object(long_description_raw_api_object)

        # =======================================================================
        # Updates
        # =======================================================================
        patches = []
        patches.extend(DE2TechSubprocessor.get_patches(tech_group))
        raw_api_object.add_raw_member("updates", patches, "engine.util.tech.Tech")

        # =======================================================================
        # Misc (Objects that are not used by the tech group itself, but use its values)
        # =======================================================================
        if tech_group.is_researchable():
            AoCAuxiliarySubprocessor.get_researchable_tech(tech_group)
Beispiel #4
0
    def get_attack_effects(
        tech_group: GenieTechEffectBundleGroup,
        line: GenieGameEntityGroup,
        diff: ConverterObject,
        ability_ref: str
    ) -> list[ForwardRef]:
        """
        Upgrades effects that are used for attacking (unit command: 7)

        :param tech_group: Tech that gets the patch.
        :type tech_group: ...dataformat.converter_object.ConverterObjectGroup
        :param line: Unit/Building line that gets the ability.
        :type line: ...dataformat.converter_object.ConverterObjectGroup
        :param diff: A diff between two ConvertObject instances.
        :type diff: ...dataformat.converter_object.ConverterObject
        :param ability_ref: Reference of the ability raw API object the effects are added to.
        :type ability_ref: str
        :returns: The forward references for the effects.
        :rtype: list
        """
        head_unit_id = line.get_head_unit_id()
        tech_id = tech_group.get_id()
        dataset = line.data

        patches = []

        name_lookup_dict = internal_name_lookups.get_entity_lookups(dataset.game_version)
        armor_lookup_dict = internal_name_lookups.get_armor_class_lookups(dataset.game_version)
        tech_lookup_dict = internal_name_lookups.get_tech_lookups(dataset.game_version)

        tech_name = tech_lookup_dict[tech_id][0]

        diff_attacks = diff["attacks"].value
        for diff_attack in diff_attacks.values():
            if isinstance(diff_attack, NoDiffMember):
                continue

            if isinstance(diff_attack, LeftMissingMember):
                # Create a new attack effect, then patch it in
                attack = diff_attack.ref

                armor_class = attack["type_id"].value
                attack_amount = attack["amount"].value

                if armor_class == -1:
                    continue

                class_name = armor_lookup_dict[armor_class]

                # FlatAttributeChangeDecrease
                effect_parent = "engine.effect.discrete.flat_attribute_change.FlatAttributeChange"
                attack_parent = "engine.effect.discrete.flat_attribute_change.type.FlatAttributeChangeDecrease"

                patch_target_ref = f"{ability_ref}.Batch"
                patch_target_forward_ref = ForwardRef(line, patch_target_ref)

                # Wrapper
                wrapper_name = f"Add{class_name}AttackEffectWrapper"
                wrapper_ref = f"{tech_name}.{wrapper_name}"
                wrapper_raw_api_object = RawAPIObject(wrapper_ref,
                                                      wrapper_name,
                                                      dataset.nyan_api_objects)
                wrapper_raw_api_object.add_raw_parent("engine.util.patch.Patch")

                if isinstance(line, GenieBuildingLineGroup):
                    # Store building upgrades next to their game entity definition,
                    # not in the Age up techs.
                    wrapper_raw_api_object.set_location(("data/game_entity/generic/"
                                                         f"{name_lookup_dict[head_unit_id][1]}/"))
                    wrapper_raw_api_object.set_filename(f"{tech_lookup_dict[tech_id][1]}_upgrade")

                else:
                    wrapper_raw_api_object.set_location(ForwardRef(tech_group, tech_name))

                # Nyan patch
                nyan_patch_name = f"Add{class_name}AttackEffect"
                nyan_patch_ref = f"{tech_name}.{wrapper_name}.{nyan_patch_name}"
                nyan_patch_location = ForwardRef(tech_group, wrapper_ref)
                nyan_patch_raw_api_object = RawAPIObject(nyan_patch_ref,
                                                         nyan_patch_name,
                                                         dataset.nyan_api_objects,
                                                         nyan_patch_location)
                nyan_patch_raw_api_object.add_raw_parent("engine.util.patch.NyanPatch")
                nyan_patch_raw_api_object.set_patch_target(patch_target_forward_ref)

                # New attack effect
                # ============================================================================
                attack_ref = f"{nyan_patch_ref}.{class_name}"
                attack_raw_api_object = RawAPIObject(attack_ref,
                                                     class_name,
                                                     dataset.nyan_api_objects)
                attack_raw_api_object.add_raw_parent(attack_parent)
                attack_location = ForwardRef(tech_group, nyan_patch_ref)
                attack_raw_api_object.set_location(attack_location)

                # Type
                type_ref = f"util.attribute_change_type.types.{class_name}"
                change_type = dataset.pregen_nyan_objects[type_ref].get_nyan_object()
                attack_raw_api_object.add_raw_member("type",
                                                     change_type,
                                                     effect_parent)

                # Min value (optional)
                min_value = dataset.pregen_nyan_objects[("effect.discrete.flat_attribute_change."
                                                         "min_damage.AoE2MinChangeAmount")].get_nyan_object()
                attack_raw_api_object.add_raw_member("min_change_value",
                                                     min_value,
                                                     effect_parent)

                # Max value (optional; not added because there is none in AoE2)

                # Change value
                # =================================================================================
                amount_name = f"{nyan_patch_ref}.{class_name}.ChangeAmount"
                amount_raw_api_object = RawAPIObject(
                    amount_name, "ChangeAmount", dataset.nyan_api_objects)
                amount_raw_api_object.add_raw_parent("engine.util.attribute.AttributeAmount")
                amount_location = ForwardRef(line, attack_ref)
                amount_raw_api_object.set_location(amount_location)

                attribute = dataset.pregen_nyan_objects["util.attribute.types.Health"].get_nyan_object(
                )
                amount_raw_api_object.add_raw_member("type",
                                                     attribute,
                                                     "engine.util.attribute.AttributeAmount")
                amount_raw_api_object.add_raw_member("amount",
                                                     attack_amount,
                                                     "engine.util.attribute.AttributeAmount")

                line.add_raw_api_object(amount_raw_api_object)
                # =================================================================================
                amount_forward_ref = ForwardRef(line, amount_name)
                attack_raw_api_object.add_raw_member("change_value",
                                                     amount_forward_ref,
                                                     effect_parent)

                # Ignore protection
                attack_raw_api_object.add_raw_member("ignore_protection",
                                                     [],
                                                     effect_parent)

                # Effect is added to the line, so it can be referenced by other upgrades
                line.add_raw_api_object(attack_raw_api_object)
                # ============================================================================
                attack_forward_ref = ForwardRef(line, attack_ref)
                nyan_patch_raw_api_object.add_raw_patch_member("effects",
                                                               [attack_forward_ref],
                                                               "engine.util.effect_batch.EffectBatch",
                                                               MemberOperator.ADD)

                patch_forward_ref = ForwardRef(tech_group, nyan_patch_ref)
                wrapper_raw_api_object.add_raw_member("patch",
                                                      patch_forward_ref,
                                                      "engine.util.patch.Patch")

                tech_group.add_raw_api_object(wrapper_raw_api_object)
                tech_group.add_raw_api_object(nyan_patch_raw_api_object)

                wrapper_forward_ref = ForwardRef(tech_group, wrapper_ref)
                patches.append(wrapper_forward_ref)

            elif isinstance(diff_attack, RightMissingMember):
                # Patch the effect out of the ability
                attack = diff_attack.ref

                armor_class = attack["type_id"].value
                class_name = armor_lookup_dict[armor_class]

                patch_target_ref = f"{ability_ref}.Batch"
                patch_target_forward_ref = ForwardRef(line, patch_target_ref)

                # Wrapper
                wrapper_name = f"Remove{class_name}AttackEffectWrapper"
                wrapper_ref = f"{tech_name}.{wrapper_name}"
                wrapper_raw_api_object = RawAPIObject(wrapper_ref,
                                                      wrapper_name,
                                                      dataset.nyan_api_objects)
                wrapper_raw_api_object.add_raw_parent("engine.util.patch.Patch")

                if isinstance(line, GenieBuildingLineGroup):
                    # Store building upgrades next to their game entity definition,
                    # not in the Age up techs.
                    wrapper_raw_api_object.set_location(("data/game_entity/generic/"
                                                         f"{name_lookup_dict[head_unit_id][1]}/"))
                    wrapper_raw_api_object.set_filename(f"{tech_lookup_dict[tech_id][1]}_upgrade")

                else:
                    wrapper_raw_api_object.set_location(ForwardRef(tech_group, tech_name))

                # Nyan patch
                nyan_patch_name = f"Remove{class_name}AttackEffect"
                nyan_patch_ref = f"{tech_name}.{wrapper_name}.{nyan_patch_name}"
                nyan_patch_location = ForwardRef(tech_group, wrapper_ref)
                nyan_patch_raw_api_object = RawAPIObject(nyan_patch_ref,
                                                         nyan_patch_name,
                                                         dataset.nyan_api_objects,
                                                         nyan_patch_location)
                nyan_patch_raw_api_object.add_raw_parent("engine.util.patch.NyanPatch")
                nyan_patch_raw_api_object.set_patch_target(patch_target_forward_ref)

                attack_ref = f"{ability_ref}.{class_name}"
                attack_forward_ref = ForwardRef(line, attack_ref)
                nyan_patch_raw_api_object.add_raw_patch_member("effects",
                                                               [attack_forward_ref],
                                                               "engine.util.effect_batch.EffectBatch",
                                                               MemberOperator.SUBTRACT)

                patch_forward_ref = ForwardRef(tech_group, nyan_patch_ref)
                wrapper_raw_api_object.add_raw_member("patch",
                                                      patch_forward_ref,
                                                      "engine.util.patch.Patch")

                tech_group.add_raw_api_object(wrapper_raw_api_object)
                tech_group.add_raw_api_object(nyan_patch_raw_api_object)

                wrapper_forward_ref = ForwardRef(tech_group, wrapper_ref)
                patches.append(wrapper_forward_ref)

            else:
                diff_armor_class = diff_attack["type_id"]
                if not isinstance(diff_armor_class, NoDiffMember):
                    # If this happens then the attacks are out of order
                    # and we have to try something else
                    raise Exception(f"Could not create effect upgrade for line {repr(line)}: "
                                    "Out of order")

                armor_class = diff_armor_class.ref.value
                attack_amount = diff_attack["amount"].value

                class_name = armor_lookup_dict[armor_class]

                patch_target_ref = f"{ability_ref}.Batch.{class_name}.ChangeAmount"
                patch_target_forward_ref = ForwardRef(line, patch_target_ref)

                # Wrapper
                wrapper_name = f"Change{class_name}AttackWrapper"
                wrapper_ref = f"{tech_name}.{wrapper_name}"
                wrapper_raw_api_object = RawAPIObject(wrapper_ref,
                                                      wrapper_name,
                                                      dataset.nyan_api_objects)
                wrapper_raw_api_object.add_raw_parent("engine.util.patch.Patch")

                if isinstance(line, GenieBuildingLineGroup):
                    # Store building upgrades next to their game entity definition,
                    # not in the Age up techs.
                    wrapper_raw_api_object.set_location(("data/game_entity/generic/"
                                                         f"{name_lookup_dict[head_unit_id][1]}/"))
                    wrapper_raw_api_object.set_filename(f"{tech_lookup_dict[tech_id][1]}_upgrade")

                else:
                    wrapper_raw_api_object.set_location(ForwardRef(tech_group, tech_name))

                # Nyan patch
                nyan_patch_name = f"Change{class_name}Attack"
                nyan_patch_ref = f"{tech_name}.{wrapper_name}.{nyan_patch_name}"
                nyan_patch_location = ForwardRef(tech_group, wrapper_ref)
                nyan_patch_raw_api_object = RawAPIObject(nyan_patch_ref,
                                                         nyan_patch_name,
                                                         dataset.nyan_api_objects,
                                                         nyan_patch_location)
                nyan_patch_raw_api_object.add_raw_parent("engine.util.patch.NyanPatch")
                nyan_patch_raw_api_object.set_patch_target(patch_target_forward_ref)

                nyan_patch_raw_api_object.add_raw_patch_member("amount",
                                                               attack_amount,
                                                               "engine.util.attribute.AttributeAmount",
                                                               MemberOperator.ADD)

                patch_forward_ref = ForwardRef(tech_group, nyan_patch_ref)
                wrapper_raw_api_object.add_raw_member("patch",
                                                      patch_forward_ref,
                                                      "engine.util.patch.Patch")

                tech_group.add_raw_api_object(wrapper_raw_api_object)
                tech_group.add_raw_api_object(nyan_patch_raw_api_object)

                wrapper_forward_ref = ForwardRef(tech_group, wrapper_ref)
                patches.append(wrapper_forward_ref)

        return patches