Пример #1
0
    def get_patches(cls,
                    converter_group: ConverterObjectGroup) -> list[ForwardRef]:
        """
        Returns the patches for a converter group, depending on the type
        of its effects.
        """
        patches = []
        effects = converter_group.get_effects()
        for effect in effects:
            type_id = effect.get_type()

            if type_id in (0, 4, 5):
                patches.extend(
                    cls.attribute_modify_effect(converter_group, effect))

            elif type_id == 1:
                patches.extend(
                    cls.resource_modify_effect(converter_group, effect))

            elif type_id == 2:
                # Enabling/disabling units: Handled in creatable conditions
                pass

            elif type_id == 3:
                patches.extend(cls.upgrade_unit_effect(converter_group,
                                                       effect))

        return patches
Пример #2
0
    def shoot_projectile_ability(
            converter_group: ConverterObjectGroup,
            line: GenieGameEntityGroup,
            container_obj_ref: str,
            command_id: int,
            diff: ConverterObject = None) -> list[ForwardRef]:
        """
        Creates a patch for the Selectable ability of a line.

        :param converter_group: Group that gets the patch.
        :type converter_group: ...dataformat.converter_object.ConverterObjectGroup
        :param line: Unit/Building line that has the ability.
        :type line: ...dataformat.converter_object.ConverterObjectGroup
        :param container_obj_ref: Reference of the raw API object the patch is nested in.
        :type container_obj_ref: str
        :param diff: A diff between two ConvertObject instances.
        :type diff: ...dataformat.converter_object.ConverterObject
        :returns: The forward references for the generated patches.
        :rtype: list
        """
        head_unit_id = line.get_head_unit_id()
        tech_id = converter_group.get_id()
        dataset = line.data

        patches = []

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

        game_entity_name = name_lookup_dict[head_unit_id][0]
        ability_name = command_lookup_dict[command_id][0]

        changed = False
        if diff:
            diff_animation = diff["attack_sprite_id"]
            diff_comm_sound = diff["command_sound_id"]
            diff_min_range = diff["weapon_range_min"]
            diff_max_range = diff["weapon_range_min"]
            diff_reload_time = diff["attack_speed"]
            # spawn delay also depends on animation
            diff_spawn_delay = diff["frame_delay"]
            diff_spawn_area_offsets = diff["weapon_offset"]

            if any(not isinstance(value, NoDiffMember)
                   for value in (diff_animation, diff_comm_sound,
                                 diff_min_range, diff_max_range,
                                 diff_reload_time, diff_spawn_delay,
                                 diff_spawn_area_offsets)):
                changed = True

        if changed:
            patch_target_ref = f"{game_entity_name}.{ability_name}"
            patch_target_forward_ref = ForwardRef(line, patch_target_ref)

            # Wrapper
            wrapper_name = f"Change{game_entity_name}{ability_name}Wrapper"
            wrapper_ref = f"{container_obj_ref}.{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/%s/" %
                    (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(converter_group, container_obj_ref))

            # Nyan patch
            nyan_patch_name = f"Change{game_entity_name}{ability_name}"
            nyan_patch_ref = f"{container_obj_ref}.{wrapper_name}.{nyan_patch_name}"
            nyan_patch_location = ForwardRef(converter_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)

            if not isinstance(diff_animation, NoDiffMember):
                animations_set = []
                diff_animation_id = diff_animation.get_value()
                if diff_animation_id > -1:
                    # Patch the new animation in
                    animation_forward_ref = AoCUpgradeAbilitySubprocessor.create_animation(
                        converter_group, line, diff_animation_id,
                        nyan_patch_ref, ability_name,
                        "%s_" % command_lookup_dict[command_id][1])
                    animations_set.append(animation_forward_ref)

                nyan_patch_raw_api_object.add_raw_patch_member(
                    "animations", animations_set,
                    "engine.ability.property.type.Animated",
                    MemberOperator.ASSIGN)

            if not isinstance(diff_comm_sound, NoDiffMember):
                sounds_set = []
                diff_comm_sound_id = diff_comm_sound.get_value()
                if diff_comm_sound_id > -1:
                    # Patch the new sound in
                    sound_forward_ref = AoCUpgradeAbilitySubprocessor.create_sound(
                        converter_group, diff_comm_sound_id, nyan_patch_ref,
                        ability_name,
                        "%s_" % command_lookup_dict[command_id][1])
                    sounds_set.append(sound_forward_ref)

                nyan_patch_raw_api_object.add_raw_patch_member(
                    "sounds", sounds_set,
                    "engine.ability.property.type.CommandSound",
                    MemberOperator.ASSIGN)

            if not isinstance(diff_min_range, NoDiffMember):
                min_range = diff_min_range.get_value()

                nyan_patch_raw_api_object.add_raw_patch_member(
                    "min_range", min_range,
                    "engine.ability.type.ShootProjectile", MemberOperator.ADD)

            if not isinstance(diff_max_range, NoDiffMember):
                max_range = diff_max_range.get_value()

                nyan_patch_raw_api_object.add_raw_patch_member(
                    "max_range", max_range,
                    "engine.ability.type.ShootProjectile", MemberOperator.ADD)

            if not isinstance(diff_reload_time, NoDiffMember):
                reload_time = diff_reload_time.get_value()

                nyan_patch_raw_api_object.add_raw_patch_member(
                    "reload_time", reload_time,
                    "engine.ability.type.ShootProjectile", MemberOperator.ADD)

            if not isinstance(diff_spawn_delay, NoDiffMember):
                if not isinstance(diff_animation, NoDiffMember):
                    attack_graphic_id = diff_animation.get_value()

                else:
                    attack_graphic_id = diff_animation.value.get_value()

                attack_graphic = dataset.genie_graphics[attack_graphic_id]
                frame_rate = attack_graphic.get_frame_rate()
                frame_delay = diff_spawn_delay.get_value()
                spawn_delay = frame_rate * frame_delay

                nyan_patch_raw_api_object.add_raw_patch_member(
                    "spawn_delay", spawn_delay,
                    "engine.ability.type.ShootProjectile",
                    MemberOperator.ASSIGN)

            if not isinstance(diff_spawn_area_offsets, NoDiffMember):
                diff_spawn_area_x = diff_spawn_area_offsets[0]
                diff_spawn_area_y = diff_spawn_area_offsets[1]
                diff_spawn_area_z = diff_spawn_area_offsets[2]

                if not isinstance(diff_spawn_area_x, NoDiffMember):
                    spawn_area_x = diff_spawn_area_x.get_value()

                    nyan_patch_raw_api_object.add_raw_patch_member(
                        "spawning_area_offset_x", spawn_area_x,
                        "engine.ability.type.ShootProjectile",
                        MemberOperator.ADD)

                if not isinstance(diff_spawn_area_y, NoDiffMember):
                    spawn_area_y = diff_spawn_area_y.get_value()

                    nyan_patch_raw_api_object.add_raw_patch_member(
                        "spawning_area_offset_y", spawn_area_y,
                        "engine.ability.type.ShootProjectile",
                        MemberOperator.ADD)

                if not isinstance(diff_spawn_area_z, NoDiffMember):
                    spawn_area_z = diff_spawn_area_z.get_value()

                    nyan_patch_raw_api_object.add_raw_patch_member(
                        "spawning_area_offset_z", spawn_area_z,
                        "engine.ability.type.ShootProjectile",
                        MemberOperator.ADD)

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

            converter_group.add_raw_api_object(wrapper_raw_api_object)
            converter_group.add_raw_api_object(nyan_patch_raw_api_object)

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

        return patches
