Beispiel #1
0
 private static void SendLetter(TransformationRequest request, Pawn original, Pawn spawnedAnimal)
 {
     Find.LetterStack
     .ReceiveLetter("LetterHediffFromTransformationLabel".Translate(original.LabelShort, request.outputDef.LabelCap).CapitalizeFirst(),
                    "LetterHediffFromTransformation"
                    .Translate(original.LabelShort, request.outputDef.LabelCap)
                    .CapitalizeFirst(),
                    LetterDefOf.NeutralEvent,
                    spawnedAnimal);                         // Creates a letter saying "Oh no! Pawn X has transformed into a Y!"
     Find.TickManager.slower.SignalForceNormalSpeedShort(); // Slow down the speed of the game.
 }
Beispiel #2
0
        /// <summary>
        /// Gets the manhunter chance for the given request
        /// </summary>
        /// <param name="request">The request.</param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException">request</exception>
        protected virtual float GetManhunterChance([NotNull] TransformationRequest request)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            bool isFriendly = request.originals.Any(IsFriendly);

            var settings = request.manhunterSettingsOverride
                           ?? request.outputDef.GetModExtension <FormerHumanSettings>()?.manhunterSettings
                           ?? request.outputDef.race.GetModExtension <FormerHumanSettings>()?.manhunterSettings
                           ?? ManhunterTfSettings.Default;

            return(settings.ManhunterChance(isFriendly));
        }
Beispiel #3
0
        private static Faction GetFaction(TransformationRequest request, Pawn original)
        {
            Faction faction;

            if (request.forcedFaction != null) //forced faction should be the highest priority if set
            {
                faction = request.forcedFaction;
            }
            else if (original.IsColonist)
            {
                faction = original.Faction;
            }
            else
            {
                faction = null;
            }
            return(faction);
        }
Beispiel #4
0
 /// <summary>
 /// Applies the post tf effects.
 /// this should be called just before the original pawn is cleaned up
 /// </summary>
 /// <param name="original">The original.</param>
 /// <param name="transformedPawn">The transformed pawn.</param>
 protected override void ApplyPostTfEffects(Pawn original, Pawn transformedPawn, TransformationRequest request)
 {
     //apply apparel damage
     ApplyApparelDamage(original, transformedPawn.def);
     FormerHumanUtilities.TryAssignBackstoryToTransformedPawn(transformedPawn, original);
     base.ApplyPostTfEffects(original, transformedPawn, request);
 }
