code:
using System.Collections.Generic;
using RimWorld;
using UnityEngine;
using Verse;
using System;
using Multiplayer.API;
using System.Linq;

namespace rjw
{
	public static class Nymph_Generator
	{
		/// <summary>
		/// Returns true if the given pawnGenerationRequest is for a nymph pawnKind.
		/// </summary>
		public static bool IsNymph(PawnGenerationRequest pawnGenerationRequest)
		{
			return pawnGenerationRequest.KindDef != null && pawnGenerationRequest.KindDef.defName.Contains("Nymph");
		}

		private static bool is_trait_conflicting_or_duplicate(Pawn pawn, Trait t)
		{
			foreach (var existing in pawn.story.traits.allTraits)
				if ((existing.def == t.def) || (t.def.ConflictsWith(existing)))
					return true;
			return false;
		}

		public static bool IsNymphBodyType(Pawn pawn)
		{
			return pawn.story.bodyType == BodyTypeDefOf.Female || pawn.story.bodyType == BodyTypeDefOf.Thin;
		}

		[SyncMethod]
		public static Gender RandomNymphGender()
		{
			//with males 100% its still 99%, coz im  to lazy to fix it
			//float rnd = Rand.Value;
			//Rand.PopState();
			//Rand.PushState(RJW_Multiplayer.PredictableSeed());
			float chance = RJWSettings.male_nymph_chance;

			Gender Pawngender = Rand.Chance(chance) ? Gender.Male: Gender.Female;
			//ModLog.Message(" setnymphsex: " + (rnd < chance) + " rnd:" + rnd + " chance:" + chance);
			//ModLog.Message(" setnymphsex: " + Pawngender);
			return Pawngender;
		}

		/// <summary>
		/// Replaces a pawn's randomly generated backstory and traits to turn it into propper a nymph
		/// </summary>
		[SyncMethod]
		public static void set_story(Pawn pawn)
		{
			//C# rjw story
			nymph_backstories.generate(pawn);

			//The mod More Trait Slots will adjust the max number of traits pawn can get, and therefore,
			//I need to collect pawns' traits and assign other_traits back to the pawn after adding the nymph_story traits.

			//backup generated + rjw traits
			Stack<Trait> other_traits = new Stack<Trait>();
			int numberOfTotalTraits = 0;
			if (!pawn.story.traits.allTraits.NullOrEmpty())
			{
				foreach (Trait t in pawn.story.traits.allTraits)
				{
					other_traits.Push(t);
					++numberOfTotalTraits;
				}
			}
			pawn.story.traits.allTraits.Clear();

			//xml nymph story forced traits
			var trait_count = 0;
			foreach (var t in pawn.story.Adulthood.forcedTraits)
			{
				pawn.story.traits.GainTrait(new Trait(t.def, t.degree));
				++trait_count;
			}

			//xml story + rjw backup + w/e generator generated backup
			while (trait_count < numberOfTotalTraits)
			{
				Trait t = other_traits.Pop();
				if (!is_trait_conflicting_or_duplicate(pawn, t))
					pawn.story.traits.GainTrait(t);
				++trait_count;
			}

			// add broken body hediff to broken nymph
			if (pawn.story.Adulthood.defName.Contains("broken"))
			{
				pawn.health.AddHediff(xxx.feelingBroken);
				(pawn.health.hediffSet.GetFirstHediffOfDef(xxx.feelingBroken)).Severity = Rand.Range(0.4f, 1.0f);
			}

			//reset disabled skills/works
			pawn.skills.Notify_SkillDisablesChanged();
			pawn.Notify_DisabledWorkTypesChanged();
		}

		[SyncMethod]
		private static int sum_previous_gains(SkillDef def, Pawn_StoryTracker sto, Pawn_AgeTracker age)
		{
			int total_gain = 0;
			SkillGain gain;

			// Gains from backstories
			if((gain = sto.Childhood.skillGains.FirstOrDefault((SkillGain skillGain) => skillGain.skill == def )) != null)
				total_gain += gain.amount;
			if ((gain = sto.Adulthood.skillGains.FirstOrDefault((SkillGain skillGain) => skillGain.skill == def)) != null)
				total_gain += gain.amount;

			// Gains from traits
			foreach (var trait in sto.traits.allTraits)
				if ((gain = trait.CurrentData.skillGains.FirstOrDefault((SkillGain skillGain) => skillGain.skill == def)) != null)
					total_gain += gain.amount;

			// Gains from age
			//Rand.PopState();
			//Rand.PushState(RJW_Multiplayer.PredictableSeed());
			var rgain = Rand.Value * (float)total_gain * 0.35f;
			var age_factor = Mathf.Clamp01((age.AgeBiologicalYearsFloat - 17.0f) / 10.0f); // Assume nymphs are 17~27
			total_gain += (int)(age_factor * rgain);

			return Mathf.Clamp(total_gain, 0, 20);
		}

		/// <summary>
		/// Set a nymph's initial skills & passions from backstory, traits, and age
		/// </summary>
		[SyncMethod]
		public static void set_skills(Pawn pawn)
		{
			foreach (var skill_def in DefDatabase<SkillDef>.AllDefsListForReading)
			{
				var rec = pawn.skills.GetSkill(skill_def);
				if (!rec.TotallyDisabled)
				{
					//Rand.PopState();
					//Rand.PushState(RJW_Multiplayer.PredictableSeed());
					rec.Level = sum_previous_gains(skill_def, pawn.story, pawn.ageTracker);
					rec.xpSinceLastLevel = rec.XpRequiredForLevelUp * Rand.Range(0.10f, 0.90f);

					var pas_cha = nymph_backstories.get_passion_chances(pawn.story.Childhood, pawn.story.Adulthood, skill_def);
					var rv = Rand.Value;
					if (rv < pas_cha.major) rec.passion = Passion.Major;
					else if (rv < pas_cha.minor) rec.passion = Passion.Minor;
					else rec.passion = Passion.None;
				}
				else
					rec.passion = Passion.None;
			}
		}

		[SyncMethod]
		public static PawnKindDef GetFixedNymphPawnKindDef()
		{
			var def = DefDatabase<PawnKindDef>.AllDefs.Where(x => x.defName.Contains("Nymph")).RandomElement();
			//var def = PawnKindDef.Named("Nymph");
			// This is 18 in the xml but something is overwriting it to 5.
			//def.minGenerationAge = 18;
			return def;
		}

		[SyncMethod]
		public static Pawn GenerateNymph(Faction faction = null)
		{
			// Most of the special properties of nymphs are in harmony patches to PawnGenerator.
			PawnGenerationRequest request = new PawnGenerationRequest(
				kind: GetFixedNymphPawnKindDef(),
				faction: faction,
				forceGenerateNewPawn: true,
				canGeneratePawnRelations: true,
				colonistRelationChanceFactor: 0.0f,
				relationWithExtraPawnChanceFactor: 0
				);

			//Rand.PopState();
			//Rand.PushState(RJW_Multiplayer.PredictableSeed());
			Pawn pawn = PawnGenerator.GeneratePawn(request);
			//Log.Message(""+ pawn.Faction);
			//IntVec3 spawn_loc = CellFinder.RandomClosewalkCellNear(around_loc, map, 6);//RandomSpawnCellForPawnNear could be an alternative
			//GenSpawn.Spawn(pawn, spawn_loc, map);
			return pawn;
		}
	}
}


code:
//using System;
//using RimWorld;
//using Verse;

//namespace rjw
//{
//	public class BackstoryDef : Def
//	{
//		public BackstoryDef()
//		{
//			this.slot = BackstorySlot.Childhood;
//		}

//		public static BackstoryDef Named(string defName)
//		{
//			return DefDatabase<BackstoryDef>.GetNamed(defName, true);
//		}

//		public override void ResolveReferences()
//		{
//			base.ResolveReferences();
//			if (BackstoryDatabase.allBackstories.ContainsKey(this.defName))
//			{
//				ModLog.Error("BackstoryDatabase already contains: " + this.defName);
//				return;
//			}
//			{
//				//Log.Warning("BackstoryDatabase does not contains: " + this.defName);
//			}
//			if (!this.title.NullOrEmpty())
//			{
//				Backstory backstory = new Backstory();
//				backstory.SetTitle(this.title, this.titleFemale);
//				backstory.SetTitleShort(this.titleShort, this.titleFemaleShort);
//				backstory.baseDesc = this.baseDescription;
//				backstory.slot = this.slot;
//				backstory.spawnCategories.Add(this.categoryName);
//				backstory.ResolveReferences();
//				backstory.PostLoad();
//				backstory.identifier = this.defName;
//				BackstoryDatabase.allBackstories.Add(backstory.identifier, backstory);
//				//Log.Warning("BackstoryDatabase added: " + backstory.identifier);
//				//Log.Warning("BackstoryDatabase added: " + backstory.spawnCategories.ToCommaList());
//			}
//		}

//		public string baseDescription;

//		public string title;

//		public string titleShort;

//		public string titleFemale;

//		public string titleFemaleShort;

//		public string categoryName;

//		public BackstorySlot slot;
//	}
//}

repo_name: Euclidean/rjw

license: mit


code:
using System.Collections.Generic;
using Verse;
using Multiplayer.API;
using RimWorld;

namespace rjw
{
	//MicroComputer
	internal class Hediff_MicroComputer : Hediff_MechImplants
	{
		protected int nextEventTick = GenDate.TicksPerDay;

		public override void ExposeData()
		{
			base.ExposeData();
			Scribe_Values.Look<int>(ref this.nextEventTick, "nextEventTick", GenDate.TicksPerDay, false);
		}

		[SyncMethod]
		public override void PostMake()
		{
			base.PostMake();
			//Rand.PopState();
			//Rand.PushState(RJW_Multiplayer.PredictableSeed());
			nextEventTick = Rand.Range(mcDef.minEventInterval, mcDef.maxEventInterval);
		}

		[SyncMethod]
		public override void Tick()
		{
			base.Tick();
			if (this.pawn.IsHashIntervalTick(1000))
			{
				if (this.ageTicks >= nextEventTick)
				{
					HediffDef randomEffectDef = DefDatabase<HediffDef>.GetNamed(randomEffect);
					if (randomEffectDef != null)
					{
						pawn.health.AddHediff(randomEffectDef);
					}
					else
					{
						//--ModLog.Message("" + this.GetType().ToString() + "::Tick() - There is no Random Effect");
					}
					this.ageTicks = 0;
				}
			}
		}

		protected HediffDef_MechImplants mcDef
		{
			get
			{
				return ((HediffDef_MechImplants)def);
			}
		}

		protected List<string> randomEffects
		{
			get
			{
				return mcDef.randomHediffDefs;
			}
		}

		protected string randomEffect
		{
			get
			{
				//Rand.PopState();
				//Rand.PushState(RJW_Multiplayer.PredictableSeed());
				return randomEffects.RandomElement<string>();
			}
		}
	}
}


code:
#nullable enable

using System.Collections.Generic;
using Verse;

namespace rjw
{
	[StaticConstructorOnStartup]
	public class HediffDef_EnemyImplants : HediffDef
	{
		//single parent eggs
		public string parentDef = "";
		//multiparent eggs
		public List<string> parentDefs = new();

		//for implanting eggs
		public bool CanHaveParent(string defName)
		{
			// Predefined parent eggs.
			if (parentDef == defName) return true;
			if (parentDefs.Contains(defName)) return true;
			// Dynamic egg.
			return RJWPregnancySettings.egg_pregnancy_implant_anyone;
		}
	}

	[StaticConstructorOnStartup]
	public class HediffDef_InsectEgg : HediffDef_EnemyImplants
	{
		//this is filled from xml
		//1 day = 60000 ticks
		public float eggsize = 1;
		public bool selffertilized = false;

		public List<string> childrenDefs = new();
		public string? UnFertEggDef = null;
		public string? FertEggDef = null;
	}

	[StaticConstructorOnStartup]
	public class HediffDef_MechImplants : HediffDef_EnemyImplants
	{
		public List<string> randomHediffDefs = new();
		public int minEventInterval = 30000;
		public int maxEventInterval = 90000;

		public List<string> childrenDefs = new();
	}
}


code:
using System;
using System.Collections.Generic;
using RimWorld;
using Verse;
using UnityEngine;
using System.Text;
using Multiplayer.API;
using System.Linq;
using RimWorld.Planet;
using static rjw.PregnancyHelper;

namespace rjw
{
	public abstract class Hediff_BasePregnancy : HediffWithComps
	//public abstract class Hediff_BasePregnancy : HediffWithParents
	{
		///<summary>
		///This hediff class simulates pregnancy.
		///</summary>

		//Static fields
		private const int MiscarryCheckInterval = 1000;

		protected const string starvationMessage = "MessageMiscarriedStarvation";
		protected const string poorHealthMessage = "MessageMiscarriedPoorHealth";

		protected static readonly HashSet<string> non_genetic_traits = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("NonInheritedTraits").strings);

