using HarmonyLib; using System.Collections.Generic; using System.Reflection.Emit; using UniLinq; using UnityEngine; [HarmonyPatch] public static class DamagePatches { [HarmonyPatch(typeof(EntityAlive), nameof(EntityAlive.damageEntityLocal))] [HarmonyTranspiler] private static IEnumerable Transpiler_damageEntityLocal_EntityAlive(IEnumerable instructions) { var codes = instructions.ToList(); var mtd_calc = AccessTools.Method(typeof(Equipment), nameof(Equipment.CalcDamage)); for (int i = 0; i < codes.Count; i++) { if (codes[i].Calls(mtd_calc)) { codes[i] = CodeInstruction.Call(typeof(DamagePatches), nameof(DamagePatches.CalcEquipmentDamage)); codes.RemoveRange(i - 12, 12); codes.InsertRange(i - 12, new[] { new CodeInstruction(OpCodes.Ldarg_0), CodeInstruction.LoadField(typeof(EntityAlive), nameof(EntityAlive.MinEventContext)), CodeInstruction.LoadField(typeof(MinEventParams), nameof(MinEventParams.Other)) }); break; } } return codes; } [HarmonyPatch(typeof(ItemActionAttack), nameof(ItemActionAttack.Hit))] [HarmonyTranspiler] private static IEnumerable Transpiler_Hit_ItemActionAttack(IEnumerable instructions) { var codes = instructions.ToList(); var mtd_getdamagegroup = AccessTools.Method(typeof(DamageSource), nameof(DamageSource.GetEntityDamageEquipmentSlotGroup)); for (int i = 0; i < codes.Count; i++) { if (codes[i].Calls(mtd_getdamagegroup)) { codes.InsertRange(i + 3, new[] { new CodeInstruction(OpCodes.Ldloc_S, codes[i - 2].operand), new CodeInstruction(OpCodes.Ldloc_S, codes[i - 1].operand), CodeInstruction.Call(typeof(DamageSource), nameof(DamageSource.GetEntityDamageBodyPart)), CodeInstruction.Call(typeof(DamagePatches), nameof(DamagePatches.GetBodyPartTags)), CodeInstruction.Call(typeof(FastTags), "op_BitwiseOr") }); break; } } return codes; } private static void CalcEquipmentDamage(Equipment equipment, ref DamageResponse damageResponse, EntityAlive attacker) { damageResponse.ArmorDamage = damageResponse.Strength; if (damageResponse.Source.DamageTypeTag.Test_AnySet(Equipment.physicalDamageTypes)) { if (damageResponse.Strength > 0) { float totalPhysicalArmorResistPercent = GetTotalPhysicalArmorResistPercent(equipment, in damageResponse, attacker) * .01f; damageResponse.ArmorDamage = Utils.FastMax((totalPhysicalArmorResistPercent > 0f) ? 1 : 0, Mathf.RoundToInt((float)damageResponse.Strength * totalPhysicalArmorResistPercent)); damageResponse.Strength -= damageResponse.ArmorDamage; return; } } else { damageResponse.Strength = Mathf.RoundToInt(Utils.FastMax(0f, (float)damageResponse.Strength * (1f - EffectManager.GetValue(PassiveEffects.ElementalDamageResist, null, 0f, equipment.m_entity, null, damageResponse.Source.DamageTypeTag) * .01f))); damageResponse.ArmorDamage = Mathf.RoundToInt((float)Utils.FastMax(0, damageResponse.ArmorDamage - damageResponse.Strength)); } } private static float GetTotalPhysicalArmorResistPercent(Equipment equipment, in DamageResponse damageResponse, EntityAlive attacker) { if (!equipment?.m_entity) return 0f; FastTags bodyPartTags = GetBodyPartTags(damageResponse.HitBodyPart); float resist = EffectManager.GetValue(PassiveEffects.PhysicalDamageResist, null, 0f, equipment.m_entity, null, Equipment.coreDamageResist | bodyPartTags); if (attacker) { attacker.MinEventContext.Other = equipment.m_entity; attacker.MinEventContext.ItemValue = damageResponse.Source.AttackingItem ?? ItemValue.None; if (damageResponse.Source.AttackingItem != null) { if (damageResponse.Source.AttackingItem.ItemClass.Actions[1] is ItemActionProjectile) { return MultiActionReversePatches.ProjectileGetValue(PassiveEffects.TargetArmor, damageResponse.Source.AttackingItem, resist, attacker, null, damageResponse.Source.AttackingItem.ItemClass.ItemTags | bodyPartTags); } return EffectManager.GetValue(PassiveEffects.TargetArmor, damageResponse.Source.AttackingItem, resist, attacker, null, damageResponse.Source.AttackingItem.ItemClass.ItemTags | bodyPartTags); } return EffectManager.GetValue(PassiveEffects.TargetArmor, null, resist, attacker, null, bodyPartTags); } return resist; } public static FastTags GetBodyPartTags(EnumBodyPartHit bodyparts) { if ((bodyparts & EnumBodyPartHit.LeftUpperArm) > EnumBodyPartHit.None) { return LeftUpperArmTags; } if ((bodyparts & EnumBodyPartHit.LeftLowerArm) > EnumBodyPartHit.None) { return LeftLowerArmTags; } if ((bodyparts & EnumBodyPartHit.RightUpperArm) > EnumBodyPartHit.None) { return RightUpperArmTags; } if ((bodyparts & EnumBodyPartHit.RightLowerArm) > EnumBodyPartHit.None) { return RightLowerArmTags; } if ((bodyparts & EnumBodyPartHit.LeftUpperLeg) > EnumBodyPartHit.None) { return LeftUpperLegTags; } if ((bodyparts & EnumBodyPartHit.LeftLowerLeg) > EnumBodyPartHit.None) { return LeftLowerLegTags; } if ((bodyparts & EnumBodyPartHit.RightUpperLeg) > EnumBodyPartHit.None) { return RightUpperLegTags; } if ((bodyparts & EnumBodyPartHit.RightLowerLeg) > EnumBodyPartHit.None) { return RightLowerLegTags; } if ((bodyparts & EnumBodyPartHit.Head) > EnumBodyPartHit.None) { return HeadTags; } if ((bodyparts & EnumBodyPartHit.Torso) > EnumBodyPartHit.None) { return TorsoTags; } if ((bodyparts & EnumBodyPartHit.Special) > EnumBodyPartHit.None) { return SpecialTags; } return FastTags.none; } private static FastTags TorsoTags = FastTags.Parse("torso"); private static FastTags HeadTags = FastTags.Parse("head"); private static FastTags SpecialTags = FastTags.Parse("special"); private static FastTags ArmsTags = FastTags.Parse("arms"); private static FastTags UpperArmsTags = FastTags.Parse("upperArms"); private static FastTags LowerArmsTags = FastTags.Parse("lowerArms"); private static FastTags LeftArmTags = FastTags.Parse("leftArms"); private static FastTags RightArmTags = FastTags.Parse("rightArms"); private static FastTags LeftUpperArmTags = FastTags.Parse("leftUpperArms") | LeftArmTags | UpperArmsTags | ArmsTags; private static FastTags LeftLowerArmTags = FastTags.Parse("leftLowerArms") | LeftArmTags | LowerArmsTags | ArmsTags; private static FastTags RightUpperArmTags = FastTags.Parse("rightUpperArms") | RightArmTags | UpperArmsTags | ArmsTags; private static FastTags RightLowerArmTags = FastTags.Parse("rightLowerArms") | RightArmTags | LowerArmsTags | ArmsTags; private static FastTags LegsTags = FastTags.Parse("legs"); private static FastTags UpperLegsTags = FastTags.Parse("upperLegs"); private static FastTags LowerLegsTags = FastTags.Parse("lowerLegs"); private static FastTags LeftLegTags = FastTags.Parse("leftLegs"); private static FastTags RightLegTags = FastTags.Parse("rightLegs"); private static FastTags LeftUpperLegTags = FastTags.Parse("leftUpperLegs") | LeftLegTags | UpperLegsTags | LegsTags; private static FastTags LeftLowerLegTags = FastTags.Parse("leftLowerLegs") | LeftLegTags | LowerLegsTags | LegsTags; private static FastTags RightUpperLegTags = FastTags.Parse("rightUpperLegs") | RightLegTags | UpperLegsTags | LegsTags; private static FastTags RightLowerLegTags = FastTags.Parse("rightLowerLegs") | RightLegTags | LowerLegsTags | LegsTags; }