public void CalculatePawnCost(ColonistCostDetails cost, CustomPawn pawn)
        {
            cost.Clear();
            cost.name = pawn.NickName;

            // Start with the market value plus a bit of a mark-up.
            cost.marketValue  = pawn.Pawn.MarketValue;
            cost.marketValue += 300;

            // Calculate passion cost.  Each passion above 8 makes all passions
            // cost more.  Minor passion counts as one passion.  Major passion
            // counts as 3.
            double skillCount           = pawn.currentPassions.Keys.Count();
            double passionLevelCount    = 0;
            double passionLevelCost     = 20;
            double passionateSkillCount = 0;

            foreach (SkillDef def in pawn.currentPassions.Keys)
            {
                Passion passion = pawn.currentPassions[def];
                int     level   = pawn.GetSkillLevel(def);

                if (passion == Passion.Major)
                {
                    passionLevelCount    += 3.0;
                    passionateSkillCount += 1.0;
                }
                else if (passion == Passion.Minor)
                {
                    passionLevelCount    += 1.0;
                    passionateSkillCount += 1.0;
                }
            }
            double levelCost = passionLevelCost;

            if (passionLevelCount > 8)
            {
                double penalty = passionLevelCount - 8;
                levelCost += penalty * 0.4;
            }
            cost.marketValue += levelCost * passionLevelCount;

            // Calculate trait cost.
            if (pawn.TraitCount > Constraints.MaxVanillaTraits)
            {
                int    extraTraitCount = pawn.TraitCount - Constraints.MaxVanillaTraits;
                double extraTraitCost  = 100;
                for (int i = 0; i < extraTraitCount; i++)
                {
                    cost.marketValue += extraTraitCost;
                    extraTraitCost    = Math.Ceiling(extraTraitCost * 2.5);
                }
            }

            // Calculate cost of worn apparel.
            for (int layer = 0; layer < PawnLayers.Count; layer++)
            {
                if (PawnLayers.IsApparelLayer(layer))
                {
                    var def = pawn.GetAcceptedApparel(layer);
                    if (def == null)
                    {
                        continue;
                    }
                    EquipmentKey key = new EquipmentKey();
                    key.ThingDef = def;
                    key.StuffDef = pawn.GetSelectedStuff(layer);
                    EquipmentRecord record = PrepareCarefully.Instance.EquipmentDatabase.Find(key);
                    if (record == null)
                    {
                        continue;
                    }
                    EquipmentSelection selection = new EquipmentSelection(record, 1);
                    double             c         = CalculateEquipmentCost(selection);
                    if (def != null)
                    {
                        // TODO: Discounted materials should be based on the faction, not hard-coded.
                        // TODO: Should we continue with the discounting?
                        if (key.StuffDef != null)
                        {
                            if (key.StuffDef.defName == "Synthread")
                            {
                                if (freeApparel.Contains(key.ThingDef.defName))
                                {
                                    c = 0;
                                }
                                else if (cheapApparel.Contains(key.ThingDef.defName))
                                {
                                    c = c * 0.15d;
                                }
                            }
                        }
                    }
                    cost.apparel += c;
                }
            }

            // Calculate cost for any materials needed for implants.
            OptionsHealth healthOptions = PrepareCarefully.Instance.Providers.Health.GetOptions(pawn);

            foreach (Implant option in pawn.Implants)
            {
                // Check if there are any ancestor parts that override the selection.
                UniqueBodyPart uniquePart = healthOptions.FindBodyPartsForRecord(option.BodyPartRecord);
                if (uniquePart == null)
                {
                    Log.Warning("Prepare Carefully could not find body part record when computing the cost of an implant: " + option.BodyPartRecord.def.defName);
                    continue;
                }
                if (pawn.AtLeastOneImplantedPart(uniquePart.Ancestors.Select((UniqueBodyPart p) => { return(p.Record); })))
                {
                    continue;
                }

                //  Figure out the cost of the part replacement based on its recipe's ingredients.
                if (option.recipe != null)
                {
                    RecipeDef def = option.recipe;
                    foreach (IngredientCount amount in def.ingredients)
                    {
                        int    count     = 0;
                        double totalCost = 0;
                        bool   skip      = false;
                        foreach (ThingDef ingredientDef in amount.filter.AllowedThingDefs)
                        {
                            if (ingredientDef == ThingDefOf.Medicine)
                            {
                                skip = true;
                                break;
                            }
                            count++;
                            EquipmentRecord entry = PrepareCarefully.Instance.EquipmentDatabase[new EquipmentKey(ingredientDef, null)];
                            if (entry != null)
                            {
                                totalCost += entry.cost * (double)amount.GetBaseCount();
                            }
                        }
                        if (skip || count == 0)
                        {
                            continue;
                        }
                        cost.bionics += (int)(totalCost / (double)count);
                    }
                }
            }

            cost.apparel = Math.Ceiling(cost.apparel);
            cost.bionics = Math.Ceiling(cost.bionics);

            // Use a multiplier to balance pawn cost vs. equipment cost.
            // Disabled for now.
            cost.Multiply(1.0);

            cost.ComputeTotal();
        }
        public void CalculatePawnCost(ColonistCostDetails cost, CustomPawn pawn)
        {
            cost.Clear();
            cost.name = pawn.NickName;

            // Start with the market value plus a bit of a mark-up.
            cost.marketValue  = pawn.Pawn.MarketValue;
            cost.marketValue += 300;

            // Reduce cost if random injuries have been chosen.
            if (pawn.RandomInjuries)
            {
                float ageMultiplier = pawn.BiologicalAge;
                if (ageMultiplier > 100)
                {
                    ageMultiplier = 100;
                }
                float injuryValue = Mathf.Pow(ageMultiplier, 1.177455f);
                injuryValue       = injuryValue / 10f;
                injuryValue       = Mathf.Floor(injuryValue) * 10f;
                cost.marketValue -= injuryValue;
            }

            // Calculate passion cost.  Each passion above 8 makes all passions
            // cost more.  Minor passion counts as one passion.  Major passion
            // counts as 3.
            double skillCount           = pawn.currentPassions.Keys.Count();
            double passionLevelCount    = 0;
            double passionLevelCost     = 20;
            double passionateSkillCount = 0;

            foreach (SkillDef def in pawn.currentPassions.Keys)
            {
                Passion passion = pawn.currentPassions[def];
                int     level   = pawn.GetSkillLevel(def);

                if (passion == Passion.Major)
                {
                    passionLevelCount    += 3.0;
                    passionateSkillCount += 1.0;
                }
                else if (passion == Passion.Minor)
                {
                    passionLevelCount    += 1.0;
                    passionateSkillCount += 1.0;
                }
            }
            double levelCost = passionLevelCost;

            if (passionLevelCount > 8)
            {
                double penalty = passionLevelCount - 8;
                levelCost += penalty * 0.4;
            }
            cost.marketValue += levelCost * passionLevelCount;

            // Calculat cost of worn apparel.
            for (int layer = 0; layer < PawnLayers.Count; layer++)
            {
                if (PawnLayers.IsApparelLayer(layer))
                {
                    var def = pawn.GetAcceptedApparel(layer);
                    SelectedEquipment customPawn = new SelectedEquipment();
                    customPawn.def   = def;
                    customPawn.count = 1;
                    if (def != null)
                    {
                        var stuff = pawn.GetSelectedStuff(layer);
                        customPawn.stuffDef = stuff;
                    }
                    double c = CalculateEquipmentCost(customPawn);
                    if (def != null)
                    {
                        if (customPawn.stuffDef != null)
                        {
                            if (customPawn.stuffDef.defName == "Synthread")
                            {
                                if (freeApparel.Contains(customPawn.def.defName))
                                {
                                    c = 0;
                                }
                                else if (cheapApparel.Contains(customPawn.def.defName))
                                {
                                    c = c * 0.15d;
                                }
                            }
                        }
                    }
                    cost.apparel += c;
                }
            }

            // Calculate cost for any materials needed for implants.
            foreach (Implant option in pawn.Implants)
            {
                // Check if there are any ancestor parts that override the selection.
                if (PrepareCarefully.Instance.HealthManager.ImplantManager.AncestorIsImplant(pawn, option.BodyPartRecord))
                {
                    continue;
                }

                //  Figure out the cost of the part replacement based on its recipe's ingredients.
                if (option.recipe != null)
                {
                    RecipeDef def = option.recipe;
                    foreach (IngredientCount amount in def.ingredients)
                    {
                        int    count     = 0;
                        double totalCost = 0;
                        bool   skip      = false;
                        foreach (ThingDef ingredientDef in amount.filter.AllowedThingDefs)
                        {
                            if (ingredientDef == ThingDefOf.Medicine)
                            {
                                skip = true;
                                break;
                            }
                            count++;
                            EquipmentDatabaseEntry entry = PrepareCarefully.Instance.EquipmentEntries[new EquipmentKey(ingredientDef, null)];
                            if (entry != null)
                            {
                                totalCost += entry.cost * (double)amount.GetBaseCount();
                            }
                        }
                        if (skip || count == 0)
                        {
                            continue;
                        }
                        cost.bionics += (int)(totalCost / (double)count);
                    }
                }
            }

            cost.apparel = Math.Ceiling(cost.apparel);
            cost.bionics = Math.Ceiling(cost.bionics);

            // Use a multiplier to balance pawn cost vs. equipment cost.
            // Disabled for now.
            cost.Multiply(1.0);

            cost.ComputeTotal();
        }