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