예제 #1
0
        /// <summary>Tries the apply the mutation to the given pawn</summary>
        /// <param name="pawn">The pawn.</param>
        /// <param name="mutagenDef">The mutagen definition. used to determine if it's a valid target or not</param>
        /// <param name="outAddedHediffs">The out added hediffs.</param>
        /// <param name="cause">The cause.</param>
        /// <param name="addLogEntry">if set to <c>true</c> [add log entry].</param>
        /// <returns>if the mutation was added or not</returns>
        public bool TryApply(Pawn pawn, MutagenDef mutagenDef, List <Hediff> outAddedHediffs = null, Hediff cause = null, bool addLogEntry = true)
        {
            if (!mutagenDef.CanInfect(pawn))
            {
                return(false);
            }
            if (!hediff.IsValidFor(pawn))
            {
                return(false);
            }
            bool added = PawnmorphHediffGiverUtility.TryApply(pawn, hediff, partsToAffect, canAffectAnyLivePart, countToAffect, outAddedHediffs);

            if (addLogEntry && added && partsToAffect != null)
            {
                AddMutationLogFor(pawn);
            }

            if (added)
            {
                var cDef = cause?.def;
                if (cDef != null)
                {
                    AspectUtils.TryApplyAspectsFrom(cDef, pawn);
                }
            }
            return(added);
        }
예제 #2
0
        /// <summary>tries to apply the mutations to the given body part records</summary>
        /// <param name="pawn">The pawn.</param>
        /// <param name="recordsToAdd">The records to add.</param>
        /// <param name="mutagen">The mutagen.</param>
        /// <returns></returns>
        public bool TryApply(Pawn pawn, List <BodyPartRecord> recordsToAdd, MutagenDef mutagen = null)
        {
            mutagen = mutagen ?? MutagenDefOf.defaultMutagen;
            if (!mutagen.CanInfect(pawn))
            {
                return(false);
            }
            if (!hediff.IsValidFor(pawn))
            {
                return(false);
            }
            bool anyAdded = false;
            HashSet <BodyPartRecord> nonMissingRecords = new HashSet <BodyPartRecord>(pawn.health.hediffSet.GetNotMissingParts());

            foreach (BodyPartRecord bodyPartRecord in recordsToAdd)
            {
                if (!nonMissingRecords.Contains(bodyPartRecord))
                {
                    continue;
                }
                anyAdded |= TryApply(pawn, bodyPartRecord, mutagen, nonMissingRecords);
            }

            return(anyAdded);
        }