		//Fields
		///All babies should be premade and stored here
		public List<Pawn> babies;
		///Reference to daddy, goes null sometimes
		public Pawn father;
		///Is pregnancy visible?
		public bool is_discovered = false;
		public bool is_parent_known = false;
		public bool ShouldMiscarry = false;
		public bool ImmortalMiscarry = false;
		///Is pregnancy type checked?
		public bool is_checked = false;
		///Mechanoid pregnancy, false - spawn aggressive mech
		public bool is_hacked = false;
		///Contractions duration, effectively additional hediff stage, a dirty hack to make birthing process notable
		public int contractions;
		///Gestation progress
		public float p_start_tick = 0;
		public float p_end_tick = 0;
		public float lastTick = 0;
		public GeneSet geneSet = null;
		//public string last_name
		//{
		//	get
		//	{
		//		string last_name = "";
		//		if (xxx.is_human(father))
		//			last_name = NameTriple.FromString(father.Name.ToStringFull).Last;
		//		else if (xxx.is_human(pawn))
		//			last_name = NameTriple.FromString(pawn.Name.ToStringFull).Last;
		//		return last_name;
		//	}
		//}

		//public float skin_whiteness
		//{
		//	get
		//	{
		//		float skin_whiteness = Rand.Range(0, 1);
		//		if (xxx.has_traits(pawn) && pawn.RaceProps.Humanlike)
		//		{
		//			skin_whiteness = pawn.story.melanin;
		//		}
		//		if (father != null && xxx.has_traits(father) && father.RaceProps.Humanlike)
		//		{
		//			skin_whiteness = Rand.Range(skin_whiteness, father.story.melanin);
		//		}
		//		return skin_whiteness;
		//	}
		//}

		//public List<Trait> traitpool
		//{
		//	get
		//	{
		//		List<Trait> traitpool = new List<Trait>();
		//		if (xxx.has_traits(pawn) && pawn.RaceProps.Humanlike)
		//		{
		//			foreach (Trait momtrait in pawn.story.traits.allTraits)
		//			{
		//				if (!RJWPregnancySettings.trait_filtering_enabled || !non_genetic_traits.Contains(momtrait.def.defName))
		//					traitpool.Add(momtrait);
		//			}
		//		}
		//		if (father != null && xxx.has_traits(father) && father.RaceProps.Humanlike)
		//		{
		//			foreach (Trait poptrait in father.story.traits.allTraits)
		//			{
		//				if (!RJWPregnancySettings.trait_filtering_enabled || !non_genetic_traits.Contains(poptrait.def.defName))
		//					traitpool.Add(poptrait);
		//			}
		//		}
		//		return traitpool;
		//	}
		//}

		//
		// Properties
		//
		public float GestationProgress
		{
			get => Severity;
			private set => Severity = value;
		}

		private bool IsSeverelyWounded
		{
			get
			{
				float num = 0;
				List<Hediff> hediffs = pawn.health.hediffSet.hediffs;
				foreach (Hediff h in hediffs)
				{
					//this errors somewhy,
					//ModLog.Message(" 1 " + h.Part.IsCorePart);
					//ModLog.Message(" 2 " + h.Part.parent.IsCorePart);
					//if (h.Part.IsCorePart || h.Part.parent.IsCorePart)
					if (h is Hediff_Injury && (!h.IsPermanent() || !h.IsTended()))
					{
						if (h.Part != null)
							if (h.Part.IsCorePart || h.Part.parent.IsCorePart)
								num += h.Severity;
					}
				}
				List<Hediff_MissingPart> missingPartsCommonAncestors = pawn.health.hediffSet.GetMissingPartsCommonAncestors();
				foreach (Hediff_MissingPart mp in missingPartsCommonAncestors)
				{
					if (mp.IsFreshNonSolidExtremity)
					{
						if (mp.Part != null)
							if (mp.Part.IsCorePart || mp.Part.parent.IsCorePart)
								num += mp.Part.def.GetMaxHealth(pawn);
					}
				}
				return num > 38 * pawn.RaceProps.baseHealthScale;
			}
		}

		/// <summary>
		/// Indicates pregnancy can be aborted using usual means.
		/// </summary>
		public virtual bool canBeAborted
		{
			get
			{
				return true;
			}
		}

		/// <summary>
		/// Indicates pregnancy can be miscarried.
		/// </summary>
		public virtual bool canMiscarry
		{
			get
			{
				return true;
			}
		}

