Beispiel #1
0
        private void CheckTfMutationProgress()
        {
            if (AnimalMutations.Count == 0)
            {
                return;
            }

            var mx  = AnimalMutations.Count;
            var idx = Mathf.FloorToInt(Mathf.Clamp(PercentDone * mx, 0, mx));

            if (idx != _curMutationIndex)
            {
                _curMutationIndex = idx;
                var pawn = innerContainer?.FirstOrDefault() as Pawn;
                if (pawn == null)
                {
                    return;
                }
                var mut  = AnimalMutations[idx];
                var muts = MutationUtilities.AddMutation(pawn, mut, ancillaryEffects: MutationUtilities.AncillaryMutationEffects.None);
                foreach (Hediff_AddedMutation hediffAddedMutation in muts)
                {
                    var adjComp = hediffAddedMutation.SeverityAdjust;
                    if (adjComp != null)
                    {
                        hediffAddedMutation.Severity = adjComp.NaturalSeverityLimit;
                    }
                }
            }
        }
Beispiel #2
0
        private static void SwapMutations([NotNull] Pawn pawn, [NotNull] MorphDef morph)
        {
            if (pawn.health?.hediffSet?.hediffs == null)
            {
                Log.Error($"pawn {pawn.Name} has null health or hediffs?");
                return;
            }

            var partDefsToAddTo = pawn.health.hediffSet.hediffs.OfType <Hediff_AddedMutation>() //only want to count mutations
                                  .Where(m => m.Part != null && !m.def.HasComp(typeof(SpreadingMutationComp)) && !morph.IsAnAssociatedMutation(m))
                                                                                                //don't want mutations without a part or mutations that spread past the part they were added to
                                  .Select(m => m.Part)
                                  .ToList();                                                    //needs to be a list because we're about to modify hediffs

            List <BodyPartRecord> addedRecords = new List <BodyPartRecord>();

            foreach (BodyPartRecord bodyPartRecord in partDefsToAddTo)
            {
                if (addedRecords.Contains(bodyPartRecord))
                {
                    continue;                                       //if a giver already added to the record don't add it twice
                }
                // ReSharper disable once AssignNullToNotNullAttribute
                var mutation = morph.GetMutationForPart(bodyPartRecord.def).RandomElementWithFallback();
                if (mutation != null)
                {
                    var result = MutationUtilities.AddMutation(pawn, mutation, bodyPartRecord);
                    foreach (Hediff_AddedMutation addedMutation in result)
                    {
                        addedRecords.Add(addedMutation.Part);
                    }
                }
            }
        }
        private static void CheckRequiredMutations([NotNull] Pawn pawn, [NotNull] List <MutationDef> requiredMutations)
        {
            if (pawn == null)
            {
                throw new ArgumentNullException(nameof(pawn));
            }
            if (requiredMutations == null)
            {
                throw new ArgumentNullException(nameof(requiredMutations));
            }
            List <BodyPartRecord> addLst = new List <BodyPartRecord>();

            foreach (MutationDef requiredMutation in requiredMutations)
            {
                if (requiredMutation.parts == null)
                {
                    continue;
                }
                addLst.Clear();
                foreach (BodyPartRecord record in pawn.GetAllNonMissingParts(requiredMutation.parts)) //get all parts missing the required mutations
                {
                    var hediff = pawn.health.hediffSet.hediffs.FirstOrDefault(h => h.def == requiredMutation && h.Part == record);
                    if (hediff == null)
                    {
                        addLst.Add(record);
                    }
                }

                if (addLst.Count != 0)
                {
                    MutationUtilities.AddMutation(pawn, requiredMutation, addLst);
                }
            }
        }
Beispiel #4
0
        /// <summary>
        /// Tries to apply this hediff giver
        /// </summary>
        /// <param name="pawn">The pawn.</param>
        /// <param name="cause">The cause.</param>
        /// <param name="mutagen">The mutagen.</param>
        public void TryApply(Pawn pawn, Hediff cause, MutagenDef mutagen)
        {
            MutationDef mut   = GetRandomMutation(pawn); //grab a random mutation
            int         mPart = mut.parts?.Count ?? 0;

            int maxCount;

            if (mPart == 0)
            {
                maxCount = 0;
            }
            else
            {
                maxCount = GetMaxCount(pawn, mut.parts);
            }


            if (MutationUtilities.AddMutation(pawn, mut, maxCount))
            {
                IntermittentMagicSprayer.ThrowMagicPuffDown(pawn.Position.ToVector3(), pawn.MapHeld);

                var comp = cause.TryGetComp <HediffComp_Single>();
                if (comp != null)
                {
                    comp.stacks--;
                    if (comp.stacks <= 0)
                    {
                        pawn.health.RemoveHediff(cause);
                    }
                }
            }
        }
Beispiel #5
0
        private void TryAddMutationsToPawn([NotNull] Pawn original, [CanBeNull] Hediff requestCause,
                                           [NotNull] PawnKindDef requestOutputDef)
        {
            MorphDef mDef = null;

            if (requestCause != null) //first check the cause
            {
                foreach (MorphDef morphDef in MorphDef.AllDefs)
                {
                    if (morphDef.fullTransformation == requestCause.def || morphDef.partialTransformation == requestCause.def)
                    {
                        mDef = morphDef;
                        goto applyMutations; //ugly, but it's the easiest solution
                    }
                }
            }

            mDef = MorphUtilities.TryGetBestMorphOfAnimal(requestOutputDef.race);

            if (mDef == null)
            {
                DebugLogUtils.LogMsg(LogLevel.Messages, $"could not apply mutations to {original} with cause {requestCause?.def?.defName ?? "NULL"} and target {requestOutputDef.defName}");
                return;
            }


applyMutations:
            MutationUtilities.AddAllMorphMutations(original, mDef);
        }