예제 #3
0
        /// <summary> The function that does the heavy lifting for a HediffGiver. </summary>
        /// <param name="pawn"> The pawn the parent hediff is applied to. </param>
        /// <param name="cause"> The parent hediff where this HediffGiver is located in. </param>
        public override void OnIntervalPassed(Pawn pawn, [NotNull] Hediff cause)
        {
            // Push a multiplay-safe randomization seed.
            RandUtilities.PushState();


            var   singleComp = cause.TryGetComp <HediffComp_Single>();
            float mult       = singleComp?.stacks
                               ?? 1; //the more stacks of partial morphs the pawn has the faster the mutation rate should be

            mult *= pawn.GetStatValue(PMStatDefOf.MutagenSensitivity);
            mult *= singleComp?.Props?.mutationRateMultiplier ?? 1;
            mult  = Mathf.Max(0.001f, mult); //prevent division by zero


            // After roughly this duration, try to apply the hediff if the pawn is of human-like intelligence.
            if (Rand.MTBEventOccurs(mtbDays / mult, mtbUnits, 30f) && pawn.RaceProps.intelligence == Intelligence.Humanlike)
            {
                //mutagen is what contains information like infect-ability of a pawn and post mutation effects
                MutagenDef mutagen = cause.def?.GetMutagenDef() ?? MutagenDefOf.defaultMutagen;

                // Check if this HediffGiver has the HediffComp_Single property (basically a dummy property that only comes into play in this function).
                var comp = singleComp;

                // If we haven't already tried to apply this giver's hediff and the pawn either passes a percentile roll or are of the right gender, try and apply the hediff.
                if (!_triggered.TryGetValue(cause) && (gender == pawn.gender || Rand.RangeInclusive(0, 100) <= chance) && TryApply(pawn, mutagen, null, cause))
                {
                    _triggered[cause] = true;
                    DoMutationAddedEffects(pawn);

                    // If the parent has the single comp, decrement it's current count and remove it if it's out of charges.
                    if (comp != null)
                    {
                        comp.stacks--;
                        if (comp.stacks <= 0)
                        {
                            pawn.health.RemoveHediff(cause);
                        }
                    }
                }
                else
                {
                    _triggered[cause] = true;
                    // If the giver had the single comp, clear the list so it can try and apply the hediff again.
                    // While this does prevent the partial hediffs from getting "stuck", it does mean that they
                    // can apply a hediff that already exists or failed because of the %chance rule. Need to find
                    // a better solution to this problem eventually.
                    if (comp != null)
                    {
                        ClearHediff(cause);
                    }
                }
            }

            // Pop the seed to restore balance to the universe (and the game).
            RandUtilities.PopState();
        }
 /// <summary>
 /// Gets the net mutagenic buildup multiplier for this pawn.
 /// </summary>
 /// <param name="pawn">The pawn.</param>
 /// <param name="mutagenDef">The mutagen definition.</param>
 /// <returns></returns>
 public static float GetMutagenicBuildupMultiplier([NotNull] this Pawn pawn, MutagenDef mutagenDef = null)
 {
     mutagenDef = mutagenDef ?? MutagenDefOf.defaultMutagen;
     if (!mutagenDef.CanInfect(pawn))
     {
         return(0);
     }
     return(pawn.GetStatValue(StatDefOf.ToxicSensitivity) * pawn.GetStatValue(PMStatDefOf.MutagenSensitivity));
 }
예제 #5
0
        /// <summary>Tries to apply the mutation to the given body part record</summary>
        /// <param name="pawn">The pawn.</param>
        /// <param name="recordToAdd">The record to add.</param>
        /// <param name="mutagen">The mutagen.</param>
        /// <returns></returns>
        public bool TryApply(Pawn pawn, BodyPartRecord recordToAdd, MutagenDef mutagen = null)
        {
            mutagen = mutagen ?? MutagenDefOf.defaultMutagen;
            if (!mutagen.CanInfect(pawn))
            {
                return(false);
            }
            HashSet <BodyPartRecord> nonMissingRecords = new HashSet <BodyPartRecord>(pawn.health.hediffSet.GetNotMissingParts());

            return(TryApply(pawn, recordToAdd, mutagen, nonMissingRecords));
        }
예제 #6
0
        private static void MutatePawn(Pawn pawn, MutagenDef mutagen)
        {
            HediffSet hediffSet = pawn.health.hediffSet;

            if (!pawn.Spawned || !mutagen.CanInfect(pawn))
            {
                return;
            }

            pawn.health.AddHediff(MorphTransformationDefOf.FullRandomTF);
            IntermittentMagicSprayer.ThrowMagicPuffDown(pawn.Position.ToVector3(), pawn.Map);
        }