		public override string TipStringExtra
		{
			get
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.Append(base.TipStringExtra);
				if(is_parent_known)
					stringBuilder.AppendLine("Father: " + xxx.get_pawnname(father));
				else
					stringBuilder.AppendLine("Father: " + "Unknown");

				return stringBuilder.ToString();
			}
		}

		/// <summary>
		/// do not merge pregnancies
		/// </summary>
		//public override bool TryMergeWith(Hediff other)
		//{
		//	return false;
		//}

		public override void PostMake()
		{
			// Ensure the hediff always applies to the torso, regardless of incorrect directive
			base.PostMake();
			BodyPartRecord torso = pawn.RaceProps.body.AllParts.Find(x => x.def.defName == "Torso");
			if (Part != torso)
				Part = torso;

			//(debug->add heddif)
			//init empty preg, instabirth, cause error during birthing
			//Initialize(pawn, Trytogetfather(ref pawn));
		}

		public override bool Visible => is_discovered;

		public virtual void DiscoverPregnancy()
		{
			is_discovered = true;
			if (PawnUtility.ShouldSendNotificationAbout(this.pawn) && (RJWPregnancySettings.animal_pregnancy_notifications_enabled || !this.pawn.IsAnimal()))
			{
				if (!is_checked)
				{
					string key1 = "RJW_PregnantTitle";
					string message_title = TranslatorFormattedStringExtensions.Translate(key1, pawn.LabelIndefinite()).CapitalizeFirst();
					string key2 = "RJW_PregnantText";

					string message_text = TranslatorFormattedStringExtensions.Translate(key2, pawn.LabelIndefinite()).CapitalizeFirst();
					Find.LetterStack.ReceiveLetter(message_title, message_text, LetterDefOf.NeutralEvent, pawn, null);

				}
				else
				{
					PregnancyMessage();
				}
			}
		}

		public virtual void CheckPregnancy()
		{
			is_checked = true;
			if (!is_discovered)
				DiscoverPregnancy();
			else
				PregnancyMessage();
		}

		public virtual void PregnancyMessage()
		{
			string key1 = "RJW_PregnantTitle";
			string message_title = TranslatorFormattedStringExtensions.Translate(key1, pawn.LabelIndefinite());
			string key2 = "RJW_PregnantNormal";
			string message_text = TranslatorFormattedStringExtensions.Translate(key2, pawn.LabelIndefinite());
			Find.LetterStack.ReceiveLetter(message_title, message_text, LetterDefOf.NeutralEvent, pawn, null);
		}

		// Quick method to simply return a body part instance by a given part name
		internal static BodyPartRecord GetPawnBodyPart(Pawn pawn, String bodyPart)
		{
			return pawn.RaceProps.body.AllParts.Find(x => x.def == DefDatabase<BodyPartDef>.GetNamed(bodyPart));
		}

		public virtual void Miscarry()
		{
			if (!babies.NullOrEmpty())
				foreach (Pawn baby in babies)
				{
					baby.Destroy();
					baby.Discard();
				}
			pawn.health?.RemoveHediff(this);
		}

		/// <summary>
		/// Called on abortion (noy implemented yet)
		/// </summary>
		public virtual void Abort()
		{
			Miscarry();
		}

		/// <summary>
		/// Mechanoids can remove pregnancy
		/// </summary>
		public virtual void Kill()
		{
			Miscarry();
		}

		[SyncMethod]
		public Pawn partstospawn(Pawn baby, Pawn mother, Pawn dad)
		{
			//decide what parts to inherit
			//default use own parts
			Pawn partstospawn = baby;
			//Rand.PopState();
			//Rand.PushState(RJW_Multiplayer.PredictableSeed());
			//spawn with mother parts
			if (mother != null && Rand.Range(0, 100) <= 10)
				partstospawn = mother;
			//spawn with father parts
			if (dad != null && Rand.Range(0, 100) <= 10)
				partstospawn = dad;

			//ModLog.Message(" Pregnancy partstospawn " + partstospawn);
			return partstospawn;
		}

		[SyncMethod]
		public bool spawnfutachild(Pawn baby, Pawn mother, Pawn dad)
		{
			int futachance = 0;
			if (mother != null && Genital_Helper.is_futa(mother))
				futachance = futachance + 25;
			if (dad != null && Genital_Helper.is_futa(dad))
				futachance = futachance + 25;

			//ModLog.Message(" Pregnancy spawnfutachild " + futachance);
			//Rand.PopState();
			//Rand.PushState(RJW_Multiplayer.PredictableSeed());
			//theres 1% change baby will be futa
			//bug ... or ... feature ... nature finds a way
			return (Rand.Range(0, 100) <= futachance);
		}

		[SyncMethod]
		public static Pawn Trytogetfather(ref Pawn mother)
		{
			//birthing with debug has no father
			//Postmake.initialize() has no father
			ModLog.Warning("Hediff_BasePregnancy::Trytogetfather() - debug? no father defined, trying to add one");

			Pawn pawn = mother;
			Pawn father = null;

			//possible fathers
			List<Pawn> partners = pawn.relations.RelatedPawns.Where(x =>
					Genital_Helper.has_penis_fertile(x) && !x.Dead &&
					(pawn.relations.DirectRelationExists(PawnRelationDefOf.Lover, x) ||
					pawn.relations.DirectRelationExists(PawnRelationDefOf.Fiance, x) ||
					pawn.relations.DirectRelationExists(PawnRelationDefOf.Spouse, x))
					).ToList();

			//add bonded animal
			if (RJWSettings.bestiality_enabled && xxx.is_zoophile(mother))
				partners.AddRange(pawn.relations.RelatedPawns.Where(x =>
					Genital_Helper.has_penis_fertile(x) &&
					pawn.relations.DirectRelationExists(PawnRelationDefOf.Bond, x)).ToList());

			if (partners.Any())
			{
				father = partners.RandomElement();
				ModLog.Warning("Hediff_BasePregnancy::Trytogetfather() - father set to: " + xxx.get_pawnname(father));
			}

			if (father == null)
			{
				father = mother;
				ModLog.Warning("Hediff_BasePregnancy::Trytogetfather() - father is null, set to: " + xxx.get_pawnname(mother));
			}
			return father;
		}

		public override void Tick()
		{
			ageTicks++;
			float thisTick = Find.TickManager.TicksGame;
			GestationProgress = (1 + thisTick - p_start_tick) / (p_end_tick - p_start_tick);

			if ((thisTick - lastTick) >= 1000)
			{
				if (babies.NullOrEmpty())
				{
					ModLog.Warning(" no babies (debug?) " + this.GetType().Name);
					if (father == null)
					{
						father = Trytogetfather(ref pawn);
					}
					Initialize(pawn, father, SelectDnaGivingParent(pawn, father));
					GestationProgress = (1 + thisTick - p_start_tick) / (p_end_tick - p_start_tick);
					return;
				}
				lastTick = thisTick;
				if (canMiscarry)
				{
					//miscarry with immortal partners
					if (ImmortalMiscarry)
					{
						if (RJWSettings.DevMode) ModLog.Message($"{this} parent(s) immortal, cancel pregnancy");
						Miscarry();
						return;
					}
					//ModLog.Message(" Pregnancy is ticking for " + pawn + " this is " + this.def.defName + " will end in " + 1/progress_per_tick/TicksPerDay + " days resulting in "+ babies[0].def.defName);
					if (!Find.Storyteller.difficulty.babiesAreHealthy)
					{
						//miscarry after starving
						if (pawn.needs.food != null && pawn.needs.food.CurCategory == HungerCategory.Starving)
						{
							var hed = pawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.Malnutrition);
							if (hed != null)
								if (hed.Severity > 0.4)
								{
									if (Visible && PawnUtility.ShouldSendNotificationAbout(pawn))
									{
										string text = "MessageMiscarriedStarvation".Translate(pawn.LabelIndefinite()).CapitalizeFirst();
										Messages.Message(text, pawn, MessageTypeDefOf.NegativeHealthEvent);
									}
									Miscarry();
									return;
								}
						}
						//let beatings only be important when pregnancy is developed somewhat
						//miscarry after SeverelyWounded
						if (Visible && (IsSeverelyWounded || ShouldMiscarry))
						{
							if (Visible && PawnUtility.ShouldSendNotificationAbout(pawn))
							{
								string text = "MessageMiscarriedPoorHealth".Translate(pawn.LabelIndefinite()).CapitalizeFirst();
								Messages.Message(text, pawn, MessageTypeDefOf.NegativeHealthEvent);
							}
							Miscarry();
							return;
						}

					}
				}

				// Check if pregnancy is far enough along to "show" for the body type
				if (!is_discovered)
				{
					BodyTypeDef bodyT = pawn?.story?.bodyType;
					//float threshold = 0f;

					if ((bodyT == BodyTypeDefOf.Thin && GestationProgress > 0.25f) ||
						(bodyT == BodyTypeDefOf.Female && GestationProgress > 0.35f) ||
						(GestationProgress > 0.50f)) // todo: Modded bodies? (FemaleBB for, example)
						DiscoverPregnancy();

					//switch (bodyT)
					//{
					//case BodyType.Thin: threshold = 0.3f; break;
					//case BodyType.Female: threshold = 0.389f; break;
					//case BodyType.Male: threshold = 0.41f; break;
					//default: threshold = 0.5f; break;
					//}
					//if (GestationProgress > threshold){ DiscoverPregnancy(); }
				}

				if (CurStageIndex == 3)
				{
					if (contractions == 0)
					{
						if (PawnUtility.ShouldSendNotificationAbout(pawn) && (RJWPregnancySettings.animal_pregnancy_notifications_enabled || !this.pawn.IsAnimal()))
						{
							string text = "RJW_Contractions".Translate(pawn.LabelIndefinite());
							Messages.Message(text, pawn, MessageTypeDefOf.NeutralEvent);
						}
						contractions++;
					}
					if (GestationProgress >= 1 && (pawn.CarriedBy == null || pawn.CarriedByCaravan()))//birthing takes an hour
					{
						if (PawnUtility.ShouldSendNotificationAbout(pawn) && (RJWPregnancySettings.animal_pregnancy_notifications_enabled || !this.pawn.IsAnimal()))
						{
							string message_title = "RJW_GaveBirthTitle".Translate(pawn.LabelIndefinite()).CapitalizeFirst();
							string message_text = "RJW_GaveBirthText".Translate(pawn.LabelIndefinite()).CapitalizeFirst();
							string baby_text = ((babies.Count == 1) ? "RJW_ABaby".Translate(pawn.LabelPossessive) : "RJW_NBabies".Translate(babies.Count, pawn.LabelPossessive));
							message_text = message_text + baby_text;
							Find.LetterStack.ReceiveLetter(message_title, message_text, LetterDefOf.PositiveEvent, pawn);
						}
						GiveBirth();
					}
				}
			}
		}

		/// <summary>
		/// Give birth if contraction stage, even if mother died
		/// </summary>
		public override void Notify_PawnDied(DamageInfo? dinfo, Hediff culprit = null)
		{
			base.Notify_PawnDied(dinfo,culprit);
			if (CurStageIndex == 3)
				GiveBirth();
		}

		public override void ExposeData()
		{
			base.ExposeData();
			Scribe_References.Look(ref father, "father", true);
			Scribe_Deep.Look(ref geneSet, "genes");
			Scribe_Values.Look(ref is_checked, "is_checked");
			Scribe_Values.Look(ref is_hacked, "is_hacked");
			Scribe_Values.Look(ref is_discovered, "is_discovered");
			Scribe_Values.Look(ref is_parent_known, "is_parent_known");
			Scribe_Values.Look(ref ShouldMiscarry, "ShouldMiscarry");
			Scribe_Values.Look(ref ImmortalMiscarry, "ImmortalMiscarry");
			Scribe_Values.Look(ref contractions, "contractions");
			Scribe_Collections.Look(ref babies, "babies", saveDestroyedThings: true, lookMode: LookMode.Deep, ctorArgs: new object[0]);
			Scribe_Values.Look(ref p_start_tick, "p_start_tick", 0);
			Scribe_Values.Look(ref p_end_tick, "p_end_tick", 0);
			Scribe_Values.Look(ref lastTick, "lastTick", 0);
		}

		/// <summary>
		/// The parent that gives the "DNA" of a baby. Indicates whether the baby
		/// should be the same species as its mother or as its father.
		/// </summary>
		public enum DnaGivingParent
		{
			Mother,
			Father
		}

		/// <summary>
		/// Decides which parent's species the baby should have. This method is
		/// random for some configurations!
		/// </summary>
		[SyncMethod]
		public static DnaGivingParent SelectDnaGivingParent(Pawn mother, Pawn father)
		{
			bool IsAndroidmother = AndroidsCompatibility.IsAndroid(mother);
			bool IsAndroidfather = AndroidsCompatibility.IsAndroid(father);
			//androids can only birth non androids
			if (IsAndroidmother && !IsAndroidfather)
			{
				return DnaGivingParent.Father;
			}
			else if (!IsAndroidmother && IsAndroidfather)
			{
				return DnaGivingParent.Mother;
			}
			else if (IsAndroidmother && IsAndroidfather)
			{
				ModLog.Warning("Both parents are andoids, what have you done monster!");
				//this should never happen but w/e
			}

			bool is_humanmother = xxx.is_human(mother);
			bool is_humanfather = xxx.is_human(father);
			//Decide on which parent is first to be inherited
			if (father != null && RJWPregnancySettings.use_parent_method)
			{
				//Log.Message("The baby race needs definition");
				//humanality
				if (is_humanmother && is_humanfather)
				{
					//Log.Message("It's of two humanlikes");
					if (!Rand.Chance(RJWPregnancySettings.humanlike_DNA_from_mother))
					{
						//Log.Message("Mother will birth father race");
						return DnaGivingParent.Father;
					}
					else
					{
						//Log.Message("Mother will birth own race");
						return DnaGivingParent.Mother;
					}
				}
				//bestiality
				else if (is_humanmother ^ is_humanfather)
				{
					//TODO: fix gene inheritance from mother if ModsConfig.BiotechActive(also line 528)
					//if (RJWPregnancySettings.bestiality_DNA_inheritance == 0.0f || ModsConfig.BiotechActive)
					if (RJWPregnancySettings.bestiality_DNA_inheritance == 0.0f)
					{
						//Log.Message("mother will birth beast");
						if (is_humanmother)
							return DnaGivingParent.Father;
						else
							return DnaGivingParent.Mother;
					}
					else if (RJWPregnancySettings.bestiality_DNA_inheritance == 1.0f)
					{
						//Log.Message("mother will birth humanlike");
						if (is_humanmother)
							return DnaGivingParent.Mother;
						else
							return DnaGivingParent.Father;
					}
					else
					{
						if (!Rand.Chance(RJWPregnancySettings.bestial_DNA_from_mother))
						{
							//Log.Message("Mother will birth father race");
							return DnaGivingParent.Father;
						}
						else
						{
							//Log.Message("Mother will birth own race");
							return DnaGivingParent.Mother;
						}
					}

				}
				//animality
				else
				{
					if (!Rand.Chance(RJWPregnancySettings.bestial_DNA_from_mother))
					{
						//Log.Message("Mother will birth father race");
						return DnaGivingParent.Father;
					}
					else
					{
						//Log.Message("Mother will birth own race");
						return DnaGivingParent.Mother;
					}
				}
			}
			else
			{
				return DnaGivingParent.Mother;
			}
		}

		//This should generate pawns to be born in due time. Should take into account all settings and parent races
		[SyncMethod]
		protected virtual void GenerateBabies(DnaGivingParent dnaGivingParent)
		{
			Pawn mother = pawn;
			//Log.Message("Generating babies for " + this.def.defName);
			if (mother == null)
			{
				ModLog.Error("Hediff_BasePregnancy::GenerateBabies() - no mother defined");
				return;
			}

			if (father == null)
			{
				ModLog.Error("Hediff_BasePregnancy::GenerateBabies() - no father defined");
				return;
			}

			//Babies will have average number of traits of their parents, this way it will hopefully be compatible with various mods that change number of allowed traits
			//int trait_count = 0;
			// not anymore. Using number of traits originally generated by game as a guide

			Pawn parent = (dnaGivingParent == DnaGivingParent.Father) ? father : mother;
			//ModLog.Message(" The main parent is " + parent);
			//Log.Message("Mother: " + xxx.get_pawnname(mother) + " kind: " + mother.kindDef);
			//Log.Message("Father: " + xxx.get_pawnname(father) + " kind: " + father.kindDef);
			//Log.Message("Baby base: " + xxx.get_pawnname(parent) + " kind: " + parent.kindDef);

			string last_name = "";
			if (xxx.is_human(father))
				last_name = NameTriple.FromString(father.Name.ToStringFull).Last;
			else if (xxx.is_human(pawn))
				last_name = NameTriple.FromString(pawn.Name.ToStringFull).Last;

			//float skin_whiteness = Rand.Range(0, 1);
			//if (xxx.has_traits(pawn) && pawn.RaceProps.Humanlike)
			//{
			//	skin_whiteness = pawn.story.melanin;
			//}
			//if (father != null && xxx.has_traits(father) && father.RaceProps.Humanlike)
			//{
			//	skin_whiteness = Rand.Range(skin_whiteness, father.story.melanin);
			//}

			List<Trait> traitpool = new List<Trait>();
			List<Trait> momtraits = new List<Trait>();
			List<Trait> poptraits = new List<Trait>();
			List<Trait> traits_to_inherit = new List<Trait>();
			System.Random rd = new System.Random();
			int rand_trait_index = 0;
			float max_num_momtraits_inherited = RJWPregnancySettings.max_num_momtraits_inherited;
            float max_num_poptraits_inherited = RJWPregnancySettings.max_num_poptraits_inherited;
			float max_num_traits_inherited = max_num_momtraits_inherited + max_num_poptraits_inherited;
			int i = 1;
			int j = 1;
			//create list object to store traits of pop and mom
			if (xxx.has_traits(pawn) && pawn.RaceProps.Humanlike)
			{
				foreach (Trait momtrait in pawn.story.traits.allTraits)
				{
					if (!non_genetic_traits.Contains(momtrait.def.defName) && !momtrait.ScenForced)
						momtraits.Add(momtrait);
				}
			}
			if (father != null && xxx.has_traits(father) && father.RaceProps.Humanlike)
			{
				foreach (Trait poptrait in father.story.traits.allTraits)
				{
					if (!non_genetic_traits.Contains(poptrait.def.defName) && !poptrait.ScenForced)
						poptraits.Add(poptrait);
				}
			}
			//add traits from pop and mom to list for traits to inherit
			if(!momtraits.NullOrEmpty())
            {
				i = 1;
				while (momtraits.Count > 0 && i <= max_num_momtraits_inherited)
				{
					rand_trait_index = rd.Next(0, momtraits.Count);
					traits_to_inherit.Add(momtraits[rand_trait_index]);
					momtraits.RemoveAt(rand_trait_index);
                }
            }
			if(!poptraits.NullOrEmpty())
            {
				j = 1;
				while (poptraits.Count > 0 && j <= max_num_poptraits_inherited)
				{
					rand_trait_index = rd.Next(0, poptraits.Count);
					traits_to_inherit.Add(poptraits[rand_trait_index]);
					poptraits.RemoveAt(rand_trait_index);
				}
			}

			//if there is only mom or even no mom traits to be considered, then there is no need to check duplicated tratis from parents
			//then the traits_to_inherit List is ready to be transfered into traitpool
			if (poptraits.NullOrEmpty() || momtraits.NullOrEmpty())
            {
				foreach(Trait traits in traits_to_inherit)
                {
					traitpool.Add(traits);
                }
            }
			//if there are traits from both pop and mom, need to check if there are duplicated traits from parents
			else
            {
			//if length of traits_to_inherit equals maximum number of traits, then it means traits from bot parents reaches maximum value ,and no duplication, this list is ready to go
			//then the following big if chunk is not going to be executed, it will go directly to the last foreach chunk
				if (traits_to_inherit.Count() != max_num_traits_inherited)
				{
			//if not equivalent, it may due to removal of duplicated elements or number of traits of mom or pop are less than maximum number of traits can be inherited from mom or pop
			//now check if all the traits of mom has been added to traitpool for babies and if number of traits from mom has reached maximum while make sure momtraits is not null first
					if (momtraits.Count != 0 && i != max_num_momtraits_inherited)
					{
						while (poptraits != null && momtraits.Count > 0 && i <= max_num_momtraits_inherited)
						{
							rand_trait_index = rd.Next(0, momtraits.Count);
							//if this newly selected traits is not duplciated with traits already in traits_to_inherit
							if (!traits_to_inherit.Contains(momtraits[rand_trait_index]))
							{
								traits_to_inherit.Add(momtraits[rand_trait_index]);
							}
							momtraits.RemoveAt(rand_trait_index);
						}
					}
			//do processing to poptraits in the same way as momtraits
					if (poptraits != null && poptraits.Count != 0 && j != max_num_poptraits_inherited)
					{
						while (poptraits.Count > 0 && i <= max_num_poptraits_inherited)
						{
							rand_trait_index = rd.Next(0, poptraits.Count);
							//if this newly selected traits is not duplciated with traits already in traits_to_inherit
							if (!traits_to_inherit.Contains(poptraits[rand_trait_index]))
							{
								traits_to_inherit.Add(poptraits[rand_trait_index]);
							}
							poptraits.RemoveAt(rand_trait_index);
						}
					}
				}
			//add all traits in finalized trait_to_inherit List into traitpool List for further processing
			//if the above if chunk is executed, the following foreach chunk still needs to be executed, therefore there is no need to put this foreach chunk into an else chunk
				foreach (Trait traits in traits_to_inherit)
				{
					traitpool.Add(traits);
				}
			}

			//Pawn generation request
			PawnKindDef spawn_kind_def = parent.kindDef;
			Faction spawn_faction = mother.IsPrisoner ? null : mother.Faction;

			//ModLog.Message(" default child spawn_kind_def - " + spawn_kind_def);
			string MotherRaceName = "";
			string FatherRaceName = "";
			MotherRaceName = mother.kindDef.race.defName;
			if (father != null)
				FatherRaceName = father.kindDef.race.defName;
			//ModLog.Message(" MotherRaceName is " + MotherRaceName);
			//ModLog.Message(" FatherRaceName is " + FatherRaceName);
			if (MotherRaceName != FatherRaceName && FatherRaceName != "")
			{
				var groups = DefDatabase<RaceGroupDef>.AllDefs.Where(x => !x.hybridRaceParents.NullOrEmpty() && !x.hybridChildKindDef.NullOrEmpty());
				//ModLog.Message(" found custom RaceGroupDefs " + groups.Count());
				foreach (var t in groups)
				{
					//ModLog.Message(" trying custom RaceGroupDef " + t.defName);
					//ModLog.Message(" custom hybridRaceParents " + t.hybridRaceParents.Count());
					//ModLog.Message(" contains hybridRaceParents MotherRaceName? " + t.hybridRaceParents.Contains(MotherRaceName));
					//ModLog.Message(" contains hybridRaceParents FatherRaceName? " + t.hybridRaceParents.Contains(FatherRaceName));
					if ((t.hybridRaceParents.Contains(MotherRaceName) && t.hybridRaceParents.Contains(FatherRaceName))
						|| (t.hybridRaceParents.Contains("Any") && (t.hybridRaceParents.Contains(MotherRaceName) || t.hybridRaceParents.Contains(FatherRaceName))))
					{
						//ModLog.Message(" has hybridRaceParents");
						if (t.hybridChildKindDef.Contains("MotherKindDef"))
							spawn_kind_def = mother.kindDef;
						else if (t.hybridChildKindDef.Contains("FatherKindDef") && father != null)
							spawn_kind_def = father.kindDef;
						else
						{
							//ModLog.Message(" trying hybridChildKindDef " + t.defName);
							var child_kind_def_list = new List<PawnKindDef>();
							child_kind_def_list.AddRange(DefDatabase<PawnKindDef>.AllDefs.Where(x => t.hybridChildKindDef.Contains(x.defName)));

							//ModLog.Message(" found custom hybridChildKindDefs " + t.hybridChildKindDef.Count);
							if (!child_kind_def_list.NullOrEmpty())
								spawn_kind_def = child_kind_def_list.RandomElement();
						}
					}
				}
			}

			if (spawn_kind_def.defName.Contains("Nymph"))
			{
				//child is nymph, try to find other PawnKindDef
				var spawn_kind_def_list = new List<PawnKindDef>();
				spawn_kind_def_list.AddRange(DefDatabase<PawnKindDef>.AllDefs.Where(x => x.race == spawn_kind_def.race && !x.defName.Contains("Nymph")));
				//no other PawnKindDef found try mother
				if (spawn_kind_def_list.NullOrEmpty())
					spawn_kind_def_list.AddRange(DefDatabase<PawnKindDef>.AllDefs.Where(x => x.race == mother.kindDef.race && !x.defName.Contains("Nymph")));
				//no other PawnKindDef found try father
				if (spawn_kind_def_list.NullOrEmpty() && father !=null)
					spawn_kind_def_list.AddRange(DefDatabase<PawnKindDef>.AllDefs.Where(x => x.race == father.kindDef.race && !x.defName.Contains("Nymph")));
				//no other PawnKindDef found fallback to generic colonist
				if (spawn_kind_def_list.NullOrEmpty())
					spawn_kind_def = PawnKindDefOf.Colonist;

				spawn_kind_def = spawn_kind_def_list.RandomElement();
			}
			//ModLog.Message(" final child spawn_kind_def - " + spawn_kind_def);

			//pregnancies with slimes birth only slimes
			//should somehow merge with above
			if (xxx.is_slime(mother))
			{
				parent = mother;
				spawn_kind_def = parent.kindDef;
			}
			if (father != null)
			{
				if (xxx.is_slime(father))
				{
					parent = father;
					spawn_kind_def = parent.kindDef;
				}
			}

			PawnGenerationRequest request = new PawnGenerationRequest(
				kind: spawn_kind_def,
				faction: spawn_faction,
				forceGenerateNewPawn: true,
				developmentalStages: DevelopmentalStage.Newborn,
				allowDowned: true,
				canGeneratePawnRelations: false,
				colonistRelationChanceFactor: 0,
				allowFood: false,
				allowAddictions: false,
				relationWithExtraPawnChanceFactor: 0,
				//fixedMelanin: skin_whiteness,
				fixedLastName: last_name,
				//forceNoIdeo: true,
				forbidAnyTitle: true,
				forceNoBackstory: true,
				forcedEndogenes: PregnancyUtility.GetInheritedGenes(father, mother)
				);

			//ModLog.Message(" Generated request, making babies");
			//Litter size. Let's use the main parent litter size, reduced by fertility.
			float litter_size = (parent.RaceProps.litterSizeCurve == null) ? 1 : Rand.ByCurve(parent.RaceProps.litterSizeCurve);
			//ModLog.Message(" base Litter size " + litter_size);
			litter_size *= Math.Min(mother.health.capacities.GetLevel(xxx.reproduction), 1);
			litter_size *= Math.Min(father == null ? 1 : father.health.capacities.GetLevel(xxx.reproduction), 1);
			litter_size = Math.Max(1, litter_size);
			//ModLog.Message(" Litter size (w fertility) " + litter_size);

			float max_litter = GetMaxLitterSize(spawn_kind_def);

			//Generate random amount of babies within litter/max size
			litter_size = (Rand.Range(litter_size, max_litter));
			//ModLog.Message(" Litter size roll 1:" + litter_size);
			litter_size = Mathf.RoundToInt(litter_size);
			//ModLog.Message(" Litter size roll 2:" + litter_size);
			litter_size = Math.Max(1, litter_size);
			//ModLog.Message(" final Litter size " + litter_size);

			for (i = 0; i < litter_size; i++)
			{
				Pawn baby = PawnGenerator.GeneratePawn(request);

				if (xxx.is_human(baby))
				{
					if (mother.IsSlaveOfColony)
					{
						//Log.Message("mother.SlaveFaction " + mother.SlaveFaction);
						//Log.Message("mother.HomeFaction " + mother.HomeFaction);
						//Log.Message("mother.Faction " + mother.Faction);

						if (mother.SlaveFaction != null)
							baby.SetFaction(mother.SlaveFaction);
						else if (mother.HomeFaction != null)
							baby.SetFaction(mother.HomeFaction);
						else if (mother.Faction != null)
							baby.SetFaction(mother.Faction);
						else
							baby.SetFaction(Faction.OfPlayer);
						baby.guest.SetGuestStatus(Faction.OfPlayer, GuestStatus.Slave);
					}
					else if (mother.IsPrisonerOfColony)
					{
						//Log.Message("mother.HomeFaction " + mother.HomeFaction);
						if (mother.HomeFaction != null)
							baby.SetFaction(mother.HomeFaction);
						baby.guest.SetGuestStatus(Faction.OfPlayer, GuestStatus.Prisoner);
					}

					//Choose traits to add to the child. Unlike CnP this will allow for some random traits
					if (traitpool.Count > 0)
					{
						updateTraits(baby, traitpool);
					}
				}
				babies.Add(baby);
			}
		}

		private float GetMaxLitterSize(PawnKindDef childKindDef)
		{
			//Babies body size vs mother body size (bonus childrens boost for multi children pregnancy, ~1.7 for humans ~ x2.2 orassans)
			//assuming mother belly is 1/3 of mother body size
			float babySize = childKindDef.RaceProps.lifeStageAges[0].def.bodySizeFactor; // adult size/5, probably?
			babySize *= childKindDef.RaceProps.baseBodySize; // adult size
			//ModLog.Message(" Baby size " + babySize);
			float maxLitterSize = 1f / 3f / babySize;
			//ModLog.Message(" Max size " + maxLitterSize);
			return maxLitterSize;
		}

		/// <summary>
		/// Update pawns traits
		/// Uses original pawns trains and given list of traits as a source of traits to select.
		/// </summary>
		/// <param name="pawn">humanoid pawn</param>
		/// <param name="traitpool">list of parent traits</param>
		/// <param name="traitLimit">maximum allowed number of traits</param>
		[SyncMethod]
		void updateTraits(Pawn pawn, List<Trait> parenttraitpool, int traitLimit = -1)
		{
			if (pawn?.story?.traits == null)
			{
				return;
			}

			if (traitLimit == -1)
			{
				traitLimit = pawn.story.traits.allTraits.Count;
			}

			//Personal pool
			List<Trait> personalTraitPool = new List<Trait>(pawn.story.traits.allTraits);
			//Parents pool
			if (parenttraitpool != null)
			{
				personalTraitPool.AddRange(parenttraitpool);
			}

			//Game suggested traits.
			var forcedTraits = personalTraitPool
				.Where(x => x.ScenForced)
				.Distinct(new TraitComparer(ignoreDegree: true)); // result can be a mess, because game allows this mess to be created in scenario editor

			List<Trait> selectedTraits = new List<Trait>();
			selectedTraits.AddRange(forcedTraits); // enforcing scenario forced traits

			var comparer = new TraitComparer(); // trait comparision implementation, because without game compares traits *by reference*, makeing them all unique.

			while (selectedTraits.Count < traitLimit && personalTraitPool.Count > 0)
			{
				int index = Rand.Range(0, personalTraitPool.Count); // getting trait and removing from the pull
				var trait = personalTraitPool[index];
				personalTraitPool.RemoveAt(index);

				if (!selectedTraits.Any(x => comparer.Equals(x, trait) ||  // skipping traits conflicting with already added
											 x.def.ConflictsWith(trait)))
				{
					selectedTraits.Add(new Trait(trait.def, trait.Degree, false));
				}
			}

			pawn.story.traits.allTraits = selectedTraits;
		}

		//Handles the spawning of pawns
		//this is extended by other scripts
		public abstract void GiveBirth();

		//Add relations
		//post pregnancy effects
		//update birth stats
		//make baby futa if needed
		public virtual void PostBirth(Pawn mother, Pawn father, Pawn baby)
		{
			BabyPostBirth(mother, father, baby);

			if (baby.playerSettings != null && mother.playerSettings != null)
			{
				baby.playerSettings.AreaRestrictionInPawnCurrentMap = mother.playerSettings.AreaRestrictionInPawnCurrentMap; //or should this be effective one?
			}

			//if (xxx.is_human(baby))
			//{
			//	baby.story.melanin = skin_whiteness;
			//	baby.story.birthLastName = last_name;
			//}

			//ModLog.Message("" + this.GetType().ToString() + " post PostBirth 1: " + baby.story.birthLastName);
			//spawn futa
			bool isfuta = spawnfutachild(baby, mother, father);

			if (!RacePartDef_Helper.TryRacePartDef_partAdders(baby))
			{
				RemoveBabyParts(baby, Genital_Helper.get_AllPartsHediffList(baby));
				if (isfuta)
				{
					SexPartAdder.add_genitals(baby, partstospawn(baby, mother, father), Gender.Male);
					SexPartAdder.add_genitals(baby, partstospawn(baby, mother, father), Gender.Female);
					SexPartAdder.add_breasts(baby, partstospawn(baby, mother, father), Gender.Female);
					baby.gender = Gender.Female;                //set gender to female for futas, should cause no errors since babies already generated with relations n stuff
				}
				else
				{
					SexPartAdder.add_genitals(baby, partstospawn(baby, mother, father));
					SexPartAdder.add_breasts(baby, partstospawn(baby, mother, father));
				}
				SexPartAdder.add_anus(baby, partstospawn(baby, mother, father));
			}

			//ModLog.Message("" + this.GetType().ToString() + " post PostBirth 2: " + baby.story.birthLastName);
			if (mother.Spawned)
			{
				// Move the baby in front of the mother, rather than on top
				if (mother.CurrentBed() != null)
				{
					baby.Position = baby.Position + new IntVec3(0, 0, 1).RotatedBy(mother.CurrentBed().Rotation);
				}
				// Spawn guck
				FilthMaker.TryMakeFilth(mother.Position, mother.Map, ThingDefOf.Filth_AmnioticFluid, mother.LabelIndefinite(), 5);
				mother.caller?.DoCall();
				baby.caller?.DoCall();
				father?.caller?.DoCall();
			}

			//ModLog.Message("" + this.GetType().ToString() + " post PostBirth 3: " + baby.story.birthLastName);
			if (xxx.is_human(baby))
				mother.records.AddTo(xxx.CountOfBirthHuman, 1);
			if (xxx.is_animal(baby))
				mother.records.AddTo(xxx.CountOfBirthAnimal, 1);
		}

		public static void RemoveBabyParts(Pawn baby, List<Hediff> list)
		{
			//ModLog.Message(" RemoveBabyParts( " + xxx.get_pawnname(baby) + " ) - " + list.Count);
			if (!list.NullOrEmpty())
				foreach (var x in list)
				{
					//ModLog.Message(" RemoveBabyParts( " + xxx.get_pawnname(baby) + " ) - " + x.def.defName);

					baby.health.RemoveHediff(x);
					//baby.health.RemoveHediff(baby.health.hediffSet.hediffs.Remove(x));
				}
		}
		[SyncMethod]
		public static void BabyPostBirth(Pawn mother, Pawn father, Pawn baby)
		{
			if (!xxx.is_human(baby)) return;

			baby.story.Childhood = null;
			baby.story.Adulthood = null;

			try
			{
				// set child to civil
				String bsDef = null;
				bool isTribal = false;

				// set child to tribal if both parents tribals
				if (father != null && father.story != null)
				{
					if (mother.story.GetBackstory(BackstorySlot.Adulthood) != null && father.story.GetBackstory(BackstorySlot.Adulthood).spawnCategories.Contains("Tribal"))
						isTribal = true;
					else if (mother.story.GetBackstory(BackstorySlot.Adulthood) == null && father.story.GetBackstory(BackstorySlot.Childhood).spawnCategories.Contains("Tribal"))
						isTribal = true;
				}
				else
				{
					//(int)Find.GameInitData.playerFaction.def.techLevel < 4;
					if ((int)mother.Faction.def.techLevel < 4)
						isTribal = true;
				}

				if (isTribal)
				{
					bsDef = "rjw_childT";
					if (baby.GetRJWPawnData().RaceSupportDef != null)
						if (!baby.GetRJWPawnData().RaceSupportDef.backstoryChildTribal.NullOrEmpty())
							bsDef = baby.GetRJWPawnData().RaceSupportDef.backstoryChildTribal.RandomElement();
				}
				else
				{
					bsDef = "rjw_childC";
					if (baby.GetRJWPawnData().RaceSupportDef != null)
						if (!baby.GetRJWPawnData().RaceSupportDef.backstoryChildCivil.NullOrEmpty())
							bsDef = baby.GetRJWPawnData().RaceSupportDef.backstoryChildCivil.RandomElement();
				}

				baby.story.Childhood = DefDatabase<BackstoryDef>.AllDefsListForReading.FirstOrDefault(x => x.defName.Contains(bsDef));
			}
			catch (Exception e)
			{
				ModLog.Warning(e.ToString());
			}
		}

		protected void InitializeIfNoBabies()
		{
			if (babies.NullOrEmpty())
			{
				ModLog.Warning(" no babies (debug?) " + this.GetType().Name);
				if (father == null)
				{
					father = Trytogetfather(ref pawn);
				}
				Initialize(pawn, father, SelectDnaGivingParent(pawn, father));
			}
		}

		//This method is doing the work of the constructor since hediffs are created through HediffMaker instead of normal oop way
		//This can't be in PostMake() because there wouldn't be father.
		public void Initialize(Pawn mother, Pawn dad, DnaGivingParent dnaGivingParent)
		{
			BodyPartRecord torso = mother.RaceProps.body.AllParts.Find(x => x.def.defName == "Torso");
			mother.health.AddHediff(this, torso);
			//ModLog.Message("" + this.GetType().ToString() + " pregnancy hediff generated: " + this.Label);
			//ModLog.Message("" + this.GetType().ToString() + " mother: " + mother + " father: " + dad);
			father = dad;
			if (father != null)
			{
				babies = new List<Pawn>();
				contractions = 0;
				//ModLog.Message("" + this.GetType().ToString() + " generating babies before: " + this.babies.Count);
				GenerateBabies(dnaGivingParent);
				//if (ModsConfig.BiotechActive)
				//	geneSet = PregnancyUtility.GetInheritedGeneSet(father, mother);
				//	SetParents(mother, father, PregnancyUtility.GetInheritedGeneSet(father, mother));

			}

			float gestationPeriod = GetGestationPeriod();
			p_start_tick = Find.TickManager.TicksGame;
			p_end_tick = p_start_tick + gestationPeriod;
			lastTick = p_start_tick;

			if (xxx.ImmortalsIsActive && (mother.health.hediffSet.HasHediff(xxx.IH_Immortal) || father.health.hediffSet.HasHediff(xxx.IH_Immortal)))
			{
				ImmortalMiscarry = true;
				ShouldMiscarry = true;
			}
			//ModLog.Message("" + this.GetType().ToString() + " generating babies after: " + this.babies.Count);
		}

		private float GetGestationPeriod()
		{
			float gestationPeriod;
			if (babies[0].RaceProps?.gestationPeriodDays < 1)
			{
				if (xxx.is_human(babies[0]))
					gestationPeriod = 45 * GenDate.TicksPerDay; //default human
				else
					gestationPeriod = GenDate.TicksPerDay;
			}
			else
			{
				gestationPeriod = babies[0].RaceProps.gestationPeriodDays * GenDate.TicksPerDay;
			}

			if (pawn.health.hediffSet.HasHediff(HediffDef.Named("FertilityEnhancer")))
				gestationPeriod /= 1.25f;

			gestationPeriod *= RJWPregnancySettings.normal_pregnancy_duration;
			return gestationPeriod;
		}

		private static Dictionary<Type, string> _hediffOfClass = null;
		protected static Dictionary<Type, string> hediffOfClass
		{
			get
			{
				if (_hediffOfClass == null)
				{
					_hediffOfClass = new Dictionary<Type, string>();
					var allRJWPregnancies = GenTypes.AllActiveAssemblies
						.SelectMany(
							a => a
							.GetTypes()
							.Where(t => t.IsSubclassOf(typeof(Hediff_BasePregnancy)))
						);

					foreach (var pregClass in allRJWPregnancies)
					{
						var attribute = (RJWAssociatedHediffAttribute)pregClass.GetCustomAttributes(typeof(RJWAssociatedHediffAttribute), false).FirstOrDefault();
						if (attribute != null)
						{
							_hediffOfClass[pregClass] = attribute.defName;
						}
					}
				}

				return _hediffOfClass;
			}
		}

		public static T Create<T>(Pawn mother, Pawn father) where T : Hediff_BasePregnancy
		{
			return Create<T>(mother, father, SelectDnaGivingParent(mother, father));
		}

		/// <summary>
		/// Creates pregnancy hediff and assigns it to mother
		/// </summary>
		/// <typeparam name="T">type of pregnancy, should be subclass of Hediff_BasePregnancy</typeparam>
		/// <param name="mother"></param>
		/// <param name="father"></param>
		/// <returns>created hediff</returns>
		public static T Create<T>(Pawn mother, Pawn father, DnaGivingParent dnaGivingParent) where T : Hediff_BasePregnancy
		{
			if (mother == null)
				return null;
			//if (mother.RaceHasOviPregnancy() && !(T is Hediff_MechanoidPregnancy))
			//{
			//	//return null;
			//}
			//else
			//{
			//}

			BodyPartRecord torso = mother.RaceProps.body.AllParts.Find(x => x.def.defName == "Torso");

			string defName = hediffOfClass.ContainsKey(typeof(T)) ? hediffOfClass[typeof(T)] : "RJW_pregnancy";
			if (RJWSettings.DevMode) ModLog.Message($"Hediff_BasePregnancy::create hediff:{defName} class:{typeof(T).FullName}");

			T hediff = HediffHelper.MakeHediff<T>(HediffDef.Named(defName), mother, torso);
			hediff.Initialize(mother, father, dnaGivingParent);
			return hediff;
		}

		/// <summary>
		/// list of all known RJW pregnancy hediff names (new can be regicreted by mods)
		/// </summary>
		/// <returns></returns>
		public static IEnumerable<string> KnownPregnancies()
		{
			return hediffOfClass.Values.Distinct(); // todo: performance
		}

		public override string DebugString()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append(base.DebugString());
			stringBuilder.AppendLine("Gestation progress: " + GestationProgress.ToStringPercent());
			//stringBuilder.AppendLine("Time left: " + ((int)((1f - GestationProgress) * babies[babies.Count-1].RaceProps.gestationPeriodDays * TicksPerDay * RJWPregnancySettings.normal_pregnancy_duration)).ToStringTicksToPeriod());
			return stringBuilder.ToString();
		}
		//public override IEnumerable<Gizmo> GetGizmos()
		//{
		//	foreach (Gizmo gizmo in base.GetGizmos())
		//	{
		//		yield return gizmo;
		//	}
		//	if (!DebugSettings.ShowDevGizmos)
		//	{
		//		yield break;
		//	}
		//	if (CurStageIndex < 2)
		//	{
		//		Command_Action command_Action = new Command_Action();
		//		command_Action.defaultLabel = "DEV: Next trimester";
		//		command_Action.action = delegate
		//		{
		//			HediffStage hediffStage = def.stages[CurStageIndex + 1];
		//			severityInt = hediffStage.minSeverity;
		//		};
		//		yield return command_Action;
		//	}
		//	if (ModsConfig.BiotechActive && pawn.RaceProps.Humanlike && pawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.PregnancyLabor) == null)
		//	{
		//		Command_Action command_Action2 = new Command_Action();
		//		command_Action2.defaultLabel = "DEV: Start Labor";
		//		command_Action2.action = delegate
		//		{
		//			StartLabor();
		//			pawn.health.RemoveHediff(this);
		//		};
		//		yield return command_Action2;
		//	}
		//}
		//public void StartLabor()
		//{
		//	if (ModLister.CheckBiotech("labor"))
		//	{
		//		((Hediff_Labor)pawn.health.AddHediff(HediffDefOf.PregnancyLabor)).SetParents(pawn, father, PregnancyUtility.GetInheritedGeneSet(father, pawn));
		//		Hediff firstHediffOfDef = pawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.MorningSickness);
		//		if (firstHediffOfDef != null)
		//		{
		//			pawn.health.RemoveHediff(firstHediffOfDef);
		//		}
		//		Hediff firstHediffOfDef2 = pawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.PregnancyMood);
		//		if (firstHediffOfDef2 != null)
		//		{
		//			pawn.health.RemoveHediff(firstHediffOfDef2);
		//		}
		//		if (PawnUtility.ShouldSendNotificationAbout(pawn))
		//		{
		//			Find.LetterStack.ReceiveLetter("LetterColonistPregnancyLaborLabel".Translate(pawn), "LetterColonistPregnancyLabor".Translate(pawn), LetterDefOf.NeutralEvent);
		//		}
		//	}
		//}
	}
}


