/// <summary>
        /// Performs parry calculations. Deflects damage from defender-pawn onto parryThing, applying armor reduction in the process.
        /// On critical parry does a riposte against this verb's CasterPawn.
        /// </summary>
        /// <param name="defender">Pawn doing the parrying</param>
        /// <param name="parryThing">Thing used to parry the blow (weapon/shield)</param>
        /// <param name="isRiposte">Whether to do a riposte</param>
        private void DoParry(Pawn defender, Thing parryThing, bool isRiposte = false)
        {
            if (parryThing != null)
            {
                foreach (var dinfo in DamageInfosToApply(defender))
                {
                    LastAttackVerb = this;
                    ArmorUtilityCE.ApplyParryDamage(dinfo, parryThing);
                    LastAttackVerb = null;
                }
            }
            if (isRiposte)
            {
                SoundDef sound = null;
                if (parryThing is Apparel_Shield)
                {
                    // Shield bash
                    DamageInfo dinfo = new DamageInfo(DamageDefOf.Blunt, 6, parryThing.GetStatValue(CE_StatDefOf.MeleePenetrationFactor), -1, defender, null, parryThing.def);
                    dinfo.SetBodyRegion(BodyPartHeight.Undefined, BodyPartDepth.Outside);
                    dinfo.SetAngle((CasterPawn.Position - defender.Position).ToVector3());
                    caster.TakeDamage(dinfo);
                    if (!parryThing.Stuff.stuffProps.soundMeleeHitBlunt.NullOrUndefined())
                    {
                        sound = parryThing.Stuff.stuffProps.soundMeleeHitBlunt;
                    }
                }
                else
                {
                    Verb_MeleeAttackCE verb = defender.meleeVerbs.TryGetMeleeVerb(caster) as Verb_MeleeAttackCE;
                    if (verb == null)
                    {
                        Log.Error("CE failed to get attack verb for riposte from Pawn " + defender.ToString());
                    }
                    else
                    {
                        verb.ApplyMeleeDamageToTarget(caster);
                        sound = verb.SoundHitPawn();
                    }
                }
                // Held, because the caster may have died and despawned
                sound?.PlayOneShot(new TargetInfo(caster.PositionHeld, caster.MapHeld));
            }
            // Register with parry tracker
            ParryTracker tracker = defender.MapHeld?.GetComponent <ParryTracker>();

            if (tracker == null)
            {
                Log.Error("CE failed to find ParryTracker to register pawn " + defender.ToString());
            }
            else
            {
                tracker.RegisterParryFor(defender, verbProps.AdjustedCooldownTicks(this, defender));
            }
        }
        /// <summary>
        /// Performs parry calculations. Deflects damage from defender-pawn onto parryThing, applying armor reduction in the process.
        /// On critical parry does a riposte against this verb's CasterPawn.
        /// </summary>
        /// <param name="defender">Pawn doing the parrying</param>
        /// <param name="parryThing">Thing used to parry the blow (weapon/shield)</param>
        /// <param name="isRiposte">Whether to do a riposte</param>
        private void DoParry(Pawn defender, Thing parryThing, bool isRiposte = false)
        {
            if (parryThing != null)
            {
                foreach (var dinfo in DamageInfosToApply(defender))
                {
                    ArmorUtilityCE.ApplyParryDamage(dinfo, parryThing);
                }
            }
            if (isRiposte)
            {
                SoundDef sound = null;
                if (parryThing is Apparel_Shield)
                {
                    // Shield bash
                    DamageInfo dinfo = new DamageInfo(DamageDefOf.Blunt, 6, -1, defender, null, parryThing.def);
                    caster.TakeDamage(dinfo);
                    if (!parryThing.Stuff.stuffProps.soundMeleeHitBlunt.NullOrUndefined())
                    {
                        sound = parryThing.Stuff.stuffProps.soundMeleeHitBlunt;
                    }
                }
                else
                {
                    Verb_MeleeAttackCE verb = defender.meleeVerbs.TryGetMeleeVerb() as Verb_MeleeAttackCE;
                    if (verb == null)
                    {
                        Log.Error("CE failed to get attack verb for riposte from Pawn " + defender.ToString());
                    }
                    else
                    {
                        verb.ApplyMeleeDamageToTarget(caster);
                        sound = verb.SoundHitPawn();
                    }
                }
                sound?.PlayOneShot(new TargetInfo(caster.Position, caster.Map));
            }
            // Register with parry tracker
            ParryTracker tracker = defender.Map.GetComponent <ParryTracker>();

            if (tracker == null)
            {
                Log.Error("CE failed to find ParryTracker to register pawn " + defender.ToString());
            }
            else
            {
                tracker.RegisterParryFor(defender, verbProps.AdjustedCooldownTicks(ownerEquipment));
            }
        }
        private void ApplyDamageToPart(DamageInfo dinfo, Pawn pawn, ref DamageWorker_AddInjuryCE.LocalInjuryResult result)
        {
            BodyPartRecord exactPartFromDamageInfo = GetExactPartFromDamageInfo(dinfo, pawn);

            if (exactPartFromDamageInfo == null)
            {
                return;
            }
            bool       involveArmor   = !dinfo.InstantOldInjury;
            DamageInfo postArmorDinfo = dinfo;
            bool       shieldAbsorbed = false;

            if (involveArmor)
            {
                postArmorDinfo = ArmorUtilityCE.GetAfterArmorDamage(dinfo, pawn, exactPartFromDamageInfo, out shieldAbsorbed);
                if (dinfo.ForceHitPart == null &&
                    postArmorDinfo.ForceHitPart != null &&
                    exactPartFromDamageInfo != postArmorDinfo.ForceHitPart)
                {
                    exactPartFromDamageInfo = postArmorDinfo.ForceHitPart;   // If the shot was deflected, update our body part
                    if (pawn.Spawned)
                    {
                        LessonAutoActivator.TeachOpportunity(CE_ConceptDefOf.CE_ArmorSystem, OpportunityType.Critical);                 // Inform the player about armor deflection
                    }
                }
            }

            // Vanilla code - apply hediff
            if ((double)postArmorDinfo.Amount < 0.001)
            {
                result.deflected = true;
                return;
            }
            HediffDef     hediffDefFromDamage = HealthUtility.GetHediffDefFromDamage(postArmorDinfo.Def, pawn, exactPartFromDamageInfo);
            Hediff_Injury hediff_Injury       = (Hediff_Injury)HediffMaker.MakeHediff(hediffDefFromDamage, pawn, null);

            hediff_Injury.Part   = exactPartFromDamageInfo;
            hediff_Injury.source = postArmorDinfo.WeaponGear;
            hediff_Injury.sourceBodyPartGroup = postArmorDinfo.WeaponBodyPartGroup;
            hediff_Injury.sourceHediffDef     = postArmorDinfo.WeaponLinkedHediff;
            hediff_Injury.Severity            = (float)postArmorDinfo.Amount;
            if (postArmorDinfo.InstantOldInjury)
            {
                HediffComp_GetsOld hediffComp_GetsOld = hediff_Injury.TryGetComp <HediffComp_GetsOld>();
                if (hediffComp_GetsOld != null)
                {
                    hediffComp_GetsOld.IsOld = true;
                }
                else
                {
                    Log.Error(string.Concat(new object[]
                    {
                        "Tried to create instant old injury on Hediff without a GetsOld comp: ",
                        hediffDefFromDamage,
                        " on ",
                        pawn
                    }));
                }
            }
            result.wounded     = true;
            result.lastHitPart = hediff_Injury.Part;
            if (DamageWorker_AddInjuryCE.IsHeadshot(postArmorDinfo, hediff_Injury, pawn))
            {
                result.headshot = true;
            }
            if (postArmorDinfo.InstantOldInjury && (hediff_Injury.def.CompPropsFor(typeof(HediffComp_GetsOld)) == null || hediff_Injury.Part.def.oldInjuryBaseChance == 0f || hediff_Injury.Part.def.IsSolid(hediff_Injury.Part, pawn.health.hediffSet.hediffs) || pawn.health.hediffSet.PartOrAnyAncestorHasDirectlyAddedParts(hediff_Injury.Part)))
            {
                return;
            }
            this.FinalizeAndAddInjury(pawn, hediff_Injury, postArmorDinfo, ref result);
            this.CheckPropagateDamageToInnerSolidParts(postArmorDinfo, pawn, hediff_Injury, involveArmor, ref result);
            this.CheckDuplicateDamageToOuterParts(postArmorDinfo, pawn, hediff_Injury, involveArmor, ref result);

            // Apply secondary damage
            if (!shieldAbsorbed)
            {
                var props = dinfo.WeaponGear?.projectile as ProjectilePropertiesCE;
                if (props != null && !props.secondaryDamage.NullOrEmpty() && dinfo.Def == props.damageDef)
                {
                    foreach (SecondaryDamage sec in props.secondaryDamage)
                    {
                        if (pawn.Dead)
                        {
                            return;
                        }
                        var secDinfo = sec.GetDinfo(postArmorDinfo);
                        secDinfo.SetForcedHitPart(exactPartFromDamageInfo);
                        pawn.TakeDamage(secDinfo);
                    }
                }
            }
        }