Beispiel #5
0
        /// <summary>
        ///     preform the requested transform
        /// </summary>
        /// <param name="request">The request.</param>
        /// <returns></returns>
        protected override TransformedPawnSingle TransformImpl(TransformationRequest request)
        {
            Pawn original = request.originals[0];

            if (request.addMutationToOriginal)
            {
                TryAddMutationsToPawn(original, request.cause, request.outputDef);
            }

            var     reactionStatus = original.GetFormerHumanReactionStatus();
            float   newAge         = TransformerUtility.ConvertAge(original, request.outputDef.race.race);
            Faction faction;

            faction = GetFaction(request, original);

            Gender newGender =
                TransformerUtility.GetTransformedGender(original, request.forcedGender, request.forcedGenderChance);


            var pRequest = FormerHumanUtilities.CreateSapientAnimalRequest(request.outputDef, original, faction, fixedGender: newGender);



            Pawn animalToSpawn = PawnGenerator.GeneratePawn(pRequest); //make the temp pawn



            animalToSpawn.needs.food.CurLevel =
                original.needs.food.CurLevel;   // Copies the original pawn's food need to the animal's.
            animalToSpawn.needs.rest.CurLevel =
                original.needs.rest.CurLevel;   // Copies the original pawn's rest need to the animal's.
            animalToSpawn.Name = original.Name; // Copies the original pawn's name to the animal's.
            float sapienceLevel = request.forcedSapienceLevel ?? GetSapienceLevel(original, animalToSpawn);

            if (request.forcedFaction == null && original.Faction != faction && original.Faction != animalToSpawn.Faction && FormerHumanUtilities.GetQuantizedSapienceLevel(sapienceLevel) <= SapienceLevel.MostlySapient)
            {
                //set the faction to the original's if mostly sapient or above
                animalToSpawn.SetFaction(original.Faction);
            }


            GiveTransformedPawnSapienceState(animalToSpawn, sapienceLevel);

            FormerHumanUtilities.InitializeTransformedPawn(original, animalToSpawn, sapienceLevel); //use a normal distribution?

            Pawn spawnedAnimal = SpawnAnimal(original, animalToSpawn);                              // Spawns the animal into the map.

            ReactionsHelper.OnPawnTransforms(original, animalToSpawn, reactionStatus);              //this needs to happen before MakeSapientAnimal because that removes relations

            var rFaction = request.factionResponsible ?? GetFactionResponsible(original);
            var inst     = new TransformedPawnSingle
            {
                original           = original,
                animal             = spawnedAnimal,
                factionResponsible = rFaction,
                reactionStatus     = reactionStatus
            };


            if (original.Spawned)
            {
                for (var i = 0; i < 10; i++) // Create a cloud of magic.
                {
                    IntermittentMagicSprayer.ThrowMagicPuffDown(spawnedAnimal.Position.ToVector3(), spawnedAnimal.MapHeld);
                    IntermittentMagicSprayer.ThrowMagicPuffUp(spawnedAnimal.Position.ToVector3(), spawnedAnimal.MapHeld);
                }
            }

            if (request.tale != null) // If a tale was provided, push it to the tale recorder.
            {
                TaleRecorder.RecordTale(request.tale, original, animalToSpawn);
            }

            Faction oFaction = original.FactionOrExtraHomeFaction;
            Map     oMap     = original.Map;


            //apply any other post tf effects
            ApplyPostTfEffects(original, animalToSpawn, request);

            TransformerUtility
            .CleanUpHumanPawnPostTf(original, request.cause);    //now clean up the original pawn (remove apparel, drop'em, ect)

            //notify the faction that their member has been transformed
            oFaction?.Notify_MemberTransformed(original, animalToSpawn, oMap == null, oMap);

            if (!request.noLetter && reactionStatus == FormerHumanReactionStatus.Colonist || reactionStatus == FormerHumanReactionStatus.Prisoner) //only send the letter for colonists and prisoners
            {
                SendLetter(request, original, spawnedAnimal);
            }

            if (original.Spawned)
            {
                original.DeSpawn(); // Remove the original pawn from the current map.
            }
            DebugLogUtils.Assert(!PrisonBreakUtility.CanParticipateInPrisonBreak(original),
                                 $"{original.Name} has been cleaned up and de-spawned but can still participate in prison breaks");


            return(inst);
        }
Beispiel #6
0
 /// <summary>Returns true if the specified request is valid.</summary>
 /// <param name="request">The request.</param>
 /// <returns>
 /// <c>true</c> if the specified request is valid; otherwise, <c>false</c>.
 /// </returns>
 protected override bool IsValid(TransformationRequest request)
 {
     return(base.IsValid(request) && request.originals.Length == 1);
 }
Beispiel #7
0
 /// <summary>
 /// Transforms the specified request and preforms all necessary cleanup after the transformation if successful
 /// </summary>
 /// implementers should make sure to preform all necessary cleanup of the pawn post transformation
 /// <param name="request">The request.</param>
 /// <returns>the transformed pawn instance to be added to the database, should return null if the request cannot be met</returns>
 [CanBeNull] public abstract TransformedPawn Transform(TransformationRequest request);