code:
using System.Collections.Generic;
using System.Linq;
using RimWorld;
using Verse;

namespace rjw
{
	///<summary>
	///This hediff class simulates pregnancy with animal children, mother may be human. It is not intended to be reasonable.
	///Differences from humanlike pregnancy are that animals are given some training and that less punishing relations are used for parent-child.
	///</summary>
	[RJWAssociatedHediff("RJW_pregnancy_beast")]
	public class Hediff_BestialPregnancy : Hediff_BasePregnancy
	{
		private static readonly PawnRelationDef relation_birthgiver = PawnRelationDefOf.Parent;
		//static int max_train_level = TrainableUtility.TrainableDefsInListOrder.Sum(tr => tr.steps);

		public override void PregnancyMessage()
		{
			string message_title = "RJW_PregnantTitle".Translate(pawn.LabelIndefinite()).CapitalizeFirst();
			string message_text1 = "RJW_PregnantText".Translate(pawn.LabelIndefinite()).CapitalizeFirst();
			string message_text2 = "RJW_PregnantStrange".Translate();
			Find.LetterStack.ReceiveLetter(message_title, message_text1 + "\n" + message_text2, LetterDefOf.NeutralEvent, pawn);
		}

		//Makes half-human babies start off better. They start obedient, and if mother is a human, they get hediff to boost their training
		protected void train(Pawn baby, Pawn mother, Pawn father)
		{
			bool _;
			if (!xxx.is_human(baby) && baby.Faction == Faction.OfPlayer)
			{
				if (xxx.is_human(mother) && baby.Faction == Faction.OfPlayer && baby.training.CanAssignToTrain(TrainableDefOf.Obedience, out _).Accepted)
				{
					baby.training.Train(TrainableDefOf.Obedience, mother);
				}
				if (xxx.is_human(mother) && baby.Faction == Faction.OfPlayer && baby.training.CanAssignToTrain(TrainableDefOf.Tameness, out _).Accepted)
				{
					baby.training.Train(TrainableDefOf.Tameness, mother);
				}
			}
			//baby.RaceProps.TrainableIntelligence.LabelCap.
			//if (xxx.is_human(mother))
			//{
			//	Let the animals be born as colony property
			//	if (mother.IsPrisonerOfColony || mother.IsColonist)
			//	{
			//		baby.SetFaction(Faction.OfPlayer);
			//	}
			//	let it be trained half to the max
			//	var baby_int = baby.RaceProps.TrainableIntelligence;
			//	int max_int = TrainableUtility.TrainableDefsInListOrder.FindLastIndex(tr => (tr.requiredTrainableIntelligence == baby_int));
			//	if (max_int == -1)
			//		return;
			//	Log.Message("RJW training " + baby + " max_int is " + max_int);
			//	var available_tricks = TrainableUtility.TrainableDefsInListOrder.GetRange(0, max_int + 1);
			//	int max_steps = available_tricks.Sum(tr => tr.steps);
			//	Log.Message("RJW training " + baby + " vill do " + max_steps/2 + " steps");
			//	int t_score = Rand.Range(Mathf.RoundToInt(max_steps / 4), Mathf.RoundToInt(max_steps / 2));
			//	for (int i = 1; i <= t_score; i++)
			//	{
			//		var tr = available_tricks.Where(t => !baby.training.IsCompleted(t)). RandomElement();
			//		Log.Message("RJW training " + baby + " for " + tr);
			//		baby.training.Train(tr, mother);
			//	}

			//	baby.health.AddHediff(HediffDef.Named("RJW_smartPup"));
			//}
		}

