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
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
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
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
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
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
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
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
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
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
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