/// <summary> /// called after the parent thing is spawned /// </summary> /// <param name="respawningAfterLoad">if set to <c>true</c> [respawning after load].</param> public override void PostSpawnSetup(bool respawningAfterLoad) { base.PostSpawnSetup(respawningAfterLoad); if (respawningAfterLoad) { return; } if (!triggered) { triggered = true; if (Pawn.health.hediffSet.HasHediff(TfHediffDefOf.TransformedHuman)) { return; } float sL = Rand.Value; FormerHumanUtilities.MakeAnimalSapient((Pawn)parent, sL, false); FormerHumanUtilities.NotifyRelatedPawnsFormerHuman((Pawn)parent, FormerHumanUtilities.RELATED_WILD_FORMER_HUMAN_LETTER, FormerHumanUtilities .RELATED_WILD_FORMER_HUMAN_LETTER_LABEL); } }
/// <summary> /// called every tick /// </summary> public override void CompTick() { base.CompTick(); if (parent.def.GetModExtension <FormerHumanSettings>()?.neverFormerHuman == true) { Log.Error($"{nameof(CompAlwaysFormerHuman)} found on {parent.def.defName} which should never be a former human!"); triggered = true; return; } if (!triggered) { triggered = true; if (Pawn.IsFormerHuman()) { return; } bool isManhunter = Pawn.MentalStateDef == MentalStateDefOf.Manhunter || Pawn.MentalStateDef == MentalStateDefOf.ManhunterPermanent; float sL = Rand.Value; FormerHumanUtilities.MakeAnimalSapient((Pawn)parent, sL, !isManhunter); FormerHumanUtilities.NotifyRelatedPawnsFormerHuman((Pawn)parent, FormerHumanUtilities.RELATED_WILD_FORMER_HUMAN_LETTER, FormerHumanUtilities .RELATED_WILD_FORMER_HUMAN_LETTER_LABEL); } }
/// <summary> /// enter the given sapience state /// </summary> /// <param name="stateDef">The state definition.</param> /// <param name="initialLevel">The initial level.</param> public void EnterState([NotNull] SapienceStateDef stateDef, float initialLevel) { _sapienceState?.Exit(); _sapienceState = stateDef.CreateState(); //need to refresh comps and needs for pawn here Pawn.needs?.AddOrRemoveNeedsAsAppropriate(); _sapienceState.Init(this); SapienceLevel = FormerHumanUtilities.GetQuantizedSapienceLevel(initialLevel); PawnComponentsUtility.AddAndRemoveDynamicComponents(Pawn); var sNeed = SapienceNeed; sNeed?.SetSapience(initialLevel); _sapienceState.Enter(); if (Pawn.Faction == Faction.OfPlayer) { Find.ColonistBar?.MarkColonistsDirty(); } //initialize work settings if they have it Pawn.workSettings?.EnableAndInitializeIfNotAlreadyInitialized(); //interrupts any jobs in case this changes their intelligence Pawn.jobs?.EndCurrentJob(JobCondition.InterruptForced); }
/// <summary> /// called after the parent thing is spawned /// </summary> /// <param name="respawningAfterLoad">if set to <c>true</c> [respawning after load].</param> public override void PostSpawnSetup(bool respawningAfterLoad) { base.PostSpawnSetup(respawningAfterLoad); if (respawningAfterLoad) { return; } RandUtilities.PushState(); if (!triggered) { triggered = true; if (CanBeFormerHuman() && Rand.RangeInclusive(0, 100) <= Props.Chance) { float sL = Rand.Value; FormerHumanUtilities.MakeAnimalSapient((Pawn)parent, sL, false); FormerHumanUtilities.NotifyRelatedPawnsFormerHuman((Pawn)parent, FormerHumanUtilities.RELATED_WILD_FORMER_HUMAN_LETTER, FormerHumanUtilities .RELATED_WILD_FORMER_HUMAN_LETTER_LABEL); _isRelatedToColonist = Pawn.IsRelatedToColonistPawn(); } } RandUtilities.PopState(); }
/// <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); }
private void MakeMergedPawn([NotNull] SapienceTracker sTracker) { if (sTracker.CurrentState != null) { return; } (Pawn p1, Pawn p2) = FormerHumanUtilities.GenerateRandomUnmergedHuman(sTracker.Pawn); CleanupPawn(p1); CleanupPawn(p2); Pawn[] tmpArr = { p1, p2 }; MergedPawnUtilities.TransferToMergedPawn(tmpArr, sTracker.Pawn); var tfPawn = new MergedPawns() { meld = sTracker.Pawn, originals = new List <Pawn> { p1, p2 } }; var gComp = Find.World.GetComponent <PawnmorphGameComp>(); gComp.AddTransformedPawn(tfPawn); //TODO figure out how relationships work for merged pawns sTracker.EnterState(SapienceStateDefOf.MergedPawn, Rand.Range(0.2f, 1)); }
private float GetInteractionWeight(Pawn initiator, Pawn recipient, Filter <PawnRelationDef> relationRestriction, bool mustBeColonist) { Pawn oHuman = FormerHumanUtilities.GetOriginalPawnOfFormerHuman(recipient); if (relationRestriction != null) //check any relationships if applicable { if (oHuman == null) { if (mustBeColonist) { return(0); //if there is no original pawn they can't be a colonist } if (!relationRestriction.isBlackList) { return (0); //if the filter is a white list a blank original pawn can't pass it because there is no relationship } return(BaseInteractionChance); } foreach (PawnRelationDef pawnRelationDef in initiator.GetRelations(oHuman)) { if (relationRestriction.PassesFilter(pawnRelationDef)) { return(BaseInteractionChance); } } return(0); //none passed } return(BaseInteractionChance); }
/// <summary> /// called after the parent thing is spawned /// </summary> /// <param name="respawningAfterLoad">if set to <c>true</c> [respawning after load].</param> public override void PostSpawnSetup(bool respawningAfterLoad) { base.PostSpawnSetup(respawningAfterLoad); if (respawningAfterLoad) { return; } if (parent.def.GetModExtension <FormerHumanSettings>()?.neverFormerHuman == true) { Log.Error($"{nameof(CompAlwaysFormerHuman)} found on {parent.def.defName} which should never be a former human!"); triggered = true; return; } if (!triggered) { triggered = true; if (Pawn.IsFormerHuman()) { return; } float sL = Rand.Value; FormerHumanUtilities.MakeAnimalSapient((Pawn)parent, sL, false); FormerHumanUtilities.NotifyRelatedPawnsFormerHuman((Pawn)parent, FormerHumanUtilities.RELATED_WILD_FORMER_HUMAN_LETTER, FormerHumanUtilities .RELATED_WILD_FORMER_HUMAN_LETTER_LABEL); } }
static void InitializeForFormerHumans([NotNull] Pawn_WorkSettings __instance, [NotNull] Pawn ___pawn) { if (___pawn.IsSapientOrFeralFormerHuman()) { FormerHumanUtilities.InitializeWorkSettingsFor(___pawn, __instance); } }
static void InitializeForFormerHumans([NotNull] Pawn_WorkSettings __instance, [NotNull] Pawn ___pawn) { if (___pawn.IsFormerHuman() && ___pawn.workSettings != null) { FormerHumanUtilities.InitializeWorkSettingsFor(___pawn, __instance); } }
/// <summary> /// called before the mental state is started /// </summary> public override void PreStart() { _prey = FormerHumanUtilities.FindRandomPreyFor(pawn); if (_prey == null) { Log.Error($"could not find prey for {pawn.Name}"); } }
private void MakePawnPermanentlyFeral(Pawn obj) { if (obj?.IsFormerHuman() != true) { return; } FormerHumanUtilities.MakePermanentlyFeral(obj); }
/// <summary> /// Makes the parent a former human. /// </summary> /// <returns></returns> public void MakeFormerHuman(float initialLevel) //TODO move most of FormerHumanUtilities.MakeAnimalSapient here { if (_isFormerHuman) { Log.Warning($"{nameof(MakeFormerHuman)} is being called on {parent.def}'s {nameof(FormerHumanTracker)} more then once!"); return; } _isFormerHuman = true; SapienceLevel = FormerHumanUtilities.GetQuantizedSapienceLevel(initialLevel); }
/// <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> /// Sets the sapience. /// </summary> /// <param name="sapience">The sapience.</param> public void SetSapience(float sapience) { _seekerLevel = Mathf.Clamp(sapience, 0, Mathf.Min(MaxLevel, Limit)); CurLevel = _seekerLevel; SapienceLevel cLevel = FormerHumanUtilities.GetQuantizedSapienceLevel(CurLevel); if (_currentLevel != cLevel) { _currentLevel = cLevel; OnSapienceLevelChanges(); } }
/// <summary> /// Exposes the data. /// </summary> public override void ExposeData() { base.ExposeData(); Scribe_Values.Look(ref _seekerLevel, nameof(_seekerLevel), -1); if (Scribe.mode == LoadSaveMode.PostLoadInit) { if (_seekerLevel < 0) { _seekerLevel = CurLevel; } _currentLevel = FormerHumanUtilities.GetQuantizedSapienceLevel(_seekerLevel); CurLevel = Mathf.Clamp(CurLevel, 0, MaxLevel); } }
/// <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; Hediff tfHumanHediff = animal?.health?.hediffSet?.GetFirstHediffOfDef(TfHediffDefOf.TransformedHuman); if (tfHumanHediff == null) { return(false); } var rFaction = transformedPawn.FactionResponsible; Log.Message($"going to spawn {transformedPawn.original.Name} {transformedPawn.original.KindLabel}"); 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); } 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 animal.Destroy(); return(true); }
/// <summary> /// Generates the things that can be sold /// </summary> /// <param name="forTile">For tile.</param> /// <param name="forFaction">For faction.</param> /// <returns></returns> public override IEnumerable <Thing> GenerateThings(int forTile, Faction forFaction = null) { var enumer = GenerateThingEnumer(forTile, forFaction).ToList(); foreach (Pawn pawn in enumer.OfType <Pawn>()) { if (!pawn.IsFormerHuman()) { continue; } FormerHumanUtilities.NotifyRelatedPawnsFormerHuman(pawn, FormerHumanUtilities.RELATED_SOLD_FORMER_HUMAN_LETTER, FormerHumanUtilities.RELATED_SOLD_FORMER_HUMAN_LETTER_LABEL); } return(enumer); }
/// <summary> /// Tries the execute worker. /// </summary> /// <param name="parms">The parms.</param> /// <returns></returns> protected override bool TryExecuteWorker(IncidentParms parms) { var map = (Map)parms.target; if (!RCellFinder.TryFindRandomPawnEntryCell(out IntVec3 result, map, CellFinder.EdgeRoadChance_Animal)) { return(false); } PawnKindDef kind = PMPawnKindDefOf.Sheep; IntVec3 loc = CellFinder.RandomClosewalkCellNear(result, map, 12); Pawn pawn = PawnGenerator.GeneratePawn(kind); GenSpawn.Spawn(pawn, loc, map, Rot4.Random); pawn.SetFaction(Faction.OfPlayer); var oPawn = GenerateGordon(pawn); FormerHumanUtilities.MakeAnimalSapient(oPawn, pawn); if (pawn.story != null) { pawn.story.adulthood = PMBackstoryDefOf.PM_SheepChef.backstory; } if (pawn.skills != null) { var record = pawn.skills.GetSkill(SkillDefOf.Cooking); record.passion = Passion.Major; record.Level = Mathf.Max(5, record.Level); } SendStandardLetter("PMSheepChefLetterLabel".Translate(kind.label).CapitalizeFirst(), "PMSheepChefLetter".Translate(kind.label), LetterDefOf.PositiveEvent, parms, new TargetInfo(result, map)); var wComp = Find.World.GetComponent <PawnmorphGameComp>(); wComp.sheepChefEventFired = true; var pm = TfSys.TransformedPawn.Create(oPawn, pawn); Find.World.GetComponent <PawnmorphGameComp>().AddTransformedPawn(pm); return(true); }
static IEnumerable <Toil> Postfix(IEnumerable <Toil> values, [NotNull] JobDriver_PredatorHunt __instance) { foreach (Toil toil in values) { yield return(toil); } if (!__instance.pawn.IsSapientOrFeralFormerHuman()) { yield break; } yield return(Toils_General.Do(() => { FormerHumanUtilities.GiveSapientAnimalHuntingThought(__instance.pawn, __instance.Prey); })); }
static void MakeAnimalSapientFormerHuman(Pawn pawn) { if (pawn == null) { return; } if (pawn.IsFormerHuman()) { return; } if (!pawn.RaceProps.Animal) { return; } FormerHumanUtilities.MakeAnimalSapient(pawn); }
static void MakeAnimalFormerHuman(Pawn pawn) { if (pawn == null) { return; } if (pawn.GetSapienceState() != null) { return; } if (!pawn.RaceProps.Animal) { return; } FormerHumanUtilities.MakeAnimalSapient(pawn, Rand.Range(0.1f, 1f)); }
void TryStartRandomHunt(Pawn pawn) { if (!pawn.RaceProps.predator) { return; } var prey = FormerHumanUtilities.FindRandomPreyFor(pawn); if (prey == null) { return; } var job = new Job(JobDefOf.PredatorHunt, prey) { killIncappedTarget = true }; pawn.jobs?.StartJob(job, JobCondition.InterruptForced); }
/// <summary>Adds the hediff if not permanently feral.</summary> /// <param name="pawn">The pawn.</param> /// <param name="hediff">The hediff.</param> public static void AddHediffIfNotPermanentlyFeral(Pawn pawn, HediffDef hediff) { if (!pawn.health.hediffSet.HasHediff(HediffDef.Named("PermanentlyFeral")) && !pawn.health.hediffSet.HasHediff(hediff)) // If a pawn does not have the PermanentlyFeral hediff nor the provided hediff... { Hediff xhediff = HediffMaker.MakeHediff(hediff, pawn); // ...create an initialized version of the provided hediff... xhediff.Severity = Rand.Range(0.00f, 1.00f); // ...set it to a random severity... pawn.health.AddHediff(xhediff); // ...then apply it.. PawnComponentsUtility.AddAndRemoveDynamicComponents(pawn); //make sure they have all the dynamic comps they need //make sure it has a name if (pawn.Name == null) { pawn.Name = new NameSingle(pawn.LabelShort); } FormerHumanUtilities.TryAssignBackstoryToTransformedPawn(pawn, null); //try to assign them a background if they're sapient } }
/// <summary> /// called every tick /// </summary> public override void CompTick() { base.CompTick(); if (!triggered) { triggered = true; if (CanBeFormerHuman() && Rand.RangeInclusive(0, 100) <= Props.Chance) { float sL = Rand.Value; FormerHumanUtilities.MakeAnimalSapient((Pawn)parent, sL); FormerHumanUtilities.NotifyRelatedPawnsFormerHuman((Pawn)parent, FormerHumanUtilities.RELATED_WILD_FORMER_HUMAN_LETTER, FormerHumanUtilities .RELATED_WILD_FORMER_HUMAN_LETTER_LABEL); _isRelatedToColonist = Pawn.IsRelatedToColonistPawn(); } } }
/// <summary> /// called every so often by the need manager. /// </summary> /// <exception cref="System.NotImplementedException"></exception> public override void NeedInterval() { base.NeedInterval(); if (pawn.IsHashIntervalTick(TimeMetrics.TICKS_PER_REAL_SECOND)) //just every second or so { TrySubscribe(); CalculateCachesIfNeeded(); _seekerLevel = Mathf.Min(_seekerLevel, Limit); float instinctChange = GetInstinctChangePerTick(pawn) * TimeMetrics.TICKS_PER_REAL_SECOND; if (Mathf.Abs(instinctChange) > EPSILON) { AddInstinctChange(instinctChange); } //_maxLevelCached = null; SapienceLevel sLevel = FormerHumanUtilities.GetQuantizedSapienceLevel(CurLevel); if (sLevel != _currentLevel) { _currentLevel = sLevel; OnSapienceLevelChanges(); } } }
/// <summary> /// called every so often by the need manager. /// </summary> /// <exception cref="System.NotImplementedException"></exception> public override void NeedInterval() { base.NeedInterval(); if (pawn.IsHashIntervalTick(TimeMetrics.TICKS_PER_REAL_SECOND)) //just every second or so { float instinctChange = GetInstinctChangePerTick(pawn) * TimeMetrics.TICKS_PER_REAL_SECOND; if (Mathf.Abs(instinctChange) > EPSILON) { AddInstinctChange(Mathf.CeilToInt(instinctChange)); } _maxLevelCached = null; SapienceLevel sLevel = FormerHumanUtilities.GetQuantizedSapienceLevel(CurLevel); if (sLevel != _currentLevel) { _currentLevel = sLevel; OnSapienceLevelChanges(); } if (_currentLevel == SapienceLevel.Feral && Rand.MTBEventOccurs(4, 60000f, 30f)) { TriggerPermanentlyFeralChange(); } } }
internal void MakePermanentlyFeral() { Hediff fHediff; if (StateDef.forcedHediff != null) { fHediff = Pawn.health.hediffSet.GetFirstHediffOfDef(StateDef.forcedHediff); } else { fHediff = null; } //transfer relationships back if possible var gComp = Find.World.GetComponent <PawnmorphGameComp>(); Pawn oPawn = gComp.GetTransformedPawnContaining(Pawn)?.Item1?.OriginalPawns.FirstOrDefault(); if (oPawn == Pawn) { oPawn = null; } Pawn_RelationsTracker aRelations = Pawn.relations; if (aRelations != null && oPawn != null) { FormerHumanUtilities.TransferRelationsToOriginal(oPawn, Pawn); } Pawn.health.AddHediff(TfHediffDefOf.PermanentlyFeral); if (fHediff != null) { Pawn.health.RemoveHediff(fHediff); } var loader = Find.World.GetComponent <PawnmorphGameComp>(); TransformedPawn inst = loader.GetTransformedPawnContaining(Pawn)?.Item1; var singleInst = inst as TransformedPawnSingle; //hacky, need to come up with a better solution foreach (Pawn instOriginalPawn in inst?.OriginalPawns ?? Enumerable.Empty <Pawn>() ) //needed to handle merges correctly { ReactionsHelper.OnPawnPermFeral(instOriginalPawn, Pawn, singleInst?.reactionStatus ?? FormerHumanReactionStatus.Wild); } //remove the original and destroy the pawns foreach (Pawn instOriginalPawn in inst?.OriginalPawns ?? Enumerable.Empty <Pawn>()) { instOriginalPawn.Destroy(); } if (inst != null) { loader.RemoveInstance(inst); } if (inst != null || Pawn.Faction == Faction.OfPlayer) { Find.LetterStack.ReceiveLetter("LetterHediffFromPermanentTFLabel".Translate(Pawn.LabelShort).CapitalizeFirst(), "LetterHediffFromPermanentTF".Translate(Pawn.LabelShort).CapitalizeFirst(), LetterDefOf.NegativeEvent, Pawn); } Pawn.needs?.AddOrRemoveNeedsAsAppropriate(); //make sure any comps get added/removed as appropriate PawnComponentsUtility.AddAndRemoveDynamicComponents(Pawn); }
/// <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); }
IEnumerable <Thing> GenerateThingEnumer(int forTile, Faction forFaction) { int numKinds = kindCountRange.RandomInRange; int count = countRange.RandomInRange; List <PawnKindDef> kinds = new List <PawnKindDef>(); for (int j = 0; j < numKinds; j++) { if (!(from k in DefDatabase <PawnKindDef> .AllDefs where !kinds.Contains(k) && PawnKindAllowed(k, forTile) select k).TryRandomElementByWeight((PawnKindDef k) => SelectionChance(k), out PawnKindDef result)) { break; } kinds.Add(result); } for (int i = 0; i < count; i++) { if (!kinds.TryRandomElement(out PawnKindDef kind)) { break; } PawnKindDef kind2 = kind; int tile = forTile; Pawn pawnOriginal = Find.WorldPawns.AllPawnsAlive.Where(p => !p.IsPlayerControlledCaravanMember() && (PawnUtility.ForSaleBySettlement(p) || p.kindDef == PawnKindDefOf.Slave || (PawnUtility.IsKidnappedPawn(p) && p.RaceProps.Humanlike) && !PawnUtility.IsFactionLeader(p))).RandomElement(); PawnGenerationRequest request = new PawnGenerationRequest(kind2, null, PawnGenerationContext.NonPlayer, tile); Pawn pawn = PawnGenerator.GeneratePawn(request); //Generate the animal! if (pawnOriginal == null) { Gender newGender = pawn.gender; if (Rand.RangeInclusive(0, 100) <= 25) { switch (pawn.gender) { case (Gender.Male): newGender = Gender.Female; break; case (Gender.Female): newGender = Gender.Male; break; default: break; } } float animalAge = pawn.ageTracker.AgeBiologicalYearsFloat; float animalLifeExpectancy = pawn.def.race.lifeExpectancy; float humanLifeExpectancy = 80f; float age = animalAge * humanLifeExpectancy / animalLifeExpectancy; age = Mathf.Max(age, 17); //make sure the human is at least 17 years old float chronoAge = pawn.ageTracker.AgeChronologicalYears * age / animalAge; var pkds = new List <PawnKindDef> { PawnKindDefOf.Slave, PawnKindDefOf.Colonist, PawnKindDefOf.SpaceRefugee, PawnKindDefOf.Villager, PawnKindDefOf.Drifter, PawnKindDefOf.AncientSoldier }; PawnKindDef rKind = pkds.RandElement(); var hRequest = new PawnGenerationRequest(rKind, Faction.OfPlayer, PawnGenerationContext.NonPlayer, fixedBiologicalAge: age, fixedChronologicalAge: chronoAge, fixedGender: newGender); pawnOriginal = PawnGenerator.GeneratePawn(hRequest); pawn.Name = pawnOriginal.Name; } else { pawn.Name = pawnOriginal.Name; Find.WorldPawns.RemovePawn(pawnOriginal); } var pm = TfSys.TransformedPawn.Create(pawnOriginal, pawn); //pawnOriginal is human, pawn is animal FormerHumanUtilities.MakeAnimalSapient(pawnOriginal, pawn, Rand.Range(0.5f, 1f)); Find.World.GetComponent <PawnmorphGameComp>().AddTransformedPawn(pm); yield return(pawn); } }