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. }
/// <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)); }
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); }
/// <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); }
/// <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); }
/// <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); }
/// <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);
/// <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); }