예제 #7
0
        /// <summary>
        /// Tries the apply aspects that might be given from this mutagen
        /// </summary>
        /// <param name="mutagen">The mutagen.</param>
        /// <param name="pawn">The pawn.</param>
        /// <exception cref="ArgumentNullException">
        /// mutagen
        /// or
        /// pawn
        /// </exception>
        public static void TryApplyAspects([NotNull] this MutagenDef mutagen, [NotNull] Pawn pawn)
        {
            if (mutagen == null)
            {
                throw new ArgumentNullException(nameof(mutagen));
            }
            if (pawn == null)
            {
                throw new ArgumentNullException(nameof(pawn));
            }

            foreach (AspectGiver aspectGiver in mutagen.aspectGivers.MakeSafe())
            {
                aspectGiver.TryGiveAspects(pawn);
            }
        }
            private static bool Prefix_AddHumanlikeOrders(Vector3 clickPos, Pawn pawn, List <FloatMenuOption> opts)
            {
                if (pawn.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation))
                {
                    foreach (LocalTargetInfo localTargetInfo3 in GenUI.TargetsAt(clickPos, TargetingParameters.ForRescue(pawn),
                                                                                 true))
                    {
                        LocalTargetInfo localTargetInfo4 = localTargetInfo3;
                        var             victim           = (Pawn)localTargetInfo4.Thing;
                        MutagenDef      mutagen          = MutagenDefOf.MergeMutagen;
                        if (mutagen.CanTransform(victim) &&
                            pawn.CanReserveAndReach(victim, PathEndMode.OnCell, Danger.Deadly, 1, -1, null, true) &&
                            Building_MutagenChamber.FindCryptosleepCasketFor(victim, pawn, true) != null)
                        {
                            string text4   = "CarryToChamber".Translate(localTargetInfo4.Thing.LabelCap, localTargetInfo4.Thing);
                            JobDef jDef    = Mutagen_JobDefOf.CarryToMutagenChamber;
                            Action action3 = delegate
                            {
                                Building_MutagenChamber building_chamber =
                                    Building_MutagenChamber.FindCryptosleepCasketFor(victim, pawn);
                                if (building_chamber == null)
                                {
                                    building_chamber = Building_MutagenChamber.FindCryptosleepCasketFor(victim, pawn, true);
                                }
                                if (building_chamber == null)
                                {
                                    Messages.Message("CannotCarryToChamber".Translate() + ": " + "NoChamber".Translate(), victim,
                                                     MessageTypeDefOf.RejectInput, false);
                                    return;
                                }

                                var job = new Job(jDef, victim, building_chamber);
                                job.count = 1;
                                pawn.jobs.TryTakeOrderedJob(job);
                            };
                            string label   = text4;
                            Action action2 = action3;
                            Pawn   revalidateClickTarget = victim;
                            opts.Add(FloatMenuUtility
                                     .DecoratePrioritizedTask(new FloatMenuOption(label, action2, MenuOptionPriority.Default, null, revalidateClickTarget),
                                                              pawn, victim));
                        }
                    }
                }

                return(true);
            }
예제 #9
0
        /// <summary> Determines whether this instance can infect the specified pawn. </summary>
        /// <param name="mutationDef"> The mutation definition. </param>
        /// <param name="pawn"> The pawn. </param>
        /// <returns> <c>true</c> if this instance can infect the specified pawn; otherwise, <c>false</c>. </returns>
        /// <exception cref="System.ArgumentNullException"> mutationDef or pawn is null. </exception>
        public static bool CanInfect([NotNull] this HediffDef mutationDef, [NotNull] Pawn pawn)
        {
            if (mutationDef == null)
            {
                throw new ArgumentNullException(nameof(mutationDef));
            }
            if (pawn == null)
            {
                throw new ArgumentNullException(nameof(pawn));
            }



            MutagenDef mutagenSource = mutationDef.GetMutagenDef();

            return(mutagenSource.CanInfect(pawn));
        }
예제 #10
0
        bool TryApply(Pawn pawn, BodyPartRecord recordToAdd, [NotNull] MutagenDef mutagen, HashSet <BodyPartRecord> nonMissingRecords)
        {
            if (!mutagen.CanInfect(pawn))
            {
                return(false);
            }
            if (!nonMissingRecords.Contains(recordToAdd))
            {
                return(false);
            }
            if (!hediff.IsValidFor(pawn))
            {
                return(false);
            }
            var hediffInst = HediffMaker.MakeHediff(hediff, pawn, recordToAdd);

            pawn.health.AddHediff(hediffInst, recordToAdd);
            DoMutationAddedEffects(pawn);
            AddMutationLogFor(pawn);

            return(true);
        }