Beispiel #6
0
        private void AddPartMutations()
        {
            var mutationsAdded = 0;

            while (_curIndex < _checkList.Count)
            {
                BodyPartRecord part = _checkList[_curIndex];

                var lst = _scratchDict.TryGetValue(part.def);

                if (lst == null) //end check early if there are no parts that can be added
                {
                    _curIndex++;
                    _curMutationIndex = 0;
                    continue;
                }
                //make sure we try each mutation per part

                while (_curMutationIndex < lst.Count)
                {
                    var mutation = lst[_curMutationIndex];
                    if (Rand.Value < mutation.addChance)
                    {
                        MutationUtilities.AddMutation(pawn, mutation.mutation, part);
                        var mutagen = def.GetMutagenDef();
                        mutagen.TryApplyAspects(pawn);
                        mutationsAdded++;
                    }
                    else if (mutation.blocks)
                    {
                        return; //wait here until the blocking mutation is added
                    }

                    _curMutationIndex++;

                    //check if we added enough mutations to break early
                    if (mutationsAdded >= MinMutationsPerCheck)
                    {
                        goto loopBreak;//break both loops
                    }
                }

                _curIndex++;           //increment after so mutations can 'block'
                _curMutationIndex = 0; //reset the mutation index every time we move up a part

                //check if we have added enough mutations to end the loop early
                if (mutationsAdded >= MinMutationsPerCheck)
                {
                    break;
                }
            }

loopBreak:  //label so we can break both loops

            if (mutationsAdded > 0)
            {
                OnMutationsAdded(mutationsAdded);
            }
        }
Beispiel #7
0
        void AddMutation([CanBeNull] BodyPartRecord record)
        {
            if (record == null)
            {
                var h = HediffMaker.MakeHediff(_mutationDef, _pawn);
                _pawn.health.AddHediff(h);
                return;
            }

            MutationUtilities.AddMutation(_pawn, _mutationDef, record, MutationUtilities.AncillaryMutationEffects.Default);
        }
Beispiel #8
0
        private void GivePawnRandomMutations([CanBeNull] MorphDef morph)
        {
            Pawn pawn = Find.CurrentMap.thingGrid
                        .ThingsAt(UI.MouseCell())
                        .OfType <Pawn>()
                        .FirstOrDefault();

            if (pawn == null)
            {
                return;
            }


            var mutations = morph?.AllAssociatedMutations;

            if (mutations == null)
            {
                mutations = DefDatabase <MutationDef> .AllDefs;
            }



            var mutList = mutations.ToList();

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

            int num = Rand.Range(1, Mathf.Min(10, mutList.Count));

            var i = 0;
            List <Hediff_AddedMutation> givenList = new List <Hediff_AddedMutation>();
            List <MutationDef>          triedGive = new List <MutationDef>();

            while (i < num && mutList.Count > 0)
            {
                var giver = mutList.RandElement();
                mutList.Remove(giver);
                triedGive.Add(giver);
                var res = MutationUtilities.AddMutation(pawn, giver);
                givenList.AddRange(res);
                i++;
            }

            if (givenList.Count > 0)
            {
                Log.Message($"gave {pawn.Name} [{givenList.Join(m => m.Label)}] from [{triedGive.Join(m => m.defName)}]");
            }
            else
            {
                Log.Message($"could not give {pawn.Name} any from [{triedGive.Join(m => m.defName)}]");
            }
        }
Beispiel #9
0
        private void AddMutations()
        {
            if (FinishedAddingMutations)
            {
                DecrementPartialComp(); //decrement only if we're finished adding mutations
                return;
            }
            if (!AnyMutationsInStage(CurStage))
            {
                return;
            }

            if (_scratchDict.Count == 0)
            {
                ResetPossibleMutations();
            }



            if (_curIndex < _checkList.Count)
            {
                AddPartMutations();
            }
            else
            {
                //add whole body mutations
                int mutationsAdded = 0;

                for (var index = 0; index < _wholeBodyParts.Count; index++)
                {
                    MutationEntry mutationEntry = _wholeBodyParts[index];
                    if (Rand.Value < mutationEntry.addChance)
                    {
                        MutationUtilities.AddMutation(pawn, mutationEntry.mutation);
                        var mutagen = def.GetMutagenDef();
                        mutagen.TryApplyAspects(pawn);
                        mutationsAdded++;
                    }

                    if (mutationsAdded >= MinMutationsPerCheck)
                    {
                        break;
                    }
                }

                if (mutationsAdded > 0)
                {
                    OnMutationsAdded(mutationsAdded);
                }
            }
        }