		//Handles the spawning of pawns and adding relations
		public override void GiveBirth()
		{
			Pawn mother = pawn;
			if (mother == null)
				return;

			InitializeIfNoBabies();
			List<Pawn> siblings = new List<Pawn>();
			foreach (Pawn baby in babies)
			{
				//backup melanin, LastName for when baby reset by other mod on spawn/backstorychange
				//var skin_whiteness = baby.story.melanin;
				//var last_name = baby.story.birthLastName;

				PawnUtility.TrySpawnHatchedOrBornPawn(baby, mother);

				Need_Sex sex_need = mother.needs?.TryGetNeed<Need_Sex>();
				if (mother.Faction != null && !(mother.Faction?.IsPlayer ?? false) && sex_need != null)
				{
					sex_need.CurLevel = 1.0f;
				}

				if (!RJWSettings.Disable_bestiality_pregnancy_relations)
				{
					baby.relations.AddDirectRelation(relation_birthgiver, mother);
					if (father != null && mother != father)
					{
						baby.relations.AddDirectRelation(relation_birthgiver, father);
					}
				}
				train(baby, mother, father);

				PostBirth(mother, father, baby);

				//restore melanin, LastName for when baby reset by other mod on spawn/backstorychange
				//baby.story.melanin = skin_whiteness;
				//baby.story.birthLastName = last_name;
			}
			mother.health.RemoveHediff(this);
		}
	}
}