예제 #11
0
        /// <summary>
        /// applies damage to all apparel the pawn is wearing based on
        /// </summary>
        /// <param name="pawn">The pawn.</param>
        /// <param name="newRace">The new race.</param>
        /// <param name="mutagen">the mutagen that caused the transformation, if null uses default values for <see cref="MutagenDamageProperties"/></param>
        /// <exception cref="System.ArgumentNullException">
        /// pawn
        /// or
        /// newRace
        /// </exception>
        public static void ApplyTfDamageToApparel([NotNull] Pawn pawn, [NotNull] ThingDef newRace, [CanBeNull] MutagenDef mutagen)
        {
            if (pawn == null)
            {
                throw new ArgumentNullException(nameof(pawn));
            }
            if (newRace == null)
            {
                throw new ArgumentNullException(nameof(newRace));
            }
            Pawn_ApparelTracker apparelTracker = pawn.apparel;
            List <Apparel>      cachedApparel  = apparelTracker?.WornApparel?.ToList(); //make a copy of all worn apparel

            if (cachedApparel == null || cachedApparel.Count == 0)
            {
                return;
            }

            MutagenDamageProperties damageProps = mutagen?.damageProperties ?? DefaultDamageValues;

            float oldSize = pawn.RaceProps.baseBodySize;
            float newSize = newRace.race.baseBodySize;
            float percentDiff;

            if (oldSize < EPSILON && newSize < EPSILON) //prevent division by zero
            {
                percentDiff = 0;                        //if they're both really small say no change
            }
            else if (oldSize < EPSILON)
            {
                percentDiff = MAX_APPAREL_PDIFF; //if just old size is small then completely destroy the apparel
            }
            else
            {
                percentDiff  = (newSize - oldSize) / oldSize; //signed percent difference between
                percentDiff += APPAREL_PDIFF_OFFSET;          //add a little offset so if the body size is the same or slightly smaller we still apply some damage
                //trying to account for differences in 'body shape'
            }


            float percentDamage =
                Mathf.Clamp(percentDiff, 0,
                            MAX_APPAREL_PDIFF); //clamp pDiff between [0, Max], if they shrink don't damage apparel

            percentDamage /= MAX_APPAREL_PDIFF; //normalize the percentDifference to get a percentage to damage apparel by
            int totalStuffProduced = 0;

            foreach (Apparel apparel in cachedApparel)
            {
                int damage = Mathf.CeilToInt(apparel.MaxHitPoints * percentDamage * damageProps.apparelDamageMultiplier)
                             + damageProps.apparelDamageOffset;
                int newHitPoints = Mathf.Max(apparel.HitPoints - damage, 0);
                var damageDone   = apparel.HitPoints - newHitPoints; //save the actual damage done

                apparel.HitPoints = newHitPoints;
                if (apparel.HitPoints == 0)
                {
                    apparelTracker.Remove(apparel);
                    apparelTracker.Notify_ApparelRemoved(apparel);
                    apparel.Destroy();
                }

                var stuffProduced = Mathf.FloorToInt(damageDone * damageProps.spawnedBiproductMult);
                totalStuffProduced += Mathf.Min(stuffProduced, MAX_APPAREL_DAMAGE_PRODUCT_PER_APPAREL);
            }

            if (damageProps.biproduct != null && damageProps.spawnedBiproductMult > EPSILON)
            {
                Thing thing = ThingMaker.MakeThing(damageProps.biproduct);
                thing.stackCount = totalStuffProduced;

                if (pawn.Spawned)
                {
                    GenPlace.TryPlaceThing(thing, pawn.PositionHeld, pawn.MapHeld, ThingPlaceMode.Near);
                }
                else
                {
                    Caravan caravan = pawn.GetCaravan();
                    caravan?.AddPawnOrItem(thing, false);
                }
            }
        }
예제 #12
0
        /// <summary> Add mutations to the given part. </summary>
        private void AddMutationToPart(BodyPartRecord record, [NotNull] Pawn pawn, AnimalClassBase aClass = null, bool recursive = false, MutagenDef mutagen = null)
        {
            MutationDef mutation;

            if (aClass != null)
            {
                mutation = aClass?.GetAllMorphsInClass()
                           .SelectMany(m => m.GetMutationForPart(record.def))
                           .RandomElementWithFallback();
            }
            else
            {
                mutation = MutationUtilities.GetMutationsByPart(record.def).RandomElementWithFallback();
            }

            if (mutation != null)
            {
                MutationUtilities.AddMutation(pawn, mutation, record);
            }

            mutagen?.TryApplyAspects(pawn);

            if (recursive) // Recursively add mutations to child parts.
            {
                foreach (BodyPartRecord cPart in record.GetDirectChildParts())
                {
                    AddMutationToPart(cPart, pawn, aClass, true, mutagen);
                }
            }
        }