Beispiel #10
0
        public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
        {
            base.Apply(target, dest);
            Pawn addPawn = Properties.applyToSelf ? parent.pawn : target.Pawn;

            if (addPawn == null)
            {
                return;
            }

            List <RemoveMutationDurationComp.MutationEntry>
                removedMutations = new List <RemoveMutationDurationComp.MutationEntry>();
            var mutations        = addPawn.health.hediffSet.hediffs.OfType <Hediff_AddedMutation>().ToList();

            //store any mutations that will be removed by this action

            foreach (MutationDef mutationDef in Properties.mutations.MakeSafe())
            {
                StoreRemovedMutations(mutationDef, mutations, removedMutations);
            }
            bool addedList = false;


            foreach (MutationDef mutationDef in Properties.mutations.MakeSafe())
            {
                var res = MutationUtilities.AddMutation(target.Pawn, mutationDef);

                foreach (Hediff_AddedMutation hediff in res)
                {
                    var rmComp = hediff.TryGetComp <RemoveMutationDurationComp>();
                    if (rmComp == null)
                    {
                        continue;
                    }
                    rmComp.ticksToDisappear = GetDurationSeconds(hediff.pawn).SecondsToTicks();
                    if (!addedList) //only add the list to one mutation
                    {
                        rmComp.addMutations = removedMutations;
                        addedList           = true;
                    }
                }
            }
        }
        /// <summary>
        ///     Tries to apply this hediff giver
        /// </summary>
        /// <param name="pawn">The pawn.</param>
        /// <param name="cause">The cause.</param>
        /// <param name="mutagen">The mutagen.</param>
        public void TryApply(Pawn pawn, Hediff cause, [NotNull] MutagenDef mutagen)
        {
            if (mutagen == null)
            {
                throw new ArgumentNullException(nameof(mutagen));
            }
            var mut = Mutations[Rand.Range(0, Mutations.Count)]; //grab a random mutation

            if (MutationUtilities.AddMutation(pawn, mut))
            {
                IntermittentMagicSprayer.ThrowMagicPuffDown(pawn.Position.ToVector3(), pawn.MapHeld);
                if (cause.def.HasComp(typeof(HediffComp_Single)))
                {
                    pawn.health.RemoveHediff(cause);
                }
                mutagen.TryApplyAspects(pawn);
                if (mut.mutationTale != null)
                {
                    TaleRecorder.RecordTale(mut.mutationTale, pawn);
                }
            }
        }
        /// <summary>
        ///     Adds some extra buildup. taking into account toxic resistance and immunities
        /// </summary>
        /// <param name="pawn">The pawn.</param>
        /// <param name="dInfo">The d information.</param>
        protected void AddExtraBuildup(Pawn pawn, DamageInfo dInfo)
        {
            if (!MutagenDefOf.defaultMutagen.CanInfect(pawn))
            {
                return;
            }
            float extraSeverity = dInfo.Amount * 0.02f * dInfo.GetSeverityPerDamage();

            extraSeverity *= pawn.GetStatValue(StatDefOf.ToxicSensitivity);

            if (Mathf.Abs(extraSeverity) < EPSILON)
            {
                return;
            }

            HediffDef hDef = dInfo.Def.GetModExtension <MutagenicDamageExtension>()?.mutagenicBuildup
                             ?? MorphTransformationDefOf.MutagenicBuildup_Weapon;

            if (pawn != null)
            {
                MutationUtilities.AdjustMutagenicBuildup(pawn, extraSeverity, hDef);
            }
        }
        /// <summary>
        ///     Adds the mutation on.
        /// </summary>
        /// <param name="forceHitPart">The force hit part.</param>
        /// <param name="pawn">The pawn.</param>
        protected void AddMutationOn([NotNull] BodyPartRecord forceHitPart, [NotNull] Pawn pawn)
        {
            if (!MutagenDefOf.defaultMutagen.CanInfect(pawn))
            {
                return;
            }
            while (forceHitPart != null)
            {
                var mutation = MutationUtilities.GetMutationsByPart(forceHitPart.def).RandomElementWithFallback();
                if (mutation == null)
                {
                    forceHitPart = forceHitPart.parent; //go upward until we hit a mutable part
                    continue;
                }

                if (!MutationUtilities.AddMutation(pawn, mutation, forceHitPart))
                {
                    forceHitPart = forceHitPart.parent; //go upward until we hit a mutable part
                    continue;
                }

                break; //if we apply a mutation break the loop
            }
        }
        public override void CompPostPostRemoved()
        {
            base.CompPostPostRemoved();

            foreach (MutationEntry mutationEntry in addMutations.MakeSafe())
            {
                if (mutationEntry.mDef == null)
                {
                    continue;
                }

                var res = MutationUtilities.AddMutation(Pawn, mutationEntry.mDef, mutationEntry.record);
                if (!res)
                {
                    continue;
                }
                foreach (Hediff_AddedMutation mutation in res)
                {
                    mutation.Severity = mutationEntry.severity;
                }
            }

            addMutations?.Clear();
        }
        static void HandleAlienRaceExtensions([NotNull] Pawn pawn, [NotNull] RaceMutationSettingsExtension ext)
        {
            var retrievers = ext.mutationRetrievers;

            if (retrievers == null || retrievers.Count == 0 || pawn.def == null)
            {
                return;
            }

            foreach (MutationDef mutationDef in retrievers.GetMutationsFor(pawn.def, pawn))
            {
                var mutations = MutationUtilities.AddMutation(pawn, mutationDef, ancillaryEffects: MutationUtilities.AncillaryMutationEffects.None);


                foreach (Hediff_AddedMutation mutationAdded in mutations)
                {
                    var adjComp = mutationAdded.SeverityAdjust;
                    if (adjComp != null)
                    {
                        mutationAdded.Severity = adjComp.NaturalSeverityLimit;
                    }
                }
            }
        }
        private void DrawPartEntrySkinSyncMode(string label, List <BodyPartRecord> parts, ref float curPos, Rect rect, MutationLayer layer)
        {
            Rect labelRect = new Rect(rect.x, curPos, rect.width, Text.CalcHeight(label, rect.width));

            Widgets.Label(labelRect, label);
            curPos += labelRect.height;

            List <Hediff_AddedMutation> mutations = pawn.health.hediffSet.hediffs
                                                    .Where(m => m.def.GetType() == typeof(MutationDef))
                                                    .Cast <Hediff_AddedMutation>()
                                                    .Where(m => parts.Contains(m.Part) && m.TryGetComp <RemoveFromPartComp>().Layer == layer)
                                                    .ToList();

            string partButtonText = $"{(mutations.NullOrEmpty() ? NO_MUTATIONS_LOC_STRING.Translate().ToString() : string.Join(", ", mutations.Select(m => m.LabelCap).Distinct()))}";
            string editButtonText = EDIT_PARAMS_LOC_STRING.Translate();

            float editButtonWidth  = Text.CalcSize(editButtonText).x + BUTTON_HORIZONTAL_PADDING;
            float partButtonWidth  = rect.width - editButtonWidth;
            float partButtonHeight = Text.CalcHeight(partButtonText, partButtonWidth - BUTTON_HORIZONTAL_PADDING);

            Rect partButtonRect = new Rect(rect.x, curPos, partButtonWidth, partButtonHeight);
            Rect editButtonRect = new Rect(partButtonWidth, curPos, editButtonWidth, partButtonHeight);
            Rect descUpdateRect = new Rect(rect.x, curPos, rect.width, partButtonHeight);

            if (Widgets.ButtonText(partButtonRect, partButtonText))
            {
                List <FloatMenuOption> options = new List <FloatMenuOption>();
                void removeMutations()
                {
                    foreach (Hediff_AddedMutation mutation in mutations)
                    {
                        pawn.health.RemoveHediff(mutation);
                    }
                    recachePreview = true;
                }

                options.Add(new FloatMenuOption(NO_MUTATIONS_LOC_STRING.Translate(), removeMutations));
                foreach (MutationDef mutationDef in cachedMutationDefsByPart[parts.First().def].Where(m => m.CompProps <RemoveFromPartCompProperties>().layer == layer))
                {
                    void addMutation()
                    {
                        removeMutations();
                        foreach (BodyPartRecord part in parts)
                        {
                            MutationUtilities.AddMutation(pawn, mutationDef, part);
                        }
                    }

                    options.Add(new FloatMenuOption(mutationDef.LabelCap, addMutation));
                }
                Find.WindowStack.Add(new FloatMenu(options));
            }

            if (Widgets.ButtonText(editButtonRect, editButtonText))
            {
                // Pop open window to modify current stage, severity, halted status, etc.
            }

            if (Mouse.IsOver(descUpdateRect))
            {
                foreach (MutationDef mutation in mutations.Select(m => m.Def).Distinct().ToList())
                {
                    partDescBuilder.AppendLine($"{mutation.LabelCap}");
                    partDescBuilder.AppendLine($"{mutation.description}");
                    partDescBuilder.AppendLine();
                }
            }

            curPos += partButtonHeight;
        }
