/// <summary>
        ///     Tries to revert the transformed pawn instance, implementation.
        /// </summary>
        /// <param name="transformedPawn">The transformed pawn.</param>
        /// <returns></returns>
        protected override bool TryRevertImpl(TransformedPawnSingle transformedPawn)
        {
            if (transformedPawn == null)
            {
                throw new ArgumentNullException(nameof(transformedPawn));
            }
            if (!transformedPawn.IsValid)
            {
                Log.Warning(nameof(SimpleMechaniteMutagen) + " received an invalid transformed pawn to revert");
                return(false);
            }


            Pawn animal = transformedPawn.animal;

            if (animal == null)
            {
                return(false);
            }
            var rFaction = transformedPawn.FactionResponsible;


            var spawned = (Pawn)GenSpawn.Spawn(transformedPawn.original, animal.PositionHeld, animal.MapHeld);

            if (spawned.Faction != animal.Faction && rFaction == null) //if the responsible faction is null (no one knows who did it) have the reverted pawn join that faction
            {
                spawned.SetFaction(animal.Faction);
            }


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

            //transfer hediffs from the former human back onto the original pawn
            FormerHumanUtilities.TransferHediffs(animal, spawned);

            SetHumanoidSapience(spawned, animal);

            FixBondRelationship(spawned, animal);
            FormerHumanUtilities.TransferEverything(animal, spawned);

            spawned.Faction?.Notify_MemberReverted(spawned, animal, spawned.Map == null, spawned.Map);

            ReactionsHelper.OnPawnReverted(spawned, animal, transformedPawn.reactionStatus);
            spawned.health.AddHediff(MorphTransformationDefOf.StabiliserHigh); //add stabilizer on reversion


            TransformerUtility.CleanUpHumanPawnPostTf(animal, null);
            animal.Destroy();
            return(true);
        }
Пример #2
0
 /// <summary>
 /// Applies the apparel damage to the given pawn
 /// </summary>
 /// <param name="pawn">The pawn.</param>
 /// <param name="newRace">The new race.</param>
 /// <exception cref="System.ArgumentNullException">
 /// pawn
 /// or
 /// newRace
 /// </exception>
 protected void ApplyApparelDamage([NotNull] Pawn pawn, [NotNull] ThingDef newRace)
 {
     if (pawn == null)
     {
         throw new ArgumentNullException(nameof(pawn));
     }
     if (newRace == null)
     {
         throw new ArgumentNullException(nameof(newRace));
     }
     TransformerUtility.ApplyTfDamageToApparel(pawn, newRace, def);
 }
Пример #3
0
        Pawn GenerateGordon(Pawn animal)
        {
            PawnKindDef kind = PawnKindDefOf.Colonist; //TODO get these randomly ;
            Faction     faction = Faction.OfPlayer;
            bool        useFirst = Rand.Bool;
            string      firstName, lastName;

            firstName = lastName = null;
            if (useFirst)
            {
                firstName = "Gordon";
            }
            else
            {
                lastName = "Ramsey";
            }



            float convertedAge = Mathf.Max(TransformerUtility.ConvertAge(animal, ThingDefOf.Human.race), 17);
            float chronoAge    = animal.ageTracker.AgeChronologicalYears * convertedAge / animal.ageTracker.AgeBiologicalYears;
            var   local        = new PawnGenerationRequest(kind, faction, PawnGenerationContext.NonPlayer, -1,
                                                           fixedChronologicalAge: chronoAge,
                                                           fixedBiologicalAge: convertedAge, fixedBirthName: firstName,
                                                           fixedLastName: lastName, fixedGender: Gender.Male, forcedTraits: ForcedTraits)
            {
                ForcedTraits = ForcedTraits, ValidatorPreGear = GordenValidator
            };


            Pawn lPawn = PawnGenerator.GeneratePawn(local);



            if (!BackstoryDatabase.TryGetWithIdentifier("chef", out Backstory back))
            {
            }
            else
            {
                lPawn.story.adulthood = back;
            }

            AssignMutations(lPawn);
            return(lPawn);
        }
