Пример #1
0
        public void RandomizeAppearance(CustomPawn customPawn)
        {
            Pawn pawn;
            int  tries = 0;

            do
            {
                pawn = GenerateSameKindOfColonist(customPawn);
                tries++;
            }while (pawn.gender != customPawn.Gender && tries < 1000);

            customPawn.HairDef = pawn.story.hairDef;
            customPawn.SetColor(PawnLayers.Hair, pawn.story.hairColor);
            customPawn.HeadGraphicPath = pawn.story.HeadGraphicPath;
            customPawn.MelaninLevel    = pawn.story.melanin;

            for (int i = 0; i < PawnLayers.Count; i++)
            {
                if (PawnLayers.IsApparelLayer(i))
                {
                    customPawn.SetSelectedStuff(i, null);
                    customPawn.SetSelectedApparel(i, null);
                }
            }
            foreach (Apparel current in pawn.apparel.WornApparel)
            {
                int layer = PawnLayers.ToPawnLayerIndex(current.def.apparel);
                if (layer != -1)
                {
                    customPawn.SetSelectedStuff(layer, current.Stuff);
                    customPawn.SetSelectedApparel(layer, current.def);
                }
            }
        }
Пример #2
0
 public void SetColor(int layer, Color color)
 {
     this.colors[layer] = color;
     if (PawnLayers.IsApparelLayer(layer))
     {
         colorCache[new EquipmentKey(selectedApparel[layer], selectedStuff[layer])] = color;
     }
     if (layer == PawnLayers.BodyType)
     {
         SkinColor = color;
     }
     else if (layer == PawnLayers.HeadType)
     {
         SkinColor = color;
     }
 }
Пример #3
0
        public CustomPawn CreatePawn()
        {
            // TODO: Evaluate
            //Pawn source = PawnGenerator.GeneratePawn(PawnKindDefOf.Colonist, Faction.OfColony);
            Pawn source = new Randomizer().GenerateColonist();

            source.health = new Pawn_HealthTracker(source);

            CustomPawn pawn = new CustomPawn(source);

            pawn.Gender = this.gender;
            if (age > 0)
            {
                pawn.ChronologicalAge = age;
                pawn.BiologicalAge    = age;
            }
            if (chronologicalAge > 0)
            {
                pawn.ChronologicalAge = chronologicalAge;
            }
            if (biologicalAge > 0)
            {
                pawn.BiologicalAge = biologicalAge;
            }
            pawn.FirstName = this.firstName;
            pawn.NickName  = this.nickName;
            pawn.LastName  = this.lastName;

            HairDef h = FindHairDef(this.hairDef);

            if (h != null)
            {
                pawn.HairDef = h;
            }

            pawn.HeadGraphicPath = this.headGraphicPath;
            pawn.SetColor(PawnLayers.Hair, hairColor);
            pawn.SetColor(PawnLayers.HeadType, skinColor);
            Backstory backstory = FindBackstory(childhood);

            if (backstory != null)
            {
                pawn.Childhood = backstory;
            }
            backstory = FindBackstory(adulthood);
            if (backstory != null)
            {
                pawn.Adulthood = backstory;
            }

            int traitCount = pawn.Traits.Count();

            for (int i = 0; i < traitCount; i++)
            {
                pawn.ClearTrait(i);
            }
            for (int i = 0; i < traitNames.Count; i++)
            {
                string traitName = traitNames[i];
                if (i >= traitCount)
                {
                    break;
                }
                Trait trait = FindTrait(traitName, traitDegrees[i]);
                if (trait != null)
                {
                    pawn.SetTrait(i, trait);
                }
            }

            for (int i = 0; i < this.skillNames.Count; i++)
            {
                string   name = this.skillNames[i];
                SkillDef def  = FindSkillDef(pawn.Pawn, name);
                if (def == null)
                {
                    continue;
                }
                pawn.currentPassions[def] = this.passions[i];
                pawn.SetUnmodifiedSkillLevel(def, this.skillValues[i]);
            }

            for (int i = 0; i < PawnLayers.Count; i++)
            {
                if (PawnLayers.IsApparelLayer(i))
                {
                    pawn.SetSelectedApparel(i, null);
                    pawn.SetSelectedStuff(i, null);
                }
            }
            for (int i = 0; i < this.apparelLayers.Count; i++)
            {
                int      layer = this.apparelLayers[i];
                ThingDef def   = DefDatabase <ThingDef> .GetNamedSilentFail(this.apparel[i]);

                if (def == null)
                {
                    continue;
                }
                ThingDef stuffDef = null;
                if (!string.IsNullOrEmpty(this.apparelStuff[i]))
                {
                    stuffDef = DefDatabase <ThingDef> .GetNamedSilentFail(this.apparelStuff[i]);

                    if (stuffDef == null)
                    {
                        continue;
                    }
                }
                pawn.SetSelectedApparel(layer, def);
                pawn.SetSelectedStuff(layer, stuffDef);
                pawn.SetColor(layer, this.apparelColors[i]);
            }

            return(pawn);
        }