code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RimWorld;
using Verse;
using UnityEngine;

namespace rjw
{
	[RJWAssociatedHediff("RJW_pregnancy")]
	public class Hediff_HumanlikePregnancy : Hediff_BasePregnancy
	///<summary>
	///This hediff class simulates pregnancy resulting in humanlike childs.
	///</summary>
	{
		//Handles the spawning of pawns and adding relations
		public override void GiveBirth()
		{
			Pawn mother = pawn;
			if (mother == null)
				return;

			InitializeIfNoBabies();
			List<Pawn> siblings = new List<Pawn>();
			foreach (Pawn baby in babies)
			{
				//backup melanin, LastName for when baby reset by other mod on spawn/backstorychange
				//var skin_whiteness = baby.story.melanin;
				//var last_name = baby.story.birthLastName;

				//ModLog.Message("" + this.GetType().ToString() + " pre TrySpawnHatchedOrBornPawn: " + baby.story.birthLastName);
				PawnUtility.TrySpawnHatchedOrBornPawn(baby, mother);
				//ModLog.Message("" + this.GetType().ToString() + " post TrySpawnHatchedOrBornPawn: " + baby.story.birthLastName);

				var sex_need = mother.needs?.TryGetNeed<Need_Sex>();
				if (mother.Faction != null && !(mother.Faction?.IsPlayer ?? false) && sex_need != null)
				{
					sex_need.CurLevel = 1.0f;
				}
				if (mother.IsSlaveOfColony)
				{
					//Log.Message("mother.SlaveFaction " + mother.SlaveFaction);
					//Log.Message("mother.HomeFaction " + mother.HomeFaction);
					//Log.Message("mother.Faction " + mother.Faction);

					if (mother.SlaveFaction != null)
						baby.SetFaction(mother.SlaveFaction);
					else if (mother.HomeFaction != null)
						baby.SetFaction(mother.HomeFaction);
					else if (mother.Faction != null)
						baby.SetFaction(mother.Faction);
					else
						baby.SetFaction(Faction.OfPlayer);
					baby.guest.SetGuestStatus(Faction.OfPlayer, GuestStatus.Slave);
				}
				else if (mother.IsPrisonerOfColony)
				{
					//Log.Message("mother.HomeFaction " + mother.HomeFaction);
					if (mother.HomeFaction != null)
						baby.SetFaction(mother.HomeFaction);
					baby.guest.SetGuestStatus(Faction.OfPlayer, GuestStatus.Prisoner);
				}

				baby.relations.AddDirectRelation(PawnRelationDefOf.Parent, mother);
				if (father != null && mother != father)
				{
					baby.relations.AddDirectRelation(PawnRelationDefOf.Parent, father);
				}

				//ModLog.Message("" + this.GetType().ToString() + " pre PostBirth: " + baby.story.birthLastName);
				PostBirth(mother, father, baby);
				//ModLog.Message("" + this.GetType().ToString() + " post PostBirth: " + baby.story.birthLastName);

				//restore melanin, LastName for when baby reset by other mod on spawn/backstorychange
				//baby.story.melanin = skin_whiteness;
				//baby.story.birthLastName = last_name;
			}
			mother.health.RemoveHediff(this);
		}
	}
}


code:
using System;
using System.Linq;
using System.Collections.Generic;
using RimWorld;
using RimWorld.Planet;
using Verse;
using System.Text;
using Verse.AI.Group;
using Multiplayer.API;

namespace rjw
{
	public class Hediff_InsectEgg : HediffWithComps
	{
		/*
		 * Dev Note: To easily test egg-birth, set the p_end_tick to p_start_tick + 10 in the SaveFile.
		 */

		public float p_start_tick = 0;
		public float p_end_tick = 0;
		public float lastTick = 0;

		private HediffDef_InsectEgg HediffDefOfEgg => (HediffDef_InsectEgg)def;

		public string parentDef => HediffDefOfEgg.parentDef;

		public List<string> parentDefs => HediffDefOfEgg.parentDefs;
		public List<GeneDef> eggGenes;

		// TODO: I'd like to change "father" to "fertilizer" but that would be a breaking change.
		public Pawn father;					//can be parentkind defined in egg
		public Pawn implanter;					//can be any pawn
		public bool canbefertilized = true;
		public bool fertilized => father != null;
		public float eggssize = 0.1f;
		protected List<Pawn> babies;
		float Gestation = 0f;

		///Contractions duration, effectively additional hediff stage, a dirty hack to make birthing process notable
		//protected const int TicksPerHour = 2500;
		protected int contractions = 0;

		public override string LabelBase
		{
			get
			{
				if (Prefs.DevMode && implanter != null)
				{
						return implanter.kindDef.race.label + "Hediff_InsectEgg_egg".Translate();
				}

				if (eggssize <= 0.10f)
					return "Hediff_InsectEgg_small".Translate();
				if (eggssize <= 0.3f)
					return "Hediff_InsectEgg_medium".Translate();
				else if (eggssize <= 0.5f)
					return "Hediff_InsectEgg_big".Translate();
				else
					return "Hediff_InsectEgg_huge".Translate();
			}
		}

		public override string LabelInBrackets
		{
			get
			{
				if (Prefs.DevMode)
				{
					if (fertilized)
						return "Hediff_InsectEgg_fertilized".Translate();
					else
						return "Hediff_InsectEgg_unfertilized".Translate();
				}
				return null;
			}
		}

		public float GestationProgress
		{
			get => Gestation;
			set => Gestation = value;
		}

		public override bool TryMergeWith(Hediff other)
		{
			return false;
		}

		public override void Tick()
		{
			var thisTick = Find.TickManager.TicksGame;
			GestationProgress = (1 + thisTick - p_start_tick) / (p_end_tick - p_start_tick);

			if ((thisTick - lastTick) >= 1000)
			{
				lastTick = thisTick;
				//birthing takes an hour
				if (GestationProgress >= 1 && contractions == 0 && !(pawn.jobs.curDriver is JobDriver_Sex))
				{
					if (PawnUtility.ShouldSendNotificationAbout(pawn) && (pawn.IsColonist || pawn.IsPrisonerOfColony))
					{
						string key = "RJW_EggContractions";
						string text = TranslatorFormattedStringExtensions.Translate(key, pawn.LabelIndefinite());
						Messages.Message(text, pawn, MessageTypeDefOf.NeutralEvent);
					}
					contractions++;
					if (!Genital_Helper.has_ovipositorF(pawn))
						pawn.health.AddHediff(xxx.submitting);
				}
				else if (GestationProgress >= 1 && contractions != 0 && (pawn.CarriedBy == null || pawn.CarriedByCaravan()))
				{
					if (PawnUtility.ShouldSendNotificationAbout(pawn) && (pawn.IsColonist || pawn.IsPrisonerOfColony))
					{
						string key1 = "RJW_GaveBirthEggTitle";
						string message_title = TranslatorFormattedStringExtensions.Translate(key1, pawn.LabelIndefinite());
						string key2 = "RJW_GaveBirthEggText";
						string message_text = TranslatorFormattedStringExtensions.Translate(key2, pawn.LabelIndefinite());

						Messages.Message(message_text, pawn, MessageTypeDefOf.SituationResolved);
					}
					GiveBirth();
				}
			}
		}

		public override void ExposeData()
		{
			base.ExposeData();
			Scribe_References.Look(ref father, "father", true);
			Scribe_References.Look(ref implanter, "implanter", true);
			Scribe_Values.Look(ref Gestation, "Gestation");
			Scribe_Values.Look(ref p_start_tick, "p_start_tick", 0);
			Scribe_Values.Look(ref p_end_tick, "p_end_tick", 0);
			Scribe_Values.Look(ref lastTick, "lastTick", 0);
			Scribe_Values.Look(ref eggssize, "eggssize", 0.1f);
			Scribe_Values.Look(ref canbefertilized, "canbefertilized", true);
			Scribe_Collections.Look(ref eggGenes, label: "genes", lookMode: LookMode.Def);
			Scribe_Collections.Look(ref babies, "babies", saveDestroyedThings: true,  lookMode: LookMode.Deep, ctorArgs: new object[0]);
		}
		public override void Notify_PawnDied(DamageInfo? dinfo, Hediff culprit = null)
		{
			base.Notify_PawnDied(dinfo, culprit);
			GiveBirth();
		}

		//should someday remake into birth eggs and then within few ticks hatch them
		[SyncMethod]
		public void GiveBirth()
		{
			Pawn mother = pawn;
			Pawn baby = null;

			if (RJWSettings.DevMode) ModLog.Message($"{pawn} is giving birth to an InsectEgg");
			if (fertilized)
			{
				if (RJWSettings.DevMode) ModLog.Message($"Egg was fertilized - Fertilizer {father} and Implanter {implanter}");
				PawnKindDef spawn_kind_def = implanter.kindDef;

				Faction spawn_faction = DetermineSpawnFaction(mother);
				spawn_kind_def = AdjustSpawnKindDef(mother, spawn_kind_def);

				if (!spawn_kind_def.RaceProps.Humanlike)
				{
					BirthFertilizedAnimalEgg(mother, spawn_kind_def);
				}
				else //humanlike baby
				{
					baby = ProcessHumanLikeInsectEgg(mother, spawn_kind_def, spawn_faction);
				}
				UpdateBirtherRecords(mother);
			}
			else
			{
				BirthUnfertilizedEggs(mother);
			}
			// Post birth
			ProcessPostBirth(mother, baby);

			mother.health.RemoveHediff(this);
		}

		/// <summary>
		/// Bumps the Birth-Statistic for eggs.
		/// </summary>
		/// <param name="mother">The pawn that birthed a new egg</param>
		private static void UpdateBirtherRecords(Pawn mother)
		{

			if (RJWSettings.DevMode) ModLog.Message($"Updating {mother}s records after birthing an egg");

			mother.records.AddTo(xxx.CountOfBirthEgg, 1);
		}

		/// <summary>
		/// Adjusts the Pawn_Kind_Def if it is a Nymph.
		/// Issue is that later processing cannot nicely deal with Nymphs.
		/// </summary>
		/// <param name="mother">The mother, for potential back-up lookup</param>
		/// <param name="spawn_kind_def">The current spawn_kind_def</param>
		/// <returns></returns>
		[SyncMethod]
		private PawnKindDef AdjustSpawnKindDef(Pawn mother, PawnKindDef spawn_kind_def)
		{
			if (spawn_kind_def.defName.Contains("Nymph"))
			{
				//child is nymph, try to find other PawnKindDef
				var spawn_kind_def_list = new List<PawnKindDef>();
				spawn_kind_def_list.AddRange(DefDatabase<PawnKindDef>.AllDefs.Where(x => x.race == spawn_kind_def.race && !x.defName.Contains("Nymph")));
				//no other PawnKindDef found try mother
				if (spawn_kind_def_list.NullOrEmpty())
					spawn_kind_def_list.AddRange(DefDatabase<PawnKindDef>.AllDefs.Where(x => x.race == mother.kindDef.race && !x.defName.Contains("Nymph")));
				//no other PawnKindDef found try implanter
				if (spawn_kind_def_list.NullOrEmpty() && implanter != null)
					spawn_kind_def_list.AddRange(DefDatabase<PawnKindDef>.AllDefs.Where(x => x.race == implanter.kindDef.race && !x.defName.Contains("Nymph")));
				//no other PawnKindDef found fallback to generic colonist
				if (spawn_kind_def_list.NullOrEmpty())
					spawn_kind_def = PawnKindDefOf.Colonist;

				spawn_kind_def = spawn_kind_def_list.RandomElement();
			}

			return spawn_kind_def;
		}

		[SyncMethod]
		private void ProcessPostBirth(Pawn mother, Pawn baby)
		{
			if (mother.Spawned)
			{
				// Spawn guck
				if (mother.caller != null)
				{
					mother.caller.DoCall();
				}
				if (baby != null)
				{
					if (baby.caller != null)
					{
						baby.caller.DoCall();
					}
				}
				FilthMaker.TryMakeFilth(mother.Position, mother.Map, ThingDefOf.Filth_AmnioticFluid, mother.LabelIndefinite(), 5);
				int howmuch = Rand.Range(1, 3);
				int i = 0;
				if (xxx.is_insect(baby) || xxx.is_insect(mother) || xxx.is_insect(implanter) || xxx.is_insect(father))
				{
					while (i++ < howmuch)
					{
						Thing jelly = ThingMaker.MakeThing(ThingDefOf.InsectJelly);
						if (mother.MapHeld?.areaManager?.Home[mother.PositionHeld] == false)
							jelly.SetForbidden(true, false);
						GenPlace.TryPlaceThing(jelly, mother.PositionHeld, mother.MapHeld, ThingPlaceMode.Near);
					}
				}
			}
		}