Пример #4
0
        /// <summary>
        ///     Tries to revert the given pawn.
        /// </summary>
        /// <param name="transformedPawn">The transformed pawn.</param>
        /// <returns></returns>
        public override bool TryRevert(Pawn transformedPawn)
        {
            var pawnStatus = GameComp.GetTransformedPawnContaining(transformedPawn);

            if (pawnStatus != null)
            {
                if (pawnStatus.Value.status != TransformedStatus.Transformed)
                {
                    return(false);
                }
                if (pawnStatus.Value.pawn is TransformedPawnSingle inst)
                {
                    if (TryRevertImpl(inst))
                    {
                        GameComp.RemoveInstance(inst);
                        return(true);
                    }
                    else
                    {
                        Log.Warning($"could not revert original pawn instance {inst}");
                    }
                }
                else
                {
                    Log.Warning($"{nameof(SimpleMechaniteMutagen)} received \"{pawnStatus.Value.pawn?.GetType()?.Name ??"NULL"}\" but was expecting \"{nameof(TransformedPawnSingle)}\"");
                }
                return(false);
            }
            else
            {
                Log.Warning($"unable to find status for transformed pawn {transformedPawn.ThingID}");
            }



            PawnGenerationRequest request = TransformerUtility.GenerateRandomPawnFromAnimal(transformedPawn);



            Pawn pawnTf = PawnGenerator.GeneratePawn(request);

            pawnTf.needs.food.CurLevel = transformedPawn.needs.food.CurLevel;
            pawnTf.needs.rest.CurLevel = transformedPawn.needs.rest.CurLevel;
            Log.Message($"going to spawn {pawnTf.Name} {pawnTf.KindLabel}");
            var spawned = (Pawn)GenSpawn.Spawn(pawnTf, transformedPawn.GetCorrectPosition(), transformedPawn.GetCorrectMap());

            spawned.equipment.DestroyAllEquipment();
            spawned.apparel.DestroyAll();

            if (transformedPawn.Name is NameTriple nT)
            {
                spawned.Name = nT; //give the new random pawn the same name as the former human
            }


            for (var i = 0; i < 10; i++)
            {
                IntermittentMagicSprayer.ThrowMagicPuffDown(spawned.GetCorrectPosition().ToVector3(), spawned.GetCorrectMap());
                IntermittentMagicSprayer.ThrowMagicPuffUp(spawned.GetCorrectPosition().ToVector3(), spawned.GetCorrectMap());
            }


            AddReversionThought(spawned);



            transformedPawn.Destroy();
            return(true);
        }
Пример #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);
        }
Пример #6
0
        /// <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);
        }