Пример #4
0
        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();
        }
Пример #5
0
        public CustomPawn LoadPawn(SaveRecordPawnV3 record)
        {
            // TODO: Ahlpa 14 Evaluate
            Pawn source = new Randomizer().GenerateColonist();
            //Pawn source = PawnGenerator.GeneratePawn(PawnKindDefOf.Colonist, Faction.OfPlayer);

            CustomPawn pawn = new CustomPawn(source);

            pawn.Gender = record.gender;
            if (record.age > 0)
            {
                pawn.ChronologicalAge = record.age;
                pawn.BiologicalAge    = record.age;
            }
            if (record.chronologicalAge > 0)
            {
                pawn.ChronologicalAge = record.chronologicalAge;
            }
            if (record.biologicalAge > 0)
            {
                pawn.BiologicalAge = record.biologicalAge;
            }

            pawn.FirstName = record.firstName;
            pawn.NickName  = record.nickName;
            pawn.LastName  = record.lastName;

            HairDef h = FindHairDef(record.hairDef);

            if (h != null)
            {
                pawn.HairDef = h;
            }
            else
            {
                Log.Warning("Could not load hair definition \"" + record.hairDef + "\"");
                Failed = true;
            }

            pawn.HeadGraphicPath = record.headGraphicPath;
            pawn.SetColor(PawnLayers.Hair, record.hairColor);
            pawn.SetColor(PawnLayers.HeadType, record.skinColor);
            Backstory backstory = FindBackstory(record.childhood);

            if (backstory != null)
            {
                pawn.Childhood = backstory;
            }
            else
            {
                Log.Warning("Could not load childhood backstory definition \"" + record.childhood + "\"");
                Failed = true;
            }
            backstory = FindBackstory(record.adulthood);
            if (backstory != null)
            {
                pawn.Adulthood = backstory;
            }
            else
            {
                Log.Warning("Could not load adulthood backstory definition \"" + record.adulthood + "\"");
                Failed = true;
            }

            int traitCount = pawn.Traits.Count();

            for (int i = 0; i < traitCount; i++)
            {
                pawn.ClearTrait(i);
            }
            for (int i = 0; i < record.traitNames.Count; i++)
            {
                string traitName = record.traitNames[i];
                if (i >= traitCount)
                {
                    break;
                }
                Trait trait = FindTrait(traitName, record.traitDegrees[i]);
                if (trait != null)
                {
                    pawn.SetTrait(i, trait);
                }
                else
                {
                    Log.Warning("Could not load trait definition \"" + traitName + "\"");
                    Failed = true;
                }
            }

            for (int i = 0; i < record.skillNames.Count; i++)
            {
                string   name = record.skillNames[i];
                SkillDef def  = FindSkillDef(pawn.Pawn, name);
                if (def == null)
                {
                    Log.Warning("Could not load skill definition \"" + name + "\"");
                    Failed = true;
                    continue;
                }
                pawn.currentPassions[def]  = record.passions[i];
                pawn.originalPassions[def] = record.passions[i];
                pawn.SetOriginalSkillLevel(def, record.skillValues[i]);
                pawn.SetUnmodifiedSkillLevel(def, record.skillValues[i]);
            }
            if (record.originalPassions != null && record.originalPassions.Count == record.skillNames.Count)
            {
                for (int i = 0; i < record.skillNames.Count; i++)
                {
                    string   name = record.skillNames[i];
                    SkillDef def  = FindSkillDef(pawn.Pawn, name);
                    if (def == null)
                    {
                        Log.Warning("Could not load skill definition \"" + name + "\"");
                        Failed = true;
                        continue;
                    }
                    //pawn.originalPassions[def] = record.originalPassions[i];
                }
            }

            for (int i = 0; i < PawnLayers.Count; i++)
            {
                if (PawnLayers.IsApparelLayer(i))
                {
                    pawn.SetSelectedApparel(i, null);
                    pawn.SetSelectedStuff(i, null);
                }
            }
            for (int i = 0; i < record.apparelLayers.Count; i++)
            {
                int      layer = record.apparelLayers[i];
                ThingDef def   = DefDatabase <ThingDef> .GetNamedSilentFail(record.apparel[i]);

                if (def == null)
                {
                    Log.Warning("Could not load thing definition for apparel \"" + record.apparel[i] + "\"");
                    Failed = true;
                    continue;
                }
                ThingDef stuffDef = null;
                if (!string.IsNullOrEmpty(record.apparelStuff[i]))
                {
                    stuffDef = DefDatabase <ThingDef> .GetNamedSilentFail(record.apparelStuff[i]);

                    if (stuffDef == null)
                    {
                        Log.Warning("Could not load stuff definition \"" + record.apparelStuff[i] + "\" for apparel \"" + record.apparel[i] + "\"");
                        Failed = true;
                        continue;
                    }
                }
                pawn.SetSelectedApparel(layer, def);
                pawn.SetSelectedStuff(layer, stuffDef);
                pawn.SetColor(layer, record.apparelColors[i]);
            }

            for (int i = 0; i < record.implants.Count; i++)
            {
                SaveRecordImplantV3 implantRecord = record.implants[i];
                BodyPartRecord      bodyPart      = PrepareCarefully.Instance.HealthManager.ImplantManager.FindReplaceableBodyPartByName(implantRecord.bodyPart);
                if (bodyPart == null)
                {
                    Log.Warning("Could not find replaceable body part definition \"" + implantRecord.bodyPart + "\"");
                    Failed = true;
                    continue;
                }
                if (implantRecord.recipe != null)
                {
                    RecipeDef recipeDef = FindRecipeDef(implantRecord.recipe);
                    if (recipeDef == null)
                    {
                        Log.Warning("Could not find recipe definition \"" + implantRecord.recipe + "\"");
                        Failed = true;
                        continue;
                    }
                    bool found = false;
                    foreach (var p in recipeDef.appliedOnFixedBodyParts)
                    {
                        if (p.defName.Equals(bodyPart.def.defName))
                        {
                            found = true;
                            break;
                        }
                    }
                    if (!found)
                    {
                        Log.Warning("Body part \"" + bodyPart.def.defName + "\" does not match recipe used to replace it");
                        Failed = true;
                        continue;
                    }
                    Implant implant = new Implant();
                    implant.BodyPartRecord = bodyPart;
                    implant.recipe         = recipeDef;
                    implant.label          = implant.Label;
                    pawn.AddImplant(implant);
                }
            }

            foreach (var injuryRecord in record.injuries)
            {
                HediffDef def = DefDatabase <HediffDef> .GetNamedSilentFail(injuryRecord.hediffDef);

                if (def == null)
                {
                    Log.Warning("Could not find hediff definition \"" + injuryRecord.hediffDef + "\"");
                    Failed = true;
                    continue;
                }
                InjuryOption option = PrepareCarefully.Instance.HealthManager.InjuryManager.FindOptionByHediffDef(def);
                if (option == null)
                {
                    Log.Warning("Could not find injury option for \"" + injuryRecord.hediffDef + "\"");
                    Failed = true;
                    continue;
                }
                BodyPartRecord bodyPart = null;
                if (injuryRecord.bodyPart != null)
                {
                    bodyPart = PrepareCarefully.Instance.HealthManager.FirstBodyPartRecord(injuryRecord.bodyPart);
                    if (bodyPart == null)
                    {
                        Log.Warning("Could not find body part \"" + injuryRecord.bodyPart + "\"");
                        Failed = true;
                        continue;
                    }
                }
                Injury injury = new Injury();
                injury.Option         = option;
                injury.BodyPartRecord = bodyPart;
                if (injuryRecord.severity != null)
                {
                    injury.Severity = injuryRecord.Severity;
                }
                pawn.AddInjury(injury);
            }

            pawn.RandomInjuries  = record.randomInjuries;
            pawn.RandomRelations = record.randomRelations;
            pawn.ClearCachedAbilities();
            pawn.ClearCachedLifeStage();

            return(pawn);
        }
