public static void Patch_Pawn_EquipmentTracker_MakeRoomFor(Pawn_EquipmentTracker __instance, ref ThingWithComps eq)
        {
            CompShield shieldComp = eq.TryGetComp <CompShield>();

            if (shieldComp != null)
            {
                //Unequip any existing shield.
                ThingWithComps shield = __instance.GetShield();
                if (shield != null)
                {
                    Pawn           pawn = EquipmentTracker_GetPawn(__instance);
                    ThingWithComps thingWithComps;

                    if (__instance.TryDropEquipment(shield, out thingWithComps, pawn.Position, true))
                    {
                        if (thingWithComps != null)
                        {
                            thingWithComps.SetForbidden(false, true);
                        }
                    }
                    else
                    {
                        Log.Error(pawn + " couldn't make room for shield " + eq);
                    }
                }
            }
        }
        public static void Patch_PawnRenderer_RenderPawnAt(PawnRenderer __instance, ref Vector3 drawLoc, ref RotDrawMode bodyDrawType, ref bool headStump)
        {
            Pawn pawn = PawnRenderer_GetPawn(__instance);

            //Render shield.
            if (pawn != null && pawn.GetShield() is ThingWithComps shield)
            {
                Vector3 bodyVector = drawLoc;

                CompShield shieldComp = shield.GetComp <CompShield>();
                bodyVector += shieldComp.ShieldProps.renderProperties.Rot4ToVector3(pawn.Rotation);

                shieldComp.RenderShield(bodyVector, pawn.Rotation, pawn, shield);
            }
        }
        public static void Patch_Pawn_Tick(Pawn __instance)
        {
            if (__instance.equipment != null && (__instance.ParentHolder != null && !ThingOwnerUtility.ContentsSuspended(__instance.ParentHolder)))
            {
                //Tick shield.
                ThingWithComps shield = __instance.GetShield();
                if (shield == null)
                {
                    return;
                }

                CompShield shieldComp = shield.GetComp <CompShield>();

                shield.Tick();
            }
        }
        public static bool Patch_Pawn_HealthTracker_PreApplyDamage(Pawn_HealthTracker __instance, ref DamageInfo dinfo, out bool absorbed)
        {
            absorbed = false;

            //Log.Message("Try getting pawn.");

            Pawn pawn = HealthTracker_GetPawn(__instance);

            if (pawn == null)
            {
                return(true);
            }

            //Notify of agressor
            DamageInfo violence = new DamageInfo(dinfo);

            violence.SetAmount(0);
            pawn?.mindState.Notify_DamageTaken(violence);

            //Log.Message("Pawn got. " + pawn.Name);

            if (pawn.equipment == null)
            {
                return(true);
            }

            //Log.Message("Equipment got.");

            //Try getting equipped shield.
            ThingWithComps shield = pawn.GetShield();

            if (shield == null)
            {
                return(true);
            }

            CompShield shieldComp = shield.GetComp <CompShield>();

            SoundDef shieldSound   = shieldComp.BlockSound ?? shieldComp.ShieldProps.defaultSound;
            bool     discardShield = false;

            //Determine if it is a melee or ranged attack.
            if (shieldComp.ShieldProps.canBlockRanged &&
                (dinfo.Instigator != null &&
                 !dinfo.Instigator.Position.AdjacentTo8WayOrInside(pawn.Position)) ||
                dinfo.Def.isExplosive)
            {
                //Ranged
                absorbed = shieldComp.AbsorbDamage(pawn, dinfo, true);
                if (absorbed && shieldSound != null)
                {
                    shieldSound.PlayOneShot(pawn);
                }
                //MoteMaker.ThrowText(dinfo.Instigator.DrawPos, dinfo.Instigator.Map, "Ranged absorbed=" + absorbed);

                if (shieldComp.IsBroken)
                {
                    discardShield = true;
                }
            }
            else if (shieldComp.ShieldProps.canBlockMelee &&
                     (dinfo.Instigator != null &&
                      dinfo.Instigator.Position.AdjacentTo8WayOrInside(pawn.Position)))
            {
                //Melee
                absorbed = shieldComp.AbsorbDamage(pawn, dinfo, false);
                if (absorbed && shieldSound != null)
                {
                    shieldSound.PlayOneShot(pawn);
                }
                //MoteMaker.ThrowText(dinfo.Instigator.DrawPos, dinfo.Instigator.Map, "Melee absorbed=" + absorbed);

                if (shieldComp.IsBroken)
                {
                    discardShield = true;
                }
            }

            if (shieldComp.ShieldProps.useFatigue && pawn.health.hediffSet.GetFirstHediffOfDef(ShieldHediffDefOf.ShieldFatigue) is Hediff hediff && hediff.Severity >= hediff.def.maxSeverity)
            {
                discardShield = true;
            }

            //Discard shield either from damage or fatigue.
            if (shieldComp.ShieldProps.canBeAutoDiscarded && discardShield)
            {
                ThingWithComps thingWithComps;
                if (pawn.equipment.TryDropEquipment(shield, out thingWithComps, pawn.Position, true))
                {
                    if (thingWithComps != null)
                    {
                        thingWithComps.SetForbidden(false, true);
                    }
                }
                else
                {
                    Log.Error(pawn + " couldn't discard shield " + shield);
                }
            }

            if (absorbed)
            {
                return(false);
            }

            return(true);
        }