Beispiel #17
0
        public override void DoWindowContents(Rect inRect)
        {
            // Step 1 - Gather and set relevent information.
            float col1, col2, col3;
            List <MutationDef> allMutations = DefDatabase <MutationDef> .AllDefs.ToList();

            List <BodyPartRecord>       mutableParts  = pawn.RaceProps.body.AllParts.Where(m => DefDatabase <MutationDef> .AllDefs.SelectMany(n => n.parts).Distinct().Contains(m.def)).ToList();
            List <Hediff_AddedMutation> pawnMutations = pawn.health.hediffSet.hediffs.Where(m => m.def.GetType() == typeof(MutationDef)).Cast <Hediff_AddedMutation>().ToList();

            // Step 2 - Draw the title of the window.
            Text.Font = GameFont.Medium;
            string title       = $"{WINDOW_TITLE_LOC_STRING.Translate()} - {pawn.Name.ToStringShort} ({pawn.def.LabelCap})";
            float  titleHeight = Text.CalcHeight(title, inRect.width);

            Widgets.Label(new Rect(inRect.x, inRect.y, inRect.width, Text.CalcHeight(title, inRect.width)), title);
            Text.Font = GameFont.Small;
            col1      = col2 = col3 = titleHeight;

            // Step 3 - Determine vewing areas for body part list and description.
            float drawableWidth        = (inRect.width - PREVIEW_SIZE.x - 2 * SPACER_SIZE) / 2;
            float drawableHeight       = inRect.height - titleHeight - Math.Max(APPLY_BUTTON_SIZE.y, Math.Max(RESET_BUTTON_SIZE.y, CANCEL_BUTTON_SIZE.y)) - 2 * SPACER_SIZE;
            Rect  partListOutRect      = new Rect(inRect.x, titleHeight, drawableWidth, drawableHeight);
            Rect  partListViewRect     = new Rect(partListOutRect.x, partListOutRect.y, partListScrollSize.x, partListScrollSize.y - titleHeight);
            Rect  previewRect          = new Rect(inRect.x + SPACER_SIZE + drawableWidth, titleHeight, PREVIEW_SIZE.x, PREVIEW_SIZE.y);
            Rect  descriptionOutRect   = new Rect(inRect.x + 2 * SPACER_SIZE + PREVIEW_SIZE.x, titleHeight, drawableWidth, drawableHeight);
            Rect  descriptiontViewRect = new Rect(descriptionOutRect.x, descriptionOutRect.y, descriptionOutRect.width - 16f, descriptionOutRect.height);

            // Step 4 - Draw the body part list, selection buttons and edit buttons.
            string editButtonText  = EDIT_PARAMS_LOC_STRING.Translate();
            float  editButtonWidth = Text.CalcSize(editButtonText).x + BUTTON_HORIZONTAL_PADDING;

            Widgets.BeginScrollView(partListOutRect, ref partListScrollPos, partListViewRect);
            if (doSymmetry)
            {
                List <BodyPartDef> uniqueMutablePartDefs = mutableParts.Select(m => m.def).Distinct().ToList();
                foreach (BodyPartDef part in uniqueMutablePartDefs)
                {
                    List <Hediff_AddedMutation> mutationsOnPart = pawnMutations.Where(m => m.Part.def == part).ToList();
                    string text       = part.LabelCap;
                    float  textHeight = Text.CalcHeight(text, partListViewRect.width);
                    Widgets.Label(new Rect(0f, col1, partListViewRect.width, textHeight), text);
                    col1 += textHeight;
                    foreach (MutationLayer layer in Enum.GetValues(typeof(MutationLayer)))
                    {
                        List <MutationDef> applicableMutations = allMutations.Where(m => m.parts.Contains(part) && m.comps.Find(n => n.GetType() == typeof(RemoveFromPartCompProperties)).ChangeType <RemoveFromPartCompProperties>().layer == layer).ToList();
                        if (!applicableMutations.NullOrEmpty())
                        {
                            List <Hediff_AddedMutation> mutationsOnLayer = mutationsOnPart.Where(m => m.TryGetComp <RemoveFromPartComp>().Layer == layer).ToList();
                            string buttonText   = $"{layer}: {(mutationsOnLayer.NullOrEmpty() ? NO_MUTATIONS_LOC_STRING.Translate().ToString() : string.Join(", ", mutationsOnLayer.Select(m => m.LabelCap).Distinct()))}";
                            float  buttonHeight = Text.CalcHeight(buttonText, partListViewRect.width);
                            if (Widgets.ButtonText(new Rect(0f, col1, partListViewRect.width - editButtonWidth, buttonHeight), buttonText))
                            {
                                List <FloatMenuOption> options = new List <FloatMenuOption>();
                                Action removeAction            = delegate()
                                {
                                    if (!mutationsOnLayer.NullOrEmpty())
                                    {
                                        foreach (Hediff_AddedMutation hediff in mutationsOnLayer)
                                        {
                                            pawn.health.RemoveHediff(hediff);
                                        }
                                    }
                                    forceRecachePreview = true;
                                };
                                options.Add(new FloatMenuOption(NO_MUTATIONS_LOC_STRING.Translate(), removeAction));
                                foreach (MutationDef mutationDef in applicableMutations)
                                {
                                    Action action = delegate()
                                    {
                                        if (!mutationsOnLayer.NullOrEmpty())
                                        {
                                            foreach (Hediff_AddedMutation hediff in mutationsOnLayer)
                                            {
                                                pawn.health.RemoveHediff(hediff);
                                            }
                                        }
                                        foreach (BodyPartRecord bpr in pawn.RaceProps.body.AllParts.Where(m => m.def == part))
                                        {
                                            MutationUtilities.AddMutation(pawn, mutationDef, bpr);
                                        }
                                        forceRecachePreview = true;
                                    };
                                    options.Add(new FloatMenuOption(mutationDef.LabelCap, action));
                                }
                                Find.WindowStack.Add(new FloatMenu(options));
                            }
                            if (Widgets.ButtonText(new Rect(partListViewRect.width - editButtonWidth, col1, editButtonWidth, buttonHeight), editButtonText))
                            {
                                // Edit the paramaters of the relevant mutations, such as current stage, if it's halted, etc. (Check for full list of what can be modified later)
                            }
                            col1 += buttonHeight;
                        }
                    }
                }
            }
            else
            {
                foreach (BodyPartRecord part in mutableParts)
                {
                    string text       = part.LabelCap;
                    float  textHeight = Text.CalcHeight(text, partListViewRect.width);
                    Widgets.Label(new Rect(0f, col1, partListViewRect.width, textHeight), text);
                    col1 += textHeight;
                    foreach (MutationLayer layer in Enum.GetValues(typeof(MutationLayer)))
                    {
                        List <MutationDef> applicableMutations = allMutations.Where(m => m.parts.Contains(part.def) && m.comps.Find(n => n.GetType() == typeof(RemoveFromPartCompProperties)).ChangeType <RemoveFromPartCompProperties>().layer == layer).ToList();
                        if (!applicableMutations.NullOrEmpty())
                        {
                            Hediff_AddedMutation mutationOnPartAndLayer = pawnMutations.Find(m => m.TryGetComp <Hediffs.RemoveFromPartComp>().Layer == layer && m.Part == part);
                            string buttonText   = $"{layer}: {(mutationOnPartAndLayer == null ? NO_MUTATIONS_LOC_STRING.Translate().ToString() : mutationOnPartAndLayer.LabelCap)}";
                            float  buttonHeight = Text.CalcHeight(buttonText, partListViewRect.width);
                            if (Widgets.ButtonText(new Rect(0f, col1, partListViewRect.width - editButtonWidth, buttonHeight), buttonText))
                            {
                                List <FloatMenuOption> options = new List <FloatMenuOption>();
                                Action removeAction            = delegate()
                                {
                                    if (mutationOnPartAndLayer != null)
                                    {
                                        pawn.health.RemoveHediff(mutationOnPartAndLayer);
                                    }
                                    forceRecachePreview = true;
                                };
                                options.Add(new FloatMenuOption(NO_MUTATIONS_LOC_STRING.Translate(), removeAction));
                                foreach (MutationDef mutationDef in applicableMutations)
                                {
                                    Action action = delegate()
                                    {
                                        if (mutationOnPartAndLayer != null)
                                        {
                                            pawn.health.RemoveHediff(mutationOnPartAndLayer);
                                        }
                                        MutationUtilities.AddMutation(pawn, mutationDef, part);
                                        forceRecachePreview = true;
                                    };
                                    options.Add(new FloatMenuOption(mutationDef.LabelCap, action));
                                }
                                Find.WindowStack.Add(new FloatMenu(options));
                            }
                            if (Widgets.ButtonText(new Rect(partListViewRect.width - editButtonWidth, col1, editButtonWidth, buttonHeight), editButtonText))
                            {
                                // Edit the paramaters of the mutation on the current part and layer, such as its current stage, if it's halted, etc. (Check for full list of what can be modified later)
                            }
                            col1 += buttonHeight;
                        }
                    }
                }
            }
            if (Event.current.type == EventType.Layout)
            {
                partListScrollSize.x = partListOutRect.width - 16f;
                partListScrollSize.y = col1;
            }
            Widgets.EndScrollView();

            // Step 5 - Draw the preview area then rotation and clothes buttons then symmetry toggle.
            if (forceRecachePreview || previewImage == null)
            {
                setPawnPreview();
            }
            GUI.DrawTexture(previewRect, previewImage);
            col2 += previewRect.height;
            float rotCWHorPos          = previewRect.x + previewRect.width / 2 - TOGGLE_CLOTHES_BUTTON_SIZE.x / 2 - ROTATE_CW_BUTTON_SIZE.x - SPACER_SIZE;
            float toggleClothingHorPos = previewRect.x + previewRect.width / 2 - TOGGLE_CLOTHES_BUTTON_SIZE.x / 2;
            float rotCCWHorPos         = previewRect.x + previewRect.width / 2 + TOGGLE_CLOTHES_BUTTON_SIZE.x / 2 + SPACER_SIZE;

            col2 += SPACER_SIZE;
            if (Widgets.ButtonImageFitted(new Rect(rotCWHorPos, col2, ROTATE_CW_BUTTON_SIZE.x, ROTATE_CW_BUTTON_SIZE.y), ButtonTexturesPM.rotCW, Color.white, Color.blue))
            {
                previewRot.Rotate(RotationDirection.Clockwise);
                SoundDefOf.Tick_Tiny.PlayOneShotOnCamera();
                forceRecachePreview = true;
            }
            if (Widgets.ButtonImageFitted(new Rect(toggleClothingHorPos, col2, TOGGLE_CLOTHES_BUTTON_SIZE.x, TOGGLE_CLOTHES_BUTTON_SIZE.y), ButtonTexturesPM.toggleClothes, Color.white, Color.blue))
            {
                toggleClothesEnabled = !toggleClothesEnabled;
                (toggleClothesEnabled ? SoundDefOf.Checkbox_TurnedOn : SoundDefOf.Checkbox_TurnedOff).PlayOneShotOnCamera();
                forceRecachePreview = true;
            }
            if (Widgets.ButtonImageFitted(new Rect(rotCCWHorPos, col2, ROTATE_CCW_BUTTON_SIZE.x, ROTATE_CCW_BUTTON_SIZE.y), ButtonTexturesPM.rotCCW, Color.white, Color.blue))
            {
                previewRot.Rotate(RotationDirection.Counterclockwise);
                SoundDefOf.Tick_Tiny.PlayOneShotOnCamera();
                forceRecachePreview = true;
            }
            col2 += Math.Max(TOGGLE_CLOTHES_BUTTON_SIZE.y, Math.Max(ROTATE_CW_BUTTON_SIZE.y, ROTATE_CCW_BUTTON_SIZE.y));
            string toggleText       = DO_SYMMETRY_LOC_STRING.Translate();
            float  toggleTextHeight = Text.CalcHeight(toggleText, PREVIEW_SIZE.x);

            Widgets.CheckboxLabeled(new Rect(inRect.x + SPACER_SIZE + drawableWidth, col2, PREVIEW_SIZE.x, toggleTextHeight), DO_SYMMETRY_LOC_STRING.Translate(), ref doSymmetry);
            col2 += toggleTextHeight;

            // Step 6 - Draw description box.

            // Step 7 - Draw the apply, reset and cancel buttons.
            float buttonVertPos = titleHeight + drawableHeight + SPACER_SIZE;
            float applyHorPos   = inRect.width / 2 - APPLY_BUTTON_SIZE.x - RESET_BUTTON_SIZE.x / 2 - SPACER_SIZE;
            float resetHorPos   = inRect.width / 2 - RESET_BUTTON_SIZE.x / 2;
            float cancelHorPos  = inRect.width / 2 + RESET_BUTTON_SIZE.x / 2 + SPACER_SIZE;

            if (Widgets.ButtonText(new Rect(applyHorPos, buttonVertPos, APPLY_BUTTON_SIZE.x, APPLY_BUTTON_SIZE.y), APPLY_BUTTON_LOC_STRING.Translate()))
            {
                OnAcceptKeyPressed();
            }
            if (Widgets.ButtonText(new Rect(resetHorPos, buttonVertPos, RESET_BUTTON_SIZE.x, RESET_BUTTON_SIZE.y), RESET_BUTTON_LOC_STRING.Translate()))
            {
                SoundDefOf.Checkbox_TurnedOff.PlayOneShotOnCamera(null);
                ResetPawnHealth();
                forceRecachePreview = true;
            }
            if (Widgets.ButtonText(new Rect(cancelHorPos, buttonVertPos, CANCEL_BUTTON_SIZE.x, CANCEL_BUTTON_SIZE.y), CANCEL_BUTTON_LOC_STRING.Translate()))
            {
                OnCancelKeyPressed();
            }
        }