Пример #3
0
    def resource_cost_upgrade(converter_group: ConverterObjectGroup,
                              line: GenieGameEntityGroup,
                              value: typing.Union[int, float],
                              operator: MemberOperator,
                              team: bool = False) -> list[ForwardRef]:
        """
        Creates a patch for the resource modify effect (ID: 100).

        :param converter_group: Tech/Civ that gets the patch.
        :type converter_group: ...dataformat.converter_object.ConverterObjectGroup
        :param line: Unit/Building line that has the ability.
        :type line: ...dataformat.converter_object.ConverterObjectGroup
        :param value: Value used for patching the member.
        :type value: int, float
        :param operator: Operator used for patching the member.
        :type operator: MemberOperator
        :returns: The forward references for the generated patches.
        :rtype: list
        """
        head_unit = line.get_head_unit()
        head_unit_id = line.get_head_unit_id()
        dataset = line.data

        patches = []

        obj_id = converter_group.get_id()
        if isinstance(converter_group, GenieTechEffectBundleGroup):
            tech_lookup_dict = internal_name_lookups.get_tech_lookups(
                dataset.game_version)
            obj_name = tech_lookup_dict[obj_id][0]

        else:
            civ_lookup_dict = internal_name_lookups.get_civ_lookups(
                dataset.game_version)
            obj_name = civ_lookup_dict[obj_id][0]

        name_lookup_dict = internal_name_lookups.get_entity_lookups(
            dataset.game_version)

        game_entity_name = name_lookup_dict[head_unit_id][0]

        for resource_amount in head_unit["resource_cost"].get_value():
            resource_id = resource_amount["type_id"].get_value()

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

            if resource_id == 0:
                resource_name = "Food"

            elif resource_id == 1:
                resource_name = "Carbon"

            elif resource_id == 2:
                resource_name = "Ore"

            elif resource_id == 3:
                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"].get_value():
                continue

            patch_target_ref = "%s.CreatableGameEntity.%sCost.%sAmount" % (
                game_entity_name, game_entity_name, resource_name)
            patch_target_forward_ref = ForwardRef(line, patch_target_ref)

            # Wrapper
            wrapper_name = f"Change{game_entity_name}{resource_name}CostWrapper"
            wrapper_ref = f"{obj_name}.{wrapper_name}"
            wrapper_location = ForwardRef(converter_group, obj_name)
            wrapper_raw_api_object = RawAPIObject(wrapper_ref, wrapper_name,
                                                  dataset.nyan_api_objects,
                                                  wrapper_location)
            wrapper_raw_api_object.add_raw_parent("engine.util.patch.Patch")

            # Nyan patch
            nyan_patch_name = f"Change{game_entity_name}{resource_name}Cost"
            nyan_patch_ref = f"{obj_name}.{wrapper_name}.{nyan_patch_name}"
            nyan_patch_location = ForwardRef(converter_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", value, "engine.util.resource.ResourceAmount",
                operator)

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

            if team:
                team_property = dataset.pregen_nyan_objects[
                    "util.patch.property.types.Team"].get_nyan_object()
                properties = {
                    dataset.nyan_api_objects["engine.util.patch.property.type.Diplomatic"]:
                    team_property
                }
                wrapper_raw_api_object.add_raw_member(
                    "properties", properties, "engine.util.patch.Patch")

            converter_group.add_raw_api_object(wrapper_raw_api_object)
            converter_group.add_raw_api_object(nyan_patch_raw_api_object)

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

        return patches