		/// <summary>
		/// Pops out eggs that are not fertilized.
		/// </summary>
		/// <param name="mother"></param>
		private void BirthUnfertilizedEggs(Pawn mother)
		{
			if (RJWSettings.DevMode) ModLog.Message($"{mother} is giving 'birth' to unfertilized Insect-Eggs.");

			if (PawnUtility.ShouldSendNotificationAbout(pawn) && (pawn.IsColonist || pawn.IsPrisonerOfColony))
			{
				string key = "EggDead";
				string text = TranslatorFormattedStringExtensions.Translate(key, pawn.LabelIndefinite()).CapitalizeFirst();
				Messages.Message(text, pawn, MessageTypeDefOf.SituationResolved);
			}
			Thing egg;
			var UEgg = DefDatabase<ThingDef>.GetNamedSilentFail(HediffDefOfEgg.UnFertEggDef);
			if (UEgg == null)
				UEgg = (DefDatabase<ThingDef>.GetNamedSilentFail("RJW_EggInsectUnfertilized"));
			egg = ThingMaker.MakeThing(UEgg);

			if (mother.MapHeld?.areaManager?.Home[mother.PositionHeld] == false)
				egg.SetForbidden(true, false);
			GenPlace.TryPlaceThing(egg, mother.PositionHeld, mother.MapHeld, ThingPlaceMode.Near);
		}

		private Pawn ProcessHumanLikeInsectEgg(Pawn mother, PawnKindDef spawn_kind_def, Faction spawn_faction)
		{
			ModLog.Message("Hediff_InsectEgg::BirthBaby() " + spawn_kind_def + " of " + spawn_faction + " in " + (int)(50 * implanter.GetStatValue(StatDefOf.PsychicSensitivity)) + " chance!");

			PawnGenerationRequest request = new PawnGenerationRequest(
				kind: spawn_kind_def,
				faction: spawn_faction,
				forceGenerateNewPawn: true,
				developmentalStages: DevelopmentalStage.Newborn,
				allowDowned: true,
				canGeneratePawnRelations: false,
				colonistRelationChanceFactor: 0,
				allowFood: false,
				allowAddictions: false,
				relationWithExtraPawnChanceFactor: 0,
				//forceNoIdeo: true,
				forbidAnyTitle: true,
				forceNoBackstory: true);

			Pawn baby = PawnGenerator.GeneratePawn(request);
			// If we have genes, and the baby has not set any, add the ones stored from fertilization as endogenes
			if (RJWPregnancySettings.egg_pregnancy_genes && eggGenes != null && eggGenes.Count > 0)
			{
				if (RJWSettings.DevMode) ModLog.Message($"Setting {eggGenes.Count} genes for {baby}");
				foreach (var gene in baby.genes.GenesListForReading)
					baby.genes.RemoveGene(gene);
				foreach (var gene in eggGenes)
					baby.genes.AddGene(gene, false);
			} else
			{
				if (RJWSettings.DevMode) ModLog.Message($"Did not find genes for {baby}");
			}

			DetermineIfBabyIsPrisonerOrSlave(mother, baby);

			SetBabyRelations(baby,implanter,father, mother);

			PawnUtility.TrySpawnHatchedOrBornPawn(baby, mother);

			if (spawn_faction == Faction.OfInsects || (spawn_faction != null && (spawn_faction.def.defName.Contains("insect") || spawn_faction == implanter.Faction)))
			{
				Lord lord = implanter.GetLord();
				if (lord != null)
				{
					lord.AddPawn(baby);
				}
			}

			Hediff_BasePregnancy.BabyPostBirth(mother, father, baby);
			Sexualizer.sexualize_pawn(baby);

			// Move the baby in front of the mother, rather than on top
			if (mother.Spawned)
				if (mother.CurrentBed() != null)
				{
					baby.Position = baby.Position + new IntVec3(0, 0, 1).RotatedBy(mother.CurrentBed().Rotation);
				}

			return baby;
		}

		private void SetBabyRelations(Pawn Baby, Pawn EggProducer, Pawn Fertilizer, Pawn Host)
		{
			if (RJWSettings.DevMode) ModLog.Message($"Setting Relations for {Baby}: Egg-Mother={EggProducer}, Egg-Fertilizer={Fertilizer}, Egg-Host={Host}");
            if (!RJWSettings.Disable_egg_pregnancy_relations)
				if (Baby.RaceProps.IsFlesh)
				{
					if (EggProducer != null)
						Baby.relations.AddDirectRelation(PawnRelationDefOf.Parent, EggProducer);
					// Note: Depending on the Sex of the Fertilizer, it's labelled as "Mother" too.
					if (Fertilizer != null)
						Baby.relations.AddDirectRelation(PawnRelationDefOf.Parent, Fertilizer);
					if (Host != null && Host != EggProducer)
						Baby.relations.AddDirectRelation(PawnRelationDefOf.ParentBirth, Host);
				}
		}

		private static void DetermineIfBabyIsPrisonerOrSlave(Pawn mother, Pawn baby)
		{
			if (mother.IsSlaveOfColony)
			{
				if (mother.SlaveFaction != null)
					baby.SetFaction(mother.SlaveFaction);
				else if (mother.HomeFaction != null)
					baby.SetFaction(mother.HomeFaction);
				else if (mother.Faction != null)
					baby.SetFaction(mother.Faction);
				else
					baby.SetFaction(Faction.OfPlayer);
				baby.guest.SetGuestStatus(Faction.OfPlayer, GuestStatus.Slave);
			}
			else if (mother.IsPrisonerOfColony)
			{
				if (mother.HomeFaction != null)
					baby.SetFaction(mother.HomeFaction);
				baby.guest.SetGuestStatus(Faction.OfPlayer, GuestStatus.Prisoner);
			}
		}

		[SyncMethod]
		private void BirthFertilizedAnimalEgg(Pawn mother, PawnKindDef spawn_kind_def)
		{
			if (RJWSettings.DevMode) ModLog.Message($"{mother} is birthing an fertilized egg of {spawn_kind_def} ");

			Thing egg;
			ThingDef EggDef;
			string childrendef = "";
			PawnKindDef children = null;

			//make egg
			EggDef = DefDatabase<ThingDef>.GetNamedSilentFail(HediffDefOfEgg.FertEggDef);			//try to find predefined
			if (EggDef == null)                                                                     //fail, use generic
				EggDef = (DefDatabase<ThingDef>.GetNamedSilentFail("RJW_EggInsectFertilized"));
			egg = ThingMaker.MakeThing(EggDef);

			//make child
			List<string> childlist = new List<string>();
			if (!HediffDefOfEgg.childrenDefs.NullOrEmpty())
			{
				foreach (var child in HediffDefOfEgg.childrenDefs)
				{
					if (DefDatabase<PawnKindDef>.GetNamedSilentFail(child) != null)
						childlist.AddDistinct(child);
				}
				childrendef = childlist.RandomElement();                                                    //try to find predefined
			}
			if (!childrendef.NullOrEmpty())
				children = DefDatabase<PawnKindDef>.GetNamedSilentFail(childrendef);

			if (children == null)                                                                           //use fatherDef
				children = spawn_kind_def;

			//put child into egg
			if (children != null)
			{
				var t = egg.TryGetComp<CompHatcher>();
				t.Props.hatcherPawn = children;
				t.hatcheeParent = implanter;
				t.otherParent = father;
				t.hatcheeFaction = implanter.Faction;
			}

			if (mother.MapHeld?.areaManager?.Home[mother.PositionHeld] == false)
				egg.SetForbidden(true, false);

			//poop egg
			GenPlace.TryPlaceThing(egg, mother.PositionHeld, mother.MapHeld, ThingPlaceMode.Near);
		}

		private Faction DetermineSpawnFaction(Pawn mother)
		{
			Faction spawn_faction;

			//core Hive Insects... probably
			if (implanter.Faction == Faction.OfInsects || father.Faction == Faction.OfInsects || mother.Faction == Faction.OfInsects)
			{
				spawn_faction = Faction.OfInsects;
				int chance = 5;

				//random chance to make insect neutral/tamable
				if (father.Faction == Faction.OfInsects)
					chance = 5;
				if (father.Faction != Faction.OfInsects)
					chance = 10;
				if (father.Faction == Faction.OfPlayer)
					chance = 25;
				if (implanter.Faction == Faction.OfPlayer)
					chance += 25;
				if (implanter.Faction == Faction.OfPlayer && xxx.is_human(implanter))
					chance += (int)(25 * implanter.GetStatValue(StatDefOf.PsychicSensitivity));
				if (Rand.Range(0, 100) <= chance)
					spawn_faction = null;

				//chance tame insect on birth
				if (spawn_faction == null)
					if (implanter.Faction == Faction.OfPlayer && xxx.is_human(implanter))
						if (Rand.Range(0, 100) <= (int)(50 * implanter.GetStatValue(StatDefOf.PsychicSensitivity)))
							spawn_faction = Faction.OfPlayer;
			}
			//humanlikes
			else if (xxx.is_human(implanter))
			{
				spawn_faction = implanter.Faction;
			}
			//animal, spawn implanter faction (if not player faction/not tamed)
			else if (!xxx.is_human(implanter) && !(implanter.Faction?.IsPlayer ?? false))
			{
				spawn_faction = implanter.Faction;
			}
			//spawn factionless(tamable, probably)
			else
			{
				spawn_faction = null;
			}

			return spawn_faction;
		}

		/// <summary>
		/// Sets the Father of an egg.
		/// If possible, the genes of the baby are determined too and stored in the egg-pregnancy.
		/// Exception is for androids or immortals (mod content).
		/// </summary>
		/// <param name="Pawn"> Pawn to be set as Father </param>
		public void Fertilize(Pawn Pawn)
		{
			if (implanter == null)
			{
				return;
			}
			if (xxx.ImmortalsIsActive && (Pawn.health.hediffSet.HasHediff(xxx.IH_Immortal) || pawn.health.hediffSet.HasHediff(xxx.IH_Immortal)))
			{
				if (RJWSettings.DevMode) ModLog.Message($"{xxx.get_pawnname(pawn)} is immortal no Fertilize egg {this} cancel");
				return;
			}
			if (AndroidsCompatibility.IsAndroid(pawn))
			{
				return;
			}

			if (!fertilized && canbefertilized && GestationProgress < 0.5)
			{
				if (RJWSettings.DevMode) ModLog.Message($"{xxx.get_pawnname(pawn)} had eggs inside fertilized (Fertilized by {xxx.get_pawnname(father)}): {this}");
				father = Pawn;
				ChangeEgg(implanter);
			}

			// If both parents are human / have genes, set the genes of the offspring
			if (RJWPregnancySettings.egg_pregnancy_genes && father != null && implanter != null && father.genes != null && implanter.genes != null)
			{
				if (RJWSettings.DevMode) ModLog.Message($"Setting InsectEgg-Genes for {this}");
				DetermineChildGenes();
			} else
			{
				if (RJWSettings.DevMode) ModLog.Message($"Could not set Genes for {this}");
			}
		}

		/// <summary>
		/// Sets the genes of the child if both Implanter and Fertilizer have genes.
		/// Intentionally in it's own method for easier access with Harmony Patches.
		/// </summary>
		private void DetermineChildGenes()
		{
			eggGenes = PregnancyUtility.GetInheritedGenes(father, implanter);
			if (RJWSettings.DevMode) ModLog.Message($"Set Genes for {this} from {father} & {implanter} - total of {eggGenes.Count} genes set.");
		}

		/// <summary>
		/// Sets the Implanter and thus the base-egg type.
		/// If the egg is Self-Fertilized, the egg also gets fertilized (with Implanter as father, too).
		/// </summary>
		/// <param name="pawn">Pawn to be implanter.</param>
		public void InitImplanter(Pawn pawn)
		{
			if (implanter == null)
			{
				if (RJWSettings.DevMode) ModLog.Message("Hediff_InsectEgg:: set implanter:" + xxx.get_pawnname(pawn));
				implanter = pawn;
				ChangeEgg(implanter);

				if (!implanter.health.hediffSet.HasHediff(xxx.sterilized))
				{
					if (HediffDefOfEgg.selffertilized)
						Fertilize(implanter);
				}
				else
					canbefertilized = false;
			}
		}

		//Change egg type after implanting/fertilizing
		public void ChangeEgg(Pawn Pawn)
		{
			if (Pawn != null)
			{
				float p_end_tick_mods = GetIncubationPeriod(Pawn);

				p_start_tick = Find.TickManager.TicksGame;
				p_end_tick = p_start_tick + p_end_tick_mods;
				lastTick = p_start_tick;

				eggssize = Pawn.RaceProps.baseBodySize / 5 * (this.def as HediffDef_InsectEgg).eggsize * RJWPregnancySettings.egg_pregnancy_eggs_size;
				// no 0 severity egg size
				if (eggssize < 0.01f)
					eggssize = 0.01f;

				// cap egg size in ovi to 10%
				if (this.part.def == xxx.genitalsDef)
					if (eggssize > 0.1f && Genital_Helper.has_ovipositorF(pawn))
						if (Genital_Helper.has_ovipositorF(pawn))
							eggssize = 0.1f;

				Severity = eggssize;
			}
		}

