/// <summary>
 ///     Gets the normalized direct influence of the given morph
 /// </summary>
 /// this does not take into account influence the children of the given class might have on the pawn
 /// <param name="class">The morph.</param>
 /// <returns></returns>
 /// <exception cref="ArgumentNullException">morph</exception>
 public float GetDirectNormalizedInfluence([NotNull] AnimalClassBase @class)
 {
     if (@class == null)
     {
         throw new ArgumentNullException(nameof(@class));
     }
     return(_influenceDict.TryGetValue(@class) / MorphUtilities.GetMaxInfluenceOfRace(parent.def));
 }
        private void DrawMorphInfluenceList(ref Vector2 curPos, float width)
        {
            // Set up the mutation tracker.
            MutationTracker mutationTracker = PawnToShowMutationsFor.GetMutationTracker();

            if (mutationTracker == null)
            {
                return;
            }

            // Create a list of the current morph influences upon the pawn.
            var influences = mutationTracker.ToList();

            // Determine the remaining human influence.
            float humInf = MorphUtilities.GetMaxInfluenceOfRace(PawnToShowMutationsFor.def);

            foreach (var influence in influences)
            {
                humInf -= influence.Value;
            }
            var maxRaceInfluence = MorphUtilities.GetMaxInfluenceOfRace(PawnToShowMutationsFor.def);

            // If the remaining human influence is greater than 0.0001, print its influence first.
            // (0.0001 is used to compensate for floating point number's occasional lack of precision.)
            if (humInf > EPSILON)
            {
                GUI.color = Color.green;
                string text       = $"Human ({(humInf/maxRaceInfluence).ToStringPercent()})";
                float  rectHeight = Text.CalcHeight(text, width);
                Widgets.Label(new Rect(curPos.x, curPos.y, width, rectHeight), text);
                curPos.y += rectHeight;
                GUI.color = Color.white;
            }

            if (influences.Count == 0)
            {
                return;
            }

            float maxInfluence = influences.MaxBy(x => x.Value).Value;

            // List the morph influences upon the pawn in descending order.
            foreach (var influence in influences.OrderByDescending(x => x.Value))
            {
                // Set the greatest influence's color to cyan
                if (Math.Abs(influence.Value - maxInfluence) < EPSILON)
                {
                    GUI.color = Color.cyan;
                }
                var    nVal       = influence.Value / maxRaceInfluence;
                string text       = $"{influence.Key.LabelCap} ({nVal.ToStringPercent()})";
                float  rectHeight = Text.CalcHeight(text, width);
                Widgets.Label(new Rect(curPos.x, curPos.y, width, rectHeight), text);
                curPos.y += rectHeight;
                GUI.color = Color.white;
            }
        }
        /// <summary>
        /// Recalculates the mutation influences if needed.
        /// </summary>
        public void RecalcIfNeeded()
        {
            int counter = 0;

            foreach (Hediff hediff in Pawn.health.hediffSet.hediffs)
            {
                if (hediff is Hediff_AddedMutation)
                {
                    counter++;
                }
            }

            if (counter != MutationsCount)
            {
                Log.Warning($"{Pawn.Name} mutation tracker has only {MutationsCount} tracked mutations but pawn actually has {counter}");
                RecalculateMutationInfluences();
                return;
            }

            bool  anyNegative    = false;
            float totalInfluence = 0;

            foreach (KeyValuePair <AnimalClassBase, float> keyValuePair in _influenceDict)
            {
                if (keyValuePair.Value < 0)
                {
                    anyNegative = true;
                }
                totalInfluence += keyValuePair.Value;
            }

            var maxInfluence = MorphUtilities.GetMaxInfluenceOfRace(parent.def);

            if (anyNegative)
            {
                Log.Warning($"{Pawn.Name} has negative mutation influence");
                RecalculateMutationInfluences();
            }
            if (Mathf.Abs(totalInfluence - TotalInfluence) > EPSILON)
            {
                Log.Warning($"{Pawn.Name} mutation tracker total is incorrect calculated:{totalInfluence} vs cached:{TotalInfluence}");
                RecalculateMutationInfluences();
            }
            else if (totalInfluence > maxInfluence)
            {
                Log.Warning($"{Pawn.Name} mutation tracker total is incorrect calculated:{totalInfluence}  greater then max:{maxInfluence}");
                RecalculateMutationInfluences();
            }
        }