Beispiel #8
0
        /// <summary>
        /// Applies the post tf effects.
        /// this should be called just before the original pawn is cleaned up
        /// </summary>
        /// <param name="original">The original.</param>
        /// <param name="transformedPawn">The transformed pawn.</param>
        /// <param name="request">The transformation request</param>
        protected virtual void ApplyPostTfEffects([NotNull] Pawn original, [NotNull] Pawn transformedPawn, [NotNull] TransformationRequest request)
        {
            if (original == null)
            {
                throw new ArgumentNullException(nameof(original));
            }
            if (transformedPawn == null)
            {
                throw new ArgumentNullException(nameof(transformedPawn));
            }
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }
            List <Aspect> aspects = new List <Aspect>();

            foreach (AspectGiver aspectGiver in def.tfAspectGivers.MakeSafe())
            {
                aspects.Clear();
                if (aspectGiver.TryGiveAspects(original, aspects))
                {
                    foreach (Aspect aspect in aspects) //make sure we add them to both pawns
                    {
                        var aDef    = aspect;
                        var tracker = transformedPawn.GetAspectTracker();
                        tracker?.Add(aDef, aspect.StageIndex);
                    }
                }
            }


            float manhunterChance = GetManhunterChance(request);

            if (manhunterChance > FormerHumanUtilities.MANHUNTER_EPSILON && Rand.Value < manhunterChance)
            {
                MentalStateDef stateDef = MentalStateDefOf.Manhunter;

                transformedPawn.mindState?.mentalStateHandler?.TryStartMentalState(stateDef, forceWake: true);
            }
            else if (def.appliesTfParalysis)
            {
                //don't add tf paralysis on manhunter
                transformedPawn.health.AddHediff(TfHediffDefOf.TransformationParalysis);
            }
        }
        /// <summary>
        /// preform the requested transform
        /// </summary>
        /// <param name="request">The request.</param>
        /// <returns></returns>
        protected override MergedPawns TransformImpl(TransformationRequest request)
        {
            Pawn  firstPawn  = request.originals[0];
            Pawn  secondPawn = request.originals[1];
            float averageAge = firstPawn.ageTracker.AgeBiologicalYearsFloat
                               + secondPawn.ageTracker.AgeBiologicalYearsFloat;

            averageAge /= 2;


            float newAge = averageAge * request.outputDef.race.race.lifeExpectancy / firstPawn.RaceProps.lifeExpectancy;

            Faction faction = request.forcedFaction ?? Faction.OfPlayer;

            var pRequest = FormerHumanUtilities.CreateMergedAnimalRequest(request.outputDef, request.originals, faction);



            Pawn meldToSpawn = PawnGenerator.GeneratePawn(pRequest);

            HediffDef hediffToAdd = HediffDef.Named(FORMER_HUMAN_HEDIFF); //make sure hediff is added before spawning meld

            //make them count as former humans
            var tracker = meldToSpawn.GetFormerHumanTracker();

            if (tracker == null)
            {
                Log.Error($"{meldToSpawn.def.defName} is a meld but does not have a former human tracker!");
            }
            else
            {
                tracker.MakeFormerHuman(1);
            }



            Hediff hediff = HediffMaker.MakeHediff(hediffToAdd, meldToSpawn);

            hediff.Severity = Rand.Range(request.minSeverity, request.maxSeverity);
            meldToSpawn.health.AddHediff(hediff);

            Pawn_NeedsTracker needs = meldToSpawn.needs;

            needs.food.CurLevel = firstPawn.needs.food.CurLevel;
            needs.rest.CurLevel = firstPawn.needs.rest.CurLevel;
            meldToSpawn.training.SetWantedRecursive(TrainableDefOf.Obedience, true);
            meldToSpawn.training.Train(TrainableDefOf.Obedience, null, true);
            meldToSpawn.Name = firstPawn.Name;
            var meld = (Pawn)GenSpawn.Spawn(meldToSpawn, firstPawn.PositionHeld, firstPawn.MapHeld);

            for (var i = 0; i < 10; i++)
            {
                IntermittentMagicSprayer.ThrowMagicPuffDown(meld.Position.ToVector3(), meld.MapHeld);
                IntermittentMagicSprayer.ThrowMagicPuffUp(meld.Position.ToVector3(), meld.MapHeld);
            }

            meld.SetFaction(Faction.OfPlayer);

            ReactionsHelper.OnPawnsMerged(firstPawn, firstPawn.IsPrisoner, secondPawn, secondPawn.IsPrisoner, meld);


            TransformerUtility.CleanUpHumanPawnPostTf(firstPawn, null);
            TransformerUtility.CleanUpHumanPawnPostTf(secondPawn, null);

            var inst = new MergedPawns
            {
                originals          = request.originals.ToList(), //we want to make a copy here
                meld               = meld,
                mutagenDef         = def,
                factionResponsible = Faction.OfPlayer
            };

            return(inst);
        }