Пример #4
0
    def get_patches(cls,
                    converter_group: ConverterObjectGroup) -> list[ForwardRef]:
        """
        Returns the patches for a converter group, depending on the type
        of its effects.
        """
        patches = []
        dataset = converter_group.data
        team_bonus = False

        if isinstance(converter_group, CivTeamBonus):
            effects = converter_group.get_effects()

            # Change converter group here, so that the Civ object gets the patches
            converter_group = dataset.civ_groups[
                converter_group.get_civilization_id()]
            team_bonus = True

        elif isinstance(converter_group, CivBonus):
            effects = converter_group.get_effects()

            # Change converter group here, so that the Civ object gets the patches
            converter_group = dataset.civ_groups[
                converter_group.get_civilization_id()]

        else:
            effects = converter_group.get_effects()

        team_effect = False
        for effect in effects:
            type_id = effect.get_type()

            if team_bonus or type_id in (10, 11, 12, 13, 14, 15, 16):
                team_effect = True
                type_id -= 10

            if type_id in (0, 4, 5):
                patches.extend(
                    cls.attribute_modify_effect(converter_group,
                                                effect,
                                                team=team_effect))

            elif type_id in (1, 6):
                patches.extend(
                    cls.resource_modify_effect(converter_group,
                                               effect,
                                               team=team_effect))

            elif type_id == 2:
                # Enabling/disabling units: Handled in creatable conditions
                pass

            elif type_id == 3:
                patches.extend(
                    AoCTechSubprocessor.upgrade_unit_effect(
                        converter_group, effect))

            elif type_id == 101:
                patches.extend(
                    AoCTechSubprocessor.tech_cost_modify_effect(
                        converter_group, effect, team=team_effect))

            elif type_id == 102:
                # Tech disable: Only used for civ tech tree
                pass

            elif type_id == 103:
                patches.extend(
                    AoCTechSubprocessor.tech_time_modify_effect(
                        converter_group, effect, team=team_effect))

            team_effect = False

        return patches
