/// <summary>
        /// Creates tool tip text for the critter resource entries and headers.
        /// </summary>
        /// <param name="heading">The heading to display on the tool tip.</param>
        /// <param name="totals">The total quantity available and reserved for errands.</param>
        /// <returns>The tool tip text formatted for those values.</returns>
        public static string FormatTooltip(string heading, CritterTotals totals)
        {
            int total = totals.Total, reserved = totals.Reserved;

            return(heading + "\n" + string.Format(STRINGS.UI.RESOURCESCREEN.AVAILABLE_TOOLTIP,
                                                  total - reserved, reserved, total));
        }
 /// <summary>
 /// Adds a critter in the current world to the inventory.
 /// </summary>
 /// <param name="creature">The creature to add.</param>
 private void AddCritter(KPrefabID id)
 {
     if (counts.TryGetValue(id.GetCritterType(), out CritterInventoryPerType byType))
     {
         var  species = id.PrefabTag;
         bool targeted = false, targetable = false;
         // Create critter totals if not present
         if (!byType.TryGetValue(species, out CritterTotals totals))
         {
             byType.Add(species, totals = new CritterTotals());
             discovered = true;
         }
         totals.Total++;
         if (id.TryGetComponent(out FactionAlignment alignment))
         {
             targeted   = FACTION_TARGETED.Get(alignment);
             targetable = FACTION_TARGETABLE.Get(alignment);
         }
         // Reserve wrangled, marked for attack, and trussed/bagged creatures
         if ((id.TryGetComponent(out Capturable capturable) && capturable.
              IsMarkedForCapture) || (targeted && targetable) || id.HasTag(
                 GameTags.Creatures.Bagged))
         {
             totals.Reserved++;
         }
     }
 }
        /// <summary>
        /// Populates a list of the creatures matching the critter type specified.
        /// </summary>
        /// <param name="totals">The location where the quantity of creatures will be stored.</param>
        /// <param name="type">The critter type to match.</param>
        public static CritterTotals FindCreatures(IDictionary <Tag, CritterTotals> totals,
                                                  CritterType type)
        {
            if (totals == null)
            {
                throw new ArgumentNullException("totals");
            }
            var all = new CritterTotals();

            IterateCreatures((creature) => {
                var species = creature.PrefabID();
                var go      = creature.gameObject;
                if (type.Matches(creature))
                {
                    var alignment = go.GetComponent <FactionAlignment>();
                    // Create critter totals if not present
                    if (!totals.TryGetValue(species, out CritterTotals total))
                    {
                        total = new CritterTotals();
                        totals.Add(species, total);
                    }
                    total.Total++;
                    all.Total++;
                    // Reserve wrangled, marked for attack, and trussed/bagged creatures
                    if ((go.GetComponent <Capturable>()?.IsMarkedForCapture ?? false) ||
                        ((alignment?.targeted ?? false) && alignment.targetable) ||
                        creature.HasTag(GameTags.Creatures.Bagged))
                    {
                        total.Reserved++;
                        all.Reserved++;
                    }
                }
            });
            return(all);
        }
        /// <summary>
        /// Updates an individual resource entry with the critters found.
        /// </summary>
        /// <param name="entry">The entry to update.</param>
        /// <param name="quantity">The quantity of this critter which is present.</param>
        private static void UpdateEntry(ResourceEntry entry, CritterTotals quantity)
        {
            var trEntry = Traverse.Create(entry);
            // Update the tool tip text
            var tooltip = trEntry.GetField <ToolTip>("tooltip");

            if (tooltip != null)
            {
                tooltip.OnToolTip = null;
                tooltip.toolTip   = CritterInventoryUtils.FormatTooltip(entry.NameLabel.text,
                                                                        quantity);
            }
            // Determine the color for the labels
            var color = trEntry.GetField <Color>("AvailableColor");

            if (quantity.Available <= 0)
            {
                color = trEntry.GetField <Color>("UnavailableColor");
            }
            LocText qLabel = entry.QuantityLabel, nLabel = entry.NameLabel;

            if (qLabel.color != color)
            {
                qLabel.color = color;
            }
            if (nLabel.color != color)
            {
                nLabel.color = color;
            }
            // Add up overall totals
            qLabel.SetText(quantity.Available.ToString());
        }
 /// <summary>
 /// Adds a critter in the current world to the inventory.
 /// </summary>
 /// <param name="creature">The creature to add.</param>
 private void AddCritter(CreatureBrain creature)
 {
     if (counts.TryGetValue(creature.GetCritterType(), out CritterInventoryPerType
                            byType))
     {
         var  species = creature.PrefabID();
         var  alignment = creature.GetComponent <FactionAlignment>();
         bool targeted = false, targetable = false;
         // Create critter totals if not present
         if (!byType.TryGetValue(species, out CritterTotals totals))
         {
             byType.Add(species, totals = new CritterTotals());
             discovered = true;
         }
         totals.Total++;
         if (alignment != null)
         {
             targeted   = FACTION_TARGETED.Get(alignment);
             targetable = FACTION_TARGETABLE.Get(alignment);
         }
         // Reserve wrangled, marked for attack, and trussed/bagged creatures
         if ((creature.GetComponent <Capturable>()?.IsMarkedForCapture ?? false) ||
             (targeted && targetable) || creature.HasTag(GameTags.Creatures.Bagged))
         {
             totals.Reserved++;
         }
     }
 }
 /// <summary>
 /// Gets the total quantity of critters of a specific type.
 /// </summary>
 /// <param name="type">The critter type, wild or tame.</param>
 /// <param name="species">The critter species to examine.</param>
 /// <returns>The total quantity of critters of that type and species.</returns>
 internal CritterTotals GetBySpecies(CritterType type, Tag species)
 {
     if (!counts.TryGetValue(type, out CritterInventoryPerType byType))
     {
         throw new ArgumentOutOfRangeException(nameof(type));
     }
     if (!byType.TryGetValue(species, out CritterTotals totals))
     {
         totals = new CritterTotals();
     }
     return(totals);
 }
        /// <summary>
        /// Gets the total quantity of each critter of a specific type.
        /// </summary>
        /// <param name="type">The critter type, wild or tame.</param>
        /// <param name="results">The location to populate the results per species.</param>
        /// <returns>The total quantity of critters of that type.</returns>
        internal CritterTotals PopulateTotals(CritterType type,
                                              IDictionary <Tag, CritterTotals> results)
        {
            if (!counts.TryGetValue(type, out CritterInventoryPerType byType))
            {
                throw new ArgumentOutOfRangeException(nameof(type));
            }
            var all = new CritterTotals();

            foreach (var pair in byType)
            {
                var totals  = pair.Value;
                var species = pair.Key;
                if (results != null && !results.ContainsKey(species))
                {
                    results.Add(species, totals);
                }
                all.Total    += totals.Total;
                all.Reserved += totals.Reserved;
            }
            return(all);
        }
        /// <summary>
        /// Creates tool tip text for the critter resource entries and headers.
        /// </summary>
        /// <param name="heading">The heading to display on the tool tip.</param>
        /// <param name="totals">The total quantity available and reserved for errands.</param>
        /// <param name="trend">The trend in the last 150 seconds.</param>
        /// <returns>The tool tip text formatted for those values.</returns>
        internal static string FormatTooltip(string heading, CritterTotals totals, float trend)
        {
            int total = totals.Total, reserved = totals.Reserved;
            var ret = new System.Text.StringBuilder(256);

            ret.Append(heading);
            ret.Append("\n");
            ret.AppendFormat(STRINGS.UI.RESOURCESCREEN.AVAILABLE_TOOLTIP,
                             GameUtil.GetFormattedSimple(total - reserved), GameUtil.GetFormattedSimple(
                                 reserved), GameUtil.GetFormattedSimple(total));
            ret.Append("\n\n");
            if (trend == 0.0f)
            {
                ret.Append(STRINGS.UI.RESOURCESCREEN.TREND_TOOLTIP_NO_CHANGE);
            }
            else
            {
                ret.AppendFormat(STRINGS.UI.RESOURCESCREEN.TREND_TOOLTIP, trend > 0.0f ?
                                 STRINGS.UI.RESOURCESCREEN.INCREASING_STR : STRINGS.UI.RESOURCESCREEN.
                                 DECREASING_STR, GameUtil.GetFormattedSimple(trend));
            }
            return(ret.ToString());
        }