		private float GetIncubationPeriod(Pawn implanter)
		{
			float incubationTicks;

			if (implanter.RaceProps?.gestationPeriodDays < 1f)
			{
				incubationTicks = GenDate.TicksPerDay;
			}
			else
			{
				incubationTicks = implanter.RaceProps.gestationPeriodDays * GenDate.TicksPerDay;
			}

			if (pawn.health.hediffSet.HasHediff(HediffDef.Named("FertilityEnhancer")))
				incubationTicks /= 2f;

			incubationTicks *= RJWPregnancySettings.egg_pregnancy_duration;

			return incubationTicks;
		}

		//for setting implanter/fertilize eggs
		public bool IsParent(Pawn parent)
		{
			//anyone can fertilize
			if (RJWPregnancySettings.egg_pregnancy_fertilize_anyone) return true;

			//only set egg parent or implanter can fertilize
			else return parentDef == parent.kindDef.defName
						|| parentDefs.Contains(parent.kindDef.defName)
						|| implanter.kindDef == parent.kindDef; // unknown eggs
		}

		public override string DebugString()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append(base.DebugString());
			stringBuilder.AppendLine(" Gestation progress: " + GestationProgress.ToStringPercent());
			if (RJWSettings.DevMode) stringBuilder.AppendLine(" Implanter: " + xxx.get_pawnname(implanter));
			if (RJWSettings.DevMode) stringBuilder.AppendLine(" Father: " + xxx.get_pawnname(father));
			return stringBuilder.ToString();
		}
	}
}


code:
using RimWorld;
using System.Linq;
using Verse;
using Verse.AI;

namespace rjw
{
	public class Hediff_Orgasm : HediffWithComps
	{
		public override void PostAdd(DamageInfo? dinfo)
		{
			string key = "FeltOrgasm";
			string text = TranslatorFormattedStringExtensions.Translate(key, pawn.LabelIndefinite()).CapitalizeFirst();
			Messages.Message(text, pawn, MessageTypeDefOf.NeutralEvent);
		}
	}

	public class Hediff_TransportCums : HediffWithComps
	{
		public override void PostAdd(DamageInfo? dinfo)
		{
			if (pawn.gender == Gender.Female)
			{
				string key = "CumsTransported";
				string text = TranslatorFormattedStringExtensions.Translate(key, pawn.LabelIndefinite()).CapitalizeFirst();
				Messages.Message(text, pawn, MessageTypeDefOf.NeutralEvent);
				PawnGenerationRequest req = new PawnGenerationRequest(PawnKindDefOf.Drifter, fixedGender:Gender.Male );
				Pawn cumSender = PawnGenerator.GeneratePawn(req);
				Find.WorldPawns.PassToWorld(cumSender);
				//Pawn cumSender = (from p in Find.WorldPawns.AllPawnsAlive where p.gender == Gender.Male select p).RandomElement<Pawn>();
				//--ModLog.Message("" + this.GetType().ToString() + "PostAdd() - Sending " + xxx.get_pawnname(cumSender) + "'s cum into " + xxx.get_pawnname(pawn) + "'s vagina");
				//PregnancyHelper.impregnate(pawn, cumSender, xxx.rjwSextype.Vaginal);
			}
			pawn.health.RemoveHediff(this);
		}
	}

	public class Hediff_TransportEggs : HediffWithComps
	{
		public override void PostAdd(DamageInfo? dinfo)
		{
			if (pawn.gender == Gender.Female)
			{
				string key = "EggsTransported";
				string text = TranslatorFormattedStringExtensions.Translate(key, pawn.LabelIndefinite()).CapitalizeFirst();
				Messages.Message(text, pawn, MessageTypeDefOf.NeutralEvent);

				PawnKindDef spawn = PawnKindDefOf.Megascarab;
				PawnGenerationRequest req1 = new PawnGenerationRequest(spawn, fixedGender:Gender.Female );
				PawnGenerationRequest req2 = new PawnGenerationRequest(spawn, fixedGender:Gender.Male );
				Pawn implanter = PawnGenerator.GeneratePawn(req1);
				Pawn fertilizer = PawnGenerator.GeneratePawn(req2);
				Find.WorldPawns.PassToWorld(implanter);
				Find.WorldPawns.PassToWorld(fertilizer);
				Sexualizer.sexualize_pawn(implanter);
				Sexualizer.sexualize_pawn(fertilizer);
				//Pawn cumSender = (from p in Find.WorldPawns.AllPawnsAlive where p.gender == Gender.Male select p).RandomElement<Pawn>();
				//--ModLog.Message("" + this.GetType().ToString() + "PostAdd() - Sending " + xxx.get_pawnname(cumSender) + "'s cum into " + xxx.get_pawnname(pawn) + "'s vagina");
				//PregnancyHelper.impregnate(pawn, implanter, xxx.rjwSextype.Vaginal);
				//PregnancyHelper.impregnate(pawn, fertilizer, xxx.rjwSextype.Vaginal);
			}
			pawn.health.RemoveHediff(this);
		}
	}
}


code:
using System.Collections.Generic;
using Verse;

namespace rjw
{
	internal class Hediff_MechImplants : HediffWithComps
	{
		public override bool TryMergeWith(Hediff other)
		{
			return false;
		}
	}
}


code:
using System.Collections.Generic;
using RimWorld;
using Verse;
using Verse.AI.Group;
using System.Linq;
using UnityEngine;
using Multiplayer.API;

namespace rjw
{
	///<summary>
	///This hediff class simulates pregnancy with mechanoids, mother may be human. It is not intended to be reasonable.
	///Differences from bestial pregnancy are that ... it is lethal
	///TODO: extend with something "friendlier"? than Mech_Scyther.... two Mech_Scyther's? muhahaha
	///</summary>
	[RJWAssociatedHediff("RJW_pregnancy_mech")]
	public class Hediff_MechanoidPregnancy : Hediff_BasePregnancy
	{
		public override bool canBeAborted
		{
			get
			{
				return false;
			}
		}

		public override bool canMiscarry
		{
			get
			{
				return false;
			}
		}

		public override void PregnancyMessage()
		{
			string message_title = "RJW_PregnantTitle".Translate(pawn.LabelIndefinite()).CapitalizeFirst();
			string message_text1 = "RJW_PregnantText".Translate(pawn.LabelIndefinite()).CapitalizeFirst();
			string message_text2 = "RJW_PregnantMechStrange".Translate();
			Find.LetterStack.ReceiveLetter(message_title, message_text1 + "\n" + message_text2, LetterDefOf.ThreatBig, pawn);
		}

		public void Hack()
		{
			is_hacked = true;
		}

		public override void Notify_PawnDied(DamageInfo? dinfo, Hediff culprit = null)
		{
			base.Notify_PawnDied(dinfo, culprit);
			GiveBirth();
		}

		//Handles the spawning of pawns
		[SyncMethod]
		public override void GiveBirth()
		{
			Pawn mother = pawn;
			if (mother == null)
				return;

			if (!babies.NullOrEmpty())
			{
				foreach (Pawn baby in babies)
				{
					baby.Destroy();
					baby.Discard(true);
				}
				babies.Clear();
			}

			Faction spawn_faction = null;

			if (!is_hacked)
			{
				spawn_faction = father?.Faction;
				spawn_faction ??= Faction.OfMechanoids;
			}
			else if (ModsConfig.BiotechActive)
				spawn_faction = Faction.OfPlayer;

			PawnKindDef children = null;

			if (RJWSettings.DevMode) ModLog.Message(xxx.get_pawnname(pawn) + " birth:" + this.ToString());

			foreach (HediffDef_MechImplants implant in DefDatabase<HediffDef_MechImplants>.AllDefs.Where(x => x.parentDefs.Contains(father.kindDef.ToString())))         //try to find predefined
			{
				string childrendef;																			//try to find predefined
				List<string> childlist = new List<string>();
				if (!implant.childrenDefs.NullOrEmpty())
				{
					foreach (var child in (implant.childrenDefs))
					{
						if (DefDatabase<PawnKindDef>.GetNamedSilentFail(child) != null)
							childlist.AddDistinct(child);
					}
					childrendef = childlist.RandomElement();												//try to find predefined
					children = DefDatabase<PawnKindDef>.GetNamedSilentFail(childrendef);
					if (children != null)
						continue;
				}
			}

			if (children == null)                                                                           //fallback, use fatherDef
				children = father.kindDef;

			PawnGenerationRequest request = new PawnGenerationRequest(
				kind: children,
				faction: spawn_faction,
				forceGenerateNewPawn: true,
				developmentalStages: DevelopmentalStage.Newborn
				);

			Pawn mech = PawnGenerator.GeneratePawn(request);
			PawnUtility.TrySpawnHatchedOrBornPawn(mech, mother);
			if (!is_hacked)
			{
				LordJob_MechanoidsDefend lordJob = new LordJob_MechanoidsDefend();
				Lord lord = LordMaker.MakeNewLord(mech.Faction, lordJob, mech.Map);
				lord.AddPawn(mech);
			}
			FilthMaker.TryMakeFilth(mech.PositionHeld, mech.MapHeld, mother.RaceProps.BloodDef, mother.LabelIndefinite());

			IEnumerable<BodyPartRecord> source = from x in mother.health.hediffSet.GetNotMissingParts() where
												x.IsInGroup(BodyPartGroupDefOf.Torso)
												&& !x.IsCorePart
												//&& x.groups.Contains(BodyPartGroupDefOf.Torso)
												//&& x.depth == BodyPartDepth.Inside
												//&& x.height == BodyPartHeight.Bottom
												//someday include depth filter
												//so it doesn't cut out external organs (breasts)?
												//vag  is genital part and genital is external
												//anal is internal
												//make sep part of vag?
												//&& x.depth == BodyPartDepth.Inside
												select x;

			mother.health.RemoveHediff(this);
			if (source.Any())
			{
				foreach (BodyPartRecord part in source)
				{
					mother.health.DropBloodFilth();
				}
				if (RJWPregnancySettings.safer_mechanoid_pregnancy && is_checked)
				{
					foreach (BodyPartRecord part in source)
					{
						DamageDef surgicalCut = DamageDefOf.SurgicalCut;
						float amount = 5f;
						float armorPenetration = 999f;
						mother.TakeDamage(new DamageInfo(surgicalCut, amount, armorPenetration, -1f, null, part, null, DamageInfo.SourceCategory.ThingOrUnknown, null));
					}
				}
				else
				{
					foreach (BodyPartRecord part in source)
					{
						Hediff_MissingPart hediff_MissingPart = (Hediff_MissingPart)HediffMaker.MakeHediff(HediffDefOf.MissingBodyPart, mother, part);
						hediff_MissingPart.lastInjury = HediffDefOf.Cut;
						hediff_MissingPart.IsFresh = true;
						mother.health.AddHediff(hediff_MissingPart);
					}
				}
			}

		}
	}
}


code:
using RimWorld;
using RimWorld.Planet;
using UnityEngine;
using Verse;
using Multiplayer.API;

namespace rjw
{
	internal class Hediff_Parasite : Hediff_Pregnant
	{
		[SyncMethod]
		new public static void DoBirthSpawn(Pawn mother, Pawn father)
		{
			//Rand.PopState();
			//Rand.PushState(RJW_Multiplayer.PredictableSeed());
			int num = (mother.RaceProps.litterSizeCurve == null) ? 1 : Mathf.RoundToInt(Rand.ByCurve(mother.RaceProps.litterSizeCurve));
			if (num < 1)
			{
				num = 1;
			}
			PawnGenerationRequest request = new PawnGenerationRequest(
					kind: father.kindDef,
					faction: father.Faction,
					forceGenerateNewPawn: true,
					developmentalStages: DevelopmentalStage.Newborn,
					allowDowned: true,
					canGeneratePawnRelations: false,
					mustBeCapableOfViolence: true,
					colonistRelationChanceFactor: 0,
					allowFood: false,
					allowAddictions: false,
					relationWithExtraPawnChanceFactor: 0
				);

			Pawn pawn = null;
			for (int i = 0; i < num; i++)
			{
				pawn = PawnGenerator.GeneratePawn(request);
				if (PawnUtility.TrySpawnHatchedOrBornPawn(pawn, mother))
				{
					if (pawn.playerSettings != null && mother.playerSettings != null)
					{
						pawn.playerSettings.AreaRestrictionInPawnCurrentMap = father.playerSettings.AreaRestrictionInPawnCurrentMap; //TODO is this correct?
					}
					if (pawn.RaceProps.IsFlesh)
					{
						pawn.relations.AddDirectRelation(PawnRelationDefOf.Parent, mother);
						if (father != null)
						{
							pawn.relations.AddDirectRelation(PawnRelationDefOf.Parent, father);
						}
					}
				}
				else
				{
					Find.WorldPawns.PassToWorld(pawn, PawnDiscardDecideMode.Discard);
				}
			}
			if (mother.Spawned)
			{
				FilthMaker.TryMakeFilth(mother.Position, mother.Map, ThingDefOf.Filth_AmnioticFluid, mother.LabelIndefinite(), 5);
				if (mother.caller != null)
				{
					mother.caller.DoCall();
				}
				if (pawn.caller != null)
				{
					pawn.caller.DoCall();
				}
			}
		}
	}
}