Пример #7
0
        /// <summary>
        ///     Tries to revert the given pawn.
        /// </summary>
        /// <param name="transformedPawn">The transformed pawn.</param>
        /// <returns></returns>
        public override bool TryRevert(Pawn transformedPawn)
        {
            if (transformedPawn == null)
            {
                throw new ArgumentNullException(nameof(transformedPawn));
            }

            Tuple <TransformedPawn, TransformedStatus> status = GameComp.GetTransformedPawnContaining(transformedPawn);

            if (status != null)
            {
                if (status.Item2 != TransformedStatus.Transformed)
                {
                    return(false);
                }

                if (status.Item1 is MergedPawns merged)
                {
                    if (merged.mutagenDef != def)
                    {
                        return(false);
                    }

                    if (TryRevertImpl(merged))
                    {
                        GameComp.RemoveInstance(merged);
                        return(true);
                    }
                }

                return(false);
            }

            HediffDef formerDef = HediffDef.Named(FORMER_HUMAN_HEDIFF);

            if (transformedPawn.health.hediffSet.HasHediff(formerDef))
            {
                Hediff     formerHediff = transformedPawn.health.hediffSet.hediffs.First(h => h.def == formerDef);
                ThoughtDef thoughtDef   = null;

                for (var i = 0; i < 2; i++)
                {
                    PawnGenerationRequest request = TransformerUtility.GenerateRandomPawnFromAnimal(transformedPawn);
                    Pawn pawnTf = PawnGenerator.GeneratePawn(request);
                    pawnTf.needs.food.CurLevel = transformedPawn.needs.food.CurInstantLevel;
                    pawnTf.needs.rest.CurLevel = transformedPawn.needs.rest.CurLevel;

                    var spawnedPawn = (Pawn)GenSpawn.Spawn(pawnTf, transformedPawn.PositionHeld, transformedPawn.MapHeld);
                    spawnedPawn.apparel.DestroyAll();
                    spawnedPawn.equipment.DestroyAllEquipment();
                    for (var j = 0; j < 10; j++)
                    {
                        IntermittentMagicSprayer.ThrowMagicPuffDown(spawnedPawn.Position.ToVector3(), spawnedPawn.MapHeld);
                        IntermittentMagicSprayer.ThrowMagicPuffUp(spawnedPawn.Position.ToVector3(), spawnedPawn.MapHeld);
                    }

                    thoughtDef       = AddRandomThought(spawnedPawn, formerHediff.CurStageIndex);
                    _scratchArray[i] = spawnedPawn;
                }
                PawnRelationDef relationDef;
                bool            relationIsMergeMate = thoughtDef == def.revertedThoughtGood;
                relationDef = relationIsMergeMate ? TfRelationDefOf.MergeMate : TfRelationDefOf.ExMerged;
                _scratchArray[0].relations.AddDirectRelation(relationDef, _scratchArray[1]);

                CheckForBrainDamage(transformedPawn, _scratchArray[0], _scratchArray[1]);
                transformedPawn.Destroy();



                return(true);
            }

            return(false);
        }
Пример #8
0
        /// <summary>
        ///     Tries to revert the given pawn.
        /// </summary>
        /// <param name="transformedPawn">The transformed pawn.</param>
        /// <returns></returns>
        public override bool TryRevert(Pawn transformedPawn)
        {
            if (transformedPawn == null)
            {
                throw new ArgumentNullException(nameof(transformedPawn));
            }

            var pawnStatus = GameComp.GetTransformedPawnContaining(transformedPawn);
            var sState     = transformedPawn.GetSapienceState();

            if (sState == null)
            {
                return(false);
            }
            if (pawnStatus != null)
            {
                if (pawnStatus.Value.status != TransformedStatus.Transformed)
                {
                    return(false);
                }
                if (pawnStatus.Value.pawn is MergedPawns merged)
                {
                    if (sState.StateDef != def.transformedSapienceState)
                    {
                        return(false);
                    }

                    if (TryRevertImpl(merged))
                    {
                        GameComp.RemoveInstance(merged);
                        return(true);
                    }
                }

                return(false);
            }


            if (sState.StateDef == def.transformedSapienceState)
            {
                ThoughtDef thoughtDef = null;

                for (var i = 0; i < 2; i++)
                {
                    PawnGenerationRequest request = TransformerUtility.GenerateRandomPawnFromAnimal(transformedPawn);
                    Pawn pawnTf = PawnGenerator.GeneratePawn(request);
                    pawnTf.needs.food.CurLevel = transformedPawn.needs.food.CurInstantLevel;
                    pawnTf.needs.rest.CurLevel = transformedPawn.needs.rest.CurLevel;

                    var spawnedPawn = (Pawn)GenSpawn.Spawn(pawnTf, transformedPawn.PositionHeld, transformedPawn.MapHeld);
                    spawnedPawn.apparel.DestroyAll();
                    spawnedPawn.equipment.DestroyAllEquipment();
                    for (var j = 0; j < 10; j++)
                    {
                        IntermittentMagicSprayer.ThrowMagicPuffDown(spawnedPawn.Position.ToVector3(), spawnedPawn.MapHeld);
                        IntermittentMagicSprayer.ThrowMagicPuffUp(spawnedPawn.Position.ToVector3(), spawnedPawn.MapHeld);
                    }

                    _scratchArray[i] = spawnedPawn;
                }
                PawnRelationDef relationDef;
                bool            relationIsMergeMate = thoughtDef == def.revertedThoughtGood;
                relationDef = relationIsMergeMate ? TfRelationDefOf.MergeMate : TfRelationDefOf.ExMerged;
                _scratchArray[0].relations.AddDirectRelation(relationDef, _scratchArray[1]);

                CheckForBrainDamage(transformedPawn, _scratchArray[0], _scratchArray[1]);
                transformedPawn.Destroy();



                return(true);
            }

            return(false);
        }