Beispiel #18
0
        private void DrawPartButtons(ref float curY, Rect partListViewRect, List <Hediff_AddedMutation> mutations, List <BodyPartRecord> parts, MutationLayer layer, string label)
        {
            // Draw the main mutation selection button. It should take up the whole width if there are no mutations, otherwise it will leave a space for the edit button.
            float partButtonWidth = partListViewRect.width - (mutations.NullOrEmpty() ? 0 : editButtonWidth);
            Rect  partButtonRect  = new Rect(partListViewRect.x, curY, partButtonWidth, Text.CalcHeight(label, partButtonWidth - BUTTON_HORIZONTAL_PADDING));

            if (Widgets.ButtonText(partButtonRect, label))
            {
                List <FloatMenuOption> options = new List <FloatMenuOption>();
                void removeMutations()
                {
                    foreach (Hediff_AddedMutation mutation in mutations)
                    {
                        addedMutations.RemoveByPartAndLayer(mutation.Part, layer);
                        if (cachedInitialHediffs.Select(m => m.hediff).Contains(mutation))
                        {
                            addedMutations.AddData(mutation.Def, mutation.Part, mutation.Severity, mutation.ProgressionHalted, true);
                        }
                        pawn.health.RemoveHediff(mutation);
                    }
                    recachePreview = true;
                    RecachePawnMutations();
                }

                options.Add(new FloatMenuOption(NO_MUTATIONS_LOC_STRING.Translate(), removeMutations));


                List <MutationDef> mutationDefs = cachedMutationDefsByPartDef[parts.FirstOrDefault().def];
                foreach (MutationDef mutationDef in mutationDefs.Where(m => m.RemoveComp.layer == layer && (DebugSettings.godMode || m.IsTagged())))
                {
                    void addMutation()
                    {
                        foreach (Hediff_AddedMutation mutation in mutations)
                        {
                            pawn.health.RemoveHediff(mutation);
                        }
                        foreach (BodyPartRecord part in parts)
                        {
                            addedMutations.RemoveByPartAndLayer(part, layer);
                            addedMutations.AddData(mutationDef, part, mutationDef.initialSeverity, false, false);
                            MutationUtilities.AddMutation(pawn, mutationDef, part, ancillaryEffects: MutationUtilities.AncillaryMutationEffects.None); //don't give the green puffs
                        }
                        recachePreview = true;
                        RecachePawnMutations();
                    }

                    options.Add(new FloatMenuOption(mutationDef.LabelCap, addMutation));
                }
                Find.WindowStack.Add(new FloatMenu(options));
            }
            curY += partButtonRect.height;

            // If there are actually mutations, draw the edit button.
            if (!mutations.NullOrEmpty())
            {
                Rect editButtonRect = new Rect(partButtonWidth, partButtonRect.y, editButtonWidth, partButtonRect.height);
                if (Widgets.ButtonText(editButtonRect, editButtonText))
                {
                    detailPart = (detailPart.Item1 == parts.FirstOrDefault() && detailPart.Item2 == layer) ? new Tuple <BodyPartRecord, MutationLayer>(new BodyPartRecord(), 0) : new Tuple <BodyPartRecord, MutationLayer>(parts.FirstOrDefault(), layer);
                }
            }

            // If the currently selected part and layer match up with the part to give details for, draw the edit area below the buttons.
            if (detailPart.Item1 == parts.FirstOrDefault() && detailPart.Item2 == layer)
            {
                foreach (MutationDef mutationDef in mutations.Select(m => m.Def).Distinct())
                {
                    List <Hediff_AddedMutation> mutationsOfDef = mutations.Where(m => m.Def == mutationDef).ToList();

                    // Draw the LabelCap of the current Def if there is more than one type of mutation in the current list.
                    if (mutations.Select(m => m.Def).Distinct().Count() > 1)
                    {
                        Widgets.ListSeparator(ref curY, partListViewRect.width, mutationDef.LabelCap);
                    }

                    // Draw the various labels for the severity bar (need to refine this later).
                    string stageLabelText     = $"Stage {mutationsOfDef.FirstOrDefault().CurStageIndex}: {mutationsOfDef.FirstOrDefault().LabelCap}";
                    Rect   severityLabelsRect = new Rect(partListViewRect.x, curY, partListViewRect.width, Text.CalcHeight(stageLabelText, partListViewRect.width));
                    Text.Anchor = TextAnchor.MiddleLeft;
                    Widgets.Label(severityLabelsRect, stageLabelText);
                    Text.Anchor = TextAnchor.MiddleRight;
                    Widgets.Label(severityLabelsRect, mutationsOfDef.FirstOrDefault().Severity.ToString("n2"));
                    Text.Anchor = TextAnchor.UpperLeft;
                    curY       += severityLabelsRect.height;

                    // Draw the severity slider
                    float curSeverity = mutationsOfDef.Select(n => n.Severity).Average();
                    float newSeverity = Widgets.HorizontalSlider(new Rect(partListViewRect.x, curY, partListViewRect.width, SLIDER_HEIGHT), curSeverity, mutationDef.minSeverity, mutationDef.maxSeverity);
                    if (curSeverity != newSeverity)
                    {
                        curSeverity = newSeverity;
                        foreach (Hediff_AddedMutation mutationOfDef in mutationsOfDef)
                        {
                            MutationData relevantEntry = addedMutations.MutationsByPartAndLayer(mutationOfDef.Part, layer);
                            if (relevantEntry != null)
                            {
                                relevantEntry.severity = newSeverity;
                            }
                            else
                            {
                                addedMutations.AddData(mutationOfDef.Def, mutationOfDef.Part, newSeverity, mutationOfDef.ProgressionHalted, false);
                            }
                            mutationOfDef.Severity = newSeverity;
                        }
                        recachePreview = true;
                    }
                    curY += SLIDER_HEIGHT;

                    // If the mutation has the ability to be paused, show the toggle for it.
                    // This is a CheckboxMulti to handle edge cases, but likely could be replaced with a simple Checkbox.
                    if (mutationDef.CompProps <CompProperties_MutationSeverityAdjust>() != null)
                    {
                        float pauseLabelWidth           = partListViewRect.width - IS_PAUSED_CHECKBOX_SIZE.x;
                        Rect  pauseLabelRect            = new Rect(partListViewRect.x, curY, pauseLabelWidth, Text.CalcHeight(IS_PAUSED_LOC_STRING.Translate(), partListViewRect.width));
                        Rect  checkBoxRect              = new Rect(partListViewRect.x + pauseLabelWidth, curY, IS_PAUSED_CHECKBOX_SIZE.x, IS_PAUSED_CHECKBOX_SIZE.y);
                        MultiCheckboxState initialState = !mutationsOfDef.Select(n => n.ProgressionHalted).Contains(true) ? MultiCheckboxState.Off : !mutationsOfDef.Select(n => n.ProgressionHalted).Contains(false) ? MultiCheckboxState.On : MultiCheckboxState.Partial;
                        Widgets.Label(pauseLabelRect, IS_PAUSED_LOC_STRING.Translate());
                        MultiCheckboxState newState = Widgets.CheckboxMulti(checkBoxRect, initialState);
                        if (initialState != newState)
                        {
                            initialState = newState;
                            mutationsOfDef.FirstOrDefault().SeverityAdjust.Halted = !mutationsOfDef.FirstOrDefault().SeverityAdjust.Halted;
                            foreach (Hediff_AddedMutation mutationOfDef in mutationsOfDef)
                            {
                                MutationData relevantEntry = addedMutations.MutationsByPartAndLayer(mutationOfDef.Part, layer);
                                if (cachedInitialHediffs.Select(m => m.hediff).Contains(mutationOfDef))
                                {
                                    bool initialHediffIsHalted = cachedInitialHediffs.Where(m => m.hediff == mutationOfDef).FirstOrDefault().isHalted;
                                    if (newState == MultiCheckboxState.On == initialHediffIsHalted)
                                    {
                                        addedMutations.RemoveByPartAndLayer(mutationOfDef.Part, layer);
                                    }
                                }
                                if (relevantEntry != null)
                                {
                                    relevantEntry.isHalted = newState == MultiCheckboxState.On;
                                }
                                else
                                {
                                    addedMutations.AddData(mutationOfDef.Def, mutationOfDef.Part, mutationOfDef.Severity, newState == MultiCheckboxState.On, false);
                                }
                            }
                        }
                        curY += Math.Max(pauseLabelRect.height, checkBoxRect.height);
                    }
                }
            }

            // Create a zone for updating the lower description box (The one that shows details based on the currently hovered over mutation).
            Rect descriptionUpdateRect = new Rect(partListViewRect.x, partButtonRect.y, partListViewRect.width, curY - partButtonRect.y);

            if (Mouse.IsOver(descriptionUpdateRect))
            {
                foreach (MutationDef mutation in mutations.Select(m => m.def).Distinct())
                {
                    Hediff_AddedMutation firstMutationOfDef = mutations.Where(m => m.def == mutation).FirstOrDefault();
                    partDescBuilder.AppendLine(firstMutationOfDef.LabelCap);
                    partDescBuilder.AppendLine(firstMutationOfDef.Description);
                    partDescBuilder.AppendLine(firstMutationOfDef.TipStringExtra);
                    partDescBuilder.AppendLine();
                }
            }
        }