Пример #5
0
    def ballistics_upgrade(converter_group: ConverterObjectGroup,
                           line: GenieGameEntityGroup,
                           value: typing.Any,
                           operator: MemberOperator,
                           team: bool = False) -> list[ForwardRef]:
        """
        Creates a patch for the ballistics modify effect (ID: 19).

        :param converter_group: Tech/Civ that gets the patch.
        :type converter_group: ...dataformat.converter_object.ConverterObjectGroup
        :param line: Unit/Building line that has the ability.
        :type line: ...dataformat.converter_object.ConverterObjectGroup
        :param value: Value used for patching the member.
        :type value: Any
        :param operator: Operator used for patching the member.
        :type operator: MemberOperator
        :returns: The forward references for the generated patches.
        :rtype: list
        """
        head_unit = line.get_head_unit()
        head_unit_id = line.get_head_unit_id()
        dataset = line.data

        patches = []

        if value == 0:
            target_mode = dataset.nyan_api_objects[
                "engine.util.target_mode.type.CurrentPosition"]

        elif value == 1:
            target_mode = dataset.nyan_api_objects[
                "engine.util.target_mode.type.ExpectedPosition"]

        obj_id = converter_group.get_id()
        if isinstance(converter_group, GenieTechEffectBundleGroup):
            tech_lookup_dict = internal_name_lookups.get_tech_lookups(
                dataset.game_version)
            obj_name = tech_lookup_dict[obj_id][0]

        else:
            civ_lookup_dict = internal_name_lookups.get_civ_lookups(
                dataset.game_version)
            obj_name = civ_lookup_dict[obj_id][0]

        name_lookup_dict = internal_name_lookups.get_entity_lookups(
            dataset.game_version)

        game_entity_name = name_lookup_dict[head_unit_id][0]

        projectile_id0 = head_unit["projectile_id0"].value
        if projectile_id0 > -1:
            patch_target_ref = f"{game_entity_name}.ShootProjectile.Projectile0.Projectile"
            patch_target_forward_ref = ForwardRef(line, patch_target_ref)

            # Wrapper
            wrapper_name = f"Change{game_entity_name}Projectile0TargetModeWrapper"
            wrapper_ref = f"{obj_name}.{wrapper_name}"
            wrapper_location = ForwardRef(converter_group, obj_name)
            wrapper_raw_api_object = RawAPIObject(wrapper_ref, wrapper_name,
                                                  dataset.nyan_api_objects,
                                                  wrapper_location)
            wrapper_raw_api_object.add_raw_parent("engine.util.patch.Patch")

            # Nyan patch
            nyan_patch_name = f"Change{game_entity_name}Projectile0TargetMode"
            nyan_patch_ref = f"{obj_name}.{wrapper_name}.{nyan_patch_name}"
            nyan_patch_location = ForwardRef(converter_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(
                "target_mode", target_mode, "engine.ability.type.Projectile",
                operator)

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

            if team:
                team_property = dataset.pregen_nyan_objects[
                    "util.patch.property.types.Team"].get_nyan_object()
                properties = {
                    dataset.nyan_api_objects["engine.util.patch.property.type.Diplomatic"]:
                    team_property
                }
                wrapper_raw_api_object.add_raw_member(
                    "properties", properties, "engine.util.patch.Patch")

            converter_group.add_raw_api_object(wrapper_raw_api_object)
            converter_group.add_raw_api_object(nyan_patch_raw_api_object)

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

        return patches
Пример #6
0
    def upgrade_unit_effect(converter_group: ConverterObjectGroup,
                            effect: GenieEffectObject) -> list[ForwardRef]:
        """
        Creates the patches for upgrading entities in a line.
        """
        patches = []
        tech_id = converter_group.get_id()
        dataset = converter_group.data

        tech_lookup_dict = internal_name_lookups.get_tech_lookups(
            dataset.game_version)

        head_unit_id = effect["attr_a"].get_value()
        upgrade_target_id = effect["attr_b"].get_value()

        if head_unit_id not in dataset.unit_ref.keys() or\
                upgrade_target_id not in dataset.unit_ref.keys():
            # Skip annexes or transform units
            return patches

        line = dataset.unit_ref[head_unit_id]
        upgrade_target_pos = line.get_unit_position(upgrade_target_id)
        upgrade_source_pos = upgrade_target_pos - 1

        upgrade_source = line.line[upgrade_source_pos]
        upgrade_target = line.line[upgrade_target_pos]
        tech_name = tech_lookup_dict[tech_id][0]

        diff = upgrade_source.diff(upgrade_target)

        patches.extend(
            AoCUpgradeAbilitySubprocessor.death_ability(
                converter_group, line, tech_name, diff))
        patches.extend(
            AoCUpgradeAbilitySubprocessor.despawn_ability(
                converter_group, line, tech_name, diff))
        patches.extend(
            AoCUpgradeAbilitySubprocessor.idle_ability(converter_group, line,
                                                       tech_name, diff))
        patches.extend(
            AoCUpgradeAbilitySubprocessor.live_ability(converter_group, line,
                                                       tech_name, diff))
        patches.extend(
            AoCUpgradeAbilitySubprocessor.los_ability(converter_group, line,
                                                      tech_name, diff))
        patches.extend(
            AoCUpgradeAbilitySubprocessor.named_ability(
                converter_group, line, tech_name, diff))
        # patches.extend(AoCUpgradeAbilitySubprocessor.resistance_ability(converter_group, line, tech_name, diff))
        patches.extend(
            AoCUpgradeAbilitySubprocessor.selectable_ability(
                converter_group, line, tech_name, diff))
        patches.extend(
            AoCUpgradeAbilitySubprocessor.turn_ability(converter_group, line,
                                                       tech_name, diff))

        if line.is_projectile_shooter():
            patches.extend(
                RoRUpgradeAbilitySubprocessor.shoot_projectile_ability(
                    converter_group, line, tech_name, 7, diff))

        elif line.is_melee() or line.is_ranged():
            if line.has_command(7):
                # Attack
                patches.extend(
                    AoCUpgradeAbilitySubprocessor.
                    apply_discrete_effect_ability(converter_group,
                                                  line, tech_name, 7,
                                                  line.is_ranged(), diff))

        if isinstance(line, GenieUnitLineGroup):
            patches.extend(
                AoCUpgradeAbilitySubprocessor.move_ability(
                    converter_group, line, tech_name, diff))

        if isinstance(line, GenieBuildingLineGroup):
            # TODO: Damage percentages change
            # patches.extend(AoCUpgradeAbilitySubprocessor.attribute_change_tracker_ability(converter_group, line,
            #                                                                               tech_name, diff))
            pass

        return patches
Пример #7
0
    def tech_cost_modify_effect(
        converter_group: ConverterObjectGroup,
        effect: GenieEffectObject,
        team: bool = False
    ) -> list[ForwardRef]:
        """
        Creates the patches for modifying tech costs.
        """
        patches = []
        dataset = converter_group.data

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

        obj_id = converter_group.get_id()
        if isinstance(converter_group, GenieTechEffectBundleGroup):
            obj_name = tech_lookup_dict[obj_id][0]

        else:
            obj_name = civ_lookup_dict[obj_id][0]

        tech_id = effect["attr_a"].get_value()
        resource_id = effect["attr_b"].get_value()
        mode = effect["attr_c"].get_value()
        amount = int(effect["attr_d"].get_value())

        if tech_id not in tech_lookup_dict.keys():
            # Skips some legacy techs from AoK such as the tech for bombard cannon
            return patches

        tech_group = dataset.tech_groups[tech_id]
        tech_name = tech_lookup_dict[tech_id][0]

        if resource_id == 0:
            resource_name = "Food"

        elif resource_id == 1:
            resource_name = "Wood"

        elif resource_id == 2:
            resource_name = "Stone"

        elif resource_id == 3:
            resource_name = "Gold"

        else:
            raise Exception("no valid resource ID found")

        # Check if the tech actually costs an amount of the defined resource
        for resource_amount in tech_group.tech["research_resource_costs"].get_value():
            cost_resource_id = resource_amount["type_id"].get_value()

            if cost_resource_id == resource_id:
                break

        else:
            # Skip patch generation if no matching resource cost was found
            return patches

        if mode == 0:
            operator = MemberOperator.ASSIGN

        else:
            operator = MemberOperator.ADD

        patch_target_ref = "%s.ResearchableTech.%sCost.%sAmount" % (tech_name,
                                                                    tech_name,
                                                                    resource_name)
        patch_target_forward_ref = ForwardRef(tech_group, patch_target_ref)

        # Wrapper
        wrapper_name = f"Change{tech_name}CostWrapper"
        wrapper_ref = f"{tech_name}.{wrapper_name}"
        wrapper_location = ForwardRef(converter_group, obj_name)
        wrapper_raw_api_object = RawAPIObject(wrapper_ref,
                                              wrapper_name,
                                              dataset.nyan_api_objects,
                                              wrapper_location)
        wrapper_raw_api_object.add_raw_parent("engine.util.patch.Patch")

        # Nyan patch
        nyan_patch_name = f"Change{tech_name}Cost"
        nyan_patch_ref = f"{tech_name}.{wrapper_name}.{nyan_patch_name}"
        nyan_patch_location = ForwardRef(converter_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",
                                                       amount,
                                                       "engine.util.resource.ResourceAmount",
                                                       operator)

        if team:
            team_property = dataset.pregen_nyan_objects["util.patch.property.types.Team"].get_nyan_object(
            )
            properties = {
                dataset.nyan_api_objects["engine.util.patch.property.type.Diplomatic"]: team_property
            }
            wrapper_raw_api_object.add_raw_member("properties",
                                                  properties,
                                                  "engine.util.patch.Patch")

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

        converter_group.add_raw_api_object(wrapper_raw_api_object)
        converter_group.add_raw_api_object(nyan_patch_raw_api_object)

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

        return patches
Пример #8
0
    def tech_time_modify_effect(
        converter_group: ConverterObjectGroup,
        effect: GenieEffectObject,
        team: bool = False
    ) -> list[ForwardRef]:
        """
        Creates the patches for modifying tech research times.
        """
        patches = []
        dataset = converter_group.data

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

        obj_id = converter_group.get_id()
        if isinstance(converter_group, GenieTechEffectBundleGroup):
            obj_name = tech_lookup_dict[obj_id][0]

        else:
            obj_name = civ_lookup_dict[obj_id][0]

        tech_id = effect["attr_a"].get_value()
        mode = effect["attr_c"].get_value()
        research_time = effect["attr_d"].get_value()

        if tech_id not in tech_lookup_dict.keys():
            # Skips some legacy techs from AoK such as the tech for bombard cannon
            return patches

        tech_group = dataset.tech_groups[tech_id]
        tech_name = tech_lookup_dict[tech_id][0]

        if mode == 0:
            operator = MemberOperator.ASSIGN

        else:
            operator = MemberOperator.ADD

        patch_target_ref = f"{tech_name}.ResearchableTech"
        patch_target_forward_ref = ForwardRef(tech_group, patch_target_ref)

        # Wrapper
        wrapper_name = f"Change{tech_name}ResearchTimeWrapper"
        wrapper_ref = f"{tech_name}.{wrapper_name}"
        wrapper_location = ForwardRef(converter_group, obj_name)
        wrapper_raw_api_object = RawAPIObject(wrapper_ref,
                                              wrapper_name,
                                              dataset.nyan_api_objects,
                                              wrapper_location)
        wrapper_raw_api_object.add_raw_parent("engine.util.patch.Patch")

        # Nyan patch
        nyan_patch_name = f"Change{tech_name}ResearchTime"
        nyan_patch_ref = f"{tech_name}.{wrapper_name}.{nyan_patch_name}"
        nyan_patch_location = ForwardRef(converter_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("research_time",
                                                       research_time,
                                                       "engine.util.research.ResearchableTech",
                                                       operator)

        if team:
            team_property = dataset.pregen_nyan_objects["util.patch.property.types.Team"].get_nyan_object(
            )
            properties = {
                dataset.nyan_api_objects["engine.util.patch.property.type.Diplomatic"]: team_property
            }
            wrapper_raw_api_object.add_raw_member("properties",
                                                  properties,
                                                  "engine.util.patch.Patch")

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

        converter_group.add_raw_api_object(wrapper_raw_api_object)
        converter_group.add_raw_api_object(nyan_patch_raw_api_object)

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

        return patches
Пример #9
0
    def upgrade_unit_effect(
        converter_group: ConverterObjectGroup,
        effect: GenieEffectObject
    ) -> list[ForwardRef]:
        """
        Creates the patches for upgrading entities in a line.
        """
        patches = []
        tech_id = converter_group.get_id()
        dataset = converter_group.data

        tech_lookup_dict = internal_name_lookups.get_tech_lookups(dataset.game_version)

        upgrade_source_id = effect["attr_a"].get_value()
        upgrade_target_id = effect["attr_b"].get_value()

        if upgrade_source_id not in dataset.unit_ref.keys() or\
                upgrade_target_id not in dataset.unit_ref.keys():
            # Skip annexes or transform units
            return patches

        line = dataset.unit_ref[upgrade_source_id]
        upgrade_source_pos = line.get_unit_position(upgrade_source_id)
        try:
            upgrade_target_pos = line.get_unit_position(upgrade_target_id)

        except KeyError:
            # TODO: Implement branching line upgrades
            warn(f"Could not create upgrade from unit {upgrade_source_id} to {upgrade_target_id}")
            return patches

        if isinstance(line, GenieBuildingLineGroup):
            # Building upgrades always reference the head unit
            # so we use the decremented target id instead
            upgrade_source_pos = upgrade_target_pos - 1

        elif upgrade_target_pos - upgrade_source_pos != 1:
            # Skip effects that upgrades entities not next to each other in
            # the line.
            return patches

        upgrade_source = line.line[upgrade_source_pos]
        upgrade_target = line.line[upgrade_target_pos]
        tech_name = tech_lookup_dict[tech_id][0]

        diff = upgrade_source.diff(upgrade_target)

        patches.extend(AoCUpgradeAbilitySubprocessor.death_ability(
            converter_group, line, tech_name, diff))
        patches.extend(AoCUpgradeAbilitySubprocessor.despawn_ability(
            converter_group, line, tech_name, diff))
        patches.extend(AoCUpgradeAbilitySubprocessor.idle_ability(
            converter_group, line, tech_name, diff))
        patches.extend(AoCUpgradeAbilitySubprocessor.live_ability(
            converter_group, line, tech_name, diff))
        patches.extend(AoCUpgradeAbilitySubprocessor.los_ability(
            converter_group, line, tech_name, diff))
        patches.extend(AoCUpgradeAbilitySubprocessor.named_ability(
            converter_group, line, tech_name, diff))
        patches.extend(AoCUpgradeAbilitySubprocessor.resistance_ability(
            converter_group, line, tech_name, diff))
        patches.extend(AoCUpgradeAbilitySubprocessor.selectable_ability(
            converter_group, line, tech_name, diff))
        patches.extend(AoCUpgradeAbilitySubprocessor.turn_ability(
            converter_group, line, tech_name, diff))

        if line.is_projectile_shooter():
            patches.extend(AoCUpgradeAbilitySubprocessor.shoot_projectile_ability(converter_group, line,
                                                                                  tech_name,
                                                                                  upgrade_source,
                                                                                  upgrade_target,
                                                                                  7, diff))
        elif line.is_melee() or line.is_ranged():
            if line.has_command(7):
                # Attack
                patches.extend(AoCUpgradeAbilitySubprocessor.apply_discrete_effect_ability(converter_group,
                                                                                           line, tech_name,
                                                                                           7,
                                                                                           line.is_ranged(),
                                                                                           diff))

        if isinstance(line, GenieUnitLineGroup):
            patches.extend(AoCUpgradeAbilitySubprocessor.move_ability(converter_group, line,
                                                                      tech_name, diff))

        if isinstance(line, GenieBuildingLineGroup):
            patches.extend(AoCUpgradeAbilitySubprocessor.attribute_change_tracker_ability(converter_group, line,
                                                                                          tech_name, diff))

        return patches
Пример #10
0
    def berserk_heal_rate_upgrade(
        converter_group: ConverterObjectGroup,
        value: typing.Union[int, float],
        operator: MemberOperator,
        team: bool = False
    ) -> list[ForwardRef]:
        """
        Creates a patch for the berserk heal rate modify effect (ID: 96).

        :param converter_group: Tech/Civ that gets the patch.
        :type converter_group: ...dataformat.converter_object.ConverterObjectGroup
        :param value: Value used for patching the member.
        :type value: int, float
        :param operator: Operator used for patching the member.
        :type operator: MemberOperator
        :returns: The forward references for the generated patches.
        :rtype: list
        """
        berserk_id = 8
        dataset = converter_group.data
        line = dataset.unit_lines[berserk_id]

        patches = []

        name_lookup_dict = internal_name_lookups.get_entity_lookups(dataset.game_version)

        obj_id = converter_group.get_id()
        if isinstance(converter_group, GenieTechEffectBundleGroup):
            tech_lookup_dict = internal_name_lookups.get_tech_lookups(dataset.game_version)
            obj_name = tech_lookup_dict[obj_id][0]

        else:
            civ_lookup_dict = internal_name_lookups.get_civ_lookups(dataset.game_version)
            obj_name = civ_lookup_dict[obj_id][0]

        game_entity_name = name_lookup_dict[berserk_id][0]

        patch_target_ref = f"{game_entity_name}.RegenerateHealth.HealthRate"
        patch_target_forward_ref = ForwardRef(line, patch_target_ref)

        # Wrapper
        wrapper_name = f"Change{game_entity_name}HealthRegenerationWrapper"
        wrapper_ref = f"{obj_name}.{wrapper_name}"
        wrapper_location = ForwardRef(converter_group, obj_name)
        wrapper_raw_api_object = RawAPIObject(wrapper_ref,
                                              wrapper_name,
                                              dataset.nyan_api_objects,
                                              wrapper_location)
        wrapper_raw_api_object.add_raw_parent("engine.util.patch.Patch")

        # Nyan patch
        nyan_patch_name = f"Change{game_entity_name}HealthRegeneration"
        nyan_patch_ref = f"{obj_name}.{wrapper_name}.{nyan_patch_name}"
        nyan_patch_location = ForwardRef(converter_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)

        # Regeneration is on a counter, so we have to invert the value
        value = 1 / value
        nyan_patch_raw_api_object.add_raw_patch_member("rate",
                                                       value,
                                                       "engine.util.attribute.AttributeRate",
                                                       operator)

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

        if team:
            team_property = dataset.pregen_nyan_objects["util.patch.property.types.Team"].get_nyan_object(
            )
            properties = {
                dataset.nyan_api_objects["engine.util.patch.property.type.Diplomatic"]: team_property
            }
            wrapper_raw_api_object.add_raw_member("properties",
                                                  properties,
                                                  "engine.util.patch.Patch")

        converter_group.add_raw_api_object(wrapper_raw_api_object)
        converter_group.add_raw_api_object(nyan_patch_raw_api_object)

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

        return patches
Пример #11
0
    def monk_conversion_upgrade(
        converter_group: ConverterObjectGroup,
        value: typing.Any,
        operator: MemberOperator,
        team: bool = False
    ) -> list[ForwardRef]:
        """
        Creates a patch for the monk conversion effect (ID: 27).

        :param converter_group: Tech/Civ that gets the patch.
        :type converter_group: ...dataformat.converter_object.ConverterObjectGroup
        :param value: Value used for patching the member.
        :type value: Any
        :param operator: Operator used for patching the member.
        :type operator: MemberOperator
        :returns: The forward references for the generated patches.
        :rtype: list
        """
        force_ids = [115, 180]
        dataset = converter_group.data

        patches = []

        for force_id in force_ids:
            line = dataset.unit_lines[force_id]

            name_lookup_dict = internal_name_lookups.get_entity_lookups(dataset.game_version)

            obj_id = converter_group.get_id()
            if isinstance(converter_group, GenieTechEffectBundleGroup):
                tech_lookup_dict = internal_name_lookups.get_tech_lookups(dataset.game_version)
                obj_name = tech_lookup_dict[obj_id][0]

            else:
                civ_lookup_dict = internal_name_lookups.get_civ_lookups(dataset.game_version)
                obj_name = civ_lookup_dict[obj_id][0]

            game_entity_name = name_lookup_dict[force_id][0]

            patch_target_ref = f"{game_entity_name}.Convert"
            patch_target_forward_ref = ForwardRef(line, patch_target_ref)

            # Wrapper
            wrapper_name = f"Enable{game_entity_name}ConversionWrapper"
            wrapper_ref = f"{obj_name}.{wrapper_name}"
            wrapper_location = ForwardRef(converter_group, obj_name)
            wrapper_raw_api_object = RawAPIObject(wrapper_ref,
                                                  wrapper_name,
                                                  dataset.nyan_api_objects,
                                                  wrapper_location)
            wrapper_raw_api_object.add_raw_parent("engine.util.patch.Patch")

            # Nyan patch
            nyan_patch_name = f"Enable{game_entity_name}Conversion"
            nyan_patch_ref = f"{obj_name}.{wrapper_name}.{nyan_patch_name}"
            nyan_patch_location = ForwardRef(converter_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)

            monk_forward_ref = ForwardRef(line, game_entity_name)
            nyan_patch_raw_api_object.add_raw_patch_member("blacklisted_entities",
                                                           [monk_forward_ref],
                                                           "engine.ability.type.ApplyDiscreteEffect",
                                                           MemberOperator.SUBTRACT)

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

            if team:
                team_property = dataset.pregen_nyan_objects["util.patch.property.types.Team"].get_nyan_object(
                )
                properties = {
                    dataset.nyan_api_objects["engine.util.patch.property.type.Diplomatic"]: team_property
                }
                wrapper_raw_api_object.add_raw_member("properties",
                                                      properties,
                                                      "engine.util.patch.Patch")

            converter_group.add_raw_api_object(wrapper_raw_api_object)
            converter_group.add_raw_api_object(nyan_patch_raw_api_object)

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

        return patches
Пример #12
0
    def building_conversion_upgrade(
        converter_group: ConverterObjectGroup,
        value: typing.Any,
        operator: MemberOperator,
        team: bool = False
    ) -> list[ForwardRef]:
        """
        Creates a patch for the building conversion effect (ID: 28).

        :param converter_group: Tech/Civ that gets the patch.
        :type converter_group: ...dataformat.converter_object.ConverterObjectGroup
        :param value: Value used for patching the member.
        :type value: Any
        :param operator: Operator used for patching the member.
        :type operator: MemberOperator
        :returns: The forward references for the generated patches.
        :rtype: list
        """
        force_ids = [115, 180]
        dataset = converter_group.data

        patches = []

        for force_id in force_ids:
            line = dataset.unit_lines[force_id]

            name_lookup_dict = internal_name_lookups.get_entity_lookups(dataset.game_version)

            obj_id = converter_group.get_id()
            if isinstance(converter_group, GenieTechEffectBundleGroup):
                tech_lookup_dict = internal_name_lookups.get_tech_lookups(dataset.game_version)
                obj_name = tech_lookup_dict[obj_id][0]

            else:
                civ_lookup_dict = internal_name_lookups.get_civ_lookups(dataset.game_version)
                obj_name = civ_lookup_dict[obj_id][0]

            game_entity_name = name_lookup_dict[force_id][0]

            patch_target_ref = f"{game_entity_name}.Convert"
            patch_target_forward_ref = ForwardRef(line, patch_target_ref)

            # Building conversion

            # Wrapper
            wrapper_name = "EnableBuildingConversionWrapper"
            wrapper_ref = f"{obj_name}.{wrapper_name}"
            wrapper_location = ForwardRef(converter_group, obj_name)
            wrapper_raw_api_object = RawAPIObject(wrapper_ref,
                                                  wrapper_name,
                                                  dataset.nyan_api_objects,
                                                  wrapper_location)
            wrapper_raw_api_object.add_raw_parent("engine.util.patch.Patch")

            # Nyan patch
            nyan_patch_name = "EnableBuildingConversion"
            nyan_patch_ref = f"{obj_name}.{wrapper_name}.{nyan_patch_name}"
            nyan_patch_location = ForwardRef(converter_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 allowed types
            allowed_types = [
                dataset.pregen_nyan_objects["util.game_entity_type.types.Building"].get_nyan_object(
                )
            ]
            nyan_patch_raw_api_object.add_raw_patch_member("allowed_types",
                                                           allowed_types,
                                                           "engine.ability.type.ApplyDiscreteEffect",
                                                           MemberOperator.ADD)

            # Blacklisted buildings
            tc_line = dataset.building_lines[109]
            farm_line = dataset.building_lines[50]
            temple_line = dataset.building_lines[104]
            wonder_line = dataset.building_lines[276]

            blacklisted_forward_refs = [ForwardRef(tc_line, "CommandCenter"),
                                        ForwardRef(farm_line, "Farm"),
                                        ForwardRef(temple_line, "Temple"),
                                        ForwardRef(wonder_line, "Monument"),
                                        ]
            nyan_patch_raw_api_object.add_raw_patch_member("blacklisted_entities",
                                                           blacklisted_forward_refs,
                                                           "engine.ability.type.ApplyDiscreteEffect",
                                                           MemberOperator.ADD)

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

            converter_group.add_raw_api_object(wrapper_raw_api_object)
            converter_group.add_raw_api_object(nyan_patch_raw_api_object)

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

        return patches
Пример #13
0
    def cost_carbon_upgrade(converter_group: ConverterObjectGroup,
                            line: GenieGameEntityGroup,
                            value: typing.Union[int, float],
                            operator: MemberOperator,
                            team: bool = False) -> list[ForwardRef]:
        """
        Creates a patch for the carbon cost modify effect (ID: 104).

        :param converter_group: Tech/Civ that gets the patch.
        :type converter_group: ...dataformat.converter_object.ConverterObjectGroup
        :param line: Unit/Building line that has the ability.
        :type line: ...dataformat.converter_object.ConverterObjectGroup
        :param value: Value used for patching the member.
        :type value: int, float
        :param operator: Operator used for patching the member.
        :type operator: MemberOperator
        :returns: The forward references for the generated patches.
        :rtype: list
        """
        head_unit_id = line.get_head_unit_id()
        dataset = line.data

        patches = []

        obj_id = converter_group.get_id()
        if isinstance(converter_group, GenieTechEffectBundleGroup):
            tech_lookup_dict = internal_name_lookups.get_tech_lookups(
                dataset.game_version)
            obj_name = tech_lookup_dict[obj_id][0]

        else:
            civ_lookup_dict = internal_name_lookups.get_civ_lookups(
                dataset.game_version)
            obj_name = civ_lookup_dict[obj_id][0]

        name_lookup_dict = internal_name_lookups.get_entity_lookups(
            dataset.game_version)

        game_entity_name = name_lookup_dict[head_unit_id][0]

        patch_target_ref = (f"{game_entity_name}.CreatableGameEntity."
                            f"{game_entity_name}Cost.CarbonAmount")
        patch_target_forward_ref = ForwardRef(line, patch_target_ref)

        # Wrapper
        wrapper_name = f"Change{game_entity_name}CarbonCostWrapper"
        wrapper_ref = f"{obj_name}.{wrapper_name}"
        wrapper_location = ForwardRef(converter_group, obj_name)
        wrapper_raw_api_object = RawAPIObject(wrapper_ref, wrapper_name,
                                              dataset.nyan_api_objects,
                                              wrapper_location)
        wrapper_raw_api_object.add_raw_parent("engine.util.patch.Patch")

        # Nyan patch
        nyan_patch_name = f"Change{game_entity_name}CarbonCost"
        nyan_patch_ref = f"{obj_name}.{wrapper_name}.{nyan_patch_name}"
        nyan_patch_location = ForwardRef(converter_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", value, "engine.util.resource.ResourceAmount", operator)

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

        if team:
            team_property = dataset.pregen_nyan_objects[
                "util.patch.property.types.Team"].get_nyan_object()
            properties = {
                dataset.nyan_api_objects["engine.util.patch.property.type.Diplomatic"]:
                team_property
            }
            wrapper_raw_api_object.add_raw_member("properties", properties,
                                                  "engine.util.patch.Patch")

        converter_group.add_raw_api_object(wrapper_raw_api_object)
        converter_group.add_raw_api_object(nyan_patch_raw_api_object)

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

        return patches