Пример #9
0
        /// <summary>
        /// safely change the pawns race
        /// </summary>
        /// <param name="pawn">The pawn.</param>
        /// <param name="race">The race.</param>
        /// <param name="reRollTraits">if race related traits should be reRolled</param>
        /// <exception cref="ArgumentNullException">pawn</exception>
        public static void ChangePawnRace([NotNull] Pawn pawn, [NotNull] ThingDef race, bool reRollTraits = false)
        {
            if (pawn == null)
            {
                throw new ArgumentNullException(nameof(pawn));
            }
            if (race == null)
            {
                throw new ArgumentNullException(nameof(race));
            }
            MorphDef oldMorph = pawn.def.GetMorphOfRace();
            ThingDef oldRace  = pawn.def;

            AspectTracker aTracker = pawn.GetAspectTracker();

            AspectDef oldMorphAspectDef = oldMorph?.group?.aspectDef;

            if (oldMorphAspectDef != null && aTracker != null)
            {
                Aspect aspect = aTracker.GetAspect(oldMorphAspectDef);
                if (aspect != null)
                {
                    aTracker.Remove(aspect);
                }
            }

            TransformerUtility.ScaleInjuriesToNewRace(pawn, race);

            //var pos = pawn.Position;
            Faction faction = pawn.Faction;
            Map     map     = pawn.Map;

            if (map != null)
            {
                RegionListersUpdater.DeregisterInRegions(pawn, map);
            }
            var removed = false;

            if (map?.listerThings != null)
            {
                if (map.listerThings.Contains(pawn))
                {
                    map.listerThings.Remove(pawn); //make sure to update the lister things or else dying will break
                    removed = true;
                }
            }

            pawn.def = race;

            if (removed && !map.listerThings.Contains(pawn))
            {
                map.listerThings.Add(pawn);
            }

            if (map != null)
            {
                RegionListersUpdater.RegisterInRegions(pawn, map);
            }

            map?.mapPawns.UpdateRegistryForPawn(pawn);

            //add the group hediff if applicable
            AspectDef aspectDef = race.GetMorphOfRace()?.group?.aspectDef;

            if (aspectDef != null)
            {
                aTracker?.Add(aspectDef);
            }

            if (map != null)
            {
                var comp = map.GetComponent <MorphTracker>();
                comp.NotifyPawnRaceChanged(pawn, oldMorph);
            }

            if (race == ThingDefOf.Human)
            {
                ValidateReversion(pawn);
            }
            else
            {
                ValidateExplicitRaceChange(pawn, race, oldRace);
            }

            var mTracker = pawn.GetComp <MorphTrackingComp>();

            if (mTracker == null)
            {
                Warning($"changing the race of {pawn.Name} but they have no {nameof(MorphTrackingComp)}!");
            }
            else
            {
                mTracker.needsRaceCompCheck = true;
            }

            //no idea what HarmonyPatches.Patch.ChangeBodyType is for, not listed in pasterbin
            pawn.RefreshGraphics();

            if (reRollTraits && race is ThingDef_AlienRace alienDef)
            {
                ReRollRaceTraits(pawn, alienDef);
            }

            //save location
            if (Current.ProgramState == ProgramState.Playing)
            {
                pawn.ExposeData();
            }
            if (pawn.Faction != faction)
            {
                pawn.SetFaction(faction);
            }
            foreach (IRaceChangeEventReceiver raceChangeEventReceiver in pawn.AllComps.OfType <IRaceChangeEventReceiver>())
            {
                raceChangeEventReceiver.OnRaceChange(oldRace);
            }
        }