Beispiel #19
0
        private static void ApplyMutations([NotNull] Pawn pawn, bool canApplyRestricted, bool setAtMaxStage,
                                           [NotNull] MorphPawnKindExtension kindExtension)
        {
            List <MutationDef> mutations;
            var addedPartsSet = new HashSet <BodyPartDef>();

            if (!canApplyRestricted)
            {
                canApplyRestricted = pawn.CanReceiveRareMutations();
            }


            if (canApplyRestricted)
            {
                mutations = kindExtension.GetRandomMutations(pawn.thingIDNumber).ToList();
            }
            else
            {
                mutations = kindExtension.GetRandomMutations(pawn.thingIDNumber)
                            .Where(g => !g.IsRestricted)              //only keep the unrestricted mutations
                            .ToList();
            }

            if (mutations.Count == 0)
            {
                Warning($"could not get any mutations for {pawn.Name} using extension\n{kindExtension.ToStringFull()}");
            }

            var toGive    = new List <MutationDef>();
            var addedList = new List <BodyPartRecord>();

            int toGiveCount = kindExtension.hediffRange.RandomInRange; //get a random number of mutations to add
            int max         = Mathf.Min(mutations.Count, toGiveCount);
            var i           = 0;

            while (i < max)
            {
                if (mutations.Count == 0)
                {
                    break;
                }
                while (true)
                {
                    if (mutations.Count == 0)
                    {
                        break;
                    }
                    int         rI     = Rand.Range(0, mutations.Count);
                    MutationDef mGiver = mutations[rI];

                    mutations.RemoveAt(rI); //remove the entry so we don't pull duplicates
                    if (mGiver.parts.Any(p => p != null && addedPartsSet.Contains(p))
                        )                   //make sure its for a part we haven't encountered yet
                    {
                        continue;
                    }

                    foreach (BodyPartDef part in mGiver.parts)
                    {
                        addedPartsSet.Add(part);
                    }
                    toGive.Add(mGiver);
                    i++;  //only count 1 regardless of what was added
                    break;
                }
            }


            foreach (MutationDef giver in toGive)
            {
                giver.ClearOverlappingMutations(pawn); // make sure to remove any overlapping hediffs added during a different stage

                var result = MutationUtilities.AddMutation(pawn, giver, int.MaxValue, MutationUtilities.AncillaryMutationEffects.None);
                addedList.AddRange(result.Parts);
            }

            if (toGive.Count > 0 && (addedList.Count == 0 || !pawn.health.hediffSet.hediffs.OfType <Hediff_AddedMutation>().Any()))
            {
                LogMsg(LogLevel.Warnings, $"could not add mutations to pawn {pawn.Name} with ext\n{kindExtension}");
            }

            if (setAtMaxStage)
            {
                var addedMutations = new List <Hediff_AddedMutation>();
                List <Hediff_AddedMutation> allMutationsOnPawn =
                    pawn.health.hediffSet.hediffs.OfType <Hediff_AddedMutation>().ToList(); //save these
                foreach (BodyPartRecord bodyPartRecord in addedList)                        //get a list of all mutations we just added
                {
                    foreach (Hediff_AddedMutation mutation in allMutationsOnPawn)
                    {
                        if (mutation.Part == bodyPartRecord && toGive.Contains(mutation.def as MutationDef))
                        {
                            if (!addedMutations.Contains(mutation))
                            {
                                addedMutations.Add(mutation);
                            }
                        }
                    }
                }


                foreach (Hediff_AddedMutation hediff in addedMutations)
                {
                    if (hediff.pawn == null)
                    {
                        continue;                      //sometimes the hediffs are removed by other mutations
                    }
                    if (hediff.TryGetComp <HediffComp_Production>() != null)
                    {
                        continue;                                                     //do not increase production hediffs
                    }
                    var comp = hediff.TryGetComp <Comp_MutationSeverityAdjust>();
                    if (comp != null)
                    {
                        hediff.Severity = comp.NaturalSeverityLimit;
                        continue;
                    }

                    HediffStage lastStage = hediff.def.stages?.LastOrDefault();
                    if (lastStage == null)
                    {
                        continue;
                    }

                    float severity = lastStage.minSeverity + 0.01f;
                    hediff.Severity = severity;
                }
            }


            pawn.CheckRace(false); //don't apply missing mutations to avoid giving restricted mutations and to respect the limit
        }
        private void AddPartMutations()
        {
            var mutationsAdded = 0;

            while (_curIndex < _checkList.Count)
            {
                BodyPartRecord part = _checkList[_curIndex];
                if (!pawn.RaceProps.body.AllParts.Contains(part))
                {
                    //if the pawn's race changes the mutation order may no longer be valid
                    //need to reset it and try again later
                    break;
                }

                var lst = _scratchDict.TryGetValue(part.def);

                if (lst == null) //end check early if there are no parts that can be added
                {
                    _curIndex++;
                    _curMutationIndex = 0;
                    continue;
                }
                //make sure we try each mutation per part

                while (_curMutationIndex < lst.Count)
                {
                    var mutation = lst[_curMutationIndex];

                    //check if the mutation can actually be added
                    if (!mutation.mutation.CanApplyMutations(pawn, part))
                    {
                        _curMutationIndex++;
                        continue;
                    }
                    else if (Rand.Value < mutation.addChance)
                    {
                        var result = MutationUtilities.AddMutation(pawn, mutation.mutation, part);
                        if (result) //make sure the mutation was actually added before doing this
                        {
                            var mutagen = def.GetMutagenDef();
                            mutagen.TryApplyAspects(pawn);
                            mutationsAdded++;
                        }
                    }
                    else if (mutation.blocks)
                    {
                        return; //wait here until the blocking mutation is added
                    }

                    _curMutationIndex++;

                    //check if we added enough mutations to break early
                    if (mutationsAdded >= MinMutationsPerCheck)
                    {
                        goto loopBreak;//break both loops
                    }
                }

                _curIndex++;           //increment after so mutations can 'block'
                _curMutationIndex = 0; //reset the mutation index every time we move up a part

                //check if we have added enough mutations to end the loop early
                if (mutationsAdded >= MinMutationsPerCheck)
                {
                    break;
                }
            }

loopBreak:  //label so we can break both loops

            if (mutationsAdded > 0)
            {
                OnMutationsAdded(mutationsAdded);
            }
        }
Beispiel #21
0
 void AddAllMutations()
 {
     MutationUtilities.AddMutation(_pawn, _mutationDef);
 }
Beispiel #22
0
 private void AssignMutations(Pawn gordon)
 {
     MutationUtilities.AddAllMorphMutations(gordon, MorphDefOfs.SheepMorph, MutationUtilities.AncillaryMutationEffects.None).SetAllToNaturalMax();
 }