Пример #6
0
        protected override void DrawPanelContent(State state)
        {
            base.DrawPanelContent(state);
            CustomPawn customPawn = state.CurrentPawn;

            string label = PawnLayers.Label(this.selectedPawnLayer);

            if (WidgetDropdown.Button(RectLayerSelector, label, true, false, true))
            {
                List <FloatMenuOption> list = new List <FloatMenuOption>();
                int layerCount = this.pawnLayerActions.Count;
                for (int i = 0; i < layerCount; i++)
                {
                    int pawnLayer = pawnLayers[i];
                    label = PawnLayers.Label(pawnLayers[i]);
                    list.Add(new FloatMenuOption(label, this.pawnLayerActions[i], MenuOptionPriority.Default, null, null, 0, null, null));
                }
                Find.WindowStack.Add(new FloatMenu(list, null, false));
            }
            GUI.DrawTexture(RectPortrait, Textures.TexturePortraitBackground);

            customPawn.UpdatePortrait();
            DrawPawn(customPawn, RectPortrait);

            GUI.color = ColorPortraitBorder;
            Widgets.DrawBox(RectPortrait, 1);
            GUI.color = Color.white;

            // Conflict alert
            if (customPawn.ApparelConflict != null)
            {
                GUI.color = Color.white;
                Rect alertRect = new Rect(RectPortrait.x + 77, RectPortrait.y + 150, 36, 32);
                GUI.DrawTexture(alertRect, Textures.TextureAlert);
                TooltipHandler.TipRegion(alertRect, customPawn.ApparelConflict);
            }

            // Draw selector field.
            Rect   fieldRect = new Rect(RectPortrait.x, RectPortrait.y + RectPortrait.height + 5, RectPortrait.width, 28);
            Action previousSelectionAction = null;
            Action nextSelectionAction     = null;
            Action clickAction             = null;

            OptionsApparel  apparelOptions = null;
            List <ThingDef> apparelList    = null;
            OptionsHair     hairOptions    = null;
            List <HairDef>  hairList       = null;

            if (this.selectedPawnLayer == PawnLayers.Hair)
            {
                hairOptions = PrepareCarefully.Instance.Providers.Hair.GetHairsForRace(customPawn);
                hairList    = hairOptions.GetHairs(customPawn.Gender);
            }
            else if (PawnLayers.IsApparelLayer(this.selectedPawnLayer))
            {
                apparelOptions = PrepareCarefully.Instance.Providers.Apparel.GetApparelForRace(customPawn);
                apparelList    = apparelOptions.GetApparel(this.selectedPawnLayer);
            }

            if (this.selectedPawnLayer == PawnLayers.HeadType)
            {
                int headTypeCount = PrepareCarefully.Instance.Providers.HeadTypes.GetHeadTypes(customPawn).Count();
                if (customPawn.HeadType != null && headTypeCount > 1)
                {
                    previousSelectionAction = () => {
                        SoundDefOf.TickTiny.PlayOneShotOnCamera();
                        SelectNextHead(customPawn, -1);
                    };
                    nextSelectionAction = () => {
                        SoundDefOf.TickTiny.PlayOneShotOnCamera();
                        SelectNextHead(customPawn, 1);
                    };
                }
                if (customPawn.HeadType != null && headTypeCount > 0)
                {
                    clickAction = () => {
                        ShowHeadDialog(customPawn);
                    };
                }
            }
            else if (this.selectedPawnLayer == PawnLayers.BodyType)
            {
                if (PrepareCarefully.Instance.Providers.BodyTypes.GetBodyTypesForPawn(customPawn.Pawn).Count > 1)
                {
                    previousSelectionAction = () => {
                        SoundDefOf.TickTiny.PlayOneShotOnCamera();
                        SelectNextBodyType(customPawn, -1);
                    };
                    nextSelectionAction = () => {
                        SoundDefOf.TickTiny.PlayOneShotOnCamera();
                        SelectNextBodyType(customPawn, 1);
                    };
                }
                clickAction = () => {
                    ShowBodyTypeDialog(customPawn);
                };
            }
            else if (this.selectedPawnLayer == PawnLayers.Hair)
            {
                if (hairList.Count > 1)
                {
                    previousSelectionAction = () => {
                        SoundDefOf.TickTiny.PlayOneShotOnCamera();
                        SelectNextHair(customPawn, -1);
                    };
                    nextSelectionAction = () => {
                        SoundDefOf.TickTiny.PlayOneShotOnCamera();
                        SelectNextHair(customPawn, 1);
                    };
                }
                if (hairList.Count > 0)
                {
                    clickAction = () => {
                        ShowHairDialog(customPawn);
                    };
                }
            }
            else
            {
                if (apparelList.Count > 1)
                {
                    previousSelectionAction = () => {
                        SoundDefOf.TickTiny.PlayOneShotOnCamera();
                        SelectNextApparel(customPawn, -1);
                    };
                    nextSelectionAction = () => {
                        SelectNextApparel(customPawn, 1);
                        SoundDefOf.TickTiny.PlayOneShotOnCamera();
                    };
                }
                if (apparelList.Count > 0)
                {
                    clickAction = () => {
                        ShowApparelDialog(customPawn, this.selectedPawnLayer);
                    };
                }
            }

            string selectorLabel = PawnLayerLabel.CapitalizeFirst();

            if (hairList != null && hairList.Count == 0)
            {
                selectorLabel = "EdB.PC.Common.NoOptionAvailable".Translate();
            }
            if (apparelList != null && apparelList.Count == 0)
            {
                selectorLabel = "EdB.PC.Common.NoOptionAvailable".Translate();
            }
            DrawFieldSelector(fieldRect, selectorLabel, previousSelectionAction, nextSelectionAction, clickAction);

            float cursorY = fieldRect.y + 34;

            // Draw stuff selector for apparel
            if (PawnLayers.IsApparelLayer(this.selectedPawnLayer))
            {
                ThingDef apparelDef = customPawn.GetSelectedApparel(selectedPawnLayer);
                if (apparelDef != null && apparelDef.MadeFromStuff)
                {
                    if (customPawn.GetSelectedStuff(selectedPawnLayer) == null)
                    {
                        Log.Error("Selected stuff for " + PawnLayers.ToApparelLayer(selectedPawnLayer) + " is null");
                    }
                    Rect stuffFieldRect = new Rect(RectPortrait.x, cursorY, RectPortrait.width, 28);
                    DrawFieldSelector(stuffFieldRect, customPawn.GetSelectedStuff(selectedPawnLayer).LabelCap,
                                      () => {
                        ThingDef selected = customPawn.GetSelectedStuff(selectedPawnLayer);
                        int index         = this.apparelStuffLookup[apparelDef].FindIndex((ThingDef d) => { return(selected == d); });
                        index--;
                        if (index < 0)
                        {
                            index = this.apparelStuffLookup[apparelDef].Count - 1;
                        }
                        customPawn.SetSelectedStuff(selectedPawnLayer, apparelStuffLookup[apparelDef][index]);
                    },
                                      () => {
                        ThingDef selected = customPawn.GetSelectedStuff(selectedPawnLayer);
                        int index         = this.apparelStuffLookup[apparelDef].FindIndex((ThingDef d) => { return(selected == d); });
                        index++;
                        if (index >= this.apparelStuffLookup[apparelDef].Count)
                        {
                            index = 0;
                        }
                        customPawn.SetSelectedStuff(selectedPawnLayer, this.apparelStuffLookup[apparelDef][index]);
                    },
                                      () => {
                        ShowApparelStuffDialog(customPawn, this.selectedPawnLayer);
                    }
                                      );

                    cursorY += stuffFieldRect.height;
                }
            }
            cursorY += 8;

            // Draw Color Selector
            if (PawnLayers.IsApparelLayer(selectedPawnLayer))
            {
                if (apparelList != null && apparelList.Count > 0)
                {
                    ThingDef def = customPawn.GetSelectedApparel(selectedPawnLayer);
                    if (def != null && def.HasComp(typeof(CompColorable)))
                    {
                        if (def.MadeFromStuff)
                        {
                            DrawColorSelector(customPawn, cursorY, null);
                        }
                        else
                        {
                            DrawColorSelector(customPawn, cursorY, def.colorGenerator);
                        }
                    }
                }
            }
            else if (selectedPawnLayer == PawnLayers.BodyType || selectedPawnLayer == PawnLayers.HeadType)
            {
                AlienRace alienRace = customPawn.AlienRace;
                if (alienRace == null || alienRace.UseMelaninLevels)
                {
                    DrawHumanlikeColorSelector(customPawn, cursorY);
                }
                else
                {
                    DrawAlienPawnColorSelector(customPawn, cursorY, alienRace.PrimaryColors, true);
                }
            }
            else if (selectedPawnLayer == PawnLayers.Hair)
            {
                if (hairList != null && hairList.Count > 0)
                {
                    DrawColorSelector(customPawn, cursorY, hairOptions.Colors, true);
                }
            }

            // Random button
            if (RectButtonRandomize.Contains(Event.current.mousePosition))
            {
                GUI.color = Style.ColorButtonHighlight;
            }
            else
            {
                GUI.color = Style.ColorButton;
            }
            GUI.DrawTexture(RectButtonRandomize, Textures.TextureButtonRandom);
            if (Widgets.ButtonInvisible(RectButtonRandomize, false))
            {
                SoundDefOf.TickLow.PlayOneShotOnCamera();
                RandomizeAppearance();
            }

            // Gender buttons.
            if (state.CurrentPawn.Pawn.RaceProps != null && state.CurrentPawn.Pawn.RaceProps.hasGenders)
            {
                bool genderFemaleSelected = state.CurrentPawn.Gender == Gender.Female;
                Style.SetGUIColorForButton(RectGenderFemale, genderFemaleSelected);
                GUI.DrawTexture(RectGenderFemale, Textures.TextureButtonGenderFemale);
                if (!genderFemaleSelected && Widgets.ButtonInvisible(RectGenderFemale, false))
                {
                    SoundDefOf.TickTiny.PlayOneShotOnCamera();
                    GenderUpdated(Gender.Female);
                }
                bool genderMaleSelected = state.CurrentPawn.Gender == Gender.Male;
                Style.SetGUIColorForButton(RectGenderMale, genderMaleSelected);
                GUI.DrawTexture(RectGenderMale, Textures.TextureButtonGenderMale);
                if (!genderMaleSelected && Widgets.ButtonInvisible(RectGenderMale, false))
                {
                    SoundDefOf.TickTiny.PlayOneShotOnCamera();
                    GenderUpdated(Gender.Male);
                }
            }
            GUI.color = Color.white;
        }
        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();
        }
        public CustomPawn LoadPawn(SaveRecordPawnV3 record)
        {
            PawnKindDef pawnKindDef = null;

            if (record.pawnKindDef != null)
            {
                pawnKindDef = DefDatabase <PawnKindDef> .GetNamedSilentFail(record.pawnKindDef);

                if (pawnKindDef == null)
                {
                    Log.Warning("Prepare Carefully could not find the pawn kind definition for the saved character: \"" + record.pawnKindDef + "\"");
                    return(null);
                }
            }

            ThingDef pawnThingDef = ThingDefOf.Human;

            if (record.thingDef != null)
            {
                ThingDef thingDef = DefDatabase <ThingDef> .GetNamedSilentFail(record.thingDef);

                if (thingDef != null)
                {
                    pawnThingDef = thingDef;
                }
            }

            Pawn source;

            if (pawnKindDef != null)
            {
                source = new Randomizer().GenerateKindOfColonist(pawnKindDef);
            }
            else
            {
                source = new Randomizer().GenerateColonist();
            }
            source.health.Reset();

            CustomPawn pawn = new CustomPawn(source);

            if (pawn.Id == null)
            {
                pawn.GenerateId();
            }
            else
            {
                pawn.Id = record.id;
            }

            pawn.Gender = record.gender;
            if (record.age > 0)
            {
                pawn.ChronologicalAge = record.age;
                pawn.BiologicalAge    = record.age;
            }
            if (record.chronologicalAge > 0)
            {
                pawn.ChronologicalAge = record.chronologicalAge;
            }
            if (record.biologicalAge > 0)
            {
                pawn.BiologicalAge = record.biologicalAge;
            }

            pawn.FirstName = record.firstName;
            pawn.NickName  = record.nickName;
            pawn.LastName  = record.lastName;

            HairDef h = FindHairDef(record.hairDef);

            if (h != null)
            {
                pawn.HairDef = h;
            }
            else
            {
                Log.Warning("Could not load hair definition \"" + record.hairDef + "\"");
                Failed = true;
            }

            pawn.HeadGraphicPath = record.headGraphicPath;
            pawn.SetColor(PawnLayers.Hair, record.hairColor);

            if (record.melanin >= 0.0f)
            {
                pawn.MelaninLevel = record.melanin;
            }
            else
            {
                pawn.MelaninLevel = PawnColorUtils.FindMelaninValueFromColor(record.skinColor);
            }
            // Set the skin color (only for Alien Races).
            if (pawn.AlienRace != null)
            {
                pawn.SkinColor = record.skinColor;
            }

            Backstory backstory = FindBackstory(record.childhood);

            if (backstory != null)
            {
                pawn.Childhood = backstory;
            }
            else
            {
                Log.Warning("Could not load childhood backstory definition \"" + record.childhood + "\"");
                Failed = true;
            }
            if (record.adulthood != null)
            {
                backstory = FindBackstory(record.adulthood);
                if (backstory != null)
                {
                    pawn.Adulthood = backstory;
                }
                else
                {
                    Log.Warning("Could not load adulthood backstory definition \"" + record.adulthood + "\"");
                    Failed = true;
                }
            }

            // Get the body type from the save record.  If there's no value in the save, then assign the
            // default body type from the pawn's backstories.
            BodyType?bodyType = null;

            try {
                bodyType = (BodyType)Enum.Parse(typeof(BodyType), record.bodyType);
            }
            catch (Exception) {
            }
            if (!bodyType.HasValue)
            {
                if (pawn.Adulthood != null)
                {
                    bodyType = pawn.Adulthood.BodyTypeFor(pawn.Gender);
                }
                else
                {
                    bodyType = pawn.Childhood.BodyTypeFor(pawn.Gender);
                }
            }
            if (bodyType.HasValue)
            {
                pawn.BodyType = bodyType.Value;
            }

            pawn.ClearTraits();
            for (int i = 0; i < record.traitNames.Count; i++)
            {
                string traitName = record.traitNames[i];
                Trait  trait     = FindTrait(traitName, record.traitDegrees[i]);
                if (trait != null)
                {
                    pawn.AddTrait(trait);
                }
                else
                {
                    Log.Warning("Could not load trait definition \"" + traitName + "\"");
                    Failed = true;
                }
            }

            for (int i = 0; i < record.skillNames.Count; i++)
            {
                string name = record.skillNames[i];
                if (name == "Research")
                {
                    name = "Intellectual";
                }
                SkillDef def = FindSkillDef(pawn.Pawn, name);
                if (def == null)
                {
                    Log.Warning("Could not load skill definition \"" + name + "\"");
                    Failed = true;
                    continue;
                }
                pawn.currentPassions[def]  = record.passions[i];
                pawn.originalPassions[def] = record.passions[i];
                pawn.SetOriginalSkillLevel(def, record.skillValues[i]);
                pawn.SetUnmodifiedSkillLevel(def, record.skillValues[i]);
            }
            if (record.originalPassions != null && record.originalPassions.Count == record.skillNames.Count)
            {
                for (int i = 0; i < record.skillNames.Count; i++)
                {
                    string   name = record.skillNames[i];
                    SkillDef def  = FindSkillDef(pawn.Pawn, name);
                    if (def == null)
                    {
                        Log.Warning("Could not load skill definition \"" + name + "\"");
                        Failed = true;
                        continue;
                    }
                    //pawn.originalPassions[def] = record.originalPassions[i];
                }
            }

            for (int i = 0; i < PawnLayers.Count; i++)
            {
                if (PawnLayers.IsApparelLayer(i))
                {
                    pawn.SetSelectedApparel(i, null);
                    pawn.SetSelectedStuff(i, null);
                }
            }
            for (int i = 0; i < record.apparelLayers.Count; i++)
            {
                int      layer = record.apparelLayers[i];
                ThingDef def   = DefDatabase <ThingDef> .GetNamedSilentFail(record.apparel[i]);

                if (def == null)
                {
                    Log.Warning("Could not load thing definition for apparel \"" + record.apparel[i] + "\"");
                    Failed = true;
                    continue;
                }
                ThingDef stuffDef = null;
                if (!string.IsNullOrEmpty(record.apparelStuff[i]))
                {
                    stuffDef = DefDatabase <ThingDef> .GetNamedSilentFail(record.apparelStuff[i]);

                    if (stuffDef == null)
                    {
                        Log.Warning("Could not load stuff definition \"" + record.apparelStuff[i] + "\" for apparel \"" + record.apparel[i] + "\"");
                        Failed = true;
                        continue;
                    }
                }
                pawn.SetSelectedApparel(layer, def);
                pawn.SetSelectedStuff(layer, stuffDef);
                pawn.SetColor(layer, record.apparelColors[i]);
            }

            OptionsHealth healthOptions = PrepareCarefully.Instance.Providers.Health.GetOptions(pawn);

            for (int i = 0; i < record.implants.Count; i++)
            {
                SaveRecordImplantV3 implantRecord  = record.implants[i];
                UniqueBodyPart      uniqueBodyPart = healthOptions.FindBodyPartByName(implantRecord.bodyPart, implantRecord.bodyPartIndex != null ? implantRecord.bodyPartIndex.Value : 0);
                if (uniqueBodyPart == null)
                {
                    Log.Warning("Prepare Carefully could not add the implant because it could not find the needed body part \"" + implantRecord.bodyPart + "\""
                                + (implantRecord.bodyPartIndex != null ? " with index " + implantRecord.bodyPartIndex : ""));
                    Failed = true;
                    continue;
                }
                BodyPartRecord bodyPart = uniqueBodyPart.Record;
                if (implantRecord.recipe != null)
                {
                    RecipeDef recipeDef = FindRecipeDef(implantRecord.recipe);
                    if (recipeDef == null)
                    {
                        Log.Warning("Prepare Carefully could not add the implant because it could not find the recipe definition \"" + implantRecord.recipe + "\"");
                        Failed = true;
                        continue;
                    }
                    bool found = false;
                    foreach (var p in recipeDef.appliedOnFixedBodyParts)
                    {
                        if (p.defName.Equals(bodyPart.def.defName))
                        {
                            found = true;
                            break;
                        }
                    }
                    if (!found)
                    {
                        Log.Warning("Prepare carefully could not apply the saved implant recipe \"" + implantRecord.recipe + "\" to the body part \"" + bodyPart.def.defName + "\".  Recipe does not support that part.");
                        Failed = true;
                        continue;
                    }
                    Implant implant = new Implant();
                    implant.BodyPartRecord = bodyPart;
                    implant.recipe         = recipeDef;
                    implant.label          = implant.Label;
                    pawn.AddImplant(implant);
                }
            }

            foreach (var injuryRecord in record.injuries)
            {
                HediffDef def = DefDatabase <HediffDef> .GetNamedSilentFail(injuryRecord.hediffDef);

                if (def == null)
                {
                    Log.Warning("Prepare Carefully could not add the injury because it could not find the hediff definition \"" + injuryRecord.hediffDef + "\"");
                    Failed = true;
                    continue;
                }
                InjuryOption option = healthOptions.FindInjuryOptionByHediffDef(def);
                if (option == null)
                {
                    Log.Warning("Prepare Carefully could not add the injury because it could not find a matching injury option for the saved hediff \"" + injuryRecord.hediffDef + "\"");
                    Failed = true;
                    continue;
                }
                BodyPartRecord bodyPart = null;
                if (injuryRecord.bodyPart != null)
                {
                    UniqueBodyPart uniquePart = healthOptions.FindBodyPartByName(injuryRecord.bodyPart,
                                                                                 injuryRecord.bodyPartIndex != null ? injuryRecord.bodyPartIndex.Value : 0);
                    if (uniquePart == null)
                    {
                        Log.Warning("Prepare Carefully could not add the injury because it could not find the needed body part \"" + injuryRecord.bodyPart + "\""
                                    + (injuryRecord.bodyPartIndex != null ? " with index " + injuryRecord.bodyPartIndex : ""));
                        Failed = true;
                        continue;
                    }
                    bodyPart = uniquePart.Record;
                }
                Injury injury = new Injury();
                injury.Option         = option;
                injury.BodyPartRecord = bodyPart;
                if (injuryRecord.severity != null)
                {
                    injury.Severity = injuryRecord.Severity;
                }
                if (injuryRecord.painFactor != null)
                {
                    injury.PainFactor = injuryRecord.PainFactor;
                }
                pawn.AddInjury(injury);
            }

            pawn.CopySkillsAndPassionsToPawn();
            pawn.ClearPawnCaches();

            return(pawn);
        }